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

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

Issue 2831683003: Refactor to centralize code which decides whether ObjectPaintProperties are needed. (Closed)
Patch Set: none Created 3 years, 7 months 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 <memory> 7 #include <memory>
8 #include "core/dom/DOMNodeIds.h" 8 #include "core/dom/DOMNodeIds.h"
9 #include "core/frame/FrameView.h" 9 #include "core/frame/FrameView.h"
10 #include "core/frame/LocalFrame.h" 10 #include "core/frame/LocalFrame.h"
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after
217 context.container_for_absolute_position = nullptr; 217 context.container_for_absolute_position = nullptr;
218 context.fixed_position = context.current; 218 context.fixed_position = context.current;
219 context.fixed_position.transform = fixed_transform_node; 219 context.fixed_position.transform = fixed_transform_node;
220 context.fixed_position.scroll = fixed_scroll_node; 220 context.fixed_position.scroll = fixed_scroll_node;
221 221
222 std::unique_ptr<PropertyTreeState> contents_state(new PropertyTreeState( 222 std::unique_ptr<PropertyTreeState> contents_state(new PropertyTreeState(
223 context.current.transform, context.current.clip, context.current_effect)); 223 context.current.transform, context.current.clip, context.current_effect));
224 frame_view.SetTotalPropertyTreeStateForContents(std::move(contents_state)); 224 frame_view.SetTotalPropertyTreeStateForContents(std::move(contents_state));
225 } 225 }
226 226
227 static bool NeedsPaintOffsetTranslation(const LayoutObject& object) {
228 if (!object.IsBoxModelObject())
229 return false;
230 const LayoutBoxModelObject& box_model = ToLayoutBoxModelObject(object);
231 if (RuntimeEnabledFeatures::rootLayerScrollingEnabled() &&
232 box_model.IsLayoutView()) {
233 // Root layer scrolling always creates a translation node for LayoutView to
234 // ensure fixed and absolute contexts use the correct transform space.
235 return true;
236 } else if (box_model.HasLayer() &&
237 box_model.Layer()->PaintsWithTransform(
238 kGlobalPaintFlattenCompositingLayers)) {
239 return true;
240 }
241 return false;
242 }
243
227 void PaintPropertyTreeBuilder::UpdatePaintOffsetTranslation( 244 void PaintPropertyTreeBuilder::UpdatePaintOffsetTranslation(
228 const LayoutBoxModelObject& object, 245 const LayoutBoxModelObject& object,
229 PaintPropertyTreeBuilderContext& context) { 246 PaintPropertyTreeBuilderContext& context) {
230 bool uses_paint_offset_translation = false; 247 if (NeedsPaintOffsetTranslation(object) &&
231 if (RuntimeEnabledFeatures::rootLayerScrollingEnabled() && 248 // As an optimization, skip these paint offset translation nodes when
232 object.IsLayoutView()) { 249 // the offset is an identity. An exception is the layout view because root
233 // Root layer scrolling always creates a translation node for LayoutView to 250 // layer scrolling needs a transform node to ensure fixed and absolute
234 // ensure fixed and absolute contexts use the correct transform space. 251 // descendants use the correct transform space.
235 uses_paint_offset_translation = true; 252 (object.IsLayoutView() ||
236 } else if (object.HasLayer() && 253 context.current.paint_offset != LayoutPoint())) {
237 context.current.paint_offset != LayoutPoint() && 254 auto& properties = *object.GetMutableForPainting().PaintProperties();
238 object.Layer()->PaintsWithTransform( 255 // We should use the same subpixel paint offset values for snapping
239 kGlobalPaintFlattenCompositingLayers)) { 256 // regardless of whether a transform is present. If there is a transform
240 uses_paint_offset_translation = true; 257 // we round the paint offset but keep around the residual fractional
241 } 258 // component for the transformed content to paint with. In spv1 this was
259 // called "subpixel accumulation". For more information, see
260 // PaintLayer::subpixelAccumulation() and
261 // PaintLayerPainter::paintFragmentByApplyingTransform.
262 IntPoint rounded_paint_offset =
263 RoundedIntPoint(context.current.paint_offset);
264 LayoutPoint fractional_paint_offset =
265 LayoutPoint(context.current.paint_offset - rounded_paint_offset);
242 266
243 if (!uses_paint_offset_translation) { 267 context.force_subtree_update |= properties.UpdatePaintOffsetTranslation(
268 context.current.transform,
269 TransformationMatrix().Translate(rounded_paint_offset.X(),
270 rounded_paint_offset.Y()),
271 FloatPoint3D(), context.current.should_flatten_inherited_transform,
272 context.current.rendering_context_id);
273
274 context.current.transform = properties.PaintOffsetTranslation();
275 context.current.paint_offset = fractional_paint_offset;
276 if (RuntimeEnabledFeatures::rootLayerScrollingEnabled() &&
277 object.IsLayoutView()) {
278 context.absolute_position.transform = properties.PaintOffsetTranslation();
279 context.fixed_position.transform = properties.PaintOffsetTranslation();
280 context.absolute_position.paint_offset = LayoutPoint();
281 context.fixed_position.paint_offset = LayoutPoint();
282 }
283 } else {
244 if (auto* properties = object.GetMutableForPainting().PaintProperties()) 284 if (auto* properties = object.GetMutableForPainting().PaintProperties())
245 context.force_subtree_update |= properties->ClearPaintOffsetTranslation(); 285 context.force_subtree_update |= properties->ClearPaintOffsetTranslation();
246 return;
247 }
248
249 // We should use the same subpixel paint offset values for snapping
250 // regardless of whether a transform is present. If there is a transform
251 // we round the paint offset but keep around the residual fractional
252 // component for the transformed content to paint with. In spv1 this was
253 // called "subpixel accumulation". For more information, see
254 // PaintLayer::subpixelAccumulation() and
255 // PaintLayerPainter::paintFragmentByApplyingTransform.
256 IntPoint rounded_paint_offset = RoundedIntPoint(context.current.paint_offset);
257 LayoutPoint fractional_paint_offset =
258 LayoutPoint(context.current.paint_offset - rounded_paint_offset);
259
260 auto& properties = object.GetMutableForPainting().EnsurePaintProperties();
261 context.force_subtree_update |= properties.UpdatePaintOffsetTranslation(
262 context.current.transform,
263 TransformationMatrix().Translate(rounded_paint_offset.X(),
264 rounded_paint_offset.Y()),
265 FloatPoint3D(), context.current.should_flatten_inherited_transform,
266 context.current.rendering_context_id);
267
268 context.current.transform = properties.PaintOffsetTranslation();
269 context.current.paint_offset = fractional_paint_offset;
270 if (RuntimeEnabledFeatures::rootLayerScrollingEnabled() &&
271 object.IsLayoutView()) {
272 context.absolute_position.transform = properties.PaintOffsetTranslation();
273 context.fixed_position.transform = properties.PaintOffsetTranslation();
274 context.absolute_position.paint_offset = LayoutPoint();
275 context.fixed_position.paint_offset = LayoutPoint();
276 } 286 }
277 } 287 }
278 288
289 static bool NeedsTransformForNonRootSVG(const LayoutObject& object) {
290 // TODO(pdr): Check for the presence of a transform instead of the value.
291 // Checking for an identity matrix will cause the property tree structure
292 // to change during animations if the animation passes through the
293 // identity matrix.
294 return object.IsSVGChild() &&
295 !object.LocalToSVGParentTransform().IsIdentity();
296 }
297
279 // SVG does not use the general transform update of |updateTransform|, instead 298 // SVG does not use the general transform update of |updateTransform|, instead
280 // creating a transform node for SVG-specific transforms without 3D. 299 // creating a transform node for SVG-specific transforms without 3D.
281 void PaintPropertyTreeBuilder::UpdateTransformForNonRootSVG( 300 void PaintPropertyTreeBuilder::UpdateTransformForNonRootSVG(
282 const LayoutObject& object, 301 const LayoutObject& object,
283 PaintPropertyTreeBuilderContext& context) { 302 PaintPropertyTreeBuilderContext& context) {
284 DCHECK(object.IsSVGChild()); 303 DCHECK(object.IsSVGChild());
285 // SVG does not use paint offset internally, except for SVGForeignObject which 304 // SVG does not use paint offset internally, except for SVGForeignObject which
286 // has different SVG and HTML coordinate spaces. 305 // has different SVG and HTML coordinate spaces.
287 DCHECK(object.IsSVGForeignObject() || 306 DCHECK(object.IsSVGForeignObject() ||
288 context.current.paint_offset == LayoutPoint()); 307 context.current.paint_offset == LayoutPoint());
289 308
290 if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) { 309 if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
291 AffineTransform transform = object.LocalToSVGParentTransform(); 310 AffineTransform transform = object.LocalToSVGParentTransform();
292 // TODO(pdr): Check for the presence of a transform instead of the value. 311 if (NeedsTransformForNonRootSVG(object)) {
293 // Checking for an identity matrix will cause the property tree structure
294 // to change during animations if the animation passes through the
295 // identity matrix.
296 if (!transform.IsIdentity()) {
297 // The origin is included in the local transform, so leave origin empty. 312 // The origin is included in the local transform, so leave origin empty.
298 auto& properties = object.GetMutableForPainting().EnsurePaintProperties(); 313 auto& properties = *object.GetMutableForPainting().PaintProperties();
299 context.force_subtree_update |= properties.UpdateTransform( 314 context.force_subtree_update |= properties.UpdateTransform(
300 context.current.transform, TransformationMatrix(transform), 315 context.current.transform, TransformationMatrix(transform),
301 FloatPoint3D()); 316 FloatPoint3D());
302 } else { 317 } else {
303 if (auto* properties = object.GetMutableForPainting().PaintProperties()) 318 if (auto* properties = object.GetMutableForPainting().PaintProperties())
304 context.force_subtree_update |= properties->ClearTransform(); 319 context.force_subtree_update |= properties->ClearTransform();
305 } 320 }
306 } 321 }
307 322
308 if (object.PaintProperties() && object.PaintProperties()->Transform()) { 323 if (object.PaintProperties() && object.PaintProperties()->Transform()) {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
340 // Transform origin has no effect without a transform or motion path. 355 // Transform origin has no effect without a transform or motion path.
341 if (!style.HasTransform()) 356 if (!style.HasTransform())
342 return FloatPoint3D(); 357 return FloatPoint3D();
343 FloatSize border_box_size(box.Size()); 358 FloatSize border_box_size(box.Size());
344 return FloatPoint3D( 359 return FloatPoint3D(
345 FloatValueForLength(style.TransformOriginX(), border_box_size.Width()), 360 FloatValueForLength(style.TransformOriginX(), border_box_size.Width()),
346 FloatValueForLength(style.TransformOriginY(), border_box_size.Height()), 361 FloatValueForLength(style.TransformOriginY(), border_box_size.Height()),
347 style.TransformOriginZ()); 362 style.TransformOriginZ());
348 } 363 }
349 364
365 static bool NeedsTransform(const LayoutObject& object) {
366 if (!object.IsBox())
367 return false;
368 return object.StyleRef().HasTransform() || object.StyleRef().Preserves3D() ||
369 CompositingReasonsForTransform(ToLayoutBox(object)) !=
370 kCompositingReasonNone;
371 }
372
350 void PaintPropertyTreeBuilder::UpdateTransform( 373 void PaintPropertyTreeBuilder::UpdateTransform(
351 const LayoutObject& object, 374 const LayoutObject& object,
352 PaintPropertyTreeBuilderContext& context) { 375 PaintPropertyTreeBuilderContext& context) {
353 if (object.IsSVGChild()) { 376 if (object.IsSVGChild()) {
354 UpdateTransformForNonRootSVG(object, context); 377 UpdateTransformForNonRootSVG(object, context);
355 return; 378 return;
356 } 379 }
357 380
358 if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) { 381 if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
359 const ComputedStyle& style = object.StyleRef(); 382 const ComputedStyle& style = object.StyleRef();
360 383
361 // A transform node is allocated for transforms, preserves-3d and any 384 // A transform node is allocated for transforms, preserves-3d and any
362 // direct compositing reason. The latter is required because this is the 385 // direct compositing reason. The latter is required because this is the
363 // only way to represent compositing both an element and its stacking 386 // only way to represent compositing both an element and its stacking
364 // descendants. 387 // descendants.
365 bool has_transform = false; 388 if (NeedsTransform(object)) {
366 if (object.IsBox()) {
367 auto& box = ToLayoutBox(object); 389 auto& box = ToLayoutBox(object);
368 390
369 CompositingReasons compositing_reasons = 391 CompositingReasons compositing_reasons =
370 CompositingReasonsForTransform(box); 392 CompositingReasonsForTransform(box);
371 393
372 if (style.HasTransform() || style.Preserves3D() || 394 TransformationMatrix matrix;
373 compositing_reasons != kCompositingReasonNone) { 395 style.ApplyTransform(
374 TransformationMatrix matrix; 396 matrix, box.Size(), ComputedStyle::kExcludeTransformOrigin,
375 style.ApplyTransform( 397 ComputedStyle::kIncludeMotionPath,
376 matrix, box.Size(), ComputedStyle::kExcludeTransformOrigin, 398 ComputedStyle::kIncludeIndependentTransformProperties);
377 ComputedStyle::kIncludeMotionPath,
378 ComputedStyle::kIncludeIndependentTransformProperties);
379 399
380 // TODO(trchen): transform-style should only be respected if a 400 // TODO(trchen): transform-style should only be respected if a
381 // PaintLayer is created. If a node with transform-style: preserve-3d 401 // PaintLayer is created. If a node with transform-style: preserve-3d
382 // does not exist in an existing rendering context, it establishes a new 402 // does not exist in an existing rendering context, it establishes a new
383 // one. 403 // one.
384 unsigned rendering_context_id = context.current.rendering_context_id; 404 unsigned rendering_context_id = context.current.rendering_context_id;
385 if (style.Preserves3D() && !rendering_context_id) 405 if (style.Preserves3D() && !rendering_context_id)
386 rendering_context_id = PtrHash<const LayoutObject>::GetHash(&object); 406 rendering_context_id = PtrHash<const LayoutObject>::GetHash(&object);
387 407
388 CompositorElementId compositor_element_id = 408 CompositorElementId compositor_element_id =
389 style.HasCurrentTransformAnimation() 409 style.HasCurrentTransformAnimation()
390 ? CreateDomNodeBasedCompositorElementId(object) 410 ? CreateDomNodeBasedCompositorElementId(object)
391 : CompositorElementId(); 411 : CompositorElementId();
392 412
393 auto& properties = 413 auto& properties = *object.GetMutableForPainting().PaintProperties();
394 object.GetMutableForPainting().EnsurePaintProperties(); 414 context.force_subtree_update |= properties.UpdateTransform(
395 context.force_subtree_update |= properties.UpdateTransform( 415 context.current.transform, matrix, TransformOrigin(box),
396 context.current.transform, matrix, TransformOrigin(box), 416 context.current.should_flatten_inherited_transform,
397 context.current.should_flatten_inherited_transform, 417 rendering_context_id, compositing_reasons, compositor_element_id);
398 rendering_context_id, compositing_reasons, compositor_element_id); 418 } else {
399 has_transform = true;
400 }
401 }
402 if (!has_transform) {
403 if (auto* properties = object.GetMutableForPainting().PaintProperties()) 419 if (auto* properties = object.GetMutableForPainting().PaintProperties())
404 context.force_subtree_update |= properties->ClearTransform(); 420 context.force_subtree_update |= properties->ClearTransform();
405 } 421 }
406 } 422 }
407 423
408 const auto* properties = object.PaintProperties(); 424 const auto* properties = object.PaintProperties();
409 if (properties && properties->Transform()) { 425 if (properties && properties->Transform()) {
410 context.current.transform = properties->Transform(); 426 context.current.transform = properties->Transform();
411 if (object.StyleRef().Preserves3D()) { 427 if (object.StyleRef().Preserves3D()) {
412 context.current.rendering_context_id = 428 context.current.rendering_context_id =
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
454 // Either way here we are only interested in the bounding box of them. 470 // Either way here we are only interested in the bounding box of them.
455 DCHECK(object.IsLayoutInline()); 471 DCHECK(object.IsLayoutInline());
456 maximum_mask_region = ToLayoutInline(object).LinesBoundingBox(); 472 maximum_mask_region = ToLayoutInline(object).LinesBoundingBox();
457 } 473 }
458 maximum_mask_region.MoveBy(paint_offset); 474 maximum_mask_region.MoveBy(paint_offset);
459 mask_clip = EnclosingIntRect(maximum_mask_region); 475 mask_clip = EnclosingIntRect(maximum_mask_region);
460 mask_color_filter = kColorFilterNone; 476 mask_color_filter = kColorFilterNone;
461 return true; 477 return true;
462 } 478 }
463 479
480 static bool NeedsEffect(const LayoutObject& object) {
481 const ComputedStyle& style = object.StyleRef();
482
483 const bool is_css_isolated_group =
484 object.IsBoxModelObject() && style.IsStackingContext();
485
486 if (!is_css_isolated_group && !object.IsSVGChild())
487 return false;
488
489 if (object.IsSVG()) {
490 // This handles SVGRoot objects which have PaintLayers.
491 if (object.IsSVGRoot() && object.HasNonIsolatedBlendingDescendants())
492 return true;
493 if (SVGLayoutSupport::IsIsolationRequired(&object))
494 return true;
495 } else if (object.IsBoxModelObject()) {
496 if (PaintLayer* layer = ToLayoutBoxModelObject(object).Layer()) {
497 if (layer->HasNonIsolatedDescendantWithBlendMode())
498 return true;
499 }
500 }
501
502 SkBlendMode blend_mode = object.IsBlendingAllowed()
503 ? WebCoreCompositeToSkiaComposite(
504 kCompositeSourceOver, style.BlendMode())
505 : SkBlendMode::kSrcOver;
506 if (blend_mode != SkBlendMode::kSrcOver)
507 return true;
508
509 float opacity = style.Opacity();
510 if (opacity != 1.0f)
511 return true;
512
513 if (CompositingReasonFinder::RequiresCompositingForOpacityAnimation(style))
514 return true;
515
516 if (object.IsSVGChild()) {
517 if (SVGResources* resources =
518 SVGResourcesCache::CachedResourcesForLayoutObject(&object)) {
519 if (resources->Masker())
520 return true;
521 }
522 }
523
524 if (object.StyleRef().HasMask())
525 return true;
526
527 return false;
528 }
529
464 void PaintPropertyTreeBuilder::UpdateEffect( 530 void PaintPropertyTreeBuilder::UpdateEffect(
465 const LayoutObject& object, 531 const LayoutObject& object,
466 PaintPropertyTreeBuilderContext& context) { 532 PaintPropertyTreeBuilderContext& context) {
467 const ComputedStyle& style = object.StyleRef(); 533 const ComputedStyle& style = object.StyleRef();
468 534
469 const bool is_css_isolated_group =
470 object.IsBoxModelObject() && style.IsStackingContext();
471 if (!is_css_isolated_group && !object.IsSVGChild()) {
472 if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
473 if (auto* properties = object.GetMutableForPainting().PaintProperties()) {
474 context.force_subtree_update |= properties->ClearEffect();
475 context.force_subtree_update |= properties->ClearMask();
476 context.force_subtree_update |= properties->ClearMaskClip();
477 }
478 }
479 return;
480 }
481
482 // TODO(trchen): Can't omit effect node if we have 3D children. 535 // TODO(trchen): Can't omit effect node if we have 3D children.
483 if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) { 536 if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
484 const ClipPaintPropertyNode* output_clip = 537 const ClipPaintPropertyNode* output_clip =
485 context.input_clip_of_current_effect; 538 context.input_clip_of_current_effect;
486 539
487 bool effect_node_needed = false; 540 if (NeedsEffect(object)) {
541 auto& properties = *object.GetMutableForPainting().PaintProperties();
488 542
489 // Can't omit effect node if we have paint children with exotic blending. 543 // We may begin to composite our subtree prior to an animation starts,
490 if (object.IsSVG()) { 544 // but a compositor element ID is only needed when an animation is
491 // This handles SVGRoot objects which have PaintLayers. 545 // current.
492 if (object.IsSVGRoot() && object.HasNonIsolatedBlendingDescendants()) 546 CompositingReasons compositing_reasons = kCompositingReasonNone;
493 effect_node_needed = true; 547 if (CompositingReasonFinder::RequiresCompositingForOpacityAnimation(
494 else if (SVGLayoutSupport::IsIsolationRequired(&object)) 548 style)) {
495 effect_node_needed = true; 549 compositing_reasons = kCompositingReasonActiveAnimation;
496 } else if (PaintLayer* layer = ToLayoutBoxModelObject(object).Layer()) { 550 }
497 if (layer->HasNonIsolatedDescendantWithBlendMode())
498 effect_node_needed = true;
499 }
500 551
501 SkBlendMode blend_mode = object.IsBlendingAllowed() 552 IntRect mask_clip;
502 ? WebCoreCompositeToSkiaComposite( 553 ColorFilter mask_color_filter;
503 kCompositeSourceOver, style.BlendMode()) 554 bool has_mask = ComputeMaskParameters(
504 : SkBlendMode::kSrcOver; 555 mask_clip, mask_color_filter, object, context.current.paint_offset);
505 if (blend_mode != SkBlendMode::kSrcOver) 556 if (has_mask) {
506 effect_node_needed = true; 557 context.force_subtree_update |= properties.UpdateMaskClip(
558 context.current.clip, context.current.transform,
559 FloatRoundedRect(mask_clip));
560 output_clip = properties.MaskClip();
507 561
508 float opacity = style.Opacity(); 562 // TODO(crbug.com/683425): PaintArtifactCompositor does not handle
509 if (opacity != 1.0f) 563 // grouping (i.e. descendant-dependent compositing reason) properly
510 effect_node_needed = true; 564 // yet. This forces masked subtree always create a layer for now.
565 compositing_reasons |= kCompositingReasonIsolateCompositedDescendants;
566 } else {
567 if (auto* properties = object.GetMutableForPainting().PaintProperties())
568 context.force_subtree_update |= properties->ClearMaskClip();
569 }
511 570
512 // We may begin to composite our subtree prior to an animation starts, 571 SkBlendMode blend_mode =
513 // but a compositor element ID is only needed when an animation is current. 572 object.IsBlendingAllowed()
514 CompositorElementId compositor_element_id = 573 ? WebCoreCompositeToSkiaComposite(kCompositeSourceOver,
515 style.HasCurrentOpacityAnimation() 574 style.BlendMode())
516 ? CreateDomNodeBasedCompositorElementId(object) 575 : SkBlendMode::kSrcOver;
517 : CompositorElementId();
518 CompositingReasons compositing_reasons = kCompositingReasonNone;
519 if (CompositingReasonFinder::RequiresCompositingForOpacityAnimation(
520 style)) {
521 compositing_reasons = kCompositingReasonActiveAnimation;
522 effect_node_needed = true;
523 }
524 DCHECK(!style.HasCurrentOpacityAnimation() ||
525 compositing_reasons != kCompositingReasonNone);
526 576
527 IntRect mask_clip; 577 CompositorElementId compositor_element_id =
528 ColorFilter mask_color_filter; 578 style.HasCurrentOpacityAnimation()
529 bool has_mask = ComputeMaskParameters(mask_clip, mask_color_filter, object, 579 ? CreateDomNodeBasedCompositorElementId(object)
530 context.current.paint_offset); 580 : CompositorElementId();
531 if (has_mask) {
532 effect_node_needed = true;
533 581
534 auto& properties = object.GetMutableForPainting().EnsurePaintProperties(); 582 DCHECK(!style.HasCurrentOpacityAnimation() ||
535 context.force_subtree_update |= properties.UpdateMaskClip( 583 compositing_reasons != kCompositingReasonNone);
536 context.current.clip, context.current.transform,
537 FloatRoundedRect(mask_clip));
538 output_clip = properties.MaskClip();
539 584
540 // TODO(crbug.com/683425): PaintArtifactCompositor does not handle
541 // grouping (i.e. descendant-dependent compositing reason) properly yet.
542 // This forces masked subtree always create a layer for now.
543 compositing_reasons |= kCompositingReasonIsolateCompositedDescendants;
544 } else {
545 if (auto* properties = object.GetMutableForPainting().PaintProperties())
546 context.force_subtree_update |= properties->ClearMaskClip();
547 }
548
549 if (effect_node_needed) {
550 auto& properties = object.GetMutableForPainting().EnsurePaintProperties();
551 context.force_subtree_update |= properties.UpdateEffect( 585 context.force_subtree_update |= properties.UpdateEffect(
552 context.current_effect, context.current.transform, output_clip, 586 context.current_effect, context.current.transform, output_clip,
553 kColorFilterNone, CompositorFilterOperations(), opacity, blend_mode, 587 kColorFilterNone, CompositorFilterOperations(), style.Opacity(),
554 compositing_reasons, compositor_element_id); 588 blend_mode, compositing_reasons, compositor_element_id);
555 if (has_mask) { 589 if (has_mask) {
556 // TODO(crbug.com/683425): PaintArtifactCompositor does not handle 590 // TODO(crbug.com/683425): PaintArtifactCompositor does not handle
557 // grouping (i.e. descendant-dependent compositing reason) properly yet. 591 // grouping (i.e. descendant-dependent compositing reason) properly
558 // Adding CompositingReasonSquashingDisallowed forces mask not getting 592 // yet. Adding CompositingReasonSquashingDisallowed forces mask not
559 // squashed into a child effect. Have no compositing reason otherwise. 593 // getting squashed into a child effect. Have no compositing reason
594 // otherwise.
560 context.force_subtree_update |= properties.UpdateMask( 595 context.force_subtree_update |= properties.UpdateMask(
561 properties.Effect(), context.current.transform, output_clip, 596 properties.Effect(), context.current.transform, output_clip,
562 mask_color_filter, CompositorFilterOperations(), 1.f, 597 mask_color_filter, CompositorFilterOperations(), 1.f,
563 SkBlendMode::kDstIn, kCompositingReasonSquashingDisallowed, 598 SkBlendMode::kDstIn, kCompositingReasonSquashingDisallowed,
564 CompositorElementId()); 599 CompositorElementId());
565 } else { 600 } else {
566 context.force_subtree_update |= properties.ClearMask(); 601 context.force_subtree_update |= properties.ClearMask();
567 } 602 }
568 } else { 603 } else {
569 if (auto* properties = object.GetMutableForPainting().PaintProperties()) { 604 if (auto* properties = object.GetMutableForPainting().PaintProperties()) {
570 context.force_subtree_update |= properties->ClearEffect(); 605 context.force_subtree_update |= properties->ClearEffect();
571 context.force_subtree_update |= properties->ClearMask(); 606 context.force_subtree_update |= properties->ClearMask();
607 context.force_subtree_update |= properties->ClearMaskClip();
572 } 608 }
573 } 609 }
574 } 610 }
575 611
576 const auto* properties = object.PaintProperties(); 612 const auto* properties = object.PaintProperties();
577 if (properties && properties->Effect()) { 613 if (properties && properties->Effect()) {
578 context.current_effect = properties->Effect(); 614 context.current_effect = properties->Effect();
579 if (properties->MaskClip()) { 615 if (properties->MaskClip()) {
580 context.input_clip_of_current_effect = context.current.clip = 616 context.input_clip_of_current_effect = context.current.clip =
581 context.absolute_position.clip = context.fixed_position.clip = 617 context.absolute_position.clip = context.fixed_position.clip =
582 properties->MaskClip(); 618 properties->MaskClip();
583 } 619 }
584 } 620 }
585 } 621 }
586 622
623 static bool NeedsFilter(const LayoutObject& object) {
624 // TODO(trchen): SVG caches filters in SVGResources. Implement it.
625 return object.IsBoxModelObject() && ToLayoutBoxModelObject(object).Layer() &&
626 (object.StyleRef().HasFilter() || object.HasReflection());
627 }
628
587 void PaintPropertyTreeBuilder::UpdateFilter( 629 void PaintPropertyTreeBuilder::UpdateFilter(
588 const LayoutObject& object, 630 const LayoutObject& object,
589 PaintPropertyTreeBuilderContext& context) { 631 PaintPropertyTreeBuilderContext& context) {
590 const ComputedStyle& style = object.StyleRef(); 632 const ComputedStyle& style = object.StyleRef();
591 633
592 if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) { 634 if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
593 CompositorFilterOperations filter; 635 if (NeedsFilter(object)) {
594 if (object.IsSVGChild()) { 636 CompositorFilterOperations filter =
595 // TODO(trchen): SVG caches filters in SVGResources. Implement it. 637 ToLayoutBoxModelObject(object)
596 } else if (PaintLayer* layer = ToLayoutBoxModelObject(object).Layer()) { 638 .Layer()
597 // TODO(trchen): Eliminate PaintLayer dependency. 639 ->CreateCompositorFilterOperationsForFilter(style);
598 filter = layer->CreateCompositorFilterOperationsForFilter(style);
599 }
600 640
601 // The CSS filter spec didn't specify how filters interact with overflow 641 // The CSS filter spec didn't specify how filters interact with overflow
602 // clips. The implementation here mimics the old Blink/WebKit behavior for 642 // clips. The implementation here mimics the old Blink/WebKit behavior for
603 // backward compatibility. 643 // backward compatibility.
604 // Basically the output of the filter will be affected by clips that applies 644 // Basically the output of the filter will be affected by clips that
605 // to the current element. The descendants that paints into the input of the 645 // applies to the current element. The descendants that paints into the
606 // filter ignores any clips collected so far. For example: 646 // input of the filter ignores any clips collected so far. For example:
607 // <div style="overflow:scroll"> 647 // <div style="overflow:scroll">
608 // <div style="filter:blur(1px);"> 648 // <div style="filter:blur(1px);">
609 // <div>A</div> 649 // <div>A</div>
610 // <div style="position:absolute;">B</div> 650 // <div style="position:absolute;">B</div>
611 // </div> 651 // </div>
612 // </div> 652 // </div>
613 // In this example "A" should be clipped if the filter was not present. 653 // In this example "A" should be clipped if the filter was not present.
614 // With the filter, "A" will be rastered without clipping, but instead 654 // With the filter, "A" will be rastered without clipping, but instead
615 // the blurred result will be clipped. 655 // the blurred result will be clipped.
616 // On the other hand, "B" should not be clipped because the overflow clip is 656 // On the other hand, "B" should not be clipped because the overflow clip
617 // not in its containing block chain, but as the filter output will be 657 // is not in its containing block chain, but as the filter output will be
618 // clipped, so a blurred "B" may still be invisible. 658 // clipped, so a blurred "B" may still be invisible.
619 const ClipPaintPropertyNode* output_clip = context.current.clip; 659 const ClipPaintPropertyNode* output_clip = context.current.clip;
620 660
621 // TODO(trchen): A filter may contain spatial operations such that an 661 // TODO(trchen): A filter may contain spatial operations such that an
622 // output pixel may depend on an input pixel outside of the output clip. 662 // output pixel may depend on an input pixel outside of the output clip.
623 // We should generate a special clip node to represent this expansion. 663 // We should generate a special clip node to represent this expansion.
624 664
625 // We may begin to composite our subtree prior to an animation starts, 665 // We may begin to composite our subtree prior to an animation starts,
626 // but a compositor element ID is only needed when an animation is current. 666 // but a compositor element ID is only needed when an animation is
627 CompositorElementId compositor_element_id = 667 // current.
628 style.HasCurrentFilterAnimation() 668 CompositorElementId compositor_element_id =
629 ? CreateDomNodeBasedCompositorElementId(object) 669 style.HasCurrentFilterAnimation()
630 : CompositorElementId(); 670 ? CreateDomNodeBasedCompositorElementId(object)
631 CompositingReasons compositing_reasons = 671 : CompositorElementId();
632 CompositingReasonFinder::RequiresCompositingForFilterAnimation(style) 672 CompositingReasons compositing_reasons =
633 ? kCompositingReasonActiveAnimation 673 CompositingReasonFinder::RequiresCompositingForFilterAnimation(style)
634 : kCompositingReasonNone; 674 ? kCompositingReasonActiveAnimation
635 DCHECK(!style.HasCurrentFilterAnimation() || 675 : kCompositingReasonNone;
636 compositing_reasons != kCompositingReasonNone); 676 DCHECK(!style.HasCurrentFilterAnimation() ||
677 compositing_reasons != kCompositingReasonNone);
637 678
638 if (compositing_reasons == kCompositingReasonNone && filter.IsEmpty()) { 679 auto& properties = *object.GetMutableForPainting().PaintProperties();
639 if (auto* properties = object.GetMutableForPainting().PaintProperties())
640 context.force_subtree_update |= properties->ClearFilter();
641 } else {
642 auto& properties = object.GetMutableForPainting().EnsurePaintProperties();
643 context.force_subtree_update |= properties.UpdateFilter( 680 context.force_subtree_update |= properties.UpdateFilter(
644 context.current_effect, context.current.transform, output_clip, 681 context.current_effect, context.current.transform, output_clip,
645 kColorFilterNone, std::move(filter), 1.f, SkBlendMode::kSrcOver, 682 kColorFilterNone, std::move(filter), 1.f, SkBlendMode::kSrcOver,
646 compositing_reasons, compositor_element_id); 683 compositing_reasons, compositor_element_id);
684 } else {
685 if (auto* properties = object.GetMutableForPainting().PaintProperties())
686 context.force_subtree_update |= properties->ClearFilter();
647 } 687 }
648 } 688 }
649 689
650 const auto* properties = object.PaintProperties(); 690 const auto* properties = object.PaintProperties();
651 if (properties && properties->Filter()) { 691 if (properties && properties->Filter()) {
652 context.current_effect = properties->Filter(); 692 context.current_effect = properties->Filter();
653 // TODO(trchen): Change input clip to expansion hint once implemented. 693 // TODO(trchen): Change input clip to expansion hint once implemented.
654 const ClipPaintPropertyNode* input_clip = 694 const ClipPaintPropertyNode* input_clip =
655 properties->Filter()->OutputClip(); 695 properties->Filter()->OutputClip();
656 context.input_clip_of_current_effect = context.current.clip = 696 context.input_clip_of_current_effect = context.current.clip =
657 context.absolute_position.clip = context.fixed_position.clip = 697 context.absolute_position.clip = context.fixed_position.clip =
658 input_clip; 698 input_clip;
659 } 699 }
660 } 700 }
661 701
702 static bool NeedsCssClip(const LayoutObject& object) {
703 return object.HasClip();
704 }
705
662 void PaintPropertyTreeBuilder::UpdateCssClip( 706 void PaintPropertyTreeBuilder::UpdateCssClip(
663 const LayoutObject& object, 707 const LayoutObject& object,
664 PaintPropertyTreeBuilderContext& context) { 708 PaintPropertyTreeBuilderContext& context) {
665 if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) { 709 if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
666 if (object.HasClip()) { 710 if (NeedsCssClip(object)) {
667 // Create clip node for descendants that are not fixed position. 711 // Create clip node for descendants that are not fixed position.
668 // We don't have to setup context.absolutePosition.clip here because this 712 // We don't have to setup context.absolutePosition.clip here because this
669 // object must be a container for absolute position descendants, and will 713 // object must be a container for absolute position descendants, and will
670 // copy from in-flow context later at updateOutOfFlowContext() step. 714 // copy from in-flow context later at updateOutOfFlowContext() step.
671 DCHECK(object.CanContainAbsolutePositionObjects()); 715 DCHECK(object.CanContainAbsolutePositionObjects());
672 LayoutRect clip_rect = 716 LayoutRect clip_rect =
673 ToLayoutBox(object).ClipRect(context.current.paint_offset); 717 ToLayoutBox(object).ClipRect(context.current.paint_offset);
674 auto& properties = object.GetMutableForPainting().EnsurePaintProperties(); 718 auto& properties = *object.GetMutableForPainting().PaintProperties();
675 context.force_subtree_update |= properties.UpdateCssClip( 719 context.force_subtree_update |= properties.UpdateCssClip(
676 context.current.clip, context.current.transform, 720 context.current.clip, context.current.transform,
677 FloatRoundedRect(FloatRect(clip_rect))); 721 FloatRoundedRect(FloatRect(clip_rect)));
678 } else { 722 } else {
679 if (auto* properties = object.GetMutableForPainting().PaintProperties()) 723 if (auto* properties = object.GetMutableForPainting().PaintProperties())
680 context.force_subtree_update |= properties->ClearCssClip(); 724 context.force_subtree_update |= properties->ClearCssClip();
681 } 725 }
682 } 726 }
683 727
684 const auto* properties = object.PaintProperties(); 728 const auto* properties = object.PaintProperties();
(...skipping 12 matching lines...) Expand all
697 object.GetMutableForPainting().ClearLocalBorderBoxProperties(); 741 object.GetMutableForPainting().ClearLocalBorderBoxProperties();
698 } else { 742 } else {
699 PropertyTreeState local_border_box = 743 PropertyTreeState local_border_box =
700 PropertyTreeState(context.current.transform, context.current.clip, 744 PropertyTreeState(context.current.transform, context.current.clip,
701 context.current_effect); 745 context.current_effect);
702 object.GetMutableForPainting().SetLocalBorderBoxProperties( 746 object.GetMutableForPainting().SetLocalBorderBoxProperties(
703 local_border_box); 747 local_border_box);
704 } 748 }
705 } 749 }
706 750
751 static bool NeedsScrollbarPaintOffset(const LayoutObject& object) {
752 if (object.IsBoxModelObject()) {
753 if (auto* area = ToLayoutBoxModelObject(object).GetScrollableArea()) {
754 if (area->HorizontalScrollbar() || area->VerticalScrollbar())
755 return true;
756 }
757 }
758 return false;
759 }
760
707 // TODO(trchen): Remove this once we bake the paint offset into frameRect. 761 // TODO(trchen): Remove this once we bake the paint offset into frameRect.
708 void PaintPropertyTreeBuilder::UpdateScrollbarPaintOffset( 762 void PaintPropertyTreeBuilder::UpdateScrollbarPaintOffset(
709 const LayoutObject& object, 763 const LayoutObject& object,
710 PaintPropertyTreeBuilderContext& context) { 764 PaintPropertyTreeBuilderContext& context) {
711 if (!object.NeedsPaintPropertyUpdate() && !context.force_subtree_update) 765 if (!object.NeedsPaintPropertyUpdate() && !context.force_subtree_update)
712 return; 766 return;
713 767
714 bool needs_scrollbar_paint_offset = false; 768 if (NeedsScrollbarPaintOffset(object)) {
715 IntPoint rounded_paint_offset = RoundedIntPoint(context.current.paint_offset); 769 IntPoint rounded_paint_offset =
716 if (rounded_paint_offset != IntPoint() && object.IsBoxModelObject()) { 770 RoundedIntPoint(context.current.paint_offset);
717 if (auto* area = ToLayoutBoxModelObject(object).GetScrollableArea()) { 771 auto paint_offset = TransformationMatrix().Translate(
718 if (area->HorizontalScrollbar() || area->VerticalScrollbar()) { 772 rounded_paint_offset.X(), rounded_paint_offset.Y());
719 auto paint_offset = TransformationMatrix().Translate( 773 auto& properties = *object.GetMutableForPainting().PaintProperties();
720 rounded_paint_offset.X(), rounded_paint_offset.Y()); 774 context.force_subtree_update |= properties.UpdateScrollbarPaintOffset(
721 auto& properties = 775 context.current.transform, paint_offset, FloatPoint3D());
722 object.GetMutableForPainting().EnsurePaintProperties(); 776 } else {
723 context.force_subtree_update |= properties.UpdateScrollbarPaintOffset( 777 if (auto* properties = object.GetMutableForPainting().PaintProperties())
724 context.current.transform, paint_offset, FloatPoint3D()); 778 context.force_subtree_update |= properties->ClearScrollbarPaintOffset();
725 needs_scrollbar_paint_offset = true;
726 }
727 }
728 } 779 }
780 }
729 781
730 auto* properties = object.GetMutableForPainting().PaintProperties(); 782 static bool NeedsOverflowScroll(const LayoutObject& object) {
731 if (!needs_scrollbar_paint_offset && properties) 783 return object.IsBox() && ToLayoutBox(object).ShouldClipOverflow();
732 context.force_subtree_update |= properties->ClearScrollbarPaintOffset();
733 } 784 }
734 785
735 void PaintPropertyTreeBuilder::UpdateOverflowClip( 786 void PaintPropertyTreeBuilder::UpdateOverflowClip(
736 const LayoutObject& object, 787 const LayoutObject& object,
737 PaintPropertyTreeBuilderContext& context) { 788 PaintPropertyTreeBuilderContext& context) {
738 if (!object.IsBox())
739 return;
740
741 if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) { 789 if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
742 const LayoutBox& box = ToLayoutBox(object); 790 if (NeedsOverflowScroll(object)) {
743 // The <input> elements can't have contents thus CSS overflow property 791 const LayoutBox& box = ToLayoutBox(object);
744 // doesn't apply. However for layout purposes we do generate child layout 792 LayoutRect clip_rect;
745 // objects for them, e.g. button label. We should clip the overflow from
746 // those children. This is called control clip and we technically treat them
747 // like overflow clip.
748 LayoutRect clip_rect;
749 if (box.ShouldClipOverflow()) {
750 clip_rect = 793 clip_rect =
751 LayoutRect(box.OverflowClipRect(context.current.paint_offset)); 794 LayoutRect(box.OverflowClipRect(context.current.paint_offset));
795
796 auto& properties = *object.GetMutableForPainting().PaintProperties();
797 const auto* current_clip = context.current.clip;
798 if (box.StyleRef().HasBorderRadius()) {
799 auto inner_border = box.StyleRef().GetRoundedInnerBorderFor(
800 LayoutRect(context.current.paint_offset, box.Size()));
801 context.force_subtree_update |= properties.UpdateInnerBorderRadiusClip(
802 context.current.clip, context.current.transform, inner_border);
803 current_clip = properties.InnerBorderRadiusClip();
804 } else {
805 context.force_subtree_update |= properties.ClearInnerBorderRadiusClip();
806 }
807
808 context.force_subtree_update |=
809 properties.UpdateOverflowClip(current_clip, context.current.transform,
810 FloatRoundedRect(FloatRect(clip_rect)));
752 } else { 811 } else {
753 if (auto* properties = object.GetMutableForPainting().PaintProperties()) { 812 if (auto* properties = object.GetMutableForPainting().PaintProperties()) {
754 context.force_subtree_update |= 813 context.force_subtree_update |=
755 properties->ClearInnerBorderRadiusClip(); 814 properties->ClearInnerBorderRadiusClip();
756 context.force_subtree_update |= properties->ClearOverflowClip(); 815 context.force_subtree_update |= properties->ClearOverflowClip();
757 } 816 }
758 return; 817 return;
759 } 818 }
760
761 auto& properties = object.GetMutableForPainting().EnsurePaintProperties();
762 const auto* current_clip = context.current.clip;
763 if (box.StyleRef().HasBorderRadius()) {
764 auto inner_border = box.StyleRef().GetRoundedInnerBorderFor(
765 LayoutRect(context.current.paint_offset, box.Size()));
766 context.force_subtree_update |= properties.UpdateInnerBorderRadiusClip(
767 context.current.clip, context.current.transform, inner_border);
768 current_clip = properties.InnerBorderRadiusClip();
769 } else {
770 context.force_subtree_update |= properties.ClearInnerBorderRadiusClip();
771 }
772
773 context.force_subtree_update |=
774 properties.UpdateOverflowClip(current_clip, context.current.transform,
775 FloatRoundedRect(FloatRect(clip_rect)));
776 } 819 }
777 820
778 const auto* properties = object.PaintProperties(); 821 const auto* properties = object.PaintProperties();
779 if (properties && properties->OverflowClip()) 822 if (properties && properties->OverflowClip())
780 context.current.clip = properties->OverflowClip(); 823 context.current.clip = properties->OverflowClip();
781 } 824 }
782 825
783 static FloatPoint PerspectiveOrigin(const LayoutBox& box) { 826 static FloatPoint PerspectiveOrigin(const LayoutBox& box) {
784 const ComputedStyle& style = box.StyleRef(); 827 const ComputedStyle& style = box.StyleRef();
785 // Perspective origin has no effect without perspective. 828 // Perspective origin has no effect without perspective.
786 DCHECK(style.HasPerspective()); 829 DCHECK(style.HasPerspective());
787 FloatSize border_box_size(box.Size()); 830 FloatSize border_box_size(box.Size());
788 return FloatPoint( 831 return FloatPoint(
789 FloatValueForLength(style.PerspectiveOriginX(), border_box_size.Width()), 832 FloatValueForLength(style.PerspectiveOriginX(), border_box_size.Width()),
790 FloatValueForLength(style.PerspectiveOriginY(), 833 FloatValueForLength(style.PerspectiveOriginY(),
791 border_box_size.Height())); 834 border_box_size.Height()));
792 } 835 }
793 836
837 static bool NeedsPerspective(const LayoutObject& object) {
838 return object.IsBox() && object.StyleRef().HasPerspective();
839 }
840
794 void PaintPropertyTreeBuilder::UpdatePerspective( 841 void PaintPropertyTreeBuilder::UpdatePerspective(
795 const LayoutObject& object, 842 const LayoutObject& object,
796 PaintPropertyTreeBuilderContext& context) { 843 PaintPropertyTreeBuilderContext& context) {
797 if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) { 844 if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
798 const ComputedStyle& style = object.StyleRef(); 845 if (NeedsPerspective(object)) {
799 if (object.IsBox() && style.HasPerspective()) { 846 const ComputedStyle& style = object.StyleRef();
800 // The perspective node must not flatten (else nothing will get 847 // The perspective node must not flatten (else nothing will get
801 // perspective), but it should still extend the rendering context as 848 // perspective), but it should still extend the rendering context as
802 // most transform nodes do. 849 // most transform nodes do.
803 TransformationMatrix matrix = 850 TransformationMatrix matrix =
804 TransformationMatrix().ApplyPerspective(style.Perspective()); 851 TransformationMatrix().ApplyPerspective(style.Perspective());
805 FloatPoint3D origin = PerspectiveOrigin(ToLayoutBox(object)) + 852 FloatPoint3D origin = PerspectiveOrigin(ToLayoutBox(object)) +
806 ToLayoutSize(context.current.paint_offset); 853 ToLayoutSize(context.current.paint_offset);
807 auto& properties = object.GetMutableForPainting().EnsurePaintProperties(); 854 auto& properties = *object.GetMutableForPainting().PaintProperties();
808 context.force_subtree_update |= properties.UpdatePerspective( 855 context.force_subtree_update |= properties.UpdatePerspective(
809 context.current.transform, matrix, origin, 856 context.current.transform, matrix, origin,
810 context.current.should_flatten_inherited_transform, 857 context.current.should_flatten_inherited_transform,
811 context.current.rendering_context_id); 858 context.current.rendering_context_id);
812 } else { 859 } else {
813 if (auto* properties = object.GetMutableForPainting().PaintProperties()) 860 if (auto* properties = object.GetMutableForPainting().PaintProperties())
814 context.force_subtree_update |= properties->ClearPerspective(); 861 context.force_subtree_update |= properties->ClearPerspective();
815 } 862 }
816 } 863 }
817 864
818 const auto* properties = object.PaintProperties(); 865 const auto* properties = object.PaintProperties();
819 if (properties && properties->Perspective()) { 866 if (properties && properties->Perspective()) {
820 context.current.transform = properties->Perspective(); 867 context.current.transform = properties->Perspective();
821 context.current.should_flatten_inherited_transform = false; 868 context.current.should_flatten_inherited_transform = false;
822 } 869 }
823 } 870 }
824 871
872 static bool NeedsSVGLocalToBorderBoxTransform(const LayoutObject& object) {
873 return object.IsSVGRoot();
874 }
875
825 void PaintPropertyTreeBuilder::UpdateSvgLocalToBorderBoxTransform( 876 void PaintPropertyTreeBuilder::UpdateSvgLocalToBorderBoxTransform(
826 const LayoutObject& object, 877 const LayoutObject& object,
827 PaintPropertyTreeBuilderContext& context) { 878 PaintPropertyTreeBuilderContext& context) {
828 if (!object.IsSVGRoot()) 879 if (!object.IsSVGRoot())
829 return; 880 return;
830 881
831 if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) { 882 if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
832 AffineTransform transform_to_border_box = 883 AffineTransform transform_to_border_box =
833 SVGRootPainter(ToLayoutSVGRoot(object)) 884 SVGRootPainter(ToLayoutSVGRoot(object))
834 .TransformToPixelSnappedBorderBox(context.current.paint_offset); 885 .TransformToPixelSnappedBorderBox(context.current.paint_offset);
835 if (!transform_to_border_box.IsIdentity()) { 886 if (!transform_to_border_box.IsIdentity() &&
836 auto& properties = object.GetMutableForPainting().EnsurePaintProperties(); 887 NeedsSVGLocalToBorderBoxTransform(object)) {
888 auto& properties = *object.GetMutableForPainting().PaintProperties();
837 context.force_subtree_update |= 889 context.force_subtree_update |=
838 properties.UpdateSvgLocalToBorderBoxTransform( 890 properties.UpdateSvgLocalToBorderBoxTransform(
839 context.current.transform, transform_to_border_box, 891 context.current.transform, transform_to_border_box,
840 FloatPoint3D()); 892 FloatPoint3D());
841 } else { 893 } else {
842 if (auto* properties = object.GetMutableForPainting().PaintProperties()) { 894 if (auto* properties = object.GetMutableForPainting().PaintProperties()) {
843 context.force_subtree_update |= 895 context.force_subtree_update |=
844 properties->ClearSvgLocalToBorderBoxTransform(); 896 properties->ClearSvgLocalToBorderBoxTransform();
845 } 897 }
846 } 898 }
(...skipping 16 matching lines...) Expand all
863 // The current main thread scrolling reasons implementation only changes 915 // The current main thread scrolling reasons implementation only changes
864 // reasons at frame boundaries, so we can early-out when not at a LayoutView. 916 // reasons at frame boundaries, so we can early-out when not at a LayoutView.
865 // TODO(pdr): Need to find a solution to the style-related main thread 917 // TODO(pdr): Need to find a solution to the style-related main thread
866 // scrolling reasons such as opacity and transform which violate this. 918 // scrolling reasons such as opacity and transform which violate this.
867 if (!object.IsLayoutView()) 919 if (!object.IsLayoutView())
868 return ancestor_reasons; 920 return ancestor_reasons;
869 return GetMainThreadScrollingReasons(*object.GetFrameView(), 921 return GetMainThreadScrollingReasons(*object.GetFrameView(),
870 ancestor_reasons); 922 ancestor_reasons);
871 } 923 }
872 924
925 static bool NeedsScrollTranslation(const LayoutObject& object) {
926 if (object.HasOverflowClip()) {
927 const LayoutBox& box = ToLayoutBox(object);
928 auto* scrollable_area = box.GetScrollableArea();
929 IntSize scroll_offset = box.ScrolledContentOffset();
930 if (!scroll_offset.IsZero() || scrollable_area->ScrollsOverflow())
931 return true;
932 }
933 return false;
934 }
935
873 void PaintPropertyTreeBuilder::UpdateScrollAndScrollTranslation( 936 void PaintPropertyTreeBuilder::UpdateScrollAndScrollTranslation(
874 const LayoutObject& object, 937 const LayoutObject& object,
875 PaintPropertyTreeBuilderContext& context) { 938 PaintPropertyTreeBuilderContext& context) {
876 if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) { 939 if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
877 bool needs_scroll_properties = false; 940 if (NeedsScrollTranslation(object)) {
878 if (object.HasOverflowClip()) { 941 const LayoutBox& box = ToLayoutBox(object);
942 auto* scrollable_area = box.GetScrollableArea();
943 IntSize scroll_offset = box.ScrolledContentOffset();
944 auto& properties = *object.GetMutableForPainting().PaintProperties();
945
946 IntSize scroll_clip = scrollable_area->VisibleContentRect().Size();
947 IntSize scroll_bounds = scrollable_area->ContentsSize();
948 bool user_scrollable_horizontal =
949 scrollable_area->UserInputScrollable(kHorizontalScrollbar);
950 bool user_scrollable_vertical =
951 scrollable_area->UserInputScrollable(kVerticalScrollbar);
952
879 auto ancestor_reasons = 953 auto ancestor_reasons =
880 context.current.scroll->GetMainThreadScrollingReasons(); 954 context.current.scroll->GetMainThreadScrollingReasons();
881 auto reasons = GetMainThreadScrollingReasons(object, ancestor_reasons); 955 auto reasons = GetMainThreadScrollingReasons(object, ancestor_reasons);
882 956
883 const LayoutBox& box = ToLayoutBox(object); 957 // Main thread scrolling reasons depend on their ancestor's reasons
884 auto* scrollable_area = box.GetScrollableArea(); 958 // so ensure the entire subtree is updated when reasons change.
885 IntSize scroll_offset = box.ScrolledContentOffset(); 959 if (auto* existing_scroll_translation = properties.ScrollTranslation()) {
886 if (!scroll_offset.IsZero() || scrollable_area->ScrollsOverflow()) { 960 auto* existing_scroll_node = existing_scroll_translation->ScrollNode();
887 needs_scroll_properties = true; 961 if (existing_scroll_node->GetMainThreadScrollingReasons() != reasons)
888 auto& properties = 962 context.force_subtree_update = true;
889 object.GetMutableForPainting().EnsurePaintProperties(); 963 }
890 964
891 IntSize scroll_clip = scrollable_area->VisibleContentRect().Size(); 965 CompositorElementId compositor_element_id =
892 IntSize scroll_bounds = scrollable_area->ContentsSize(); 966 CreateDomNodeBasedCompositorElementId(object);
893 bool user_scrollable_horizontal = 967 TransformationMatrix matrix = TransformationMatrix().Translate(
894 scrollable_area->UserInputScrollable(kHorizontalScrollbar); 968 -scroll_offset.Width(), -scroll_offset.Height());
895 bool user_scrollable_vertical = 969 context.force_subtree_update |= properties.UpdateScrollTranslation(
896 scrollable_area->UserInputScrollable(kVerticalScrollbar); 970 context.current.transform, matrix, FloatPoint3D(),
897 971 context.current.should_flatten_inherited_transform,
898 // Main thread scrolling reasons depend on their ancestor's reasons 972 context.current.rendering_context_id, kCompositingReasonNone,
899 // so ensure the entire subtree is updated when reasons change. 973 compositor_element_id, context.current.scroll, scroll_clip,
900 if (auto* existing_scroll_translation = 974 scroll_bounds, user_scrollable_horizontal, user_scrollable_vertical,
901 properties.ScrollTranslation()) { 975 reasons, scrollable_area);
902 auto* existing_scroll_node = 976 } else {
903 existing_scroll_translation->ScrollNode();
904 if (existing_scroll_node->GetMainThreadScrollingReasons() != reasons)
905 context.force_subtree_update = true;
906 }
907
908 CompositorElementId compositor_element_id =
909 CreateDomNodeBasedCompositorElementId(object);
910 TransformationMatrix matrix = TransformationMatrix().Translate(
911 -scroll_offset.Width(), -scroll_offset.Height());
912 context.force_subtree_update |= properties.UpdateScrollTranslation(
913 context.current.transform, matrix, FloatPoint3D(),
914 context.current.should_flatten_inherited_transform,
915 context.current.rendering_context_id, kCompositingReasonNone,
916 compositor_element_id, context.current.scroll, scroll_clip,
917 scroll_bounds, user_scrollable_horizontal, user_scrollable_vertical,
918 reasons, scrollable_area);
919 }
920 }
921
922 if (!needs_scroll_properties) {
923 // Ensure pre-existing properties are cleared. 977 // Ensure pre-existing properties are cleared.
924 if (auto* properties = object.GetMutableForPainting().PaintProperties()) 978 if (auto* properties = object.GetMutableForPainting().PaintProperties())
925 context.force_subtree_update |= properties->ClearScrollTranslation(); 979 context.force_subtree_update |= properties->ClearScrollTranslation();
926 } 980 }
927 } 981 }
928 982
929 if (object.PaintProperties() && 983 if (object.PaintProperties() &&
930 object.PaintProperties()->ScrollTranslation()) { 984 object.PaintProperties()->ScrollTranslation()) {
931 context.current.transform = object.PaintProperties()->ScrollTranslation(); 985 context.current.transform = object.PaintProperties()->ScrollTranslation();
932 context.current.scroll = context.current.transform->ScrollNode(); 986 context.current.scroll = context.current.transform->ScrollNode();
933 context.current.should_flatten_inherited_transform = false; 987 context.current.should_flatten_inherited_transform = false;
934 } 988 }
935 } 989 }
936 990
991 static bool NeedsCssClipFixedPosition(const LayoutObject& object) {
992 return !object.IsLayoutView() && !object.CanContainFixedPositionObjects() &&
993 NeedsCssClip(object);
994 }
995
937 void PaintPropertyTreeBuilder::UpdateOutOfFlowContext( 996 void PaintPropertyTreeBuilder::UpdateOutOfFlowContext(
938 const LayoutObject& object, 997 const LayoutObject& object,
939 PaintPropertyTreeBuilderContext& context) { 998 PaintPropertyTreeBuilderContext& context) {
940 if (object.IsLayoutBlock()) 999 if (object.IsLayoutBlock())
941 context.paint_offset_for_float = context.current.paint_offset; 1000 context.paint_offset_for_float = context.current.paint_offset;
942 1001
943 if (object.CanContainAbsolutePositionObjects()) { 1002 if (object.CanContainAbsolutePositionObjects()) {
944 context.absolute_position = context.current; 1003 context.absolute_position = context.current;
945 context.container_for_absolute_position = &object; 1004 context.container_for_absolute_position = &object;
946 } 1005 }
(...skipping 12 matching lines...) Expand all
959 } else if (object.CanContainFixedPositionObjects()) { 1018 } else if (object.CanContainFixedPositionObjects()) {
960 context.fixed_position = context.current; 1019 context.fixed_position = context.current;
961 } else if (object.GetMutableForPainting().PaintProperties() && 1020 } else if (object.GetMutableForPainting().PaintProperties() &&
962 object.PaintProperties()->CssClip()) { 1021 object.PaintProperties()->CssClip()) {
963 // CSS clip applies to all descendants, even if this object is not a 1022 // CSS clip applies to all descendants, even if this object is not a
964 // containing block ancestor of the descendant. It is okay for 1023 // containing block ancestor of the descendant. It is okay for
965 // absolute-position descendants because having CSS clip implies being 1024 // absolute-position descendants because having CSS clip implies being
966 // absolute position container. However for fixed-position descendants we 1025 // absolute position container. However for fixed-position descendants we
967 // need to insert the clip here if we are not a containing block ancestor of 1026 // need to insert the clip here if we are not a containing block ancestor of
968 // them. 1027 // them.
969 auto* css_clip = 1028 auto& properties = *object.GetMutableForPainting().PaintProperties();
970 object.GetMutableForPainting().PaintProperties()->CssClip(); 1029 auto* css_clip = properties.CssClip();
971 1030
972 // Before we actually create anything, check whether in-flow context and 1031 // Before we actually create anything, check whether in-flow context and
973 // fixed-position context has exactly the same clip. Reuse if possible. 1032 // fixed-position context has exactly the same clip. Reuse if possible.
974 if (context.fixed_position.clip == css_clip->Parent()) { 1033 if (context.fixed_position.clip == css_clip->Parent()) {
975 context.fixed_position.clip = css_clip; 1034 context.fixed_position.clip = css_clip;
976 } else { 1035 } else {
977 if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) { 1036 if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
978 auto& properties =
979 object.GetMutableForPainting().EnsurePaintProperties();
980 context.force_subtree_update |= properties.UpdateCssClipFixedPosition( 1037 context.force_subtree_update |= properties.UpdateCssClipFixedPosition(
981 context.fixed_position.clip, 1038 context.fixed_position.clip,
982 const_cast<TransformPaintPropertyNode*>( 1039 const_cast<TransformPaintPropertyNode*>(
983 css_clip->LocalTransformSpace()), 1040 css_clip->LocalTransformSpace()),
984 css_clip->ClipRect()); 1041 css_clip->ClipRect());
985 } 1042 }
986 const auto* properties = object.PaintProperties(); 1043 if (properties.CssClipFixedPosition())
987 if (properties && properties->CssClipFixedPosition()) 1044 context.fixed_position.clip = properties.CssClipFixedPosition();
988 context.fixed_position.clip = properties->CssClipFixedPosition();
989 return; 1045 return;
990 } 1046 }
991 } 1047 }
992 1048
993 if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) { 1049 if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
994 if (auto* properties = object.GetMutableForPainting().PaintProperties()) 1050 if (auto* properties = object.GetMutableForPainting().PaintProperties())
995 context.force_subtree_update |= properties->ClearCssClipFixedPosition(); 1051 context.force_subtree_update |= properties->ClearCssClipFixedPosition();
996 } 1052 }
997 } 1053 }
998 1054
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
1101 box.HasClip() || 1157 box.HasClip() ||
1102 // Relative lengths (e.g., percentage values) in transform, perspective, 1158 // Relative lengths (e.g., percentage values) in transform, perspective,
1103 // transform-origin, and perspective-origin can depend on the size of the 1159 // transform-origin, and perspective-origin can depend on the size of the
1104 // frame rect, so force a property update if it changes. TODO(pdr): We 1160 // frame rect, so force a property update if it changes. TODO(pdr): We
1105 // only need to update properties if there are relative lengths. 1161 // only need to update properties if there are relative lengths.
1106 box.StyleRef().HasTransform() || box.StyleRef().HasPerspective() || 1162 box.StyleRef().HasTransform() || box.StyleRef().HasPerspective() ||
1107 box_generates_property_nodes_for_mask_and_clip_path) 1163 box_generates_property_nodes_for_mask_and_clip_path)
1108 box.GetMutableForPainting().SetNeedsPaintPropertyUpdate(); 1164 box.GetMutableForPainting().SetNeedsPaintPropertyUpdate();
1109 } 1165 }
1110 1166
1167 void PaintPropertyTreeBuilder::UpdatePaintProperties(
1168 const LayoutObject& object,
1169 PaintPropertyTreeBuilderContext& context) {
1170 bool needs_paint_properties =
1171 NeedsPaintOffsetTranslation(object) || NeedsTransform(object) ||
1172 NeedsEffect(object) || NeedsTransformForNonRootSVG(object) ||
1173 NeedsFilter(object) || NeedsCssClip(object) ||
1174 NeedsScrollbarPaintOffset(object) || NeedsOverflowScroll(object) ||
1175 NeedsPerspective(object) || NeedsSVGLocalToBorderBoxTransform(object) ||
1176 NeedsScrollTranslation(object) || NeedsCssClipFixedPosition(object);
1177
1178 bool had_paint_properties = object.PaintProperties();
1179
1180 if (needs_paint_properties) {
1181 object.GetMutableForPainting().EnsurePaintProperties();
1182 } else {
1183 object.GetMutableForPainting().ClearPaintProperties();
1184 if (had_paint_properties)
1185 context.force_subtree_update = true;
1186 }
1187 }
1188
1111 void PaintPropertyTreeBuilder::UpdatePropertiesForSelf( 1189 void PaintPropertyTreeBuilder::UpdatePropertiesForSelf(
1112 const LayoutObject& object, 1190 const LayoutObject& object,
1113 PaintPropertyTreeBuilderContext& context) { 1191 PaintPropertyTreeBuilderContext& context) {
1114 if (object.IsSVGHiddenContainer()) { 1192 if (object.IsSVGHiddenContainer()) {
1115 // SVG resources are painted within one or more other locations in the 1193 // SVG resources are painted within one or more other locations in the
1116 // SVG during paint, and hence have their own independent paint property 1194 // SVG during paint, and hence have their own independent paint property
1117 // trees, paint offset, etc. 1195 // trees, paint offset, etc.
1118 context = PaintPropertyTreeBuilderContext(); 1196 context = PaintPropertyTreeBuilderContext();
1119 } 1197 }
1120 1198
1199 UpdatePaintProperties(object, context);
1200
1121 // This is not in FindObjectPropertiesNeedingUpdateScope because paint offset 1201 // This is not in FindObjectPropertiesNeedingUpdateScope because paint offset
1122 // can change without needsPaintPropertyUpdate. 1202 // can change without needsPaintPropertyUpdate.
1123 UpdateForObjectLocationAndSize(object, context); 1203 UpdateForObjectLocationAndSize(object, context);
1124 1204
1125 #if DCHECK_IS_ON() 1205 #if DCHECK_IS_ON()
1126 FindObjectPropertiesNeedingUpdateScope check_needs_update_scope(object, 1206 FindObjectPropertiesNeedingUpdateScope check_needs_update_scope(object,
1127 context); 1207 context);
1128 #endif 1208 #endif
1129 1209
1130 if (object.IsBoxModelObject() || object.IsSVG()) { 1210 if (object.IsBoxModelObject() || object.IsSVG()) {
(...skipping 23 matching lines...) Expand all
1154 UpdateOverflowClip(object, context); 1234 UpdateOverflowClip(object, context);
1155 UpdatePerspective(object, context); 1235 UpdatePerspective(object, context);
1156 UpdateSvgLocalToBorderBoxTransform(object, context); 1236 UpdateSvgLocalToBorderBoxTransform(object, context);
1157 UpdateScrollAndScrollTranslation(object, context); 1237 UpdateScrollAndScrollTranslation(object, context);
1158 UpdateOutOfFlowContext(object, context); 1238 UpdateOutOfFlowContext(object, context);
1159 1239
1160 context.force_subtree_update |= object.SubtreeNeedsPaintPropertyUpdate(); 1240 context.force_subtree_update |= object.SubtreeNeedsPaintPropertyUpdate();
1161 } 1241 }
1162 1242
1163 } // namespace blink 1243 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698