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..afc807d04c8131cca9bb83b8fd2b4886e6e99cf4 |
--- /dev/null |
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp |
@@ -0,0 +1,184 @@ |
+// 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::WalkContext { |
pdr.
2015/10/14 17:52:07
CurrentPropertyTreeContext?
trchen
2015/10/14 22:51:13
I'm thinking just Context... Being a nested class
|
+ explicit WalkContext(TransformPaintPropertyNode* newCurrentTransform = nullptr) : currentTransform(newCurrentTransform) { } |
+ TransformPaintPropertyNode* currentTransform; |
+}; |
+ |
+struct PaintPropertyTreeBuilder::WalkContextHTML : public WalkContext { |
pdr.
2015/10/14 17:52:07
Does this need to be so abstract? What other subcl
trchen
2015/10/14 22:51:13
I'm thinking of SVG. They are different because th
|
+ static WalkContextHTML contextForDocumentNode(TransformPaintPropertyNode* fixed, TransformPaintPropertyNode* absolute) { return WalkContextHTML(fixed, absolute); } |
+ |
+ LayoutPoint paintOffset; |
+ |
+ TransformPaintPropertyNode* transformForOutOfFlowPositioned; |
+ LayoutPoint paintOffsetForOutOfFlowPositioned; |
+ |
+ TransformPaintPropertyNode* transformForFixedPositioned; |
+ LayoutPoint paintOffsetForFixedPositioned; |
+private: |
+ WalkContextHTML(TransformPaintPropertyNode* fixed, TransformPaintPropertyNode* absolute) |
+ : WalkContext(absolute) |
+ , transformForOutOfFlowPositioned(absolute) |
+ , transformForFixedPositioned(fixed) |
+ { |
+ } |
+}; |
+ |
+void PaintPropertyTreeBuilder::buildPropertyTrees(FrameView& rootFrame) |
+{ |
+ walk(rootFrame, WalkContext()); |
+} |
+ |
+void PaintPropertyTreeBuilder::walk(FrameView& frameView, const WalkContext& context) |
+{ |
+ ObjectPaintProperties& properties = frameView.ensureObjectPaintProperties(); |
+ |
+ TransformationMatrix frameTranslate; |
+ frameTranslate.translate(frameView.x(), frameView.y()); |
+ TransformPaintPropertyNode* transformNodeForSelf = new TransformPaintPropertyNode(frameTranslate, FloatPoint3D(), context.currentTransform); |
+ properties.setTransformNodeForSelf(adoptRef(transformNodeForSelf)); |
+ |
+ TransformationMatrix frameScroll; |
+ frameScroll.translate(-frameView.scrollX(), -frameView.scrollY()); |
+ TransformPaintPropertyNode* transformNodeForDescendants = new TransformPaintPropertyNode(frameScroll, FloatPoint3D(), transformNodeForSelf); |
+ properties.setTransformNodeForDescendants(adoptRef(transformNodeForDescendants)); |
+ |
+ if (LayoutView* layoutView = frameView.layoutView()) |
+ walk(*layoutView, WalkContextHTML::contextForDocumentNode(transformNodeForSelf, transformNodeForDescendants)); |
+} |
+ |
+static bool shouldCreateTransformNodeForSelf(LayoutBoxModelObject& object) |
+{ |
+ // TODO(trchen): Eliminate PaintLayer dependency. |
+ PaintLayer* layer = object.layer(); |
+ if (!layer) |
+ return false; |
+ |
+ return layer->paintsWithTransform(GlobalPaintNormalPhase); |
+} |
+ |
+static FloatPoint perspectiveOrigin(const LayoutBox& box) |
+{ |
+ const ComputedStyle& style = box.styleRef(); |
+ |
+ FloatSize borderBoxSize(box.size()); |
+ return FloatPoint(floatValueForLength(style.perspectiveOriginX(), borderBoxSize.width()), floatValueForLength(style.perspectiveOriginY(), borderBoxSize.height())); |
+} |
+ |
+void PaintPropertyTreeBuilder::walk(LayoutBoxModelObject& object, const WalkContextHTML& context) |
+{ |
+ ASSERT(object.isBox() != object.isLayoutInline()); // Either or. |
+ |
+ WalkContextHTML localContext(context); |
+ RefPtr<TransformPaintPropertyNode> newTransformNodeForSelf; |
+ RefPtr<TransformPaintPropertyNode> newTransformNodeForDescendants; |
+ |
+ 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(); |
+ |
+ bool hasTransform = object.isBox() && style.hasTransform(); |
pdr.
2015/10/14 18:44:15
I think it's important to unblock some work that d
trchen
2015/10/14 22:51:13
We need to keep track of paint offset in order to
pdr.
2015/10/15 04:53:52
In order to land this, we will need a ridiculous n
trchen
2015/10/15 23:24:31
IMO without paint offset handling the code will be
|
+ if (shouldCreateTransformNodeForSelf(object)) { |
+ TransformationMatrix matrix; |
+ if (hasTransform) |
+ style.applyTransform(matrix, toLayoutBox(object).size(), ComputedStyle::IncludeTransformOrigin, ComputedStyle::IncludeMotionPath, ComputedStyle::IncludeIndependentTransformProperties); |
+ matrix.translateRight(localContext.paintOffset.x(), localContext.paintOffset.y()); |
+ // TODO(jbroman): Put the real transform origin here, instead of using a |
+ // matrix with the origin baked in. |
+ newTransformNodeForSelf = adoptRef(new TransformPaintPropertyNode(matrix, FloatPoint3D(), localContext.currentTransform)); |
+ localContext.currentTransform = newTransformNodeForSelf.get(); |
+ localContext.paintOffset = LayoutPoint(); |
+ } else { |
+ ASSERT(!hasTransform); |
+ } |
+ |
+ if (object.isBox() && style.hasPerspective()) { |
+ FloatPoint origin = perspectiveOrigin(toLayoutBox(object)); |
+ TransformationMatrix matrix; |
+ matrix.applyPerspective(style.perspective()); |
+ matrix.translate(-origin.x(), -origin.y()); |
jbroman
2015/10/14 15:11:58
TransformationMatrix::applyTransformOrigin
trchen
2015/10/14 22:51:13
Done.
|
+ matrix.translateRight(origin.x(), origin.y()); |
+ matrix.translateRight(localContext.paintOffset.x(), localContext.paintOffset.y()); |
+ newTransformNodeForDescendants = adoptRef(new TransformPaintPropertyNode(matrix, FloatPoint3D(), localContext.currentTransform)); |
+ localContext.currentTransform = newTransformNodeForDescendants.get(); |
+ localContext.paintOffset = LayoutPoint(); |
+ } |
+ |
+ if (style.position() != StaticPosition || hasTransform) { |
+ localContext.transformForOutOfFlowPositioned = localContext.currentTransform; |
+ localContext.paintOffsetForOutOfFlowPositioned = localContext.paintOffset; |
+ } |
+ |
+ if (hasTransform) { |
+ localContext.transformForFixedPositioned = localContext.currentTransform; |
+ localContext.paintOffsetForFixedPositioned = localContext.paintOffset; |
+ } |
+ |
+ 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()); |
+ newTransformNodeForDescendants = adoptRef(new TransformPaintPropertyNode(matrix, FloatPoint3D(), localContext.currentTransform)); |
+ localContext.currentTransform = newTransformNodeForDescendants.get(); |
+ } |
+ } |
+ |
+ if (newTransformNodeForSelf || newTransformNodeForDescendants) { |
+ ObjectPaintProperties& properties = object.ensureObjectPaintProperties(); |
+ properties.setTransformNodeForSelf(newTransformNodeForSelf.release()); |
+ properties.setTransformNodeForDescendants(newTransformNodeForDescendants.release()); |
+ } else { |
+ object.setObjectPaintProperties(nullptr); |
+ } |
+ |
+ if (object.isSVGRoot()) { |
+ // TODO(trchen): Implement SVG walk. |
+ return; |
+ } |
+ |
+ for (LayoutObject* child = object.slowFirstChild(); child; child = child->nextSibling()) { |
+ if (child->isText()) |
+ continue; |
+ walk(toLayoutBoxModelObject(*child), localContext); |
+ } |
+} |
+ |
+} // namespace blink |