summaryrefslogtreecommitdiffstats
path: root/layout/base/nsCSSFrameConstructor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'layout/base/nsCSSFrameConstructor.cpp')
-rw-r--r--layout/base/nsCSSFrameConstructor.cpp240
1 files changed, 82 insertions, 158 deletions
diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp
index 3c1896c162..149f2f24bf 100644
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -170,6 +170,7 @@ nsIFrame* NS_NewSVGFEImageFrame(PresShell* aPresShell, ComputedStyle* aStyle);
nsIFrame* NS_NewSVGFEUnstyledLeafFrame(PresShell* aPresShell,
ComputedStyle* aStyle);
nsIFrame* NS_NewFileControlLabelFrame(PresShell*, ComputedStyle*);
+nsIFrame* NS_NewComboboxLabelFrame(PresShell*, ComputedStyle*);
nsIFrame* NS_NewMiddleCroppingLabelFrame(PresShell*, ComputedStyle*);
#include "mozilla/dom/NodeInfo.h"
@@ -320,7 +321,7 @@ static bool ShouldSuppressColumnSpanDescendants(nsIFrame* aFrame) {
}
if (!aFrame->IsBlockFrameOrSubclass() ||
- aFrame->HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS | NS_FRAME_OUT_OF_FLOW) ||
+ aFrame->HasAnyStateBits(NS_BLOCK_BFC | NS_FRAME_OUT_OF_FLOW) ||
aFrame->IsFixedPosContainingBlock()) {
// Need to suppress column-span if we:
// - Are a different block formatting context,
@@ -2286,7 +2287,7 @@ nsIFrame* nsCSSFrameConstructor::ConstructTableCell(
aState, content, innerPseudoStyle, cellFrame,
PseudoStyleType::scrolledContent, false, scrollFrame);
}
- cellInnerFrame = NS_NewBlockFormattingContext(mPresShell, innerPseudoStyle);
+ cellInnerFrame = NS_NewBlockFrame(mPresShell, innerPseudoStyle);
}
auto* parent = scrollFrame ? scrollFrame : cellFrame;
InitAndRestoreFrame(aState, content, parent, cellInnerFrame);
@@ -2566,7 +2567,7 @@ nsIFrame* nsCSSFrameConstructor::ConstructDocElementFrame(
MOZ_ASSERT(display->mDisplay == StyleDisplay::Block ||
display->mDisplay == StyleDisplay::FlowRoot,
"Unhandled display type for root element");
- contentFrame = NS_NewBlockFormattingContext(mPresShell, computedStyle);
+ contentFrame = NS_NewBlockFrame(mPresShell, computedStyle);
ConstructBlock(
state, aDocElement,
state.GetGeometricParent(*display, mDocElementContainingBlock),
@@ -3012,91 +3013,33 @@ static inline void ClearLazyBits(nsIContent* aStartContent,
}
}
-nsIFrame* nsCSSFrameConstructor::ConstructSelectFrame(
+/* static */
+const nsCSSFrameConstructor::FrameConstructionData*
+nsCSSFrameConstructor::FindSelectData(const Element& aElement,
+ ComputedStyle& aStyle) {
+ // Construct a frame-based listbox or combobox
+ const auto* sel = dom::HTMLSelectElement::FromNode(aElement);
+ MOZ_ASSERT(sel);
+ if (sel->IsCombobox()) {
+ static constexpr FrameConstructionData sComboboxData{
+ ToCreationFunc(NS_NewComboboxControlFrame), 0,
+ PseudoStyleType::buttonContent};
+ return &sComboboxData;
+ }
+ // FIXME: Can we simplify this to avoid needing ConstructListboxSelectFrame,
+ // and reuse ConstructScrollableBlock or so?
+ static constexpr FrameConstructionData sListBoxData{
+ &nsCSSFrameConstructor::ConstructListBoxSelectFrame};
+ return &sListBoxData;
+}
+
+nsIFrame* nsCSSFrameConstructor::ConstructListBoxSelectFrame(
nsFrameConstructorState& aState, FrameConstructionItem& aItem,
nsContainerFrame* aParentFrame, const nsStyleDisplay* aStyleDisplay,
nsFrameList& aFrameList) {
nsIContent* const content = aItem.mContent;
ComputedStyle* const computedStyle = aItem.mComputedStyle;
- // Construct a frame-based listbox or combobox
- dom::HTMLSelectElement* sel = dom::HTMLSelectElement::FromNode(content);
- MOZ_ASSERT(sel);
- if (sel->IsCombobox()) {
- // Construct a frame-based combo box.
- // The frame-based combo box is built out of three parts. A display area, a
- // button and a dropdown list. The display area and button are created
- // through anonymous content. The drop-down list's frame is created
- // explicitly. The combobox frame shares its content with the drop-down
- // list.
- nsComboboxControlFrame* comboboxFrame =
- NS_NewComboboxControlFrame(mPresShell, computedStyle);
-
- // Save the history state so we don't restore during construction
- // since the complete tree is required before we restore.
- nsILayoutHistoryState* historyState = aState.mFrameState;
- aState.mFrameState = nullptr;
- // Initialize the combobox frame
- InitAndRestoreFrame(aState, content,
- aState.GetGeometricParent(*aStyleDisplay, aParentFrame),
- comboboxFrame);
-
- comboboxFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
-
- aState.AddChild(comboboxFrame, aFrameList, content, aParentFrame);
-
- // Resolve pseudo element style for the dropdown list
- RefPtr<ComputedStyle> listStyle =
- mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
- PseudoStyleType::dropDownList, computedStyle);
-
- // child frames of combobox frame
- nsFrameList childList;
-
- // Create display and button frames from the combobox's anonymous content.
- // The anonymous content is appended to existing anonymous content for this
- // element (the scrollbars).
- //
- // nsComboboxControlFrame needs special frame creation behavior for its
- // first piece of anonymous content, which means that we can't take the
- // normal ProcessChildren path.
- AutoTArray<nsIAnonymousContentCreator::ContentInfo, 2> newAnonymousItems;
- DebugOnly<nsresult> rv =
- GetAnonymousContent(content, comboboxFrame, newAnonymousItems);
- MOZ_ASSERT(NS_SUCCEEDED(rv));
- MOZ_ASSERT(!newAnonymousItems.IsEmpty());
-
- // Manually create a frame for the special NAC.
- MOZ_ASSERT(newAnonymousItems[0].mContent ==
- comboboxFrame->GetDisplayNode());
- newAnonymousItems.RemoveElementAt(0);
- nsIFrame* customFrame = comboboxFrame->CreateFrameForDisplayNode();
- MOZ_ASSERT(customFrame);
- childList.AppendFrame(nullptr, customFrame);
-
- nsFrameConstructorSaveState floatSaveState;
- aState.MaybePushFloatContainingBlock(comboboxFrame, floatSaveState);
-
- // The other piece of NAC can take the normal path.
- AutoFrameConstructionItemList fcItems(this);
- AutoFrameConstructionPageName pageNameTracker(aState, comboboxFrame);
- AddFCItemsForAnonymousContent(aState, comboboxFrame, newAnonymousItems,
- fcItems, pageNameTracker);
- ConstructFramesFromItemList(aState, fcItems, comboboxFrame,
- /* aParentIsWrapperAnonBox = */ false,
- childList);
-
- comboboxFrame->SetInitialChildList(FrameChildListID::Principal,
- std::move(childList));
-
- aState.mFrameState = historyState;
- if (aState.mFrameState) {
- // Restore frame state for the entire subtree of |comboboxFrame|.
- RestoreFrameState(comboboxFrame, aState.mFrameState);
- }
- return comboboxFrame;
- }
-
// Listbox, not combobox
nsContainerFrame* listFrame =
NS_NewListControlFrame(mPresShell, computedStyle);
@@ -3175,7 +3118,7 @@ nsIFrame* nsCSSFrameConstructor::ConstructFieldSetFrame(
const nsStyleDisplay* fieldsetContentDisplay =
fieldsetContentStyle->StyleDisplay();
- bool isScrollable = fieldsetContentDisplay->IsScrollableOverflow();
+ const bool isScrollable = fieldsetContentDisplay->IsScrollableOverflow();
nsContainerFrame* scrollFrame = nullptr;
if (isScrollable) {
fieldsetContentStyle = BeginBuildingScrollFrame(
@@ -3204,8 +3147,7 @@ nsIFrame* nsCSSFrameConstructor::ConstructFieldSetFrame(
MOZ_ASSERT(fieldsetContentDisplay->mDisplay == StyleDisplay::Block,
"bug in StyleAdjuster::adjust_for_fieldset_content?");
- contentFrame =
- NS_NewBlockFormattingContext(mPresShell, fieldsetContentStyle);
+ contentFrame = NS_NewBlockFrame(mPresShell, fieldsetContentStyle);
if (fieldsetContentStyle->StyleColumn()->IsColumnContainerStyle()) {
contentFrameTop = BeginBuildingColumns(
aState, content, parent, contentFrame, fieldsetContentStyle);
@@ -3499,11 +3441,18 @@ nsCSSFrameConstructor::FindHTMLData(const Element& aElement,
"Unexpected parent for fieldset content anon box");
if (aElement.IsInNativeAnonymousSubtree() &&
- aElement.NodeInfo()->NameAtom() == nsGkAtoms::label &&
- static_cast<nsFileControlFrame*>(do_QueryFrame(aParentFrame))) {
- static constexpr FrameConstructionData sFileLabelData(
- NS_NewFileControlLabelFrame);
- return &sFileLabelData;
+ aElement.NodeInfo()->NameAtom() == nsGkAtoms::label && aParentFrame) {
+ if (static_cast<nsFileControlFrame*>(do_QueryFrame(aParentFrame))) {
+ static constexpr FrameConstructionData sFileLabelData(
+ NS_NewFileControlLabelFrame);
+ return &sFileLabelData;
+ }
+ if (aParentFrame->GetParent() &&
+ aParentFrame->GetParent()->IsComboboxControlFrame()) {
+ static constexpr FrameConstructionData sComboboxLabelData(
+ NS_NewComboboxLabelFrame);
+ return &sComboboxLabelData;
+ }
}
static constexpr FrameConstructionDataByTag sHTMLData[] = {
@@ -3515,7 +3464,7 @@ nsCSSFrameConstructor::FindHTMLData(const Element& aElement,
SIMPLE_TAG_CREATE(wbr, NS_NewWBRFrame),
SIMPLE_TAG_CHAIN(input, nsCSSFrameConstructor::FindInputData),
SIMPLE_TAG_CREATE(textarea, NS_NewTextControlFrame),
- COMPLEX_TAG_CREATE(select, &nsCSSFrameConstructor::ConstructSelectFrame),
+ SIMPLE_TAG_CHAIN(select, nsCSSFrameConstructor::FindSelectData),
SIMPLE_TAG_CHAIN(object, nsCSSFrameConstructor::FindObjectData),
SIMPLE_TAG_CHAIN(embed, nsCSSFrameConstructor::FindObjectData),
COMPLEX_TAG_CREATE(fieldset,
@@ -3741,11 +3690,6 @@ void nsCSSFrameConstructor::ConstructFrameFromItemInternal(
CHECK_ONLY_ONE_BIT(FCDATA_WRAP_KIDS_IN_BLOCKS,
FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS);
#undef CHECK_ONLY_ONE_BIT
- NS_ASSERTION(!(bits & FCDATA_FORCED_NON_SCROLLABLE_BLOCK) ||
- ((bits & FCDATA_FUNC_IS_FULL_CTOR) &&
- data->mFunc.mFullConstructor ==
- &nsCSSFrameConstructor::ConstructNonScrollableBlock),
- "Unexpected FCDATA_FORCED_NON_SCROLLABLE_BLOCK flag");
MOZ_ASSERT(
!(bits & FCDATA_IS_WRAPPER_ANON_BOX) || (bits & FCDATA_USE_CHILD_ITEMS),
"Wrapper anon boxes should always have FCDATA_USE_CHILD_ITEMS");
@@ -3823,7 +3767,7 @@ void nsCSSFrameConstructor::ConstructFrameFromItemInternal(
innerFrame = outerFrame;
break;
default: {
- innerFrame = NS_NewBlockFormattingContext(mPresShell, outerStyle);
+ innerFrame = NS_NewBlockFrame(mPresShell, outerStyle);
if (outerStyle->StyleColumn()->IsColumnContainerStyle()) {
outerFrame = BeginBuildingColumns(aState, content, container,
innerFrame, outerStyle);
@@ -3836,7 +3780,7 @@ void nsCSSFrameConstructor::ConstructFrameFromItemInternal(
}
}
} else {
- innerFrame = NS_NewBlockFormattingContext(mPresShell, outerStyle);
+ innerFrame = NS_NewBlockFrame(mPresShell, outerStyle);
InitAndRestoreFrame(aState, content, container, innerFrame);
outerFrame = innerFrame;
}
@@ -4386,14 +4330,14 @@ nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay& aDisplay,
// XXX Ignore tables for the time being (except caption)
const uint32_t kCaptionCtorFlags =
FCDATA_IS_TABLE_PART | FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable);
- bool caption = aDisplay.mDisplay == StyleDisplay::TableCaption;
- bool suppressScrollFrame = false;
- bool needScrollFrame =
+ const bool caption = aDisplay.mDisplay == StyleDisplay::TableCaption;
+ const bool needScrollFrame =
aDisplay.IsScrollableOverflow() && !propagatedScrollToViewport;
if (needScrollFrame) {
- suppressScrollFrame = mPresShell->GetPresContext()->IsPaginated() &&
- aDisplay.IsBlockOutsideStyle() &&
- !aElement.IsInNativeAnonymousSubtree();
+ const bool suppressScrollFrame =
+ mPresShell->GetPresContext()->IsPaginated() &&
+ aDisplay.IsBlockOutsideStyle() &&
+ !aElement.IsInNativeAnonymousSubtree();
if (!suppressScrollFrame) {
static constexpr FrameConstructionData sScrollableBlockData[2] = {
{&nsCSSFrameConstructor::ConstructScrollableBlock},
@@ -4401,27 +4345,14 @@ nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay& aDisplay,
kCaptionCtorFlags}};
return &sScrollableBlockData[caption];
}
-
- // If the scrollable frame would have propagated its scrolling to the
- // viewport, we still want to construct a regular block rather than a
- // scrollframe so that it paginates correctly, but we don't want to set
- // the bit on the block that tells it to clip at paint time.
- if (mPresShell->GetPresContext()->ElementWouldPropagateScrollStyles(
- aElement)) {
- suppressScrollFrame = false;
- }
}
// Handle various non-scrollable blocks.
- static constexpr FrameConstructionData sNonScrollableBlockData[2][2] = {
- {{&nsCSSFrameConstructor::ConstructNonScrollableBlock},
- {&nsCSSFrameConstructor::ConstructNonScrollableBlock,
- kCaptionCtorFlags}},
- {{&nsCSSFrameConstructor::ConstructNonScrollableBlock,
- FCDATA_FORCED_NON_SCROLLABLE_BLOCK},
- {&nsCSSFrameConstructor::ConstructNonScrollableBlock,
- FCDATA_FORCED_NON_SCROLLABLE_BLOCK | kCaptionCtorFlags}}};
- return &sNonScrollableBlockData[suppressScrollFrame][caption];
+ static constexpr FrameConstructionData sNonScrollableBlockData[2] = {
+ {&nsCSSFrameConstructor::ConstructNonScrollableBlock},
+ {&nsCSSFrameConstructor::ConstructNonScrollableBlock,
+ kCaptionCtorFlags}};
+ return &sNonScrollableBlockData[caption];
}
case StyleDisplayInside::Table: {
static constexpr FrameConstructionData data(
@@ -4555,8 +4486,7 @@ nsIFrame* nsCSSFrameConstructor::ConstructScrollableBlock(
// Create our block frame
// pass a temporary stylecontext, the correct one will be set later
- nsContainerFrame* scrolledFrame =
- NS_NewBlockFormattingContext(mPresShell, computedStyle);
+ nsContainerFrame* scrolledFrame = NS_NewBlockFrame(mPresShell, computedStyle);
// Make sure to AddChild before we call ConstructBlock so that we
// end up before our descendants in fixed-pos lists as needed.
@@ -4579,26 +4509,7 @@ nsIFrame* nsCSSFrameConstructor::ConstructNonScrollableBlock(
nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay,
nsFrameList& aFrameList) {
ComputedStyle* const computedStyle = aItem.mComputedStyle;
-
- // We want a block formatting context root in paginated contexts for
- // every block that would be scrollable in a non-paginated context.
- // We mark our blocks with a bit here if this condition is true, so
- // we can check it later in nsIFrame::ApplyPaginatedOverflowClipping.
- bool clipPaginatedOverflow =
- (aItem.mFCData->mBits & FCDATA_FORCED_NON_SCROLLABLE_BLOCK) != 0;
- nsFrameState flags = nsFrameState(0);
- if ((aDisplay->IsAbsolutelyPositionedStyle() || aDisplay->IsFloatingStyle() ||
- aDisplay->DisplayInside() == StyleDisplayInside::FlowRoot ||
- clipPaginatedOverflow) &&
- !aParentFrame->IsInSVGTextSubtree()) {
- flags = NS_BLOCK_STATIC_BFC;
- if (clipPaginatedOverflow) {
- flags |= NS_BLOCK_CLIP_PAGINATED_OVERFLOW;
- }
- }
-
nsContainerFrame* newFrame = NS_NewBlockFrame(mPresShell, computedStyle);
- newFrame->AddStateBits(flags);
ConstructBlock(aState, aItem.mContent,
aState.GetGeometricParent(*aDisplay, aParentFrame),
aParentFrame, computedStyle, &newFrame, aFrameList,
@@ -5165,10 +5076,14 @@ static bool ShouldSuppressFrameInSelect(const nsIContent* aParent,
return false;
}
+ // Allow native anonymous content no matter what.
+ if (aChild.IsRootOfNativeAnonymousSubtree()) {
+ return false;
+ }
+
// Options with labels have their label text added in ::before by forms.css.
// Suppress frames for their child text.
- if (aParent->IsHTMLElement(nsGkAtoms::option) &&
- !aChild.IsRootOfNativeAnonymousSubtree()) {
+ if (aParent->IsHTMLElement(nsGkAtoms::option)) {
return aParent->AsElement()->HasNonEmptyAttr(nsGkAtoms::label);
}
@@ -5191,11 +5106,7 @@ static bool ShouldSuppressFrameInSelect(const nsIContent* aParent,
return false;
}
- // Allow native anonymous content no matter what.
- if (aChild.IsRootOfNativeAnonymousSubtree()) {
- return false;
- }
-
+ // Anything else is not ok.
return true;
}
@@ -8042,6 +7953,20 @@ nsIFrame* nsCSSFrameConstructor::CreateContinuingFrame(
return newFrame;
}
+void nsCSSFrameConstructor::MaybeSetNextPageContentFramePageName(
+ const nsIFrame* aFrame) {
+ MOZ_ASSERT(aFrame, "Frame should not be null");
+ // No parent means the root frame, which isn't what this funciton is for.
+ MOZ_ASSERT(aFrame->GetParent(),
+ "Frame should be the first child placed on a new page, not the "
+ "root frame.");
+ if (mNextPageContentFramePageName) {
+ return;
+ }
+ const nsAtom* const autoValue = aFrame->GetParent()->GetAutoPageValue();
+ mNextPageContentFramePageName = aFrame->ComputePageValue(autoValue);
+}
+
nsresult nsCSSFrameConstructor::ReplicateFixedFrames(
nsPageContentFrame* aParentFrame) {
// Now deal with fixed-pos things.... They should appear on all pages,
@@ -8743,15 +8668,14 @@ void nsCSSFrameConstructor::CreateNeededAnonFlexOrGridItems(
mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle(
PseudoStyleType::anonymousItem, aParentFrame->Style());
- static constexpr FrameConstructionData sBlockFormattingContextFCData(
- ToCreationFunc(NS_NewBlockFormattingContext),
- FCDATA_SKIP_FRAMESET | FCDATA_USE_CHILD_ITEMS |
- FCDATA_IS_WRAPPER_ANON_BOX);
+ static constexpr FrameConstructionData sBlockFCData(
+ ToCreationFunc(NS_NewBlockFrame), FCDATA_SKIP_FRAMESET |
+ FCDATA_USE_CHILD_ITEMS |
+ FCDATA_IS_WRAPPER_ANON_BOX);
- FrameConstructionItem* newItem = new (this)
- FrameConstructionItem(&sBlockFormattingContextFCData,
- // Use the content of our parent frame
- parentContent, wrapperStyle.forget(), true);
+ // Use the content of our parent frame
+ auto* newItem = new (this) FrameConstructionItem(
+ &sBlockFCData, parentContent, wrapperStyle.forget(), true);
newItem->mIsAllInline =
newItem->mComputedStyle->StyleDisplay()->IsInlineOutsideStyle();