--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -627,16 +627,38 @@ GetIBContainingBlockFor(nsIFrame* aFrame
// post-conditions
NS_ASSERTION(parentFrame, "no normal ancestor found for ib-split frame "
"in GetIBContainingBlockFor");
NS_ASSERTION(parentFrame != aFrame, "parentFrame is actually the child frame - bogus reslt");
return parentFrame;
}
+static nsIFrame*
+GetMulticolContainingBlockFor(nsIFrame* aFrame)
+{
+ NS_PRECONDITION(aFrame->HasMulticolAncestor(),
+ "GetMulticolContainingBlockFor() should only be called on"
+ "frames inside a multicol element!");
+
+ nsIFrame* currFrame = aFrame->GetParent();
+ while (currFrame){
+ // Find the first non-multicol, non-pseudo styled parent frame
+ if (!currFrame->HasMulticolAncestor() &&
+ !currFrame->StyleContext()->GetPseudo()) {
+ break;
+ }
+ currFrame = currFrame->GetParent();
+ }
+
+ MOZ_ASSERT(currFrame, "No valid ColumnSetWrapper in multicol hierarchy!");
+
+ return currFrame;
+}
+
// This is a bit slow, but sometimes we need it.
static bool
ParentIsWrapperAnonBox(nsIFrame* aParent)
{
nsIFrame* maybeAnonBox = aParent;
if (maybeAnonBox->StyleContext()->GetPseudo() ==
nsCSSAnonBoxes::cellContent) {
// The thing that would maybe be a wrapper anon box is the cell.
@@ -678,16 +700,42 @@ FindFirstNonBlock(const nsFrameList& aLi
for (; !link.AtEnd(); link.Next()) {
if (link.NextFrame()->IsInlineOutside()) {
break;
}
}
return link;
}
+static nsFrameList::FrameLinkEnumerator
+FindFirstColumnSpan(const nsFrameList& aList)
+{
+ nsFrameList::FrameLinkEnumerator link(aList);
+ for (; !link.AtEnd(); link.Next()) {
+ if (link.NextFrame()->StyleContext()->StyleColumn()->mColumnSpan
+ == NS_STYLE_COLUMN_SPAN_ALL) {
+ break;
+ }
+ }
+ return link;
+}
+
+static nsFrameList::FrameLinkEnumerator
+FindFirstNonColumnSpan(const nsFrameList& aList)
+{
+ nsFrameList::FrameLinkEnumerator link(aList);
+ for (; !link.AtEnd(); link.Next()) {
+ if (link.NextFrame()->StyleContext()->StyleColumn()->mColumnSpan
+ != NS_STYLE_COLUMN_SPAN_ALL) {
+ break;
+ }
+ }
+ return link;
+}
+
inline void
SetInitialSingleChild(nsContainerFrame* aParent, nsIFrame* aFrame)
{
NS_PRECONDITION(!aFrame->GetNextSibling(), "Should be using a frame list");
nsFrameList temp(aFrame, aFrame);
aParent->SetInitialChildList(kPrincipalList, temp);
}
@@ -880,16 +928,21 @@ public:
nsContainerFrame* aFloatContainingBlock);
~nsFrameConstructorState();
bool HasAncestorFilter()
{
return mTreeMatchContext && mTreeMatchContext->mAncestorFilter.HasFilter();
}
+
+ // xxxNeerja - write comment
+ void OverwriteAbsoluteState(nsContainerFrame* aNewAbsoluteContainingBlock,
+ nsFrameList& aSplitAbsoluteList,
+ nsFrameConstructorSaveState& aAbsoluteSaveState);
// Function to push the existing absolute containing block state and
// create a new scope. Code that uses this function should get matching
// logic in GetAbsoluteContainingBlock.
// Also makes aNewAbsoluteContainingBlock the containing block for
// fixed-pos elements if necessary.
// aPositionedFrame is the frame whose style actually makes
// aNewAbsoluteContainingBlock a containing block. E.g. for a scrollable element
@@ -953,17 +1006,21 @@ public:
nsAbsoluteItems& GetFixedItems()
{
return mFixedPosIsAbsPos ? mAbsoluteItems : mFixedItems;
}
const nsAbsoluteItems& GetFixedItems() const
{
return mFixedPosIsAbsPos ? mAbsoluteItems : mFixedItems;
}
-
+
+ nsAbsoluteItems& GetAbsoluteItems()
+ {
+ return mAbsoluteItems;
+ }
/**
* class to automatically push and pop a pending binding in the frame
* constructor state. See nsCSSFrameConstructor::FrameConstructionItem
* mPendingBinding documentation.
*/
class PendingBindingAutoPusher;
friend class PendingBindingAutoPusher;
@@ -1122,16 +1179,55 @@ AdjustAbsoluteContainingBlock(nsContaine
}
// Always use the container's first continuation. (Inline frames can have
// non-fluid bidi continuations...)
return static_cast<nsContainerFrame*>(aContainingBlockIn->FirstContinuation());
}
void
+nsFrameConstructorState::OverwriteAbsoluteState(nsContainerFrame* aNewAbsoluteContainingBlock,
+ nsFrameList& aSplitAbsoluteList,
+ nsFrameConstructorSaveState& aSaveState)
+{
+ // First overwrite the original state and then save it in aSaveState
+ mAbsoluteItems = nsAbsoluteItems(AdjustAbsoluteContainingBlock(aNewAbsoluteContainingBlock));
+ while (aSplitAbsoluteList.NotEmpty()) {
+ mAbsoluteItems.AddChild(aSplitAbsoluteList.RemoveFirstChild());
+ }
+//
+// /* See if we're wiring the fixed-pos and abs-pos lists together. This happens iff
+// * we're a transformed element.
+// */
+// mFixedPosIsAbsPos = aNewAbsoluteContainingBlock &&
+// aNewAbsoluteContainingBlock->IsFixedPosContainingBlock();
+//
+// if (aNewAbsoluteContainingBlock) {
+// aNewAbsoluteContainingBlock->MarkAsAbsoluteContainingBlock();
+// }
+//
+// aSaveState.mItems->containingBlock = AdjustAbsoluteContainingBlock(aNewAbsoluteContainingBlock);
+// while (aSplitAbsoluteList.NotEmpty()) {
+// aSaveState.mItems->AddChild(aSplitAbsoluteList.RemoveFirstChild());
+// }
+// aSaveState.mSavedItems = aSaveState.mItems;
+// aSaveState.mChildListID = nsIFrame::kAbsoluteList;
+// aSaveState.mState = this;
+// aSaveState.mSavedFixedPosIsAbsPos = aNewAbsoluteContainingBlock &&
+// aNewAbsoluteContainingBlock->IsFixedPosContainingBlock();;
+
+ //xxxNeerja - Do we need to do this?
+// if (mFixedPosIsAbsPos) {
+// aSaveState.mSavedFixedItems = mFixedItems;
+// mFixedItems = mAbsoluteItems;
+// }
+
+}
+
+void
nsFrameConstructorState::PushAbsoluteContainingBlock(nsContainerFrame* aNewAbsoluteContainingBlock,
nsIFrame* aPositionedFrame,
nsFrameConstructorSaveState& aSaveState)
{
aSaveState.mItems = &mAbsoluteItems;
aSaveState.mSavedItems = mAbsoluteItems;
aSaveState.mChildListID = nsIFrame::kAbsoluteList;
aSaveState.mState = this;
@@ -9209,16 +9305,20 @@ nsCSSFrameConstructor::CreateContinuingF
newFrame = NS_NewXULLabelFrame(shell, styleContext);
newFrame->Init(content, aParentFrame, aFrame);
#endif
} else if (LayoutFrameType::ColumnSet == frameType) {
MOZ_ASSERT(!aFrame->IsTableCaption(),
"no support for fragmenting table captions yet");
newFrame = NS_NewColumnSetFrame(shell, styleContext, nsFrameState(0));
newFrame->Init(content, aParentFrame, aFrame);
+ } else if (LayoutFrameType::ColumnSetWrapper == frameType) {
+ newFrame =
+ CreateContinuingColumnSetWrapperFrame(shell, aPresContext, aFrame,
+ aParentFrame, content, styleContext);
} else if (LayoutFrameType::Page == frameType) {
nsContainerFrame* canvasFrame;
newFrame = ConstructPageFrame(shell, aParentFrame, aFrame, canvasFrame);
} else if (LayoutFrameType::TableWrapper == frameType) {
newFrame =
CreateContinuingOuterTableFrame(shell, aPresContext, aFrame, aParentFrame,
content, styleContext);
@@ -9643,16 +9743,21 @@ FindPreviousNonWhitespaceSibling(nsIFram
bool
nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame)
{
NS_PRECONDITION(aFrame, "Must have a frame");
NS_PRECONDITION(aFrame->GetParent(), "Frame shouldn't be root");
NS_PRECONDITION(aFrame == aFrame->FirstContinuation(),
"aFrame not the result of GetPrimaryFrame()?");
+ if (aFrame->HasMulticolAncestor()) {
+ ReframeContainingBlock(aFrame);
+ return true;
+ }
+
if (IsFramePartOfIBSplit(aFrame)) {
// The removal functions can't handle removal of an {ib} split directly; we
// need to rebuild the containing block.
#ifdef DEBUG
if (gNoisyContentUpdates) {
printf("nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval: "
"frame=");
nsFrame::ListTag(stdout, aFrame);
@@ -12158,68 +12263,370 @@ nsCSSFrameConstructor::ConstructBlock(ns
// Create column wrapper if necessary
nsContainerFrame* blockFrame = *aNewFrame;
NS_ASSERTION((blockFrame->IsBlockFrame() || blockFrame->IsDetailsFrame()),
"not a block frame nor a details frame?");
nsContainerFrame* parent = aParentFrame;
RefPtr<nsStyleContext> blockStyle = aStyleContext;
const nsStyleColumn* columns = aStyleContext->StyleColumn();
+ // Something to let us know that we are constructing blocks inside a multicol
+ // parent.
+ blockFrame->SetHasMulticolAncestor(parent->HasMulticolAncestor());
+
if (columns->mColumnCount != NS_STYLE_COLUMN_COUNT_AUTO
|| columns->mColumnWidth.GetUnit() != eStyleUnit_Auto) {
- nsContainerFrame* columnSetFrame =
- NS_NewColumnSetFrame(mPresShell, aStyleContext,
- nsFrameState(NS_FRAME_OWNS_ANON_BOXES));
-
- InitAndRestoreFrame(aState, aContent, aParentFrame, columnSetFrame);
+
+ nsContainerFrame* columnSetWrapper =
+ NS_NewColumnSetWrapperFrame(mPresShell,
+ aStyleContext,
+ nsFrameState(NS_FRAME_OWNS_ANON_BOXES));
+ InitAndRestoreFrame(aState, aContent, aParentFrame, columnSetWrapper);
+
blockStyle = mPresShell->StyleSet()->
ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::columnContent,
aStyleContext);
- parent = columnSetFrame;
- *aNewFrame = columnSetFrame;
+
+ parent = columnSetWrapper;
+ *aNewFrame = columnSetWrapper;
if (aPositionedFrameForAbsPosContainer == blockFrame) {
- aPositionedFrameForAbsPosContainer = columnSetFrame;
- }
-
- SetInitialSingleChild(columnSetFrame, blockFrame);
+ aPositionedFrameForAbsPosContainer = columnSetWrapper;
+ }
+ blockFrame->SetHasMulticolAncestor(true);
+
+ } else if (parent->HasMulticolAncestor() &&
+ columns->mColumnSpan == NS_STYLE_COLUMN_SPAN_ALL) {
+ // Column span *inside a multicol parent* must be a BFC, therefore recreate
+ // it as such.
+ nsContainerFrame* spanner =
+ NS_NewBlockFormattingContext(mPresShell, blockStyle);
+ *aNewFrame = spanner;
+ blockFrame->Destroy();
+ blockFrame = spanner;
+ blockFrame->SetHasMulticolAncestor(true);
}
blockFrame->SetStyleContextWithoutNotification(blockStyle);
InitAndRestoreFrame(aState, aContent, parent, blockFrame);
- aState.AddChild(*aNewFrame, aFrameItems, aContent, aStyleContext,
- aContentParentFrame ? aContentParentFrame :
- aParentFrame);
if (!mRootElementFrame) {
// The frame we're constructing will be the root element frame.
// Set mRootElementFrame before processing children.
mRootElementFrame = *aNewFrame;
}
+ aState.AddChild(*aNewFrame, aFrameItems, aContent, aStyleContext,
+ aContentParentFrame ? aContentParentFrame : aParentFrame);
// We should make the outer frame be the absolute containing block,
// if one is required. We have to do this because absolute
// positioning must be computed with respect to the CSS dimensions
// of the element, which are the dimensions of the outer block. But
// we can't really do that because only blocks can have absolute
// children. So use the block and try to compensate with hacks
// in nsBlockFrame::CalculateContainingBlockSizeForAbsolutes.
nsFrameConstructorSaveState absoluteSaveState;
(*aNewFrame)->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
if (aPositionedFrameForAbsPosContainer) {
- // NS_ASSERTION(aRelPos, "should have made area frame for this");
- aState.PushAbsoluteContainingBlock(*aNewFrame, aPositionedFrameForAbsPosContainer, absoluteSaveState);
+ aState.PushAbsoluteContainingBlock(*aNewFrame,
+ aPositionedFrameForAbsPosContainer,
+ absoluteSaveState);
}
// Process the child content
nsFrameItems childItems;
ProcessChildren(aState, aContent, aStyleContext, blockFrame, true,
childItems, true, aPendingBinding);
- // Set the frame's initial child list
- blockFrame->SetInitialChildList(kPrincipalList, childItems);
+ if (!DoChildrenNeedSplitting(blockFrame, childItems)) {
+ // Set the frame's initial child list
+ (*aNewFrame)->SetInitialChildList(kPrincipalList, childItems);
+
+ if ((*aNewFrame)->Type() == LayoutFrameType::ColumnSetWrapper) {
+ // Edge case where we have an empty column set wrapper. This can only
+ // happen when NewFrame and blockFrame are different and NewFrame is the
+ // wrapper and it's temporary child blockFrame has no children.
+ // In this case, we don't need the temporary child blockFrame anymore
+ // so just destroy it.
+ // Note: An empty column set wrapper is ok to have since it represents
+ // the case of an empty multicol element.
+ MOZ_ASSERT((*aNewFrame) != blockFrame,
+ "NewFrame and blockFrame must be different here!");
+ MOZ_ASSERT(childItems.IsEmpty(),
+ "NewFrame can only be columnSetWrapper when blockFrame's "
+ "childItems are empty!");
+ (*aNewFrame)->RemoveStateBits(NS_FRAME_OWNS_ANON_BOXES);
+ blockFrame->Destroy();
+ }
+ return;
+ }
+
+ ProcessColumnSpan(aState, blockFrame, aNewFrame, childItems, aFrameItems,
+ aContentParentFrame ? aContentParentFrame : aParentFrame,
+ aPositionedFrameForAbsPosContainer);
+}
+
+bool
+nsCSSFrameConstructor::DoChildrenNeedSplitting(nsContainerFrame* aFrame,
+ nsFrameItems& aChildItems)
+{
+ if (aFrame->StyleContext()->StyleColumn()->mColumnSpan
+ != NS_STYLE_COLUMN_SPAN_ALL &&
+ aChildItems.NotEmpty() &&
+ aFrame->HasMulticolAncestor() &&
+ !aFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
+ // The childen of a column-span will never need to be split because
+ // even if there is a nested column-span inside it, the nested column-span
+ // is not inside the BFC of a multicol ancestor since it's parent
+ // column-span sets up its own BFC. Therefore, the nested column-span
+ // is the same case as a column-span outside of a multicol.
+ // A frame with no children doesn't need splitting because there are
+ // no children to split.
+ // Anything under a multicol parent (other than column-spans themselves and
+ // frames with no childen as above) will need to be 'split' whether it
+ // has column-span children or not because we must recreate the frame
+ // hierarchy even for non column-span containing branches of the frame tree.
+ return true;
+ }
+
+ return false;
+}
+
+void
+nsCSSFrameConstructor::
+ProcessColumnSpan(nsFrameConstructorState& aState,
+ nsContainerFrame* aOldParent,
+ nsContainerFrame** aNewFrame,
+ nsFrameItems& aChildItems,
+ nsFrameItems& aFrameItems,
+ nsContainerFrame* aFinalParent,
+ nsIFrame* aPositionedFrameForAbsPosContainer)
+{
+ MOZ_ASSERT(aChildItems.NotEmpty(), "Child items cannot be empty here!");
+
+ nsContainerFrame* grandParent = aOldParent->GetParent();
+ MOZ_ASSERT(grandParent, "Parent cannot be empty here!");
+ nsIContent* content = aOldParent->GetContent();
+ nsStyleContext* styleContext = aOldParent->StyleContext();
+
+ if ((*aNewFrame)->Type() != LayoutFrameType::ColumnSetWrapper) {
+ MOZ_ASSERT(grandParent->Type() != LayoutFrameType::ColumnSetWrapper,
+ "Grandparent cannot be columnSetWrapper! In that case newFrame==gparent");
+
+ nsFrameItems splitChildren;
+ SplitBlocks(aState, aOldParent, aChildItems, splitChildren);
+ MOZ_ASSERT(splitChildren.NotEmpty(), "Child items cannot be empty here!");
+
+ aFrameItems.RemoveFrame(aOldParent);
+ //aOldParent is guaranteed to be a block here
+ nsBlockFrame* oldBlockParent = static_cast<nsBlockFrame*>(aOldParent);
+ oldBlockParent->TransferFloats();
+
+ *aNewFrame = static_cast<nsContainerFrame*>(splitChildren.FirstChild());
+ while (splitChildren.NotEmpty()) {
+ nsContainerFrame* currChild =
+ static_cast<nsContainerFrame*>(splitChildren.RemoveFirstChild());
+ aState.AddChild(currChild, aFrameItems, content, styleContext, aFinalParent);
+
+ if (aPositionedFrameForAbsPosContainer &&
+ aPositionedFrameForAbsPosContainer == aOldParent) {
+ nsFrameList splitAbsoluteList;
+ SplitAbsoluteListForSplitBlock(currChild, aState.GetAbsoluteItems(), splitAbsoluteList);
+ nsFrameConstructorSaveState absoluteSaveState;
+ currChild->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
+ aState.OverwriteAbsoluteState(currChild, splitAbsoluteList, absoluteSaveState);
+ aState.PushAbsoluteContainingBlock(currChild, currChild, absoluteSaveState);
+ }
+ }
+ } else {
+ nsFrameItems finalChildItems;
+ WrapNonSpannerChildrenInColumnSets(aState, aOldParent, aChildItems,
+ finalChildItems);
+ MOZ_ASSERT(finalChildItems.NotEmpty(), "Child items cannot be empty here!");
+
+ // aOldParent is guaranteed to be a block here
+ nsBlockFrame* oldBlockParent = static_cast<nsBlockFrame*>(aOldParent);
+ oldBlockParent->TransferFloats();
+
+ MoveChildrenTo(aOldParent, grandParent, finalChildItems);
+
+ // Clean up the aOldParent
+ // Note: In this case aOldParent was never added to aFrameItems
+ //aOldParent->Destroy();
+ }
+ aOldParent->Destroy();
+}
+
+void
+nsCSSFrameConstructor::SplitBlocks(nsFrameConstructorState& aState,
+ nsContainerFrame* aOldParent,
+ nsFrameList& aUnsplitChildItems,
+ nsFrameItems& aSplitChildItems,
+ nsStyleContext* aNonSpannerSC)
+{
+ MOZ_ASSERT(aUnsplitChildItems.NotEmpty(), "Child items cannot be empty here!");
+
+ nsBlockFrame* previousSplitBlock = nullptr;
+ while (aUnsplitChildItems.NotEmpty()) {
+ nsContainerFrame* grandParent = aOldParent->GetParent();
+ MOZ_ASSERT(grandParent, "Parent cannot be empty here!");
+ nsIContent* content = aOldParent->GetContent();
+ nsStyleContext* styleContext = aOldParent->StyleContext();
+
+ nsBlockFrame* splitBlock = NS_NewBlockFrame(mPresShell, styleContext);
+ InitAndRestoreFrame(aState, content, grandParent, splitBlock, false);
+ splitBlock->SetHasMulticolAncestor(aOldParent->HasMulticolAncestor());
+
+ nsFrameList::
+ FrameLinkEnumerator firstColumnSpan = FindFirstColumnSpan(aUnsplitChildItems);
+ nsFrameList splitBlockChildren = aUnsplitChildItems.ExtractHead(firstColumnSpan);
+
+ if (splitBlockChildren.IsEmpty()) {
+ // If the extracted child item list is empty, this means that the spanner
+ // is the first child/ first few children inside childItems so create
+ // a block that only contains spanners (as opposed to only non spanners)
+
+ RefPtr<nsStyleContext> spannerSC = mPresShell->StyleSet()->
+ ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::mozColumnSpanWrapper,
+ styleContext);
+ splitBlock->SetStyleContextWithoutNotification(spannerSC);
+
+ nsFrameList::
+ FrameLinkEnumerator firstNonColumnSpan = FindFirstNonColumnSpan(aUnsplitChildItems);
+ splitBlockChildren = aUnsplitChildItems.ExtractHead(firstNonColumnSpan);
+ } else if (aNonSpannerSC) {
+ splitBlock->SetStyleContextWithoutNotification(aNonSpannerSC);
+ }
+
+ // xxxNeerja - Does it make sense to copy all state bits from aOldParent
+ // to all its split children?
+ if (aOldParent->Type() == LayoutFrameType::Block) {
+ splitBlock->AddStateBits(aOldParent->GetStateBits());
+ }
+ MoveChildrenTo(aOldParent, splitBlock, splitBlockChildren);
+ aSplitChildItems.AddChild(splitBlock);
+
+ if (previousSplitBlock) {
+ SetFrameIsIBSplit(previousSplitBlock, splitBlock);
+ }
+ previousSplitBlock = splitBlock;
+ }
+ SetFrameIsIBSplit(previousSplitBlock, nullptr);
+}
+
+void
+nsCSSFrameConstructor::
+WrapNonSpannerChildrenInColumnSets(nsFrameConstructorState& aState,
+ nsContainerFrame* aOldParent,
+ nsFrameItems& aInitialChildItems,
+ nsFrameItems& aFinalChildItems)
+{
+ nsIFrame* parent = aOldParent->GetParent();
+ MOZ_ASSERT(parent, "Parent cannot be null!");
+
+ nsContainerFrame* columnSetWrapper = static_cast<nsContainerFrame*>(parent);
+ MOZ_ASSERT(columnSetWrapper->Type() == LayoutFrameType::ColumnSetWrapper,
+ "The grandparent must be a columnSetWrapper here!");
+
+ nsIContent* content = columnSetWrapper->GetContent();
+ nsStyleContext* styleContext = columnSetWrapper->StyleContext();
+
+ RefPtr<nsStyleContext> columnSetStyle = mPresShell->StyleSet()->
+ ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::mozColumnSet,
+ styleContext);
+
+ RefPtr<nsStyleContext> blockStyle = mPresShell->StyleSet()->
+ ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::columnContent,
+ styleContext);
+
+ while (aInitialChildItems.NotEmpty()) {
+ nsFrameList::
+ FrameLinkEnumerator firstColumnSpan = FindFirstColumnSpan(aInitialChildItems);
+ nsFrameList children = aInitialChildItems.ExtractHead(firstColumnSpan);
+
+ if (children.IsEmpty()) {
+ // If the extracted child item list is empty, this means that the spanner
+ // is the first child/ first few children inside childItems
+ nsFrameList::FrameLinkEnumerator firstNonColumnSpan =
+ FindFirstNonColumnSpan(aInitialChildItems);
+ children = aInitialChildItems.ExtractHead(firstNonColumnSpan);
+ aFinalChildItems.AppendFrames(columnSetWrapper, children);
+ continue;
+ }
+
+ nsContainerFrame* columnSetFrame =
+ NS_NewColumnSetFrame(mPresShell, columnSetStyle,
+ nsFrameState(NS_FRAME_OWNS_ANON_BOXES));
+ InitAndRestoreFrame(aState, content, columnSetWrapper, columnSetFrame);
+
+ nsBlockFrame* blockFrame = NS_NewBlockFrame(mPresShell, blockStyle);
+ InitAndRestoreFrame(aState, content, columnSetFrame, blockFrame);
+ blockFrame->AddStateBits(aOldParent->GetStateBits());
+
+ MoveChildrenTo(aOldParent, blockFrame, children);
+ SetInitialSingleChild(columnSetFrame, blockFrame);
+
+ // Setting parent to columnSetWrapper is unnecessary here because
+ // MoveChildrenTo (later on) will reparent the finalchildList
+ aFinalChildItems.AppendFrame(columnSetWrapper, columnSetFrame);
+ }
+
+ // Note: Because of this function, column-span wrappers and ColumnSetFrame
+ // wrappers are not ib-siblings of each other since we create columnSetFrames
+ // as one additional wrapper around non-spanning elements and this would upset
+ // the IB-sibling chain.
+}
+
+void
+nsCSSFrameConstructor::SplitAbsoluteListForSplitBlock(nsContainerFrame* aSplitFrame,
+ nsAbsoluteItems& aOriginalAbsoluteList,
+ nsFrameList& aSplitAbsoluteList)
+{
+ for (nsIFrame* currAbsoluteFrame = aOriginalAbsoluteList.FirstChild(); currAbsoluteFrame != nullptr;) {
+ nsIFrame* placeholder = currAbsoluteFrame->GetPlaceholderFrame();
+ if (placeholder) {
+ // Check if this placeholder is a descendent of aSplitFrame, if it is then move its OOF
+ // into the splitAbsoluteList
+ nsIFrame* parent = placeholder->GetParent();
+ while (parent && parent != aSplitFrame) {
+ parent = parent->GetParent();
+ }
+ if (parent) {
+ nsIFrame* nextAbsoluteFrame = currAbsoluteFrame->GetNextSibling();
+ aOriginalAbsoluteList.RemoveFrame(currAbsoluteFrame);
+
+ aSplitAbsoluteList.AppendFrame(aSplitFrame, currAbsoluteFrame);
+ currAbsoluteFrame = nextAbsoluteFrame;
+ }
+ } else {
+ NS_WARNING("An OOF exists with a null placeholder!");
+ }
+ }
+}
+
+nsIFrame*
+nsCSSFrameConstructor::CreateContinuingColumnSetWrapperFrame(nsIPresShell* aPresShell,
+ nsPresContext* aPresContext,
+ nsIFrame* aFrame,
+ nsContainerFrame* aParentFrame,
+ nsIContent* aContent,
+ nsStyleContext* aStyleContext)
+{
+ nsContainerFrame* columnSetWrapper =
+ NS_NewColumnSetWrapperFrame(aPresShell, aStyleContext, nsFrameState(0));
+ columnSetWrapper->Init(aContent, aParentFrame, aFrame);
+
+ nsFrameItems newChildFrames;
+ nsIFrame* childFrame = aFrame->PrincipalChildList().FirstChild();
+ if (childFrame) {
+ nsIFrame* continuingFrame =
+ CreateContinuingFrame(aPresContext, childFrame, columnSetWrapper);
+ newChildFrames.AddChild(continuingFrame);
+ }
+ columnSetWrapper->SetInitialChildList(kPrincipalList, newChildFrames);
+ return columnSetWrapper;
}
nsIFrame*
nsCSSFrameConstructor::ConstructInline(nsFrameConstructorState& aState,
FrameConstructionItem& aItem,
nsContainerFrame* aParentFrame,
const nsStyleDisplay* aDisplay,
nsFrameItems& aFrameItems)
@@ -12303,16 +12710,19 @@ nsCSSFrameConstructor::ConstructInline(n
newFrame->AddStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
if (positioned) {
// Relatively positioned frames becomes a container for child
// frames that are positioned
aState.PushAbsoluteContainingBlock(newFrame, newFrame, absoluteSaveState);
}
+ // Mark if this inline is under a multicol element
+ newFrame->SetHasMulticolAncestor(aParentFrame->HasMulticolAncestor());
+
// Process the child content
nsFrameItems childItems;
ConstructFramesFromItemList(aState, aItem.mChildItems, newFrame,
/* aParentIsWrapperAnonBox = */ false,
childItems);
nsFrameList::FrameLinkEnumerator firstBlockEnumerator(childItems);
if (!aItem.mIsAllInline) {
@@ -12352,17 +12762,17 @@ nsCSSFrameConstructor::CreateIBSiblings(
bool aIsPositioned,
nsFrameItems& aChildItems,
nsFrameItems& aSiblings)
{
nsIContent* content = aInitialInline->GetContent();
nsStyleContext* styleContext = aInitialInline->StyleContext();
nsContainerFrame* parentFrame = aInitialInline->GetParent();
- // Resolve the right style context for our anonymous blocks.
+ // Resolve the right style context for our non-spanner anonymous blocks.
// The distinction in styles is needed because of CSS 2.1, section
// 9.2.1.1, which says:
// When such an inline box is affected by relative positioning, any
// resulting translation also affects the block-level box contained
// in the inline box.
RefPtr<nsStyleContext> blockSC = mPresShell->StyleSet()->
ResolveInheritingAnonymousBoxStyle(nsCSSAnonBoxes::mozBlockInsideInlineWrapper,
styleContext);
@@ -12371,32 +12781,35 @@ nsCSSFrameConstructor::CreateIBSiblings(
static_cast<nsContainerFrame*>(aInitialInline->FirstContinuation());
do {
// On entry to this loop aChildItems is not empty and the first frame in it
// is block-level.
NS_PRECONDITION(aChildItems.NotEmpty(), "Should have child items");
NS_PRECONDITION(!aChildItems.FirstChild()->IsInlineOutside(),
"Must have list starting with block");
- // The initial run of blocks belongs to an anonymous block that we create
- // right now. The anonymous block will be the parent of these block
- // children of the inline.
- nsBlockFrame* blockFrame = NS_NewBlockFrame(mPresShell, blockSC);
- InitAndRestoreFrame(aState, content, parentFrame, blockFrame, false);
-
// Find the first non-block child which defines the end of our block kids
// and the start of our next inline's kids
nsFrameList::FrameLinkEnumerator firstNonBlock =
FindFirstNonBlock(aChildItems);
nsFrameList blockKids = aChildItems.ExtractHead(firstNonBlock);
- MoveChildrenTo(aInitialInline, blockFrame, blockKids);
-
- SetFrameIsIBSplit(lastNewInline, blockFrame);
- aSiblings.AddChild(blockFrame);
+ // The initial run of blocks need to be split into runs of blocks with
+ // and without column-span:all and wrapped with anonymous blocks.
+ // This is needed because blocks with column-span:all must be
+ // given an anonymous block wrapper with a pseudo style to distinguish
+ // them from regular blocks so we can perform column-span
+ // related splitting later, if needed.
+ nsFrameItems splitBlocks;
+ SplitBlocks(aState, aInitialInline, blockKids, splitBlocks, blockSC);
+ MOZ_ASSERT(splitBlocks.NotEmpty(), "List of split blocks cannot be empty!");
+
+ SetFrameIsIBSplit(lastNewInline,
+ static_cast<nsContainerFrame*>(splitBlocks.FirstChild()));
+ aSiblings.AppendFrames(parentFrame, splitBlocks);
// Now grab the initial inlines in aChildItems and put them into an inline
// frame.
nsInlineFrame* inlineFrame = NS_NewInlineFrame(mPresShell, styleContext);
InitAndRestoreFrame(aState, content, parentFrame, inlineFrame, false);
inlineFrame->AddStateBits(NS_FRAME_MAY_HAVE_GENERATED_CONTENT |
NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
if (aIsPositioned) {
@@ -12406,17 +12819,19 @@ nsCSSFrameConstructor::CreateIBSiblings(
if (aChildItems.NotEmpty()) {
nsFrameList::FrameLinkEnumerator firstBlock(aChildItems);
FindFirstBlock(firstBlock);
nsFrameList inlineKids = aChildItems.ExtractHead(firstBlock);
MoveChildrenTo(aInitialInline, inlineFrame, inlineKids);
}
- SetFrameIsIBSplit(blockFrame, inlineFrame);
+ inlineFrame->SetHasMulticolAncestor(aInitialInline->HasMulticolAncestor());
+ SetFrameIsIBSplit(static_cast<nsContainerFrame*>(aSiblings.LastChild()),
+ inlineFrame);
aSiblings.AddChild(inlineFrame);
lastNewInline = inlineFrame;
} while (aChildItems.NotEmpty());
SetFrameIsIBSplit(lastNewInline, nullptr);
}
void
@@ -12812,16 +13227,21 @@ nsCSSFrameConstructor::WipeContainingBlo
RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async);
return true;
}
}
// Now we have several cases involving {ib} splits. Put them all in a
// do/while with breaks to take us to the "go and reconstruct" code.
do {
+ if (aFrame->HasMulticolAncestor() ||
+ aFrame->Type() == LayoutFrameType::ColumnSetWrapper) {
+ // Need to go ahead and reconstruct.
+ break;
+ }
if (IsInlineFrame(aFrame)) {
if (aItems.AreAllItemsInline()) {
// We can just put the kids in.
return false;
}
if (!IsFramePartOfIBSplit(aFrame)) {
// Need to go ahead and reconstruct.
@@ -12874,21 +13294,22 @@ nsCSSFrameConstructor::WipeContainingBlo
// enforces that the root is display:none, display:table, or display:block.
// Note that walking up "too far" is OK in terms of correctness, even if it
// might be a little inefficient. This is why we walk out of all
// pseudo-frames -- telling which ones are or are not OK to walk out of is
// too hard (and I suspect that we do in fact need to walk out of all of
// them).
while (IsFramePartOfIBSplit(aContainingBlock) ||
aContainingBlock->IsInlineOutside() ||
- aContainingBlock->StyleContext()->GetPseudo()) {
+ aContainingBlock->StyleContext()->GetPseudo() ||
+ aContainingBlock->HasMulticolAncestor()) {
aContainingBlock = aContainingBlock->GetParent();
NS_ASSERTION(aContainingBlock,
- "Must have non-inline, non-ib-split, non-pseudo frame as "
- "root (or child of root, for a table root)!");
+ "Must have non-inline, non-ib-split, non-pseudo, non-multicol"
+ " frame as root (or child of root, for a table root)!");
}
// Tell parent of the containing block to reformulate the
// entire block. This is painful and definitely not optimal
// but it will *always* get the right answer.
nsIContent* blockContent = aContainingBlock->GetContent();
#ifdef DEBUG
@@ -12921,17 +13342,22 @@ nsCSSFrameConstructor::ReframeContaining
if (mPresShell->IsReflowLocked()) {
// don't ReframeContainingBlock, this will result in a crash
// if we remove a tree that's in reflow - see bug 121368 for testcase
NS_ERROR("Atemptted to nsCSSFrameConstructor::ReframeContainingBlock during a Reflow!!!");
return;
}
// Get the first "normal" ancestor of the target frame.
- nsIFrame* containingBlock = GetIBContainingBlockFor(aFrame);
+ nsIFrame* containingBlock = nullptr;
+ if (aFrame->HasMulticolAncestor()) {
+ containingBlock = GetMulticolContainingBlockFor(aFrame);
+ } else {
+ containingBlock = GetIBContainingBlockFor(aFrame);
+ }
if (containingBlock) {
// From here we look for the containing block in case the target
// frame is already a block (which can happen when an inline frame
// wraps some of its content in an anonymous block; see
// ConstructInline)
// NOTE: We used to get the FloatContainingBlock here, but it was often wrong.
// GetIBContainingBlock works much better and provides the correct container in all cases
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -34,16 +34,17 @@ struct nsGenConInitializer;
class nsContainerFrame;
class nsFirstLineFrame;
class nsFirstLetterFrame;
class nsICSSAnonBoxPseudo;
class nsIDocument;
class nsPageContentFrame;
struct PendingBinding;
class nsGenericDOMDataNode;
+struct nsAbsoluteItems;
class nsFrameConstructorState;
namespace mozilla {
namespace dom {
class FlattenedChildIterator;
@@ -1916,16 +1917,74 @@ private:
bool ShouldHaveFirstLineStyle(nsIContent* aContent,
nsStyleContext* aStyleContext);
void ShouldHaveSpecialBlockStyle(nsIContent* aContent,
nsStyleContext* aStyleContext,
bool* aHaveFirstLetterStyle,
bool* aHaveFirstLineStyle);
+ /**
+ * This method includes all column-span related implementation
+ */
+ void ProcessColumnSpan(nsFrameConstructorState& aState,
+ nsContainerFrame* aOldParent,
+ nsContainerFrame** aNewFrame,
+ nsFrameItems& aChildItems,
+ nsFrameItems& aFrameItems,
+ nsContainerFrame* aFinalParent,
+ nsIFrame* aPositionedFrameForAbsPosContainer);
+
+ /**
+ * Checks to see if aFrame is part of a multicol frame heirarchy. If yes,
+ * and aFrame is not a colum-span then returns true since aChildItems will
+ * need to be split via nsCSSFrameConstructor::SplitBlocks (Unless aChildItems
+ * is an empty list in which case we return false)
+ */
+ bool DoChildrenNeedSplitting(nsContainerFrame* aFrame,
+ nsFrameItems& aChildItems);
+
+ /**
+ * Takes aUnsplitChildItems and reparents consecutive runs of column-span and
+ * non-column span blocks into an anonymous block wrapper. The parent of this
+ * wrapper becomes the original block's grand parent (i.e. it is pushed one
+ * level up in the frame hierarchy).
+ * Each column-span wrapper is given an appropriate style context and each
+ * non-column-span wrapper is either given the parent's style context or
+ * aNonSpannerSC if it exists. It also sets IB-split bits here.
+ * We refer to this process as 'splitting'. The list of wrapped children
+ * is returned as aSplitChildItems.
+ */
+ void SplitBlocks(nsFrameConstructorState& aState,
+ nsContainerFrame* aOldParent,
+ nsFrameList& aUnsplitChildItems,
+ nsFrameItems& aSplitChildItems,
+ nsStyleContext* aNonSpannerSC = nullptr);
+
+ /**
+ * Create ColumnSetFrames around any consecutive non-spanning elements
+ * present in aInitialChildItems. Let the spanning items stay as is and return
+ * this new list in aFinalChildItems.
+ */
+ void WrapNonSpannerChildrenInColumnSets(nsFrameConstructorState& aState,
+ nsContainerFrame* aOldParent,
+ nsFrameItems& aInitialChildItems,
+ nsFrameItems& aFinalChildItems);
+
+ void SplitAbsoluteListForSplitBlock(nsContainerFrame* aSplitFrame,
+ nsAbsoluteItems& aOriginalAbsoluteList,
+ nsFrameList& aSplitAbsoluteList);
+
+ nsIFrame* CreateContinuingColumnSetWrapperFrame(nsIPresShell* aPresShell,
+ nsPresContext* aPresContext,
+ nsIFrame* aFrame,
+ nsContainerFrame* aParentFrame,
+ nsIContent* aContent,
+ nsStyleContext* aStyleContext);
+
// |aContentParentFrame| should be null if it's really the same as
// |aParentFrame|.
// @param aFrameItems where we want to put the block in case it's in-flow.
// @param aNewFrame an in/out parameter. On input it is the block to be
// constructed. On output it is reset to the outermost
// frame constructed (e.g. if we need to wrap the block in an
// nsColumnSetFrame.
// @param aParentFrame is the desired parent for the (possibly wrapped)
--- a/layout/generic/FrameTypeList.h
+++ b/layout/generic/FrameTypeList.h
@@ -13,16 +13,17 @@ FRAME_TYPE(Block)
FRAME_TYPE(Box)
FRAME_TYPE(Br)
FRAME_TYPE(Bullet)
FRAME_TYPE(BCTableCell)
FRAME_TYPE(Canvas)
FRAME_TYPE(CheckboxRadio)
FRAME_TYPE(ColorControl)
FRAME_TYPE(ColumnSet)
+FRAME_TYPE(ColumnSetWrapper)
FRAME_TYPE(ComboboxControl)
FRAME_TYPE(ComboboxDisplay)
FRAME_TYPE(Deck)
FRAME_TYPE(DateTimeControl)
FRAME_TYPE(Details)
FRAME_TYPE(FieldSet)
FRAME_TYPE(FlexContainer)
FRAME_TYPE(FrameSet)
--- a/layout/generic/moz.build
+++ b/layout/generic/moz.build
@@ -132,16 +132,17 @@ UNIFIED_SOURCES += [
'MathMLTextRunFactory.cpp',
'nsAbsoluteContainingBlock.cpp',
'nsBackdropFrame.cpp',
'nsBlockFrame.cpp',
'nsBlockReflowContext.cpp',
'nsBulletFrame.cpp',
'nsCanvasFrame.cpp',
'nsColumnSetFrame.cpp',
+ 'nsColumnSetWrapperFrame.cpp',
'nsContainerFrame.cpp',
'nsFirstLetterFrame.cpp',
'nsFlexContainerFrame.cpp',
'nsFloatManager.cpp',
'nsFontInflationData.cpp',
'nsFrame.cpp',
'nsFrameList.cpp',
'nsFrameSelection.cpp',
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -952,16 +952,52 @@ nsBlockFrame::GetPrefWidthTightBounds(gf
}
}
}
data.ForceBreak();
return NS_OK;
}
+void
+nsBlockFrame::UpdateStyleOfOwnedAnonBoxesForColumnSpanSplit(
+ mozilla::ServoRestyleState& aRestyleState) {
+ MOZ_ASSERT(StyleContext()->StyleColumn()->mColumnSpan ==
+ NS_STYLE_COLUMN_SPAN_ALL, "Why call this if we are not the column span?");
+
+ nsIFrame* blockFrame = GetProperty(nsIFrame::IBSplitPrevSibling());
+ if (!blockFrame) {
+ // If this column-span is not an IB-split sibling then no need to restyle it?
+ return;
+ }
+
+ // The later blocks need to get original parent's style.
+ ServoStyleContext* originalStyle = blockFrame->StyleContext()->AsServo();
+
+ // The anonymous block's style inherits from the original parent
+ RefPtr<ServoStyleContext> newContext =
+ aRestyleState.StyleSet().ResolveInheritingAnonymousBoxStyle(
+ nsCSSAnonBoxes::mozColumnSpanWrapper, originalStyle);
+
+ MOZ_ASSERT(!GetPrevContinuation(), "Must be first continuation");
+ MOZ_ASSERT(StyleContext()->GetPseudo() == nsCSSAnonBoxes::mozColumnSpanWrapper,
+ "Unexpected kind of style context");
+
+ for (nsIFrame* cont = this; cont; cont = cont->GetNextContinuation()) {
+ cont->SetStyleContext(newContext);
+ }
+
+ nsIFrame* nextSibling = GetProperty(nsIFrame::IBSplitSibling());
+ if (nextSibling) {
+ for (nsIFrame* cont = nextSibling; cont; cont = cont->GetNextContinuation()) {
+ cont->SetStyleContext(originalStyle);
+ }
+ }
+}
+
/**
* Return whether aNewAvailableSpace is smaller *on either side*
* (inline-start or inline-end) than aOldAvailableSpace, so that we know
* if we need to redo layout on an line, replaced block, or block
* formatting context, because its height (which we used to compute
* aNewAvailableSpace) caused it to intersect additional floats.
*/
static bool
@@ -5634,16 +5670,53 @@ nsBlockFrame::UpdateFirstLetterStyle(Ser
aRestyleState.StyleSet().ResolveStyleForText(textFrame->GetContent(),
firstLetterStyle->AsServo());
textFrame->SetStyleContext(firstTextStyle);
// We don't need to update style for textFrame's continuations: it's already
// set up to inherit from parentStyle, which is what we want.
}
+void
+nsBlockFrame::TransferFloats()
+{
+ // Remember the next sibling here because RemoveFloat() later resets
+ // the sibling chain.
+ nsIFrame* currFloat = mFloats.FirstChild();
+ nsIFrame* nextFloat = nullptr;
+ if (currFloat) {
+ nextFloat = currFloat->GetNextSibling();
+ }
+ while (currFloat) {
+ nsIFrame* placeholder = currFloat->GetPlaceholderFrame();
+ if (placeholder) {
+ // Find the topmost block parent this placeholder belongs to
+ nsIFrame* finalParent = placeholder->GetParent();
+ while (!finalParent->IsFloatContainingBlock()) {
+ finalParent = finalParent->GetParent();
+ }
+
+ RemoveFloat(currFloat);
+
+ // Add this float to the float list of its new and final parent
+ nsBlockFrame* finalBlockParent = static_cast<nsBlockFrame*>(finalParent);
+ currFloat->SetParent(finalBlockParent);
+ nsFrameList temp(currFloat, currFloat);
+ finalBlockParent->AppendFrames(nsIFrame::kFloatList, temp);
+
+ currFloat = nextFloat;
+ if (nextFloat) {
+ nextFloat = nextFloat->GetNextSibling();
+ }
+ } else {
+ NS_WARNING("An OOF exists with a null placeholder!");
+ }
+ }
+}
+
static nsIFrame*
FindChildContaining(nsBlockFrame* aFrame, nsIFrame* aFindFrame)
{
NS_ASSERTION(aFrame, "must have frame");
nsIFrame* child;
while (true) {
nsIFrame* block = aFrame;
do {
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -289,16 +289,21 @@ public:
nscoord GetPrefISize(gfxContext *aRenderingContext) override;
nsRect ComputeTightBounds(DrawTarget* aDrawTarget) const override;
nsresult GetPrefWidthTightBounds(gfxContext* aContext,
nscoord* aX,
nscoord* aXMost) override;
+ // Restyles the block wrappers around our column spans.
+ // This will only be called when such wrappers in fact exist.
+ void UpdateStyleOfOwnedAnonBoxesForColumnSpanSplit(
+ mozilla::ServoRestyleState& aRestyleState);
+
/**
* Compute the final block size of this frame.
*
* @param aReflowInput Data structure passed from parent during reflow.
* @param aReflowStatus A pointer to the reflow status for when we're finished
* doing reflow. this will get set appropriately if the block-size
* causes us to exceed the current available (page) block-size.
* @param aContentBSize The block-size of content, precomputed outside of this
@@ -411,16 +416,18 @@ public:
* etc, but _not_ first-letter).
*/
void UpdatePseudoElementStyles(mozilla::ServoRestyleState& aRestyleState);
// Update our first-letter styles during stylo post-traversal. This needs to
// be done at a slightly different time than our other pseudo-elements.
void UpdateFirstLetterStyle(mozilla::ServoRestyleState& aRestyleState);
+ void TransferFloats();
+
protected:
explicit nsBlockFrame(nsStyleContext* aContext, ClassID aID = kClassID)
: nsContainerFrame(aContext, aID)
, mMinWidth(NS_INTRINSIC_WIDTH_UNKNOWN)
, mPrefWidth(NS_INTRINSIC_WIDTH_UNKNOWN)
{
#ifdef DEBUG
InitDebugFlags();
--- a/layout/generic/nsBlockReflowContext.cpp
+++ b/layout/generic/nsBlockReflowContext.cpp
@@ -290,16 +290,20 @@ nsBlockReflowContext::ReflowBlock(const
mSpace.BSize(mWritingMode) -
usedMargin.BStartEnd(mWritingMode));
tI = space.LineLeft(mWritingMode, mContainerSize);
tB = mBCoord;
if ((mFrame->GetStateBits() & NS_BLOCK_FLOAT_MGR) == 0)
aFrameRI.mBlockDelta =
mOuterReflowInput.mBlockDelta + mBCoord - aLine->BStart();
+
+ // XXXneerja - temporary fix for margin related bug
+ // Parent doesn't pass correct ISize!!
+ //aFrameRI.AvailableISize() = space.ISize(mWritingMode);
}
#ifdef DEBUG
mMetrics.ISize(mWritingMode) = nscoord(0xdeadbeef);
mMetrics.BSize(mWritingMode) = nscoord(0xdeadbeef);
#endif
mOuterReflowInput.mFloatManager->Translate(tI, tB);
new file mode 100644
--- /dev/null
+++ b/layout/generic/nsColumnSetWrapperFrame.cpp
@@ -0,0 +1,190 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* rendering wrapper object for css3 multi-column layout */
+
+
+#include "nsColumnSetWrapperFrame.h"
+
+using namespace mozilla;
+
+nsContainerFrame*
+NS_NewColumnSetWrapperFrame(nsIPresShell* aPresShell,
+ nsStyleContext* aContext,
+ nsFrameState aStateFlags)
+{
+ nsColumnSetWrapperFrame* frame =
+ new (aPresShell) nsColumnSetWrapperFrame(aContext);
+ frame->AddStateBits(aStateFlags | NS_BLOCK_MARGIN_ROOT);
+ return frame;
+}
+
+NS_IMPL_FRAMEARENA_HELPERS(nsColumnSetWrapperFrame)
+
+nsColumnSetWrapperFrame::nsColumnSetWrapperFrame(nsStyleContext* aContext)
+: nsContainerFrame(aContext, kClassID)
+{
+}
+
+nscoord
+nsColumnSetWrapperFrame::GetMinISize(gfxContext* aRenderingContext)
+{
+ nscoord minISize = 0;
+ DISPLAY_MIN_WIDTH(this, minISize);
+
+ for (nsIFrame* childFrame : mFrames) {
+ nscoord childMinISize =
+ nsLayoutUtils::IntrinsicForContainer(aRenderingContext, childFrame,
+ nsLayoutUtils::MIN_ISIZE);
+ minISize = std::max(minISize, childMinISize);
+ }
+ return minISize;
+}
+
+nscoord
+nsColumnSetWrapperFrame::GetPrefISize(gfxContext* aRenderingContext)
+{
+ nscoord prefISize = 0;
+ DISPLAY_PREF_WIDTH(this, prefISize);
+
+ for (nsIFrame* childFrame : mFrames) {
+ nscoord childPrefISize =
+ nsLayoutUtils::IntrinsicForContainer(aRenderingContext, childFrame,
+ nsLayoutUtils::PREF_ISIZE);
+ prefISize = std::max(prefISize, childPrefISize);
+ }
+ return prefISize;
+}
+
+void
+nsColumnSetWrapperFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
+ const nsDisplayListSet& aLists)
+{
+ DisplayBorderBackgroundOutline(aBuilder, aLists);
+
+ // Our children won't have backgrounds so it doesn't matter where we put them.
+ for (nsIFrame* childFrame : mFrames) {
+ BuildDisplayListForChild(aBuilder, childFrame, aLists);
+ }
+}
+
+void
+nsColumnSetWrapperFrame::AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult)
+{
+ // xxxneerja
+ // Seems like we only append the first child, is this correct?
+ if (mFrames.NotEmpty()) {
+ aResult.AppendElement(OwnedAnonBox(mFrames.FirstChild()));
+ }
+}
+
+void
+nsColumnSetWrapperFrame::Reflow(nsPresContext* aPresContext,
+ ReflowOutput& aDesiredSize,
+ const ReflowInput& aReflowInput,
+ nsReflowStatus& aStatus)
+{
+ MarkInReflow();
+ DO_GLOBAL_REFLOW_COUNT("nsColumnSetWrapperFrame");
+ DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
+ MOZ_ASSERT(aStatus.IsEmpty(), "Expecting outparam to be initially empty");
+
+ if (IsFrameTreeTooDeep(aReflowInput, aDesiredSize, aStatus)) {
+ return;
+ }
+
+ WritingMode wm = aReflowInput.GetWritingMode();
+ LogicalMargin borderPadding = aReflowInput.ComputedLogicalBorderPadding();
+ borderPadding.ApplySkipSides(GetLogicalSkipSides(&aReflowInput));
+
+ nscoord computedISize = NS_UNCONSTRAINEDSIZE;
+ nscoord availableBSize = NS_UNCONSTRAINEDSIZE;
+ if (aReflowInput.ComputedISize() != NS_UNCONSTRAINEDSIZE) {
+ computedISize = aReflowInput.ComputedISize();
+ }
+ if (aReflowInput.AvailableBSize() != NS_UNCONSTRAINEDSIZE) {
+ availableBSize = aReflowInput.AvailableBSize() - borderPadding.BStartEnd(wm);
+ }
+ LogicalSize availableSpace(wm, computedISize, availableBSize);
+ nsSize containerSize = aReflowInput.ComputedSizeAsContainerIfConstrained();
+
+ aDesiredSize.ClearSize();
+
+ LogicalPoint childOrigin(wm,
+ borderPadding.IStart(wm),
+ borderPadding.BStart(wm));
+
+ nscoord columnSpanBottomMargin = 0;
+
+ for (nsIFrame* childFrame : mFrames) {
+ nsReflowStatus childStatus;
+ WritingMode childWm = childFrame->GetWritingMode();
+ ReflowInput childReflowInput(aPresContext, aReflowInput, childFrame,
+ availableSpace);
+ ReflowOutput childDesiredSize(childWm, aDesiredSize.mFlags);
+
+ if (childFrame->StyleContext()->StyleColumn()->mColumnSpan
+ == NS_STYLE_COLUMN_SPAN_ALL) {
+ LogicalMargin computedMargin = childReflowInput.ComputedLogicalMargin();
+ childOrigin.B(childWm) += computedMargin.BStart(childWm);
+ columnSpanBottomMargin = computedMargin.BEnd(childWm);
+ aDesiredSize.BSize(wm) += computedMargin.BStartEnd(childWm);
+ } else if (columnSpanBottomMargin > 0) {
+ childOrigin.B(childWm) += columnSpanBottomMargin;
+ columnSpanBottomMargin = 0;
+ }
+
+ ReflowChild(childFrame, aPresContext, childDesiredSize, childReflowInput,
+ childWm, childOrigin, containerSize, 0, childStatus);
+
+ FinishReflowChild(childFrame, aPresContext, childDesiredSize,
+ &childReflowInput, childWm, childOrigin, containerSize, 0);
+
+ aDesiredSize.BSize(wm) += childDesiredSize.BSize(childWm);
+ aStatus.MergeCompletionStatusFrom(childStatus);
+
+ childOrigin.B(childWm) += childDesiredSize.BSize(childWm);
+ }
+
+ aDesiredSize.ISize(wm) = computedISize + borderPadding.IStartEnd(wm);
+ aDesiredSize.BSize(wm) += borderPadding.BStartEnd(wm);
+
+ if (aReflowInput.ComputedBSize() != NS_AUTOHEIGHT) {
+ aDesiredSize.BSize(wm) = aReflowInput.ComputedBSize() +
+ borderPadding.BStartEnd(wm);
+ }
+
+ // Overflow area = union(my overflow area, kids' overflow areas)
+ aDesiredSize.SetOverflowAreasToDesiredBounds();
+ for (nsIFrame* childFrame : mFrames) {
+ ConsiderChildOverflow(aDesiredSize.mOverflowAreas, childFrame);
+ }
+
+ FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowInput, aStatus, false);
+
+ NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize)
+}
+
+void
+nsColumnSetWrapperFrame::AppendFrames(ChildListID aListID,
+ nsFrameList& aFrameList)
+{
+ MOZ_CRASH("unsupported operation");
+}
+
+void
+nsColumnSetWrapperFrame::InsertFrames(ChildListID aListID,
+ nsIFrame* aPrevFrame,
+ nsFrameList& aFrameList)
+{
+ MOZ_CRASH("unsupported operation");
+}
+
+void
+nsColumnSetWrapperFrame::RemoveFrame(ChildListID aListID,
+ nsIFrame* aOldFrame)
+{
+ MOZ_CRASH("unsupported operation");
+}
new file mode 100644
--- /dev/null
+++ b/layout/generic/nsColumnSetWrapperFrame.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* rendering wrapper object for css3 multi-column layout */
+
+
+#ifndef nsColumnSetWrapperFrame_h___
+#define nsColumnSetWrapperFrame_h___
+
+#include "nsContainerFrame.h"
+
+/* This class is a wrapper for nsColumnSetFrames and column-span elements i.e.
+ * spanners. Essentially, we divide the *original* nsColumnSetFrame
+ * into multiple nsColumnSetFrames on the basis of the number and position of
+ * spanning elements.
+ * This wrapper is necessary for implementing column-span as it allows us to
+ * maintain each nsColumnSetFrame as an independent set of columns and each
+ * spanning element then becomes just a block level element.
+ */
+class nsColumnSetWrapperFrame final : public nsContainerFrame
+{
+public:
+ NS_DECL_FRAMEARENA_HELPERS(nsColumnSetWrapperFrame)
+
+ friend nsContainerFrame* NS_NewColumnSetWrapperFrame(nsIPresShell* aPresShell,
+ nsStyleContext* aContext,
+ nsFrameState aStateFlags);
+ void BuildDisplayList(nsDisplayListBuilder* aBuilder,
+ const nsDisplayListSet& aLists) override;
+
+ void AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult) override;
+
+#ifdef DEBUG_FRAME_DUMP
+ nsresult GetFrameName(nsAString& aResult) const override {
+ return MakeFrameName(NS_LITERAL_STRING("ColumnSetWrapper"), aResult);
+ }
+#endif
+
+ nscoord GetMinISize(gfxContext* aRenderingContext) override;
+ nscoord GetPrefISize(gfxContext* aRenderingContext) override;
+
+ void Reflow(nsPresContext* aPresContext,
+ ReflowOutput& aDesiredSize,
+ const ReflowInput& aReflowInput,
+ nsReflowStatus& aStatus) override;
+
+ void AppendFrames(ChildListID aListID, nsFrameList& aFrameList) override;
+
+ void InsertFrames(ChildListID aListID,
+ nsIFrame* aPrevFrame,
+ nsFrameList& aFrameList) override;
+
+ void RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame) override;
+
+private:
+ explicit nsColumnSetWrapperFrame(nsStyleContext* aContext);
+ ~nsColumnSetWrapperFrame() override
+ {
+ }
+
+};
+
+#endif /* nsColumnSetWrapperFrame_h___ */
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -349,17 +349,21 @@ nsIFrame::GetAbsoluteContainingBlock() c
}
void
nsIFrame::MarkAsAbsoluteContainingBlock()
{
MOZ_ASSERT(GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
NS_ASSERTION(!GetProperty(AbsoluteContainingBlockProperty()),
"Already has an abs-pos containing block property?");
- NS_ASSERTION(!HasAnyStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN),
+
+ // This assertion can fail in the case of a having a multicol parent because
+ // we are copying state bits as is of the original unsplit parent to the new
+ // split parent so skip this check for multicol ancestors.
+ NS_ASSERTION(HasMulticolAncestor() || !HasAnyStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN),
"Already has NS_FRAME_HAS_ABSPOS_CHILDREN state bit?");
AddStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN);
SetProperty(AbsoluteContainingBlockProperty(), new nsAbsoluteContainingBlock(GetAbsoluteListID()));
}
void
nsIFrame::MarkAsNotAbsoluteContainingBlock()
{
@@ -11079,17 +11083,24 @@ nsIFrame::DoUpdateStyleOfOwnedAnonBoxes(
}
AutoTArray<OwnedAnonBox,4> frames;
AppendDirectlyOwnedAnonBoxes(frames);
for (OwnedAnonBox& box : frames) {
if (box.mUpdateStyleFn) {
box.mUpdateStyleFn(this, box.mAnonBoxFrame, aRestyleState);
} else {
- UpdateStyleOfChildAnonBox(box.mAnonBoxFrame, aRestyleState);
+ if (box.mAnonBoxFrame->StyleContext()->StyleColumn()->mColumnSpan ==
+ NS_STYLE_COLUMN_SPAN_ALL) {
+ nsBlockFrame* blockFrame = static_cast<nsBlockFrame*>(box.mAnonBoxFrame);
+ MOZ_ASSERT(blockFrame, "This must be a valid block frame!");
+ blockFrame->UpdateStyleOfOwnedAnonBoxesForColumnSpanSplit(aRestyleState);
+ } else {
+ UpdateStyleOfChildAnonBox(box.mAnonBoxFrame, aRestyleState);
+ }
}
}
}
/* virtual */ void
nsIFrame::AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult)
{
MOZ_ASSERT(!(GetStateBits() & NS_FRAME_OWNS_ANON_BOXES));
--- a/layout/generic/nsFrameIdList.h
+++ b/layout/generic/nsFrameIdList.h
@@ -13,16 +13,17 @@ FRAME_ID(nsBlockFrame, Block, NotLeaf)
FRAME_ID(nsBox, None, NotLeaf)
FRAME_ID(nsBoxFrame, Box, NotLeaf)
FRAME_ID(nsBulletFrame, Bullet, Leaf)
FRAME_ID(nsButtonBoxFrame, Box, NotLeaf)
FRAME_ID(nsCanvasFrame, Canvas, NotLeaf)
FRAME_ID(nsCheckboxRadioFrame, CheckboxRadio, Leaf)
FRAME_ID(nsColorControlFrame, ColorControl, Leaf)
FRAME_ID(nsColumnSetFrame, ColumnSet, NotLeaf)
+FRAME_ID(nsColumnSetWrapperFrame, ColumnSetWrapper, NotLeaf)
FRAME_ID(nsComboboxControlFrame, ComboboxControl, NotLeaf)
FRAME_ID(nsComboboxDisplayFrame, ComboboxDisplay, NotLeaf)
FRAME_ID(nsContinuingTextFrame, Text, Leaf)
FRAME_ID(nsDateTimeControlFrame, DateTimeControl, NotLeaf)
FRAME_ID(nsDeckFrame, Deck, NotLeaf)
FRAME_ID(nsDocElementBoxFrame, Box, NotLeaf)
FRAME_ID(nsFieldSetFrame, FieldSet, NotLeaf)
FRAME_ID(nsFileControlFrame, Block, Leaf)
--- a/layout/generic/nsHTMLParts.h
+++ b/layout/generic/nsHTMLParts.h
@@ -105,16 +105,18 @@ NS_NewContinuingTextFrame(nsIPresShell*
nsIFrame*
NS_NewEmptyFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
inline nsIFrame*
NS_NewWBRFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) {
return NS_NewEmptyFrame(aPresShell, aContext);
}
nsContainerFrame*
+NS_NewColumnSetWrapperFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, nsFrameState aStateFlags);
+nsContainerFrame*
NS_NewColumnSetFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, nsFrameState aStateFlags);
class nsSimplePageSequenceFrame;
nsSimplePageSequenceFrame*
NS_NewSimplePageSequenceFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
class nsPageFrame;
nsPageFrame*
NS_NewPageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -628,16 +628,17 @@ public:
, mReflowRequestedForCharDataChange(false)
, mForceDescendIntoIfVisible(false)
, mBuiltDisplayList(false)
, mFrameIsModified(false)
, mHasOverrideDirtyRegion(false)
, mMayHaveWillChangeBudget(false)
, mBuiltBlendContainer(false)
, mIsPrimaryFrame(false)
+ , mHasMulticolAncestor(false)
{
mozilla::PodZero(&mOverflow);
}
nsPresContext* PresContext() const {
return StyleContext()->PresContext();
}
@@ -2072,16 +2073,34 @@ public:
/**
* Return true if this frame is the primary frame for mContent.
*/
bool IsPrimaryFrame() const { return mIsPrimaryFrame; }
void SetIsPrimaryFrame(bool aIsPrimary) { mIsPrimaryFrame = aIsPrimary; }
/**
+ * Returns if the current frame has an ancestor with column-count or
+ * column-width set.
+ */
+ bool HasMulticolAncestor() const
+ {
+ return mHasMulticolAncestor;
+ }
+
+ /**
+ * Set if the current frame has an ancestor with column-count or
+ * column-width set.
+ */
+ void SetHasMulticolAncestor(bool aHasMulticolAncestor)
+ {
+ mHasMulticolAncestor = aHasMulticolAncestor;
+ }
+
+ /**
* This call is invoked on the primary frame for a character data content
* node, when it is changed in the content tree.
*/
virtual nsresult CharacterDataChanged(CharacterDataChangeInfo* aInfo) = 0;
/**
* This call is invoked when the value of a content objects's attribute
* is changed.
@@ -4341,18 +4360,23 @@ protected:
private:
/**
* True if this is the primary frame for mContent.
*/
bool mIsPrimaryFrame : 1;
protected:
-
- // There is a 3-bit gap left here.
+ /**
+ * True if the frame has an ancestor that has either column-count or
+ * column-width defined.
+ */
+ bool mHasMulticolAncestor : 1;
+
+ // There is a 2-bit gap left here.
// Helpers
/**
* Can we stop inside this frame when we're skipping non-rendered whitespace?
* @param aForward [in] Are we moving forward (or backward) in content order.
* @param aOffset [in/out] At what offset into the frame to start looking.
* on output - what offset was reached (whether or not we found a place to stop).
* @return STOP: An appropriate offset was found within this frame,
--- a/layout/generic/nsInlineFrame.cpp
+++ b/layout/generic/nsInlineFrame.cpp
@@ -970,17 +970,19 @@ nsInlineFrame::UpdateStyleOfOwnedAnonBox
// changehint being in aChangeList is good enough. So we don't need to touch
// aChangeList at all here.
while (blockFrame) {
MOZ_ASSERT(!blockFrame->GetPrevContinuation(),
"Must be first continuation");
MOZ_ASSERT(blockFrame->StyleContext()->GetPseudo() ==
- nsCSSAnonBoxes::mozBlockInsideInlineWrapper,
+ nsCSSAnonBoxes::mozBlockInsideInlineWrapper ||
+ blockFrame->StyleContext()->GetPseudo() ==
+ nsCSSAnonBoxes::mozColumnSpanWrapper,
"Unexpected kind of style context");
// We don't want to just walk through using GetNextContinuationWithSameStyle
// here, because we want to set updated style contexts on both our
// ib-sibling blocks and inlines.
for (nsIFrame* cont = blockFrame; cont; cont = cont->GetNextContinuation()) {
cont->SetStyleContext(newContext);
}
--- a/layout/generic/nsSplittableFrame.cpp
+++ b/layout/generic/nsSplittableFrame.cpp
@@ -277,16 +277,36 @@ nsSplittableFrame::GetLogicalSkipSides(c
}
} else {
nsIFrame* nif = GetNextInFlow();
if (nif && !IS_TRUE_OVERFLOW_CONTAINER(nif)) {
skip |= eLogicalSideBitsBEnd;
}
}
+ if (GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) {
+ // All but the last part of an column-span split should skip the "bottom"
+ // side (as determined by this frame's direction) and all but the first
+ // part of such a split should skip the "top" side.
+ // But figuring out which part of the split we are involves getting
+ // our first continuation, which might be expensive. So don't bother if
+ // we already have the relevant bits set.
+ if (skip != LogicalSides(eLogicalSideBitsBBoth)) {
+ // We're missing one of the skip bits, so check whether we need to set it.
+ // Only get the first continuation once, as an optimization.
+ nsIFrame* firstContinuation = FirstContinuation();
+ if (firstContinuation->FrameIsNonLastInIBSplit()) {
+ skip |= eLogicalSideBitsBEnd;
+ }
+ if (firstContinuation->FrameIsNonFirstInIBSplit()) {
+ skip |= eLogicalSideBitsBStart;
+ }
+ }
+ }
+
return skip;
}
LogicalSides
nsSplittableFrame::PreReflowBlockLevelLogicalSkipSides() const
{
if (MOZ_UNLIKELY(IS_TRUE_OVERFLOW_CONTAINER(this))) {
return LogicalSides(mozilla::eLogicalSideBitsBBoth);
--- a/layout/painting/nsCSSRendering.cpp
+++ b/layout/painting/nsCSSRendering.cpp
@@ -522,26 +522,26 @@ JoinBoxesForBlockAxisSlice(nsIFrame* aFr
{
// Inflate the block-axis size as if our continuations were laid out
// adjacent in that axis. Note that we don't touch the inline size.
nsRect borderArea = aBorderArea;
nscoord bSize = 0;
auto wm = aFrame->GetWritingMode();
nsIFrame* f = aFrame->GetNextContinuation();
for (; f; f = f->GetNextContinuation()) {
- MOZ_ASSERT(!(f->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT),
- "anonymous ib-split block shouldn't have border/background");
+// MOZ_ASSERT(!(f->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT),
+// "anonymous ib-split block shouldn't have border/background");
bSize += f->BSize(wm);
}
(wm.IsVertical() ? borderArea.width : borderArea.height) += bSize;
bSize = 0;
f = aFrame->GetPrevContinuation();
for (; f; f = f->GetPrevContinuation()) {
- MOZ_ASSERT(!(f->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT),
- "anonymous ib-split block shouldn't have border/background");
+// MOZ_ASSERT(!(f->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT),
+// "anonymous ib-split block shouldn't have border/background");
bSize += f->BSize(wm);
}
(wm.IsVertical() ? borderArea.x : borderArea.y) -= bSize;
(wm.IsVertical() ? borderArea.width : borderArea.height) += bSize;
return borderArea;
}
/**
--- a/layout/style/nsCSSAnonBoxList.h
+++ b/layout/style/nsCSSAnonBoxList.h
@@ -57,16 +57,18 @@ CSS_ANON_BOX(mozText, ":-moz-text")
// placeholder frames for out of flows. Note that :-moz-placeholder is used for
// the pseudo-element that represents the placeholder text in <input
// placeholder="foo">, so we need a different string here.
CSS_NON_INHERITING_ANON_BOX(oofPlaceholder, ":-moz-oof-placeholder")
// nsFirstLetterFrames for content outside the ::first-letter.
CSS_ANON_BOX(firstLetterContinuation, ":-moz-first-letter-continuation")
CSS_ANON_BOX(mozBlockInsideInlineWrapper, ":-moz-block-inside-inline-wrapper")
+CSS_ANON_BOX(mozColumnSpanWrapper, ":-moz-column-span-wrapper")
+CSS_ANON_BOX(mozColumnSet, ":-moz-column-set")
CSS_WRAPPER_ANON_BOX(mozMathMLAnonymousBlock, ":-moz-mathml-anonymous-block")
CSS_ANON_BOX(mozXULAnonymousBlock, ":-moz-xul-anonymous-block")
// Framesets
CSS_NON_INHERITING_ANON_BOX(horizontalFramesetBorder, ":-moz-hframeset-border")
CSS_NON_INHERITING_ANON_BOX(verticalFramesetBorder, ":-moz-vframeset-border")
CSS_ANON_BOX(mozLineFrame, ":-moz-line-frame")
--- a/layout/style/res/ua.css
+++ b/layout/style/res/ua.css
@@ -153,17 +153,17 @@
*|*::-moz-cell-content {
display: block !important;
position: static !important;
unicode-bidi: inherit;
text-overflow: inherit;
overflow-clip-box: inherit;
}
-*|*::-moz-block-inside-inline-wrapper {
+*|*::-moz-block-inside-inline-wrapper, *|*::-moz-column-span-wrapper {
display: block !important;
/* we currently inherit from the inline that is split */
position: inherit; /* static or relative or sticky */
outline: inherit;
outline-offset: inherit;
clip-path: inherit;
filter: inherit;
mask: inherit;
@@ -178,16 +178,44 @@
to always inherit them. */
top: inherit;
left: inherit;
bottom: inherit;
right: inherit;
z-index: inherit;
}
+*|*::-moz-column-span-wrapper {
+ opacity: unset;
+ column-span: all;
+ margin-top: inherit; //TODO: remove this
+ margin-bottom: inherit; //TODO: remove this
+}
+
+*|*::-moz-column-set {
+ /* Prevent inheriting of borders on ColumnSetFrames since they are now
+ inherited by ColumnSetWrapper frame instead*/
+ display: inherit !important;
+ columns: inherit; //xxxNeerja remove longhand properties if shorthand properties are included
+ column-count: inherit;
+ column-width: inherit;
+ column-gap: inherit;
+ column-rule: inherit;
+ column-rule-color: inherit;
+ column-rule-style: inherit;
+ column-rule-width: inherit;
+ column-fill: inherit;
+/* overflow: inherit;*/
+/* font-family: inherit;*/
+/* font-size: inherit;*/
+/* line-height: inherit;*/
+ height: 100%; //xxxNeerja - remove this workaround after fix for Bug 1411422
+ width: 100%; //xxxNeerja - remove this workaround after fix for Bug 1411422
+}
+
*|*::-moz-xul-anonymous-block {
display: block ! important;
position: static ! important;
float: none ! important;
-moz-box-ordinal-group: inherit !important;
text-overflow: inherit;
overflow-clip-box: inherit;
}
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -3092,17 +3092,17 @@ pref("layout.css.font-loading-api.enable
// Should stray control characters be rendered visibly?
#ifdef RELEASE_OR_BETA
pref("layout.css.control-characters.visible", false);
#else
pref("layout.css.control-characters.visible", true);
#endif
// Is support for column-span enabled?
-pref("layout.css.column-span.enabled", false);
+pref("layout.css.column-span.enabled", true);
// Are inter-character ruby annotations enabled?
pref("layout.css.ruby.intercharacter.enabled", false);
// pref for which side vertical scrollbars should be on
// 0 = end-side in UI direction
// 1 = end-side in document/content direction
// 2 = right