From 799bc86f7c2d07c113d1dfa9bb3f2603a79fce3b Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 3 Mar 2017 15:45:40 -0500 Subject: [PATCH] Bug 1340723 part 3. Fix stylo to properly update styles on the anonymous blocks we create in a block-inside-inline situation when the style of the inline changes. r=emilio MozReview-Commit-ID: JYz6g1ZJInT --HG-- extra : rebase_source : 356785e1de38745c9ca23a04ce58a1d53dce692b --- layout/base/ServoRestyleManager.cpp | 3 + layout/base/nsCSSFrameConstructor.cpp | 1 + layout/generic/nsInlineFrame.cpp | 61 +++++++++++++++++++ layout/generic/nsInlineFrame.h | 7 +++ layout/reftests/ib-split/reftest-stylo.list | 2 + layout/reftests/ib-split/reftest.list | 2 + .../ib-split/relpos-inline-1-ref.html | 15 +++++ .../reftests/ib-split/relpos-inline-1a.html | 22 +++++++ .../reftests/ib-split/relpos-inline-1b.html | 30 +++++++++ 9 files changed, 143 insertions(+) create mode 100644 layout/reftests/ib-split/relpos-inline-1-ref.html create mode 100644 layout/reftests/ib-split/relpos-inline-1a.html create mode 100644 layout/reftests/ib-split/relpos-inline-1b.html diff --git a/layout/base/ServoRestyleManager.cpp b/layout/base/ServoRestyleManager.cpp index 76a7d9215983..7d415bb63a91 100644 --- a/layout/base/ServoRestyleManager.cpp +++ b/layout/base/ServoRestyleManager.cpp @@ -235,6 +235,9 @@ ServoRestyleManager::RecreateStyleContexts(Element* aElement, // XXX This could not always work as expected: there are kinds of content // with the first split and the last sharing style, but others not. We // should handle those properly. + // XXXbz I think the UpdateStyleOfOwnedAnonBoxes call below handles _that_ + // right, but not other cases where we happen to have different styles on + // different continuations... (e.g. first-line). for (nsIFrame* f = styleFrame; f; f = GetNextContinuationWithSameStyle(f, oldStyleContext)) { f->SetStyleContext(newContext); diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 8f44d204f5f2..0130532f99df 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -12129,6 +12129,7 @@ nsCSSFrameConstructor::ConstructInline(nsFrameConstructorState& aState, aFrameItems.AddChild(newFrame); + newFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES); CreateIBSiblings(aState, newFrame, positioned, childItems, aFrameItems); return newFrame; diff --git a/layout/generic/nsInlineFrame.cpp b/layout/generic/nsInlineFrame.cpp index 5dc9ebf0e2da..5d33979a06e3 100644 --- a/layout/generic/nsInlineFrame.cpp +++ b/layout/generic/nsInlineFrame.cpp @@ -19,8 +19,10 @@ #include "nsDisplayList.h" #include "mozilla/Likely.h" #include "SVGTextFrame.h" +#include "nsStyleChangeList.h" #include "mozilla/StyleSetHandle.h" #include "mozilla/StyleSetHandleInlines.h" +#include "mozilla/ServoStyleSet.h" #ifdef DEBUG #undef NOISY_PUSHING @@ -1021,6 +1023,65 @@ nsInlineFrame::AccessibleType() } #endif +void +nsInlineFrame::DoUpdateStyleOfOwnedAnonBoxes(ServoStyleSet& aStyleSet, + nsStyleChangeList& aChangeList, + nsChangeHint aHintForThisFrame) +{ + MOZ_ASSERT(GetStateBits() & NS_FRAME_OWNS_ANON_BOXES, + "Why did we get called?"); + MOZ_ASSERT(GetStateBits() & NS_FRAME_PART_OF_IBSPLIT, + "Why did we have the NS_FRAME_OWNS_ANON_BOXES bit set?"); + // Note: this assert _looks_ expensive, but it's cheap in all the cases when + // it passes! + MOZ_ASSERT(nsLayoutUtils::FirstContinuationOrIBSplitSibling(this) == this, + "Only the primary frame of the inline in a block-inside-inline " + "split should have NS_FRAME_OWNS_ANON_BOXES"); + MOZ_ASSERT(mContent->GetPrimaryFrame() == this, + "We should be the primary frame for our element"); + + nsPresContext* presContext = PresContext(); + // Get the FramePropertyTable up front, since we are likely to need it + // multiple times. The other option would be to just call + // nsIFrame::Properties() every time we need to do a lookup, but that does + // more pointer-chasing. + FramePropertyTable* propTable = presContext->PropertyTable(); + nsIFrame* blockFrame = propTable->Get(this, nsIFrame::IBSplitSibling()); + MOZ_ASSERT(blockFrame, "Why did we have an IB split?"); + + nsIAtom* pseudo = blockFrame->StyleContext()->GetPseudo(); + MOZ_ASSERT(pseudo == nsCSSAnonBoxes::mozAnonymousBlock || + pseudo == nsCSSAnonBoxes::mozAnonymousPositionedBlock, + "Unexpected kind of style context"); + + // The anonymous block's style inherits from ours, and we already have our new + // style context. + RefPtr newContext = + aStyleSet.ResolveAnonymousBoxStyle(pseudo, StyleContext()); + + // We're guaranteed that newContext only differs from the old style context on + // the block in things they might inherit from us. And changehint processing + // guarantees walking the continuation and ib-sibling chains, so our existing + // changehint beign 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"); + // We _could_ just walk along using GetNextContinuationWithSameStyle here, + // but it would involve going back to the first continuation every so often, + // which is a bit silly when we can just keep track of our first + // continuations. + for (nsIFrame* cont = blockFrame; cont; cont = cont->GetNextContinuation()) { + cont->SetStyleContext(newContext); + } + + nsIFrame* nextInline = propTable->Get(blockFrame, nsIFrame::IBSplitSibling()); + MOZ_ASSERT(nextInline, "There is always a trailing inline in an IB split"); + blockFrame = propTable->Get(nextInline, nsIFrame::IBSplitSibling()); + } +} + ////////////////////////////////////////////////////////////////////// // nsLineFrame implementation diff --git a/layout/generic/nsInlineFrame.h b/layout/generic/nsInlineFrame.h index 00f89065cca6..ccdbaf600fcc 100644 --- a/layout/generic/nsInlineFrame.h +++ b/layout/generic/nsInlineFrame.h @@ -116,6 +116,13 @@ public: : (!GetNextInFlow()); } + // Update the style on the block wrappers around our non-inline-outside kids. + // This will only be called when such wrappers in fact exist. + virtual void DoUpdateStyleOfOwnedAnonBoxes( + mozilla::ServoStyleSet& aStyleSet, + nsStyleChangeList& aChangeList, + nsChangeHint aHintForThisFrame) override; + protected: // Additional reflow state used during our reflow methods struct InlineReflowInput { diff --git a/layout/reftests/ib-split/reftest-stylo.list b/layout/reftests/ib-split/reftest-stylo.list index 71a018582dd3..d03929ad0dc7 100644 --- a/layout/reftests/ib-split/reftest-stylo.list +++ b/layout/reftests/ib-split/reftest-stylo.list @@ -84,3 +84,5 @@ fails == float-inside-inline-between-blocks-1.html float-inside-inline-between-b == append-to-empty-trailing-inline-1.html append-to-empty-trailing-inline-1.html == append-to-nested-split-inline-1.html append-to-nested-split-inline-1.html == append-to-nested-split-inline-1-ref.html append-to-nested-split-inline-1-ref.html +== relpos-inline-1a.html relpos-inline-1a.html +== relpos-inline-1b.html relpos-inline-1b.html diff --git a/layout/reftests/ib-split/reftest.list b/layout/reftests/ib-split/reftest.list index 779921d2100b..8c43a3727b4b 100644 --- a/layout/reftests/ib-split/reftest.list +++ b/layout/reftests/ib-split/reftest.list @@ -83,3 +83,5 @@ == append-to-empty-trailing-inline-1.html append-to-empty-trailing-inline-1-ref.html == append-to-nested-split-inline-1.html append-to-nested-split-inline-1-ref.html == append-to-nested-split-inline-1-ref.html append-to-nested-split-inline-1-noib-ref.html +== relpos-inline-1a.html relpos-inline-1-ref.html +== relpos-inline-1b.html relpos-inline-1-ref.html diff --git a/layout/reftests/ib-split/relpos-inline-1-ref.html b/layout/reftests/ib-split/relpos-inline-1-ref.html new file mode 100644 index 000000000000..074c4fc48039 --- /dev/null +++ b/layout/reftests/ib-split/relpos-inline-1-ref.html @@ -0,0 +1,15 @@ + + + + + + + All text should be offset 200px. +
Some more text
+ + diff --git a/layout/reftests/ib-split/relpos-inline-1a.html b/layout/reftests/ib-split/relpos-inline-1a.html new file mode 100644 index 000000000000..b2059bc67ef6 --- /dev/null +++ b/layout/reftests/ib-split/relpos-inline-1a.html @@ -0,0 +1,22 @@ + + + + CSS 2.1 Test Suite: handling of blocks inside inlines + + + + + + + + + All text should be offset 200px. +
Some more text
+
+ + diff --git a/layout/reftests/ib-split/relpos-inline-1b.html b/layout/reftests/ib-split/relpos-inline-1b.html new file mode 100644 index 000000000000..e9f7bd62cfad --- /dev/null +++ b/layout/reftests/ib-split/relpos-inline-1b.html @@ -0,0 +1,30 @@ + + + + CSS 2.1 Test Suite: handling of blocks inside inlines + + + + + + + + + All text should be offset 200px. +
Some more text
+
+ + +