Bug 1343771. Fix stylo to properly update styles on the anonymous block inside a table cell. r=emilio
authorBoris Zbarsky <bzbarsky@mit.edu>
Fri, 03 Mar 2017 16:14:39 -0500
changeset 345907 a1a760aee967f10e29592efe0ce8de63a12a3c28
parent 345906 53a53f671871e4d7a854bd2c9d04471dd307b533
child 345908 b866630a4183b38c2c234508b1ca3b80f51d8595
push id31451
push usercbook@mozilla.com
push dateMon, 06 Mar 2017 09:52:09 +0000
treeherdermozilla-central@7099e03837e8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemilio
bugs1343771
milestone54.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 1343771. Fix stylo to properly update styles on the anonymous block inside a table cell. r=emilio MozReview-Commit-ID: 8LnPTKVxxVc
layout/base/nsCSSFrameConstructor.cpp
layout/generic/nsFrame.cpp
layout/generic/nsFrame.h
layout/tables/nsTableCellFrame.cpp
layout/tables/nsTableCellFrame.h
layout/tables/reftests/dynamic-text-indent-table-cell-ref.html
layout/tables/reftests/dynamic-text-indent-table-cell.html
layout/tables/reftests/dynamic-text-overflow-table-cell-notref.html
layout/tables/reftests/dynamic-text-overflow-table-cell-ref.html
layout/tables/reftests/dynamic-text-overflow-table-cell.html
layout/tables/reftests/reftest-stylo.list
layout/tables/reftests/reftest.list
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -2288,16 +2288,17 @@ nsCSSFrameConstructor::ConstructTableCel
     // Warning: If you change this and add a wrapper frame around table cell
     // frames, make sure Bug 368554 doesn't regress!
     // See IsInAutoWidthTableCellForQuirk() in nsImageFrame.cpp.
     newFrame = NS_NewTableCellFrame(mPresShell, styleContext, tableFrame);
   }
 
   // Initialize the table cell frame
   InitAndRestoreFrame(aState, content, aParentFrame, newFrame);
+  newFrame->AddStateBits(NS_FRAME_OWNS_ANON_BOXES);
 
   // Resolve pseudo style and initialize the body cell frame
   RefPtr<nsStyleContext> innerPseudoStyle;
   innerPseudoStyle = mPresShell->StyleSet()->
     ResolveAnonymousBoxStyle(nsCSSAnonBoxes::cellContent, styleContext);
 
   // Create a block frame that will format the cell's content
   bool isBlock;
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -84,26 +84,28 @@
 
 #include "gfxContext.h"
 #include "nsRenderingContext.h"
 #include "nsAbsoluteContainingBlock.h"
 #include "StickyScrollContainer.h"
 #include "nsFontInflationData.h"
 #include "nsRegion.h"
 #include "nsIFrameInlines.h"
+#include "nsStyleChangeList.h"
 
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/EffectCompositor.h"
 #include "mozilla/EffectSet.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/MouseEvents.h"
+#include "mozilla/ServoStyleSet.h"
 #include "mozilla/css/ImageLoader.h"
 #include "mozilla/gfx/Tools.h"
 #include "nsPrintfCString.h"
 #include "ActiveLayerTracker.h"
 
 #include "nsITheme.h"
 #include "nsThemeConstants.h"
 
