OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "config.h" |
| 6 #include "core/paint/PaintPropertyTreeBuilder.h" |
| 7 |
| 8 #include "core/frame/FrameView.h" |
| 9 #include "core/layout/LayoutView.h" |
| 10 #include "core/paint/ObjectPaintProperties.h" |
| 11 #include "core/paint/PaintLayer.h" |
| 12 #include "platform/graphics/paint/TransformPaintPropertyNode.h" |
| 13 #include "platform/transforms/TransformationMatrix.h" |
| 14 |
| 15 namespace blink { |
| 16 |
| 17 // The context for layout tree walk. |
| 18 // The walk will be done in the primary tree order (= DOM order), thus the conte
xt will also be |
| 19 // responsible for bookkeeping tree state in other order, for example, the most
recent position |
| 20 // container seen. |
| 21 struct PaintPropertyTreeBuilderContext { |
| 22 PaintPropertyTreeBuilderContext() : currentTransform(nullptr), transformForO
utOfFlowPositioned(nullptr), transformForFixedPositioned(nullptr) { } |
| 23 |
| 24 // The combination of a transform and paint offset describes a linear space. |
| 25 // When a layout object recur to its children, the main context is expected
to refer |
| 26 // the object's border box, then the callee will derive its own border box b
y translating |
| 27 // the space with its own layout location. |
| 28 TransformPaintPropertyNode* currentTransform; |
| 29 LayoutPoint paintOffset; |
| 30 |
| 31 // Separate context for out-of-flow positioned and fixed positioned elements
are needed |
| 32 // because they don't use DOM parent as their positioning parent (i.e. conta
ining block). |
| 33 // These additional contexts normally pass through untouched, and are only c
opied from |
| 34 // the main context when the current element serves as the positioning paren
t of corresponding |
| 35 // positioned descendants. |
| 36 TransformPaintPropertyNode* transformForOutOfFlowPositioned; |
| 37 LayoutPoint paintOffsetForOutOfFlowPositioned; |
| 38 |
| 39 TransformPaintPropertyNode* transformForFixedPositioned; |
| 40 LayoutPoint paintOffsetForFixedPositioned; |
| 41 }; |
| 42 |
| 43 void PaintPropertyTreeBuilder::buildPropertyTrees(FrameView& rootFrame) |
| 44 { |
| 45 walk(rootFrame, PaintPropertyTreeBuilderContext()); |
| 46 } |
| 47 |
| 48 void PaintPropertyTreeBuilder::walk(FrameView& frameView, const PaintPropertyTre
eBuilderContext& context) |
| 49 { |
| 50 PaintPropertyTreeBuilderContext localContext(context); |
| 51 |
| 52 TransformationMatrix frameTranslate; |
| 53 frameTranslate.translate(frameView.x(), frameView.y()); |
| 54 // The frame owner applies paint offset already. |
| 55 // This assumption may change in the future. |
| 56 ASSERT(context.paintOffset == LayoutPoint()); |
| 57 RefPtr<TransformPaintPropertyNode> newTransformNodeForPreTranslation = Trans
formPaintPropertyNode::create(frameTranslate, FloatPoint3D(), context.currentTra
nsform); |
| 58 localContext.transformForFixedPositioned = newTransformNodeForPreTranslation
.get(); |
| 59 localContext.paintOffsetForFixedPositioned = LayoutPoint(); |
| 60 |
| 61 // This is going away in favor of Settings::rootLayerScrolls. |
| 62 DoubleSize scrollOffset = frameView.scrollOffsetDouble(); |
| 63 TransformationMatrix frameScroll; |
| 64 frameScroll.translate(-scrollOffset.width(), -scrollOffset.height()); |
| 65 RefPtr<TransformPaintPropertyNode> newTransformNodeForScrollTranslation = Tr
ansformPaintPropertyNode::create(frameScroll, FloatPoint3D(), newTransformNodeFo
rPreTranslation); |
| 66 localContext.currentTransform = localContext.transformForOutOfFlowPositioned
= newTransformNodeForScrollTranslation.get(); |
| 67 localContext.paintOffset = localContext.paintOffsetForOutOfFlowPositioned =
LayoutPoint(); |
| 68 |
| 69 frameView.setPreTranslation(newTransformNodeForPreTranslation.release()); |
| 70 frameView.setScrollTranslation(newTransformNodeForScrollTranslation.release(
)); |
| 71 |
| 72 if (LayoutView* layoutView = frameView.layoutView()) |
| 73 walk(*layoutView, localContext); |
| 74 } |
| 75 |
| 76 static void deriveBorderBoxFromContainerContext(const LayoutBoxModelObject& obje
ct, PaintPropertyTreeBuilderContext& context) |
| 77 { |
| 78 // TODO(trchen): There is some insanity going on with tables. Double check r
esults. |
| 79 switch (object.styleRef().position()) { |
| 80 case StaticPosition: |
| 81 break; |
| 82 case RelativePosition: |
| 83 context.paintOffset += object.offsetForInFlowPosition(); |
| 84 break; |
| 85 case AbsolutePosition: |
| 86 context.currentTransform = context.transformForOutOfFlowPositioned; |
| 87 context.paintOffset = context.paintOffsetForOutOfFlowPositioned; |
| 88 break; |
| 89 case StickyPosition: |
| 90 context.paintOffset += object.offsetForInFlowPosition(); |
| 91 break; |
| 92 case FixedPosition: |
| 93 context.currentTransform = context.transformForFixedPositioned; |
| 94 context.paintOffset = context.paintOffsetForFixedPositioned; |
| 95 break; |
| 96 default: |
| 97 ASSERT_NOT_REACHED(); |
| 98 } |
| 99 if (object.isBox()) |
| 100 context.paintOffset += toLayoutBox(object).locationOffset(); |
| 101 } |
| 102 |
| 103 static PassRefPtr<TransformPaintPropertyNode> createPaintOffsetTranslationIfNeed
ed(const LayoutBoxModelObject& object, PaintPropertyTreeBuilderContext& context) |
| 104 { |
| 105 // TODO(trchen): Eliminate PaintLayer dependency. |
| 106 bool shouldCreatePaintOffsetTranslationNode = object.layer() && object.layer
()->paintsWithTransform(GlobalPaintNormalPhase); |
| 107 |
| 108 if (context.paintOffset == LayoutPoint() || !shouldCreatePaintOffsetTranslat
ionNode) |
| 109 return nullptr; |
| 110 |
| 111 TransformationMatrix matrix; |
| 112 matrix.translate(context.paintOffset.x(), context.paintOffset.y()); |
| 113 RefPtr<TransformPaintPropertyNode> newTransformNodeForPaintOffsetTranslation
= TransformPaintPropertyNode::create( |
| 114 TransformationMatrix().translate(context.paintOffset.x(), context.paintO
ffset.y()), |
| 115 FloatPoint3D(), context.currentTransform); |
| 116 context.currentTransform = newTransformNodeForPaintOffsetTranslation.get(); |
| 117 context.paintOffset = LayoutPoint(); |
| 118 return newTransformNodeForPaintOffsetTranslation.release(); |
| 119 } |
| 120 |
| 121 static FloatPoint3D transformOrigin(const LayoutBox& box) |
| 122 { |
| 123 const ComputedStyle& style = box.styleRef(); |
| 124 FloatSize borderBoxSize(box.size()); |
| 125 return FloatPoint3D( |
| 126 floatValueForLength(style.transformOriginX(), borderBoxSize.width()), |
| 127 floatValueForLength(style.transformOriginY(), borderBoxSize.height()), |
| 128 style.transformOriginZ()); |
| 129 } |
| 130 |
| 131 static PassRefPtr<TransformPaintPropertyNode> createTransformIfNeeded(const Layo
utBoxModelObject& object, PaintPropertyTreeBuilderContext& context) |
| 132 { |
| 133 const ComputedStyle& style = object.styleRef(); |
| 134 if (!object.isBox() || !style.hasTransform()) |
| 135 return nullptr; |
| 136 |
| 137 ASSERT(context.paintOffset == LayoutPoint()); |
| 138 |
| 139 TransformationMatrix matrix; |
| 140 style.applyTransform(matrix, toLayoutBox(object).size(), ComputedStyle::Excl
udeTransformOrigin, |
| 141 ComputedStyle::IncludeMotionPath, ComputedStyle::IncludeIndependentTrans
formProperties); |
| 142 RefPtr<TransformPaintPropertyNode> newTransformNodeForTransform = TransformP
aintPropertyNode::create( |
| 143 matrix, transformOrigin(toLayoutBox(object)), context.currentTransform); |
| 144 context.currentTransform = newTransformNodeForTransform.get(); |
| 145 return newTransformNodeForTransform.release(); |
| 146 } |
| 147 |
| 148 static FloatPoint perspectiveOrigin(const LayoutBox& box) |
| 149 { |
| 150 const ComputedStyle& style = box.styleRef(); |
| 151 FloatSize borderBoxSize(box.size()); |
| 152 return FloatPoint( |
| 153 floatValueForLength(style.perspectiveOriginX(), borderBoxSize.width()), |
| 154 floatValueForLength(style.perspectiveOriginY(), borderBoxSize.height()))
; |
| 155 } |
| 156 |
| 157 static PassRefPtr<TransformPaintPropertyNode> createPerspectiveIfNeeded(const La
youtBoxModelObject& object, PaintPropertyTreeBuilderContext& context) |
| 158 { |
| 159 const ComputedStyle& style = object.styleRef(); |
| 160 if (!object.isBox() || !style.hasPerspective()) |
| 161 return nullptr; |
| 162 |
| 163 RefPtr<TransformPaintPropertyNode> newTransformNodeForPerspective = Transfor
mPaintPropertyNode::create( |
| 164 TransformationMatrix().applyPerspective(style.perspective()), |
| 165 perspectiveOrigin(toLayoutBox(object)) + toLayoutSize(context.paintOffse
t), context.currentTransform); |
| 166 context.currentTransform = newTransformNodeForPerspective.get(); |
| 167 |
| 168 return newTransformNodeForPerspective.release(); |
| 169 } |
| 170 |
| 171 static PassRefPtr<TransformPaintPropertyNode> createScrollTranslationIfNeeded(co
nst LayoutBoxModelObject& object, PaintPropertyTreeBuilderContext& context) |
| 172 { |
| 173 if (!object.hasOverflowClip()) |
| 174 return nullptr; |
| 175 |
| 176 PaintLayer* layer = object.layer(); |
| 177 ASSERT(layer); |
| 178 DoubleSize scrollOffset = layer->scrollableArea()->scrollOffset(); |
| 179 if (scrollOffset.isZero() && !layer->scrollsOverflow()) |
| 180 return nullptr; |
| 181 |
| 182 RefPtr<TransformPaintPropertyNode> newTransformNodeForScrollTranslation = Tr
ansformPaintPropertyNode::create( |
| 183 TransformationMatrix().translate(-scrollOffset.width(), -scrollOffset.he
ight()), |
| 184 FloatPoint3D(), context.currentTransform); |
| 185 context.currentTransform = newTransformNodeForScrollTranslation.get(); |
| 186 return newTransformNodeForScrollTranslation.release(); |
| 187 } |
| 188 |
| 189 static void updateOutOfFlowContext(const LayoutBoxModelObject& object, PaintProp
ertyTreeBuilderContext& context) |
| 190 { |
| 191 const ComputedStyle& style = object.styleRef(); |
| 192 bool hasTransform = object.isBox() && style.hasTransform(); |
| 193 if (style.position() != StaticPosition || hasTransform) { |
| 194 context.transformForOutOfFlowPositioned = context.currentTransform; |
| 195 context.paintOffsetForOutOfFlowPositioned = context.paintOffset; |
| 196 } |
| 197 if (hasTransform) { |
| 198 context.transformForFixedPositioned = context.currentTransform; |
| 199 context.paintOffsetForFixedPositioned = context.paintOffset; |
| 200 } |
| 201 } |
| 202 |
| 203 void PaintPropertyTreeBuilder::walk(LayoutBoxModelObject& object, const PaintPro
pertyTreeBuilderContext& context) |
| 204 { |
| 205 ASSERT(object.isBox() != object.isLayoutInline()); // Either or. |
| 206 |
| 207 PaintPropertyTreeBuilderContext localContext(context); |
| 208 |
| 209 deriveBorderBoxFromContainerContext(object, localContext); |
| 210 RefPtr<TransformPaintPropertyNode> newTransformNodeForPaintOffsetTranslation
= createPaintOffsetTranslationIfNeeded(object, localContext); |
| 211 RefPtr<TransformPaintPropertyNode> newTransformNodeForTransform = createTran
sformIfNeeded(object, localContext); |
| 212 RefPtr<TransformPaintPropertyNode> newTransformNodeForPerspective = createPe
rspectiveIfNeeded(object, localContext); |
| 213 RefPtr<TransformPaintPropertyNode> newTransformNodeForScrollTranslation = cr
eateScrollTranslationIfNeeded(object, localContext); |
| 214 updateOutOfFlowContext(object, localContext); |
| 215 |
| 216 if (newTransformNodeForPaintOffsetTranslation || newTransformNodeForTransfor
m || newTransformNodeForPerspective || newTransformNodeForScrollTranslation) { |
| 217 ObjectPaintProperties& properties = object.ensureObjectPaintProperties()
; |
| 218 properties.setPaintOffsetTranslation(newTransformNodeForPaintOffsetTrans
lation.release()); |
| 219 properties.setTransform(newTransformNodeForTransform.release()); |
| 220 properties.setPerspective(newTransformNodeForPerspective.release()); |
| 221 properties.setScrollTranslation(newTransformNodeForScrollTranslation.rel
ease()); |
| 222 } else { |
| 223 object.clearObjectPaintProperties(); |
| 224 } |
| 225 |
| 226 // TODO(trchen): Walk subframes for LayoutFrame. |
| 227 |
| 228 // TODO(trchen): Implement SVG walk. |
| 229 if (object.isSVGRoot()) { |
| 230 return; |
| 231 } |
| 232 |
| 233 for (LayoutObject* child = object.slowFirstChild(); child; child = child->ne
xtSibling()) { |
| 234 if (child->isText()) |
| 235 continue; |
| 236 walk(toLayoutBoxModelObject(*child), localContext); |
| 237 } |
| 238 } |
| 239 |
| 240 } // namespace blink |
OLD | NEW |