| 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..1a20dca89d1c06925a8c8a34274c1f0d2b41e490
|
| --- /dev/null
|
| +++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
|
| @@ -0,0 +1,200 @@
|
| +// 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 {
|
| + Context() : 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);
|
| +
|
| + 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());
|
| + TransformPaintPropertyNode* transformNodeForPreTranslation = new TransformPaintPropertyNode(frameTranslate, FloatPoint3D(), context.currentTransform);
|
| + frameView.setPreTranslation(adoptRef(transformNodeForPreTranslation));
|
| + localContext.transformForFixedPositioned = transformNodeForPreTranslation;
|
| + localContext.paintOffsetForFixedPositioned = LayoutPoint();
|
| +
|
| + // This is going away in favor of Settings::rootLayerScrolls.
|
| + TransformationMatrix frameScroll;
|
| + frameScroll.translate(-frameView.scrollX(), -frameView.scrollY());
|
| + TransformPaintPropertyNode* transformNodeForScrollTranslation = new TransformPaintPropertyNode(frameScroll, FloatPoint3D(), transformNodeForPreTranslation);
|
| + frameView.setScrollTranslation(adoptRef(transformNodeForScrollTranslation));
|
| + localContext.currentTransform = localContext.transformForOutOfFlowPositioned = transformNodeForScrollTranslation;
|
| + localContext.paintOffset = localContext.paintOffsetForOutOfFlowPositioned = LayoutPoint();
|
| +
|
| + 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());
|
| +}
|
| +
|
| +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 Context& context)
|
| +{
|
| + ASSERT(object.isBox() != object.isLayoutInline()); // Either or.
|
| +
|
| + 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 = adoptRef(new TransformPaintPropertyNode(matrix, FloatPoint3D(), localContext.currentTransform));
|
| + localContext.currentTransform = newTransformNodeForPreTranslation.get();
|
| + localContext.paintOffset = LayoutPoint();
|
| + }
|
| +
|
| + // Step 3: Create a transform node for CSS transform (if presents).
|
| + bool hasTransform = object.isBox() && style.hasTransform();
|
| + if (hasTransform) {
|
| + TransformationMatrix matrix;
|
| + style.applyTransform(matrix, toLayoutBox(object).size(), ComputedStyle::ExcludeTransformOrigin, ComputedStyle::IncludeMotionPath, ComputedStyle::IncludeIndependentTransformProperties);
|
| + newTransformNodeForTransform = adoptRef(new TransformPaintPropertyNode(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).
|
| + if (object.isBox() && style.hasPerspective()) {
|
| + TransformationMatrix matrix;
|
| + matrix.applyPerspective(style.perspective());
|
| + newTransformNodeForPerspective = adoptRef(new TransformPaintPropertyNode(matrix, perspectiveOrigin(toLayoutBox(object)), localContext.currentTransform));
|
| + localContext.currentTransform = newTransformNodeForPerspective.get();
|
| + ASSERT(localContext.paintOffset == LayoutPoint());
|
| + }
|
| +
|
| + // Step 4: Update the context for out-of-flow descendants (if position container is established).
|
| + if (style.position() != StaticPosition || hasTransform) {
|
| + localContext.transformForOutOfFlowPositioned = localContext.currentTransform;
|
| + localContext.paintOffsetForOutOfFlowPositioned = localContext.paintOffset;
|
| + }
|
| + if (hasTransform) {
|
| + localContext.transformForFixedPositioned = localContext.currentTransform;
|
| + localContext.paintOffsetForFixedPositioned = localContext.paintOffset;
|
| + }
|
| +
|
| + // Step 5: 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 = adoptRef(new TransformPaintPropertyNode(matrix, FloatPoint3D(), localContext.currentTransform));
|
| + localContext.currentTransform = newTransformNodeForScrollTranslation.get();
|
| + }
|
| + }
|
| + // At this point, the current space is the space we paint in-flow children.
|
| +
|
| + // 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()) {
|
| + // 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
|
|
|