@@ -10045,16 +10047,60 @@ nsFrame::BoxReflow(nsBoxLayoutState&    
 nsBoxLayoutMetrics*
 nsFrame::BoxMetrics() const
 {
   nsBoxLayoutMetrics* metrics = Properties().Get(BoxMetricsProperty());
   NS_ASSERTION(metrics, "A box layout method was called but InitBoxMetrics was never called");
   return metrics;
 }
 
+void
+nsFrame::UpdateStyleOfChildAnonBox(nsIFrame* aChildFrame,
+                                   ServoStyleSet& aStyleSet,
+                                   nsStyleChangeList& aChangeList,
+                                   nsChangeHint aHintForThisFrame)
+{
+  MOZ_ASSERT(aChildFrame->GetParent() == this,
+             "This should only be used for children!");
+  MOZ_ASSERT(aChildFrame->GetContent() == GetContent(),
+             "What content node is it a frame for?");
+
+  // We could force the caller to pass in the pseudo, since some callers know it
+  // statically...  But this API is a bit nicer.
+  nsIAtom* pseudo = aChildFrame->StyleContext()->GetPseudo();
+  MOZ_ASSERT(nsCSSAnonBoxes::IsAnonBox(pseudo), "Child is not an anon box?");
+
+  // Anon boxes inherit from their parent; that's us.
+  RefPtr<nsStyleContext> newContext =
+    aStyleSet.ResolveAnonymousBoxStyle(pseudo, StyleContext());
+
+  // Figure out whether we have an actual change.  It's important that we do
+  // this, even though all the child's changes are due to properties it inherits
+  // from us, because it's possible that no one ever asked us for those style
+  // structs and hence changes to them aren't reflected in aHintForThisFrame at
+  // all.
+  uint32_t equalStructs, samePointerStructs; // Not used, actually.
+  nsChangeHint childHint = aChildFrame->StyleContext()->CalcStyleDifference(
+    newContext,
+    NS_HintsNotHandledForDescendantsIn(aHintForThisFrame),
+    &equalStructs,
+    &samePointerStructs);
+  if (childHint) {
+    aChangeList.AppendChange(aChildFrame, aChildFrame->GetContent(), childHint);
+  }
+
+  for (nsIFrame* kid = aChildFrame; kid; kid = kid->GetNextContinuation()) {
+    kid->SetStyleContext(newContext);
+  }
+
+  // Now that we've updated the style on aChildFrame, check whether it itself
+  // has anon boxes to deal with.
+  aChildFrame->UpdateStyleOfOwnedAnonBoxes(aStyleSet, aChangeList, childHint);
+}
+
 /* static */ void
 nsIFrame::AddInPopupStateBitToDescendants(nsIFrame* aFrame)
 {
   if (!aFrame->HasAnyStateBits(NS_FRAME_IN_POPUP) &&
       aFrame->TrackingVisibility()) {
     // Assume all frames in popups are visible.
     aFrame->IncApproximateVisibleCount();
   }
--- a/layout/generic/nsFrame.h
+++ b/layout/generic/nsFrame.h
@@ -683,16 +683,23 @@ protected:
   void GetBoxName(nsAutoString& aName) override;
 #endif
 
   nsBoxLayoutMetrics* BoxMetrics() const;
 
   // Fire DOM event. If no aContent argument use frame's mContent.
   void FireDOMEvent(const nsAString& aDOMEventName, nsIContent *aContent = nullptr);
 
+  // A helper for implementing UpdateStyleOfOwnedAnonBoxes for the specific case
+  // of the owned anon box being a child of this frame.
+  void UpdateStyleOfChildAnonBox(nsIFrame* aChildFrame,
+                                 mozilla::ServoStyleSet& aStyleSet,
+                                 nsStyleChangeList& aChangeList,
+                                 nsChangeHint aHintForThisFrame);
+
 private:
   void BoxReflow(nsBoxLayoutState& aState,
                  nsPresContext*    aPresContext,
                  ReflowOutput&     aDesiredSize,
                  nsRenderingContext* aRenderingContext,
                  nscoord aX,
                  nscoord aY,
                  nscoord aWidth,
--- a/layout/tables/nsTableCellFrame.cpp
+++ b/layout/tables/nsTableCellFrame.cpp
@@ -1099,16 +1099,27 @@ nsTableCellFrame::GetBorderWidth(Writing
 }
 
 nsIAtom*
 nsTableCellFrame::GetType() const
 {
   return nsGkAtoms::tableCellFrame;
 }
 
+void
+nsTableCellFrame::DoUpdateStyleOfOwnedAnonBoxes(ServoStyleSet& aStyleSet,
+                                                nsStyleChangeList& aChangeList,
+                                                nsChangeHint aHintForThisFrame)
+{
+  nsIFrame* kid = mFrames.FirstChild();
+  MOZ_ASSERT(kid && !kid->GetNextSibling(),
+             "Table cells should have just one child");
+  UpdateStyleOfChildAnonBox(kid, aStyleSet, aChangeList, aHintForThisFrame);
+}
+
 #ifdef DEBUG_FRAME_DUMP
 nsresult
 nsTableCellFrame::GetFrameName(nsAString& aResult) const
 {
   return MakeFrameName(NS_LITERAL_STRING("TableCell"), aResult);
 }
 #endif
 
--- a/layout/tables/nsTableCellFrame.h
+++ b/layout/tables/nsTableCellFrame.h
@@ -164,16 +164,22 @@ public:
    * content model or in the style info, and is always >= 1.
    * to get the effective row span (the actual value that applies), use GetEffectiveRowSpan()
    * @see nsTableFrame::GetEffectiveRowSpan()
    */
   virtual int32_t GetRowSpan();
 
   // there is no set row index because row index depends on the cell's parent row only
 
+  // Update the style on the block wrappers around our kids.
+  virtual void DoUpdateStyleOfOwnedAnonBoxes(
+    mozilla::ServoStyleSet& aStyleSet,
+    nsStyleChangeList& aChangeList,
+    nsChangeHint aHintForThisFrame) override;
+
   /*---------------- nsITableCellLayout methods ------------------------*/
 
   /**
    * return the cell's starting row index (starting at 0 for the first row).
    * for continued cell frames the row index is that of the cell's first-in-flow
    * and the column index (starting at 0 for the first column
    */
   NS_IMETHOD GetCellIndexes(int32_t &aRowIndex, int32_t &aColIndex) override;
new file mode 100644
--- /dev/null
+++ b/layout/tables/reftests/dynamic-text-indent-table-cell-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <table>
+    <tr>
+      <td style="text-indent: 50px">
+        Some text
+      </td>
+    </tr>
+  </table>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/tables/reftests/dynamic-text-indent-table-cell.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <table>
+    <tr>
+      <td>
+        Some text
+      </td>
+    </tr>
+  </table>
+  <script>
+    onload = function() {
+      var td = document.querySelector("td");
+      // Make sure layout has happened.
+      var width = td.offsetWidth;
+      td.style.textIndent = "50px";
+      document.documentElement.className = "";
+    }
+  </script>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/tables/reftests/dynamic-text-overflow-table-cell-notref.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<table style="table-layout: fixed; width: 130px">
+  <tr>
+    <td style="overflow: hidden; white-space: nowrap;">
+      Some long text that cannot possibly fit in 130 px, because it just can't.
+    </td>
+  </tr>
+</table>
new file mode 100644
--- /dev/null
+++ b/layout/tables/reftests/dynamic-text-overflow-table-cell-ref.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<table style="table-layout: fixed; width: 130px">
+  <tr>
+    <td style="overflow: hidden; white-space: nowrap; text-overflow: ellipsis">
+      Some long text that cannot possibly fit in 130 px, because it just can't.
+    </td>
+  </tr>
+</table>
new file mode 100644
--- /dev/null
+++ b/layout/tables/reftests/dynamic-text-overflow-table-cell.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+  <table style="table-layout: fixed; width: 130px">
+    <tr>
+      <td style="overflow: hidden; white-space: nowrap;">
+        Some long text that cannot possibly fit in 130 px, because it just can't.
+      </td>
+    </tr>
+  </table>
+  <script>
+    onload = function() {
+      var td = document.querySelector("td");
+      // Make sure layout has happened.
+      var width = td.offsetWidth;
+      td.style.textOverflow = "ellipsis";
+      document.documentElement.className = "";
+    }
+  </script>
+</html>
--- a/layout/tables/reftests/reftest-stylo.list
+++ b/layout/tables/reftests/reftest-stylo.list
@@ -3,8 +3,10 @@
 == 1220621-1a.html 1220621-1a.html
 == 1220621-1b.html 1220621-1b.html
 == 1220621-1c.html 1220621-1c.html
 == 1220621-1d.html 1220621-1d.html
 == 1220621-1e.html 1220621-1e.html
 == 1220621-1f.html 1220621-1f.html
 == 1220621-2a.html 1220621-2a.html
 == 1220621-2b.html 1220621-2b.html
+== dynamic-text-overflow-table-cell.html dynamic-text-overflow-table-cell.html
+== dynamic-text-indent-table-cell.html dynamic-text-indent-table-cell.html
--- a/layout/tables/reftests/reftest.list
+++ b/layout/tables/reftests/reftest.list
@@ -2,8 +2,11 @@
 == 1220621-1a.html 1220621-1-ref.html
 == 1220621-1b.html 1220621-1-ref.html
 == 1220621-1c.html 1220621-1-ref.html
 == 1220621-1d.html 1220621-1-ref.html
 == 1220621-1e.html 1220621-1-ref.html
 == 1220621-1f.html 1220621-1-ref.html
 == 1220621-2a.html 1220621-2-ref.html
 == 1220621-2b.html 1220621-2-ref.html
+== dynamic-text-overflow-table-cell.html dynamic-text-overflow-table-cell-ref.html
+!= dynamic-text-overflow-table-cell.html dynamic-text-overflow-table-cell-notref.html
+== dynamic-text-indent-table-cell.html dynamic-text-indent-table-cell-ref.html