Bug 1343771. Fix stylo to properly update styles on the anonymous block inside a table cell. r?emilio
MozReview-Commit-ID: 8LnPTKVxxVc
--- 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