OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "config.h" | 5 #include "config.h" |
6 #include "core/paint/PaintPropertyTreeBuilder.h" | 6 #include "core/paint/PaintPropertyTreeBuilder.h" |
7 | 7 |
8 #include "core/frame/FrameView.h" | 8 #include "core/frame/FrameView.h" |
9 #include "core/layout/LayoutView.h" | 9 #include "core/layout/LayoutView.h" |
10 #include "core/paint/ObjectPaintProperties.h" | 10 #include "core/paint/ObjectPaintProperties.h" |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
72 localContext.currentTransform = localContext.transformForOutOfFlowPositioned = newTransformNodeForScrollTranslation.get(); | 72 localContext.currentTransform = localContext.transformForOutOfFlowPositioned = newTransformNodeForScrollTranslation.get(); |
73 localContext.paintOffset = localContext.paintOffsetForOutOfFlowPositioned = LayoutPoint(); | 73 localContext.paintOffset = localContext.paintOffsetForOutOfFlowPositioned = LayoutPoint(); |
74 | 74 |
75 frameView.setPreTranslation(newTransformNodeForPreTranslation.release()); | 75 frameView.setPreTranslation(newTransformNodeForPreTranslation.release()); |
76 frameView.setScrollTranslation(newTransformNodeForScrollTranslation.release( )); | 76 frameView.setScrollTranslation(newTransformNodeForScrollTranslation.release( )); |
77 | 77 |
78 if (LayoutView* layoutView = frameView.layoutView()) | 78 if (LayoutView* layoutView = frameView.layoutView()) |
79 walk(*layoutView, localContext); | 79 walk(*layoutView, localContext); |
80 } | 80 } |
81 | 81 |
82 static void deriveBorderBoxFromContainerContext(const LayoutBoxModelObject& obje ct, PaintPropertyTreeBuilderContext& context) | 82 static void deriveBorderBoxFromContainerContext(const LayoutObject& object, Pain tPropertyTreeBuilderContext& context) |
83 { | 83 { |
84 if (!object.isBoxModelObject()) | |
85 return; | |
86 | |
87 const LayoutBoxModelObject& boxModelObject = toLayoutBoxModelObject(object); | |
88 | |
84 // TODO(trchen): There is some insanity going on with tables. Double check r esults. | 89 // TODO(trchen): There is some insanity going on with tables. Double check r esults. |
85 switch (object.styleRef().position()) { | 90 switch (object.styleRef().position()) { |
86 case StaticPosition: | 91 case StaticPosition: |
87 break; | 92 break; |
88 case RelativePosition: | 93 case RelativePosition: |
89 context.paintOffset += object.offsetForInFlowPosition(); | 94 context.paintOffset += boxModelObject.offsetForInFlowPosition(); |
90 break; | 95 break; |
91 case AbsolutePosition: | 96 case AbsolutePosition: |
92 context.currentTransform = context.transformForOutOfFlowPositioned; | 97 context.currentTransform = context.transformForOutOfFlowPositioned; |
93 context.paintOffset = context.paintOffsetForOutOfFlowPositioned; | 98 context.paintOffset = context.paintOffsetForOutOfFlowPositioned; |
94 break; | 99 break; |
95 case StickyPosition: | 100 case StickyPosition: |
96 context.paintOffset += object.offsetForInFlowPosition(); | 101 context.paintOffset += boxModelObject.offsetForInFlowPosition(); |
97 break; | 102 break; |
98 case FixedPosition: | 103 case FixedPosition: |
99 context.currentTransform = context.transformForFixedPositioned; | 104 context.currentTransform = context.transformForFixedPositioned; |
100 context.paintOffset = context.paintOffsetForFixedPositioned; | 105 context.paintOffset = context.paintOffsetForFixedPositioned; |
101 break; | 106 break; |
102 default: | 107 default: |
103 ASSERT_NOT_REACHED(); | 108 ASSERT_NOT_REACHED(); |
104 } | 109 } |
105 if (object.isBox()) | 110 if (boxModelObject.isBox()) |
106 context.paintOffset += toLayoutBox(object).locationOffset(); | 111 context.paintOffset += toLayoutBox(boxModelObject).locationOffset(); |
107 } | 112 } |
108 | 113 |
109 static PassRefPtr<TransformPaintPropertyNode> createPaintOffsetTranslationIfNeed ed(const LayoutBoxModelObject& object, PaintPropertyTreeBuilderContext& context) | 114 static PassRefPtr<TransformPaintPropertyNode> createPaintOffsetTranslationIfNeed ed(const LayoutObject& object, PaintPropertyTreeBuilderContext& context) |
110 { | 115 { |
111 // TODO(trchen): Eliminate PaintLayer dependency. | 116 bool shouldCreatePaintOffsetTranslationNode = false; |
112 bool shouldCreatePaintOffsetTranslationNode = object.layer() && object.layer ()->paintsWithTransform(GlobalPaintNormalPhase); | 117 if (object.isSVGRoot()) { |
118 // SVG doesn't use paint offset internally so emit a paint offset at the html->svg boundary. | |
119 shouldCreatePaintOffsetTranslationNode = true; | |
120 } else if (object.isBoxModelObject()) { | |
121 // TODO(trchen): Eliminate PaintLayer dependency. | |
122 PaintLayer* layer = toLayoutBoxModelObject(object).layer(); | |
123 shouldCreatePaintOffsetTranslationNode = layer && layer->paintsWithTrans form(GlobalPaintNormalPhase); | |
124 } | |
113 | 125 |
114 if (context.paintOffset == LayoutPoint() || !shouldCreatePaintOffsetTranslat ionNode) | 126 if (context.paintOffset == LayoutPoint() || !shouldCreatePaintOffsetTranslat ionNode) |
115 return nullptr; | 127 return nullptr; |
116 | 128 |
117 RefPtr<TransformPaintPropertyNode> newTransformNodeForPaintOffsetTranslation = TransformPaintPropertyNode::create( | 129 RefPtr<TransformPaintPropertyNode> newTransformNodeForPaintOffsetTranslation = TransformPaintPropertyNode::create( |
118 TransformationMatrix().translate(context.paintOffset.x(), context.paintO ffset.y()), | 130 TransformationMatrix().translate(context.paintOffset.x(), context.paintO ffset.y()), |
119 FloatPoint3D(), context.currentTransform); | 131 FloatPoint3D(), context.currentTransform); |
120 context.currentTransform = newTransformNodeForPaintOffsetTranslation.get(); | 132 context.currentTransform = newTransformNodeForPaintOffsetTranslation.get(); |
121 context.paintOffset = LayoutPoint(); | 133 context.paintOffset = LayoutPoint(); |
122 return newTransformNodeForPaintOffsetTranslation.release(); | 134 return newTransformNodeForPaintOffsetTranslation.release(); |
123 } | 135 } |
124 | 136 |
125 static FloatPoint3D transformOrigin(const LayoutBox& box) | 137 static FloatPoint3D transformOrigin(const LayoutBox& box) |
126 { | 138 { |
127 const ComputedStyle& style = box.styleRef(); | 139 const ComputedStyle& style = box.styleRef(); |
128 FloatSize borderBoxSize(box.size()); | 140 FloatSize borderBoxSize(box.size()); |
129 return FloatPoint3D( | 141 return FloatPoint3D( |
130 floatValueForLength(style.transformOriginX(), borderBoxSize.width()), | 142 floatValueForLength(style.transformOriginX(), borderBoxSize.width()), |
131 floatValueForLength(style.transformOriginY(), borderBoxSize.height()), | 143 floatValueForLength(style.transformOriginY(), borderBoxSize.height()), |
132 style.transformOriginZ()); | 144 style.transformOriginZ()); |
133 } | 145 } |
134 | 146 |
135 static PassRefPtr<TransformPaintPropertyNode> createTransformIfNeeded(const Layo utBoxModelObject& object, PaintPropertyTreeBuilderContext& context) | 147 static PassRefPtr<TransformPaintPropertyNode> createTransformIfNeeded(const Layo utObject& object, PaintPropertyTreeBuilderContext& context) |
136 { | 148 { |
149 if (object.isSVG() && !object.isSVGRoot()) { | |
150 const AffineTransform& transform = object.localToParentTransform(); | |
151 if (transform.isIdentity()) | |
152 return nullptr; | |
153 | |
154 // SVG's transform origin is baked into the localToParentTransform. | |
155 RefPtr<TransformPaintPropertyNode> newTransformNodeForTransform = Transf ormPaintPropertyNode::create( | |
156 transform, FloatPoint3D(0, 0, 0), context.currentTransform); | |
157 context.currentTransform = newTransformNodeForTransform.get(); | |
158 return newTransformNodeForTransform.release(); | |
159 } | |
160 | |
137 const ComputedStyle& style = object.styleRef(); | 161 const ComputedStyle& style = object.styleRef(); |
138 if (!object.isBox() || !style.hasTransform()) | 162 if (!object.isBox() || !style.hasTransform()) |
139 return nullptr; | 163 return nullptr; |
140 | 164 |
141 ASSERT(context.paintOffset == LayoutPoint()); | 165 ASSERT(context.paintOffset == LayoutPoint()); |
142 | 166 |
143 TransformationMatrix matrix; | 167 TransformationMatrix matrix; |
144 style.applyTransform(matrix, toLayoutBox(object).size(), ComputedStyle::Excl udeTransformOrigin, | 168 style.applyTransform(matrix, toLayoutBox(object).size(), ComputedStyle::Excl udeTransformOrigin, |
145 ComputedStyle::IncludeMotionPath, ComputedStyle::IncludeIndependentTrans formProperties); | 169 ComputedStyle::IncludeMotionPath, ComputedStyle::IncludeIndependentTrans formProperties); |
146 RefPtr<TransformPaintPropertyNode> newTransformNodeForTransform = TransformP aintPropertyNode::create( | 170 RefPtr<TransformPaintPropertyNode> newTransformNodeForTransform = TransformP aintPropertyNode::create( |
147 matrix, transformOrigin(toLayoutBox(object)), context.currentTransform); | 171 matrix, transformOrigin(toLayoutBox(object)), context.currentTransform); |
148 context.currentTransform = newTransformNodeForTransform.get(); | 172 context.currentTransform = newTransformNodeForTransform.get(); |
149 return newTransformNodeForTransform.release(); | 173 return newTransformNodeForTransform.release(); |
150 } | 174 } |
151 | 175 |
152 static PassRefPtr<EffectPaintPropertyNode> createEffectIfNeeded(const LayoutBoxM odelObject& object, PaintPropertyTreeBuilderContext& context) | 176 static PassRefPtr<EffectPaintPropertyNode> createEffectIfNeeded(const LayoutObje ct& object, PaintPropertyTreeBuilderContext& context) |
153 { | 177 { |
154 const ComputedStyle& style = object.styleRef(); | 178 const ComputedStyle& style = object.styleRef(); |
155 if (!object.isBox() || !style.hasOpacity()) | 179 if (!style.hasOpacity()) |
156 return nullptr; | 180 return nullptr; |
157 RefPtr<EffectPaintPropertyNode> newEffectNode = EffectPaintPropertyNode::cre ate(style.opacity(), context.currentEffect); | 181 RefPtr<EffectPaintPropertyNode> newEffectNode = EffectPaintPropertyNode::cre ate(style.opacity(), context.currentEffect); |
158 context.currentEffect = newEffectNode.get(); | 182 context.currentEffect = newEffectNode.get(); |
159 return newEffectNode.release(); | 183 return newEffectNode.release(); |
160 } | 184 } |
161 | 185 |
162 static FloatPoint perspectiveOrigin(const LayoutBox& box) | 186 static FloatPoint perspectiveOrigin(const LayoutBox& box) |
163 { | 187 { |
164 const ComputedStyle& style = box.styleRef(); | 188 const ComputedStyle& style = box.styleRef(); |
165 FloatSize borderBoxSize(box.size()); | 189 FloatSize borderBoxSize(box.size()); |
166 return FloatPoint( | 190 return FloatPoint( |
167 floatValueForLength(style.perspectiveOriginX(), borderBoxSize.width()), | 191 floatValueForLength(style.perspectiveOriginX(), borderBoxSize.width()), |
168 floatValueForLength(style.perspectiveOriginY(), borderBoxSize.height())) ; | 192 floatValueForLength(style.perspectiveOriginY(), borderBoxSize.height())) ; |
169 } | 193 } |
170 | 194 |
171 static PassRefPtr<TransformPaintPropertyNode> createPerspectiveIfNeeded(const La youtBoxModelObject& object, PaintPropertyTreeBuilderContext& context) | 195 static PassRefPtr<TransformPaintPropertyNode> createPerspectiveIfNeeded(const La youtObject& object, PaintPropertyTreeBuilderContext& context) |
172 { | 196 { |
173 const ComputedStyle& style = object.styleRef(); | 197 const ComputedStyle& style = object.styleRef(); |
174 if (!object.isBox() || !style.hasPerspective()) | 198 if (!object.isBox() || !style.hasPerspective()) |
175 return nullptr; | 199 return nullptr; |
176 | 200 |
177 RefPtr<TransformPaintPropertyNode> newTransformNodeForPerspective = Transfor mPaintPropertyNode::create( | 201 RefPtr<TransformPaintPropertyNode> newTransformNodeForPerspective = Transfor mPaintPropertyNode::create( |
178 TransformationMatrix().applyPerspective(style.perspective()), | 202 TransformationMatrix().applyPerspective(style.perspective()), |
179 perspectiveOrigin(toLayoutBox(object)) + toLayoutSize(context.paintOffse t), context.currentTransform); | 203 perspectiveOrigin(toLayoutBox(object)) + toLayoutSize(context.paintOffse t), context.currentTransform); |
180 context.currentTransform = newTransformNodeForPerspective.get(); | 204 context.currentTransform = newTransformNodeForPerspective.get(); |
181 return newTransformNodeForPerspective.release(); | 205 return newTransformNodeForPerspective.release(); |
182 } | 206 } |
183 | 207 |
184 static PassRefPtr<TransformPaintPropertyNode> createScrollTranslationIfNeeded(co nst LayoutBoxModelObject& object, PaintPropertyTreeBuilderContext& context) | 208 static PassRefPtr<TransformPaintPropertyNode> createScrollTranslationIfNeeded(co nst LayoutObject& object, PaintPropertyTreeBuilderContext& context) |
185 { | 209 { |
186 if (!object.hasOverflowClip()) | 210 if (!object.isBoxModelObject() || !object.hasOverflowClip()) |
187 return nullptr; | 211 return nullptr; |
188 | 212 |
189 PaintLayer* layer = object.layer(); | 213 PaintLayer* layer = toLayoutBoxModelObject(object).layer(); |
190 ASSERT(layer); | 214 ASSERT(layer); |
191 DoubleSize scrollOffset = layer->scrollableArea()->scrollOffset(); | 215 DoubleSize scrollOffset = layer->scrollableArea()->scrollOffset(); |
192 if (scrollOffset.isZero() && !layer->scrollsOverflow()) | 216 if (scrollOffset.isZero() && !layer->scrollsOverflow()) |
193 return nullptr; | 217 return nullptr; |
194 | 218 |
195 RefPtr<TransformPaintPropertyNode> newTransformNodeForScrollTranslation = Tr ansformPaintPropertyNode::create( | 219 RefPtr<TransformPaintPropertyNode> newTransformNodeForScrollTranslation = Tr ansformPaintPropertyNode::create( |
196 TransformationMatrix().translate(-scrollOffset.width(), -scrollOffset.he ight()), | 220 TransformationMatrix().translate(-scrollOffset.width(), -scrollOffset.he ight()), |
197 FloatPoint3D(), context.currentTransform); | 221 FloatPoint3D(), context.currentTransform); |
198 context.currentTransform = newTransformNodeForScrollTranslation.get(); | 222 context.currentTransform = newTransformNodeForScrollTranslation.get(); |
199 return newTransformNodeForScrollTranslation.release(); | 223 return newTransformNodeForScrollTranslation.release(); |
200 } | 224 } |
201 | 225 |
202 static void updateOutOfFlowContext(const LayoutBoxModelObject& object, PaintProp ertyTreeBuilderContext& context) | 226 static void updateOutOfFlowContext(const LayoutObject& object, bool createdNewTr ansform, PaintPropertyTreeBuilderContext& context) |
203 { | 227 { |
204 const ComputedStyle& style = object.styleRef(); | 228 // At the html->svg boundary (see: createPaintOffsetTranslationIfNeeded) the currentTransform is |
205 bool hasTransform = object.isBox() && style.hasTransform(); | 229 // up-to-date for all children of the svg root element. Additionally, inside SVG, all positioning |
206 if (style.position() != StaticPosition || hasTransform) { | 230 // uses transforms. Therefore, we only need to check createdNewTransform and isSVGRoot() to |
231 // ensure out-of-flow and fixed positioning is correct at the svg->html boun dary. | |
232 | |
233 if (object.styleRef().position() != StaticPosition || createdNewTransform || object.isSVGRoot()) { | |
jbroman
2015/11/23 17:51:00
Out of curiosity (arguably out of scope for this p
trchen
2015/11/23 19:28:29
I think yes. Looks like it's pretty safe to use.
| |
207 context.transformForOutOfFlowPositioned = context.currentTransform; | 234 context.transformForOutOfFlowPositioned = context.currentTransform; |
208 context.paintOffsetForOutOfFlowPositioned = context.paintOffset; | 235 context.paintOffsetForOutOfFlowPositioned = context.paintOffset; |
209 } | 236 } |
210 if (hasTransform) { | 237 |
238 if (createdNewTransform || object.isSVGRoot()) { | |
211 context.transformForFixedPositioned = context.currentTransform; | 239 context.transformForFixedPositioned = context.currentTransform; |
212 context.paintOffsetForFixedPositioned = context.paintOffset; | 240 context.paintOffsetForFixedPositioned = context.paintOffset; |
213 } | 241 } |
214 } | 242 } |
215 | 243 |
216 void PaintPropertyTreeBuilder::walk(LayoutBoxModelObject& object, const PaintPro pertyTreeBuilderContext& context) | 244 void PaintPropertyTreeBuilder::walk(LayoutObject& object, const PaintPropertyTre eBuilderContext& context) |
217 { | 245 { |
218 ASSERT(object.isBox() != object.isLayoutInline()); // Either or. | |
219 | |
220 PaintPropertyTreeBuilderContext localContext(context); | 246 PaintPropertyTreeBuilderContext localContext(context); |
221 | 247 |
222 deriveBorderBoxFromContainerContext(object, localContext); | 248 deriveBorderBoxFromContainerContext(object, localContext); |
223 RefPtr<TransformPaintPropertyNode> newTransformNodeForPaintOffsetTranslation = createPaintOffsetTranslationIfNeeded(object, localContext); | 249 RefPtr<TransformPaintPropertyNode> newTransformNodeForPaintOffsetTranslation = createPaintOffsetTranslationIfNeeded(object, localContext); |
224 RefPtr<TransformPaintPropertyNode> newTransformNodeForTransform = createTran sformIfNeeded(object, localContext); | 250 RefPtr<TransformPaintPropertyNode> newTransformNodeForTransform = createTran sformIfNeeded(object, localContext); |
225 RefPtr<EffectPaintPropertyNode> newEffectNode = createEffectIfNeeded(object, localContext); | 251 RefPtr<EffectPaintPropertyNode> newEffectNode = createEffectIfNeeded(object, localContext); |
226 RefPtr<TransformPaintPropertyNode> newTransformNodeForPerspective = createPe rspectiveIfNeeded(object, localContext); | 252 RefPtr<TransformPaintPropertyNode> newTransformNodeForPerspective = createPe rspectiveIfNeeded(object, localContext); |
227 RefPtr<TransformPaintPropertyNode> newTransformNodeForScrollTranslation = cr eateScrollTranslationIfNeeded(object, localContext); | 253 RefPtr<TransformPaintPropertyNode> newTransformNodeForScrollTranslation = cr eateScrollTranslationIfNeeded(object, localContext); |
228 updateOutOfFlowContext(object, localContext); | 254 updateOutOfFlowContext(object, newTransformNodeForTransform, localContext); |
229 | 255 |
230 if (newTransformNodeForPaintOffsetTranslation || newTransformNodeForTransfor m || newEffectNode || newTransformNodeForPerspective || newTransformNodeForScrol lTranslation) { | 256 if (newTransformNodeForPaintOffsetTranslation || newTransformNodeForTransfor m || newEffectNode || newTransformNodeForPerspective || newTransformNodeForScrol lTranslation) { |
231 OwnPtr<ObjectPaintProperties> updatedPaintProperties = ObjectPaintProper ties::create( | 257 OwnPtr<ObjectPaintProperties> updatedPaintProperties = ObjectPaintProper ties::create( |
232 newTransformNodeForPaintOffsetTranslation.release(), | 258 newTransformNodeForPaintOffsetTranslation.release(), |
233 newTransformNodeForTransform.release(), | 259 newTransformNodeForTransform.release(), |
234 newEffectNode.release(), | 260 newEffectNode.release(), |
235 newTransformNodeForPerspective.release(), | 261 newTransformNodeForPerspective.release(), |
236 newTransformNodeForScrollTranslation.release()); | 262 newTransformNodeForScrollTranslation.release()); |
237 object.setObjectPaintProperties(updatedPaintProperties.release()); | 263 object.setObjectPaintProperties(updatedPaintProperties.release()); |
238 } else { | 264 } else { |
239 object.clearObjectPaintProperties(); | 265 object.clearObjectPaintProperties(); |
240 } | 266 } |
241 | 267 |
242 // TODO(trchen): Walk subframes for LayoutFrame. | 268 // TODO(trchen): Walk subframes for LayoutFrame. |
243 | 269 |
244 // TODO(trchen): Implement SVG walk. | |
245 if (object.isSVGRoot()) { | |
246 return; | |
247 } | |
248 | |
249 for (LayoutObject* child = object.slowFirstChild(); child; child = child->ne xtSibling()) { | 270 for (LayoutObject* child = object.slowFirstChild(); child; child = child->ne xtSibling()) { |
250 if (child->isText()) | 271 if (child->isBoxModelObject() || child->isSVG()) |
251 continue; | 272 walk(*child, localContext); |
252 walk(toLayoutBoxModelObject(*child), localContext); | |
253 } | 273 } |
254 } | 274 } |
255 | 275 |
256 } // namespace blink | 276 } // namespace blink |
OLD | NEW |