Bug 1227327 - Invalidate table parts and MathML frames when background-position changes on them. r?dbaron
Theoretically we should do the same for nsTreeBodyFrame, but that frame type is
harder to detect and I'm not sure it's worth adding code to support updating
background-position on XUL trees.
MozReview-Commit-ID: 8HPT53MX6bO
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -881,16 +881,29 @@ RestyleManager::ProcessRestyledFrames(ns
// backgrounds (and those of table parts inside of it) are
// painted as part of the table's nsDisplayTableBorderBackground
// display item, or part of its own display item. That requires
// invalidation, so change UpdateOpacityLayer to RepaintFrame.
hint &= ~nsChangeHint_UpdateOpacityLayer;
hint |= nsChangeHint_RepaintFrame;
}
+ if (hint & nsChangeHint_UpdateBackgroundPosition) {
+ // For most frame types, DLBI can detect background position changes,
+ // so we only need to schedule a paint.
+ hint |= nsChangeHint_SchedulePaint;
+ if (frame->IsFrameOfType(nsIFrame::eTablePart) ||
+ frame->IsFrameOfType(nsIFrame::eMathML)) {
+ // Table parts and MathML frames don't build display items for their
+ // backgrounds, so DLBI can't detect background-position changes for
+ // these frames. Repaint the whole frame.
+ hint |= nsChangeHint_RepaintFrame;
+ }
+ }
+
if (hint & (nsChangeHint_RepaintFrame | nsChangeHint_SyncFrameView |
nsChangeHint_UpdateOpacityLayer | nsChangeHint_UpdateTransformLayer |
nsChangeHint_ChildrenOnlyTransform | nsChangeHint_SchedulePaint)) {
ApplyRenderingChangeToTree(mPresContext, frame, hint);
}
if ((hint & nsChangeHint_RecomputePosition) && !didReflowThisFrame) {
ActiveLayerTracker::NotifyOffsetRestyle(frame);
// It is possible for this to fall back to a reflow
--- a/layout/base/nsChangeHint.h
+++ b/layout/base/nsChangeHint.h
@@ -189,16 +189,25 @@ enum nsChangeHint {
*
* Used as extra data for handling UpdateOpacityLayer hints.
*
* Note that we do not send this hint if the non-1 value was 0.99 or
* greater, since in that case we send a RepaintFrame hint instead.
*/
nsChangeHint_UpdateUsesOpacity = 1 << 25,
+ /**
+ * Indicates that the 'background-position' property changed.
+ * Regular frames can invalidate these changes using DLBI, but
+ * for some frame types we need to repaint the whole frame because
+ * the frame does not build individual background image display items
+ * for each background layer.
+ */
+ nsChangeHint_UpdateBackgroundPosition = 1 << 26,
+
// IMPORTANT NOTE: When adding new hints, consider whether you need to
// add them to NS_HintsNotHandledForDescendantsIn() below. Please also
// add them to RestyleManager::ChangeHintToString.
};
// 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
@@ -298,33 +307,35 @@ inline nsChangeHint operator^=(nsChangeH
nsChangeHint_ChildrenOnlyTransform | \
nsChangeHint_RecomputePosition | \
nsChangeHint_UpdateContainingBlock | \
nsChangeHint_BorderStyleNoneChange | \
nsChangeHint_NeedReflow | \
nsChangeHint_ReflowChangesSizeOrPosition | \
nsChangeHint_ClearAncestorIntrinsics | \
nsChangeHint_UpdateComputedBSize | \
- nsChangeHint_UpdateUsesOpacity)
+ nsChangeHint_UpdateUsesOpacity | \
+ nsChangeHint_UpdateBackgroundPosition)
inline nsChangeHint NS_HintsNotHandledForDescendantsIn(nsChangeHint aChangeHint) {
nsChangeHint result = nsChangeHint(aChangeHint & (
nsChangeHint_UpdateTransformLayer |
nsChangeHint_UpdateEffects |
nsChangeHint_InvalidateRenderingObservers |
nsChangeHint_UpdateOpacityLayer |
nsChangeHint_UpdateOverflow |
nsChangeHint_UpdatePostTransformOverflow |
nsChangeHint_UpdateParentOverflow |
nsChangeHint_ChildrenOnlyTransform |
nsChangeHint_RecomputePosition |
nsChangeHint_UpdateContainingBlock |
nsChangeHint_BorderStyleNoneChange |
nsChangeHint_UpdateComputedBSize |
- nsChangeHint_UpdateUsesOpacity));
+ nsChangeHint_UpdateUsesOpacity | \
+ nsChangeHint_UpdateBackgroundPosition));
if (!NS_IsHintSubset(nsChangeHint_NeedDirtyReflow, aChangeHint)) {
if (NS_IsHintSubset(nsChangeHint_NeedReflow, aChangeHint)) {
// If NeedDirtyReflow is *not* set, then NeedReflow is a
// non-inherited hint.
NS_UpdateHint(result, nsChangeHint_NeedReflow);
}
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -2633,17 +2633,17 @@ nsStyleImageLayers::Layer::CalcDifferenc
mSize != aOther.mSize ||
mImage != aOther.mImage ||
mMaskMode != aOther.mMaskMode ||
mComposite != aOther.mComposite) {
hint |= nsChangeHint_RepaintFrame;
}
if (mPosition != aOther.mPosition) {
- hint |= nsChangeHint_SchedulePaint;
+ hint |= nsChangeHint_UpdateBackgroundPosition;
}
return hint;
}
// --------------------
// nsStyleBackground
//
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -796,17 +796,17 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
AllocateByObjectID(mozilla::eArenaObjectID_nsStyleBackground, sz);
}
void Destroy(nsPresContext* aContext);
nsChangeHint CalcDifference(const nsStyleBackground& aOther) const;
static nsChangeHint MaxDifference() {
return nsChangeHint_UpdateEffects |
nsChangeHint_RepaintFrame |
- nsChangeHint_SchedulePaint |
+ nsChangeHint_UpdateBackgroundPosition |
nsChangeHint_NeutralChange;
}
static nsChangeHint DifferenceAlwaysHandledForDescendants() {
// CalcDifference never returns the reflow hints that are sometimes
// handled for descendants at all.
return nsChangeHint(0);
}