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

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

Issue 2515113002: WIP: Prune the prepaint tree walk (Closed)
Patch Set: Created 4 years 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"
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 bounds, userScrollableHorizontal, 91 bounds, userScrollableHorizontal,
92 userScrollableVertical, mainThreadScrollingReasons); 92 userScrollableVertical, mainThreadScrollingReasons);
93 } else { 93 } else {
94 frameView.setScroll(ScrollPaintPropertyNode::create( 94 frameView.setScroll(ScrollPaintPropertyNode::create(
95 std::move(parent), std::move(scrollOffset), clip, bounds, 95 std::move(parent), std::move(scrollOffset), clip, bounds,
96 userScrollableHorizontal, userScrollableVertical, 96 userScrollableHorizontal, userScrollableVertical,
97 mainThreadScrollingReasons)); 97 mainThreadScrollingReasons));
98 } 98 }
99 } 99 }
100 100
101 void PaintPropertyTreeBuilder::updateProperties( 101 TreeStructureChange PaintPropertyTreeBuilder::updateProperties(
102 FrameView& frameView, 102 FrameView& frameView,
103 PaintPropertyTreeBuilderContext& context) { 103 PaintPropertyTreeBuilderContext& context) {
104 if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) { 104 if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) {
105 // With root layer scrolling, the LayoutView (a LayoutObject) properties are 105 // With root layer scrolling, the LayoutView (a LayoutObject) properties are
106 // updated like other objects (see updatePropertiesAndContextForSelf and 106 // updated like other objects (see updatePropertiesAndContextForSelf and
107 // updatePropertiesAndContextForChildren) instead of needing LayoutView- 107 // updatePropertiesAndContextForChildren) instead of needing LayoutView-
108 // specific property updates here. 108 // specific property updates here.
109 context.current.paintOffset.moveBy(frameView.location()); 109 context.current.paintOffset.moveBy(frameView.location());
110 context.current.renderingContextID = 0; 110 context.current.renderingContextID = 0;
111 context.current.shouldFlattenInheritedTransform = true; 111 context.current.shouldFlattenInheritedTransform = true;
112 context.absolutePosition = context.current; 112 context.absolutePosition = context.current;
113 context.containerForAbsolutePosition = nullptr; 113 context.containerForAbsolutePosition = nullptr;
114 context.fixedPosition = context.current; 114 context.fixedPosition = context.current;
115 return; 115 return StructureNotChanged;
116 } 116 }
117 117
118 #if DCHECK_IS_ON() 118 #if DCHECK_IS_ON()
119 FindFrameViewPropertiesNeedingUpdateScope checkNeedsUpdateScope(&frameView); 119 FindFrameViewPropertiesNeedingUpdateScope checkNeedsUpdateScope(&frameView);
120 #endif 120 #endif
121 121
122 if (frameView.needsPaintPropertyUpdate()) { 122 if (frameView.needsPaintPropertyUpdate()) {
123 TransformationMatrix frameTranslate; 123 TransformationMatrix frameTranslate;
124 frameTranslate.translate(frameView.x() + context.current.paintOffset.x(), 124 frameTranslate.translate(frameView.x() + context.current.paintOffset.x(),
125 frameView.y() + context.current.paintOffset.y()); 125 frameView.y() + context.current.paintOffset.y());
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
184 context.absolutePosition = context.current; 184 context.absolutePosition = context.current;
185 context.containerForAbsolutePosition = nullptr; 185 context.containerForAbsolutePosition = nullptr;
186 context.fixedPosition = context.current; 186 context.fixedPosition = context.current;
187 context.fixedPosition.transform = fixedTransformNode; 187 context.fixedPosition.transform = fixedTransformNode;
188 context.fixedPosition.scroll = fixedScrollNode; 188 context.fixedPosition.scroll = fixedScrollNode;
189 189
190 std::unique_ptr<PropertyTreeState> contentsState( 190 std::unique_ptr<PropertyTreeState> contentsState(
191 new PropertyTreeState(context.current.transform, context.current.clip, 191 new PropertyTreeState(context.current.transform, context.current.clip,
192 context.currentEffect, context.current.scroll)); 192 context.currentEffect, context.current.scroll));
193 frameView.setTotalPropertyTreeStateForContents(std::move(contentsState)); 193 frameView.setTotalPropertyTreeStateForContents(std::move(contentsState));
194
195 // TODO(pdr): Do not return StructureChanged when the FrameView update does
196 // not actually cause a property tree node to be created/removed.
197 return frameView.needsPaintPropertyUpdate() ? StructureChanged
198 : StructureNotChanged;
194 } 199 }
195 200
196 void PaintPropertyTreeBuilder::updatePaintOffsetTranslation( 201 void PaintPropertyTreeBuilder::updatePaintOffsetTranslation(
197 const LayoutObject& object, 202 const LayoutObject& object,
198 PaintPropertyTreeBuilderContext& context) { 203 PaintPropertyTreeBuilderContext& context,
204 bool& treeStructureChanged) {
199 bool usesPaintOffsetTranslation = false; 205 bool usesPaintOffsetTranslation = false;
200 if (RuntimeEnabledFeatures::rootLayerScrollingEnabled() && 206 if (RuntimeEnabledFeatures::rootLayerScrollingEnabled() &&
201 object.isLayoutView()) { 207 object.isLayoutView()) {
202 // Root layer scrolling always creates a translation node for LayoutView to 208 // Root layer scrolling always creates a translation node for LayoutView to
203 // ensure fixed and absolute contexts use the correct transform space. 209 // ensure fixed and absolute contexts use the correct transform space.
204 usesPaintOffsetTranslation = true; 210 usesPaintOffsetTranslation = true;
205 } else if (object.isBoxModelObject() && 211 } else if (object.isBoxModelObject() &&
206 context.current.paintOffset != LayoutPoint()) { 212 context.current.paintOffset != LayoutPoint()) {
207 // TODO(trchen): Eliminate PaintLayer dependency. 213 // TODO(trchen): Eliminate PaintLayer dependency.
208 PaintLayer* layer = toLayoutBoxModelObject(object).layer(); 214 PaintLayer* layer = toLayoutBoxModelObject(object).layer();
209 if (layer && layer->paintsWithTransform(GlobalPaintNormalPhase)) 215 if (layer && layer->paintsWithTransform(GlobalPaintNormalPhase))
210 usesPaintOffsetTranslation = true; 216 usesPaintOffsetTranslation = true;
211 } 217 }
212 218
213 // We should use the same subpixel paint offset values for snapping 219 // We should use the same subpixel paint offset values for snapping
214 // regardless of whether a transform is present. If there is a transform 220 // regardless of whether a transform is present. If there is a transform
215 // we round the paint offset but keep around the residual fractional 221 // we round the paint offset but keep around the residual fractional
216 // component for the transformed content to paint with. In spv1 this was 222 // component for the transformed content to paint with. In spv1 this was
217 // called "subpixel accumulation". For more information, see 223 // called "subpixel accumulation". For more information, see
218 // PaintLayer::subpixelAccumulation() and 224 // PaintLayer::subpixelAccumulation() and
219 // PaintLayerPainter::paintFragmentByApplyingTransform. 225 // PaintLayerPainter::paintFragmentByApplyingTransform.
220 IntPoint roundedPaintOffset = roundedIntPoint(context.current.paintOffset); 226 IntPoint roundedPaintOffset = roundedIntPoint(context.current.paintOffset);
221 LayoutPoint fractionalPaintOffset = 227 LayoutPoint fractionalPaintOffset =
222 LayoutPoint(context.current.paintOffset - roundedPaintOffset); 228 LayoutPoint(context.current.paintOffset - roundedPaintOffset);
223 229
224 if (object.needsPaintPropertyUpdate()) { 230 if (object.needsPaintPropertyUpdate()) {
225 if (usesPaintOffsetTranslation) { 231 if (usesPaintOffsetTranslation) {
226 object.getMutableForPainting() 232 treeStructureChanged |=
227 .ensurePaintProperties() 233 object.getMutableForPainting()
228 .updatePaintOffsetTranslation( 234 .ensurePaintProperties()
229 context.current.transform, 235 .updatePaintOffsetTranslation(
230 TransformationMatrix().translate(roundedPaintOffset.x(), 236 context.current.transform,
231 roundedPaintOffset.y()), 237 TransformationMatrix().translate(roundedPaintOffset.x(),
232 FloatPoint3D(), context.current.shouldFlattenInheritedTransform, 238 roundedPaintOffset.y()),
233 context.current.renderingContextID); 239 FloatPoint3D(),
240 context.current.shouldFlattenInheritedTransform,
241 context.current.renderingContextID);
234 } else { 242 } else {
235 if (auto* properties = object.getMutableForPainting().paintProperties()) 243 if (auto* properties = object.getMutableForPainting().paintProperties())
236 properties->clearPaintOffsetTranslation(); 244 treeStructureChanged |= properties->clearPaintOffsetTranslation();
237 } 245 }
238 } 246 }
239 247
240 const auto* properties = object.paintProperties(); 248 const auto* properties = object.paintProperties();
241 if (properties && properties->paintOffsetTranslation()) { 249 if (properties && properties->paintOffsetTranslation()) {
242 context.current.transform = properties->paintOffsetTranslation(); 250 context.current.transform = properties->paintOffsetTranslation();
243 context.current.paintOffset = fractionalPaintOffset; 251 context.current.paintOffset = fractionalPaintOffset;
244 if (RuntimeEnabledFeatures::rootLayerScrollingEnabled() && 252 if (RuntimeEnabledFeatures::rootLayerScrollingEnabled() &&
245 object.isLayoutView()) { 253 object.isLayoutView()) {
246 context.absolutePosition.transform = properties->paintOffsetTranslation(); 254 context.absolutePosition.transform = properties->paintOffsetTranslation();
247 context.fixedPosition.transform = properties->paintOffsetTranslation(); 255 context.fixedPosition.transform = properties->paintOffsetTranslation();
248 context.absolutePosition.paintOffset = LayoutPoint(); 256 context.absolutePosition.paintOffset = LayoutPoint();
249 context.fixedPosition.paintOffset = LayoutPoint(); 257 context.fixedPosition.paintOffset = LayoutPoint();
250 } 258 }
251 } 259 }
252 } 260 }
253 261
254 static FloatPoint3D transformOrigin(const LayoutBox& box) { 262 static FloatPoint3D transformOrigin(const LayoutBox& box) {
255 const ComputedStyle& style = box.styleRef(); 263 const ComputedStyle& style = box.styleRef();
256 FloatSize borderBoxSize(box.size()); 264 FloatSize borderBoxSize(box.size());
257 return FloatPoint3D( 265 return FloatPoint3D(
258 floatValueForLength(style.transformOriginX(), borderBoxSize.width()), 266 floatValueForLength(style.transformOriginX(), borderBoxSize.width()),
259 floatValueForLength(style.transformOriginY(), borderBoxSize.height()), 267 floatValueForLength(style.transformOriginY(), borderBoxSize.height()),
260 style.transformOriginZ()); 268 style.transformOriginZ());
261 } 269 }
262 270
263 // SVG does not use the general transform update of |updateTransform|, instead 271 // SVG does not use the general transform update of |updateTransform|, instead
264 // creating a transform node for SVG-specific transforms without 3D. 272 // creating a transform node for SVG-specific transforms without 3D.
265 void PaintPropertyTreeBuilder::updateTransformForNonRootSVG( 273 TreeStructureChange PaintPropertyTreeBuilder::updateTransformForNonRootSVG(
266 const LayoutObject& object, 274 const LayoutObject& object,
267 PaintPropertyTreeBuilderContext& context) { 275 PaintPropertyTreeBuilderContext& context) {
268 DCHECK(object.isSVG() && !object.isSVGRoot()); 276 DCHECK(object.isSVG() && !object.isSVGRoot());
269 // SVG does not use paint offset internally. 277 // SVG does not use paint offset internally.
270 DCHECK(context.current.paintOffset == LayoutPoint()); 278 DCHECK(context.current.paintOffset == LayoutPoint());
271 279
280 bool treeStructureChanged = false;
272 if (object.needsPaintPropertyUpdate()) { 281 if (object.needsPaintPropertyUpdate()) {
273 const AffineTransform& transform = object.localToSVGParentTransform(); 282 const AffineTransform& transform = object.localToSVGParentTransform();
274 // TODO(pdr): Check for the presence of a transform instead of the value. 283 // TODO(pdr): Check for the presence of a transform instead of the value.
275 // Checking for an identity matrix will cause the property tree structure 284 // Checking for an identity matrix will cause the property tree structure
276 // to change during animations if the animation passes through the 285 // to change during animations if the animation passes through the
277 // identity matrix. 286 // identity matrix.
278 if (!transform.isIdentity()) { 287 if (!transform.isIdentity()) {
279 // The origin is included in the local transform, so leave origin empty. 288 // The origin is included in the local transform, so leave origin empty.
280 object.getMutableForPainting().ensurePaintProperties().updateTransform( 289 treeStructureChanged |=
281 context.current.transform, TransformationMatrix(transform), 290 object.getMutableForPainting()
282 FloatPoint3D()); 291 .ensurePaintProperties()
292 .updateTransform(context.current.transform,
293 TransformationMatrix(transform), FloatPoint3D());
283 } else { 294 } else {
284 if (auto* properties = object.getMutableForPainting().paintProperties()) 295 if (auto* properties = object.getMutableForPainting().paintProperties())
285 properties->clearTransform(); 296 treeStructureChanged |= properties->clearTransform();
286 } 297 }
287 } 298 }
288 299
289 if (object.paintProperties() && object.paintProperties()->transform()) { 300 if (object.paintProperties() && object.paintProperties()->transform()) {
290 context.current.transform = object.paintProperties()->transform(); 301 context.current.transform = object.paintProperties()->transform();
291 context.current.shouldFlattenInheritedTransform = false; 302 context.current.shouldFlattenInheritedTransform = false;
292 context.current.renderingContextID = 0; 303 context.current.renderingContextID = 0;
293 } 304 }
305 return static_cast<TreeStructureChange>(treeStructureChanged);
294 } 306 }
295 307
296 void PaintPropertyTreeBuilder::updateTransform( 308 TreeStructureChange PaintPropertyTreeBuilder::updateTransform(
297 const LayoutObject& object, 309 const LayoutObject& object,
298 PaintPropertyTreeBuilderContext& context) { 310 PaintPropertyTreeBuilderContext& context) {
299 if (object.isSVG() && !object.isSVGRoot()) { 311 if (object.isSVG() && !object.isSVGRoot())
300 updateTransformForNonRootSVG(object, context); 312 return updateTransformForNonRootSVG(object, context);
301 return;
302 }
303 313
314 bool treeStructureChanged = false;
304 if (object.needsPaintPropertyUpdate()) { 315 if (object.needsPaintPropertyUpdate()) {
305 const ComputedStyle& style = object.styleRef(); 316 const ComputedStyle& style = object.styleRef();
306 if (object.isBox() && (style.hasTransform() || style.preserves3D())) { 317 if (object.isBox() && (style.hasTransform() || style.preserves3D())) {
307 TransformationMatrix matrix; 318 TransformationMatrix matrix;
308 style.applyTransform( 319 style.applyTransform(
309 matrix, toLayoutBox(object).size(), 320 matrix, toLayoutBox(object).size(),
310 ComputedStyle::ExcludeTransformOrigin, 321 ComputedStyle::ExcludeTransformOrigin,
311 ComputedStyle::IncludeMotionPath, 322 ComputedStyle::IncludeMotionPath,
312 ComputedStyle::IncludeIndependentTransformProperties); 323 ComputedStyle::IncludeIndependentTransformProperties);
313 324
314 // TODO(trchen): transform-style should only be respected if a PaintLayer 325 // TODO(trchen): transform-style should only be respected if a PaintLayer
315 // is created. 326 // is created.
316 // If a node with transform-style: preserve-3d does not exist in an 327 // If a node with transform-style: preserve-3d does not exist in an
317 // existing rendering context, it establishes a new one. 328 // existing rendering context, it establishes a new one.
318 unsigned renderingContextID = context.current.renderingContextID; 329 unsigned renderingContextID = context.current.renderingContextID;
319 if (style.preserves3D() && !renderingContextID) 330 if (style.preserves3D() && !renderingContextID)
320 renderingContextID = PtrHash<const LayoutObject>::hash(&object); 331 renderingContextID = PtrHash<const LayoutObject>::hash(&object);
321 332
322 object.getMutableForPainting().ensurePaintProperties().updateTransform( 333 treeStructureChanged |=
323 context.current.transform, matrix, 334 object.getMutableForPainting()
324 transformOrigin(toLayoutBox(object)), 335 .ensurePaintProperties()
325 context.current.shouldFlattenInheritedTransform, renderingContextID); 336 .updateTransform(context.current.transform, matrix,
337 transformOrigin(toLayoutBox(object)),
338 context.current.shouldFlattenInheritedTransform,
339 renderingContextID);
326 } else { 340 } else {
327 if (auto* properties = object.getMutableForPainting().paintProperties()) 341 if (auto* properties = object.getMutableForPainting().paintProperties())
328 properties->clearTransform(); 342 treeStructureChanged |= properties->clearTransform();
329 } 343 }
330 } 344 }
331 345
332 const auto* properties = object.paintProperties(); 346 const auto* properties = object.paintProperties();
333 if (properties && properties->transform()) { 347 if (properties && properties->transform()) {
334 context.current.transform = properties->transform(); 348 context.current.transform = properties->transform();
335 if (object.styleRef().preserves3D()) { 349 if (object.styleRef().preserves3D()) {
336 context.current.renderingContextID = 350 context.current.renderingContextID =
337 properties->transform()->renderingContextID(); 351 properties->transform()->renderingContextID();
338 context.current.shouldFlattenInheritedTransform = false; 352 context.current.shouldFlattenInheritedTransform = false;
339 } else { 353 } else {
340 context.current.renderingContextID = 0; 354 context.current.renderingContextID = 0;
341 context.current.shouldFlattenInheritedTransform = true; 355 context.current.shouldFlattenInheritedTransform = true;
342 } 356 }
343 } 357 }
358 return static_cast<TreeStructureChange>(treeStructureChanged);
344 } 359 }
345 360
346 void PaintPropertyTreeBuilder::updateEffect( 361 TreeStructureChange PaintPropertyTreeBuilder::updateEffect(
347 const LayoutObject& object, 362 const LayoutObject& object,
348 PaintPropertyTreeBuilderContext& context) { 363 PaintPropertyTreeBuilderContext& context) {
364 bool treeStructureChanged = false;
349 const ComputedStyle& style = object.styleRef(); 365 const ComputedStyle& style = object.styleRef();
350
351 if (!style.isStackingContext()) { 366 if (!style.isStackingContext()) {
352 if (object.needsPaintPropertyUpdate()) { 367 if (object.needsPaintPropertyUpdate()) {
353 if (auto* properties = object.getMutableForPainting().paintProperties()) 368 if (auto* properties = object.getMutableForPainting().paintProperties())
354 properties->clearEffect(); 369 treeStructureChanged |= properties->clearEffect();
355 } 370 }
356 return; 371 return static_cast<TreeStructureChange>(treeStructureChanged);
357 } 372 }
358 373
359 // TODO(trchen): Can't omit effect node if we have 3D children. 374 // TODO(trchen): Can't omit effect node if we have 3D children.
360 // TODO(trchen): Can't omit effect node if we have blending children. 375 // TODO(trchen): Can't omit effect node if we have blending children.
361 if (object.needsPaintPropertyUpdate()) { 376 if (object.needsPaintPropertyUpdate()) {
362 bool effectNodeNeeded = false; 377 bool effectNodeNeeded = false;
363 378
364 float opacity = style.opacity(); 379 float opacity = style.opacity();
365 if (opacity != 1.0f) 380 if (opacity != 1.0f)
366 effectNodeNeeded = true; 381 effectNodeNeeded = true;
(...skipping 28 matching lines...) Expand all
395 if (!filter.isEmpty()) { 410 if (!filter.isEmpty()) {
396 effectNodeNeeded = true; 411 effectNodeNeeded = true;
397 outputClip = context.current.clip; 412 outputClip = context.current.clip;
398 413
399 // TODO(trchen): A filter may contain spatial operations such that an 414 // TODO(trchen): A filter may contain spatial operations such that an
400 // output pixel may depend on an input pixel outside of the output clip. 415 // output pixel may depend on an input pixel outside of the output clip.
401 // We should generate a special clip node to represent this expansion. 416 // We should generate a special clip node to represent this expansion.
402 } 417 }
403 418
404 if (effectNodeNeeded) { 419 if (effectNodeNeeded) {
405 object.getMutableForPainting().ensurePaintProperties().updateEffect( 420 treeStructureChanged |=
406 context.currentEffect, context.current.transform, outputClip, 421 object.getMutableForPainting().ensurePaintProperties().updateEffect(
407 std::move(filter), opacity); 422 context.currentEffect, context.current.transform, outputClip,
423 std::move(filter), opacity);
408 } else { 424 } else {
409 if (auto* properties = object.getMutableForPainting().paintProperties()) 425 if (auto* properties = object.getMutableForPainting().paintProperties())
410 properties->clearEffect(); 426 treeStructureChanged |= properties->clearEffect();
411 } 427 }
412 } 428 }
413 429
414 const auto* properties = object.paintProperties(); 430 const auto* properties = object.paintProperties();
415 if (properties && properties->effect()) { 431 if (properties && properties->effect()) {
416 context.currentEffect = properties->effect(); 432 context.currentEffect = properties->effect();
417 // TODO(pdr): Once the expansion clip node is created above, it should be 433 // TODO(pdr): Once the expansion clip node is created above, it should be
418 // used here to update all current clip nodes; 434 // used here to update all current clip nodes;
419 const ClipPaintPropertyNode* expansionHint = context.current.clip; 435 const ClipPaintPropertyNode* expansionHint = context.current.clip;
420 context.current.clip = context.absolutePosition.clip = 436 context.current.clip = context.absolutePosition.clip =
421 context.fixedPosition.clip = expansionHint; 437 context.fixedPosition.clip = expansionHint;
422 } 438 }
439 return static_cast<TreeStructureChange>(treeStructureChanged);
423 } 440 }
424 441
425 void PaintPropertyTreeBuilder::updateCssClip( 442 TreeStructureChange PaintPropertyTreeBuilder::updateCssClip(
426 const LayoutObject& object, 443 const LayoutObject& object,
427 PaintPropertyTreeBuilderContext& context) { 444 PaintPropertyTreeBuilderContext& context) {
445 bool treeStructureChanged = false;
428 if (object.needsPaintPropertyUpdate()) { 446 if (object.needsPaintPropertyUpdate()) {
429 if (object.hasClip()) { 447 if (object.hasClip()) {
430 // Create clip node for descendants that are not fixed position. 448 // Create clip node for descendants that are not fixed position.
431 // We don't have to setup context.absolutePosition.clip here because this 449 // We don't have to setup context.absolutePosition.clip here because this
432 // object must be a container for absolute position descendants, and will 450 // object must be a container for absolute position descendants, and will
433 // copy from in-flow context later at updateOutOfFlowContext() step. 451 // copy from in-flow context later at updateOutOfFlowContext() step.
434 DCHECK(object.canContainAbsolutePositionObjects()); 452 DCHECK(object.canContainAbsolutePositionObjects());
435 LayoutRect clipRect = 453 LayoutRect clipRect =
436 toLayoutBox(object).clipRect(context.current.paintOffset); 454 toLayoutBox(object).clipRect(context.current.paintOffset);
437 object.getMutableForPainting().ensurePaintProperties().updateCssClip( 455 treeStructureChanged |=
438 context.current.clip, context.current.transform, 456 object.getMutableForPainting().ensurePaintProperties().updateCssClip(
439 FloatRoundedRect(FloatRect(clipRect))); 457 context.current.clip, context.current.transform,
458 FloatRoundedRect(FloatRect(clipRect)));
440 } else { 459 } else {
441 if (auto* properties = object.getMutableForPainting().paintProperties()) 460 if (auto* properties = object.getMutableForPainting().paintProperties())
442 properties->clearCssClip(); 461 treeStructureChanged |= properties->clearCssClip();
443 } 462 }
444 } 463 }
445 464
446 const auto* properties = object.paintProperties(); 465 const auto* properties = object.paintProperties();
447 if (properties && properties->cssClip()) 466 if (properties && properties->cssClip())
448 context.current.clip = properties->cssClip(); 467 context.current.clip = properties->cssClip();
468 return static_cast<TreeStructureChange>(treeStructureChanged);
449 } 469 }
450 470
451 void PaintPropertyTreeBuilder::updateLocalBorderBoxContext( 471 TreeStructureChange PaintPropertyTreeBuilder::updateLocalBorderBoxContext(
452 const LayoutObject& object, 472 const LayoutObject& object,
453 PaintPropertyTreeBuilderContext& context) { 473 PaintPropertyTreeBuilderContext& context) {
454 if (!object.needsPaintPropertyUpdate()) 474 if (!object.needsPaintPropertyUpdate())
455 return; 475 return StructureNotChanged;
456 476
477 bool treeStructureChanged = false;
457 // Avoid adding an ObjectPaintProperties for non-boxes to save memory, since 478 // Avoid adding an ObjectPaintProperties for non-boxes to save memory, since
458 // we don't need them at the moment. 479 // we don't need them at the moment.
459 if (!object.isBox() && !object.hasLayer()) { 480 if (!object.isBox() && !object.hasLayer()) {
460 if (auto* properties = object.getMutableForPainting().paintProperties()) 481 if (auto* properties = object.getMutableForPainting().paintProperties())
461 properties->clearLocalBorderBoxProperties(); 482 treeStructureChanged |= properties->clearLocalBorderBoxProperties();
462 } else { 483 } else {
463 std::unique_ptr<ObjectPaintProperties::PropertyTreeStateWithOffset> 484 std::unique_ptr<ObjectPaintProperties::PropertyTreeStateWithOffset>
464 borderBoxContext = 485 borderBoxContext =
465 wrapUnique(new ObjectPaintProperties::PropertyTreeStateWithOffset( 486 wrapUnique(new ObjectPaintProperties::PropertyTreeStateWithOffset(
466 context.current.paintOffset, 487 context.current.paintOffset,
467 PropertyTreeState(context.current.transform, 488 PropertyTreeState(context.current.transform,
468 context.current.clip, context.currentEffect, 489 context.current.clip, context.currentEffect,
469 context.current.scroll))); 490 context.current.scroll)));
470 object.getMutableForPainting() 491 treeStructureChanged |=
471 .ensurePaintProperties() 492 object.getMutableForPainting()
472 .setLocalBorderBoxProperties(std::move(borderBoxContext)); 493 .ensurePaintProperties()
494 .setLocalBorderBoxProperties(std::move(borderBoxContext));
473 } 495 }
496 return static_cast<TreeStructureChange>(treeStructureChanged);
474 } 497 }
475 498
476 // TODO(trchen): Remove this once we bake the paint offset into frameRect. 499 // TODO(trchen): Remove this once we bake the paint offset into frameRect.
477 void PaintPropertyTreeBuilder::updateScrollbarPaintOffset( 500 TreeStructureChange PaintPropertyTreeBuilder::updateScrollbarPaintOffset(
478 const LayoutObject& object, 501 const LayoutObject& object,
479 const PaintPropertyTreeBuilderContext& context) { 502 const PaintPropertyTreeBuilderContext& context) {
480 if (!object.needsPaintPropertyUpdate()) 503 if (!object.needsPaintPropertyUpdate())
481 return; 504 return StructureNotChanged;
482 505
506 bool treeStructureChanged = false;
483 bool needsScrollbarPaintOffset = false; 507 bool needsScrollbarPaintOffset = false;
484 IntPoint roundedPaintOffset = roundedIntPoint(context.current.paintOffset); 508 IntPoint roundedPaintOffset = roundedIntPoint(context.current.paintOffset);
485 if (roundedPaintOffset != IntPoint() && object.isBoxModelObject()) { 509 if (roundedPaintOffset != IntPoint() && object.isBoxModelObject()) {
486 if (auto* area = toLayoutBoxModelObject(object).getScrollableArea()) { 510 if (auto* area = toLayoutBoxModelObject(object).getScrollableArea()) {
487 if (area->horizontalScrollbar() || area->verticalScrollbar()) { 511 if (area->horizontalScrollbar() || area->verticalScrollbar()) {
488 auto paintOffset = TransformationMatrix().translate( 512 auto paintOffset = TransformationMatrix().translate(
489 roundedPaintOffset.x(), roundedPaintOffset.y()); 513 roundedPaintOffset.x(), roundedPaintOffset.y());
490 object.getMutableForPainting() 514 treeStructureChanged |=
491 .ensurePaintProperties() 515 object.getMutableForPainting()
492 .updateScrollbarPaintOffset(context.current.transform, paintOffset, 516 .ensurePaintProperties()
493 FloatPoint3D()); 517 .updateScrollbarPaintOffset(context.current.transform,
518 paintOffset, FloatPoint3D());
494 needsScrollbarPaintOffset = true; 519 needsScrollbarPaintOffset = true;
495 } 520 }
496 } 521 }
497 } 522 }
498 523
499 auto* properties = object.getMutableForPainting().paintProperties(); 524 auto* properties = object.getMutableForPainting().paintProperties();
500 if (!needsScrollbarPaintOffset && properties) 525 if (!needsScrollbarPaintOffset && properties)
501 properties->clearScrollbarPaintOffset(); 526 treeStructureChanged |= properties->clearScrollbarPaintOffset();
527 return static_cast<TreeStructureChange>(treeStructureChanged);
502 } 528 }
503 529
504 void PaintPropertyTreeBuilder::updateOverflowClip( 530 TreeStructureChange PaintPropertyTreeBuilder::updateOverflowClip(
505 const LayoutObject& object, 531 const LayoutObject& object,
506 PaintPropertyTreeBuilderContext& context) { 532 PaintPropertyTreeBuilderContext& context) {
507 if (!object.isBox()) 533 if (!object.isBox())
508 return; 534 return StructureNotChanged;
509 535
536 bool treeStructureChanged = false;
510 if (object.needsPaintPropertyUpdate()) { 537 if (object.needsPaintPropertyUpdate()) {
511 const LayoutBox& box = toLayoutBox(object); 538 const LayoutBox& box = toLayoutBox(object);
512 // The <input> elements can't have contents thus CSS overflow property 539 // The <input> elements can't have contents thus CSS overflow property
513 // doesn't apply. However for layout purposes we do generate child layout 540 // doesn't apply. However for layout purposes we do generate child layout
514 // objects for them, e.g. button label. We should clip the overflow from 541 // objects for them, e.g. button label. We should clip the overflow from
515 // those children. This is called control clip and we technically treat them 542 // those children. This is called control clip and we technically treat them
516 // like overflow clip. 543 // like overflow clip.
517 LayoutRect clipRect; 544 LayoutRect clipRect;
518 if (box.hasControlClip()) { 545 if (box.hasControlClip()) {
519 clipRect = box.controlClipRect(context.current.paintOffset); 546 clipRect = box.controlClipRect(context.current.paintOffset);
520 } else if (box.hasOverflowClip() || box.styleRef().containsPaint() || 547 } else if (box.hasOverflowClip() || box.styleRef().containsPaint() ||
521 (box.isSVGRoot() && 548 (box.isSVGRoot() &&
522 toLayoutSVGRoot(box).shouldApplyViewportClip())) { 549 toLayoutSVGRoot(box).shouldApplyViewportClip())) {
523 clipRect = LayoutRect(pixelSnappedIntRect( 550 clipRect = LayoutRect(pixelSnappedIntRect(
524 box.overflowClipRect(context.current.paintOffset))); 551 box.overflowClipRect(context.current.paintOffset)));
525 } else { 552 } else {
526 if (auto* properties = object.getMutableForPainting().paintProperties()) { 553 if (auto* properties = object.getMutableForPainting().paintProperties()) {
527 properties->clearInnerBorderRadiusClip(); 554 treeStructureChanged |= properties->clearInnerBorderRadiusClip();
528 properties->clearOverflowClip(); 555 treeStructureChanged |= properties->clearOverflowClip();
529 } 556 }
530 return; 557 return static_cast<TreeStructureChange>(treeStructureChanged);
531 } 558 }
532 559
533 const auto* currentClip = context.current.clip; 560 const auto* currentClip = context.current.clip;
534 if (box.styleRef().hasBorderRadius()) { 561 if (box.styleRef().hasBorderRadius()) {
535 auto innerBorder = box.styleRef().getRoundedInnerBorderFor( 562 auto innerBorder = box.styleRef().getRoundedInnerBorderFor(
536 LayoutRect(context.current.paintOffset, box.size())); 563 LayoutRect(context.current.paintOffset, box.size()));
537 object.getMutableForPainting() 564 treeStructureChanged |=
538 .ensurePaintProperties() 565 object.getMutableForPainting()
539 .updateInnerBorderRadiusClip(context.current.clip, 566 .ensurePaintProperties()
540 context.current.transform, innerBorder); 567 .updateInnerBorderRadiusClip(
568 context.current.clip, context.current.transform, innerBorder);
541 currentClip = object.paintProperties()->innerBorderRadiusClip(); 569 currentClip = object.paintProperties()->innerBorderRadiusClip();
542 } else if (auto* properties = 570 } else if (auto* properties =
543 object.getMutableForPainting().paintProperties()) { 571 object.getMutableForPainting().paintProperties()) {
544 properties->clearInnerBorderRadiusClip(); 572 treeStructureChanged |= properties->clearInnerBorderRadiusClip();
545 } 573 }
546 574
547 object.getMutableForPainting().ensurePaintProperties().updateOverflowClip( 575 treeStructureChanged |=
548 currentClip, context.current.transform, 576 object.getMutableForPainting()
549 FloatRoundedRect(FloatRect(clipRect))); 577 .ensurePaintProperties()
578 .updateOverflowClip(currentClip, context.current.transform,
579 FloatRoundedRect(FloatRect(clipRect)));
550 } 580 }
551 581
552 const auto* properties = object.paintProperties(); 582 const auto* properties = object.paintProperties();
553 if (properties && properties->overflowClip()) 583 if (properties && properties->overflowClip())
554 context.current.clip = properties->overflowClip(); 584 context.current.clip = properties->overflowClip();
585 return static_cast<TreeStructureChange>(treeStructureChanged);
555 } 586 }
556 587
557 static FloatPoint perspectiveOrigin(const LayoutBox& box) { 588 static FloatPoint perspectiveOrigin(const LayoutBox& box) {
558 const ComputedStyle& style = box.styleRef(); 589 const ComputedStyle& style = box.styleRef();
559 FloatSize borderBoxSize(box.size()); 590 FloatSize borderBoxSize(box.size());
560 return FloatPoint( 591 return FloatPoint(
561 floatValueForLength(style.perspectiveOriginX(), borderBoxSize.width()), 592 floatValueForLength(style.perspectiveOriginX(), borderBoxSize.width()),
562 floatValueForLength(style.perspectiveOriginY(), borderBoxSize.height())); 593 floatValueForLength(style.perspectiveOriginY(), borderBoxSize.height()));
563 } 594 }
564 595
565 void PaintPropertyTreeBuilder::updatePerspective( 596 TreeStructureChange PaintPropertyTreeBuilder::updatePerspective(
566 const LayoutObject& object, 597 const LayoutObject& object,
567 PaintPropertyTreeBuilderContext& context) { 598 PaintPropertyTreeBuilderContext& context) {
599 bool treeStructureChanged = false;
568 if (object.needsPaintPropertyUpdate()) { 600 if (object.needsPaintPropertyUpdate()) {
569 const ComputedStyle& style = object.styleRef(); 601 const ComputedStyle& style = object.styleRef();
570 if (object.isBox() && style.hasPerspective()) { 602 if (object.isBox() && style.hasPerspective()) {
571 // The perspective node must not flatten (else nothing will get 603 // The perspective node must not flatten (else nothing will get
572 // perspective), but it should still extend the rendering context as 604 // perspective), but it should still extend the rendering context as
573 // most transform nodes do. 605 // most transform nodes do.
574 TransformationMatrix matrix = 606 TransformationMatrix matrix =
575 TransformationMatrix().applyPerspective(style.perspective()); 607 TransformationMatrix().applyPerspective(style.perspective());
576 FloatPoint3D origin = perspectiveOrigin(toLayoutBox(object)) + 608 FloatPoint3D origin = perspectiveOrigin(toLayoutBox(object)) +
577 toLayoutSize(context.current.paintOffset); 609 toLayoutSize(context.current.paintOffset);
578 object.getMutableForPainting().ensurePaintProperties().updatePerspective( 610 treeStructureChanged |=
579 context.current.transform, matrix, origin, 611 object.getMutableForPainting()
580 context.current.shouldFlattenInheritedTransform, 612 .ensurePaintProperties()
581 context.current.renderingContextID); 613 .updatePerspective(
614 context.current.transform, matrix, origin,
615 context.current.shouldFlattenInheritedTransform,
616 context.current.renderingContextID);
582 } else { 617 } else {
583 if (auto* properties = object.getMutableForPainting().paintProperties()) 618 if (auto* properties = object.getMutableForPainting().paintProperties())
584 properties->clearPerspective(); 619 treeStructureChanged |= properties->clearPerspective();
585 } 620 }
586 } 621 }
587 622
588 const auto* properties = object.paintProperties(); 623 const auto* properties = object.paintProperties();
589 if (properties && properties->perspective()) { 624 if (properties && properties->perspective()) {
590 context.current.transform = properties->perspective(); 625 context.current.transform = properties->perspective();
591 context.current.shouldFlattenInheritedTransform = false; 626 context.current.shouldFlattenInheritedTransform = false;
592 } 627 }
628 return static_cast<TreeStructureChange>(treeStructureChanged);
593 } 629 }
594 630
595 void PaintPropertyTreeBuilder::updateSvgLocalToBorderBoxTransform( 631 TreeStructureChange
632 PaintPropertyTreeBuilder::updateSvgLocalToBorderBoxTransform(
596 const LayoutObject& object, 633 const LayoutObject& object,
597 PaintPropertyTreeBuilderContext& context) { 634 PaintPropertyTreeBuilderContext& context) {
598 if (!object.isSVGRoot()) 635 if (!object.isSVGRoot())
599 return; 636 return StructureNotChanged;
600 637
638 bool treeStructureChanged = false;
601 if (object.needsPaintPropertyUpdate()) { 639 if (object.needsPaintPropertyUpdate()) {
602 AffineTransform transformToBorderBox = 640 AffineTransform transformToBorderBox =
603 SVGRootPainter(toLayoutSVGRoot(object)) 641 SVGRootPainter(toLayoutSVGRoot(object))
604 .transformToPixelSnappedBorderBox(context.current.paintOffset); 642 .transformToPixelSnappedBorderBox(context.current.paintOffset);
605 if (!transformToBorderBox.isIdentity()) { 643 if (!transformToBorderBox.isIdentity()) {
606 object.getMutableForPainting() 644 treeStructureChanged |= object.getMutableForPainting()
607 .ensurePaintProperties() 645 .ensurePaintProperties()
608 .updateSvgLocalToBorderBoxTransform( 646 .updateSvgLocalToBorderBoxTransform(
609 context.current.transform, transformToBorderBox, FloatPoint3D()); 647 context.current.transform,
648 transformToBorderBox, FloatPoint3D());
610 } else { 649 } else {
611 if (auto* properties = object.getMutableForPainting().paintProperties()) 650 if (auto* properties = object.getMutableForPainting().paintProperties())
612 properties->clearSvgLocalToBorderBoxTransform(); 651 treeStructureChanged |= properties->clearSvgLocalToBorderBoxTransform();
613 } 652 }
614 } 653 }
615 654
616 const auto* properties = object.paintProperties(); 655 const auto* properties = object.paintProperties();
617 if (properties && properties->svgLocalToBorderBoxTransform()) { 656 if (properties && properties->svgLocalToBorderBoxTransform()) {
618 context.current.transform = properties->svgLocalToBorderBoxTransform(); 657 context.current.transform = properties->svgLocalToBorderBoxTransform();
619 context.current.shouldFlattenInheritedTransform = false; 658 context.current.shouldFlattenInheritedTransform = false;
620 context.current.renderingContextID = 0; 659 context.current.renderingContextID = 0;
621 } 660 }
622 // The paint offset is included in |transformToBorderBox| so SVG does not need 661 // The paint offset is included in |transformToBorderBox| so SVG does not need
623 // to handle paint offset internally. 662 // to handle paint offset internally.
624 context.current.paintOffset = LayoutPoint(); 663 context.current.paintOffset = LayoutPoint();
664
665 return static_cast<TreeStructureChange>(treeStructureChanged);
625 } 666 }
626 667
627 void PaintPropertyTreeBuilder::updateScrollAndScrollTranslation( 668 TreeStructureChange PaintPropertyTreeBuilder::updateScrollAndScrollTranslation(
628 const LayoutObject& object, 669 const LayoutObject& object,
629 PaintPropertyTreeBuilderContext& context) { 670 PaintPropertyTreeBuilderContext& context) {
671 bool treeStructureChanged = false;
630 if (object.needsPaintPropertyUpdate()) { 672 if (object.needsPaintPropertyUpdate()) {
631 if (object.hasOverflowClip()) { 673 if (object.hasOverflowClip()) {
632 const LayoutBox& box = toLayoutBox(object); 674 const LayoutBox& box = toLayoutBox(object);
633 const PaintLayerScrollableArea* scrollableArea = box.getScrollableArea(); 675 const PaintLayerScrollableArea* scrollableArea = box.getScrollableArea();
634 IntSize scrollOffset = box.scrolledContentOffset(); 676 IntSize scrollOffset = box.scrolledContentOffset();
635 if (!scrollOffset.isZero() || scrollableArea->scrollsOverflow()) { 677 if (!scrollOffset.isZero() || scrollableArea->scrollsOverflow()) {
636 TransformationMatrix matrix = TransformationMatrix().translate( 678 TransformationMatrix matrix = TransformationMatrix().translate(
637 -scrollOffset.width(), -scrollOffset.height()); 679 -scrollOffset.width(), -scrollOffset.height());
638 object.getMutableForPainting() 680 treeStructureChanged |=
639 .ensurePaintProperties() 681 object.getMutableForPainting()
640 .updateScrollTranslation( 682 .ensurePaintProperties()
641 context.current.transform, matrix, FloatPoint3D(), 683 .updateScrollTranslation(
642 context.current.shouldFlattenInheritedTransform, 684 context.current.transform, matrix, FloatPoint3D(),
643 context.current.renderingContextID); 685 context.current.shouldFlattenInheritedTransform,
686 context.current.renderingContextID);
644 687
645 IntSize scrollClip = scrollableArea->visibleContentRect().size(); 688 IntSize scrollClip = scrollableArea->visibleContentRect().size();
646 IntSize scrollBounds = scrollableArea->contentsSize(); 689 IntSize scrollBounds = scrollableArea->contentsSize();
647 bool userScrollableHorizontal = 690 bool userScrollableHorizontal =
648 scrollableArea->userInputScrollable(HorizontalScrollbar); 691 scrollableArea->userInputScrollable(HorizontalScrollbar);
649 bool userScrollableVertical = 692 bool userScrollableVertical =
650 scrollableArea->userInputScrollable(VerticalScrollbar); 693 scrollableArea->userInputScrollable(VerticalScrollbar);
651 MainThreadScrollingReasons reasons = 0; 694 MainThreadScrollingReasons reasons = 0;
652 if (!object.document().settings()->threadedScrollingEnabled()) 695 if (!object.document().settings()->threadedScrollingEnabled())
653 reasons |= MainThreadScrollingReason::kThreadedScrollingDisabled; 696 reasons |= MainThreadScrollingReason::kThreadedScrollingDisabled;
654 // Checking for descendants in the layout tree has two downsides: 697 // Checking for descendants in the layout tree has two downsides:
655 // 1) There can be more descendants in layout order than in paint 698 // 1) There can be more descendants in layout order than in paint
656 // order (e.g., fixed position objects). 699 // order (e.g., fixed position objects).
657 // 2) Iterating overall all background attachment fixed objects for 700 // 2) Iterating overall all background attachment fixed objects for
658 // every scroll node can be slow, though there will be no objects 701 // every scroll node can be slow, though there will be no objects
659 // in the common case. 702 // in the common case.
660 const FrameView& frameView = *object.frameView(); 703 const FrameView& frameView = *object.frameView();
661 if (frameView.hasBackgroundAttachmentFixedDescendants(object)) { 704 if (frameView.hasBackgroundAttachmentFixedDescendants(object)) {
662 reasons |= 705 reasons |=
663 MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects; 706 MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects;
664 } 707 }
665 object.getMutableForPainting().ensurePaintProperties().updateScroll( 708 treeStructureChanged |=
666 context.current.scroll, 709 object.getMutableForPainting().ensurePaintProperties().updateScroll(
667 object.paintProperties()->scrollTranslation(), scrollClip, 710 context.current.scroll,
668 scrollBounds, userScrollableHorizontal, userScrollableVertical, 711 object.paintProperties()->scrollTranslation(), scrollClip,
669 reasons); 712 scrollBounds, userScrollableHorizontal, userScrollableVertical,
713 reasons);
670 } else { 714 } else {
671 // Ensure pre-existing properties are cleared when there is no 715 // Ensure pre-existing properties are cleared when there is no
672 // scrolling. 716 // scrolling.
673 auto* properties = object.getMutableForPainting().paintProperties(); 717 auto* properties = object.getMutableForPainting().paintProperties();
674 if (properties) { 718 if (properties) {
675 properties->clearScrollTranslation(); 719 treeStructureChanged |= properties->clearScrollTranslation();
676 properties->clearScroll(); 720 treeStructureChanged |= properties->clearScroll();
677 } 721 }
678 } 722 }
679 } 723 }
680 } 724 }
681 725
682 if (object.paintProperties() && object.paintProperties()->scroll()) { 726 if (object.paintProperties() && object.paintProperties()->scroll()) {
683 context.current.transform = object.paintProperties()->scrollTranslation(); 727 context.current.transform = object.paintProperties()->scrollTranslation();
684 context.current.scroll = object.paintProperties()->scroll(); 728 context.current.scroll = object.paintProperties()->scroll();
685 context.current.shouldFlattenInheritedTransform = false; 729 context.current.shouldFlattenInheritedTransform = false;
686 } 730 }
731 return static_cast<TreeStructureChange>(treeStructureChanged);
687 } 732 }
688 733
689 void PaintPropertyTreeBuilder::updateOutOfFlowContext( 734 TreeStructureChange PaintPropertyTreeBuilder::updateOutOfFlowContext(
690 const LayoutObject& object, 735 const LayoutObject& object,
691 PaintPropertyTreeBuilderContext& context) { 736 PaintPropertyTreeBuilderContext& context) {
692 if (object.canContainAbsolutePositionObjects()) { 737 if (object.canContainAbsolutePositionObjects()) {
693 context.absolutePosition = context.current; 738 context.absolutePosition = context.current;
694 context.containerForAbsolutePosition = &object; 739 context.containerForAbsolutePosition = &object;
695 } 740 }
696 741
742 bool treeStructureChanged = false;
697 if (object.isLayoutView()) { 743 if (object.isLayoutView()) {
698 if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) { 744 if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) {
699 const auto* initialFixedTransform = context.fixedPosition.transform; 745 const auto* initialFixedTransform = context.fixedPosition.transform;
700 const auto* initialFixedScroll = context.fixedPosition.scroll; 746 const auto* initialFixedScroll = context.fixedPosition.scroll;
701 747
702 context.fixedPosition = context.current; 748 context.fixedPosition = context.current;
703 749
704 // Fixed position transform and scroll nodes should not be affected. 750 // Fixed position transform and scroll nodes should not be affected.
705 context.fixedPosition.transform = initialFixedTransform; 751 context.fixedPosition.transform = initialFixedTransform;
706 context.fixedPosition.scroll = initialFixedScroll; 752 context.fixedPosition.scroll = initialFixedScroll;
707 } 753 }
708 } else if (object.canContainFixedPositionObjects()) { 754 } else if (object.canContainFixedPositionObjects()) {
709 context.fixedPosition = context.current; 755 context.fixedPosition = context.current;
710 } else if (object.getMutableForPainting().paintProperties() && 756 } else if (object.getMutableForPainting().paintProperties() &&
711 object.paintProperties()->cssClip()) { 757 object.paintProperties()->cssClip()) {
712 // CSS clip applies to all descendants, even if this object is not a 758 // CSS clip applies to all descendants, even if this object is not a
713 // containing block ancestor of the descendant. It is okay for 759 // containing block ancestor of the descendant. It is okay for
714 // absolute-position descendants because having CSS clip implies being 760 // absolute-position descendants because having CSS clip implies being
715 // absolute position container. However for fixed-position descendants we 761 // absolute position container. However for fixed-position descendants we
716 // need to insert the clip here if we are not a containing block ancestor of 762 // need to insert the clip here if we are not a containing block ancestor of
717 // them. 763 // them.
718 auto* cssClip = object.getMutableForPainting().paintProperties()->cssClip(); 764 auto* cssClip = object.getMutableForPainting().paintProperties()->cssClip();
719 765
720 // Before we actually create anything, check whether in-flow context and 766 // Before we actually create anything, check whether in-flow context and
721 // fixed-position context has exactly the same clip. Reuse if possible. 767 // fixed-position context has exactly the same clip. Reuse if possible.
722 if (context.fixedPosition.clip == cssClip->parent()) { 768 if (context.fixedPosition.clip == cssClip->parent()) {
723 context.fixedPosition.clip = cssClip; 769 context.fixedPosition.clip = cssClip;
724 } else { 770 } else {
725 if (object.needsPaintPropertyUpdate()) { 771 if (object.needsPaintPropertyUpdate()) {
726 object.getMutableForPainting() 772 treeStructureChanged |= object.getMutableForPainting()
727 .ensurePaintProperties() 773 .ensurePaintProperties()
728 .updateCssClipFixedPosition(context.fixedPosition.clip, 774 .updateCssClipFixedPosition(
775 context.fixedPosition.clip,
729 const_cast<TransformPaintPropertyNode*>( 776 const_cast<TransformPaintPropertyNode*>(
730 cssClip->localTransformSpace()), 777 cssClip->localTransformSpace()),
731 cssClip->clipRect()); 778 cssClip->clipRect());
732 } 779 }
733 const auto* properties = object.paintProperties(); 780 const auto* properties = object.paintProperties();
734 if (properties && properties->cssClipFixedPosition()) 781 if (properties && properties->cssClipFixedPosition())
735 context.fixedPosition.clip = properties->cssClipFixedPosition(); 782 context.fixedPosition.clip = properties->cssClipFixedPosition();
736 return; 783 return static_cast<TreeStructureChange>(treeStructureChanged);
737 } 784 }
738 } 785 }
739 786
740 if (object.needsPaintPropertyUpdate()) { 787 if (object.needsPaintPropertyUpdate()) {
741 if (auto* properties = object.getMutableForPainting().paintProperties()) 788 if (auto* properties = object.getMutableForPainting().paintProperties())
742 properties->clearCssClipFixedPosition(); 789 treeStructureChanged |= properties->clearCssClipFixedPosition();
743 } 790 }
791 return static_cast<TreeStructureChange>(treeStructureChanged);
744 } 792 }
745 793
746 // Override ContainingBlockContext based on the properties of a containing block 794 // Override ContainingBlockContext based on the properties of a containing block
747 // that was previously walked in a subtree other than the current subtree being 795 // that was previously walked in a subtree other than the current subtree being
748 // walked. Used for out-of-flow positioned descendants of multi-column spanner 796 // walked. Used for out-of-flow positioned descendants of multi-column spanner
749 // when the containing block is not in the normal tree walk order. 797 // when the containing block is not in the normal tree walk order.
750 // For example: 798 // For example:
751 // <div id="columns" style="columns: 2"> 799 // <div id="columns" style="columns: 2">
752 // <div id="relative" style="position: relative"> 800 // <div id="relative" style="position: relative">
753 // <div id="spanner" style="column-span: all"> 801 // <div id="spanner" style="column-span: all">
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
853 // Similar adjustment is done in LayoutTableCell::offsetFromContainer(). 901 // Similar adjustment is done in LayoutTableCell::offsetFromContainer().
854 if (boxModelObject.isTableCell()) { 902 if (boxModelObject.isTableCell()) {
855 LayoutObject* parentRow = boxModelObject.parent(); 903 LayoutObject* parentRow = boxModelObject.parent();
856 DCHECK(parentRow && parentRow->isTableRow()); 904 DCHECK(parentRow && parentRow->isTableRow());
857 context.current.paintOffset.moveBy( 905 context.current.paintOffset.moveBy(
858 -toLayoutBox(parentRow)->topLeftLocation()); 906 -toLayoutBox(parentRow)->topLeftLocation());
859 } 907 }
860 } 908 }
861 } 909 }
862 910
863 void PaintPropertyTreeBuilder::updatePropertiesForSelf( 911 TreeStructureChange PaintPropertyTreeBuilder::updatePropertiesForSelf(
864 const LayoutObject& object, 912 const LayoutObject& object,
865 PaintPropertyTreeBuilderContext& context) { 913 PaintPropertyTreeBuilderContext& context) {
866 if (!object.isBoxModelObject() && !object.isSVG()) 914 if (!object.isBoxModelObject() && !object.isSVG())
867 return; 915 return StructureNotChanged;
868 916
869 #if DCHECK_IS_ON() 917 #if DCHECK_IS_ON()
870 FindObjectPropertiesNeedingUpdateScope checkNeedsUpdateScope(object); 918 FindObjectPropertiesNeedingUpdateScope checkNeedsUpdateScope(object);
871 #endif 919 #endif
872 920
873 deriveBorderBoxFromContainerContext(object, context); 921 deriveBorderBoxFromContainerContext(object, context);
874 922
875 updatePaintOffsetTranslation(object, context); 923 bool treeStructureChanged = false;
876 updateTransform(object, context); 924 updatePaintOffsetTranslation(object, context, treeStructureChanged);
877 updateEffect(object, context); 925 treeStructureChanged |= updateTransform(object, context);
878 updateCssClip(object, context); 926 treeStructureChanged |= updateEffect(object, context);
879 updateLocalBorderBoxContext(object, context); 927 treeStructureChanged |= updateCssClip(object, context);
880 updateScrollbarPaintOffset(object, context); 928 treeStructureChanged |= updateLocalBorderBoxContext(object, context);
929 treeStructureChanged |= updateScrollbarPaintOffset(object, context);
930 return static_cast<TreeStructureChange>(treeStructureChanged);
881 } 931 }
882 932
883 void PaintPropertyTreeBuilder::updatePropertiesForChildren( 933 TreeStructureChange PaintPropertyTreeBuilder::updatePropertiesForChildren(
884 const LayoutObject& object, 934 const LayoutObject& object,
885 PaintPropertyTreeBuilderContext& context) { 935 PaintPropertyTreeBuilderContext& context) {
886 if (!object.isBoxModelObject() && !object.isSVG()) 936 if (!object.isBoxModelObject() && !object.isSVG())
887 return; 937 return StructureNotChanged;
888 938
889 #if DCHECK_IS_ON() 939 #if DCHECK_IS_ON()
890 FindObjectPropertiesNeedingUpdateScope checkNeedsUpdateScope(object); 940 FindObjectPropertiesNeedingUpdateScope checkNeedsUpdateScope(object);
891 #endif 941 #endif
892 942
893 updateOverflowClip(object, context); 943 bool treeStructureChanged = false;
894 updatePerspective(object, context); 944 treeStructureChanged |= updateOverflowClip(object, context);
895 updateSvgLocalToBorderBoxTransform(object, context); 945 treeStructureChanged |= updatePerspective(object, context);
896 updateScrollAndScrollTranslation(object, context); 946 treeStructureChanged |= updateSvgLocalToBorderBoxTransform(object, context);
897 updateOutOfFlowContext(object, context); 947 treeStructureChanged |= updateScrollAndScrollTranslation(object, context);
948 treeStructureChanged |= updateOutOfFlowContext(object, context);
949 return static_cast<TreeStructureChange>(treeStructureChanged);
898 } 950 }
899 951
900 } // namespace blink 952 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698