Index: third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp |
diff --git a/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp b/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp |
index 847539ad9f67180619b83ba3bbc4e0d46fa306da..5514ca0ce99c92270b580bfba02de414058c60a4 100644 |
--- a/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp |
+++ b/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp |
@@ -22,7 +22,9 @@ struct PrePaintTreeWalkContext { |
: treeBuilderContext(parentContext.treeBuilderContext), |
paintInvalidatorContext(treeBuilderContext, |
parentContext.paintInvalidatorContext), |
- ancestorOverflowPaintLayer(parentContext.ancestorOverflowPaintLayer) {} |
+ ancestorOverflowPaintLayer(parentContext.ancestorOverflowPaintLayer), |
+ ancestorTransformedOrRootPaintLayer( |
+ parentContext.ancestorTransformedOrRootPaintLayer) {} |
PaintPropertyTreeBuilderContext treeBuilderContext; |
PaintInvalidatorContext paintInvalidatorContext; |
@@ -31,6 +33,7 @@ struct PrePaintTreeWalkContext { |
// is the root layer. Note that it is tree ancestor, not containing |
// block or stacking ancestor. |
PaintLayer* ancestorOverflowPaintLayer; |
+ PaintLayer* ancestorTransformedOrRootPaintLayer; |
}; |
void PrePaintTreeWalk::walk(FrameView& rootFrame) { |
@@ -54,6 +57,7 @@ void PrePaintTreeWalk::walk(FrameView& frameView, |
PrePaintTreeWalkContext context(parentContext); |
// ancestorOverflowLayer does not cross frame boundaries. |
context.ancestorOverflowPaintLayer = nullptr; |
+ context.ancestorTransformedOrRootPaintLayer = frameView.layoutView()->layer(); |
m_propertyTreeBuilder.updateProperties(frameView, context.treeBuilderContext); |
m_paintInvalidator.invalidatePaintIfNeeded(frameView, |
context.paintInvalidatorContext); |
@@ -89,6 +93,119 @@ static void updateAuxiliaryObjectProperties(const LayoutObject& object, |
context.ancestorOverflowPaintLayer = paintLayer; |
} |
+// Returns whether |a| is an ancestor of or equal to |b|. |
+static bool isAncestorOfOrEqualTo(const ClipPaintPropertyNode* a, |
+ const ClipPaintPropertyNode* b) { |
+ while (b && b != a) { |
+ b = b->parent(); |
+ } |
+ return b == a; |
+} |
+ |
+ClipRect PrePaintTreeWalk::clipRectForContext( |
+ const PaintPropertyTreeBuilderContext::ContainingBlockContext& context, |
+ const EffectPaintPropertyNode* effect, |
+ const PropertyTreeState& ancestorState, |
+ const LayoutPoint& ancestorPaintOffset, |
+ bool& hasClip) { |
+ // Only return a non-infinite clip if clips differ, or the "ancestor" state is |
+ // actually an ancestor clip. This ensures no accuracy issues due to |
+ // transforms applied to infinite rects. |
+ if (isAncestorOfOrEqualTo(context.clip, ancestorState.clip())) |
+ return ClipRect(LayoutRect(LayoutRect::infiniteIntRect())); |
+ |
+ hasClip = true; |
+ |
+ PropertyTreeState localState(context.transform, context.clip, effect); |
+ |
+ // TODO(chrishtr): remove need for this. |
+ LayoutRect localRect(LayoutRect::infiniteIntRect()); |
+ |
+ LayoutRect rect(m_geometryMapper.sourceToDestinationVisualRect( |
+ FloatRect(localRect), localState, ancestorState)); |
+ rect.moveBy(-ancestorPaintOffset); |
+ return rect; |
+} |
+ |
+void PrePaintTreeWalk::invalidatePaintLayerOptimizationsIfNeeded( |
+ const LayoutObject& object, |
+ const PaintLayer& ancestorTransformedOrRootPaintLayer, |
+ PaintPropertyTreeBuilderContext& context) { |
+ if (!object.hasLayer()) |
+ return; |
+ |
+ PaintLayer& paintLayer = *toLayoutBoxModelObject(object).layer(); |
+ PropertyTreeState ancestorState = |
+ *ancestorTransformedOrRootPaintLayer.layoutObject() |
+ ->paintProperties() |
+ ->localBorderBoxProperties(); |
+ |
+#ifdef CHECK_CLIP_RECTS |
+ ShouldRespectOverflowClipType respectOverflowClip = RespectOverflowClip; |
+#endif |
+ if (ancestorTransformedOrRootPaintLayer.compositingState() == |
+ PaintsIntoOwnBacking && |
+ ancestorTransformedOrRootPaintLayer.layoutObject() |
+ ->paintProperties() |
+ ->overflowClip()) { |
+ ancestorState.setClip(ancestorTransformedOrRootPaintLayer.layoutObject() |
+ ->paintProperties() |
+ ->overflowClip()); |
+#ifdef CHECK_CLIP_RECTS |
+ respectOverflowClip = IgnoreOverflowClip; |
+#endif |
+ } |
+ |
+#ifdef CHECK_CLIP_RECTS |
+ ClipRects& oldClipRects = paintLayer.clipper().paintingClipRects( |
+ &ancestorTransformedOrRootPaintLayer, respectOverflowClip, LayoutSize()); |
+#endif |
+ |
+ bool hasClip = false; |
+ RefPtr<ClipRects> clipRects = ClipRects::create(); |
+ clipRects->setOverflowClipRect(clipRectForContext( |
+ context.current, context.currentEffect, ancestorState, |
+ ancestorTransformedOrRootPaintLayer.layoutObject()->paintOffset(), |
+ hasClip)); |
+#ifdef CHECK_CLIP_RECTS |
+ CHECK(!hasClip || |
+ clipRects->overflowClipRect() == oldClipRects.overflowClipRect()) |
+ << "rect= " << clipRects->overflowClipRect().toString(); |
+#endif |
+ |
+ clipRects->setFixedClipRect(clipRectForContext( |
+ context.fixedPosition, context.currentEffect, ancestorState, |
+ ancestorTransformedOrRootPaintLayer.layoutObject()->paintOffset(), |
+ hasClip)); |
+#ifdef CHECK_CLIP_RECTS |
+ CHECK(hasClip || clipRects->fixedClipRect() == oldClipRects.fixedClipRect()) |
+ << " fixed=" << clipRects->fixedClipRect().toString(); |
+#endif |
+ |
+ clipRects->setPosClipRect(clipRectForContext( |
+ context.absolutePosition, context.currentEffect, ancestorState, |
+ ancestorTransformedOrRootPaintLayer.layoutObject()->paintOffset(), |
+ hasClip)); |
+#ifdef CHECK_CLIP_RECTS |
+ CHECK(!hasClip || clipRects->posClipRect() == oldClipRects.posClipRect()) |
+ << " abs=" << clipRects->posClipRect().toString(); |
+#endif |
+ |
+ ClipRects* previousClipRects = paintLayer.previousPaintingClipRects(); |
+ |
+ if (!previousClipRects || *clipRects != *previousClipRects) { |
+ paintLayer.setNeedsRepaint(); |
+ paintLayer.setPreviousPaintPhaseDescendantOutlinesEmpty(false); |
+ paintLayer.setPreviousPaintPhaseFloatEmpty(false); |
+ paintLayer.setPreviousPaintPhaseDescendantBlockBackgroundsEmpty(false); |
+ // All subsequences which are contained below this paintLayer must also |
+ // be checked. |
+ context.forceSubtreeUpdate = true; |
+ } |
+ |
+ paintLayer.setPreviousPaintingClipRects(*clipRects); |
+} |
+ |
void PrePaintTreeWalk::walk(const LayoutObject& object, |
const PrePaintTreeWalkContext& parentContext) { |
PrePaintTreeWalkContext context(parentContext); |
@@ -120,6 +237,18 @@ void PrePaintTreeWalk::walk(const LayoutObject& object, |
m_propertyTreeBuilder.updatePropertiesForChildren(object, |
context.treeBuilderContext); |
+ if (object.isBoxModelObject() && object.hasLayer()) { |
+ if (object.styleRef().hasTransform() || |
+ &object == context.paintInvalidatorContext.paintInvalidationContainer) { |
+ context.ancestorTransformedOrRootPaintLayer = |
+ toLayoutBoxModelObject(object).layer(); |
+ } |
+ } |
+ |
+ invalidatePaintLayerOptimizationsIfNeeded( |
+ object, *context.ancestorTransformedOrRootPaintLayer, |
+ context.treeBuilderContext); |
+ |
for (const LayoutObject* child = object.slowFirstChild(); child; |
child = child->nextSibling()) { |
if (child->isLayoutMultiColumnSpannerPlaceholder()) { |