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 |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..84cdf09273fb75a4d3ac9be06771a7faa64bdf5a |
| --- /dev/null |
| +++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp |
| @@ -0,0 +1,203 @@ |
| +// Copyright 2015 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "config.h" |
| +#include "core/paint/PaintPropertyTreeBuilder.h" |
| + |
| +#include "core/frame/FrameView.h" |
| +#include "core/layout/LayoutView.h" |
| +#include "core/paint/ObjectPaintProperties.h" |
| +#include "core/paint/PaintLayer.h" |
| +#include "platform/graphics/paint/TransformPaintPropertyNode.h" |
| +#include "platform/transforms/TransformationMatrix.h" |
| + |
| +namespace blink { |
| + |
| +struct PaintPropertyTreeBuilder::Context { |
|
pdr.
2015/10/20 22:02:30
Lets doc this with a small comment describing why
jbroman
2015/10/20 23:50:13
I'd also like a brief explanation of how it works.
trchen
2015/10/21 06:16:20
Done.
|
| + Context() : currentTransform(nullptr), transformForOutOfFlowPositioned(nullptr), transformForFixedPositioned(nullptr) { } |
| + |
| + TransformPaintPropertyNode* currentTransform; |
| + LayoutPoint paintOffset; |
| + |
| + TransformPaintPropertyNode* transformForOutOfFlowPositioned; |
| + LayoutPoint paintOffsetForOutOfFlowPositioned; |
| + |
| + TransformPaintPropertyNode* transformForFixedPositioned; |
| + LayoutPoint paintOffsetForFixedPositioned; |
| +}; |
| + |
| +void PaintPropertyTreeBuilder::buildPropertyTrees(FrameView& rootFrame) |
| +{ |
| + walk(rootFrame, Context()); |
| +} |
| + |
| +void PaintPropertyTreeBuilder::walk(FrameView& frameView, const Context& context) |
| +{ |
| + Context localContext(context); |
| + RefPtr<TransformPaintPropertyNode> newTransformNodeForPreTranslation; |
|
pdr.
2015/10/20 22:02:30
In this function only, lets move these decls down
trchen
2015/10/21 06:16:20
Done.
|
| + RefPtr<TransformPaintPropertyNode> newTransformNodeForScrollTranslation; |
| + |
| + TransformationMatrix frameTranslate; |
| + frameTranslate.translate(frameView.x(), frameView.y()); |
| + // The frame owner applies paint offset already. |
| + // This assumption may change in the future. |
| + ASSERT(context.paintOffset == LayoutPoint()); |
| + newTransformNodeForPreTranslation = TransformPaintPropertyNode::create(frameTranslate, FloatPoint3D(), context.currentTransform); |
| + localContext.transformForFixedPositioned = newTransformNodeForPreTranslation.get(); |
| + localContext.paintOffsetForFixedPositioned = LayoutPoint(); |
| + |
| + // This is going away in favor of Settings::rootLayerScrolls. |
| + DoubleSize scrollOffset = frameView.scrollOffsetDouble(); |
| + TransformationMatrix frameScroll; |
| + frameScroll.translate(-scrollOffset.width(), -scrollOffset.height()); |
| + newTransformNodeForScrollTranslation = TransformPaintPropertyNode::create(frameScroll, FloatPoint3D(), newTransformNodeForPreTranslation); |
| + localContext.currentTransform = localContext.transformForOutOfFlowPositioned = newTransformNodeForScrollTranslation.get(); |
| + localContext.paintOffset = localContext.paintOffsetForOutOfFlowPositioned = LayoutPoint(); |
| + |
| + frameView.setPreTranslation(newTransformNodeForPreTranslation.release()); |
| + frameView.setScrollTranslation(newTransformNodeForScrollTranslation.release()); |
| + |
| + if (LayoutView* layoutView = frameView.layoutView()) |
| + walk(*layoutView, localContext); |
| +} |
| + |
| +static bool shouldCreatePreTranslationNode(LayoutBoxModelObject& object) |
| +{ |
| + // TODO(trchen): Eliminate PaintLayer dependency. |
| + PaintLayer* layer = object.layer(); |
| + if (!layer) |
| + return false; |
| + |
| + return layer->paintsWithTransform(GlobalPaintNormalPhase); |
| +} |
| + |
| +static FloatPoint3D transformOrigin(const LayoutBox& box) |
| +{ |
| + const ComputedStyle& style = box.styleRef(); |
| + |
| + FloatSize borderBoxSize(box.size()); |
| + return FloatPoint3D(floatValueForLength(style.transformOriginX(), borderBoxSize.width()), floatValueForLength(style.transformOriginY(), borderBoxSize.height()), style.transformOriginZ()); |
|
pdr.
2015/10/20 22:02:30
Can you break this line so it's a little easier to
trchen
2015/10/21 06:16:20
Done.
|
| +} |
| + |
| +static FloatPoint perspectiveOrigin(const LayoutBox& box) |
| +{ |
| + const ComputedStyle& style = box.styleRef(); |
| + |
|
jbroman
2015/10/20 23:50:13
super-nit: remove this newline?
trchen
2015/10/21 06:16:20
Done.
|
| + FloatSize borderBoxSize(box.size()); |
| + return FloatPoint(floatValueForLength(style.perspectiveOriginX(), borderBoxSize.width()), floatValueForLength(style.perspectiveOriginY(), borderBoxSize.height())); |
| +} |
| + |
| +void PaintPropertyTreeBuilder::walk(LayoutBoxModelObject& object, const Context& context) |
| +{ |
| + ASSERT(object.isBox() != object.isLayoutInline()); // Either or. |
|
pdr.
2015/10/20 22:02:30
There are many checks for isBox() in this function
trchen
2015/10/21 06:16:20
Yea... Many CSS properties don't apply on inlines.
|
| + |
| + Context localContext(context); |
| + RefPtr<TransformPaintPropertyNode> newTransformNodeForPreTranslation; |
| + RefPtr<TransformPaintPropertyNode> newTransformNodeForTransform; |
| + RefPtr<TransformPaintPropertyNode> newTransformNodeForPerspective; |
| + RefPtr<TransformPaintPropertyNode> newTransformNodeForScrollTranslation; |
| + |
| + // Step 1: Figure out the layout space of the current object. |
| + const ComputedStyle& style = object.styleRef(); |
| + // TODO(trchen): There is some insanity going on with tables. Double check results. |
| + switch (style.position()) { |
| + case StaticPosition: |
| + break; |
| + case RelativePosition: |
| + localContext.paintOffset += object.offsetForInFlowPosition(); |
| + break; |
| + case AbsolutePosition: |
| + localContext.currentTransform = context.transformForOutOfFlowPositioned; |
| + localContext.paintOffset = context.paintOffsetForOutOfFlowPositioned; |
| + break; |
| + case StickyPosition: |
| + localContext.paintOffset += object.offsetForInFlowPosition(); |
| + break; |
| + case FixedPosition: |
| + localContext.currentTransform = context.transformForFixedPositioned; |
| + localContext.paintOffset = context.paintOffsetForFixedPositioned; |
| + break; |
| + default: |
| + ASSERT_NOT_REACHED(); |
| + } |
| + if (object.isBox()) |
| + localContext.paintOffset += toLayoutBox(object).locationOffset(); |
| + |
| + // Step 2: Create a transform node to consolidate paint offset (if needed). |
| + if (shouldCreatePreTranslationNode(object) && localContext.paintOffset != LayoutPoint()) { |
| + TransformationMatrix matrix; |
| + matrix.translate(localContext.paintOffset.x(), localContext.paintOffset.y()); |
| + newTransformNodeForPreTranslation = TransformPaintPropertyNode::create(matrix, FloatPoint3D(), localContext.currentTransform); |
| + localContext.currentTransform = newTransformNodeForPreTranslation.get(); |
| + localContext.paintOffset = LayoutPoint(); |
| + } |
| + |
| + // Step 3: Create a transform node for CSS transform (if presents). |
|
pdr.
2015/10/20 22:02:30
Nit: "if presents" -> "if present" (here, and belo
trchen
2015/10/21 06:16:20
Done.
|
| + bool hasTransform = object.isBox() && style.hasTransform(); |
| + if (hasTransform) { |
| + TransformationMatrix matrix; |
| + style.applyTransform(matrix, toLayoutBox(object).size(), ComputedStyle::ExcludeTransformOrigin, ComputedStyle::IncludeMotionPath, ComputedStyle::IncludeIndependentTransformProperties); |
|
jbroman
2015/10/20 23:50:13
nit: Mind wrapping some of these long lines? I kno
trchen
2015/10/21 06:16:20
Done.
|
| + newTransformNodeForTransform = TransformPaintPropertyNode::create(matrix, transformOrigin(toLayoutBox(object)), localContext.currentTransform); |
| + localContext.currentTransform = newTransformNodeForTransform.get(); |
| + ASSERT(localContext.paintOffset == LayoutPoint()); |
| + } |
| + // At this point, the current space is the space we paint the element itself. |
| + |
| + // Step 3: Create a transform node for CSS perspective (if presents). |
|
jbroman
2015/10/20 23:50:13
nit: There are two step 3s. I would probably remov
trchen
2015/10/21 06:16:20
Done.
|
| + if (object.isBox() && style.hasPerspective()) { |
| + TransformationMatrix matrix; |
| + matrix.applyPerspective(style.perspective()); |
| + newTransformNodeForPerspective = TransformPaintPropertyNode::create(matrix, perspectiveOrigin(toLayoutBox(object)) + toLayoutSize(localContext.paintOffset), localContext.currentTransform); |
| + localContext.currentTransform = newTransformNodeForPerspective.get(); |
| + } |
| + |
| + // Step 4: Create a transform node for overflow clip (if presents). |
| + if (object.hasOverflowClip()) { |
| + PaintLayer* layer = object.layer(); |
| + ASSERT(layer); |
| + DoubleSize scrollOffset = layer->scrollableArea()->scrollOffset(); |
| + if (!scrollOffset.isZero() || layer->scrollsOverflow()) { |
| + TransformationMatrix matrix; |
| + matrix.translate(-scrollOffset.width(), -scrollOffset.height()); |
| + newTransformNodeForScrollTranslation = TransformPaintPropertyNode::create(matrix, FloatPoint3D(), localContext.currentTransform); |
| + localContext.currentTransform = newTransformNodeForScrollTranslation.get(); |
| + } |
| + } |
| + // At this point, the current space is the space we paint in-flow children. |
| + |
| + // Step 5: Update the context for out-of-flow descendants (if position container is established). |
| + if (style.position() != StaticPosition || hasTransform) { |
|
jbroman
2015/10/20 23:50:13
Does the logic for what creates a containing block
trchen
2015/10/21 06:16:20
Nope, any divergence is unintentional. shouldCreat
|
| + localContext.transformForOutOfFlowPositioned = localContext.currentTransform; |
| + localContext.paintOffsetForOutOfFlowPositioned = localContext.paintOffset; |
| + } |
| + if (hasTransform) { |
| + localContext.transformForFixedPositioned = localContext.currentTransform; |
| + localContext.paintOffsetForFixedPositioned = localContext.paintOffset; |
| + } |
| + |
| + // Step 6: Memorize the nodes we created for future reference during paint. |
| + if (newTransformNodeForPreTranslation || newTransformNodeForTransform || newTransformNodeForPerspective || newTransformNodeForScrollTranslation) { |
| + ObjectPaintProperties& properties = object.ensureObjectPaintProperties(); |
| + properties.setPreTranslation(newTransformNodeForPreTranslation.release()); |
| + properties.setTransform(newTransformNodeForTransform.release()); |
| + properties.setPerspective(newTransformNodeForPerspective.release()); |
| + properties.setScrollTranslation(newTransformNodeForScrollTranslation.release()); |
| + } else { |
| + object.clearObjectPaintProperties(); |
| + } |
| + |
| + // Step 7: Recur. |
| + if (object.isSVGRoot()) { |
|
pdr.
2015/10/20 22:02:30
Nit:
// TODO(trchen): Implement the SVG transform
trchen
2015/10/21 06:16:20
Done.
|
| + // TODO(trchen): Implement SVG walk. |
| + return; |
| + } |
| + |
| + for (LayoutObject* child = object.slowFirstChild(); child; child = child->nextSibling()) { |
|
pdr.
2015/10/20 22:02:30
Lets move the recur comment here.
trchen
2015/10/21 06:16:20
Nah, for SVG walk it is going to recur too. Just t
|
| + if (child->isText()) |
| + continue; |
| + walk(toLayoutBoxModelObject(*child), localContext); |
| + } |
| +} |
| + |
| +} // namespace blink |