Bug 1389029 - Create custom change hint and post restyle event for rowspan, colspan attribute changes.
MozReview-Commit-ID: IwUlgDa3DAj
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -427,22 +427,22 @@ RestyleManager::ChangeHintToString(nsCha
"UpdateSubtreeOverflow", "UpdatePostTransformOverflow",
"UpdateParentOverflow",
"ChildrenOnlyTransform", "RecomputePosition", "UpdateContainingBlock",
"BorderStyleNoneChange", "UpdateTextPath", "SchedulePaint",
"NeutralChange", "InvalidateRenderingObservers",
"ReflowChangesSizeOrPosition", "UpdateComputedBSize",
"UpdateUsesOpacity", "UpdateBackgroundPosition",
"AddOrRemoveTransform", "CSSOverflowChange",
- "UpdateWidgetProperties"
+ "UpdateWidgetProperties", "UpdateTableCellSpans"
};
- static_assert(nsChangeHint_AllHints == (1 << ArrayLength(names)) - 1,
+ static_assert(nsChangeHint_AllHints == (1u << ArrayLength(names)) - 1,
"Name list doesn't match change hints.");
- uint32_t hint = aHint & ((1 << ArrayLength(names)) - 1);
- uint32_t rest = aHint & ~((1 << ArrayLength(names)) - 1);
+ uint32_t hint = aHint & ((1u << ArrayLength(names)) - 1);
+ uint32_t rest = aHint & ~((1u << ArrayLength(names)) - 1);
if ((hint & NS_STYLE_HINT_REFLOW) == NS_STYLE_HINT_REFLOW) {
result.AppendLiteral("NS_STYLE_HINT_REFLOW");
hint = hint & ~NS_STYLE_HINT_REFLOW;
any = true;
} else if ((hint & nsChangeHint_AllReflowHints) == nsChangeHint_AllReflowHints) {
result.AppendLiteral("nsChangeHint_AllReflowHints");
hint = hint & ~nsChangeHint_AllReflowHints;
any = true;
@@ -1692,16 +1692,19 @@ RestyleManager::ProcessRestyledFrames(ns
}
if ((hint & nsChangeHint_UpdateCursor) && !didUpdateCursor) {
presContext->PresShell()->SynthesizeMouseMove(false);
didUpdateCursor = true;
}
if (hint & nsChangeHint_UpdateWidgetProperties) {
frame->UpdateWidgetProperties();
}
+ if (hint & nsChangeHint_UpdateTableCellSpans) {
+ frameConstructor->UpdateTableCellSpans(content);
+ }
}
}
frameConstructor->EndUpdate();
#ifdef DEBUG
// Verify the style tree. Note that this needs to happen once we've
// processed the whole list, since until then the tree is not in fact in a
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -9959,16 +9959,31 @@ nsCSSFrameConstructor::MaybeRecreateCont
}
#endif
ReframeContainingBlock(parent, aInsertionKind, aFlags);
return true;
}
void
+nsCSSFrameConstructor::UpdateTableCellSpans(nsIContent* aContent)
+{
+ nsTableCellFrame* cellFrame = do_QueryFrame(aContent->GetPrimaryFrame());
+
+ // It's possible that this warning could fire if some other style change
+ // simultaneously changes the 'display' of the element and makes it no
+ // longer be a table cell.
+ NS_WARNING_ASSERTION(cellFrame, "Hint should only be posted on table cells!");
+
+ if (cellFrame) {
+ cellFrame->GetTableFrame()->RowOrColSpanChanged(cellFrame);
+ }
+}
+
+void
nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent,
InsertionKind aInsertionKind,
RemoveFlags aFlags)
{
MOZ_ASSERT(aInsertionKind != InsertionKind::Async || aContent->IsElement());
MOZ_ASSERT(aContent);
// If there is no document, we don't want to recreate frames for it. (You
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -1798,16 +1798,21 @@ private:
* Recreate frames for aContent.
* @param aContent the content to recreate frames for
* @param aFlags normally you want to pass REMOVE_FOR_RECONSTRUCTION here
*/
void RecreateFramesForContent(nsIContent* aContent,
InsertionKind aInsertionKind,
RemoveFlags aFlags);
+ /**
+ * Handles change of rowspan and colspan attributes on table cells.
+ */
+ void UpdateTableCellSpans(nsIContent* aContent);
+
// If removal of aFrame from the frame tree requires reconstruction of some
// containing block (either of aFrame or of its parent) due to {ib} splits or
// table pseudo-frames, recreate the relevant frame subtree. The return value
// indicates whether this happened. aFrame must be the result of a
// GetPrimaryFrame() call on a content node (which means its parent is also
// not null).
bool MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame,
InsertionKind aInsertionKind,
--- a/layout/base/nsChangeHint.h
+++ b/layout/base/nsChangeHint.h
@@ -233,32 +233,38 @@ enum nsChangeHint : uint32_t {
nsChangeHint_CSSOverflowChange = 1 << 28,
/**
* Indicates that nsIFrame::UpdateWidgetProperties needs to be called.
* This is used for -moz-window-* properties.
*/
nsChangeHint_UpdateWidgetProperties = 1 << 29,
+ /**
+ * Indicates that there has been a colspan or rowspan attribute change
+ * on the cells of a table.
+ */
+ nsChangeHint_UpdateTableCellSpans = 1 << 30,
+
// IMPORTANT NOTE: When adding a new hint, you will need to add it to
// one of:
//
// * nsChangeHint_Hints_NeverHandledForDescendants
// * nsChangeHint_Hints_AlwaysHandledForDescendants
// * nsChangeHint_Hints_SometimesHandledForDescendants
//
// and you also may need to handle it in NS_HintsNotHandledForDescendantsIn.
//
// Please also add it to RestyleManager::ChangeHintToString and
// modify nsChangeHint_AllHints below accordingly.
/**
* Dummy hint value for all hints. It exists for compile time check.
*/
- nsChangeHint_AllHints = (1 << 30) - 1,
+ nsChangeHint_AllHints = (1u << 31) - 1,
};
// Redefine these operators to return nothing. This will catch any use
// of these operators on hints. We should not be using these operators
// on nsChangeHints
inline void operator<(nsChangeHint s1, nsChangeHint s2) {}
inline void operator>(nsChangeHint s1, nsChangeHint s2) {}
inline void operator!=(nsChangeHint s1, nsChangeHint s2) {}
@@ -348,16 +354,17 @@ inline nsChangeHint operator^=(nsChangeH
nsChangeHint_UpdateBackgroundPosition | \
nsChangeHint_UpdateComputedBSize | \
nsChangeHint_UpdateContainingBlock | \
nsChangeHint_UpdateEffects | \
nsChangeHint_UpdateOpacityLayer | \
nsChangeHint_UpdateOverflow | \
nsChangeHint_UpdateParentOverflow | \
nsChangeHint_UpdatePostTransformOverflow | \
+ nsChangeHint_UpdateTableCellSpans | \
nsChangeHint_UpdateTransformLayer | \
nsChangeHint_UpdateUsesOpacity | \
nsChangeHint_AddOrRemoveTransform | \
nsChangeHint_UpdateWidgetProperties \
)
// The change hints that are sometimes considered to be handled for descendants.
#define nsChangeHint_Hints_SometimesHandledForDescendants (\
--- a/layout/tables/nsTableCellFrame.cpp
+++ b/layout/tables/nsTableCellFrame.cpp
@@ -225,18 +225,22 @@ nsTableCellFrame::AttributeChanged(int32
{
// We need to recalculate in this case because of the nowrap quirk in
// BasicTableLayoutStrategy
if (aNameSpaceID == kNameSpaceID_None && aAttribute == nsGkAtoms::nowrap &&
PresContext()->CompatibilityMode() == eCompatibility_NavQuirks) {
PresContext()->PresShell()->
FrameNeedsReflow(this, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
}
- // let the table frame decide what to do
- GetTableFrame()->AttributeChangedFor(this, mContent, aAttribute);
+
+ if (aAttribute == nsGkAtoms::rowspan || aAttribute == nsGkAtoms::colspan) {
+ nsLayoutUtils::PostRestyleEvent(mContent->AsElement(),
+ nsRestyleHint(0),
+ nsChangeHint_UpdateTableCellSpans);
+ }
return NS_OK;
}
/* virtual */ void
nsTableCellFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
{
nsContainerFrame::DidSetStyleContext(aOldStyleContext);
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -350,40 +350,34 @@ nsTableFrame::SetInitialChildList(ChildL
// calc collapsing borders
if (IsBorderCollapse()) {
SetFullBCDamageArea();
}
}
}
void
-nsTableFrame::AttributeChangedFor(nsIFrame* aFrame,
- nsIContent* aContent,
- nsIAtom* aAttribute)
-{
- nsTableCellFrame *cellFrame = do_QueryFrame(aFrame);
- if (cellFrame) {
- if ((nsGkAtoms::rowspan == aAttribute) ||
- (nsGkAtoms::colspan == aAttribute)) {
- nsTableCellMap* cellMap = GetCellMap();
- if (cellMap) {
- // for now just remove the cell from the map and reinsert it
- int32_t rowIndex, colIndex;
- cellFrame->GetRowIndex(rowIndex);
- cellFrame->GetColIndex(colIndex);
- RemoveCell(cellFrame, rowIndex);
- AutoTArray<nsTableCellFrame*, 1> cells;
- cells.AppendElement(cellFrame);
- InsertCells(cells, rowIndex, colIndex - 1);
-
- // XXX Should this use eStyleChange? It currently doesn't need
- // to, but it might given more optimization.
- PresContext()->PresShell()->
- FrameNeedsReflow(this, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
- }
+nsTableFrame::RowOrColSpanChanged(nsTableCellFrame* aCellFrame)
+{
+ if (aCellFrame) {
+ nsTableCellMap* cellMap = GetCellMap();
+ if (cellMap) {
+ // for now just remove the cell from the map and reinsert it
+ int32_t rowIndex, colIndex;
+ aCellFrame->GetRowIndex(rowIndex);
+ aCellFrame->GetColIndex(colIndex);
+ RemoveCell(aCellFrame, rowIndex);
+ AutoTArray<nsTableCellFrame*, 1> cells;
+ cells.AppendElement(aCellFrame);
+ InsertCells(cells, rowIndex, colIndex - 1);
+
+ // XXX Should this use eStyleChange? It currently doesn't need
+ // to, but it might given more optimization.
+ PresContext()->PresShell()->
+ FrameNeedsReflow(this, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
}
}
}
/* ****** CellMap methods ******* */
/* return the effective col count */
--- a/layout/tables/nsTableFrame.h
+++ b/layout/tables/nsTableFrame.h
@@ -175,22 +175,22 @@ public:
// function for more explanation.) Should be called during frame construction.
static void RegisterPositionedTablePart(nsIFrame* aFrame);
// Unregister a positioned table part with its nsTableFrame.
static void UnregisterPositionedTablePart(nsIFrame* aFrame,
nsIFrame* aDestructRoot);
nsPoint GetFirstSectionOrigin(const ReflowInput& aReflowInput) const;
+
/*
- * Notification that aAttribute has changed for content inside a table (cell, row, etc)
+ * Notification that rowspan or colspan has changed for content inside a
+ * table cell
*/
- void AttributeChangedFor(nsIFrame* aFrame,
- nsIContent* aContent,
- nsIAtom* aAttribute);
+ void RowOrColSpanChanged(nsTableCellFrame* aCellFrame);
/** @see nsIFrame::DestroyFrom */
virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
/** @see nsIFrame::DidSetStyleContext */
virtual void DidSetStyleContext(nsStyleContext* aOldStyleContext) override;
virtual void SetInitialChildList(ChildListID aListID,