Chromium Code Reviews| Index: third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp |
| diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp b/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp |
| similarity index 63% |
| rename from third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp |
| rename to third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp |
| index 224f99c3872452f09416b9b52931a5de571633fb..fb5c2e8f970ed62a08e7e650eba428708692d6e4 100644 |
| --- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp |
| +++ b/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp |
| @@ -2,7 +2,7 @@ |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| -#include "core/paint/PaintPropertyTreeBuilder.h" |
| +#include "core/paint/PrePaintTreeWalk.h" |
| #include "core/frame/FrameView.h" |
| #include "core/layout/LayoutPart.h" |
| @@ -19,27 +19,26 @@ namespace blink { |
| // The walk will be done in the primary tree order (= DOM order), thus the context will also be |
| // responsible for bookkeeping tree state in other order, for example, the most recent position |
| // container seen. |
| -struct PaintPropertyTreeBuilderContext { |
| - PaintPropertyTreeBuilderContext() |
| - : currentTransform(nullptr) |
| - , currentClip(nullptr) |
| - , transformForAbsolutePosition(nullptr) |
| - , clipForAbsolutePosition(nullptr) |
| - , transformForFixedPosition(nullptr) |
| - , clipForFixedPosition(nullptr) |
| - , currentEffect(nullptr) { } |
| +struct PrePaintTreeWalkContext { |
| + PrePaintTreeWalkContext() |
| + : paintInvalidationContainer(nullptr) |
| + , paintInvalidationContainerForOutOfFlowPositioned(nullptr) |
|
trchen
2016/03/11 23:09:39
The name of the variable isn't accurate. Paint inv
|
| + { } |
| + |
| + // TODO(wangxianzhu): The RefPtrs are needed for SPv1 which doesn't save the properties |
| + // into LayoutObjects. Change them to normal pointers for SPv2. |
| // The combination of a transform and paint offset describes a linear space. |
| // When a layout object recur to its children, the main context is expected to refer |
| // the object's border box, then the callee will derive its own border box by translating |
| // the space with its own layout location. |
| - TransformPaintPropertyNode* currentTransform; |
| + RefPtr<TransformPaintPropertyNode> currentTransform; |
| LayoutPoint paintOffset; |
| // The clip node describes the accumulated raster clip for the current subtree. |
| // Note that the computed raster region in canvas space for a clip node is independent from |
| // the transform and paint offset above. Also the actual raster region may be affected |
| // by layerization and occlusion tracking. |
| - ClipPaintPropertyNode* currentClip; |
| + RefPtr<ClipPaintPropertyNode> currentClip; |
| // Separate context for out-of-flow positioned and fixed positioned elements are needed |
| // because they don't use DOM parent as their containing block. |
| @@ -48,28 +47,32 @@ struct PaintPropertyTreeBuilderContext { |
| // positioned descendants. |
| // Overflow clips are also inherited by containing block tree instead of DOM tree, thus they |
| // are included in the additional context too. |
| - TransformPaintPropertyNode* transformForAbsolutePosition; |
| + RefPtr<TransformPaintPropertyNode> transformForAbsolutePosition; |
| LayoutPoint paintOffsetForAbsolutePosition; |
| - ClipPaintPropertyNode* clipForAbsolutePosition; |
| + RefPtr<ClipPaintPropertyNode> clipForAbsolutePosition; |
| - TransformPaintPropertyNode* transformForFixedPosition; |
| + RefPtr<TransformPaintPropertyNode> transformForFixedPosition; |
| LayoutPoint paintOffsetForFixedPosition; |
| - ClipPaintPropertyNode* clipForFixedPosition; |
| + RefPtr<ClipPaintPropertyNode> clipForFixedPosition; |
| // The effect hierarchy is applied by the stacking context tree. It is guaranteed that every |
| // DOM descendant is also a stacking context descendant. Therefore, we don't need extra |
| // bookkeeping for effect nodes and can generate the effect tree from a DOM-order traversal. |
| - EffectPaintPropertyNode* currentEffect; |
| + RefPtr<EffectPaintPropertyNode> currentEffect; |
| + |
| + // For SPv1 only. |
| + const LayoutBoxModelObject* paintInvalidationContainer; |
| + const LayoutBoxModelObject* paintInvalidationContainerForOutOfFlowPositioned; |
| }; |
| -void PaintPropertyTreeBuilder::buildPropertyTrees(FrameView& rootFrame) |
| +void PrePaintTreeWalk::buildPropertyTreesAndInvalidatePaint(FrameView& rootFrame) |
| { |
| - walk(rootFrame, PaintPropertyTreeBuilderContext()); |
| + walk(rootFrame, PrePaintTreeWalkContext(), nullptr); |
| } |
| -void PaintPropertyTreeBuilder::walk(FrameView& frameView, const PaintPropertyTreeBuilderContext& context) |
| +void PrePaintTreeWalk::walk(FrameView& frameView, const PrePaintTreeWalkContext& context, const PaintInvalidationState* paintInvalidationState) |
| { |
| - PaintPropertyTreeBuilderContext localContext(context); |
| + PrePaintTreeWalkContext localContext(context); |
| // TODO(pdr): Creating paint properties for FrameView here will not be |
| // needed once settings()->rootLayerScrolls() is enabled. |
| @@ -97,44 +100,45 @@ void PaintPropertyTreeBuilder::walk(FrameView& frameView, const PaintPropertyTre |
| frameView.setContentClip(newClipNodeForContentClip.release()); |
| if (LayoutView* layoutView = frameView.layoutView()) |
| - walk(*layoutView, localContext); |
| + walk(*layoutView, localContext, paintInvalidationState); |
| } |
| -static void deriveBorderBoxFromContainerContext(const LayoutObject& object, PaintPropertyTreeBuilderContext& context) |
| +static void adjustContainerContextForPosition(const LayoutObject& object, PrePaintTreeWalkContext& context) |
| { |
| - if (!object.isBoxModelObject()) |
| - return; |
| - |
| - const LayoutBoxModelObject& boxModelObject = toLayoutBoxModelObject(object); |
| - |
| - // TODO(trchen): There is some insanity going on with tables. Double check results. |
| switch (object.styleRef().position()) { |
| - case StaticPosition: |
| - break; |
| - case RelativePosition: |
| - context.paintOffset += boxModelObject.offsetForInFlowPosition(); |
| - break; |
| case AbsolutePosition: |
| context.currentTransform = context.transformForAbsolutePosition; |
| context.paintOffset = context.paintOffsetForAbsolutePosition; |
| context.currentClip = context.clipForAbsolutePosition; |
| - break; |
| - case StickyPosition: |
| - context.paintOffset += boxModelObject.offsetForInFlowPosition(); |
| + context.paintInvalidationContainer = context.paintInvalidationContainerForOutOfFlowPositioned; |
|
trchen
2016/03/11 23:36:19
Per the previous comment, it is not the right plac
|
| break; |
| case FixedPosition: |
| context.currentTransform = context.transformForFixedPosition; |
| context.paintOffset = context.paintOffsetForFixedPosition; |
| context.currentClip = context.clipForFixedPosition; |
| + context.paintInvalidationContainer = context.paintInvalidationContainerForOutOfFlowPositioned; |
|
trchen
2016/03/11 23:36:19
Ditto.
|
| break; |
| default: |
| - ASSERT_NOT_REACHED(); |
| + break; |
| } |
| +} |
| + |
| +static void deriveBorderBoxFromContainerContext(const LayoutObject& object, PrePaintTreeWalkContext& context) |
| +{ |
| + if (!object.isBoxModelObject()) |
| + return; |
| + |
| + const LayoutBoxModelObject& boxModelObject = toLayoutBoxModelObject(object); |
| + |
| + // TODO(trchen): There is some insanity going on with tables. Double check results. |
| + if (object.isInFlowPositioned()) |
|
trchen
2016/03/11 23:36:19
While this refactoring is appreciated, can we do t
|
| + context.paintOffset += boxModelObject.offsetForInFlowPosition(); |
| + |
| if (boxModelObject.isBox()) |
| context.paintOffset += toLayoutBox(boxModelObject).locationOffset(); |
| } |
| -static PassRefPtr<TransformPaintPropertyNode> createPaintOffsetTranslationIfNeeded(const LayoutObject& object, PaintPropertyTreeBuilderContext& context) |
| +static PassRefPtr<TransformPaintPropertyNode> createPaintOffsetTranslationIfNeeded(const LayoutObject& object, PrePaintTreeWalkContext& context) |
| { |
| bool shouldCreatePaintOffsetTranslationNode = false; |
| if (object.isSVGRoot()) { |
| @@ -167,7 +171,7 @@ static FloatPoint3D transformOrigin(const LayoutBox& box) |
| style.transformOriginZ()); |
| } |
| -static PassRefPtr<TransformPaintPropertyNode> createTransformIfNeeded(const LayoutObject& object, PaintPropertyTreeBuilderContext& context) |
| +static PassRefPtr<TransformPaintPropertyNode> createTransformIfNeeded(const LayoutObject& object, PrePaintTreeWalkContext& context) |
| { |
| if (object.isSVG() && !object.isSVGRoot()) { |
| const AffineTransform& transform = object.localToParentTransform(); |
| @@ -196,7 +200,7 @@ static PassRefPtr<TransformPaintPropertyNode> createTransformIfNeeded(const Layo |
| return newTransformNodeForTransform.release(); |
| } |
| -static PassRefPtr<EffectPaintPropertyNode> createEffectIfNeeded(const LayoutObject& object, PaintPropertyTreeBuilderContext& context) |
| +static PassRefPtr<EffectPaintPropertyNode> createEffectIfNeeded(const LayoutObject& object, PrePaintTreeWalkContext& context) |
| { |
| const ComputedStyle& style = object.styleRef(); |
| if (!style.hasOpacity()) |
| @@ -206,7 +210,7 @@ static PassRefPtr<EffectPaintPropertyNode> createEffectIfNeeded(const LayoutObje |
| return newEffectNode.release(); |
| } |
| -static PassRefPtr<ClipPaintPropertyNode> createOverflowClipIfNeeded(const LayoutObject& object, PaintPropertyTreeBuilderContext& context) |
| +static PassRefPtr<ClipPaintPropertyNode> createOverflowClipIfNeeded(const LayoutObject& object, PrePaintTreeWalkContext& context) |
| { |
| if (!object.isBox()) |
| return nullptr; |
| @@ -236,7 +240,7 @@ static PassRefPtr<ClipPaintPropertyNode> createOverflowClipIfNeeded(const Layout |
| RefPtr<ClipPaintPropertyNode> newClipNodeForOverflowClip = ClipPaintPropertyNode::create( |
| context.currentTransform, |
| FloatRoundedRect(FloatRect(clipRect)), |
| - newClipNodeForBorderRadiusClip ? newClipNodeForBorderRadiusClip.release() : context.currentClip); |
| + newClipNodeForBorderRadiusClip ? newClipNodeForBorderRadiusClip.release() : PassRefPtr<ClipPaintPropertyNode>(context.currentClip)); |
| context.currentClip = newClipNodeForOverflowClip.get(); |
| return newClipNodeForOverflowClip.release(); |
| } |
| @@ -250,7 +254,7 @@ static FloatPoint perspectiveOrigin(const LayoutBox& box) |
| floatValueForLength(style.perspectiveOriginY(), borderBoxSize.height())); |
| } |
| -static PassRefPtr<TransformPaintPropertyNode> createPerspectiveIfNeeded(const LayoutObject& object, PaintPropertyTreeBuilderContext& context) |
| +static PassRefPtr<TransformPaintPropertyNode> createPerspectiveIfNeeded(const LayoutObject& object, PrePaintTreeWalkContext& context) |
| { |
| const ComputedStyle& style = object.styleRef(); |
| if (!object.isBox() || !style.hasPerspective()) |
| @@ -263,7 +267,7 @@ static PassRefPtr<TransformPaintPropertyNode> createPerspectiveIfNeeded(const La |
| return newTransformNodeForPerspective.release(); |
| } |
| -static PassRefPtr<TransformPaintPropertyNode> createScrollTranslationIfNeeded(const LayoutObject& object, PaintPropertyTreeBuilderContext& context) |
| +static PassRefPtr<TransformPaintPropertyNode> createScrollTranslationIfNeeded(const LayoutObject& object, PrePaintTreeWalkContext& context) |
| { |
| if (!object.isBoxModelObject() || !object.hasOverflowClip()) |
| return nullptr; |
| @@ -281,7 +285,7 @@ static PassRefPtr<TransformPaintPropertyNode> createScrollTranslationIfNeeded(co |
| return newTransformNodeForScrollTranslation.release(); |
| } |
| -static void updateOutOfFlowContext(const LayoutObject& object, PaintPropertyTreeBuilderContext& context) |
| +static void updateOutOfFlowContext(const LayoutObject& object, PrePaintTreeWalkContext& context) |
| { |
| // At the html->svg boundary (see: createPaintOffsetTranslationIfNeeded) the currentTransform is |
| // up-to-date for all children of the svg root element. Additionally, inside SVG, all positioning |
| @@ -303,7 +307,7 @@ static void updateOutOfFlowContext(const LayoutObject& object, PaintPropertyTree |
| } |
| } |
| -static PassOwnPtr<ObjectPaintProperties::LocalBorderBoxProperties> recordTreeContextIfNeeded(LayoutObject& object, const PaintPropertyTreeBuilderContext& context) |
| +static PassOwnPtr<ObjectPaintProperties::LocalBorderBoxProperties> recordTreeContextIfNeeded(const LayoutObject& object, const PrePaintTreeWalkContext& context) |
| { |
| // Note: Currently only layer painter makes use of the pre-computed context. |
| // This condition may be loosened with no adverse effects beside memory use. |
| @@ -318,45 +322,99 @@ static PassOwnPtr<ObjectPaintProperties::LocalBorderBoxProperties> recordTreeCon |
| return recordedContext.release(); |
| } |
| -void PaintPropertyTreeBuilder::walk(LayoutObject& object, const PaintPropertyTreeBuilderContext& context) |
| +static void updatePaintInvalidationContainer(const LayoutObject& object, PrePaintTreeWalkContext& context) |
| { |
| - PaintPropertyTreeBuilderContext localContext(context); |
| - |
| - deriveBorderBoxFromContainerContext(object, localContext); |
| - RefPtr<TransformPaintPropertyNode> newTransformNodeForPaintOffsetTranslation = createPaintOffsetTranslationIfNeeded(object, localContext); |
| - RefPtr<TransformPaintPropertyNode> newTransformNodeForTransform = createTransformIfNeeded(object, localContext); |
| - RefPtr<EffectPaintPropertyNode> newEffectNode = createEffectIfNeeded(object, localContext); |
| - OwnPtr<ObjectPaintProperties::LocalBorderBoxProperties> newRecordedContext = recordTreeContextIfNeeded(object, localContext); |
| - RefPtr<ClipPaintPropertyNode> newClipNodeForOverflowClip = createOverflowClipIfNeeded(object, localContext); |
| - // TODO(trchen): Insert flattening transform here, as specified by |
| - // http://www.w3.org/TR/css3-transforms/#transform-style-property |
| - RefPtr<TransformPaintPropertyNode> newTransformNodeForPerspective = createPerspectiveIfNeeded(object, localContext); |
| - RefPtr<TransformPaintPropertyNode> newTransformNodeForScrollTranslation = createScrollTranslationIfNeeded(object, localContext); |
| - updateOutOfFlowContext(object, localContext); |
| - |
| - if (newTransformNodeForPaintOffsetTranslation || newTransformNodeForTransform || newEffectNode || newClipNodeForOverflowClip || newTransformNodeForPerspective || newTransformNodeForScrollTranslation || newRecordedContext) { |
| - OwnPtr<ObjectPaintProperties> updatedPaintProperties = ObjectPaintProperties::create( |
| - newTransformNodeForPaintOffsetTranslation.release(), |
| - newTransformNodeForTransform.release(), |
| - newEffectNode.release(), |
| - newClipNodeForOverflowClip.release(), |
| - newTransformNodeForPerspective.release(), |
| - newTransformNodeForScrollTranslation.release(), |
| - newRecordedContext.release()); |
| - object.setObjectPaintProperties(updatedPaintProperties.release()); |
| - } else { |
| - object.clearObjectPaintProperties(); |
| + // Paint invalidation container is a SPv1-only concept. |
| + ASSERT(!RuntimeEnabledFeatures::slimmingPaintV2Enabled()); |
| + |
| + if (!object.isPaintInvalidationContainer()) { |
|
trchen
2016/03/11 23:36:19
This doesn't look right. I think it should be
if
|
| + if (context.paintInvalidationContainer) |
| + return; |
| + ASSERT(object.isLayoutView()); |
| + } |
| + |
| + context.currentTransform = nullptr; |
| + context.paintOffset = LayoutPoint(); |
| + context.currentClip = nullptr; |
| + context.paintInvalidationContainer = &toLayoutBoxModelObject(object); |
| + |
| + // A composited stacking context establishes new paint invalidation container for |
| + // out-of-flow-positioned descendants. |
| + if (object.styleRef().isStackingContext() || !context.paintInvalidationContainerForOutOfFlowPositioned) { |
| + // TODO(wangxianzhu): The following may be incorrect for some complex cases. Investigate if we could |
| + // make it correct for all cases or have to use ForceHorriblySlowRectMapping. |
|
trchen
2016/03/11 23:36:19
As pdr@ already pointed out, I don't think it make
|
| + context.transformForAbsolutePosition = nullptr; |
| + context.paintOffsetForAbsolutePosition = LayoutPoint(); |
| + context.clipForAbsolutePosition = nullptr; |
| + context.transformForFixedPosition = nullptr; |
| + context.paintOffsetForFixedPosition = LayoutPoint(); |
| + context.clipForFixedPosition = nullptr; |
| + context.paintInvalidationContainerForOutOfFlowPositioned = &toLayoutBoxModelObject(object); |
| + } |
| +} |
| + |
| +void PrePaintTreeWalk::walk(const LayoutObject& object, const PrePaintTreeWalkContext& context, const PaintInvalidationState* parentPaintInvalidationState) |
| +{ |
| + PrePaintTreeWalkContext localContext(context); |
| + adjustContainerContextForPosition(object, localContext); |
| + |
| + Optional<PaintInvalidationState> paintInvalidationState; |
| + if (RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled()) { |
| + if (!RuntimeEnabledFeatures::slimmingPaintV2Enabled()) |
| + updatePaintInvalidationContainer(object, localContext); |
| + paintInvalidationState.emplace(parentPaintInvalidationState, object, *localContext.paintInvalidationContainer, localContext.paintOffset); |
| + if (!RuntimeEnabledFeatures::slimmingPaintV2Enabled() && !object.shouldCheckForPaintInvalidation(*paintInvalidationState)) |
| + return; |
|
trchen
2016/03/11 23:36:19
The early return check is too late, and the semant
|
| + |
| + PaintInvalidationReason reason = object.getMutableForPainting().invalidatePaintIfNeeded(*paintInvalidationState, *localContext.paintInvalidationContainer); |
| + object.getMutableForPainting().clearPaintInvalidationState(*paintInvalidationState); |
| + if (reason == PaintInvalidationDelayedFull) |
| + m_pendingDelayedPaintInvalidations.append(const_cast<LayoutObject*>(&object)); |
| + } |
| + |
| + if (RuntimeEnabledFeatures::slimmingPaintV2Enabled() || !object.isPaintInvalidationContainer()) { |
| + deriveBorderBoxFromContainerContext(object, localContext); |
| + RefPtr<TransformPaintPropertyNode> newTransformNodeForPaintOffsetTranslation = createPaintOffsetTranslationIfNeeded(object, localContext); |
| + RefPtr<TransformPaintPropertyNode> newTransformNodeForTransform = createTransformIfNeeded(object, localContext); |
| + RefPtr<EffectPaintPropertyNode> newEffectNode = createEffectIfNeeded(object, localContext); |
| + OwnPtr<ObjectPaintProperties::LocalBorderBoxProperties> newRecordedContext = recordTreeContextIfNeeded(object, localContext); |
| + RefPtr<ClipPaintPropertyNode> newClipNodeForOverflowClip = createOverflowClipIfNeeded(object, localContext); |
| + // TODO(trchen): Insert flattening transform here, as specified by |
| + // http://www.w3.org/TR/css3-transforms/#transform-style-property |
| + RefPtr<TransformPaintPropertyNode> newTransformNodeForPerspective = createPerspectiveIfNeeded(object, localContext); |
| + RefPtr<TransformPaintPropertyNode> newTransformNodeForScrollTranslation = createScrollTranslationIfNeeded(object, localContext); |
| + updateOutOfFlowContext(object, localContext); |
| + |
| + if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { |
| + if (newTransformNodeForPaintOffsetTranslation || newTransformNodeForTransform || newEffectNode || newClipNodeForOverflowClip || newTransformNodeForPerspective || newTransformNodeForScrollTranslation || newRecordedContext) { |
| + OwnPtr<ObjectPaintProperties> updatedPaintProperties = ObjectPaintProperties::create( |
| + newTransformNodeForPaintOffsetTranslation.release(), |
| + newTransformNodeForTransform.release(), |
| + newEffectNode.release(), |
| + newClipNodeForOverflowClip.release(), |
| + newTransformNodeForPerspective.release(), |
| + newTransformNodeForScrollTranslation.release(), |
| + newRecordedContext.release()); |
| + object.getMutableForPainting().setObjectPaintProperties(updatedPaintProperties.release()); |
| + } else { |
| + object.getMutableForPainting().clearObjectPaintProperties(); |
| + } |
| + } |
| } |
| - for (LayoutObject* child = object.slowFirstChild(); child; child = child->nextSibling()) { |
| - if (child->isBoxModelObject() || child->isSVG()) |
| - walk(*child, localContext); |
| + for (const LayoutObject* child = object.slowFirstChild(); child; child = child->nextSibling()) { |
| + if (child->isBoxModelObject() || child->isSVG()) { |
| + walk(*child, localContext, paintInvalidationState.get()); |
| + } else if (RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled() && child->shouldCheckForPaintInvalidation(*paintInvalidationState)) { |
| + child->getMutableForPainting().invalidatePaintIfNeeded(*paintInvalidationState, *localContext.paintInvalidationContainer); |
| + child->getMutableForPainting().clearPaintInvalidationState(*paintInvalidationState); |
| + } |
| } |
| if (object.isLayoutPart()) { |
| Widget* widget = toLayoutPart(object).widget(); |
| if (widget && widget->isFrameView()) |
| - walk(*toFrameView(widget), localContext); |
| + walk(*toFrameView(widget), localContext, paintInvalidationState.get()); |
| // TODO(pdr): Investigate RemoteFrameView (crbug.com/579281). |
| } |
| } |