Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(239)

Side by Side Diff: third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp

Issue 2404213004: Implement incremental paint property tree rebuilding (Closed)
Patch Set: Rebase, re-implement updateTransform and updateEffect Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 "core/paint/PaintPropertyTreeBuilder.h" 5 #include "core/paint/PaintPropertyTreeBuilder.h"
6 6
7 #include "core/frame/FrameView.h" 7 #include "core/frame/FrameView.h"
8 #include "core/frame/LocalFrame.h" 8 #include "core/frame/LocalFrame.h"
9 #include "core/frame/Settings.h" 9 #include "core/frame/Settings.h"
10 #include "core/layout/LayoutInline.h" 10 #include "core/layout/LayoutInline.h"
11 #include "core/layout/LayoutPart.h" 11 #include "core/layout/LayoutPart.h"
12 #include "core/layout/LayoutView.h" 12 #include "core/layout/LayoutView.h"
13 #include "core/layout/svg/LayoutSVGRoot.h" 13 #include "core/layout/svg/LayoutSVGRoot.h"
14 #include "core/paint/FindPropertiesNeedingUpdate.h"
14 #include "core/paint/ObjectPaintProperties.h" 15 #include "core/paint/ObjectPaintProperties.h"
15 #include "core/paint/PaintLayer.h" 16 #include "core/paint/PaintLayer.h"
16 #include "core/paint/SVGRootPainter.h" 17 #include "core/paint/SVGRootPainter.h"
17 #include "platform/transforms/TransformationMatrix.h" 18 #include "platform/transforms/TransformationMatrix.h"
18 #include "wtf/PtrUtil.h" 19 #include "wtf/PtrUtil.h"
19 #include <memory> 20 #include <memory>
20 21
21 namespace blink { 22 namespace blink {
22 23
23 namespace { 24 namespace {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
65 context.current.scroll = context.absolutePosition.scroll = 66 context.current.scroll = context.absolutePosition.scroll =
66 context.fixedPosition.scroll = rootScrollNode(); 67 context.fixedPosition.scroll = rootScrollNode();
67 68
68 // Ensure scroll tree properties are reset. They will be rebuilt during the 69 // Ensure scroll tree properties are reset. They will be rebuilt during the
69 // tree walk. 70 // tree walk.
70 rootScrollNode()->clearMainThreadScrollingReasons(); 71 rootScrollNode()->clearMainThreadScrollingReasons();
71 72
72 return context; 73 return context;
73 } 74 }
74 75
75 const TransformPaintPropertyNode* updateFrameViewPreTranslation( 76 void updateFrameViewPreTranslation(
76 FrameView& frameView, 77 FrameView& frameView,
77 PassRefPtr<const TransformPaintPropertyNode> parent, 78 PassRefPtr<const TransformPaintPropertyNode> parent,
78 const TransformationMatrix& matrix, 79 const TransformationMatrix& matrix,
79 const FloatPoint3D& origin) { 80 const FloatPoint3D& origin) {
80 DCHECK(!RuntimeEnabledFeatures::rootLayerScrollingEnabled()); 81 DCHECK(!RuntimeEnabledFeatures::rootLayerScrollingEnabled());
81 if (TransformPaintPropertyNode* existingPreTranslation = 82 if (auto* existingPreTranslation = frameView.preTranslation()) {
82 frameView.preTranslation())
83 existingPreTranslation->update(std::move(parent), matrix, origin); 83 existingPreTranslation->update(std::move(parent), matrix, origin);
84 else 84 } else {
85 frameView.setPreTranslation( 85 frameView.setPreTranslation(
86 TransformPaintPropertyNode::create(std::move(parent), matrix, origin)); 86 TransformPaintPropertyNode::create(std::move(parent), matrix, origin));
87 return frameView.preTranslation(); 87 }
88 } 88 }
89 89
90 const ClipPaintPropertyNode* updateFrameViewContentClip( 90 void updateFrameViewContentClip(
91 FrameView& frameView, 91 FrameView& frameView,
92 PassRefPtr<const ClipPaintPropertyNode> parent, 92 PassRefPtr<const ClipPaintPropertyNode> parent,
93 PassRefPtr<const TransformPaintPropertyNode> localTransformSpace, 93 PassRefPtr<const TransformPaintPropertyNode> localTransformSpace,
94 const FloatRoundedRect& clipRect) { 94 const FloatRoundedRect& clipRect) {
95 DCHECK(!RuntimeEnabledFeatures::rootLayerScrollingEnabled()); 95 DCHECK(!RuntimeEnabledFeatures::rootLayerScrollingEnabled());
96 if (ClipPaintPropertyNode* existingContentClip = frameView.contentClip()) 96 if (auto* existingContentClip = frameView.contentClip()) {
97 existingContentClip->update(std::move(parent), 97 existingContentClip->update(std::move(parent),
98 std::move(localTransformSpace), clipRect); 98 std::move(localTransformSpace), clipRect);
99 else 99 } else {
100 frameView.setContentClip(ClipPaintPropertyNode::create( 100 frameView.setContentClip(ClipPaintPropertyNode::create(
101 std::move(parent), std::move(localTransformSpace), clipRect)); 101 std::move(parent), std::move(localTransformSpace), clipRect));
102 return frameView.contentClip(); 102 }
103 } 103 }
104 104
105 const TransformPaintPropertyNode* updateFrameViewScrollTranslation( 105 void updateFrameViewScrollTranslation(
106 FrameView& frameView, 106 FrameView& frameView,
107 PassRefPtr<const TransformPaintPropertyNode> parent, 107 PassRefPtr<const TransformPaintPropertyNode> parent,
108 const TransformationMatrix& matrix, 108 const TransformationMatrix& matrix,
109 const FloatPoint3D& origin) { 109 const FloatPoint3D& origin) {
110 DCHECK(!RuntimeEnabledFeatures::rootLayerScrollingEnabled()); 110 DCHECK(!RuntimeEnabledFeatures::rootLayerScrollingEnabled());
111 if (TransformPaintPropertyNode* existingScrollTranslation = 111 if (auto* existingScrollTranslation = frameView.scrollTranslation()) {
112 frameView.scrollTranslation())
113 existingScrollTranslation->update(std::move(parent), matrix, origin); 112 existingScrollTranslation->update(std::move(parent), matrix, origin);
114 else 113 } else {
115 frameView.setScrollTranslation( 114 frameView.setScrollTranslation(
116 TransformPaintPropertyNode::create(std::move(parent), matrix, origin)); 115 TransformPaintPropertyNode::create(std::move(parent), matrix, origin));
117 return frameView.scrollTranslation(); 116 }
118 } 117 }
119 118
120 ScrollPaintPropertyNode* updateFrameViewScroll( 119 void updateFrameViewScroll(
121 FrameView& frameView, 120 FrameView& frameView,
122 PassRefPtr<ScrollPaintPropertyNode> parent, 121 PassRefPtr<ScrollPaintPropertyNode> parent,
123 PassRefPtr<const TransformPaintPropertyNode> scrollOffset, 122 PassRefPtr<const TransformPaintPropertyNode> scrollOffset,
124 const IntSize& clip, 123 const IntSize& clip,
125 const IntSize& bounds, 124 const IntSize& bounds,
126 bool userScrollableHorizontal, 125 bool userScrollableHorizontal,
127 bool userScrollableVertical) { 126 bool userScrollableVertical) {
128 DCHECK(!RuntimeEnabledFeatures::rootLayerScrollingEnabled()); 127 DCHECK(!RuntimeEnabledFeatures::rootLayerScrollingEnabled());
129 if (ScrollPaintPropertyNode* existingScroll = frameView.scroll()) 128 if (auto* existingScroll = frameView.scroll()) {
130 existingScroll->update(std::move(parent), std::move(scrollOffset), clip, 129 existingScroll->update(std::move(parent), std::move(scrollOffset), clip,
131 bounds, userScrollableHorizontal, 130 bounds, userScrollableHorizontal,
132 userScrollableVertical); 131 userScrollableVertical);
133 else 132 } else {
134 frameView.setScroll(ScrollPaintPropertyNode::create( 133 frameView.setScroll(ScrollPaintPropertyNode::create(
135 std::move(parent), std::move(scrollOffset), clip, bounds, 134 std::move(parent), std::move(scrollOffset), clip, bounds,
136 userScrollableHorizontal, userScrollableVertical)); 135 userScrollableHorizontal, userScrollableVertical));
137 return frameView.scroll(); 136 }
138 } 137 }
139 138
140 void PaintPropertyTreeBuilder::buildTreeNodes( 139 void PaintPropertyTreeBuilder::updateProperties(
141 FrameView& frameView, 140 FrameView& frameView,
142 PaintPropertyTreeBuilderContext& context) { 141 PaintPropertyTreeBuilderContext& context) {
143 if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) { 142 if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) {
144 LayoutView* layoutView = frameView.layoutView(); 143 LayoutView* layoutView = frameView.layoutView();
145 if (!layoutView) 144 if (!layoutView)
146 return; 145 return;
147 146
148 TransformationMatrix frameTranslate; 147 #if DCHECK_IS_ON()
149 frameTranslate.translate(frameView.x() + layoutView->location().x() + 148 auto findObjectPropertiesNeedingUpdateScope =
150 context.current.paintOffset.x(), 149 FindObjectPropertiesNeedingUpdateScope::create(*layoutView);
151 frameView.y() + layoutView->location().y() + 150 #endif
152 context.current.paintOffset.y()); 151
153 context.current.transform = 152 if (layoutView->needsPaintPropertyUpdate()) {
154 layoutView->getMutableForPainting() 153 TransformationMatrix frameTranslate;
155 .ensurePaintProperties() 154 frameTranslate.translate(frameView.x() + layoutView->location().x() +
156 .updatePaintOffsetTranslation(context.current.transform, 155 context.current.paintOffset.x(),
157 frameTranslate, FloatPoint3D()); 156 frameView.y() + layoutView->location().y() +
157 context.current.paintOffset.y());
158 layoutView->getMutableForPainting()
159 .ensurePaintProperties()
160 .updatePaintOffsetTranslation(context.current.transform,
161 frameTranslate, FloatPoint3D());
162 }
163
164 const auto* properties = layoutView->paintProperties();
165 DCHECK(properties && properties->paintOffsetTranslation());
166 context.current.transform = properties->paintOffsetTranslation();
158 context.current.paintOffset = LayoutPoint(); 167 context.current.paintOffset = LayoutPoint();
159 context.current.renderingContextID = 0; 168 context.current.renderingContextID = 0;
160 context.current.shouldFlattenInheritedTransform = true; 169 context.current.shouldFlattenInheritedTransform = true;
161 context.absolutePosition = context.current; 170 context.absolutePosition = context.current;
162 context.containerForAbsolutePosition = 171 context.containerForAbsolutePosition =
163 nullptr; // This will get set in updateOutOfFlowContext(). 172 nullptr; // This will get set in updateOutOfFlowContext().
164 context.fixedPosition = context.current; 173 context.fixedPosition = context.current;
165 return; 174 return;
166 } 175 }
167 176
168 TransformationMatrix frameTranslate; 177 #if DCHECK_IS_ON()
169 frameTranslate.translate(frameView.x() + context.current.paintOffset.x(), 178 auto findFrameViewPropertiesNeedingUpdateScope =
170 frameView.y() + context.current.paintOffset.y()); 179 FindFrameViewPropertiesNeedingUpdateScope::create(&frameView);
171 context.current.transform = updateFrameViewPreTranslation( 180 #endif
172 frameView, context.current.transform, frameTranslate, FloatPoint3D());
173 181
174 FloatRoundedRect contentClip( 182 if (frameView.needsPaintPropertyUpdate()) {
175 IntRect(IntPoint(), frameView.visibleContentSize())); 183 TransformationMatrix frameTranslate;
176 context.current.clip = updateFrameViewContentClip( 184 frameTranslate.translate(frameView.x() + context.current.paintOffset.x(),
177 frameView, context.current.clip, frameView.preTranslation(), contentClip); 185 frameView.y() + context.current.paintOffset.y());
186 updateFrameViewPreTranslation(frameView, context.current.transform,
187 frameTranslate, FloatPoint3D());
178 188
179 // Record the fixed properties before any scrolling occurs. 189 FloatRoundedRect contentClip(
180 const auto* fixedTransformNode = context.current.transform; 190 IntRect(IntPoint(), frameView.visibleContentSize()));
181 auto* fixedScrollNode = context.current.scroll; 191 updateFrameViewContentClip(frameView, context.current.clip,
192 frameView.preTranslation(), contentClip);
182 193
183 ScrollOffset scrollOffset = frameView.scrollOffset(); 194 ScrollOffset scrollOffset = frameView.scrollOffset();
184 if (frameView.isScrollable() || !scrollOffset.isZero()) { 195 if (frameView.isScrollable() || !scrollOffset.isZero()) {
185 TransformationMatrix frameScroll; 196 TransformationMatrix frameScroll;
186 frameScroll.translate(-scrollOffset.width(), -scrollOffset.height()); 197 frameScroll.translate(-scrollOffset.width(), -scrollOffset.height());
187 context.current.transform = updateFrameViewScrollTranslation( 198 updateFrameViewScrollTranslation(frameView, frameView.preTranslation(),
188 frameView, frameView.preTranslation(), frameScroll, FloatPoint3D()); 199 frameScroll, FloatPoint3D());
189 200
190 IntSize scrollClip = frameView.visibleContentSize(); 201 IntSize scrollClip = frameView.visibleContentSize();
191 IntSize scrollBounds = frameView.contentsSize(); 202 IntSize scrollBounds = frameView.contentsSize();
192 bool userScrollableHorizontal = 203 bool userScrollableHorizontal =
193 frameView.userInputScrollable(HorizontalScrollbar); 204 frameView.userInputScrollable(HorizontalScrollbar);
194 bool userScrollableVertical = 205 bool userScrollableVertical =
195 frameView.userInputScrollable(VerticalScrollbar); 206 frameView.userInputScrollable(VerticalScrollbar);
196 context.current.scroll = updateFrameViewScroll( 207 updateFrameViewScroll(frameView, context.current.scroll,
197 frameView, context.current.scroll, frameView.scrollTranslation(), 208 frameView.scrollTranslation(), scrollClip,
198 scrollClip, scrollBounds, userScrollableHorizontal, 209 scrollBounds, userScrollableHorizontal,
199 userScrollableVertical); 210 userScrollableVertical);
200 } else { 211 } else {
201 // Ensure pre-existing properties are cleared when there is no scrolling. 212 // Ensure pre-existing properties are cleared when there is no scrolling.
202 frameView.setScrollTranslation(nullptr); 213 frameView.setScrollTranslation(nullptr);
203 frameView.setScroll(nullptr); 214 frameView.setScroll(nullptr);
215 }
204 } 216 }
205 217
206 // Initialize the context for current, absolute and fixed position cases. 218 // Initialize the context for current, absolute and fixed position cases.
207 // They are the same, except that scroll translation does not apply to 219 // They are the same, except that scroll translation does not apply to
208 // fixed position descendants. 220 // fixed position descendants.
221 const auto* fixedTransformNode = frameView.preTranslation()
222 ? frameView.preTranslation()
223 : context.current.transform;
224 auto* fixedScrollNode = context.current.scroll;
225 DCHECK(frameView.preTranslation());
226 context.current.transform = frameView.preTranslation();
227 DCHECK(frameView.contentClip());
228 context.current.clip = frameView.contentClip();
229 if (const auto* scrollTranslation = frameView.scrollTranslation())
230 context.current.transform = scrollTranslation;
231 if (auto* scroll = frameView.scroll())
232 context.current.scroll = scroll;
209 context.current.paintOffset = LayoutPoint(); 233 context.current.paintOffset = LayoutPoint();
210 context.current.renderingContextID = 0; 234 context.current.renderingContextID = 0;
211 context.current.shouldFlattenInheritedTransform = true; 235 context.current.shouldFlattenInheritedTransform = true;
212 context.absolutePosition = context.current; 236 context.absolutePosition = context.current;
213 context.containerForAbsolutePosition = nullptr; 237 context.containerForAbsolutePosition = nullptr;
214 context.fixedPosition = context.current; 238 context.fixedPosition = context.current;
215 context.fixedPosition.transform = fixedTransformNode; 239 context.fixedPosition.transform = fixedTransformNode;
216 context.fixedPosition.scroll = fixedScrollNode; 240 context.fixedPosition.scroll = fixedScrollNode;
217 241
218 std::unique_ptr<PropertyTreeState> contentsState( 242 std::unique_ptr<PropertyTreeState> contentsState(
219 new PropertyTreeState(context.current.transform, context.current.clip, 243 new PropertyTreeState(context.current.transform, context.current.clip,
220 context.currentEffect, context.current.scroll)); 244 context.currentEffect, context.current.scroll));
221 frameView.setTotalPropertyTreeStateForContents(std::move(contentsState)); 245 frameView.setTotalPropertyTreeStateForContents(std::move(contentsState));
222 } 246 }
223 247
224 void PaintPropertyTreeBuilder::updatePaintOffsetTranslation( 248 void PaintPropertyTreeBuilder::updatePaintOffsetTranslation(
225 const LayoutObject& object, 249 const LayoutObject& object,
226 PaintPropertyTreeBuilderContext& context) { 250 PaintPropertyTreeBuilderContext& context) {
227 // LayoutView's paint offset is updated in the FrameView property update. 251 // LayoutView's paint offset is updated in the FrameView property update.
228 if (object.isLayoutView()) { 252 if (object.isLayoutView()) {
229 DCHECK(context.current.paintOffset == LayoutPoint()); 253 DCHECK(context.current.paintOffset == LayoutPoint());
230 return; 254 return;
231 } 255 }
232 256
257 bool usesPaintOffsetTranslation = false;
233 if (object.isBoxModelObject() && 258 if (object.isBoxModelObject() &&
234 context.current.paintOffset != LayoutPoint()) { 259 context.current.paintOffset != LayoutPoint()) {
235 // TODO(trchen): Eliminate PaintLayer dependency. 260 // TODO(trchen): Eliminate PaintLayer dependency.
236 PaintLayer* layer = toLayoutBoxModelObject(object).layer(); 261 PaintLayer* layer = toLayoutBoxModelObject(object).layer();
237 if (layer && layer->paintsWithTransform(GlobalPaintNormalPhase)) { 262 if (layer && layer->paintsWithTransform(GlobalPaintNormalPhase))
238 // We should use the same subpixel paint offset values for snapping 263 usesPaintOffsetTranslation = true;
239 // regardless of whether a transform is present. If there is a transform 264 }
240 // we round the paint offset but keep around the residual fractional
241 // component for the transformed content to paint with. In spv1 this was
242 // called "subpixel accumulation". For more information, see
243 // PaintLayer::subpixelAccumulation() and
244 // PaintLayerPainter::paintFragmentByApplyingTransform.
245 IntPoint roundedPaintOffset =
246 roundedIntPoint(context.current.paintOffset);
247 LayoutPoint fractionalPaintOffset =
248 LayoutPoint(context.current.paintOffset - roundedPaintOffset);
249 265
250 context.current.transform = 266 // We should use the same subpixel paint offset values for snapping
251 object.getMutableForPainting() 267 // regardless of whether a transform is present. If there is a transform
252 .ensurePaintProperties() 268 // we round the paint offset but keep around the residual fractional
253 .updatePaintOffsetTranslation( 269 // component for the transformed content to paint with. In spv1 this was
254 context.current.transform, 270 // called "subpixel accumulation". For more information, see
255 TransformationMatrix().translate(roundedPaintOffset.x(), 271 // PaintLayer::subpixelAccumulation() and
256 roundedPaintOffset.y()), 272 // PaintLayerPainter::paintFragmentByApplyingTransform.
257 FloatPoint3D(), 273 IntPoint roundedPaintOffset = roundedIntPoint(context.current.paintOffset);
258 context.current.shouldFlattenInheritedTransform, 274 LayoutPoint fractionalPaintOffset =
259 context.current.renderingContextID); 275 LayoutPoint(context.current.paintOffset - roundedPaintOffset);
260 context.current.paintOffset = fractionalPaintOffset; 276
261 return; 277 if (object.needsPaintPropertyUpdate()) {
278 if (usesPaintOffsetTranslation) {
279 object.getMutableForPainting()
280 .ensurePaintProperties()
281 .updatePaintOffsetTranslation(
282 context.current.transform,
283 TransformationMatrix().translate(roundedPaintOffset.x(),
284 roundedPaintOffset.y()),
285 FloatPoint3D(), context.current.shouldFlattenInheritedTransform,
286 context.current.renderingContextID);
287 } else {
288 if (auto* properties = object.getMutableForPainting().paintProperties())
289 properties->clearPaintOffsetTranslation();
262 } 290 }
263 } 291 }
264 292
265 if (auto* properties = object.getMutableForPainting().paintProperties()) 293 const auto* properties = object.paintProperties();
266 properties->clearPaintOffsetTranslation(); 294 if (properties && properties->paintOffsetTranslation()) {
295 context.current.transform = properties->paintOffsetTranslation();
296 context.current.paintOffset = fractionalPaintOffset;
297 }
267 } 298 }
268 299
269 static FloatPoint3D transformOrigin(const LayoutBox& box) { 300 static FloatPoint3D transformOrigin(const LayoutBox& box) {
270 const ComputedStyle& style = box.styleRef(); 301 const ComputedStyle& style = box.styleRef();
271 FloatSize borderBoxSize(box.size()); 302 FloatSize borderBoxSize(box.size());
272 return FloatPoint3D( 303 return FloatPoint3D(
273 floatValueForLength(style.transformOriginX(), borderBoxSize.width()), 304 floatValueForLength(style.transformOriginX(), borderBoxSize.width()),
274 floatValueForLength(style.transformOriginY(), borderBoxSize.height()), 305 floatValueForLength(style.transformOriginY(), borderBoxSize.height()),
275 style.transformOriginZ()); 306 style.transformOriginZ());
276 } 307 }
277 308
278 // SVG does not use the general transform update of |updateTransform|, instead 309 // SVG does not use the general transform update of |updateTransform|, instead
279 // creating a transform node for SVG-specific transforms without 3D. 310 // creating a transform node for SVG-specific transforms without 3D.
280 void PaintPropertyTreeBuilder::updateTransformForNonRootSVG( 311 void PaintPropertyTreeBuilder::updateTransformForNonRootSVG(
281 const LayoutObject& object, 312 const LayoutObject& object,
282 PaintPropertyTreeBuilderContext& context) { 313 PaintPropertyTreeBuilderContext& context) {
283 DCHECK(object.isSVG() && !object.isSVGRoot()); 314 DCHECK(object.isSVG() && !object.isSVGRoot());
284 // SVG (other than SVGForeignObject) does not use paint offset internally. 315 // SVG (other than SVGForeignObject) does not use paint offset internally.
285 DCHECK(object.isSVGForeignObject() || 316 DCHECK(object.isSVGForeignObject() ||
286 context.current.paintOffset == LayoutPoint()); 317 context.current.paintOffset == LayoutPoint());
287 318
288 // FIXME(pdr): Refactor this so all non-root SVG objects use the same 319 if (object.needsPaintPropertyUpdate()) {
289 // transform function. 320 // FIXME(pdr): Refactor this so all non-root SVG objects use the same
Xianzhu 2016/10/26 19:21:51 Nit: s/FIXME/TODO/
pdr. 2016/10/26 23:10:19 Done
290 const AffineTransform& transform = object.isSVGForeignObject() 321 // transform function.
291 ? object.localSVGTransform() 322 const AffineTransform& transform = object.isSVGForeignObject()
292 : object.localToSVGParentTransform(); 323 ? object.localSVGTransform()
324 : object.localToSVGParentTransform();
325 // FIXME(pdr): Check for the presence of a transform instead of the value.
326 // Checking for an identity matrix will cause the property tree structure
327 // to change during animations if the animation passes through the
328 // identity matrix.
329 if (!transform.isIdentity()) {
330 // The origin is included in the local transform, so leave origin empty.
331 object.getMutableForPainting().ensurePaintProperties().updateTransform(
332 context.current.transform, TransformationMatrix(transform),
333 FloatPoint3D());
334 } else {
335 if (auto* properties = object.getMutableForPainting().paintProperties())
336 properties->clearTransform();
337 }
338 }
293 339
294 // FIXME(pdr): Check for the presence of a transform instead of the value. 340 if (object.paintProperties() && object.paintProperties()->transform()) {
295 // Checking for an identity matrix will cause the property tree structure to 341 context.current.transform = object.paintProperties()->transform();
296 // change during animations if the animation passes through the identity 342 context.current.shouldFlattenInheritedTransform = false;
297 // matrix.
298 if (!transform.isIdentity()) {
299 // The origin is included in the local transform, so leave origin empty.
300 context.current.transform =
301 object.getMutableForPainting().ensurePaintProperties().updateTransform(
302 context.current.transform, TransformationMatrix(transform),
303 FloatPoint3D());
304 context.current.renderingContextID = 0; 343 context.current.renderingContextID = 0;
305 context.current.shouldFlattenInheritedTransform = false;
306 } else {
307 if (auto* properties = object.getMutableForPainting().paintProperties())
308 properties->clearTransform();
309 } 344 }
310 } 345 }
311 346
312 void PaintPropertyTreeBuilder::updateTransform( 347 void PaintPropertyTreeBuilder::updateTransform(
313 const LayoutObject& object, 348 const LayoutObject& object,
314 PaintPropertyTreeBuilderContext& context) { 349 PaintPropertyTreeBuilderContext& context) {
315 if (object.isSVG() && !object.isSVGRoot()) { 350 if (object.isSVG() && !object.isSVGRoot()) {
316 updateTransformForNonRootSVG(object, context); 351 updateTransformForNonRootSVG(object, context);
317 return; 352 return;
318 } 353 }
319 354
320 const ComputedStyle& style = object.styleRef(); 355 if (object.needsPaintPropertyUpdate()) {
321 if (object.isBox() && (style.hasTransform() || style.preserves3D())) { 356 const ComputedStyle& style = object.styleRef();
322 TransformationMatrix matrix; 357 if (object.isBox() && (style.hasTransform() || style.preserves3D())) {
323 style.applyTransform(matrix, toLayoutBox(object).size(), 358 TransformationMatrix matrix;
324 ComputedStyle::ExcludeTransformOrigin, 359 style.applyTransform(
325 ComputedStyle::IncludeMotionPath, 360 matrix, toLayoutBox(object).size(),
326 ComputedStyle::IncludeIndependentTransformProperties); 361 ComputedStyle::ExcludeTransformOrigin,
327 FloatPoint3D origin = transformOrigin(toLayoutBox(object)); 362 ComputedStyle::IncludeMotionPath,
363 ComputedStyle::IncludeIndependentTransformProperties);
328 364
329 unsigned renderingContextID = context.current.renderingContextID; 365 // TODO(trchen): transform-style should only be respected if a PaintLayer
330 unsigned renderingContextIDForChildren = 0; 366 // is created.
331 bool flattensInheritedTransform =
332 context.current.shouldFlattenInheritedTransform;
333 bool childrenFlattenInheritedTransform = true;
334
335 // TODO(trchen): transform-style should only be respected if a PaintLayer
336 // is created.
337 if (style.preserves3D()) {
338 // If a node with transform-style: preserve-3d does not exist in an 367 // If a node with transform-style: preserve-3d does not exist in an
339 // existing rendering context, it establishes a new one. 368 // existing rendering context, it establishes a new one.
340 if (!renderingContextID) 369 unsigned renderingContextID = context.current.renderingContextID;
370 if (style.preserves3D() && !renderingContextID)
341 renderingContextID = PtrHash<const LayoutObject>::hash(&object); 371 renderingContextID = PtrHash<const LayoutObject>::hash(&object);
342 renderingContextIDForChildren = renderingContextID; 372
343 childrenFlattenInheritedTransform = false; 373 object.getMutableForPainting().ensurePaintProperties().updateTransform(
374 context.current.transform, matrix,
375 transformOrigin(toLayoutBox(object)),
376 context.current.shouldFlattenInheritedTransform, renderingContextID);
377 } else {
378 if (auto* properties = object.getMutableForPainting().paintProperties())
379 properties->clearTransform();
344 } 380 }
381 }
345 382
346 context.current.transform = 383 const auto* properties = object.paintProperties();
347 object.getMutableForPainting().ensurePaintProperties().updateTransform( 384 if (properties && properties->transform()) {
348 context.current.transform, matrix, origin, 385 context.current.transform = properties->transform();
349 flattensInheritedTransform, renderingContextID); 386 unsigned renderingContextID = properties->transform()->renderingContextID();
350 context.current.renderingContextID = renderingContextIDForChildren; 387 if (context.current.renderingContextID != renderingContextID) {
351 context.current.shouldFlattenInheritedTransform = 388 context.current.renderingContextID = renderingContextID;
352 childrenFlattenInheritedTransform; 389 context.current.shouldFlattenInheritedTransform = false;
353 } else { 390 } else {
354 if (auto* properties = object.getMutableForPainting().paintProperties()) 391 context.current.renderingContextID = 0;
355 properties->clearTransform(); 392 context.current.shouldFlattenInheritedTransform = true;
393 }
356 } 394 }
357 } 395 }
358 396
359 void PaintPropertyTreeBuilder::updateEffect( 397 void PaintPropertyTreeBuilder::updateEffect(
360 const LayoutObject& object, 398 const LayoutObject& object,
361 PaintPropertyTreeBuilderContext& context) { 399 PaintPropertyTreeBuilderContext& context) {
362 const ComputedStyle& style = object.styleRef(); 400 const ComputedStyle& style = object.styleRef();
363 401
364 if (!style.isStackingContext()) { 402 if (!style.isStackingContext()) {
365 if (ObjectPaintProperties* properties = 403 if (object.needsPaintPropertyUpdate()) {
366 object.getMutableForPainting().paintProperties()) 404 if (auto* properties = object.getMutableForPainting().paintProperties())
367 properties->clearEffect(); 405 properties->clearEffect();
406 }
368 return; 407 return;
369 } 408 }
370 409
371 // TODO(trchen): Can't omit effect node if we have 3D children. 410 if (object.needsPaintPropertyUpdate()) {
372 // TODO(trchen): Can't omit effect node if we have blending children. 411 // TODO(trchen): Can't omit effect node if we have 3D children.
373 bool effectNodeNeeded = false; 412 // TODO(trchen): Can't omit effect node if we have blending children.
413 bool effectNodeNeeded = false;
374 414
375 float opacity = style.opacity(); 415 float opacity = style.opacity();
376 if (opacity != 1.0f) 416 if (opacity != 1.0f)
377 effectNodeNeeded = true; 417 effectNodeNeeded = true;
378 418
379 CompositorFilterOperations filter; 419 CompositorFilterOperations filter;
380 if (object.isSVG() && !object.isSVGRoot()) { 420 if (object.isSVG() && !object.isSVGRoot()) {
381 // TODO(trchen): SVG caches filters in SVGResources. Implement it. 421 // TODO(trchen): SVG caches filters in SVGResources. Implement it.
382 } else if (PaintLayer* layer = toLayoutBoxModelObject(object).layer()) { 422 } else if (PaintLayer* layer = toLayoutBoxModelObject(object).layer()) {
383 // TODO(trchen): Eliminate PaintLayer dependency. 423 // TODO(trchen): Eliminate PaintLayer dependency.
384 filter = layer->createCompositorFilterOperationsForFilter(style); 424 filter = layer->createCompositorFilterOperationsForFilter(style);
425 }
426
427 const ClipPaintPropertyNode* outputClip = rootClipNode();
428 // The CSS filter spec didn't specify how filters interact with overflow
429 // clips. The implementation here mimics the old Blink/WebKit behavior for
430 // backward compatibility.
431 // Basically the output of the filter will be affected by clips that applies
432 // to the current element. The descendants that paints into the input of the
433 // filter ignores any clips collected so far. For example:
434 // <div style="overflow:scroll">
435 // <div style="filter:blur(1px);">
436 // <div>A</div>
437 // <div style="position:absolute;">B</div>
438 // </div>
439 // </div>
440 // In this example "A" should be clipped if the filter was not present.
441 // With the filter, "A" will be rastered without clipping, but instead
442 // the blurred result will be clipped.
443 // On the other hand, "B" should not be clipped because the overflow clip is
444 // not in its containing block chain, but as the filter output will be
445 // clipped, so a blurred "B" may still be invisible.
446 if (!filter.isEmpty()) {
447 effectNodeNeeded = true;
448 outputClip = context.current.clip;
449
450 // TODO(trchen): A filter may contain spatial operations such that an
451 // output pixel may depend on an input pixel outside of the output clip.
452 // We should generate a special clip node to represent this expansion.
453 }
454
455 if (effectNodeNeeded) {
456 object.getMutableForPainting().ensurePaintProperties().updateEffect(
457 context.currentEffect, context.current.transform, outputClip,
458 std::move(filter), opacity);
459 } else {
460 if (auto* properties = object.getMutableForPainting().paintProperties())
461 properties->clearEffect();
462 }
385 } 463 }
386 464
387 const ClipPaintPropertyNode* outputClip = rootClipNode(); 465 const auto* properties = object.paintProperties();
388 // The CSS filter spec didn't specify how filters interact with overflow 466 if (properties && properties->effect()) {
389 // clips. The implementation here mimics the old Blink/WebKit behavior for 467 context.currentEffect = properties->effect();
390 // backward compatibility. 468 // TODO(pdr): Once the expansion clip node is created above, it should be
391 // Basically the output of the filter will be affected by clips that applies 469 // used here to update all current clip nodes;
392 // to the current element. The descendants that paints into the input of the
393 // filter ignores any clips collected so far. For example:
394 // <div style="overflow:scroll">
395 // <div style="filter:blur(1px);">
396 // <div>A</div>
397 // <div style="position:absolute;">B</div>
398 // </div>
399 // </div>
400 // In this example "A" should be clipped if the filter was not present.
401 // With the filter, "A" will be rastered without clipping, but instead
402 // the blurred result will be clipped.
403 // On the other hand, "B" should not be clipped because the overflow clip is
404 // not in its containing block chain, but as the filter output will be
405 // clipped, so a blurred "B" may still be invisible.
406 if (!filter.isEmpty()) {
407 effectNodeNeeded = true;
408 outputClip = context.current.clip;
409
410 // TODO(trchen): A filter may contain spatial operations such that an output
411 // pixel may depend on an input pixel outside of the output clip. Need to
412 // generate special clip node to hint how to expand clip / cull rect.
413 const ClipPaintPropertyNode* expansionHint = context.current.clip; 470 const ClipPaintPropertyNode* expansionHint = context.current.clip;
414 context.current.clip = context.absolutePosition.clip = 471 context.current.clip = context.absolutePosition.clip =
415 context.fixedPosition.clip = expansionHint; 472 context.fixedPosition.clip = expansionHint;
416 } 473 }
417
418 if (!effectNodeNeeded) {
419 if (ObjectPaintProperties* properties =
420 object.getMutableForPainting().paintProperties())
421 properties->clearEffect();
422 return;
423 }
424
425 context.currentEffect =
426 object.getMutableForPainting().ensurePaintProperties().updateEffect(
427 context.currentEffect, context.current.transform, outputClip,
428 std::move(filter), opacity);
429 } 474 }
430 475
431 void PaintPropertyTreeBuilder::updateCssClip( 476 void PaintPropertyTreeBuilder::updateCssClip(
432 const LayoutObject& object, 477 const LayoutObject& object,
433 PaintPropertyTreeBuilderContext& context) { 478 PaintPropertyTreeBuilderContext& context) {
434 if (object.hasClip()) { 479 if (object.needsPaintPropertyUpdate()) {
435 // Create clip node for descendants that are not fixed position. 480 if (object.hasClip()) {
436 // We don't have to setup context.absolutePosition.clip here because this 481 // Create clip node for descendants that are not fixed position.
437 // object must be a container for absolute position descendants, and will 482 // We don't have to setup context.absolutePosition.clip here because this
438 // copy from in-flow context later at updateOutOfFlowContext() step. 483 // object must be a container for absolute position descendants, and will
439 DCHECK(object.canContainAbsolutePositionObjects()); 484 // copy from in-flow context later at updateOutOfFlowContext() step.
440 LayoutRect clipRect = 485 DCHECK(object.canContainAbsolutePositionObjects());
441 toLayoutBox(object).clipRect(context.current.paintOffset); 486 LayoutRect clipRect =
442 context.current.clip = 487 toLayoutBox(object).clipRect(context.current.paintOffset);
443 object.getMutableForPainting().ensurePaintProperties().updateCssClip( 488 object.getMutableForPainting().ensurePaintProperties().updateCssClip(
444 context.current.clip, context.current.transform, 489 context.current.clip, context.current.transform,
445 FloatRoundedRect(FloatRect(clipRect))); 490 FloatRoundedRect(FloatRect(clipRect)));
446 return; 491 } else {
492 if (auto* properties = object.getMutableForPainting().paintProperties())
493 properties->clearCssClip();
494 }
447 } 495 }
448 496
449 if (auto* properties = object.getMutableForPainting().paintProperties()) 497 const auto* properties = object.paintProperties();
450 properties->clearCssClip(); 498 if (properties && properties->cssClip())
499 context.current.clip = properties->cssClip();
451 } 500 }
452 501
453 void PaintPropertyTreeBuilder::updateLocalBorderBoxContext( 502 void PaintPropertyTreeBuilder::updateLocalBorderBoxContext(
454 const LayoutObject& object, 503 const LayoutObject& object,
455 PaintPropertyTreeBuilderContext& context) { 504 PaintPropertyTreeBuilderContext& context) {
456 // Avoid adding an ObjectPaintProperties for non-boxes to save memory, since 505 if (object.needsPaintPropertyUpdate()) {
457 // we don't need them at the moment. 506 // Avoid adding an ObjectPaintProperties for non-boxes to save memory, since
458 if (!object.isBox() && !object.hasLayer()) 507 // we don't need them at the moment.
459 return; 508 if (!object.isBox() && !object.hasLayer()) {
460 509 if (auto* properties = object.getMutableForPainting().paintProperties())
461 std::unique_ptr<ObjectPaintProperties::PropertyTreeStateWithOffset> 510 properties->clearLocalBorderBoxProperties();
462 borderBoxContext = 511 } else {
463 wrapUnique(new ObjectPaintProperties::PropertyTreeStateWithOffset( 512 std::unique_ptr<ObjectPaintProperties::PropertyTreeStateWithOffset>
464 context.current.paintOffset, 513 borderBoxContext =
465 PropertyTreeState(context.current.transform, context.current.clip, 514 wrapUnique(new ObjectPaintProperties::PropertyTreeStateWithOffset(
466 context.currentEffect, 515 context.current.paintOffset,
467 context.current.scroll))); 516 PropertyTreeState(context.current.transform,
468 object.getMutableForPainting() 517 context.current.clip, context.currentEffect,
469 .ensurePaintProperties() 518 context.current.scroll)));
470 .setLocalBorderBoxProperties(std::move(borderBoxContext)); 519 object.getMutableForPainting()
520 .ensurePaintProperties()
521 .setLocalBorderBoxProperties(std::move(borderBoxContext));
522 }
523 }
471 } 524 }
472 525
473 // TODO(trchen): Remove this once we bake the paint offset into frameRect. 526 // TODO(trchen): Remove this once we bake the paint offset into frameRect.
474 void PaintPropertyTreeBuilder::updateScrollbarPaintOffset( 527 void PaintPropertyTreeBuilder::updateScrollbarPaintOffset(
475 const LayoutObject& object, 528 const LayoutObject& object,
476 const PaintPropertyTreeBuilderContext& context) { 529 const PaintPropertyTreeBuilderContext& context) {
530 if (!object.needsPaintPropertyUpdate())
531 return;
532
477 IntPoint roundedPaintOffset = roundedIntPoint(context.current.paintOffset); 533 IntPoint roundedPaintOffset = roundedIntPoint(context.current.paintOffset);
478 if (roundedPaintOffset != IntPoint() && object.isBoxModelObject()) { 534 if (roundedPaintOffset != IntPoint() && object.isBoxModelObject()) {
479 if (PaintLayerScrollableArea* scrollableArea = 535 if (PaintLayerScrollableArea* scrollableArea =
480 toLayoutBoxModelObject(object).getScrollableArea()) { 536 toLayoutBoxModelObject(object).getScrollableArea()) {
481 if (scrollableArea->horizontalScrollbar() || 537 if (scrollableArea->horizontalScrollbar() ||
482 scrollableArea->verticalScrollbar()) { 538 scrollableArea->verticalScrollbar()) {
483 auto paintOffset = TransformationMatrix().translate( 539 auto paintOffset = TransformationMatrix().translate(
484 roundedPaintOffset.x(), roundedPaintOffset.y()); 540 roundedPaintOffset.x(), roundedPaintOffset.y());
485 object.getMutableForPainting() 541 object.getMutableForPainting()
486 .ensurePaintProperties() 542 .ensurePaintProperties()
487 .updateScrollbarPaintOffset(context.current.transform, paintOffset, 543 .updateScrollbarPaintOffset(context.current.transform, paintOffset,
488 FloatPoint3D()); 544 FloatPoint3D());
489 return; 545 return;
490 } 546 }
491 } 547 }
492 } 548 }
493 549
494 if (auto* properties = object.getMutableForPainting().paintProperties()) 550 if (auto* properties = object.getMutableForPainting().paintProperties())
495 properties->clearScrollbarPaintOffset(); 551 properties->clearScrollbarPaintOffset();
496 } 552 }
497 553
498 void PaintPropertyTreeBuilder::updateMainThreadScrollingReasons( 554 void PaintPropertyTreeBuilder::updateMainThreadScrollingReasons(
499 const LayoutObject& object, 555 const LayoutObject& object,
500 PaintPropertyTreeBuilderContext& context) { 556 PaintPropertyTreeBuilderContext& context) {
557 // TODO(pdr): Mark properties as needing an update for main thread scroll
558 // reasons and ensure reason changes are propagated to ancestors to account
559 // for the parent walk below.
501 if (context.current.scroll && 560 if (context.current.scroll &&
502 !object.document().settings()->threadedScrollingEnabled()) 561 !object.document().settings()->threadedScrollingEnabled()) {
503 context.current.scroll->addMainThreadScrollingReasons( 562 context.current.scroll->addMainThreadScrollingReasons(
504 MainThreadScrollingReason::kThreadedScrollingDisabled); 563 MainThreadScrollingReason::kThreadedScrollingDisabled);
564 }
505 565
506 if (object.isBackgroundAttachmentFixedObject()) { 566 if (object.isBackgroundAttachmentFixedObject()) {
507 auto* scrollNode = context.current.scroll; 567 auto* scrollNode = context.current.scroll;
508 while ( 568 while (
509 scrollNode && 569 scrollNode &&
510 !scrollNode->hasMainThreadScrollingReasons( 570 !scrollNode->hasMainThreadScrollingReasons(
511 MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects)) { 571 MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects)) {
512 scrollNode->addMainThreadScrollingReasons( 572 scrollNode->addMainThreadScrollingReasons(
513 MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects); 573 MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects);
514 scrollNode = scrollNode->parent(); 574 scrollNode = scrollNode->parent();
515 } 575 }
516 } 576 }
517 } 577 }
518 578
519 void PaintPropertyTreeBuilder::updateOverflowClip( 579 void PaintPropertyTreeBuilder::updateOverflowClip(
520 const LayoutObject& object, 580 const LayoutObject& object,
521 PaintPropertyTreeBuilderContext& context) { 581 PaintPropertyTreeBuilderContext& context) {
522 if (!object.isBox()) 582 if (!object.isBox())
523 return; 583 return;
524 const LayoutBox& box = toLayoutBox(object); 584 const LayoutBox& box = toLayoutBox(object);
585 if (object.needsPaintPropertyUpdate()) {
586 // The <input> elements can't have contents thus CSS overflow property
587 // doesn't apply. However for layout purposes we do generate child layout
588 // objects for them, e.g. button label. We should clip the overflow from
589 // those children. This is called control clip and we technically treat them
590 // like overflow clip.
591 LayoutRect clipRect;
592 if (box.hasControlClip()) {
593 clipRect = box.controlClipRect(context.current.paintOffset);
594 } else if (box.hasOverflowClip() || box.styleRef().containsPaint() ||
595 (box.isSVGRoot() &&
596 toLayoutSVGRoot(box).shouldApplyViewportClip())) {
597 clipRect = LayoutRect(pixelSnappedIntRect(
598 box.overflowClipRect(context.current.paintOffset)));
599 } else {
600 if (auto* properties = object.getMutableForPainting().paintProperties()) {
601 properties->clearInnerBorderRadiusClip();
602 properties->clearOverflowClip();
603 }
604 return;
605 }
525 606
526 // The <input> elements can't have contents thus CSS overflow property doesn't 607 const auto* currentClip = context.current.clip;
527 // apply. However for layout purposes we do generate child layout objects for 608 if (box.styleRef().hasBorderRadius()) {
528 // them, e.g. button label. We should clip the overflow from those children. 609 auto innerBorder = box.styleRef().getRoundedInnerBorderFor(
529 // This is called control clip and we technically treat them like overflow 610 LayoutRect(context.current.paintOffset, box.size()));
530 // clip. 611 object.getMutableForPainting()
531 LayoutRect clipRect; 612 .ensurePaintProperties()
532 if (box.hasControlClip()) { 613 .updateInnerBorderRadiusClip(context.current.clip,
533 clipRect = box.controlClipRect(context.current.paintOffset); 614 context.current.transform, innerBorder);
534 } else if (box.hasOverflowClip() || box.styleRef().containsPaint() || 615 currentClip = object.paintProperties()->innerBorderRadiusClip();
535 (box.isSVGRoot() && 616 } else if (auto* properties =
536 toLayoutSVGRoot(box).shouldApplyViewportClip())) { 617 object.getMutableForPainting().paintProperties()) {
537 clipRect = LayoutRect(
538 pixelSnappedIntRect(box.overflowClipRect(context.current.paintOffset)));
539 } else {
540 if (auto* properties = object.getMutableForPainting().paintProperties()) {
541 properties->clearInnerBorderRadiusClip(); 618 properties->clearInnerBorderRadiusClip();
542 properties->clearOverflowClip();
543 } 619 }
544 return; 620
621 object.getMutableForPainting().ensurePaintProperties().updateOverflowClip(
622 currentClip, context.current.transform,
623 FloatRoundedRect(FloatRect(clipRect)));
545 } 624 }
546 625
547 if (box.styleRef().hasBorderRadius()) { 626 const auto* properties = object.paintProperties();
548 auto innerBorder = box.styleRef().getRoundedInnerBorderFor( 627 if (properties && properties->overflowClip())
549 LayoutRect(context.current.paintOffset, box.size())); 628 context.current.clip = properties->overflowClip();
550 context.current.clip =
551 object.getMutableForPainting()
552 .ensurePaintProperties()
553 .updateInnerBorderRadiusClip(
554 context.current.clip, context.current.transform, innerBorder);
555 } else if (auto* properties =
556 object.getMutableForPainting().paintProperties()) {
557 properties->clearInnerBorderRadiusClip();
558 }
559
560 context.current.clip =
561 object.getMutableForPainting().ensurePaintProperties().updateOverflowClip(
562 context.current.clip, context.current.transform,
563 FloatRoundedRect(FloatRect(clipRect)));
564 } 629 }
565 630
566 static FloatPoint perspectiveOrigin(const LayoutBox& box) { 631 static FloatPoint perspectiveOrigin(const LayoutBox& box) {
567 const ComputedStyle& style = box.styleRef(); 632 const ComputedStyle& style = box.styleRef();
568 FloatSize borderBoxSize(box.size()); 633 FloatSize borderBoxSize(box.size());
569 return FloatPoint( 634 return FloatPoint(
570 floatValueForLength(style.perspectiveOriginX(), borderBoxSize.width()), 635 floatValueForLength(style.perspectiveOriginX(), borderBoxSize.width()),
571 floatValueForLength(style.perspectiveOriginY(), borderBoxSize.height())); 636 floatValueForLength(style.perspectiveOriginY(), borderBoxSize.height()));
572 } 637 }
573 638
574 void PaintPropertyTreeBuilder::updatePerspective( 639 void PaintPropertyTreeBuilder::updatePerspective(
575 const LayoutObject& object, 640 const LayoutObject& object,
576 PaintPropertyTreeBuilderContext& context) { 641 PaintPropertyTreeBuilderContext& context) {
577 const ComputedStyle& style = object.styleRef(); 642 if (object.needsPaintPropertyUpdate()) {
578 if (!object.isBox() || !style.hasPerspective()) { 643 const ComputedStyle& style = object.styleRef();
579 if (auto* properties = object.getMutableForPainting().paintProperties()) 644 if (object.isBox() && style.hasPerspective()) {
580 properties->clearPerspective(); 645 // The perspective node must not flatten (else nothing will get
581 return; 646 // perspective), but it should still extend the rendering context as
582 } 647 // most transform nodes do.
583 648 TransformationMatrix matrix =
584 // The perspective node must not flatten (else nothing will get 649 TransformationMatrix().applyPerspective(style.perspective());
585 // perspective), but it should still extend the rendering context as most 650 FloatPoint3D origin = perspectiveOrigin(toLayoutBox(object)) +
586 // transform nodes do. 651 toLayoutSize(context.current.paintOffset);
587 TransformationMatrix matrix =
588 TransformationMatrix().applyPerspective(style.perspective());
589 FloatPoint3D origin = perspectiveOrigin(toLayoutBox(object)) +
590 toLayoutSize(context.current.paintOffset);
591 context.current.transform =
592 object.getMutableForPainting().ensurePaintProperties().updatePerspective( 652 object.getMutableForPainting().ensurePaintProperties().updatePerspective(
593 context.current.transform, matrix, origin, 653 context.current.transform, matrix, origin,
594 context.current.shouldFlattenInheritedTransform, 654 context.current.shouldFlattenInheritedTransform,
595 context.current.renderingContextID); 655 context.current.renderingContextID);
596 context.current.shouldFlattenInheritedTransform = false; 656 } else {
657 if (auto* properties = object.getMutableForPainting().paintProperties())
658 properties->clearPerspective();
659 }
660 }
661
662 const auto* properties = object.paintProperties();
663 if (properties && properties->perspective()) {
664 context.current.transform = properties->perspective();
665 context.current.shouldFlattenInheritedTransform = false;
666 }
597 } 667 }
598 668
599 void PaintPropertyTreeBuilder::updateSvgLocalToBorderBoxTransform( 669 void PaintPropertyTreeBuilder::updateSvgLocalToBorderBoxTransform(
600 const LayoutObject& object, 670 const LayoutObject& object,
601 PaintPropertyTreeBuilderContext& context) { 671 PaintPropertyTreeBuilderContext& context) {
602 if (!object.isSVGRoot()) 672 if (!object.isSVGRoot())
603 return; 673 return;
604 674
605 AffineTransform transformToBorderBox = 675 if (object.needsPaintPropertyUpdate()) {
606 SVGRootPainter(toLayoutSVGRoot(object)) 676 AffineTransform transformToBorderBox =
607 .transformToPixelSnappedBorderBox(context.current.paintOffset); 677 SVGRootPainter(toLayoutSVGRoot(object))
608 678 .transformToPixelSnappedBorderBox(context.current.paintOffset);
609 // The paint offset is included in |transformToBorderBox| so SVG does not need 679 if (!transformToBorderBox.isIdentity()) {
610 // to handle paint offset internally.
611 context.current.paintOffset = LayoutPoint();
612
613 if (transformToBorderBox.isIdentity()) {
614 if (auto* properties = object.getMutableForPainting().paintProperties())
615 properties->clearSvgLocalToBorderBoxTransform();
616 return;
617 }
618
619 context.current.transform =
620 object.getMutableForPainting() 680 object.getMutableForPainting()
621 .ensurePaintProperties() 681 .ensurePaintProperties()
622 .updateSvgLocalToBorderBoxTransform( 682 .updateSvgLocalToBorderBoxTransform(
623 context.current.transform, transformToBorderBox, FloatPoint3D()); 683 context.current.transform, transformToBorderBox, FloatPoint3D());
624 context.current.shouldFlattenInheritedTransform = false; 684 } else {
625 context.current.renderingContextID = 0; 685 if (auto* properties = object.getMutableForPainting().paintProperties())
686 properties->clearSvgLocalToBorderBoxTransform();
687 }
688 }
689
690 const auto* properties = object.paintProperties();
691 if (properties && properties->svgLocalToBorderBoxTransform()) {
692 context.current.transform = properties->svgLocalToBorderBoxTransform();
693 context.current.shouldFlattenInheritedTransform = false;
694 context.current.renderingContextID = 0;
695 }
696 // The paint offset is included in |transformToBorderBox| so SVG does not need
697 // to handle paint offset internally.
698 context.current.paintOffset = LayoutPoint();
626 } 699 }
627 700
628 void PaintPropertyTreeBuilder::updateScrollAndScrollTranslation( 701 void PaintPropertyTreeBuilder::updateScrollAndScrollTranslation(
629 const LayoutObject& object, 702 const LayoutObject& object,
630 PaintPropertyTreeBuilderContext& context) { 703 PaintPropertyTreeBuilderContext& context) {
631 if (object.hasOverflowClip()) { 704 if (object.needsPaintPropertyUpdate()) {
632 const LayoutBox& box = toLayoutBox(object); 705 if (object.hasOverflowClip()) {
633 const PaintLayerScrollableArea* scrollableArea = box.getScrollableArea(); 706 const LayoutBox& box = toLayoutBox(object);
634 IntSize scrollOffset = box.scrolledContentOffset(); 707 const PaintLayerScrollableArea* scrollableArea = box.getScrollableArea();
635 if (!scrollOffset.isZero() || scrollableArea->scrollsOverflow()) { 708 IntSize scrollOffset = box.scrolledContentOffset();
636 TransformationMatrix matrix = TransformationMatrix().translate( 709 if (!scrollOffset.isZero() || scrollableArea->scrollsOverflow()) {
637 -scrollOffset.width(), -scrollOffset.height()); 710 TransformationMatrix matrix = TransformationMatrix().translate(
638 context.current.transform = 711 -scrollOffset.width(), -scrollOffset.height());
639 object.getMutableForPainting() 712 object.getMutableForPainting()
640 .ensurePaintProperties() 713 .ensurePaintProperties()
641 .updateScrollTranslation( 714 .updateScrollTranslation(
642 context.current.transform, matrix, FloatPoint3D(), 715 context.current.transform, matrix, FloatPoint3D(),
643 context.current.shouldFlattenInheritedTransform, 716 context.current.shouldFlattenInheritedTransform,
644 context.current.renderingContextID); 717 context.current.renderingContextID);
645 718
646 IntSize scrollClip = scrollableArea->visibleContentRect().size(); 719 IntSize scrollClip = scrollableArea->visibleContentRect().size();
647 IntSize scrollBounds = scrollableArea->contentsSize(); 720 IntSize scrollBounds = scrollableArea->contentsSize();
648 bool userScrollableHorizontal = 721 bool userScrollableHorizontal =
649 scrollableArea->userInputScrollable(HorizontalScrollbar); 722 scrollableArea->userInputScrollable(HorizontalScrollbar);
650 bool userScrollableVertical = 723 bool userScrollableVertical =
651 scrollableArea->userInputScrollable(VerticalScrollbar); 724 scrollableArea->userInputScrollable(VerticalScrollbar);
652 context.current.scroll = 725 object.getMutableForPainting().ensurePaintProperties().updateScroll(
653 object.getMutableForPainting().ensurePaintProperties().updateScroll( 726 context.current.scroll,
654 context.current.scroll, context.current.transform, scrollClip, 727 object.paintProperties()->scrollTranslation(), scrollClip,
655 scrollBounds, userScrollableHorizontal, userScrollableVertical); 728 scrollBounds, userScrollableHorizontal, userScrollableVertical);
656 729 } else {
657 context.current.shouldFlattenInheritedTransform = false; 730 // Ensure pre-existing properties are cleared when there is no
658 return; 731 // scrolling.
732 auto* properties = object.getMutableForPainting().paintProperties();
733 if (properties) {
734 properties->clearScrollTranslation();
735 properties->clearScroll();
736 }
737 }
659 } 738 }
660 } 739 }
661 740
662 if (auto* properties = object.getMutableForPainting().paintProperties()) { 741 if (object.paintProperties() && object.paintProperties()->scroll()) {
663 properties->clearScrollTranslation(); 742 context.current.transform = object.paintProperties()->scrollTranslation();
664 properties->clearScroll(); 743 const auto* scroll = object.paintProperties()->scroll();
744 // TODO(pdr): Remove this const cast.
745 context.current.scroll = const_cast<ScrollPaintPropertyNode*>(scroll);
746 context.current.shouldFlattenInheritedTransform = false;
665 } 747 }
666 } 748 }
667 749
668 void PaintPropertyTreeBuilder::updateOutOfFlowContext( 750 void PaintPropertyTreeBuilder::updateOutOfFlowContext(
669 const LayoutObject& object, 751 const LayoutObject& object,
670 PaintPropertyTreeBuilderContext& context) { 752 PaintPropertyTreeBuilderContext& context) {
671 if (object.canContainAbsolutePositionObjects()) { 753 if (object.canContainAbsolutePositionObjects()) {
672 context.absolutePosition = context.current; 754 context.absolutePosition = context.current;
673 context.containerForAbsolutePosition = &object; 755 context.containerForAbsolutePosition = &object;
674 } 756 }
(...skipping 19 matching lines...) Expand all
694 // absolute position container. However for fixed-position descendants we 776 // absolute position container. However for fixed-position descendants we
695 // need to insert the clip here if we are not a containing block ancestor of 777 // need to insert the clip here if we are not a containing block ancestor of
696 // them. 778 // them.
697 auto* cssClip = object.getMutableForPainting().paintProperties()->cssClip(); 779 auto* cssClip = object.getMutableForPainting().paintProperties()->cssClip();
698 780
699 // Before we actually create anything, check whether in-flow context and 781 // Before we actually create anything, check whether in-flow context and
700 // fixed-position context has exactly the same clip. Reuse if possible. 782 // fixed-position context has exactly the same clip. Reuse if possible.
701 if (context.fixedPosition.clip == cssClip->parent()) { 783 if (context.fixedPosition.clip == cssClip->parent()) {
702 context.fixedPosition.clip = cssClip; 784 context.fixedPosition.clip = cssClip;
703 } else { 785 } else {
704 context.fixedPosition.clip = 786 if (object.needsPaintPropertyUpdate()) {
705 object.getMutableForPainting() 787 object.getMutableForPainting()
706 .ensurePaintProperties() 788 .ensurePaintProperties()
707 .updateCssClipFixedPosition( 789 .updateCssClipFixedPosition(context.fixedPosition.clip,
708 context.fixedPosition.clip, 790 const_cast<TransformPaintPropertyNode*>(
709 const_cast<TransformPaintPropertyNode*>( 791 cssClip->localTransformSpace()),
710 cssClip->localTransformSpace()), 792 cssClip->clipRect());
711 cssClip->clipRect()); 793 }
794 const auto* properties = object.paintProperties();
795 if (properties && properties->cssClipFixedPosition())
796 context.fixedPosition.clip = properties->cssClipFixedPosition();
712 return; 797 return;
713 } 798 }
714 } 799 }
715 800
716 if (auto* properties = object.getMutableForPainting().paintProperties()) 801 if (object.needsPaintPropertyUpdate()) {
717 properties->clearCssClipFixedPosition(); 802 if (auto* properties = object.getMutableForPainting().paintProperties())
803 properties->clearCssClipFixedPosition();
804 }
718 } 805 }
719 806
720 // Override ContainingBlockContext based on the properties of a containing block 807 // Override ContainingBlockContext based on the properties of a containing block
721 // that was previously walked in a subtree other than the current subtree being 808 // that was previously walked in a subtree other than the current subtree being
722 // walked. Used for out-of-flow positioned descendants of multi-column spanner 809 // walked. Used for out-of-flow positioned descendants of multi-column spanner
723 // when the containing block is not in the normal tree walk order. 810 // when the containing block is not in the normal tree walk order.
724 // For example: 811 // For example:
725 // <div id="columns" style="columns: 2"> 812 // <div id="columns" style="columns: 2">
726 // <div id="relative" style="position: relative"> 813 // <div id="relative" style="position: relative">
727 // <div id="spanner" style="column-span: all"> 814 // <div id="spanner" style="column-span: all">
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
832 // Similar adjustment is done in LayoutTableCell::offsetFromContainer(). 919 // Similar adjustment is done in LayoutTableCell::offsetFromContainer().
833 if (boxModelObject.isTableCell()) { 920 if (boxModelObject.isTableCell()) {
834 LayoutObject* parentRow = boxModelObject.parent(); 921 LayoutObject* parentRow = boxModelObject.parent();
835 ASSERT(parentRow && parentRow->isTableRow()); 922 ASSERT(parentRow && parentRow->isTableRow());
836 context.current.paintOffset.moveBy( 923 context.current.paintOffset.moveBy(
837 -toLayoutBox(parentRow)->topLeftLocation()); 924 -toLayoutBox(parentRow)->topLeftLocation());
838 } 925 }
839 } 926 }
840 } 927 }
841 928
842 void PaintPropertyTreeBuilder::buildTreeNodesForSelf( 929 void PaintPropertyTreeBuilder::updatePropertiesForSelf(
843 const LayoutObject& object, 930 const LayoutObject& object,
844 PaintPropertyTreeBuilderContext& context) { 931 PaintPropertyTreeBuilderContext& context) {
845 if (!object.isBoxModelObject() && !object.isSVG()) 932 if (!object.isBoxModelObject() && !object.isSVG())
846 return; 933 return;
847 934
935 #if DCHECK_IS_ON()
936 auto findObjectPropertiesNeedingUpdateScope =
937 FindObjectPropertiesNeedingUpdateScope::create(object);
938 #endif
939
848 deriveBorderBoxFromContainerContext(object, context); 940 deriveBorderBoxFromContainerContext(object, context);
849 941
850 updatePaintOffsetTranslation(object, context); 942 updatePaintOffsetTranslation(object, context);
851 updateTransform(object, context); 943 updateTransform(object, context);
852 updateEffect(object, context); 944 updateEffect(object, context);
853 updateCssClip(object, context); 945 updateCssClip(object, context);
854 updateLocalBorderBoxContext(object, context); 946 updateLocalBorderBoxContext(object, context);
855 updateScrollbarPaintOffset(object, context); 947 updateScrollbarPaintOffset(object, context);
856 updateMainThreadScrollingReasons(object, context); 948 updateMainThreadScrollingReasons(object, context);
857 } 949 }
858 950
859 void PaintPropertyTreeBuilder::buildTreeNodesForChildren( 951 void PaintPropertyTreeBuilder::updatePropertiesForChildren(
860 const LayoutObject& object, 952 const LayoutObject& object,
861 PaintPropertyTreeBuilderContext& context) { 953 PaintPropertyTreeBuilderContext& context) {
862 if (!object.isBoxModelObject() && !object.isSVG()) 954 if (!object.isBoxModelObject() && !object.isSVG())
863 return; 955 return;
864 956
957 #if DCHECK_IS_ON()
958 auto findObjectPropertiesNeedingUpdateScope =
959 FindObjectPropertiesNeedingUpdateScope::create(object);
960 #endif
961
865 updateOverflowClip(object, context); 962 updateOverflowClip(object, context);
866 updatePerspective(object, context); 963 updatePerspective(object, context);
867 updateSvgLocalToBorderBoxTransform(object, context); 964 updateSvgLocalToBorderBoxTransform(object, context);
868 updateScrollAndScrollTranslation(object, context); 965 updateScrollAndScrollTranslation(object, context);
869 updateOutOfFlowContext(object, context); 966 updateOutOfFlowContext(object, context);
870 } 967 }
871 968
872 } // namespace blink 969 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698