Bug 1404167: Properly update the styles of first-letter childs of anon boxes. r=bz
☠☠ backed out by 660d1264adc6 ☠ ☠
authorEmilio Cobos Álvarez <emilio@crisal.io>
Fri, 29 Sep 2017 03:49:06 +0200
changeset 383786 710b592482eea53c22ea092f5ec038524a539e9f
parent 383631 946b9c995ec331f4f96360409fd8d2fc49e46838
child 383787 3bf89af7b969d7b909abce0ef8df171a595e99b8
push id32602
push userkwierso@gmail.com
push dateFri, 29 Sep 2017 21:47:40 +0000
treeherdermozilla-central@57f68296c350 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1404167
milestone58.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1404167: Properly update the styles of first-letter childs of anon boxes. r=bz MozReview-Commit-ID: Cyxs4FxGj6B Signed-off-by: Emilio Cobos Álvarez <emilio@crisal.io>
layout/base/ServoRestyleManager.cpp
layout/generic/nsBlockFrame.cpp
layout/reftests/first-letter/1404167-1-ref.html
layout/reftests/first-letter/1404167-1.html
layout/reftests/first-letter/1404167-2-ref.html
layout/reftests/first-letter/1404167-2.html
layout/reftests/first-letter/1404167-3-ref.html
layout/reftests/first-letter/1404167-3.html
layout/reftests/first-letter/reftest.list
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -63,23 +63,26 @@ ExpectedOwnerForChild(const nsIFrame& aF
     return parent->IsViewportFrame() ?
       nullptr : FirstContinuationOrPartOfIBSplit(parent);
   }
 
   if (aFrame.IsBulletFrame()) {
     return parent;
   }
 
