Chromium Code Reviews| Index: third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp |
| diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp |
| index a2325fe77835be20065d047ae322709a7a324c04..4f4d86acf14ccd0056b187c6c532b50e58c3540c 100644 |
| --- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp |
| +++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp |
| @@ -13,6 +13,7 @@ |
| #include "core/layout/svg/LayoutSVGRoot.h" |
| #include "core/paint/ObjectPaintProperties.h" |
| #include "core/paint/PaintLayer.h" |
| +#include "core/paint/PaintPropertyUnderInvalidationChecks.h" |
| #include "core/paint/SVGRootPainter.h" |
| #include "platform/transforms/TransformationMatrix.h" |
| #include "wtf/PtrUtil.h" |
| @@ -135,7 +136,7 @@ ScrollPaintPropertyNode* updateFrameViewScroll( |
| return frameView.scroll(); |
| } |
| -void PaintPropertyTreeBuilder::buildTreeNodes( |
| +void PaintPropertyTreeBuilder::updateProperties( |
| FrameView& frameView, |
| PaintPropertyTreeBuilderContext& context) { |
| if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) { |
| @@ -143,16 +144,28 @@ void PaintPropertyTreeBuilder::buildTreeNodes( |
| if (!layoutView) |
| return; |
| - TransformationMatrix frameTranslate; |
| - frameTranslate.translate(frameView.x() + layoutView->location().x() + |
| - context.current.paintOffset.x(), |
| - frameView.y() + layoutView->location().y() + |
| - context.current.paintOffset.y()); |
| - context.current.transform = |
| - layoutView->getMutableForPainting() |
| - .ensurePaintProperties() |
| - .updatePaintOffsetTranslation(context.current.transform, |
| - frameTranslate, FloatPoint3D()); |
| +#ifndef NDEBUG |
|
chrishtr
2016/10/21 22:03:09
#if DCHECK_IS_ON
pdr.
2016/10/26 03:10:48
Done
|
| + auto underInvalidationChecker = |
| + ObjectUnderInvalidationCheckScope::createIfNeeded(*layoutView); |
| +#endif |
| + |
| + if (layoutView->paintPropertiesValid()) { |
| + // No invalidation so update the context using existing properties. |
| + const auto* properties = layoutView->paintProperties(); |
| + if (properties && properties->paintOffsetTranslation()) |
|
chrishtr
2016/10/21 22:03:09
This conditional is not needed, and therefore line
pdr.
2016/10/26 03:10:48
This approach is very nice.
Done.
|
| + context.current.transform = properties->paintOffsetTranslation(); |
| + } else { |
| + TransformationMatrix frameTranslate; |
| + frameTranslate.translate(frameView.x() + layoutView->location().x() + |
| + context.current.paintOffset.x(), |
| + frameView.y() + layoutView->location().y() + |
| + context.current.paintOffset.y()); |
| + context.current.transform = |
| + layoutView->getMutableForPainting() |
| + .ensurePaintProperties() |
| + .updatePaintOffsetTranslation(context.current.transform, |
| + frameTranslate, FloatPoint3D()); |
| + } |
| context.current.paintOffset = LayoutPoint(); |
| context.current.renderingContextID = 0; |
| context.current.shouldFlattenInheritedTransform = true; |
| @@ -163,42 +176,59 @@ void PaintPropertyTreeBuilder::buildTreeNodes( |
| return; |
| } |
| - TransformationMatrix frameTranslate; |
| - frameTranslate.translate(frameView.x() + context.current.paintOffset.x(), |
| - frameView.y() + context.current.paintOffset.y()); |
| - context.current.transform = updateFrameViewPreTranslation( |
| - frameView, context.current.transform, frameTranslate, FloatPoint3D()); |
| - |
| - FloatRoundedRect contentClip( |
| - IntRect(IntPoint(), frameView.visibleContentSize())); |
| - context.current.clip = updateFrameViewContentClip( |
| - frameView, context.current.clip, frameView.preTranslation(), contentClip); |
| - |
| - // Record the fixed properties before any scrolling occurs. |
| - const auto* fixedTransformNode = context.current.transform; |
| - auto* fixedScrollNode = context.current.scroll; |
| - |
| - ScrollOffset scrollOffset = frameView.scrollOffset(); |
| - if (frameView.isScrollable() || !scrollOffset.isZero()) { |
| - TransformationMatrix frameScroll; |
| - frameScroll.translate(-scrollOffset.width(), -scrollOffset.height()); |
| - context.current.transform = updateFrameViewScrollTranslation( |
| - frameView, frameView.preTranslation(), frameScroll, FloatPoint3D()); |
| - |
| - IntSize scrollClip = frameView.visibleContentSize(); |
| - IntSize scrollBounds = frameView.contentsSize(); |
| - bool userScrollableHorizontal = |
| - frameView.userInputScrollable(HorizontalScrollbar); |
| - bool userScrollableVertical = |
| - frameView.userInputScrollable(VerticalScrollbar); |
| - context.current.scroll = updateFrameViewScroll( |
| - frameView, context.current.scroll, frameView.scrollTranslation(), |
| - scrollClip, scrollBounds, userScrollableHorizontal, |
| - userScrollableVertical); |
| +#ifndef NDEBUG |
| + auto underInvalidationChecker = |
| + FrameViewUnderInvalidationCheckScope::createIfNeeded(&frameView); |
| +#endif |
| + |
| + const auto* initialTransformNode = context.current.transform; |
| + auto* initialScrollNode = context.current.scroll; |
| + |
| + if (frameView.paintPropertiesValid()) { |
| + // No invalidation so update the context using existing properties. |
| + if (const auto* preTranslation = frameView.preTranslation()) |
| + context.current.transform = preTranslation; |
| + if (const auto* clip = frameView.contentClip()) |
| + context.current.clip = clip; |
| + if (const auto* scrollTranslation = frameView.scrollTranslation()) |
| + context.current.transform = scrollTranslation; |
| + if (auto* scroll = frameView.scroll()) |
| + context.current.scroll = scroll; |
| } else { |
| - // Ensure pre-existing properties are cleared when there is no scrolling. |
| - frameView.setScrollTranslation(nullptr); |
| - frameView.setScroll(nullptr); |
| + TransformationMatrix frameTranslate; |
| + frameTranslate.translate(frameView.x() + context.current.paintOffset.x(), |
| + frameView.y() + context.current.paintOffset.y()); |
| + context.current.transform = updateFrameViewPreTranslation( |
| + frameView, context.current.transform, frameTranslate, FloatPoint3D()); |
| + |
| + FloatRoundedRect contentClip( |
| + IntRect(IntPoint(), frameView.visibleContentSize())); |
| + context.current.clip = |
| + updateFrameViewContentClip(frameView, context.current.clip, |
| + frameView.preTranslation(), contentClip); |
| + |
| + ScrollOffset scrollOffset = frameView.scrollOffset(); |
| + if (frameView.isScrollable() || !scrollOffset.isZero()) { |
| + TransformationMatrix frameScroll; |
| + frameScroll.translate(-scrollOffset.width(), -scrollOffset.height()); |
| + context.current.transform = updateFrameViewScrollTranslation( |
| + frameView, frameView.preTranslation(), frameScroll, FloatPoint3D()); |
| + |
| + IntSize scrollClip = frameView.visibleContentSize(); |
| + IntSize scrollBounds = frameView.contentsSize(); |
| + bool userScrollableHorizontal = |
| + frameView.userInputScrollable(HorizontalScrollbar); |
| + bool userScrollableVertical = |
| + frameView.userInputScrollable(VerticalScrollbar); |
| + context.current.scroll = updateFrameViewScroll( |
| + frameView, context.current.scroll, frameView.scrollTranslation(), |
| + scrollClip, scrollBounds, userScrollableHorizontal, |
| + userScrollableVertical); |
| + } else { |
| + // Ensure pre-existing properties are cleared when there is no scrolling. |
| + frameView.setScrollTranslation(nullptr); |
| + frameView.setScroll(nullptr); |
| + } |
| } |
| // Initialize the context for current, absolute and fixed position cases. |
| @@ -210,8 +240,10 @@ void PaintPropertyTreeBuilder::buildTreeNodes( |
| context.absolutePosition = context.current; |
| context.containerForAbsolutePosition = nullptr; |
| context.fixedPosition = context.current; |
| - context.fixedPosition.transform = fixedTransformNode; |
| - context.fixedPosition.scroll = fixedScrollNode; |
| + context.fixedPosition.transform = frameView.preTranslation() |
| + ? frameView.preTranslation() |
| + : initialTransformNode; |
| + context.fixedPosition.scroll = initialScrollNode; |
| std::unique_ptr<PropertyTreeState> contentsState( |
| new PropertyTreeState(context.current.transform, context.current.clip, |
| @@ -239,16 +271,25 @@ void PaintPropertyTreeBuilder::updatePaintOffsetTranslation( |
| LayoutPoint fractionalPaintOffset = |
| LayoutPoint(context.current.paintOffset - roundedPaintOffset); |
| - context.current.transform = |
| - object.getMutableForPainting() |
| - .ensurePaintProperties() |
| - .updatePaintOffsetTranslation( |
| - context.current.transform, |
| - TransformationMatrix().translate(roundedPaintOffset.x(), |
| - roundedPaintOffset.y()), |
| - FloatPoint3D(), |
| - context.current.shouldFlattenInheritedTransform, |
| - context.current.renderingContextID); |
| + // TODO(pdr): Refactor this check to be higher so the layer and |
| + // paintsWithTransform checks can be skipped if there's no invalidation. |
| + if (object.paintPropertiesValid()) { |
| + // No invalidation so update the context using existing properties. |
| + const auto* properties = object.paintProperties(); |
| + if (properties && properties->paintOffsetTranslation()) |
| + context.current.transform = properties->paintOffsetTranslation(); |
| + } else { |
| + context.current.transform = |
| + object.getMutableForPainting() |
| + .ensurePaintProperties() |
| + .updatePaintOffsetTranslation( |
| + context.current.transform, |
| + TransformationMatrix().translate(roundedPaintOffset.x(), |
| + roundedPaintOffset.y()), |
| + FloatPoint3D(), |
| + context.current.shouldFlattenInheritedTransform, |
| + context.current.renderingContextID); |
| + } |
| context.current.paintOffset = fractionalPaintOffset; |
| return; |
| } |
| @@ -257,8 +298,10 @@ void PaintPropertyTreeBuilder::updatePaintOffsetTranslation( |
| if (object.isLayoutView()) |
| return; |
| - if (auto* properties = object.getMutableForPainting().paintProperties()) |
| - properties->clearPaintOffsetTranslation(); |
| + if (!object.paintPropertiesValid()) { |
| + if (auto* properties = object.getMutableForPainting().paintProperties()) |
| + properties->clearPaintOffsetTranslation(); |
| + } |
| } |
| static FloatPoint3D transformOrigin(const LayoutBox& box) { |
|
chrishtr
2016/10/21 22:03:09
This method is now getting very long, refactor it?
pdr.
2016/10/26 03:10:48
Done. Split out the svg-specific code into its own
|
| @@ -278,29 +321,68 @@ void PaintPropertyTreeBuilder::updateTransform( |
| DCHECK(object.isSVGForeignObject() || |
| context.current.paintOffset == LayoutPoint()); |
| - // FIXME(pdr): Check for the presence of a transform instead of the value. |
| - // Checking for an identity matrix will cause the property tree structure to |
| - // change during animations if the animation passes through the identity |
| - // matrix. |
| - // FIXME(pdr): Refactor this so all non-root SVG objects use the same |
| - // transform function. |
| - const AffineTransform& transform = object.isSVGForeignObject() |
| - ? object.localSVGTransform() |
| - : object.localToSVGParentTransform(); |
| - if (!transform.isIdentity()) { |
| - // The origin is included in the local transform, so leave origin empty. |
| - context.current.transform = |
| - object.getMutableForPainting() |
| - .ensurePaintProperties() |
| - .updateTransform(context.current.transform, |
| - TransformationMatrix(transform), FloatPoint3D()); |
| - context.current.renderingContextID = 0; |
| - context.current.shouldFlattenInheritedTransform = false; |
| - return; |
| + if (object.paintPropertiesValid()) { |
| + // No invalidation so update the context using existing properties. |
| + if (object.paintProperties() && object.paintProperties()->transform()) { |
| + context.current.transform = object.paintProperties()->transform(); |
| + context.current.shouldFlattenInheritedTransform = false; |
| + context.current.renderingContextID = 0; |
| + } |
| + } else { |
| + // FIXME(pdr): Check for the presence of a transform instead of the value. |
| + // Checking for an identity matrix will cause the property tree structure |
| + // to change during animations if the animation passes through the |
| + // identity matrix. |
| + // FIXME(pdr): Refactor this so all non-root SVG objects use the same |
| + // transform function. |
| + const AffineTransform& transform = |
| + object.isSVGForeignObject() ? object.localSVGTransform() |
| + : object.localToSVGParentTransform(); |
| + if (!transform.isIdentity()) { |
| + // The origin is included in the local transform, so leave origin empty. |
| + context.current.transform = |
| + object.getMutableForPainting() |
| + .ensurePaintProperties() |
| + .updateTransform(context.current.transform, |
| + TransformationMatrix(transform), |
| + FloatPoint3D()); |
| + context.current.shouldFlattenInheritedTransform = false; |
| + context.current.renderingContextID = 0; |
| + } else { |
| + if (auto* properties = object.getMutableForPainting().paintProperties()) |
| + properties->clearTransform(); |
| + } |
| } |
| - } else { |
| - const ComputedStyle& style = object.styleRef(); |
| - if (object.isBox() && (style.hasTransform() || style.preserves3D())) { |
| + return; |
| + } |
| + |
| + const ComputedStyle& style = object.styleRef(); |
| + if (object.isBox() && (style.hasTransform() || style.preserves3D())) { |
| + unsigned renderingContextID = context.current.renderingContextID; |
| + unsigned renderingContextIDForChildren = 0; |
| + bool flattensInheritedTransform = |
| + context.current.shouldFlattenInheritedTransform; |
| + bool childrenFlattenInheritedTransform = true; |
| + |
| + // TODO(trchen): transform-style should only be respected if a PaintLayer |
| + // is created. |
| + if (style.preserves3D()) { |
| + // If a node with transform-style: preserve-3d does not exist in an |
| + // existing rendering context, it establishes a new one. |
| + if (!renderingContextID) |
| + renderingContextID = PtrHash<const LayoutObject>::hash(&object); |
| + renderingContextIDForChildren = renderingContextID; |
| + childrenFlattenInheritedTransform = false; |
| + } |
| + context.current.renderingContextID = renderingContextIDForChildren; |
| + context.current.shouldFlattenInheritedTransform = |
| + childrenFlattenInheritedTransform; |
| + |
| + if (object.paintPropertiesValid()) { |
| + // No invalidation so update the context using existing properties. |
| + if (object.paintProperties() && object.paintProperties()->transform()) |
| + context.current.transform = object.paintProperties()->transform(); |
| + } else { |
| TransformationMatrix matrix; |
| style.applyTransform( |
| matrix, toLayoutBox(object).size(), |
| @@ -308,83 +390,79 @@ void PaintPropertyTreeBuilder::updateTransform( |
| ComputedStyle::IncludeMotionPath, |
| ComputedStyle::IncludeIndependentTransformProperties); |
| FloatPoint3D origin = transformOrigin(toLayoutBox(object)); |
| - |
| - unsigned renderingContextID = context.current.renderingContextID; |
| - unsigned renderingContextIDForChildren = 0; |
| - bool flattensInheritedTransform = |
| - context.current.shouldFlattenInheritedTransform; |
| - bool childrenFlattenInheritedTransform = true; |
| - |
| - // TODO(trchen): transform-style should only be respected if a PaintLayer |
| - // is created. |
| - if (style.preserves3D()) { |
| - // If a node with transform-style: preserve-3d does not exist in an |
| - // existing rendering context, it establishes a new one. |
| - if (!renderingContextID) |
| - renderingContextID = PtrHash<const LayoutObject>::hash(&object); |
| - renderingContextIDForChildren = renderingContextID; |
| - childrenFlattenInheritedTransform = false; |
| - } |
| - |
| context.current.transform = |
| object.getMutableForPainting() |
| .ensurePaintProperties() |
| .updateTransform(context.current.transform, matrix, origin, |
| flattensInheritedTransform, renderingContextID); |
| - context.current.renderingContextID = renderingContextIDForChildren; |
| - context.current.shouldFlattenInheritedTransform = |
| - childrenFlattenInheritedTransform; |
| - return; |
| + } |
| + } else { |
| + if (!object.paintPropertiesValid()) { |
| + if (auto* properties = object.getMutableForPainting().paintProperties()) |
| + properties->clearTransform(); |
| } |
| } |
| - |
| - if (auto* properties = object.getMutableForPainting().paintProperties()) |
| - properties->clearTransform(); |
| } |
| void PaintPropertyTreeBuilder::updateEffect( |
| const LayoutObject& object, |
| PaintPropertyTreeBuilderContext& context) { |
| - if (!object.styleRef().hasOpacity()) { |
| - if (auto* properties = object.getMutableForPainting().paintProperties()) |
| - properties->clearEffect(); |
| - return; |
| + if (object.paintPropertiesValid()) { |
| + // No invalidation so update the context using existing properties. |
| + if (object.paintProperties() && object.paintProperties()->effect()) |
| + context.currentEffect = object.paintProperties()->effect(); |
| + } else { |
| + if (object.styleRef().hasOpacity()) { |
| + context.currentEffect = |
| + object.getMutableForPainting().ensurePaintProperties().updateEffect( |
| + context.currentEffect, object.styleRef().opacity()); |
| + } else { |
| + if (auto* properties = object.getMutableForPainting().paintProperties()) |
| + properties->clearEffect(); |
| + } |
| } |
| - |
| - context.currentEffect = |
| - object.getMutableForPainting().ensurePaintProperties().updateEffect( |
| - context.currentEffect, object.styleRef().opacity()); |
| } |
| void PaintPropertyTreeBuilder::updateCssClip( |
| const LayoutObject& object, |
| PaintPropertyTreeBuilderContext& context) { |
| - if (object.hasClip()) { |
| - // Create clip node for descendants that are not fixed position. |
| - // We don't have to setup context.absolutePosition.clip here because this |
| - // object must be a container for absolute position descendants, and will |
| - // copy from in-flow context later at updateOutOfFlowContext() step. |
| - DCHECK(object.canContainAbsolutePositionObjects()); |
| - LayoutRect clipRect = |
| - toLayoutBox(object).clipRect(context.current.paintOffset); |
| - context.current.clip = |
| - object.getMutableForPainting().ensurePaintProperties().updateCssClip( |
| - context.current.clip, context.current.transform, |
| - FloatRoundedRect(FloatRect(clipRect))); |
| - return; |
| + if (object.paintPropertiesValid()) { |
| + // No invalidation so update the context using existing properties. |
| + if (object.paintProperties() && object.paintProperties()->cssClip()) |
| + context.current.clip = object.paintProperties()->cssClip(); |
| + } else { |
| + if (object.hasClip()) { |
| + // Create clip node for descendants that are not fixed position. |
| + // We don't have to setup context.absolutePosition.clip here because this |
| + // object must be a container for absolute position descendants, and will |
| + // copy from in-flow context later at updateOutOfFlowContext() step. |
| + DCHECK(object.canContainAbsolutePositionObjects()); |
| + LayoutRect clipRect = |
| + toLayoutBox(object).clipRect(context.current.paintOffset); |
| + context.current.clip = |
| + object.getMutableForPainting().ensurePaintProperties().updateCssClip( |
| + context.current.clip, context.current.transform, |
| + FloatRoundedRect(FloatRect(clipRect))); |
| + } else { |
| + if (auto* properties = object.getMutableForPainting().paintProperties()) |
| + properties->clearCssClip(); |
| + } |
| } |
| - |
| - if (auto* properties = object.getMutableForPainting().paintProperties()) |
| - properties->clearCssClip(); |
| } |
| void PaintPropertyTreeBuilder::updateLocalBorderBoxContext( |
| const LayoutObject& object, |
| PaintPropertyTreeBuilderContext& context) { |
| + if (object.paintPropertiesValid()) |
| + return; |
| + |
| // Avoid adding an ObjectPaintProperties for non-boxes to save memory, since |
| // we don't need them at the moment. |
| - if (!object.isBox() && !object.hasLayer()) |
| + if (!object.isBox() && !object.hasLayer()) { |
| + if (auto* properties = object.getMutableForPainting().paintProperties()) |
| + properties->clearLocalBorderBoxProperties(); |
|
chrishtr
2016/10/21 22:03:09
Why is this change needed but wasn't in the old co
pdr.
2016/10/26 03:10:48
This is just a cleanup so we don't leave unnecessa
|
| return; |
| + } |
| std::unique_ptr<ObjectPaintProperties::PropertyTreeStateWithOffset> |
| borderBoxContext = |
| @@ -402,6 +480,9 @@ void PaintPropertyTreeBuilder::updateLocalBorderBoxContext( |
| void PaintPropertyTreeBuilder::updateScrollbarPaintOffset( |
| const LayoutObject& object, |
| const PaintPropertyTreeBuilderContext& context) { |
| + if (object.paintPropertiesValid()) |
| + return; |
| + |
| IntPoint roundedPaintOffset = roundedIntPoint(context.current.paintOffset); |
| if (roundedPaintOffset != IntPoint() && object.isBoxModelObject()) { |
| if (PaintLayerScrollableArea* scrollableArea = |
| @@ -426,10 +507,13 @@ void PaintPropertyTreeBuilder::updateScrollbarPaintOffset( |
| void PaintPropertyTreeBuilder::updateMainThreadScrollingReasons( |
| const LayoutObject& object, |
| PaintPropertyTreeBuilderContext& context) { |
| + // TODO(pdr): Add property under-invalidation checking for main thread scroll |
| + // reasons and ensure reason changes invalidate property trees. |
| if (context.current.scroll && |
| - !object.document().settings()->threadedScrollingEnabled()) |
| + !object.document().settings()->threadedScrollingEnabled()) { |
| context.current.scroll->addMainThreadScrollingReasons( |
| MainThreadScrollingReason::kThreadedScrollingDisabled); |
| + } |
| if (object.isBackgroundAttachmentFixedObject()) { |
| auto* scrollNode = context.current.scroll; |
| @@ -451,6 +535,14 @@ void PaintPropertyTreeBuilder::updateOverflowClip( |
| return; |
| const LayoutBox& box = toLayoutBox(object); |
| + if (object.paintPropertiesValid()) { |
| + // No invalidation so update the context using existing properties. |
| + const auto* properties = object.paintProperties(); |
| + if (properties && properties->overflowClip()) |
| + context.current.clip = properties->overflowClip(); |
| + return; |
| + } |
| + |
| // The <input> elements can't have contents thus CSS overflow property doesn't |
| // apply. However for layout purposes we do generate child layout objects for |
| // them, e.g. button label. We should clip the overflow from those children. |
| @@ -503,23 +595,32 @@ void PaintPropertyTreeBuilder::updatePerspective( |
| PaintPropertyTreeBuilderContext& context) { |
| const ComputedStyle& style = object.styleRef(); |
| if (!object.isBox() || !style.hasPerspective()) { |
| - if (auto* properties = object.getMutableForPainting().paintProperties()) |
| - properties->clearPerspective(); |
| + if (!object.paintPropertiesValid()) { |
| + if (auto* properties = object.getMutableForPainting().paintProperties()) |
| + properties->clearPerspective(); |
| + } |
| return; |
| } |
| - // The perspective node must not flatten (else nothing will get |
| - // perspective), but it should still extend the rendering context as most |
| - // transform nodes do. |
| - TransformationMatrix matrix = |
| - TransformationMatrix().applyPerspective(style.perspective()); |
| - FloatPoint3D origin = perspectiveOrigin(toLayoutBox(object)) + |
| - toLayoutSize(context.current.paintOffset); |
| - context.current.transform = |
| - object.getMutableForPainting().ensurePaintProperties().updatePerspective( |
| - context.current.transform, matrix, origin, |
| - context.current.shouldFlattenInheritedTransform, |
| - context.current.renderingContextID); |
| + if (object.paintPropertiesValid()) { |
| + // No invalidation so update the context using existing properties. |
| + if (object.paintProperties() && object.paintProperties()->perspective()) |
| + context.current.transform = object.paintProperties()->perspective(); |
| + } else { |
| + // The perspective node must not flatten (else nothing will get |
| + // perspective), but it should still extend the rendering context as most |
| + // transform nodes do. |
| + TransformationMatrix matrix = |
| + TransformationMatrix().applyPerspective(style.perspective()); |
| + FloatPoint3D origin = perspectiveOrigin(toLayoutBox(object)) + |
| + toLayoutSize(context.current.paintOffset); |
| + context.current.transform = |
| + object.getMutableForPainting() |
| + .ensurePaintProperties() |
| + .updatePerspective(context.current.transform, matrix, origin, |
| + context.current.shouldFlattenInheritedTransform, |
| + context.current.renderingContextID); |
| + } |
| context.current.shouldFlattenInheritedTransform = false; |
| } |
| @@ -529,32 +630,53 @@ void PaintPropertyTreeBuilder::updateSvgLocalToBorderBoxTransform( |
| if (!object.isSVGRoot()) |
| return; |
| - AffineTransform transformToBorderBox = |
| - SVGRootPainter(toLayoutSVGRoot(object)) |
| - .transformToPixelSnappedBorderBox(context.current.paintOffset); |
| + if (object.paintPropertiesValid()) { |
| + // No invalidation so update the context using existing properties. |
| + const auto* properties = object.paintProperties(); |
| + if (properties && properties->svgLocalToBorderBoxTransform()) { |
| + context.current.transform = properties->svgLocalToBorderBoxTransform(); |
| + context.current.shouldFlattenInheritedTransform = false; |
| + context.current.renderingContextID = 0; |
| + } |
| + } else { |
| + AffineTransform transformToBorderBox = |
| + SVGRootPainter(toLayoutSVGRoot(object)) |
| + .transformToPixelSnappedBorderBox(context.current.paintOffset); |
| + |
| + if (transformToBorderBox.isIdentity()) { |
| + if (auto* properties = object.getMutableForPainting().paintProperties()) |
| + properties->clearSvgLocalToBorderBoxTransform(); |
| + } else { |
| + context.current.transform = object.getMutableForPainting() |
| + .ensurePaintProperties() |
| + .updateSvgLocalToBorderBoxTransform( |
| + context.current.transform, |
| + transformToBorderBox, FloatPoint3D()); |
| + context.current.shouldFlattenInheritedTransform = false; |
| + context.current.renderingContextID = 0; |
| + } |
| + } |
| // The paint offset is included in |transformToBorderBox| so SVG does not need |
| // to handle paint offset internally. |
| context.current.paintOffset = LayoutPoint(); |
| - |
| - if (transformToBorderBox.isIdentity()) { |
| - if (auto* properties = object.getMutableForPainting().paintProperties()) |
| - properties->clearSvgLocalToBorderBoxTransform(); |
| - return; |
| - } |
| - |
| - context.current.transform = |
| - object.getMutableForPainting() |
| - .ensurePaintProperties() |
| - .updateSvgLocalToBorderBoxTransform( |
| - context.current.transform, transformToBorderBox, FloatPoint3D()); |
| - context.current.shouldFlattenInheritedTransform = false; |
| - context.current.renderingContextID = 0; |
| } |
| void PaintPropertyTreeBuilder::updateScrollAndScrollTranslation( |
| const LayoutObject& object, |
| PaintPropertyTreeBuilderContext& context) { |
| + if (object.paintPropertiesValid()) { |
| + // No invalidation so update the context using existing properties. |
| + if (object.paintProperties() && object.paintProperties()->scroll()) { |
| + context.current.transform = object.paintProperties()->transform(); |
| + const auto* scroll = object.paintProperties()->scroll(); |
| + // TODO(pdr): Remove this const cast. |
| + context.current.scroll = const_cast<ScrollPaintPropertyNode*>(scroll); |
| + context.current.shouldFlattenInheritedTransform = false; |
| + } |
| + return; |
| + } |
| + |
| if (object.hasOverflowClip()) { |
| const LayoutBox& box = toLayoutBox(object); |
| const PaintLayerScrollableArea* scrollableArea = box.getScrollableArea(); |
| @@ -628,20 +750,29 @@ void PaintPropertyTreeBuilder::updateOutOfFlowContext( |
| if (context.fixedPosition.clip == cssClip->parent()) { |
| context.fixedPosition.clip = cssClip; |
| } else { |
| - context.fixedPosition.clip = |
| - object.getMutableForPainting() |
| - .ensurePaintProperties() |
| - .updateCssClipFixedPosition( |
| - context.fixedPosition.clip, |
| - const_cast<TransformPaintPropertyNode*>( |
| - cssClip->localTransformSpace()), |
| - cssClip->clipRect()); |
| + if (object.paintPropertiesValid()) { |
| + // No invalidation so update the context using existing properties. |
| + const auto* properties = object.paintProperties(); |
| + if (properties && properties->cssClipFixedPosition()) |
| + context.fixedPosition.clip = properties->cssClipFixedPosition(); |
| + } else { |
| + context.fixedPosition.clip = |
| + object.getMutableForPainting() |
| + .ensurePaintProperties() |
| + .updateCssClipFixedPosition( |
| + context.fixedPosition.clip, |
| + const_cast<TransformPaintPropertyNode*>( |
| + cssClip->localTransformSpace()), |
| + cssClip->clipRect()); |
| + } |
| return; |
| } |
| } |
| - if (auto* properties = object.getMutableForPainting().paintProperties()) |
| - properties->clearCssClipFixedPosition(); |
| + if (!object.paintPropertiesValid()) { |
| + if (auto* properties = object.getMutableForPainting().paintProperties()) |
| + properties->clearCssClipFixedPosition(); |
| + } |
| } |
| // Override ContainingBlockContext based on the properties of a containing block |
| @@ -766,12 +897,17 @@ static void deriveBorderBoxFromContainerContext( |
| } |
| } |
| -void PaintPropertyTreeBuilder::buildTreeNodesForSelf( |
| +void PaintPropertyTreeBuilder::updatePropertiesForSelf( |
| const LayoutObject& object, |
| PaintPropertyTreeBuilderContext& context) { |
| if (!object.isBoxModelObject() && !object.isSVG()) |
| return; |
| +#ifndef NDEBUG |
| + auto underInvalidationChecker = |
| + ObjectUnderInvalidationCheckScope::createIfNeeded(object); |
| +#endif |
| + |
| deriveBorderBoxFromContainerContext(object, context); |
| updatePaintOffsetTranslation(object, context); |
| @@ -783,12 +919,17 @@ void PaintPropertyTreeBuilder::buildTreeNodesForSelf( |
| updateMainThreadScrollingReasons(object, context); |
| } |
| -void PaintPropertyTreeBuilder::buildTreeNodesForChildren( |
| +void PaintPropertyTreeBuilder::updatePropertiesForChildren( |
| const LayoutObject& object, |
| PaintPropertyTreeBuilderContext& context) { |
| if (!object.isBoxModelObject() && !object.isSVG()) |
| return; |
| +#ifndef NDEBUG |
| + auto underInvalidationChecker = |
| + ObjectUnderInvalidationCheckScope::createIfNeeded(object); |
| +#endif |
| + |
| updateOverflowClip(object, context); |
| updatePerspective(object, context); |
| updateSvgLocalToBorderBoxTransform(object, context); |