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
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -231,16 +231,19 @@ ServoRestyleManager::RecreateStyleContex
aStyleSet->GetContext(computedValues.forget(), aParentContext, nullptr,
CSSPseudoElementType::NotPseudo, aElement);
newContext->EnsureStructsForServo(oldStyleContext);
// 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);
}
if (isTable) {
nsIFrame* primaryFrame = aElement->GetPrimaryFrame();
MOZ_ASSERT(primaryFrame->StyleContext()->GetPseudo() ==
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -12124,16 +12124,17 @@ nsCSSFrameConstructor::ConstructInline(n
// has to be chopped into several pieces, as described above.
// Grab the first inline's kids
nsFrameList firstInlineKids = childItems.ExtractHead(firstBlockEnumerator);
newFrame->SetInitialChildList(kPrincipalList, firstInlineKids);
aFrameItems.AddChild(newFrame);
+ newFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
CreateIBSiblings(aState, newFrame, positioned, childItems, aFrameItems);
return newFrame;
}
void
nsCSSFrameConstructor::CreateIBSiblings(nsFrameConstructorState& aState,
nsContainerFrame* aInitialInline,
--- a/layout/generic/nsInlineFrame.cpp
+++ b/layout/generic/nsInlineFrame.cpp
@@ -14,18 +14,20 @@
#include "nsPresContext.h"
#include "nsRenderingContext.h"
#include "nsCSSAnonBoxes.h"
#include "mozilla/RestyleManager.h"
#include "mozilla/RestyleManagerInlines.h"
#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
#endif
using namespace mozilla;
using namespace mozilla::layout;
@@ -1016,16 +1018,75 @@ nsInlineFrame::AccessibleType()
return a11y::eHTMLButtonType;
if (mContent->IsHTMLElement(nsGkAtoms::img)) // Create accessible for broken <img>
return a11y::eHyperTextType;
return a11y::eNoType;
}
#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<nsStyleContext> 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
nsFirstLineFrame*
NS_NewFirstLineFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
{
return new (aPresShell) nsFirstLineFrame(aContext);
--- a/layout/generic/nsInlineFrame.h
+++ b/layout/generic/nsInlineFrame.h
@@ -111,16 +111,23 @@ public:
bool IsLast() const {
// If the frame's bidi visual state is set, return is-last state
// else return true if it's the last continuation.
return (GetStateBits() & NS_INLINE_FRAME_BIDI_VISUAL_STATE_IS_SET)
? !!(GetStateBits() & NS_INLINE_FRAME_BIDI_VISUAL_IS_LAST)
: (!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 {
nsIFrame* mPrevFrame;
nsInlineFrame* mNextInFlow;
nsIFrame* mLineContainer;
nsLineLayout* mLineLayout;
bool mSetParentPointer; // when reflowing child frame first set its
--- a/layout/reftests/ib-split/reftest-stylo.list
+++ b/layout/reftests/ib-split/reftest-stylo.list
@@ -79,8 +79,10 @@ fails == float-inside-inline-between-blo
== ignored-margins-1a.html ignored-margins-1a.html
== ignored-margins-1b.html ignored-margins-1b.html
== ignored-margins-2a.html ignored-margins-2a.html
== ignored-margins-2b.html ignored-margins-2b.html
== trailing-inline-with-continuations-1.html trailing-inline-with-continuations-1.html
== 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
--- a/layout/reftests/ib-split/reftest.list
+++ b/layout/reftests/ib-split/reftest.list
@@ -78,8 +78,10 @@
== ignored-margins-1a.html ignored-margins-1-ref.html
== ignored-margins-1b.html ignored-margins-1-ref.html
== ignored-margins-2a.html ignored-margins-2-ref.html
== ignored-margins-2b.html ignored-margins-2-ref.html
== trailing-inline-with-continuations-1.html trailing-inline-with-continuations-1-ref.html
== 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
new file mode 100644
--- /dev/null
+++ b/layout/reftests/ib-split/relpos-inline-1-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <style>
+ span, div { position: relative; left: 200px }
+ html {
+ overflow: hidden;
+ }
+ </style>
+ </head>
+ <body>
+ <span>All text should be offset 200px.</span>
+ <div>Some more text</div>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/ib-split/relpos-inline-1a.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>CSS 2.1 Test Suite: handling of blocks inside inlines</title>
+ <link rel="author" title="Boris Zbarsky" href="mailto:bzbarsky@mit.edu" />
+ <link rel="author" title="Mozilla Corporation" href="http://mozilla.com/" />
+ <link rel="help" href="http://www.w3.org/TR/CSS21/visuren.html#anonymous-block-level"/>
+ <meta name="flags" content="" />
+ <style>
+ span { position: relative; left: 200px }
+ html {
+ overflow: hidden;
+ }
+ </style>
+ </head>
+ <body>
+ <span style="position: relative; left: 200px">
+ All text should be offset 200px.
+ <div>Some more text</div>
+ </span>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/ib-split/relpos-inline-1b.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <head>
+ <title>CSS 2.1 Test Suite: handling of blocks inside inlines</title>
+ <link rel="author" title="Boris Zbarsky" href="mailto:bzbarsky@mit.edu" />
+ <link rel="author" title="Mozilla Corporation" href="http://mozilla.com/" />
+ <link rel="help" href="http://www.w3.org/TR/CSS21/visuren.html#anonymous-block-level"/>
+ <meta name="flags" content="" />
+ <style>
+ span { position: relative }
+ html {
+ overflow: hidden;
+ }
+ </style>
+ </head>
+ <body>
+ <span style="position: relative; left: 100px">
+ All text should be offset 200px.
+ <div>Some more text</div>
+ </span>
+ <script>
+ onload = function() {
+ var s = document.querySelector("span");
+ s.offsetWidth; // flush layout
+ s.style.left = "200px";
+ document.documentElement.className = "";
+ }
+ </script>
+ </body>
+</html>