-  if (aFrame.IsLineFrame()) {
+  if (aFrame.IsLineFrame() || aFrame.IsLetterFrame()) {
     // A ::first-line always ends up here via its block, which is therefore the
     // right expected owner.  That block can be an
     // anonymous box.  For example, we could have a ::first-line on a columnated
     // block; the blockframe is the column-content anonymous box in that case.
     // So we don't want to end up in the code below, which steps out of anon
     // boxes.  Just return the parent of the line frame, which is the block.
+    //
+    // Ditto for ::first-letter. A first-letter always arrives here via its
+    // direct parent.
     return parent;
   }
 
   parent = FirstContinuationOrPartOfIBSplit(parent);
 
   // We've handled already anon boxes and bullet frames, so now we're looking at
   // a frame of a DOM element or pseudo. Hop through anon and line-boxes
   // generated by our DOM parent, and go find the owner frame for it.
@@ -562,27 +565,30 @@ UpdateBackdropIfNeeded(nsIFrame* aFrame,
   nsTArray<nsIFrame*> wrappersToRestyle;
   ServoRestyleState state(aStyleSet, aChangeList, wrappersToRestyle);
   aFrame->UpdateStyleOfOwnedChildFrame(backdropFrame, newContext, state);
 }
 
 static void
 UpdateFirstLetterIfNeeded(nsIFrame* aFrame, ServoRestyleState& aRestyleState)
 {
+  MOZ_ASSERT(!aFrame->IsFrameOfType(nsIFrame::eBlockFrame),
+             "You're probably duplicating work with UpdatePseudoElementStyles!");
   if (!aFrame->HasFirstLetterChild()) {
     return;
   }
 
   // We need to find the block the first-letter is associated with so we can
   // find the right element for the first-letter's style resolution.  Might as
   // well just delegate the whole thing to that block.
-  nsIFrame* block = aFrame;
+  nsIFrame* block = aFrame->GetParent();
   while (!block->IsFrameOfType(nsIFrame::eBlockFrame)) {
     block = block->GetParent();
   }
+
   static_cast<nsBlockFrame*>(block->FirstContinuation())->
     UpdateFirstLetterStyle(aRestyleState);
 }
 
 static void
 UpdateOneAdditionalStyleContext(nsIFrame* aFrame,
                                 uint32_t aIndex,
                                 ServoStyleContext& aOldContext,
@@ -633,22 +639,20 @@ UpdateAdditionalStyleContexts(nsIFrame* 
         aFrame, index++, *oldContext->AsServo(), aRestyleState);
   }
 }
 
 static void
 UpdateFramePseudoElementStyles(nsIFrame* aFrame,
                                ServoRestyleState& aRestyleState)
 {
-  // first-letter needs to be updated before first-line, because first-line can
-  // change the style of the first-letter.
-  UpdateFirstLetterIfNeeded(aFrame, aRestyleState);
-
   if (aFrame->IsFrameOfType(nsIFrame::eBlockFrame)) {
     static_cast<nsBlockFrame*>(aFrame)->UpdatePseudoElementStyles(aRestyleState);
+  } else {
+    UpdateFirstLetterIfNeeded(aFrame, aRestyleState);
   }
 
   UpdateBackdropIfNeeded(
     aFrame, aRestyleState.StyleSet(), aRestyleState.ChangeList());
 }
 
 enum class ServoPostTraversalFlags : uint32_t
 {
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -7576,16 +7576,22 @@ nsBlockFrame::ResolveBidi()
   }
 
   return nsBidiPresUtils::Resolve(this);
 }
 
 void
 nsBlockFrame::UpdatePseudoElementStyles(ServoRestyleState& aRestyleState)
 {
+  // first-letter needs to be updated before first-line, because first-line can
+  // change the style of the first-letter.
+  if (HasFirstLetterChild()) {
+    UpdateFirstLetterStyle(aRestyleState);
+  }
+
   if (nsBulletFrame* bullet = GetBullet()) {
     CSSPseudoElementType type = bullet->StyleContext()->GetPseudoType();
     RefPtr<nsStyleContext> newBulletStyle =
       ResolveBulletStyle(type, &aRestyleState.StyleSet());
     UpdateStyleOfOwnedChildFrame(bullet, newBulletStyle, aRestyleState);
   }
 
   if (nsIFrame* firstLineFrame = GetFirstLineFrame()) {
new file mode 100644
--- /dev/null
+++ b/layout/reftests/first-letter/1404167-1-ref.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<style>
+text::first-letter {
+  font-size: 3em;
+}
+text {
+  font-size: 15px;
+}
+</style>
+<svg width="500px" height="50px">
+  <text x="0" y="40">The first-letter size should be 45px</text>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/first-letter/1404167-1.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<style>
+text::first-letter {
+  font-size: 3em;
+}
+text {
+  font-size: 10px;
+}
+</style>
+<svg width="500px" height="50px">
+  <text x="0" y="40">The first-letter size should be 45px</text>
+</svg>
+<script>
+  document.body.offsetTop;
+  document.querySelector('text').style.fontSize = "15px";
+</script>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/first-letter/1404167-2-ref.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<style>
+td::first-letter {
+  border: inherit;
+}
+</style>
+<table>
+  <tr>
+    <td style="border: 10px solid green">
+      This text should have a green border on the first letter.
+    </td>
+  </tr>
+</table>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/first-letter/1404167-2.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<style>
+td::first-letter {
+  border: inherit;
+}
+</style>
+<table>
+  <tr>
+    <td style="border: 10px solid red">
+      This text should have a green border on the first letter.
+    </td>
+  </tr>
+</table>
+<script>
+document.body.offsetTop;
+document.querySelector('td').style.borderColor = "green";
+document.body.offsetTop;
+</script>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/first-letter/1404167-3-ref.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<style>
+fieldset::first-letter {
+  border: inherit;
+}
+</style>
+<fieldset style="border: 10px solid green;">
+  This text should have a green border on the first letter.
+</fieldset>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/first-letter/1404167-3.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<style>
+fieldset::first-letter {
+  border: inherit;
+}
+</style>
+<fieldset style="border: 10px solid red;">
+  This text should have a green border on the first letter.
+</fieldset>
+<script>
+document.body.offsetTop;
+document.querySelector('fieldset').style.borderColor = "green";
+document.body.offsetTop;
+</script>
--- a/layout/reftests/first-letter/reftest.list
+++ b/layout/reftests/first-letter/reftest.list
@@ -70,8 +70,11 @@ random-if(gtkWidget) random-if(winWidget
 HTTP(..) == indic-clusters-1.html indic-clusters-1-ref.html
 == overflow-float-nooverflow.html overflow-float-nooverflow-ref.html
 == overflow-float-overflow.html overflow-float-overflow-notref.html
 == overflow-inline-nooverflow.html overflow-inline-nooverflow-ref.html
 != overflow-inline-overflow.html overflow-inline-overflow-notref.html
 == overflow-inline-overflow.html overflow-inline-overflow-ref.html
 
 == 1385656.html 1385656-ref.html
+== 1404167-1.html 1404167-1-ref.html
+== 1404167-2.html 1404167-2-ref.html
+== 1404167-3.html 1404167-3-ref.html