1 /*
2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights
3 * reserved.
4 *
5 * Portions are Copyright (C) 1998 Netscape Communications Corporation.
6 *
7 * Other contributors:
8 * Robert O'Callahan <roc+@cs.cmu.edu>
9 * David Baron <dbaron@fas.harvard.edu>
10 * Christian Biesinger <cbiesinger@web.de>
11 * Randall Jesup <rjesup@wgate.com>
12 * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
13 * Josh Soref <timeless@mac.com>
14 * Boris Zbarsky <bzbarsky@mit.edu>
15 *
16 * This library is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU Lesser General Public
18 * License as published by the Free Software Foundation; either
19 * version 2.1 of the License, or (at your option) any later version.
20 *
21 * This library is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 * Lesser General Public License for more details.
25 *
26 * You should have received a copy of the GNU Lesser General Public
27 * License along with this library; if not, write to the Free Software
28 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
29 *
30 * Alternatively, the contents of this file may be used under the terms
31 * of either the Mozilla Public License Version 1.1, found at
32 * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
33 * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
34 * (the "GPL"), in which case the provisions of the MPL or the GPL are
35 * applicable instead of those above. If you wish to allow use of your
36 * version of this file only under the terms of one of those two
37 * licenses (the MPL or the GPL) and not to allow others to use your
38 * version of this file under the LGPL, indicate your decision by
39 * deletingthe provisions above and replace them with the notice and
40 * other provisions required by the MPL or the GPL, as the case may be.
41 * If you do not delete the provisions above, a recipient may use your
42 * version of this file under any of the LGPL, the MPL or the GPL.
43 */
44
45 #include "third_party/blink/renderer/core/paint/paint_layer.h"
46
47 #include <limits>
48
49 #include "base/allocator/partition_allocator/partition_alloc.h"
50 #include "base/containers/adapters.h"
51 #include "third_party/blink/public/platform/task_type.h"
52 #include "third_party/blink/renderer/core/animation/scroll_timeline.h"
53 #include "third_party/blink/renderer/core/css/css_property_names.h"
54 #include "third_party/blink/renderer/core/css/pseudo_style_request.h"
55 #include "third_party/blink/renderer/core/dom/document.h"
56 #include "third_party/blink/renderer/core/dom/shadow_root.h"
57 #include "third_party/blink/renderer/core/frame/local_frame.h"
58 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
59 #include "third_party/blink/renderer/core/frame/settings.h"
60 #include "third_party/blink/renderer/core/html_names.h"
61 #include "third_party/blink/renderer/core/layout/fragmentainer_iterator.h"
62 #include "third_party/blink/renderer/core/layout/geometry/transform_state.h"
63 #include "third_party/blink/renderer/core/layout/hit_test_request.h"
64 #include "third_party/blink/renderer/core/layout/hit_test_result.h"
65 #include "third_party/blink/renderer/core/layout/hit_testing_transform_state.h"
66 #include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
67 #include "third_party/blink/renderer/core/layout/layout_flow_thread.h"
68 #include "third_party/blink/renderer/core/layout/layout_inline.h"
69 #include "third_party/blink/renderer/core/layout/layout_tree_as_text.h"
70 #include "third_party/blink/renderer/core/layout/layout_view.h"
71 #include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.h"
72 #include "third_party/blink/renderer/core/layout/svg/layout_svg_root.h"
73 #include "third_party/blink/renderer/core/page/page.h"
74 #include "third_party/blink/renderer/core/page/scrolling/sticky_position_scrolling_constraints.h"
75 #include "third_party/blink/renderer/core/paint/box_reflection_utils.h"
76 #include "third_party/blink/renderer/core/paint/clip_path_clipper.h"
77 #include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
78 #include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
79 #include "third_party/blink/renderer/core/paint/filter_effect_builder.h"
80 #include "third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h"
81 #include "third_party/blink/renderer/core/paint/object_paint_invalidator.h"
82 #include "third_party/blink/renderer/core/paint/paint_info.h"
83 #include "third_party/blink/renderer/core/paint/paint_layer_paint_order_iterator.h"
84 #include "third_party/blink/renderer/core/paint/paint_layer_painter.h"
85 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
86 #include "third_party/blink/renderer/core/style/reference_clip_path_operation.h"
87 #include "third_party/blink/renderer/core/style/shape_clip_path_operation.h"
88 #include "third_party/blink/renderer/platform/bindings/runtime_call_stats.h"
89 #include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
90 #include "third_party/blink/renderer/platform/geometry/float_point_3d.h"
91 #include "third_party/blink/renderer/platform/geometry/float_rect.h"
92 #include "third_party/blink/renderer/platform/geometry/length_functions.h"
93 #include "third_party/blink/renderer/platform/graphics/compositor_filter_operations.h"
94 #include "third_party/blink/renderer/platform/graphics/filters/filter.h"
95 #include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
96 #include "third_party/blink/renderer/platform/heap/heap.h"
97 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
98 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
99 #include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
100 #include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"
101 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
102
103 namespace blink {
104
105 namespace {
106
107 static CompositingQueryMode g_compositing_query_mode =
108 kCompositingQueriesAreOnlyAllowedInCertainDocumentLifecyclePhases;
109
110 #if defined(OS_LINUX) || defined(OS_BSD)
111 struct SameSizeAsPaintLayer : DisplayItemClient {
112 // The bit fields may fit into the machine word of DisplayItemClient which
113 // has only 8-bit data.
114 unsigned bit_fields1 : 24;
115 unsigned bit_fields2;
116 void* pointers[11];
117 #if DCHECK_IS_ON()
118 void* pointer;
119 #endif
120 LayoutUnit layout_units[4];
121 IntSize size;
122 Persistent<PaintLayerScrollableArea> scrollable_area;
123 CullRect previous_cull_rect;
124 };
125
126 static_assert(sizeof(PaintLayer) == sizeof(SameSizeAsPaintLayer),
127 "PaintLayer should stay small");
128 #endif
129
130 } // namespace
131
PaintLayerRareData()132 PaintLayerRareData::PaintLayerRareData()
133 : enclosing_pagination_layer(nullptr),
134 potential_compositing_reasons_from_style(CompositingReason::kNone),
135 potential_compositing_reasons_from_non_style(CompositingReason::kNone),
136 compositing_reasons(CompositingReason::kNone),
137 squashing_disallowed_reasons(SquashingDisallowedReason::kNone),
138 grouped_mapping(nullptr) {}
139
140 PaintLayerRareData::~PaintLayerRareData() = default;
141
PaintLayer(LayoutBoxModelObject & layout_object)142 PaintLayer::PaintLayer(LayoutBoxModelObject& layout_object)
143 : is_root_layer_(IsA<LayoutView>(layout_object)),
144 has_visible_content_(false),
145 needs_descendant_dependent_flags_update_(true),
146 needs_visual_overflow_recalc_(true),
147 has_visible_descendant_(false),
148 #if DCHECK_IS_ON()
149 // The root layer (LayoutView) does not need position update at start
150 // because its Location() is always 0.
151 needs_position_update_(!IsRootLayer()),
152 #endif
153 has3d_transformed_descendant_(false),
154 needs_ancestor_dependent_compositing_inputs_update_(
155 !RuntimeEnabledFeatures::CompositeAfterPaintEnabled()),
156 child_needs_compositing_inputs_update_(
157 !RuntimeEnabledFeatures::CompositeAfterPaintEnabled()),
158 has_compositing_descendant_(false),
159 should_isolate_composited_descendants_(false),
160 lost_grouped_mapping_(false),
161 self_needs_repaint_(false),
162 descendant_needs_repaint_(false),
163 previous_paint_result_(kFullyPainted),
164 needs_paint_phase_descendant_outlines_(false),
165 needs_paint_phase_float_(false),
166 has_descendant_with_clip_path_(false),
167 has_non_isolated_descendant_with_blend_mode_(false),
168 has_fixed_position_descendant_(false),
169 has_sticky_position_descendant_(false),
170 has_non_contained_absolute_position_descendant_(false),
171 has_stacked_descendant_in_current_stacking_context_(false),
172 self_painting_status_changed_(false),
173 filter_on_effect_node_dirty_(false),
174 backdrop_filter_on_effect_node_dirty_(false),
175 is_under_svg_hidden_container_(false),
176 descendant_has_direct_or_scrolling_compositing_reason_(false),
177 needs_compositing_reasons_update_(
178 !RuntimeEnabledFeatures::CompositeAfterPaintEnabled()),
179 descendant_may_need_compositing_requirements_update_(false),
180 needs_compositing_layer_assignment_(false),
181 descendant_needs_compositing_layer_assignment_(false),
182 has_self_painting_layer_descendant_(false),
183 needs_reorder_overlay_overflow_controls_(false),
184 #if DCHECK_IS_ON()
185 layer_list_mutation_allowed_(true),
186 #endif
187 layout_object_(layout_object),
188 parent_(nullptr),
189 previous_(nullptr),
190 next_(nullptr),
191 first_(nullptr),
192 last_(nullptr),
193 static_inline_position_(0),
194 static_block_position_(0),
195 ancestor_overflow_layer_(nullptr)
196 #if DCHECK_IS_ON()
197 ,
198 stacking_parent_(nullptr)
199 #endif
200 {
201 is_self_painting_layer_ = ShouldBeSelfPaintingLayer();
202
203 UpdateScrollableArea();
204 }
205
~PaintLayer()206 PaintLayer::~PaintLayer() {
207 if (rare_data_ && rare_data_->resource_info) {
208 const ComputedStyle& style = GetLayoutObject().StyleRef();
209 if (style.HasFilter())
210 style.Filter().RemoveClient(*rare_data_->resource_info);
211 if (auto* reference_clip =
212 DynamicTo<ReferenceClipPathOperation>(style.ClipPath()))
213 reference_clip->RemoveClient(*rare_data_->resource_info);
214 rare_data_->resource_info->ClearLayer();
215 }
216
217 if (GroupedMapping()) {
218 DisableCompositingQueryAsserts disabler;
219 SetGroupedMapping(nullptr, kInvalidateLayerAndRemoveFromMapping);
220 }
221
222 // Child layers will be deleted by their corresponding layout objects, so
223 // we don't need to delete them ourselves.
224 {
225 DisableCompositingQueryAsserts disabler;
226 ClearCompositedLayerMapping(true);
227 }
228
229 // Reset this flag before disposing scrollable_area_ to prevent
230 // PaintLayerScrollableArea::WillRemoveScrollbar() from dirtying the z-order
231 // list of the stacking context. If this layer is removed from the parent,
232 // the z-order list should have been invalidated in RemoveChild().
233 needs_reorder_overlay_overflow_controls_ = false;
234
235 if (scrollable_area_)
236 scrollable_area_->Dispose();
237
238 #if DCHECK_IS_ON()
239 // stacking_parent_ should be cleared because DirtyStackingContextZOrderLists
240 // should have been called.
241 if (!GetLayoutObject().DocumentBeingDestroyed())
242 DCHECK(!stacking_parent_);
243 #endif
244 }
245
DebugName() const246 String PaintLayer::DebugName() const {
247 return GetLayoutObject().DebugName();
248 }
249
OwnerNodeId() const250 DOMNodeId PaintLayer::OwnerNodeId() const {
251 return static_cast<const DisplayItemClient&>(GetLayoutObject()).OwnerNodeId();
252 }
253
VisualRect() const254 IntRect PaintLayer::VisualRect() const {
255 return layout_object_.FragmentsVisualRectBoundingBox();
256 }
257
Compositor() const258 PaintLayerCompositor* PaintLayer::Compositor() const {
259 if (!GetLayoutObject().View())
260 return nullptr;
261 return GetLayoutObject().View()->Compositor();
262 }
263
ContentChanged(ContentChangeType change_type)264 void PaintLayer::ContentChanged(ContentChangeType change_type) {
265 // updateLayerCompositingState will query compositingReasons for accelerated
266 // overflow scrolling. This is tripped by
267 // web_tests/compositing/content-changed-chicken-egg.html
268 DisableCompositingQueryAsserts disabler;
269
270 if (Compositor()) {
271 if (change_type == kCanvasChanged)
272 SetNeedsCompositingInputsUpdate();
273
274 if (change_type == kCanvasContextChanged) {
275 SetNeedsCompositingInputsUpdate();
276
277 // Although we're missing test coverage, we need to call
278 // GraphicsLayer::SetContentsToCcLayer with the new cc::Layer for this
279 // canvas. See http://crbug.com/349195
280 if (HasCompositedLayerMapping()) {
281 GetCompositedLayerMapping()->SetNeedsGraphicsLayerUpdate(
282 kGraphicsLayerUpdateSubtree);
283 }
284 }
285 }
286
287 if (CompositedLayerMapping* composited_layer_mapping =
288 GetCompositedLayerMapping())
289 composited_layer_mapping->ContentChanged(change_type);
290 }
291
PaintsWithFilters() const292 bool PaintLayer::PaintsWithFilters() const {
293 if (!GetLayoutObject().HasFilterInducingProperty())
294 return false;
295
296 if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
297 // https://code.google.com/p/chromium/issues/detail?id=343759
298 DisableCompositingQueryAsserts disabler;
299 return !GetCompositedLayerMapping() ||
300 GetCompositingState() != kPaintsIntoOwnBacking;
301 } else {
302 return true;
303 }
304 }
305
SubpixelAccumulation() const306 PhysicalOffset PaintLayer::SubpixelAccumulation() const {
307 return rare_data_ ? rare_data_->subpixel_accumulation : PhysicalOffset();
308 }
309
SetSubpixelAccumulation(const PhysicalOffset & accumulation)310 void PaintLayer::SetSubpixelAccumulation(const PhysicalOffset& accumulation) {
311 DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
312 if (rare_data_ || !accumulation.IsZero())
313 EnsureRareData().subpixel_accumulation = accumulation;
314 }
315
UpdateLayerPositionsAfterLayout()316 void PaintLayer::UpdateLayerPositionsAfterLayout() {
317 TRACE_EVENT0("blink,benchmark",
318 "PaintLayer::updateLayerPositionsAfterLayout");
319 RUNTIME_CALL_TIMER_SCOPE(
320 V8PerIsolateData::MainThreadIsolate(),
321 RuntimeCallStats::CounterId::kUpdateLayerPositionsAfterLayout);
322
323 ClearClipRects();
324 UpdateLayerPositionRecursive();
325
326 UpdatePaginationRecursive(EnclosingPaginationLayer());
327 }
328
UpdateLayerPositionRecursive()329 void PaintLayer::UpdateLayerPositionRecursive() {
330 auto old_location = location_without_position_offset_;
331 auto old_offset_for_in_flow_rel_position = OffsetForInFlowRelPosition();
332 UpdateLayerPosition();
333
334 if (location_without_position_offset_ != old_location) {
335 SetNeedsCompositingInputsUpdate();
336 } else {
337 // TODO(chrishtr): compute this invalidation in layout instead of here.
338 auto offset_for_in_flow_rel_position =
339 rare_data_ ? rare_data_->offset_for_in_flow_rel_position
340 : PhysicalOffset();
341 if (offset_for_in_flow_rel_position != old_offset_for_in_flow_rel_position)
342 SetNeedsCompositingInputsUpdate();
343 }
344
345 // Display-locked elements always have a PaintLayer, meaning that the
346 // PaintLayer traversal won't skip locked elements. Thus, we don't have to do
347 // an ancestor check, and simply skip iterating children when this element is
348 // locked for child layout.
349 if (GetLayoutObject().LayoutBlockedByDisplayLock(
350 DisplayLockLifecycleTarget::kChildren)) {
351 return;
352 }
353
354 for (PaintLayer* child = FirstChild(); child; child = child->NextSibling())
355 child->UpdateLayerPositionRecursive();
356 }
357
SticksToScroller() const358 bool PaintLayer::SticksToScroller() const {
359 if (!GetLayoutObject().StyleRef().HasStickyConstrainedPosition())
360 return false;
361 return AncestorOverflowLayer()->GetScrollableArea();
362 }
363
FixedToViewport() const364 bool PaintLayer::FixedToViewport() const {
365 if (GetLayoutObject().StyleRef().GetPosition() != EPosition::kFixed)
366 return false;
367 return GetLayoutObject().Container() == GetLayoutObject().View();
368 }
369
ScrollsWithRespectTo(const PaintLayer * other) const370 bool PaintLayer::ScrollsWithRespectTo(const PaintLayer* other) const {
371 if (FixedToViewport() != other->FixedToViewport())
372 return true;
373 // If either element sticks we cannot trivially determine that the layers do
374 // not scroll with respect to each other.
375 if (SticksToScroller() || other->SticksToScroller())
376 return true;
377 return AncestorScrollingLayer() != other->AncestorScrollingLayer();
378 }
379
IsAffectedByScrollOf(const PaintLayer * ancestor) const380 bool PaintLayer::IsAffectedByScrollOf(const PaintLayer* ancestor) const {
381 if (this == ancestor)
382 return false;
383
384 const PaintLayer* current_layer = this;
385 while (current_layer && current_layer != ancestor) {
386 bool ancestor_escaped = false;
387 const PaintLayer* container =
388 current_layer->ContainingLayer(ancestor, &ancestor_escaped);
389 if (ancestor_escaped)
390 return false;
391 // Workaround the bug that LayoutView is mistakenly considered
392 // a fixed-pos container.
393 if (current_layer->GetLayoutObject().IsFixedPositioned() &&
394 container->IsRootLayer())
395 return false;
396 current_layer = container;
397 }
398 return current_layer == ancestor;
399 }
400
UpdateTransformationMatrix()401 void PaintLayer::UpdateTransformationMatrix() {
402 if (TransformationMatrix* transform = Transform()) {
403 LayoutBox* box = GetLayoutBox();
404 DCHECK(box);
405 transform->MakeIdentity();
406 box->StyleRef().ApplyTransform(
407 *transform, box->Size(), ComputedStyle::kIncludeTransformOrigin,
408 ComputedStyle::kIncludeMotionPath,
409 ComputedStyle::kIncludeIndependentTransformProperties);
410 MakeMatrixRenderable(
411 *transform,
412 box->GetDocument().GetSettings()->GetAcceleratedCompositingEnabled());
413 }
414 }
415
UpdateTransform(const ComputedStyle * old_style,const ComputedStyle & new_style)416 void PaintLayer::UpdateTransform(const ComputedStyle* old_style,
417 const ComputedStyle& new_style) {
418 // It's possible for the old and new style transform data to be equivalent
419 // while hasTransform() differs, as it checks a number of conditions aside
420 // from just the matrix, including but not limited to animation state.
421 if (old_style && old_style->HasTransform() == new_style.HasTransform() &&
422 new_style.TransformDataEquivalent(*old_style)) {
423 return;
424 }
425
426 // LayoutObject::HasTransformRelatedProperty is also true when there is
427 // transform-style: preserve-3d or perspective set, so check style too.
428 bool has_transform = GetLayoutObject().HasTransformRelatedProperty() &&
429 new_style.HasTransform();
430 bool had3d_transform = Has3DTransform();
431
432 bool had_transform = Transform();
433 if (has_transform != had_transform) {
434 if (has_transform)
435 EnsureRareData().transform = std::make_unique<TransformationMatrix>();
436 else
437 rare_data_->transform.reset();
438
439 // PaintLayers with transforms act as clip rects roots, so clear the cached
440 // clip rects here.
441 ClearClipRects();
442 } else if (has_transform) {
443 ClearClipRects(kAbsoluteClipRectsIgnoringViewportClip);
444 }
445
446 UpdateTransformationMatrix();
447
448 if (had3d_transform != Has3DTransform()) {
449 SetNeedsCompositingInputsUpdateInternal();
450 MarkAncestorChainForFlagsUpdate();
451 }
452
453 if (LocalFrameView* frame_view = GetLayoutObject().GetDocument().View())
454 frame_view->SetNeedsUpdateGeometries();
455 }
456
CurrentTransform() const457 TransformationMatrix PaintLayer::CurrentTransform() const {
458 if (TransformationMatrix* transform = Transform())
459 return *transform;
460 return TransformationMatrix();
461 }
462
RenderableTransform(GlobalPaintFlags global_paint_flags) const463 TransformationMatrix PaintLayer::RenderableTransform(
464 GlobalPaintFlags global_paint_flags) const {
465 TransformationMatrix* transform = Transform();
466 if (!transform)
467 return TransformationMatrix();
468
469 if (global_paint_flags & kGlobalPaintFlattenCompositingLayers) {
470 TransformationMatrix matrix = *transform;
471 MakeMatrixRenderable(matrix, false /* flatten 3d */);
472 return matrix;
473 }
474
475 return *transform;
476 }
477
ConvertFromFlowThreadToVisualBoundingBoxInAncestor(const PaintLayer * ancestor_layer,PhysicalRect & rect) const478 void PaintLayer::ConvertFromFlowThreadToVisualBoundingBoxInAncestor(
479 const PaintLayer* ancestor_layer,
480 PhysicalRect& rect) const {
481 PaintLayer* pagination_layer = EnclosingPaginationLayer();
482 DCHECK(pagination_layer);
483 LayoutFlowThread& flow_thread =
484 ToLayoutFlowThread(pagination_layer->GetLayoutObject());
485
486 // First make the flow thread rectangle relative to the flow thread, not to
487 // |layer|.
488 PhysicalOffset offset_within_pagination_layer;
489 ConvertToLayerCoords(pagination_layer, offset_within_pagination_layer);
490 rect.Move(offset_within_pagination_layer);
491
492 // Then make the rectangle visual, relative to the fragmentation context.
493 // Split our box up into the actual fragment boxes that layout in the
494 // columns/pages and unite those together to get our true bounding box.
495 rect = PhysicalRectToBeNoop(
496 flow_thread.FragmentsBoundingBox(rect.ToLayoutRect()));
497
498 // Finally, make the visual rectangle relative to |ancestorLayer|.
499 if (ancestor_layer->EnclosingPaginationLayer() != pagination_layer) {
500 rect.Move(pagination_layer->VisualOffsetFromAncestor(ancestor_layer));
501 return;
502 }
503 // The ancestor layer is inside the same pagination layer as |layer|, so we
504 // need to subtract the visual distance from the ancestor layer to the
505 // pagination layer.
506 rect.Move(-ancestor_layer->VisualOffsetFromAncestor(pagination_layer));
507 }
508
UpdatePaginationRecursive(bool needs_pagination_update)509 void PaintLayer::UpdatePaginationRecursive(bool needs_pagination_update) {
510 if (rare_data_)
511 rare_data_->enclosing_pagination_layer = nullptr;
512
513 if (GetLayoutObject().IsLayoutFlowThread())
514 needs_pagination_update = true;
515
516 if (needs_pagination_update) {
517 // Each paginated layer has to paint on its own. There is no recurring into
518 // child layers. Each layer has to be checked individually and genuinely
519 // know if it is going to have to split itself up when painting only its
520 // contents (and not any other descendant layers). We track an
521 // enclosingPaginationLayer instead of using a simple bit, since we want to
522 // be able to get back to that layer easily.
523 if (LayoutFlowThread* containing_flow_thread =
524 GetLayoutObject().FlowThreadContainingBlock())
525 EnsureRareData().enclosing_pagination_layer =
526 containing_flow_thread->Layer();
527 }
528
529 // If this element prevents child painting, then we can skip updating
530 // pagination info, since it won't be used anyway.
531 if (GetLayoutObject().PaintBlockedByDisplayLock(
532 DisplayLockLifecycleTarget::kChildren)) {
533 return;
534 }
535
536 for (PaintLayer* child = FirstChild(); child; child = child->NextSibling())
537 child->UpdatePaginationRecursive(needs_pagination_update);
538 }
539
ClearPaginationRecursive()540 void PaintLayer::ClearPaginationRecursive() {
541 if (rare_data_)
542 rare_data_->enclosing_pagination_layer = nullptr;
543 for (PaintLayer* child = FirstChild(); child; child = child->NextSibling())
544 child->ClearPaginationRecursive();
545 }
546
TransformAncestorOrRoot() const547 const PaintLayer& PaintLayer::TransformAncestorOrRoot() const {
548 return TransformAncestor() ? *TransformAncestor()
549 : *GetLayoutObject().View()->Layer();
550 }
551
MapPointInPaintInvalidationContainerToBacking(const LayoutBoxModelObject & paint_invalidation_container,PhysicalOffset & point)552 void PaintLayer::MapPointInPaintInvalidationContainerToBacking(
553 const LayoutBoxModelObject& paint_invalidation_container,
554 PhysicalOffset& point) {
555 PaintLayer* paint_invalidation_layer = paint_invalidation_container.Layer();
556 if (!paint_invalidation_layer->GroupedMapping())
557 return;
558
559 GraphicsLayer* squashing_layer =
560 paint_invalidation_layer->GroupedMapping()->SquashingLayer();
561
562 PropertyTreeState source_state =
563 paint_invalidation_container.FirstFragment().LocalBorderBoxProperties();
564 PropertyTreeState dest_state = squashing_layer->GetPropertyTreeState();
565
566 // Move the point into the source_state transform space, map to dest_state
567 // transform space, then move into squashing layer state.
568 point += paint_invalidation_container.FirstFragment().PaintOffset();
569 point = PhysicalOffset::FromFloatPointRound(
570 GeometryMapper::SourceToDestinationProjection(source_state.Transform(),
571 dest_state.Transform())
572 .MapPoint(FloatPoint(point)));
573 point -= PhysicalOffset(squashing_layer->GetOffsetFromTransformNode());
574 }
575
MapQuadInPaintInvalidationContainerToBacking(const LayoutBoxModelObject & paint_invalidation_container,FloatQuad & quad)576 void PaintLayer::MapQuadInPaintInvalidationContainerToBacking(
577 const LayoutBoxModelObject& paint_invalidation_container,
578 FloatQuad& quad) {
579 PaintLayer* paint_invalidation_layer = paint_invalidation_container.Layer();
580 if (!paint_invalidation_layer->GroupedMapping())
581 return;
582
583 GraphicsLayer* squashing_layer =
584 paint_invalidation_layer->GroupedMapping()->SquashingLayer();
585
586 PropertyTreeState source_state =
587 paint_invalidation_container.FirstFragment().LocalBorderBoxProperties();
588 PropertyTreeState dest_state = squashing_layer->GetPropertyTreeState();
589
590 // Move the rect into the source_state transform space, map to dest_state
591 // transform space, then move into squashing layer state.
592 quad.Move(
593 FloatSize(paint_invalidation_container.FirstFragment().PaintOffset()));
594 GeometryMapper::SourceToDestinationProjection(source_state.Transform(),
595 dest_state.Transform())
596 .MapQuad(quad);
597 quad.Move(
598 -ToFloatSize(FloatPoint(squashing_layer->GetOffsetFromTransformNode())));
599 }
600
DirtyVisibleContentStatus()601 void PaintLayer::DirtyVisibleContentStatus() {
602 MarkAncestorChainForFlagsUpdate();
603 // Non-self-painting layers paint into their ancestor layer, and count as part
604 // of the "visible contents" of the parent, so we need to dirty it.
605 if (!IsSelfPaintingLayer())
606 Parent()->DirtyVisibleContentStatus();
607 }
608
MarkAncestorChainForFlagsUpdate(DescendantDependentFlagsUpdateFlag flag)609 void PaintLayer::MarkAncestorChainForFlagsUpdate(
610 DescendantDependentFlagsUpdateFlag flag) {
611 #if DCHECK_IS_ON()
612 DCHECK(flag == DoesNotNeedDescendantDependentUpdate ||
613 !layout_object_.GetDocument()
614 .View()
615 ->IsUpdatingDescendantDependentFlags());
616 #endif
617 for (PaintLayer* layer = this; layer; layer = layer->Parent()) {
618 if (layer->needs_descendant_dependent_flags_update_ &&
619 layer->GetLayoutObject().NeedsPaintPropertyUpdate())
620 break;
621 if (flag == NeedsDescendantDependentUpdate)
622 layer->needs_descendant_dependent_flags_update_ = true;
623 layer->GetLayoutObject().SetNeedsPaintPropertyUpdate();
624 }
625 }
626
UpdateDescendantDependentFlags()627 void PaintLayer::UpdateDescendantDependentFlags() {
628 if (needs_descendant_dependent_flags_update_) {
629 bool old_has_non_isolated_descendant_with_blend_mode =
630 has_non_isolated_descendant_with_blend_mode_;
631 has_visible_descendant_ = false;
632 has_non_isolated_descendant_with_blend_mode_ = false;
633 has_descendant_with_clip_path_ = false;
634 has_fixed_position_descendant_ = false;
635 has_sticky_position_descendant_ = false;
636 has_non_contained_absolute_position_descendant_ = false;
637 has_stacked_descendant_in_current_stacking_context_ = false;
638 has_self_painting_layer_descendant_ = false;
639
640 bool can_contain_abs =
641 GetLayoutObject().CanContainAbsolutePositionObjects();
642
643 for (PaintLayer* child = FirstChild(); child;
644 child = child->NextSibling()) {
645 const ComputedStyle& child_style = child->GetLayoutObject().StyleRef();
646
647 child->UpdateDescendantDependentFlags();
648
649 if (child->has_visible_content_ || child->has_visible_descendant_)
650 has_visible_descendant_ = true;
651
652 has_non_isolated_descendant_with_blend_mode_ |=
653 (!child_style.IsStackingContext() &&
654 child->HasNonIsolatedDescendantWithBlendMode()) ||
655 child_style.HasBlendMode();
656
657 has_descendant_with_clip_path_ |= child->HasDescendantWithClipPath() ||
658 child->GetLayoutObject().HasClipPath();
659
660 has_fixed_position_descendant_ |=
661 child->HasFixedPositionDescendant() ||
662 child_style.GetPosition() == EPosition::kFixed;
663 has_sticky_position_descendant_ |=
664 child->HasStickyPositionDescendant() ||
665 child_style.GetPosition() == EPosition::kSticky;
666
667 if (!can_contain_abs) {
668 has_non_contained_absolute_position_descendant_ |=
669 (child->HasNonContainedAbsolutePositionDescendant() ||
670 child_style.GetPosition() == EPosition::kAbsolute);
671 }
672
673 if (!has_stacked_descendant_in_current_stacking_context_) {
674 if (child_style.IsStacked()) {
675 has_stacked_descendant_in_current_stacking_context_ = true;
676 } else if (!child_style.IsStackingContext()) {
677 has_stacked_descendant_in_current_stacking_context_ =
678 child->has_stacked_descendant_in_current_stacking_context_;
679 }
680 }
681
682 has_self_painting_layer_descendant_ =
683 has_self_painting_layer_descendant_ ||
684 child->HasSelfPaintingLayerDescendant() ||
685 child->IsSelfPaintingLayer();
686 }
687
688 UpdateStackingNode();
689
690 if (old_has_non_isolated_descendant_with_blend_mode !=
691 static_cast<bool>(has_non_isolated_descendant_with_blend_mode_)) {
692 // The LayoutView DisplayItemClient owns painting of the background
693 // of the HTML element. When blending isolation of the HTML element's
694 // descendants change, there will be an addition or removal of an
695 // isolation effect node for the HTML element to add (or remove)
696 // isolated blending, and that case we need to re-paint the LayoutView.
697 if (Parent() && Parent()->IsRootLayer())
698 GetLayoutObject().View()->SetBackgroundNeedsFullPaintInvalidation();
699 GetLayoutObject().SetNeedsPaintPropertyUpdate();
700 }
701 needs_descendant_dependent_flags_update_ = false;
702
703 if (IsSelfPaintingLayer() && needs_visual_overflow_recalc_) {
704 auto old_visual_rect = GetLayoutObject().PhysicalVisualOverflowRect();
705 GetLayoutObject().RecalcVisualOverflow();
706 if (old_visual_rect != GetLayoutObject().PhysicalVisualOverflowRect()) {
707 SetNeedsCompositingInputsUpdateInternal();
708 MarkAncestorChainForFlagsUpdate(DoesNotNeedDescendantDependentUpdate);
709 }
710 }
711 needs_visual_overflow_recalc_ = false;
712 }
713
714 bool previously_has_visible_content = has_visible_content_;
715 if (GetLayoutObject().StyleRef().Visibility() == EVisibility::kVisible) {
716 has_visible_content_ = true;
717 } else {
718 // layer may be hidden but still have some visible content, check for this
719 has_visible_content_ = false;
720 LayoutObject* r = GetLayoutObject().SlowFirstChild();
721 while (r) {
722 if (r->StyleRef().Visibility() == EVisibility::kVisible &&
723 (!r->HasLayer() || !r->EnclosingLayer()->IsSelfPaintingLayer())) {
724 has_visible_content_ = true;
725 break;
726 }
727 LayoutObject* layout_object_first_child = r->SlowFirstChild();
728 if (layout_object_first_child &&
729 (!r->HasLayer() || !r->EnclosingLayer()->IsSelfPaintingLayer())) {
730 r = layout_object_first_child;
731 } else if (r->NextSibling()) {
732 r = r->NextSibling();
733 } else {
734 do {
735 r = r->Parent();
736 if (r == &GetLayoutObject())
737 r = nullptr;
738 } while (r && !r->NextSibling());
739 if (r)
740 r = r->NextSibling();
741 }
742 }
743 }
744
745 if (HasVisibleContent() != previously_has_visible_content) {
746 SetNeedsCompositingInputsUpdateInternal();
747 // We need to tell layout_object_ to recheck its rect because we
748 // pretend that invisible LayoutObjects have 0x0 rects. Changing
749 // visibility therefore changes our rect and we need to visit
750 // this LayoutObject during the PrePaintTreeWalk.
751 layout_object_.SetShouldCheckForPaintInvalidation();
752 }
753
754 Update3DTransformedDescendantStatus();
755 }
756
Update3DTransformedDescendantStatus()757 void PaintLayer::Update3DTransformedDescendantStatus() {
758 has3d_transformed_descendant_ = false;
759
760 // Transformed or preserve-3d descendants can only be in the z-order lists,
761 // not in the normal flow list, so we only need to check those.
762 PaintLayerPaintOrderIterator iterator(*this, kStackedChildren);
763 while (PaintLayer* child_layer = iterator.Next()) {
764 bool child_has3d = false;
765 // If the child lives in a 3d hierarchy, then the layer at the root of
766 // that hierarchy needs the m_has3DTransformedDescendant set.
767 if (child_layer->Preserves3D() &&
768 (child_layer->Has3DTransform() ||
769 child_layer->Has3DTransformedDescendant()))
770 child_has3d = true;
771 else if (child_layer->Has3DTransform())
772 child_has3d = true;
773
774 if (child_has3d) {
775 has3d_transformed_descendant_ = true;
776 break;
777 }
778 }
779 }
780
UpdateLayerPosition()781 void PaintLayer::UpdateLayerPosition() {
782 // LayoutBoxes will call UpdateSizeAndScrollingAfterLayout() from
783 // LayoutBox::UpdateAfterLayout, but LayoutInlines will still need to update
784 // their size.
785 if (GetLayoutObject().IsLayoutInline())
786 UpdateSize();
787 PhysicalOffset local_point;
788 if (LayoutBox* box = GetLayoutBox()) {
789 local_point += box->PhysicalLocation();
790 }
791
792 if (!GetLayoutObject().IsOutOfFlowPositioned() &&
793 !GetLayoutObject().IsColumnSpanAll()) {
794 // We must adjust our position by walking up the layout tree looking for the
795 // nearest enclosing object with a layer.
796 LayoutObject* curr = GetLayoutObject().Container();
797 while (curr && !curr->HasLayer()) {
798 if (curr->IsBox() && !curr->IsTableRow()) {
799 // Rows and cells share the same coordinate space (that of the section).
800 // Omit them when computing our xpos/ypos.
801 local_point += ToLayoutBox(curr)->PhysicalLocation();
802 }
803 curr = curr->Container();
804 }
805 if (curr && curr->IsTableRow()) {
806 // Put ourselves into the row coordinate space.
807 local_point -= ToLayoutBox(curr)->PhysicalLocation();
808 }
809 }
810
811 if (PaintLayer* containing_layer = ContainingLayer()) {
812 auto& container = containing_layer->GetLayoutObject();
813 if (GetLayoutObject().IsOutOfFlowPositioned() &&
814 container.IsLayoutInline() &&
815 container.CanContainOutOfFlowPositionedElement(
816 GetLayoutObject().StyleRef().GetPosition())) {
817 // Adjust offset for absolute under in-flow positioned inline.
818 PhysicalOffset offset =
819 ToLayoutInline(container).OffsetForInFlowPositionedInline(
820 ToLayoutBox(GetLayoutObject()));
821 local_point += offset;
822 }
823 }
824
825 if (GetLayoutObject().IsInFlowPositioned() &&
826 GetLayoutObject().IsRelPositioned()) {
827 auto new_offset = GetLayoutObject().OffsetForInFlowPosition();
828 if (rare_data_ || !new_offset.IsZero())
829 EnsureRareData().offset_for_in_flow_rel_position = new_offset;
830 } else if (rare_data_) {
831 rare_data_->offset_for_in_flow_rel_position = PhysicalOffset();
832 }
833 location_without_position_offset_ = local_point;
834
835 #if DCHECK_IS_ON()
836 needs_position_update_ = false;
837 #endif
838 }
839
UpdateSize()840 bool PaintLayer::UpdateSize() {
841 LayoutSize old_size = size_;
842 if (IsRootLayer()) {
843 size_ = LayoutSize(GetLayoutObject().GetDocument().View()->Size());
844 } else if (GetLayoutObject().IsInline() &&
845 GetLayoutObject().IsLayoutInline()) {
846 LayoutInline& inline_flow = ToLayoutInline(GetLayoutObject());
847 IntRect line_box = EnclosingIntRect(inline_flow.PhysicalLinesBoundingBox());
848 size_ = LayoutSize(line_box.Size());
849 } else if (LayoutBox* box = GetLayoutBox()) {
850 size_ = box->Size();
851 }
852 if (old_size != size_)
853 SetNeedsCompositingInputsUpdate();
854
855 return old_size != size_;
856 }
857
UpdateSizeAndScrollingAfterLayout()858 void PaintLayer::UpdateSizeAndScrollingAfterLayout() {
859 bool did_resize = UpdateSize();
860 if (RequiresScrollableArea()) {
861 DCHECK(scrollable_area_);
862 scrollable_area_->UpdateAfterLayout();
863 if (did_resize)
864 scrollable_area_->VisibleSizeChanged();
865 }
866 }
867
PerspectiveOrigin() const868 FloatPoint PaintLayer::PerspectiveOrigin() const {
869 if (!GetLayoutObject().HasTransformRelatedProperty())
870 return FloatPoint();
871
872 const LayoutRect border_box = ToLayoutBox(GetLayoutObject()).BorderBoxRect();
873 const ComputedStyle& style = GetLayoutObject().StyleRef();
874
875 return FloatPointForLengthPoint(style.PerspectiveOrigin(),
876 FloatSize(border_box.Size()));
877 }
878
ContainingLayer(const PaintLayer * ancestor,bool * skipped_ancestor) const879 PaintLayer* PaintLayer::ContainingLayer(const PaintLayer* ancestor,
880 bool* skipped_ancestor) const {
881 // If we have specified an ancestor, surely the caller needs to know whether
882 // we skipped it.
883 DCHECK(!ancestor || skipped_ancestor);
884 if (skipped_ancestor)
885 *skipped_ancestor = false;
886
887 LayoutObject& layout_object = GetLayoutObject();
888 if (layout_object.IsOutOfFlowPositioned()) {
889 auto can_contain_this_layer =
890 layout_object.IsFixedPositioned()
891 ? &LayoutObject::CanContainFixedPositionObjects
892 : &LayoutObject::CanContainAbsolutePositionObjects;
893
894 PaintLayer* curr = Parent();
895 while (curr && !((&curr->GetLayoutObject())->*can_contain_this_layer)()) {
896 if (skipped_ancestor && curr == ancestor)
897 *skipped_ancestor = true;
898 curr = curr->Parent();
899 }
900 return curr;
901 }
902
903 // If the parent layer is not a block, there might be floating objects
904 // between this layer (included) and parent layer which need to escape the
905 // inline parent to find the actual containing layer through the containing
906 // block chain.
907 // Column span need to find the containing layer through its containing block.
908 if ((!Parent() || Parent()->GetLayoutObject().IsLayoutBlock()) &&
909 !layout_object.IsColumnSpanAll())
910 return Parent();
911
912 // This is a universal approach to find containing layer, but is slower than
913 // the earlier code.
914 base::Optional<LayoutObject::AncestorSkipInfo> skip_info;
915 if (skipped_ancestor)
916 skip_info.emplace(&ancestor->GetLayoutObject());
917 auto* object = &layout_object;
918 while (auto* container =
919 object->Container(skipped_ancestor ? &*skip_info : nullptr)) {
920 if (skipped_ancestor && skip_info->AncestorSkipped())
921 *skipped_ancestor = true;
922 if (container->HasLayer())
923 return ToLayoutBoxModelObject(container)->Layer();
924 object = container;
925 }
926 return nullptr;
927 }
928
ComputeOffsetFromAncestor(const PaintLayer & ancestor_layer) const929 PhysicalOffset PaintLayer::ComputeOffsetFromAncestor(
930 const PaintLayer& ancestor_layer) const {
931 const LayoutBoxModelObject& ancestor_object =
932 ancestor_layer.GetLayoutObject();
933 PhysicalOffset result = GetLayoutObject().LocalToAncestorPoint(
934 PhysicalOffset(), &ancestor_object, kIgnoreTransforms);
935 if (ancestor_object.UsesCompositedScrolling()) {
936 result += PhysicalOffset(
937 ToLayoutBox(ancestor_object).PixelSnappedScrolledContentOffset());
938 }
939 return result;
940 }
941
CompositingContainer() const942 PaintLayer* PaintLayer::CompositingContainer() const {
943 if (IsReplacedNormalFlowStacking())
944 return Parent();
945 if (!GetLayoutObject().StyleRef().IsStacked()) {
946 if (IsSelfPaintingLayer() || GetLayoutObject().IsColumnSpanAll())
947 return Parent();
948 return ContainingLayer();
949 }
950 return AncestorStackingContext();
951 }
952
AncestorStackingContext() const953 PaintLayer* PaintLayer::AncestorStackingContext() const {
954 for (PaintLayer* ancestor = Parent(); ancestor;
955 ancestor = ancestor->Parent()) {
956 if (ancestor->GetLayoutObject().StyleRef().IsStackingContext())
957 return ancestor;
958 }
959 return nullptr;
960 }
961
IsPaintInvalidationContainer() const962 bool PaintLayer::IsPaintInvalidationContainer() const {
963 return GetCompositingState() == kPaintsIntoOwnBacking ||
964 GetCompositingState() == kPaintsIntoGroupedBacking;
965 }
966
967 // Note: enclosingCompositingLayer does not include squashed layers. Compositing
968 // stacking children of squashed layers receive graphics layers that are
969 // parented to the compositing ancestor of the squashed layer.
EnclosingLayerWithCompositedLayerMapping(IncludeSelfOrNot include_self) const970 PaintLayer* PaintLayer::EnclosingLayerWithCompositedLayerMapping(
971 IncludeSelfOrNot include_self) const {
972 DCHECK(IsAllowedToQueryCompositingState());
973
974 if ((include_self == kIncludeSelf) &&
975 GetCompositingState() != kNotComposited &&
976 GetCompositingState() != kPaintsIntoGroupedBacking)
977 return const_cast<PaintLayer*>(this);
978
979 for (PaintLayer* curr = CompositingContainer(); curr;
980 curr = curr->CompositingContainer()) {
981 if (curr->GetCompositingState() != kNotComposited &&
982 curr->GetCompositingState() != kPaintsIntoGroupedBacking)
983 return curr;
984 }
985
986 return nullptr;
987 }
988
989 // Return the enclosingCompositedLayerForPaintInvalidation for the given Layer
990 // including crossing frame boundaries.
991 PaintLayer*
EnclosingLayerForPaintInvalidationCrossingFrameBoundaries() const992 PaintLayer::EnclosingLayerForPaintInvalidationCrossingFrameBoundaries() const {
993 const PaintLayer* layer = this;
994 PaintLayer* composited_layer = nullptr;
995 while (!composited_layer) {
996 composited_layer = layer->EnclosingLayerForPaintInvalidation();
997 if (!composited_layer) {
998 CHECK(layer->GetLayoutObject().GetFrame());
999 auto* owner = layer->GetLayoutObject().GetFrame()->OwnerLayoutObject();
1000 if (!owner)
1001 break;
1002 layer = owner->EnclosingLayer();
1003 }
1004 }
1005 return composited_layer;
1006 }
1007
EnclosingLayerForPaintInvalidation() const1008 PaintLayer* PaintLayer::EnclosingLayerForPaintInvalidation() const {
1009 DCHECK(IsAllowedToQueryCompositingState());
1010
1011 if (IsPaintInvalidationContainer())
1012 return const_cast<PaintLayer*>(this);
1013
1014 for (PaintLayer* curr = CompositingContainer(); curr;
1015 curr = curr->CompositingContainer()) {
1016 if (curr->IsPaintInvalidationContainer())
1017 return curr;
1018 }
1019
1020 return nullptr;
1021 }
1022
SetNeedsCompositingInputsUpdate(bool mark_ancestor_flags)1023 void PaintLayer::SetNeedsCompositingInputsUpdate(bool mark_ancestor_flags) {
1024 SetNeedsCompositingInputsUpdateInternal();
1025
1026 // TODO(chrishtr): These are a bit of a heavy hammer, because not all
1027 // things which require compositing inputs update require a descendant-
1028 // dependent flags update. Reduce call sites after CAP launch allows
1029 /// removal of CompositingInputsUpdater.
1030 if (mark_ancestor_flags)
1031 MarkAncestorChainForFlagsUpdate(NeedsDescendantDependentUpdate);
1032 }
1033
SetNeedsVisualOverflowRecalc()1034 void PaintLayer::SetNeedsVisualOverflowRecalc() {
1035 DCHECK(IsSelfPaintingLayer());
1036 needs_visual_overflow_recalc_ = true;
1037 MarkAncestorChainForFlagsUpdate();
1038 }
1039
SetChildNeedsCompositingInputsUpdateUpToAncestor(PaintLayer * ancestor)1040 void PaintLayer::SetChildNeedsCompositingInputsUpdateUpToAncestor(
1041 PaintLayer* ancestor) {
1042 DCHECK(ancestor);
1043
1044 for (auto* layer = this; layer && layer != ancestor; layer = layer->Parent())
1045 layer->child_needs_compositing_inputs_update_ = true;
1046
1047 ancestor->child_needs_compositing_inputs_update_ = true;
1048 }
1049
SetNeedsCompositingInputsUpdateInternal()1050 void PaintLayer::SetNeedsCompositingInputsUpdateInternal() {
1051 if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
1052 return;
1053
1054 needs_ancestor_dependent_compositing_inputs_update_ = true;
1055
1056 // We might call this function on a locked element. Now, locked elements might
1057 // have a persistent dirty child bit, meaning that the below loop won't mark
1058 // the breakcrumb bit further up the chain (since this element appears to
1059 // already have a breadcrumb). However, since the element itself needs an
1060 // ancestor dependent update, we need to force the propagation at least one
1061 // level to the parent. This ensures that the real dirty bit
1062 // (|needs_ancestor_dependent_compositing_inputs_update_|) can be discovered
1063 // by the compositing update walk.
1064 bool child_flag_may_persist_after_update =
1065 GetLayoutObject().PrePaintBlockedByDisplayLock(
1066 DisplayLockLifecycleTarget::kChildren);
1067
1068 PaintLayer* initial_layer = child_needs_compositing_inputs_update_ &&
1069 child_flag_may_persist_after_update
1070 ? Parent()
1071 : this;
1072
1073 PaintLayer* last_ancestor = nullptr;
1074 for (PaintLayer* current = initial_layer;
1075 current && !current->child_needs_compositing_inputs_update_;
1076 current = current->Parent()) {
1077 last_ancestor = current;
1078 current->child_needs_compositing_inputs_update_ = true;
1079 if (Compositor() &&
1080 (current != initial_layer ||
1081 !current->GetLayoutObject().IsStickyPositioned()) &&
1082 current->GetLayoutObject().ShouldApplyStrictContainment())
1083 break;
1084 }
1085
1086 if (Compositor()) {
1087 Compositor()->SetNeedsCompositingUpdate(
1088 kCompositingUpdateAfterCompositingInputChange);
1089
1090 if (last_ancestor)
1091 Compositor()->UpdateCompositingInputsRoot(last_ancestor);
1092 }
1093 }
1094
UpdateAncestorDependentCompositingInputs(const AncestorDependentCompositingInputs & compositing_inputs)1095 void PaintLayer::UpdateAncestorDependentCompositingInputs(
1096 const AncestorDependentCompositingInputs& compositing_inputs) {
1097 DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
1098 EnsureAncestorDependentCompositingInputs() = compositing_inputs;
1099 needs_ancestor_dependent_compositing_inputs_update_ = false;
1100 }
1101
ClearChildNeedsCompositingInputsUpdate()1102 void PaintLayer::ClearChildNeedsCompositingInputsUpdate() {
1103 DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
1104 DCHECK(!NeedsCompositingInputsUpdate());
1105 child_needs_compositing_inputs_update_ = false;
1106 }
1107
HasNonIsolatedDescendantWithBlendMode() const1108 bool PaintLayer::HasNonIsolatedDescendantWithBlendMode() const {
1109 DCHECK(!needs_descendant_dependent_flags_update_);
1110 if (has_non_isolated_descendant_with_blend_mode_)
1111 return true;
1112 if (GetLayoutObject().IsSVGRoot())
1113 return ToLayoutSVGRoot(GetLayoutObject())
1114 .HasNonIsolatedBlendingDescendants();
1115 return false;
1116 }
1117
SetCompositingReasons(CompositingReasons reasons,CompositingReasons mask)1118 void PaintLayer::SetCompositingReasons(CompositingReasons reasons,
1119 CompositingReasons mask) {
1120 CompositingReasons old_reasons =
1121 rare_data_ ? rare_data_->compositing_reasons : CompositingReason::kNone;
1122 if ((old_reasons & mask) == (reasons & mask))
1123 return;
1124 CompositingReasons new_reasons = (reasons & mask) | (old_reasons & ~mask);
1125 if (rare_data_ || new_reasons != CompositingReason::kNone)
1126 EnsureRareData().compositing_reasons = new_reasons;
1127 }
1128
SetSquashingDisallowedReasons(SquashingDisallowedReasons reasons)1129 void PaintLayer::SetSquashingDisallowedReasons(
1130 SquashingDisallowedReasons reasons) {
1131 SquashingDisallowedReasons old_reasons =
1132 rare_data_ ? rare_data_->squashing_disallowed_reasons
1133 : SquashingDisallowedReason::kNone;
1134 if (old_reasons == reasons)
1135 return;
1136 if (rare_data_ || reasons != SquashingDisallowedReason::kNone)
1137 EnsureRareData().squashing_disallowed_reasons = reasons;
1138 }
1139
SetHasCompositingDescendant(bool has_compositing_descendant)1140 void PaintLayer::SetHasCompositingDescendant(bool has_compositing_descendant) {
1141 if (has_compositing_descendant_ ==
1142 static_cast<unsigned>(has_compositing_descendant))
1143 return;
1144
1145 has_compositing_descendant_ = has_compositing_descendant;
1146
1147 if (HasCompositedLayerMapping())
1148 GetCompositedLayerMapping()->SetNeedsGraphicsLayerUpdate(
1149 kGraphicsLayerUpdateLocal);
1150 }
1151
SetShouldIsolateCompositedDescendants(bool should_isolate_composited_descendants)1152 void PaintLayer::SetShouldIsolateCompositedDescendants(
1153 bool should_isolate_composited_descendants) {
1154 if (should_isolate_composited_descendants_ ==
1155 static_cast<unsigned>(should_isolate_composited_descendants))
1156 return;
1157
1158 should_isolate_composited_descendants_ =
1159 should_isolate_composited_descendants;
1160
1161 if (HasCompositedLayerMapping())
1162 GetCompositedLayerMapping()->SetNeedsGraphicsLayerUpdate(
1163 kGraphicsLayerUpdateLocal);
1164 }
1165
HasAncestorWithFilterThatMovesPixels() const1166 bool PaintLayer::HasAncestorWithFilterThatMovesPixels() const {
1167 for (const PaintLayer* curr = this; curr; curr = curr->Parent()) {
1168 if (curr->HasFilterThatMovesPixels())
1169 return true;
1170 }
1171 return false;
1172 }
1173
operator new(size_t sz)1174 void* PaintLayer::operator new(size_t sz) {
1175 return WTF::Partitions::LayoutPartition()->Alloc(
1176 sz, WTF_HEAP_PROFILER_TYPE_NAME(PaintLayer));
1177 }
1178
operator delete(void * ptr)1179 void PaintLayer::operator delete(void* ptr) {
1180 base::PartitionFree(ptr);
1181 }
1182
AddChild(PaintLayer * child,PaintLayer * before_child)1183 void PaintLayer::AddChild(PaintLayer* child, PaintLayer* before_child) {
1184 #if DCHECK_IS_ON()
1185 DCHECK(layer_list_mutation_allowed_);
1186 #endif
1187
1188 PaintLayer* prev_sibling =
1189 before_child ? before_child->PreviousSibling() : LastChild();
1190 if (prev_sibling) {
1191 child->SetPreviousSibling(prev_sibling);
1192 prev_sibling->SetNextSibling(child);
1193 DCHECK_NE(prev_sibling, child);
1194 } else {
1195 SetFirstChild(child);
1196 }
1197
1198 if (before_child) {
1199 before_child->SetPreviousSibling(child);
1200 child->SetNextSibling(before_child);
1201 DCHECK_NE(before_child, child);
1202 } else {
1203 SetLastChild(child);
1204 }
1205
1206 child->parent_ = this;
1207
1208 // The ancestor overflow layer is calculated during compositing inputs update
1209 // and should not be set yet.
1210 CHECK(!child->AncestorOverflowLayer());
1211
1212 SetNeedsCompositingInputsUpdate();
1213
1214 const ComputedStyle& child_style = child->GetLayoutObject().StyleRef();
1215
1216 if (Compositor()) {
1217 if (!child_style.IsStacked() && !GetLayoutObject().DocumentBeingDestroyed())
1218 Compositor()->SetNeedsCompositingUpdate(kCompositingUpdateRebuildTree);
1219 }
1220
1221 if (child_style.IsStacked() || child->FirstChild()) {
1222 // Dirty the z-order list in which we are contained. The
1223 // ancestorStackingContextNode() can be null in the case where we're
1224 // building up generated content layers. This is ok, since the lists will
1225 // start off dirty in that case anyway.
1226 child->DirtyStackingContextZOrderLists();
1227 }
1228
1229 // Non-self-painting children paint into this layer, so the visible contents
1230 // status of this layer is affected.
1231 if (!child->IsSelfPaintingLayer())
1232 DirtyVisibleContentStatus();
1233
1234 MarkAncestorChainForFlagsUpdate();
1235
1236 // Need to force requirements update, due to change of stacking order.
1237 SetNeedsCompositingRequirementsUpdate();
1238
1239 child->SetNeedsRepaint();
1240 }
1241
RemoveChild(PaintLayer * old_child)1242 void PaintLayer::RemoveChild(PaintLayer* old_child) {
1243 #if DCHECK_IS_ON()
1244 DCHECK(layer_list_mutation_allowed_);
1245 #endif
1246
1247 old_child->MarkCompositingContainerChainForNeedsRepaint();
1248
1249 if (old_child->PreviousSibling())
1250 old_child->PreviousSibling()->SetNextSibling(old_child->NextSibling());
1251 if (old_child->NextSibling())
1252 old_child->NextSibling()->SetPreviousSibling(old_child->PreviousSibling());
1253
1254 if (first_ == old_child)
1255 first_ = old_child->NextSibling();
1256 if (last_ == old_child)
1257 last_ = old_child->PreviousSibling();
1258
1259 const ComputedStyle& old_child_style =
1260 old_child->GetLayoutObject().StyleRef();
1261
1262 if (!GetLayoutObject().DocumentBeingDestroyed()) {
1263 if (Compositor()) {
1264 if (!old_child_style.IsStacked())
1265 Compositor()->SetNeedsCompositingUpdate(kCompositingUpdateRebuildTree);
1266
1267 if (Compositor()->GetCompositingInputsRoot() == old_child)
1268 Compositor()->ClearCompositingInputsRoot();
1269 }
1270 // Dirty the z-order list in which we are contained.
1271 old_child->DirtyStackingContextZOrderLists();
1272 SetNeedsCompositingInputsUpdate();
1273 }
1274
1275 if (GetLayoutObject().StyleRef().Visibility() != EVisibility::kVisible)
1276 DirtyVisibleContentStatus();
1277
1278 old_child->SetPreviousSibling(nullptr);
1279 old_child->SetNextSibling(nullptr);
1280 old_child->parent_ = nullptr;
1281
1282 // Remove any ancestor overflow layers which descended into the removed child.
1283 if (old_child->AncestorOverflowLayer())
1284 old_child->RemoveAncestorOverflowLayer(old_child->AncestorOverflowLayer());
1285
1286 if (old_child->has_visible_content_ || old_child->has_visible_descendant_)
1287 MarkAncestorChainForFlagsUpdate();
1288
1289 if (old_child->EnclosingPaginationLayer())
1290 old_child->ClearPaginationRecursive();
1291 }
1292
ClearClipRects(ClipRectsCacheSlot cache_slot)1293 void PaintLayer::ClearClipRects(ClipRectsCacheSlot cache_slot) {
1294 Clipper(GeometryMapperOption::kDoNotUseGeometryMapper)
1295 .ClearClipRectsIncludingDescendants(cache_slot);
1296 }
1297
RemoveOnlyThisLayerAfterStyleChange(const ComputedStyle * old_style)1298 void PaintLayer::RemoveOnlyThisLayerAfterStyleChange(
1299 const ComputedStyle* old_style) {
1300 if (!parent_)
1301 return;
1302
1303 if (old_style && old_style->IsStacked())
1304 DirtyStackingContextZOrderLists();
1305
1306 bool did_set_paint_invalidation = false;
1307 if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
1308 // Destructing PaintLayer would cause CompositedLayerMapping and composited
1309 // layers to be destructed and detach from layer tree immediately. Layers
1310 // could have dangling scroll/clip parent if compositing update were
1311 // omitted.
1312 if (LocalFrameView* frame_view = layout_object_.GetDocument().View())
1313 frame_view->SetNeedsForcedCompositingUpdate();
1314
1315 // We need the current compositing status.
1316 DisableCompositingQueryAsserts disabler;
1317 if (IsPaintInvalidationContainer()) {
1318 // Our children will be reparented and contained by a new paint
1319 // invalidation container, so need paint invalidation. CompositingUpdate
1320 // can't see this layer (which has been removed) so won't do this for us.
1321 ObjectPaintInvalidator(GetLayoutObject())
1322 .InvalidatePaintIncludingNonCompositingDescendants();
1323 GetLayoutObject().SetSubtreeShouldDoFullPaintInvalidation();
1324 did_set_paint_invalidation = true;
1325 }
1326 }
1327
1328 if (!did_set_paint_invalidation && IsSelfPaintingLayer()) {
1329 if (PaintLayer* enclosing_self_painting_layer =
1330 parent_->EnclosingSelfPaintingLayer())
1331 enclosing_self_painting_layer->MergeNeedsPaintPhaseFlagsFrom(*this);
1332 }
1333
1334 ClearClipRects();
1335
1336 PaintLayer* next_sib = NextSibling();
1337
1338 // Now walk our kids and reattach them to our parent.
1339 PaintLayer* current = first_;
1340 while (current) {
1341 PaintLayer* next = current->NextSibling();
1342 RemoveChild(current);
1343 parent_->AddChild(current, next_sib);
1344
1345 // FIXME: We should call a specialized version of this function.
1346 current->UpdateLayerPositionsAfterLayout();
1347 current = next;
1348 }
1349
1350 // Remove us from the parent.
1351 parent_->RemoveChild(this);
1352 layout_object_.DestroyLayer();
1353 }
1354
InsertOnlyThisLayerAfterStyleChange()1355 void PaintLayer::InsertOnlyThisLayerAfterStyleChange() {
1356 if (!parent_ && GetLayoutObject().Parent()) {
1357 // We need to connect ourselves when our layoutObject() has a parent.
1358 // Find our enclosingLayer and add ourselves.
1359 PaintLayer* parent_layer = GetLayoutObject().Parent()->EnclosingLayer();
1360 DCHECK(parent_layer);
1361 PaintLayer* before_child = GetLayoutObject().Parent()->FindNextLayer(
1362 parent_layer, &GetLayoutObject());
1363 parent_layer->AddChild(this, before_child);
1364 }
1365
1366 // Remove all descendant layers from the hierarchy and add them to the new
1367 // position.
1368 for (LayoutObject* curr = GetLayoutObject().SlowFirstChild(); curr;
1369 curr = curr->NextSibling())
1370 curr->MoveLayers(parent_, this);
1371
1372 // If the previous paint invalidation container is not a stacking context and
1373 // this object is stacked content, creating this layer may cause this object
1374 // and its descendants to change paint invalidation container.
1375 bool did_set_paint_invalidation = false;
1376 if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
1377 !IsA<LayoutView>(GetLayoutObject()) && GetLayoutObject().IsRooted() &&
1378 GetLayoutObject().StyleRef().IsStacked()) {
1379 const LayoutBoxModelObject& previous_paint_invalidation_container =
1380 GetLayoutObject().Parent()->ContainerForPaintInvalidation();
1381 if (!previous_paint_invalidation_container.StyleRef().IsStackingContext()) {
1382 ObjectPaintInvalidator(GetLayoutObject())
1383 .InvalidatePaintIncludingNonSelfPaintingLayerDescendants();
1384 // Set needsRepaint along the original compositingContainer chain.
1385 GetLayoutObject().Parent()->EnclosingLayer()->SetNeedsRepaint();
1386 did_set_paint_invalidation = true;
1387 }
1388 }
1389
1390 if (!did_set_paint_invalidation && IsSelfPaintingLayer() && parent_) {
1391 if (PaintLayer* enclosing_self_painting_layer =
1392 parent_->EnclosingSelfPaintingLayer())
1393 MergeNeedsPaintPhaseFlagsFrom(*enclosing_self_painting_layer);
1394 }
1395
1396 // Clear out all the clip rects.
1397 ClearClipRects();
1398 }
1399
1400 // Returns the layer reached on the walk up towards the ancestor.
AccumulateOffsetTowardsAncestor(const PaintLayer * layer,const PaintLayer * ancestor_layer,PhysicalOffset & location)1401 static inline const PaintLayer* AccumulateOffsetTowardsAncestor(
1402 const PaintLayer* layer,
1403 const PaintLayer* ancestor_layer,
1404 PhysicalOffset& location) {
1405 DCHECK(ancestor_layer != layer);
1406
1407 const LayoutBoxModelObject& layout_object = layer->GetLayoutObject();
1408
1409 if (layout_object.IsFixedPositioned() &&
1410 (!ancestor_layer || ancestor_layer == layout_object.View()->Layer())) {
1411 // If the fixed layer's container is the root, just add in the offset of the
1412 // view. We can obtain this by calling localToAbsolute() on the LayoutView.
1413 location +=
1414 layout_object.LocalToAbsolutePoint(PhysicalOffset(), kIgnoreTransforms);
1415 return ancestor_layer;
1416 }
1417
1418 bool found_ancestor_first = false;
1419 PaintLayer* containing_layer =
1420 ancestor_layer
1421 ? layer->ContainingLayer(ancestor_layer, &found_ancestor_first)
1422 : layer->ContainingLayer(ancestor_layer, nullptr);
1423
1424 if (found_ancestor_first) {
1425 // Found ancestorLayer before the containing layer, so compute offset of
1426 // both relative to the container and subtract.
1427 PhysicalOffset this_coords;
1428 layer->ConvertToLayerCoords(containing_layer, this_coords);
1429
1430 PhysicalOffset ancestor_coords;
1431 ancestor_layer->ConvertToLayerCoords(containing_layer, ancestor_coords);
1432
1433 location += (this_coords - ancestor_coords);
1434 return ancestor_layer;
1435 }
1436
1437 if (!containing_layer)
1438 return nullptr;
1439
1440 location += layer->LocationWithoutPositionOffset();
1441 if (layer->GetLayoutObject().IsRelPositioned()) {
1442 location += layer->OffsetForInFlowRelPosition();
1443 } else if (layer->GetLayoutObject().IsInFlowPositioned()) {
1444 location += layer->GetLayoutObject().OffsetForInFlowPosition();
1445 }
1446 location -=
1447 PhysicalOffset(containing_layer->PixelSnappedScrolledContentOffset());
1448
1449 return containing_layer;
1450 }
1451
ConvertToLayerCoords(const PaintLayer * ancestor_layer,PhysicalOffset & location) const1452 void PaintLayer::ConvertToLayerCoords(const PaintLayer* ancestor_layer,
1453 PhysicalOffset& location) const {
1454 if (ancestor_layer == this)
1455 return;
1456
1457 const PaintLayer* curr_layer = this;
1458 while (curr_layer && curr_layer != ancestor_layer)
1459 curr_layer =
1460 AccumulateOffsetTowardsAncestor(curr_layer, ancestor_layer, location);
1461 }
1462
ConvertToLayerCoords(const PaintLayer * ancestor_layer,PhysicalRect & rect) const1463 void PaintLayer::ConvertToLayerCoords(const PaintLayer* ancestor_layer,
1464 PhysicalRect& rect) const {
1465 PhysicalOffset delta;
1466 ConvertToLayerCoords(ancestor_layer, delta);
1467 rect.Move(delta);
1468 }
1469
VisualOffsetFromAncestor(const PaintLayer * ancestor_layer,PhysicalOffset offset) const1470 PhysicalOffset PaintLayer::VisualOffsetFromAncestor(
1471 const PaintLayer* ancestor_layer,
1472 PhysicalOffset offset) const {
1473 if (ancestor_layer == this)
1474 return offset;
1475 PaintLayer* pagination_layer = EnclosingPaginationLayer();
1476 if (pagination_layer == this)
1477 pagination_layer = Parent()->EnclosingPaginationLayer();
1478 if (!pagination_layer) {
1479 ConvertToLayerCoords(ancestor_layer, offset);
1480 return offset;
1481 }
1482
1483 LayoutFlowThread& flow_thread =
1484 ToLayoutFlowThread(pagination_layer->GetLayoutObject());
1485 ConvertToLayerCoords(pagination_layer, offset);
1486 offset = PhysicalOffsetToBeNoop(
1487 flow_thread.FlowThreadPointToVisualPoint(offset.ToLayoutPoint()));
1488 if (ancestor_layer == pagination_layer)
1489 return offset;
1490
1491 if (ancestor_layer->EnclosingPaginationLayer() != pagination_layer) {
1492 offset += pagination_layer->VisualOffsetFromAncestor(ancestor_layer);
1493 } else {
1494 // The ancestor layer is also inside the pagination layer, so we need to
1495 // subtract the visual distance from the ancestor layer to the pagination
1496 // layer.
1497 offset -= ancestor_layer->VisualOffsetFromAncestor(pagination_layer);
1498 }
1499 return offset;
1500 }
1501
DidUpdateScrollsOverflow()1502 void PaintLayer::DidUpdateScrollsOverflow() {
1503 UpdateSelfPaintingLayer();
1504 }
1505
UpdateStackingNode()1506 void PaintLayer::UpdateStackingNode() {
1507 #if DCHECK_IS_ON()
1508 DCHECK(layer_list_mutation_allowed_);
1509 #endif
1510
1511 bool needs_stacking_node =
1512 has_stacked_descendant_in_current_stacking_context_ &&
1513 GetLayoutObject().StyleRef().IsStackingContext();
1514
1515 if (needs_stacking_node != !!stacking_node_) {
1516 if (needs_stacking_node)
1517 stacking_node_ = std::make_unique<PaintLayerStackingNode>(*this);
1518 else
1519 stacking_node_ = nullptr;
1520 }
1521
1522 if (stacking_node_)
1523 stacking_node_->UpdateZOrderLists();
1524 }
1525
RequiresScrollableArea() const1526 bool PaintLayer::RequiresScrollableArea() const {
1527 if (!GetLayoutBox())
1528 return false;
1529 if (GetLayoutObject().HasOverflowClip())
1530 return true;
1531 // Iframes with the resize property can be resized. This requires
1532 // scroll corner painting, which is implemented, in part, by
1533 // PaintLayerScrollableArea.
1534 if (GetLayoutBox()->CanResize())
1535 return true;
1536 return false;
1537 }
1538
UpdateScrollableArea()1539 void PaintLayer::UpdateScrollableArea() {
1540 if (RequiresScrollableArea() && !scrollable_area_) {
1541 scrollable_area_ = MakeGarbageCollected<PaintLayerScrollableArea>(*this);
1542 if (Compositor()) {
1543 Compositor()->SetNeedsCompositingUpdate(kCompositingUpdateRebuildTree);
1544 }
1545 GetLayoutObject().SetNeedsPaintPropertyUpdate();
1546 } else if (!RequiresScrollableArea() && scrollable_area_) {
1547 scrollable_area_->Dispose();
1548 scrollable_area_.Clear();
1549 if (Compositor()) {
1550 Compositor()->SetNeedsCompositingUpdate(kCompositingUpdateRebuildTree);
1551 }
1552 GetLayoutObject().SetBackgroundPaintLocation(
1553 kBackgroundPaintInGraphicsLayer);
1554 GetLayoutObject().SetNeedsPaintPropertyUpdate();
1555 }
1556 }
1557
HasOverflowControls() const1558 bool PaintLayer::HasOverflowControls() const {
1559 return scrollable_area_ && (scrollable_area_->HasScrollbar() ||
1560 scrollable_area_->ScrollCorner() ||
1561 GetLayoutObject().StyleRef().HasResize());
1562 }
1563
AppendSingleFragmentIgnoringPagination(PaintLayerFragments & fragments,const PaintLayer * root_layer,const CullRect * cull_rect,OverlayScrollbarClipBehavior overlay_scrollbar_clip_behavior,ShouldRespectOverflowClipType respect_overflow_clip,const PhysicalOffset * offset_from_root,const PhysicalOffset & sub_pixel_accumulation) const1564 void PaintLayer::AppendSingleFragmentIgnoringPagination(
1565 PaintLayerFragments& fragments,
1566 const PaintLayer* root_layer,
1567 const CullRect* cull_rect,
1568 OverlayScrollbarClipBehavior overlay_scrollbar_clip_behavior,
1569 ShouldRespectOverflowClipType respect_overflow_clip,
1570 const PhysicalOffset* offset_from_root,
1571 const PhysicalOffset& sub_pixel_accumulation) const {
1572 PaintLayerFragment fragment;
1573 ClipRectsContext clip_rects_context(
1574 root_layer, &root_layer->GetLayoutObject().FirstFragment(),
1575 kUncachedClipRects, overlay_scrollbar_clip_behavior,
1576 respect_overflow_clip, sub_pixel_accumulation);
1577 Clipper(GeometryMapperOption::kUseGeometryMapper)
1578 .CalculateRects(clip_rects_context, &GetLayoutObject().FirstFragment(),
1579 cull_rect, fragment.layer_bounds,
1580 fragment.background_rect, fragment.foreground_rect,
1581 offset_from_root);
1582 fragment.root_fragment_data = &root_layer->GetLayoutObject().FirstFragment();
1583 fragment.fragment_data = &GetLayoutObject().FirstFragment();
1584 fragments.push_back(fragment);
1585 }
1586
ShouldFragmentCompositedBounds(const PaintLayer * compositing_layer) const1587 bool PaintLayer::ShouldFragmentCompositedBounds(
1588 const PaintLayer* compositing_layer) const {
1589 if (!EnclosingPaginationLayer())
1590 return false;
1591 if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
1592 return true;
1593 if (PaintsWithTransform(kGlobalPaintNormalPhase))
1594 return true;
1595 if (!compositing_layer) {
1596 compositing_layer =
1597 EnclosingLayerForPaintInvalidationCrossingFrameBoundaries();
1598 }
1599 if (!compositing_layer)
1600 return true;
1601 // Composited layers may not be fragmented.
1602 return !compositing_layer->EnclosingPaginationLayer();
1603 }
1604
CollectFragments(PaintLayerFragments & fragments,const PaintLayer * root_layer,const CullRect * cull_rect,OverlayScrollbarClipBehavior overlay_scrollbar_clip_behavior,ShouldRespectOverflowClipType respect_overflow_clip,const PhysicalOffset * offset_from_root,const PhysicalOffset & sub_pixel_accumulation) const1605 void PaintLayer::CollectFragments(
1606 PaintLayerFragments& fragments,
1607 const PaintLayer* root_layer,
1608 const CullRect* cull_rect,
1609 OverlayScrollbarClipBehavior overlay_scrollbar_clip_behavior,
1610 ShouldRespectOverflowClipType respect_overflow_clip,
1611 const PhysicalOffset* offset_from_root,
1612 const PhysicalOffset& sub_pixel_accumulation) const {
1613 PaintLayerFragment fragment;
1614 const auto& first_fragment_data = GetLayoutObject().FirstFragment();
1615 const auto& first_root_fragment_data =
1616 root_layer->GetLayoutObject().FirstFragment();
1617
1618 // If both |this| and |root_layer| are fragmented and are inside the same
1619 // pagination container, then try to match fragments from |root_layer| to
1620 // |this|, so that any fragment clip for |root_layer|'s fragment matches
1621 // |this|'s. Note we check both ShouldFragmentCompositedBounds() and next
1622 // fragment here because the former may return false even if |this| is
1623 // fragmented, e.g. for fixed-position objects in paged media, and the next
1624 // fragment can be null even if the first fragment is actually in a fragmented
1625 // context when the current layer appears in only one of the multiple
1626 // fragments of the pagination container.
1627 bool is_fragmented =
1628 ShouldFragmentCompositedBounds() || first_fragment_data.NextFragment();
1629 bool should_match_fragments =
1630 is_fragmented &&
1631 root_layer->EnclosingPaginationLayer() == EnclosingPaginationLayer();
1632
1633 // The inherited offset_from_root does not include any pagination offsets.
1634 // In the presence of fragmentation, we cannot use it.
1635 bool offset_from_root_can_be_used = offset_from_root && !is_fragmented;
1636 for (auto* fragment_data = &first_fragment_data; fragment_data;
1637 fragment_data = fragment_data->NextFragment()) {
1638 const FragmentData* root_fragment_data;
1639 if (root_layer == this) {
1640 root_fragment_data = fragment_data;
1641 } else if (should_match_fragments) {
1642 for (root_fragment_data = &first_root_fragment_data; root_fragment_data;
1643 root_fragment_data = root_fragment_data->NextFragment()) {
1644 if (root_fragment_data->LogicalTopInFlowThread() ==
1645 fragment_data->LogicalTopInFlowThread())
1646 break;
1647 }
1648 } else {
1649 root_fragment_data = &first_root_fragment_data;
1650 }
1651
1652 bool cant_find_fragment = !root_fragment_data;
1653 if (cant_find_fragment) {
1654 DCHECK(should_match_fragments);
1655 // Fall back to the first fragment, in order to have
1656 // PaintLayerClipper at least compute |fragment.layer_bounds|.
1657 root_fragment_data = &first_root_fragment_data;
1658 }
1659
1660 ClipRectsContext clip_rects_context(
1661 root_layer, root_fragment_data, kUncachedClipRects,
1662 overlay_scrollbar_clip_behavior, respect_overflow_clip,
1663 sub_pixel_accumulation);
1664
1665 base::Optional<CullRect> fragment_cull_rect;
1666 if (cull_rect) {
1667 // |cull_rect| is in the coordinate space of |root_layer| (i.e. the
1668 // space of |root_layer|'s first fragment). Map the rect to the space of
1669 // the current root fragment.
1670 auto rect = cull_rect->Rect();
1671 first_root_fragment_data.MapRectToFragment(*root_fragment_data, rect);
1672 fragment_cull_rect.emplace(rect);
1673 }
1674
1675 Clipper(GeometryMapperOption::kUseGeometryMapper)
1676 .CalculateRects(
1677 clip_rects_context, fragment_data,
1678 fragment_cull_rect ? &*fragment_cull_rect : nullptr,
1679 fragment.layer_bounds, fragment.background_rect,
1680 fragment.foreground_rect,
1681 offset_from_root_can_be_used ? offset_from_root : nullptr);
1682
1683 if (cant_find_fragment) {
1684 // If we couldn't find a matching fragment when |should_match_fragments|
1685 // was true, then fall back to no clip.
1686 fragment.background_rect.Reset();
1687 fragment.foreground_rect.Reset();
1688 }
1689
1690 fragment.root_fragment_data = root_fragment_data;
1691 fragment.fragment_data = fragment_data;
1692
1693 if (GetLayoutObject().CanTraversePhysicalFragments()) {
1694 if (const auto* block = DynamicTo<LayoutBlock>(&GetLayoutObject())) {
1695 fragment.physical_fragment = block->CurrentFragment();
1696 DCHECK(fragment.physical_fragment);
1697
1698 // TODO(mstensho): Implement support for multiple fragments per node.
1699 DCHECK(!fragment_data->NextFragment());
1700 }
1701 }
1702
1703 fragments.push_back(fragment);
1704 }
1705 }
1706
HitTestRecursionData(const PhysicalRect & rect_arg,const HitTestLocation & location_arg,const HitTestLocation & original_location_arg)1707 PaintLayer::HitTestRecursionData::HitTestRecursionData(
1708 const PhysicalRect& rect_arg,
1709 const HitTestLocation& location_arg,
1710 const HitTestLocation& original_location_arg)
1711 : rect(rect_arg),
1712 location(location_arg),
1713 original_location(original_location_arg),
1714 intersects_location(location_arg.Intersects(rect_arg)) {}
1715
HitTest(const HitTestLocation & hit_test_location,HitTestResult & result,const PhysicalRect & hit_test_area)1716 bool PaintLayer::HitTest(const HitTestLocation& hit_test_location,
1717 HitTestResult& result,
1718 const PhysicalRect& hit_test_area) {
1719 DCHECK(IsSelfPaintingLayer() || HasSelfPaintingLayerDescendant());
1720
1721 // LayoutView should make sure to update layout before entering hit testing
1722 DCHECK(!GetLayoutObject().GetFrame()->View()->LayoutPending());
1723 DCHECK(!GetLayoutObject().GetDocument().GetLayoutView()->NeedsLayout());
1724
1725 const HitTestRequest& request = result.GetHitTestRequest();
1726
1727 HitTestRecursionData recursion_data(hit_test_area, hit_test_location,
1728 hit_test_location);
1729 PaintLayer* inside_layer =
1730 HitTestLayer(this, nullptr, result, recursion_data, false);
1731 if (!inside_layer && IsRootLayer()) {
1732 bool fallback = false;
1733 // If we didn't hit any layers but are still inside the document
1734 // bounds, then we should fallback to hitting the document.
1735 // For rect-based hit test, we do the fallback only when the hit-rect
1736 // is totally within the document bounds.
1737 if (hit_test_area.Contains(hit_test_location.BoundingBox())) {
1738 fallback = true;
1739
1740 // Mouse dragging outside the main document should also be
1741 // delivered to the document.
1742 // TODO(miletus): Capture behavior inconsistent with iframes
1743 // crbug.com/522109.
1744 // TODO(majidvp): This should apply more consistently across different
1745 // event types and we should not use RequestType for it. Perhaps best for
1746 // it to be done at a higher level. See http://crbug.com/505825
1747 } else if ((request.Active() || request.Release()) &&
1748 !request.IsChildFrameHitTest()) {
1749 fallback = true;
1750 }
1751 if (fallback) {
1752 GetLayoutObject().UpdateHitTestResult(result, hit_test_location.Point());
1753 inside_layer = this;
1754
1755 // Don't cache this result since it really wasn't a true hit.
1756 result.SetCacheable(false);
1757 }
1758 }
1759
1760 // Now determine if the result is inside an anchor - if the urlElement isn't
1761 // already set.
1762 Node* node = result.InnerNode();
1763 if (node && !result.URLElement())
1764 result.SetURLElement(node->EnclosingLinkEventParentOrSelf());
1765
1766 // Now return whether we were inside this layer (this will always be true for
1767 // the root layer).
1768 return inside_layer;
1769 }
1770
EnclosingNode() const1771 Node* PaintLayer::EnclosingNode() const {
1772 for (LayoutObject* r = &GetLayoutObject(); r; r = r->Parent()) {
1773 if (Node* e = r->GetNode())
1774 return e;
1775 }
1776 NOTREACHED();
1777 return nullptr;
1778 }
1779
IsInTopLayer() const1780 bool PaintLayer::IsInTopLayer() const {
1781 auto* element = DynamicTo<Element>(GetLayoutObject().GetNode());
1782 return element && element->IsInTopLayer();
1783 }
1784
1785 // Compute the z-offset of the point in the transformState.
1786 // This is effectively projecting a ray normal to the plane of ancestor, finding
1787 // where that ray intersects target, and computing the z delta between those two
1788 // points.
ComputeZOffset(const HitTestingTransformState & transform_state)1789 static double ComputeZOffset(const HitTestingTransformState& transform_state) {
1790 // We got an affine transform, so no z-offset
1791 if (transform_state.accumulated_transform_.IsAffine())
1792 return 0;
1793
1794 // Flatten the point into the target plane
1795 FloatPoint target_point = transform_state.MappedPoint();
1796
1797 // Now map the point back through the transform, which computes Z.
1798 FloatPoint3D backmapped_point =
1799 transform_state.accumulated_transform_.MapPoint(
1800 FloatPoint3D(target_point));
1801 return backmapped_point.Z();
1802 }
1803
CreateLocalTransformState(PaintLayer * root_layer,PaintLayer * container_layer,const HitTestRecursionData & recursion_data,const HitTestingTransformState * container_transform_state,const PhysicalOffset & translation_offset) const1804 HitTestingTransformState PaintLayer::CreateLocalTransformState(
1805 PaintLayer* root_layer,
1806 PaintLayer* container_layer,
1807 const HitTestRecursionData& recursion_data,
1808 const HitTestingTransformState* container_transform_state,
1809 const PhysicalOffset& translation_offset) const {
1810 // If we're already computing transform state, then it's relative to the
1811 // container (which we know is non-null).
1812 // If this is the first time we need to make transform state, then base it
1813 // off of hitTestLocation, which is relative to rootLayer.
1814 HitTestingTransformState transform_state =
1815 container_transform_state
1816 ? *container_transform_state
1817 : HitTestingTransformState(recursion_data.location.TransformedPoint(),
1818 recursion_data.location.TransformedRect(),
1819 FloatQuad(FloatRect(recursion_data.rect)));
1820
1821 PhysicalOffset offset;
1822 if (container_transform_state)
1823 ConvertToLayerCoords(container_layer, offset);
1824 else
1825 ConvertToLayerCoords(root_layer, offset);
1826
1827 offset += translation_offset;
1828
1829 LayoutObject* container_layout_object =
1830 container_layer ? &container_layer->GetLayoutObject() : nullptr;
1831 if (GetLayoutObject().ShouldUseTransformFromContainer(
1832 container_layout_object)) {
1833 TransformationMatrix container_transform;
1834 GetLayoutObject().GetTransformFromContainer(container_layout_object, offset,
1835 container_transform);
1836 transform_state.ApplyTransform(
1837 container_transform, HitTestingTransformState::kAccumulateTransform);
1838 } else {
1839 transform_state.Translate(offset.left.ToInt(), offset.top.ToInt(),
1840 HitTestingTransformState::kAccumulateTransform);
1841 }
1842
1843 return transform_state;
1844 }
1845
IsHitCandidateForDepthOrder(const PaintLayer * hit_layer,bool can_depth_sort,double * z_offset,const HitTestingTransformState * transform_state)1846 static bool IsHitCandidateForDepthOrder(
1847 const PaintLayer* hit_layer,
1848 bool can_depth_sort,
1849 double* z_offset,
1850 const HitTestingTransformState* transform_state) {
1851 if (!hit_layer)
1852 return false;
1853
1854 // The hit layer is depth-sorting with other layers, so just say that it was
1855 // hit.
1856 if (can_depth_sort)
1857 return true;
1858
1859 // We need to look at z-depth to decide if this layer was hit.
1860 if (z_offset) {
1861 DCHECK(transform_state);
1862 // This is actually computing our z, but that's OK because the hitLayer is
1863 // coplanar with us.
1864 double child_z_offset = ComputeZOffset(*transform_state);
1865 if (child_z_offset > *z_offset) {
1866 *z_offset = child_z_offset;
1867 return true;
1868 }
1869 return false;
1870 }
1871
1872 return true;
1873 }
1874
1875 // Calling IsDescendantOf is sad (slow), but it's the only way to tell
1876 // whether a hit test candidate is a descendant of the stop node.
IsHitCandidateForStopNode(const LayoutObject & candidate,const LayoutObject * stop_node)1877 static bool IsHitCandidateForStopNode(const LayoutObject& candidate,
1878 const LayoutObject* stop_node) {
1879 return !stop_node || (&candidate == stop_node) ||
1880 !candidate.IsDescendantOf(stop_node);
1881 }
1882
1883 // hitTestLocation and hitTestRect are relative to rootLayer.
1884 // A 'flattening' layer is one preserves3D() == false.
1885 // transformState.m_accumulatedTransform holds the transform from the containing
1886 // flattening layer.
1887 // transformState.m_lastPlanarPoint is the hitTestLocation in the plane of the
1888 // containing flattening layer.
1889 // transformState.m_lastPlanarQuad is the hitTestRect as a quad in the plane of
1890 // the containing flattening layer.
1891 //
1892 // If zOffset is non-null (which indicates that the caller wants z offset
1893 // information), *zOffset on return is the z offset of the hit point relative to
1894 // the containing flattening layer.
HitTestLayer(PaintLayer * root_layer,PaintLayer * container_layer,HitTestResult & result,const HitTestRecursionData & recursion_data,bool applied_transform,HitTestingTransformState * transform_state,double * z_offset,bool check_resizer_only)1895 PaintLayer* PaintLayer::HitTestLayer(PaintLayer* root_layer,
1896 PaintLayer* container_layer,
1897 HitTestResult& result,
1898 const HitTestRecursionData& recursion_data,
1899 bool applied_transform,
1900 HitTestingTransformState* transform_state,
1901 double* z_offset,
1902 bool check_resizer_only) {
1903 const LayoutObject& layout_object = GetLayoutObject();
1904 DCHECK_GE(layout_object.GetDocument().Lifecycle().GetState(),
1905 DocumentLifecycle::kCompositingClean);
1906
1907 if (!IsSelfPaintingLayer() && !HasSelfPaintingLayerDescendant())
1908 return nullptr;
1909
1910 if ((result.GetHitTestRequest().GetType() &
1911 HitTestRequest::kIgnoreZeroOpacityObjects) &&
1912 !layout_object.HasNonZeroEffectiveOpacity()) {
1913 return nullptr;
1914 }
1915
1916 ShouldRespectOverflowClipType clip_behavior = kRespectOverflowClip;
1917 if (result.GetHitTestRequest().IgnoreClipping())
1918 clip_behavior = kIgnoreOverflowClip;
1919
1920 // We can only reach an SVG foreign object's PaintLayer from
1921 // LayoutSVGForeignObject::NodeAtFloatPoint (because
1922 // IsReplacedNormalFlowStacking() true for LayoutSVGForeignObject),
1923 // where the hit_test_rect has already been transformed to local coordinates.
1924 bool use_transform = Transform() && !layout_object.IsSVGForeignObject();
1925
1926 // Apply a transform if we have one.
1927 if (use_transform && !applied_transform) {
1928 if (EnclosingPaginationLayer()) {
1929 return HitTestTransformedLayerInFragments(
1930 root_layer, container_layer, result, recursion_data, transform_state,
1931 z_offset, check_resizer_only, clip_behavior);
1932 }
1933
1934 // Make sure the parent's clip rects have been calculated.
1935 if (Parent()) {
1936 ClipRect clip_rect;
1937 Clipper(GeometryMapperOption::kUseGeometryMapper)
1938 .CalculateBackgroundClipRect(
1939 ClipRectsContext(
1940 root_layer, &root_layer->GetLayoutObject().FirstFragment(),
1941 kUncachedClipRects, kExcludeOverlayScrollbarSizeForHitTesting,
1942 clip_behavior),
1943 clip_rect);
1944 // Go ahead and test the enclosing clip now.
1945 if (!clip_rect.Intersects(recursion_data.location))
1946 return nullptr;
1947 }
1948
1949 return HitTestLayerByApplyingTransform(root_layer, container_layer, result,
1950 recursion_data, transform_state,
1951 z_offset, check_resizer_only);
1952 }
1953
1954 // Don't hit test the clip-path area when checking for occlusion. This is
1955 // necessary because SVG doesn't support rect-based hit testing, so
1956 // HitTestClippedOutByClipPath may erroneously return true for a rect-based
1957 // hit test).
1958 bool is_occlusion_test = result.GetHitTestRequest().GetType() &
1959 HitTestRequest::kHitTestVisualOverflow;
1960 if (!is_occlusion_test && layout_object.HasClipPath() &&
1961 HitTestClippedOutByClipPath(root_layer, recursion_data.location)) {
1962 return nullptr;
1963 }
1964
1965 // The natural thing would be to keep HitTestingTransformState on the stack,
1966 // but it's big, so we heap-allocate.
1967 HitTestingTransformState* local_transform_state = nullptr;
1968 STACK_UNINITIALIZED base::Optional<HitTestingTransformState> storage;
1969
1970 if (applied_transform) {
1971 // We computed the correct state in the caller (above code), so just
1972 // reference it.
1973 DCHECK(transform_state);
1974 local_transform_state = transform_state;
1975 } else if (transform_state || has3d_transformed_descendant_ ||
1976 Preserves3D()) {
1977 // We need transform state for the first time, or to offset the container
1978 // state, so create it here.
1979 storage = CreateLocalTransformState(root_layer, container_layer,
1980 recursion_data, transform_state);
1981 local_transform_state = &*storage;
1982 }
1983
1984 // Check for hit test on backface if backface-visibility is 'hidden'
1985 if (local_transform_state && layout_object.StyleRef().BackfaceVisibility() ==
1986 EBackfaceVisibility::kHidden) {
1987 STACK_UNINITIALIZED TransformationMatrix inverted_matrix =
1988 local_transform_state->accumulated_transform_.Inverse();
1989 // If the z-vector of the matrix is negative, the back is facing towards the
1990 // viewer.
1991 if (inverted_matrix.M33() < 0)
1992 return nullptr;
1993 }
1994
1995 HitTestingTransformState* unflattened_transform_state = local_transform_state;
1996 STACK_UNINITIALIZED base::Optional<HitTestingTransformState>
1997 unflattened_storage;
1998 if (local_transform_state && !Preserves3D()) {
1999 // Keep a copy of the pre-flattening state, for computing z-offsets for the
2000 // container
2001 unflattened_storage.emplace(*local_transform_state);
2002 unflattened_transform_state = &*unflattened_storage;
2003 // This layer is flattening, so flatten the state passed to descendants.
2004 local_transform_state->Flatten();
2005 }
2006
2007 // The following are used for keeping track of the z-depth of the hit point of
2008 // 3d-transformed descendants.
2009 double local_z_offset = -std::numeric_limits<double>::infinity();
2010 double* z_offset_for_descendants_ptr = nullptr;
2011 double* z_offset_for_contents_ptr = nullptr;
2012
2013 bool depth_sort_descendants = false;
2014 if (Preserves3D()) {
2015 depth_sort_descendants = true;
2016 // Our layers can depth-test with our container, so share the z depth
2017 // pointer with the container, if it passed one down.
2018 z_offset_for_descendants_ptr = z_offset ? z_offset : &local_z_offset;
2019 z_offset_for_contents_ptr = z_offset ? z_offset : &local_z_offset;
2020 } else if (z_offset) {
2021 z_offset_for_descendants_ptr = nullptr;
2022 // Container needs us to give back a z offset for the hit layer.
2023 z_offset_for_contents_ptr = z_offset;
2024 }
2025
2026 // Collect the fragments. This will compute the clip rectangles for each
2027 // layer fragment.
2028 STACK_UNINITIALIZED base::Optional<PaintLayerFragments> layer_fragments;
2029 if (recursion_data.intersects_location) {
2030 layer_fragments.emplace();
2031 if (applied_transform) {
2032 DCHECK(root_layer == this);
2033 PhysicalOffset ignored;
2034 AppendSingleFragmentIgnoringPagination(
2035 *layer_fragments, root_layer, nullptr,
2036 kExcludeOverlayScrollbarSizeForHitTesting, clip_behavior, &ignored);
2037 } else {
2038 CollectFragments(*layer_fragments, root_layer, nullptr,
2039 kExcludeOverlayScrollbarSizeForHitTesting,
2040 clip_behavior);
2041 }
2042
2043 // See if the hit test pos is inside the resizer of current layer. This
2044 // should be done before walking child layers to avoid that the resizer
2045 // clickable area is obscured by the positive child layers.
2046 if (scrollable_area_ && scrollable_area_->HitTestResizerInFragments(
2047 *layer_fragments, recursion_data.location)) {
2048 if (Node* node_for_resizer = layout_object.NodeForHitTest())
2049 result.SetInnerNode(node_for_resizer);
2050 return this;
2051 }
2052 }
2053
2054 if (check_resizer_only)
2055 return nullptr;
2056
2057 // See if the hit test pos is inside the resizer of the child layers which
2058 // has reordered the painting of the overlay overflow controls.
2059 if (stacking_node_) {
2060 for (auto* layer : base::Reversed(
2061 stacking_node_->OverlayOverflowControlsReorderedList())) {
2062 if (layer->HitTestLayer(
2063 root_layer, nullptr, result, recursion_data,
2064 false /*applied_transform*/, local_transform_state,
2065 z_offset_for_descendants_ptr, true /*check_resizer_only*/)) {
2066 return layer;
2067 }
2068 }
2069 }
2070
2071 // This variable tracks which layer the mouse ends up being inside.
2072 PaintLayer* candidate_layer = nullptr;
2073
2074 // Begin by walking our list of positive layers from highest z-index down to
2075 // the lowest z-index.
2076 PaintLayer* hit_layer = HitTestChildren(
2077 kPositiveZOrderChildren, root_layer, result, recursion_data,
2078 local_transform_state, z_offset_for_descendants_ptr, z_offset,
2079 unflattened_transform_state, depth_sort_descendants);
2080 if (hit_layer) {
2081 if (!depth_sort_descendants)
2082 return hit_layer;
2083 candidate_layer = hit_layer;
2084 }
2085
2086 // Now check our overflow objects.
2087 hit_layer = HitTestChildren(
2088 kNormalFlowChildren, root_layer, result, recursion_data,
2089 local_transform_state, z_offset_for_descendants_ptr, z_offset,
2090 unflattened_transform_state, depth_sort_descendants);
2091 if (hit_layer) {
2092 if (!depth_sort_descendants)
2093 return hit_layer;
2094 candidate_layer = hit_layer;
2095 }
2096
2097 const LayoutObject* stop_node = result.GetHitTestRequest().GetStopNode();
2098 PhysicalOffset offset;
2099 if (recursion_data.intersects_location) {
2100 // Next we want to see if the mouse pos is inside the child LayoutObjects of
2101 // the layer. Check every fragment in reverse order.
2102 if (IsSelfPaintingLayer() && !layout_object.PaintBlockedByDisplayLock(
2103 DisplayLockLifecycleTarget::kChildren)) {
2104 // Hit test with a temporary HitTestResult, because we only want to commit
2105 // to 'result' if we know we're frontmost.
2106 STACK_UNINITIALIZED HitTestResult temp_result(
2107 result.GetHitTestRequest(), recursion_data.original_location);
2108 temp_result.SetInertNode(result.InertNode());
2109 bool inside_fragment_foreground_rect = false;
2110
2111 if (HitTestContentsForFragments(
2112 *layer_fragments, offset, temp_result, recursion_data.location,
2113 kHitTestDescendants, inside_fragment_foreground_rect) &&
2114 IsHitCandidateForDepthOrder(this, false, z_offset_for_contents_ptr,
2115 unflattened_transform_state) &&
2116 IsHitCandidateForStopNode(GetLayoutObject(), stop_node)) {
2117 if (result.GetHitTestRequest().ListBased())
2118 result.Append(temp_result);
2119 else
2120 result = temp_result;
2121 if (!depth_sort_descendants)
2122 return this;
2123 // Foreground can depth-sort with descendant layers, so keep this as a
2124 // candidate.
2125 candidate_layer = this;
2126 } else if (inside_fragment_foreground_rect &&
2127 result.GetHitTestRequest().ListBased() &&
2128 IsHitCandidateForStopNode(GetLayoutObject(), stop_node)) {
2129 result.Append(temp_result);
2130 } else if (result.GetHitTestRequest().RetargetForInert() &&
2131 IsHitCandidateForStopNode(GetLayoutObject(), stop_node)) {
2132 result.SetInertNode(temp_result.InertNode());
2133 }
2134 }
2135 }
2136
2137 // Now check our negative z-index children.
2138 hit_layer = HitTestChildren(
2139 kNegativeZOrderChildren, root_layer, result, recursion_data,
2140 local_transform_state, z_offset_for_descendants_ptr, z_offset,
2141 unflattened_transform_state, depth_sort_descendants);
2142 if (hit_layer) {
2143 if (!depth_sort_descendants)
2144 return hit_layer;
2145 candidate_layer = hit_layer;
2146 }
2147
2148 // If we found a layer, return. Child layers, and foreground always render
2149 // in front of background.
2150 if (candidate_layer)
2151 return candidate_layer;
2152
2153 if (recursion_data.intersects_location && IsSelfPaintingLayer()) {
2154 STACK_UNINITIALIZED HitTestResult temp_result(
2155 result.GetHitTestRequest(), recursion_data.original_location);
2156 temp_result.SetInertNode(result.InertNode());
2157 bool inside_fragment_background_rect = false;
2158 if (HitTestContentsForFragments(*layer_fragments, offset, temp_result,
2159 recursion_data.location, kHitTestSelf,
2160 inside_fragment_background_rect) &&
2161 IsHitCandidateForDepthOrder(this, false, z_offset_for_contents_ptr,
2162 unflattened_transform_state) &&
2163 IsHitCandidateForStopNode(GetLayoutObject(), stop_node)) {
2164 if (result.GetHitTestRequest().ListBased())
2165 result.Append(temp_result);
2166 else
2167 result = temp_result;
2168 return this;
2169 } else if (result.GetHitTestRequest().RetargetForInert() &&
2170 IsHitCandidateForStopNode(GetLayoutObject(), stop_node)) {
2171 result.SetInertNode(temp_result.InertNode());
2172 }
2173 if (inside_fragment_background_rect &&
2174 result.GetHitTestRequest().ListBased() &&
2175 IsHitCandidateForStopNode(GetLayoutObject(), stop_node)) {
2176 result.Append(temp_result);
2177 }
2178 }
2179
2180 return nullptr;
2181 }
2182
HitTestContentsForFragments(const PaintLayerFragments & layer_fragments,const PhysicalOffset & offset,HitTestResult & result,const HitTestLocation & hit_test_location,HitTestFilter hit_test_filter,bool & inside_clip_rect) const2183 bool PaintLayer::HitTestContentsForFragments(
2184 const PaintLayerFragments& layer_fragments,
2185 const PhysicalOffset& offset,
2186 HitTestResult& result,
2187 const HitTestLocation& hit_test_location,
2188 HitTestFilter hit_test_filter,
2189 bool& inside_clip_rect) const {
2190 if (layer_fragments.IsEmpty())
2191 return false;
2192
2193 for (int i = layer_fragments.size() - 1; i >= 0; --i) {
2194 const PaintLayerFragment& fragment = layer_fragments.at(i);
2195 if ((hit_test_filter == kHitTestSelf &&
2196 !fragment.background_rect.Intersects(hit_test_location)) ||
2197 (hit_test_filter == kHitTestDescendants &&
2198 !fragment.foreground_rect.Intersects(hit_test_location)))
2199 continue;
2200 inside_clip_rect = true;
2201 PhysicalOffset fragment_offset = offset;
2202 fragment_offset += fragment.layer_bounds.offset;
2203 if (HitTestContents(result, fragment.physical_fragment, fragment_offset,
2204 hit_test_location, hit_test_filter))
2205 return true;
2206 }
2207
2208 return false;
2209 }
2210
HitTestTransformedLayerInFragments(PaintLayer * root_layer,PaintLayer * container_layer,HitTestResult & result,const HitTestRecursionData & recursion_data,HitTestingTransformState * transform_state,double * z_offset,bool check_resizer_only,ShouldRespectOverflowClipType clip_behavior)2211 PaintLayer* PaintLayer::HitTestTransformedLayerInFragments(
2212 PaintLayer* root_layer,
2213 PaintLayer* container_layer,
2214 HitTestResult& result,
2215 const HitTestRecursionData& recursion_data,
2216 HitTestingTransformState* transform_state,
2217 double* z_offset,
2218 bool check_resizer_only,
2219 ShouldRespectOverflowClipType clip_behavior) {
2220 PaintLayerFragments enclosing_pagination_fragments;
2221 // FIXME: We're missing a sub-pixel offset here crbug.com/348728
2222
2223 EnclosingPaginationLayer()->CollectFragments(
2224 enclosing_pagination_fragments, root_layer, nullptr,
2225 kExcludeOverlayScrollbarSizeForHitTesting, clip_behavior, nullptr,
2226 PhysicalOffset());
2227
2228 for (const auto& fragment : enclosing_pagination_fragments) {
2229 // Apply the page/column clip for this fragment, as well as any clips
2230 // established by layers in between us and the enclosing pagination layer.
2231 PhysicalRect clip_rect = fragment.background_rect.Rect();
2232 if (!recursion_data.location.Intersects(clip_rect))
2233 continue;
2234
2235 PaintLayer* hit_layer = HitTestLayerByApplyingTransform(
2236 root_layer, container_layer, result, recursion_data, transform_state,
2237 z_offset, check_resizer_only,
2238 fragment.fragment_data->LegacyPaginationOffset());
2239 if (hit_layer)
2240 return hit_layer;
2241 }
2242
2243 return nullptr;
2244 }
2245
HitTestLayerByApplyingTransform(PaintLayer * root_layer,PaintLayer * container_layer,HitTestResult & result,const HitTestRecursionData & recursion_data,HitTestingTransformState * transform_state,double * z_offset,bool check_resizer_only,const PhysicalOffset & translation_offset)2246 PaintLayer* PaintLayer::HitTestLayerByApplyingTransform(
2247 PaintLayer* root_layer,
2248 PaintLayer* container_layer,
2249 HitTestResult& result,
2250 const HitTestRecursionData& recursion_data,
2251 HitTestingTransformState* transform_state,
2252 double* z_offset,
2253 bool check_resizer_only,
2254 const PhysicalOffset& translation_offset) {
2255 // Create a transform state to accumulate this transform.
2256 HitTestingTransformState new_transform_state =
2257 CreateLocalTransformState(root_layer, container_layer, recursion_data,
2258 transform_state, translation_offset);
2259
2260 // If the transform can't be inverted, then don't hit test this layer at all.
2261 if (!new_transform_state.accumulated_transform_.IsInvertible())
2262 return nullptr;
2263
2264 // Compute the point and the hit test rect in the coords of this layer by
2265 // using the values from the transformState, which store the point and quad in
2266 // the coords of the last flattened layer, and the accumulated transform which
2267 // lets up map through preserve-3d layers.
2268 //
2269 // We can't just map hitTestLocation and hitTestRect because they may have
2270 // been flattened (losing z) by our container.
2271 FloatPoint local_point = new_transform_state.MappedPoint();
2272 PhysicalRect bounds_of_mapped_area = new_transform_state.BoundsOfMappedArea();
2273 base::Optional<HitTestLocation> new_location;
2274 if (recursion_data.location.IsRectBasedTest())
2275 new_location.emplace(local_point, new_transform_state.MappedQuad());
2276 else
2277 new_location.emplace(local_point, new_transform_state.BoundsOfMappedQuad());
2278 HitTestRecursionData new_recursion_data(bounds_of_mapped_area, *new_location,
2279 recursion_data.original_location);
2280
2281 // Now do a hit test with the root layer shifted to be us.
2282 return HitTestLayer(this, container_layer, result, new_recursion_data, true,
2283 &new_transform_state, z_offset, check_resizer_only);
2284 }
2285
HitTestContents(HitTestResult & result,const NGPhysicalBoxFragment * physical_fragment,const PhysicalOffset & fragment_offset,const HitTestLocation & hit_test_location,HitTestFilter hit_test_filter) const2286 bool PaintLayer::HitTestContents(HitTestResult& result,
2287 const NGPhysicalBoxFragment* physical_fragment,
2288 const PhysicalOffset& fragment_offset,
2289 const HitTestLocation& hit_test_location,
2290 HitTestFilter hit_test_filter) const {
2291 DCHECK(IsSelfPaintingLayer() || HasSelfPaintingLayerDescendant());
2292
2293 bool did_hit;
2294 if (physical_fragment) {
2295 did_hit = NGBoxFragmentPainter(*physical_fragment)
2296 .HitTestAllPhases(result, hit_test_location, fragment_offset,
2297 hit_test_filter);
2298 } else {
2299 did_hit = GetLayoutObject().HitTestAllPhases(
2300 result, hit_test_location, fragment_offset, hit_test_filter);
2301 }
2302
2303 if (!did_hit) {
2304 // It's wrong to set innerNode, but then claim that you didn't hit anything,
2305 // unless it is a list-based test.
2306 DCHECK(!result.InnerNode() || (result.GetHitTestRequest().ListBased() &&
2307 result.ListBasedTestResult().size()));
2308 return false;
2309 }
2310
2311 if (!result.InnerNode()) {
2312 // We hit something anonymous, and we didn't find a DOM node ancestor in
2313 // this layer.
2314
2315 if (GetLayoutObject().IsLayoutFlowThread()) {
2316 // For a flow thread it's safe to just say that we didn't hit anything.
2317 // That means that we'll continue as normally, and eventually hit a column
2318 // set sibling instead. Column sets are also anonymous, but, unlike flow
2319 // threads, they don't establish layers, so we'll fall back and hit the
2320 // multicol container parent (which should have a DOM node).
2321 return false;
2322 }
2323
2324 Node* e = EnclosingNode();
2325 // FIXME: should be a call to result.setNodeAndPosition. What we would
2326 // really want to do here is to return and look for the nearest
2327 // non-anonymous ancestor, and ignore aunts and uncles on our way. It's bad
2328 // to look for it manually like we do here, and give up on setting a local
2329 // point in the result, because that has bad implications for text selection
2330 // and caretRangeFromPoint(). See crbug.com/461791
2331 // This code path only ever hits in fullscreen tests.
2332 result.SetInnerNode(e);
2333 }
2334 return true;
2335 }
2336
IsReplacedNormalFlowStacking() const2337 bool PaintLayer::IsReplacedNormalFlowStacking() const {
2338 return GetLayoutObject().IsSVGForeignObject();
2339 }
2340
SetNeedsCompositingLayerAssignment()2341 void PaintLayer::SetNeedsCompositingLayerAssignment() {
2342 needs_compositing_layer_assignment_ = true;
2343
2344 for (PaintLayer* curr = CompositingContainer();
2345 curr && !curr->StackingDescendantNeedsCompositingLayerAssignment();
2346 curr = curr->CompositingContainer()) {
2347 curr->descendant_needs_compositing_layer_assignment_ = true;
2348 }
2349 }
2350
ClearNeedsCompositingLayerAssignment()2351 void PaintLayer::ClearNeedsCompositingLayerAssignment() {
2352 needs_compositing_layer_assignment_ = false;
2353 descendant_needs_compositing_layer_assignment_ = false;
2354 }
2355
SetNeedsCompositingRequirementsUpdate()2356 void PaintLayer::SetNeedsCompositingRequirementsUpdate() {
2357 for (PaintLayer* curr = this;
2358 curr && !curr->DescendantMayNeedCompositingRequirementsUpdate();
2359 curr = curr->Parent()) {
2360 curr->descendant_may_need_compositing_requirements_update_ = true;
2361 }
2362 }
2363
HitTestChildren(PaintLayerIteration children_to_visit,PaintLayer * root_layer,HitTestResult & result,const HitTestRecursionData & recursion_data,HitTestingTransformState * transform_state,double * z_offset_for_descendants,double * z_offset,HitTestingTransformState * unflattened_transform_state,bool depth_sort_descendants)2364 PaintLayer* PaintLayer::HitTestChildren(
2365 PaintLayerIteration children_to_visit,
2366 PaintLayer* root_layer,
2367 HitTestResult& result,
2368 const HitTestRecursionData& recursion_data,
2369 HitTestingTransformState* transform_state,
2370 double* z_offset_for_descendants,
2371 double* z_offset,
2372 HitTestingTransformState* unflattened_transform_state,
2373 bool depth_sort_descendants) {
2374 if (!HasSelfPaintingLayerDescendant())
2375 return nullptr;
2376
2377 if (GetLayoutObject().PaintBlockedByDisplayLock(
2378 DisplayLockLifecycleTarget::kChildren))
2379 return nullptr;
2380
2381 const LayoutObject* stop_node = result.GetHitTestRequest().GetStopNode();
2382 PaintLayer* stop_layer = stop_node ? stop_node->PaintingLayer() : nullptr;
2383
2384 PaintLayer* result_layer = nullptr;
2385 PaintLayerPaintOrderReverseIterator iterator(*this, children_to_visit);
2386 while (PaintLayer* child_layer = iterator.Next()) {
2387 if (child_layer->IsReplacedNormalFlowStacking())
2388 continue;
2389
2390 // Avoid the call to child_layer->HitTestLayer() if possible.
2391 if (stop_layer == this &&
2392 !IsHitCandidateForStopNode(child_layer->GetLayoutObject(), stop_node)) {
2393 continue;
2394 }
2395
2396 PaintLayer* hit_layer = nullptr;
2397 STACK_UNINITIALIZED HitTestResult temp_result(
2398 result.GetHitTestRequest(), recursion_data.original_location);
2399 temp_result.SetInertNode(result.InertNode());
2400 hit_layer = child_layer->HitTestLayer(
2401 root_layer, this, temp_result, recursion_data, false, transform_state,
2402 z_offset_for_descendants);
2403
2404 // If it is a list-based test, we can safely append the temporary result
2405 // since it might had hit nodes but not necesserily had hitLayer set.
2406 if (result.GetHitTestRequest().ListBased())
2407 result.Append(temp_result);
2408
2409 if (IsHitCandidateForDepthOrder(hit_layer, depth_sort_descendants, z_offset,
2410 unflattened_transform_state)) {
2411 result_layer = hit_layer;
2412 if (!result.GetHitTestRequest().ListBased())
2413 result = temp_result;
2414 if (!depth_sort_descendants)
2415 break;
2416 } else if (result.GetHitTestRequest().RetargetForInert()) {
2417 result.SetInertNode(temp_result.InertNode());
2418 }
2419 }
2420
2421 return result_layer;
2422 }
2423
UpdateFilterReferenceBox()2424 void PaintLayer::UpdateFilterReferenceBox() {
2425 if (!HasFilterThatMovesPixels())
2426 return;
2427 FloatRect reference_box =
2428 FloatRect(PhysicalBoundingBoxIncludingStackingChildren(
2429 PhysicalOffset(),
2430 PaintLayer::kIncludeTransformsAndCompositedChildLayers));
2431 float zoom = GetLayoutObject().StyleRef().EffectiveZoom();
2432 if (zoom != 1)
2433 reference_box.Scale(1 / zoom);
2434 if (!ResourceInfo() || ResourceInfo()->FilterReferenceBox() != reference_box)
2435 GetLayoutObject().SetNeedsPaintPropertyUpdate();
2436 EnsureResourceInfo().SetFilterReferenceBox(reference_box);
2437 }
2438
FilterReferenceBox() const2439 FloatRect PaintLayer::FilterReferenceBox() const {
2440 DCHECK(IsAllowedToQueryCompositingState());
2441 if (ResourceInfo())
2442 return ResourceInfo()->FilterReferenceBox();
2443 return FloatRect();
2444 }
2445
BackdropFilterReferenceBox() const2446 FloatRect PaintLayer::BackdropFilterReferenceBox() const {
2447 FloatRect reference_box(GetLayoutObject().BorderBoundingBox());
2448 float zoom = GetLayoutObject().StyleRef().EffectiveZoom();
2449 if (zoom != 1)
2450 reference_box.Scale(1 / zoom);
2451 return reference_box;
2452 }
2453
BackdropFilterBounds(const FloatRect & reference_box) const2454 gfx::RRectF PaintLayer::BackdropFilterBounds(
2455 const FloatRect& reference_box) const {
2456 auto& style = GetLayoutObject().StyleRef();
2457 FloatRect scaled_reference_box(reference_box);
2458 scaled_reference_box.Scale(style.EffectiveZoom());
2459 gfx::RRectF backdrop_filter_bounds =
2460 gfx::RRectF(style.GetRoundedBorderFor(LayoutRect(scaled_reference_box)));
2461 return backdrop_filter_bounds;
2462 }
HitTestClippedOutByClipPath(PaintLayer * root_layer,const HitTestLocation & hit_test_location) const2463 bool PaintLayer::HitTestClippedOutByClipPath(
2464 PaintLayer* root_layer,
2465 const HitTestLocation& hit_test_location) const {
2466 DCHECK(GetLayoutObject().HasClipPath());
2467 DCHECK(IsSelfPaintingLayer());
2468 DCHECK(root_layer);
2469
2470 PhysicalRect origin;
2471 if (EnclosingPaginationLayer())
2472 ConvertFromFlowThreadToVisualBoundingBoxInAncestor(root_layer, origin);
2473 else
2474 ConvertToLayerCoords(root_layer, origin);
2475
2476 FloatPoint point(hit_test_location.Point() - origin.offset);
2477 FloatRect reference_box(
2478 ClipPathClipper::LocalReferenceBox(GetLayoutObject()));
2479
2480 ClipPathOperation* clip_path_operation =
2481 GetLayoutObject().StyleRef().ClipPath();
2482 DCHECK(clip_path_operation);
2483 if (clip_path_operation->GetType() == ClipPathOperation::SHAPE) {
2484 ShapeClipPathOperation* clip_path =
2485 To<ShapeClipPathOperation>(clip_path_operation);
2486 return !clip_path->GetPath(reference_box).Contains(point);
2487 }
2488 DCHECK_EQ(clip_path_operation->GetType(), ClipPathOperation::REFERENCE);
2489 LayoutSVGResourceClipper* clipper = GetSVGResourceAsType(clip_path_operation);
2490 if (!clipper)
2491 return false;
2492 // If the clipPath is using "userspace on use" units, then the origin of
2493 // the coordinate system is the top-left of the reference box, so adjust
2494 // the point accordingly.
2495 if (clipper->ClipPathUnits() == SVGUnitTypes::kSvgUnitTypeUserspaceonuse)
2496 point.MoveBy(-reference_box.Location());
2497 // Unzoom the point and the reference box, since the <clipPath> geometry is
2498 // not zoomed.
2499 float inverse_zoom = 1 / GetLayoutObject().StyleRef().EffectiveZoom();
2500 point.Scale(inverse_zoom, inverse_zoom);
2501 reference_box.Scale(inverse_zoom);
2502 HitTestLocation location(point);
2503 return !clipper->HitTestClipContent(reference_box, location);
2504 }
2505
IntersectsDamageRect(const PhysicalRect & layer_bounds,const PhysicalRect & damage_rect,const PhysicalOffset & offset_from_root) const2506 bool PaintLayer::IntersectsDamageRect(
2507 const PhysicalRect& layer_bounds,
2508 const PhysicalRect& damage_rect,
2509 const PhysicalOffset& offset_from_root) const {
2510 // Always examine the canvas and the root.
2511 // FIXME: Could eliminate the isDocumentElement() check if we fix background
2512 // painting so that the LayoutView paints the root's background.
2513 if (IsRootLayer() || GetLayoutObject().IsDocumentElement())
2514 return true;
2515
2516 // If we aren't an inline flow, and our layer bounds do intersect the damage
2517 // rect, then we can go ahead and return true.
2518 LayoutView* view = GetLayoutObject().View();
2519 DCHECK(view);
2520 if (view && !GetLayoutObject().IsLayoutInline()) {
2521 if (layer_bounds.Intersects(damage_rect))
2522 return true;
2523 }
2524
2525 // Otherwise we need to compute the bounding box of this single layer and see
2526 // if it intersects the damage rect.
2527 return PhysicalBoundingBox(offset_from_root).Intersects(damage_rect);
2528 }
2529
LocalBoundingBox() const2530 PhysicalRect PaintLayer::LocalBoundingBox() const {
2531 PhysicalRect rect = GetLayoutObject().PhysicalVisualOverflowRect();
2532 if (GetLayoutObject().IsEffectiveRootScroller() || IsRootLayer()) {
2533 rect.Unite(
2534 PhysicalRect(rect.offset, GetLayoutObject().View()->ViewRect().size));
2535 }
2536 return rect;
2537 }
2538
PhysicalBoundingBox(const PaintLayer * ancestor_layer) const2539 PhysicalRect PaintLayer::PhysicalBoundingBox(
2540 const PaintLayer* ancestor_layer) const {
2541 PhysicalOffset offset_from_root;
2542 ConvertToLayerCoords(ancestor_layer, offset_from_root);
2543 return PhysicalBoundingBox(offset_from_root);
2544 }
2545
PhysicalBoundingBox(const PhysicalOffset & offset_from_root) const2546 PhysicalRect PaintLayer::PhysicalBoundingBox(
2547 const PhysicalOffset& offset_from_root) const {
2548 PhysicalRect result = LocalBoundingBox();
2549 result.Move(offset_from_root);
2550 return result;
2551 }
2552
FragmentsBoundingBox(const PaintLayer * ancestor_layer) const2553 PhysicalRect PaintLayer::FragmentsBoundingBox(
2554 const PaintLayer* ancestor_layer) const {
2555 if (!EnclosingPaginationLayer())
2556 return PhysicalBoundingBox(ancestor_layer);
2557
2558 PhysicalRect result = LocalBoundingBox();
2559 ConvertFromFlowThreadToVisualBoundingBoxInAncestor(ancestor_layer, result);
2560 return result;
2561 }
2562
BoundingBoxForCompositingOverlapTest() const2563 PhysicalRect PaintLayer::BoundingBoxForCompositingOverlapTest() const {
2564 // Apply NeverIncludeTransformForAncestorLayer, because the geometry map in
2565 // CompositingInputsUpdater will take care of applying the transform of |this|
2566 // (== the ancestorLayer argument to boundingBoxForCompositing).
2567 // TODO(trchen): Layer fragmentation is inhibited across compositing boundary.
2568 // Should we return the unfragmented bounds for overlap testing? Or perhaps
2569 // assume fragmented layers always overlap?
2570 PhysicalRect bounding_box =
2571 OverlapBoundsIncludeChildren()
2572 ? BoundingBoxForCompositingInternal(
2573 *this, nullptr, kNeverIncludeTransformForAncestorLayer)
2574 : FragmentsBoundingBox(this);
2575 const ComputedStyle& style = GetLayoutObject().StyleRef();
2576 if (style.HasBackdropFilter() &&
2577 style.BackdropFilter().HasFilterThatMovesPixels()) {
2578 bounding_box = PhysicalRect::EnclosingRect(
2579 style.BackdropFilter().MapRect(FloatRect(bounding_box)));
2580 }
2581 return bounding_box;
2582 }
2583
OverlapBoundsIncludeChildren() const2584 bool PaintLayer::OverlapBoundsIncludeChildren() const {
2585 return HasFilterThatMovesPixels();
2586 }
2587
ExpandRectForStackingChildren(const PaintLayer & composited_layer,PhysicalRect & result,PaintLayer::CalculateBoundsOptions options) const2588 void PaintLayer::ExpandRectForStackingChildren(
2589 const PaintLayer& composited_layer,
2590 PhysicalRect& result,
2591 PaintLayer::CalculateBoundsOptions options) const {
2592 // If we're locked, th en the subtree does not contribute painted output.
2593 // Furthermore, we might not have up-to-date sizing and position information
2594 // in the subtree, so skip recursing into the subtree.
2595 if (GetLayoutObject().PaintBlockedByDisplayLock(
2596 DisplayLockLifecycleTarget::kChildren)) {
2597 return;
2598 }
2599
2600 PaintLayerPaintOrderIterator iterator(*this, kAllChildren);
2601 while (PaintLayer* child_layer = iterator.Next()) {
2602 // Here we exclude both directly composited layers and squashing layers
2603 // because those Layers don't paint into the graphics layer
2604 // for this Layer. For example, the bounds of squashed Layers
2605 // will be included in the computation of the appropriate squashing
2606 // GraphicsLayer.
2607 if (options != PaintLayer::CalculateBoundsOptions::
2608 kIncludeTransformsAndCompositedChildLayers &&
2609 child_layer->GetCompositingState() != kNotComposited)
2610 continue;
2611 result.Unite(child_layer->BoundingBoxForCompositingInternal(
2612 composited_layer, this, options));
2613 }
2614 }
2615
PhysicalBoundingBoxIncludingStackingChildren(const PhysicalOffset & offset_from_root,CalculateBoundsOptions options) const2616 PhysicalRect PaintLayer::PhysicalBoundingBoxIncludingStackingChildren(
2617 const PhysicalOffset& offset_from_root,
2618 CalculateBoundsOptions options) const {
2619 PhysicalRect result = LocalBoundingBox();
2620 ExpandRectForStackingChildren(*this, result, options);
2621
2622 result.Move(offset_from_root);
2623 return result;
2624 }
2625
BoundingBoxForCompositing() const2626 PhysicalRect PaintLayer::BoundingBoxForCompositing() const {
2627 return BoundingBoxForCompositingInternal(
2628 *this, nullptr, kMaybeIncludeTransformForAncestorLayer);
2629 }
2630
ShouldApplyTransformToBoundingBox(const PaintLayer & composited_layer,CalculateBoundsOptions options) const2631 bool PaintLayer::ShouldApplyTransformToBoundingBox(
2632 const PaintLayer& composited_layer,
2633 CalculateBoundsOptions options) const {
2634 if (!Transform())
2635 return false;
2636 if (options == kIncludeTransformsAndCompositedChildLayers)
2637 return true;
2638 if (PaintsWithTransform(kGlobalPaintNormalPhase)) {
2639 if (this != &composited_layer)
2640 return true;
2641 if (options == kMaybeIncludeTransformForAncestorLayer)
2642 return true;
2643 }
2644 return false;
2645 }
2646
BoundingBoxForCompositingInternal(const PaintLayer & composited_layer,const PaintLayer * stacking_parent,CalculateBoundsOptions options) const2647 PhysicalRect PaintLayer::BoundingBoxForCompositingInternal(
2648 const PaintLayer& composited_layer,
2649 const PaintLayer* stacking_parent,
2650 CalculateBoundsOptions options) const {
2651 if (!IsSelfPaintingLayer())
2652 return PhysicalRect();
2653
2654 // FIXME: This could be improved to do a check like
2655 // hasVisibleNonCompositingDescendantLayers() (bug 92580).
2656 if (this != &composited_layer && !HasVisibleContent() &&
2657 !HasVisibleDescendant())
2658 return PhysicalRect();
2659
2660 if (GetLayoutObject().IsEffectiveRootScroller() || IsRootLayer()) {
2661 // In root layer scrolling mode, the main GraphicsLayer is the size of the
2662 // layout viewport. In non-RLS mode, it is the union of the layout viewport
2663 // and the document's layout overflow rect.
2664 IntRect result = IntRect();
2665 if (LocalFrameView* frame_view = GetLayoutObject().GetFrameView())
2666 result = IntRect(IntPoint(), frame_view->Size());
2667 return PhysicalRect(result);
2668 }
2669
2670 // The layer created for the LayoutFlowThread is just a helper for painting
2671 // and hit-testing, and should not contribute to the bounding box. The
2672 // LayoutMultiColumnSets will contribute the correct size for the layout
2673 // content of the multicol container.
2674 if (GetLayoutObject().IsLayoutFlowThread())
2675 return PhysicalRect();
2676
2677 // If there is a clip applied by an ancestor to this PaintLayer but below or
2678 // equal to |ancestorLayer|, apply that clip.
2679 PhysicalRect result = Clipper(GeometryMapperOption::kDoNotUseGeometryMapper)
2680 .LocalClipRect(composited_layer);
2681
2682 result.Intersect(LocalBoundingBox());
2683
2684 ExpandRectForStackingChildren(composited_layer, result, options);
2685
2686 // Only enlarge by the filter outsets if we know the filter is going to be
2687 // rendered in software. Accelerated filters will handle their own outsets.
2688 if (PaintsWithFilters())
2689 result = MapRectForFilter(result);
2690
2691 if (ShouldApplyTransformToBoundingBox(composited_layer, options)) {
2692 result =
2693 PhysicalRect::EnclosingRect(Transform()->MapRect(FloatRect(result)));
2694 }
2695
2696 if (ShouldFragmentCompositedBounds(&composited_layer)) {
2697 ConvertFromFlowThreadToVisualBoundingBoxInAncestor(&composited_layer,
2698 result);
2699 return result;
2700 }
2701
2702 if (stacking_parent) {
2703 PhysicalOffset delta;
2704 ConvertToLayerCoords(stacking_parent, delta);
2705 result.Move(delta);
2706 }
2707 return result;
2708 }
2709
GetCompositingState() const2710 CompositingState PaintLayer::GetCompositingState() const {
2711 DCHECK(IsAllowedToQueryCompositingState());
2712
2713 // This is computed procedurally so there is no redundant state variable that
2714 // can get out of sync from the real actual compositing state.
2715
2716 if (GroupedMapping()) {
2717 DCHECK(!GetCompositedLayerMapping());
2718 return kPaintsIntoGroupedBacking;
2719 }
2720
2721 if (!GetCompositedLayerMapping())
2722 return kNotComposited;
2723
2724 return kPaintsIntoOwnBacking;
2725 }
2726
IsAllowedToQueryCompositingState() const2727 bool PaintLayer::IsAllowedToQueryCompositingState() const {
2728 if (g_compositing_query_mode == kCompositingQueriesAreAllowed ||
2729 RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
2730 return true;
2731 return GetLayoutObject().GetDocument().Lifecycle().GetState() >=
2732 DocumentLifecycle::kInCompositingUpdate;
2733 }
2734
GetCompositedLayerMapping() const2735 CompositedLayerMapping* PaintLayer::GetCompositedLayerMapping() const {
2736 DCHECK(IsAllowedToQueryCompositingState());
2737 return rare_data_ ? rare_data_->composited_layer_mapping.get() : nullptr;
2738 }
2739
GraphicsLayerBacking(const LayoutObject * obj) const2740 GraphicsLayer* PaintLayer::GraphicsLayerBacking(const LayoutObject* obj) const {
2741 switch (GetCompositingState()) {
2742 case kNotComposited:
2743 return nullptr;
2744 case kPaintsIntoGroupedBacking:
2745 return GroupedMapping()->SquashingLayer();
2746 default:
2747 return (obj != &GetLayoutObject() &&
2748 GetCompositedLayerMapping()->ScrollingContentsLayer())
2749 ? GetCompositedLayerMapping()->ScrollingContentsLayer()
2750 : GetCompositedLayerMapping()->MainGraphicsLayer();
2751 }
2752 }
2753
EnsureCompositedLayerMapping()2754 void PaintLayer::EnsureCompositedLayerMapping() {
2755 if (HasCompositedLayerMapping())
2756 return;
2757
2758 EnsureRareData().composited_layer_mapping =
2759 std::make_unique<CompositedLayerMapping>(*this);
2760 rare_data_->composited_layer_mapping->SetNeedsGraphicsLayerUpdate(
2761 kGraphicsLayerUpdateSubtree);
2762 }
2763
ClearCompositedLayerMapping(bool layer_being_destroyed)2764 void PaintLayer::ClearCompositedLayerMapping(bool layer_being_destroyed) {
2765 if (!HasCompositedLayerMapping())
2766 return;
2767
2768 if (layer_being_destroyed) {
2769 if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
2770 // The visual rects will be in a different coordinate space after losing
2771 // their compositing container. Clear them before prepaint to avoid
2772 // spurious layout shift reports from LayoutShiftTracker.
2773 // If the PaintLayer were not being destroyed, this would happen during
2774 // the compositing update (PaintLayerCompositor::UpdateIfNeeded).
2775 // TODO: LayoutShiftTracker's reliance on having visual rects cleared
2776 // before prepaint in the case of compositing changes is not ideal, and
2777 // will not work with CompositeAfterPaint. Some transform tree changes may
2778 // still produce incorrect behavior from LayoutShiftTracker (see
2779 // discussion on review thread of http://crrev.com/c/1636403).
2780 if (Compositor()) {
2781 Compositor()
2782 ->ForceRecomputeVisualRectsIncludingNonCompositingDescendants(
2783 layout_object_);
2784 }
2785 }
2786 } else {
2787 // We need to make sure our decendants get a geometry update. In principle,
2788 // we could call setNeedsGraphicsLayerUpdate on our children, but that would
2789 // require walking the z-order lists to find them. Instead, we
2790 // over-invalidate by marking our parent as needing a geometry update.
2791 if (PaintLayer* compositing_parent =
2792 EnclosingLayerWithCompositedLayerMapping(kExcludeSelf))
2793 compositing_parent->GetCompositedLayerMapping()
2794 ->SetNeedsGraphicsLayerUpdate(kGraphicsLayerUpdateSubtree);
2795 }
2796 DCHECK(rare_data_);
2797 rare_data_->composited_layer_mapping.reset();
2798 }
2799
SetGroupedMapping(CompositedLayerMapping * grouped_mapping,SetGroupMappingOptions options)2800 void PaintLayer::SetGroupedMapping(CompositedLayerMapping* grouped_mapping,
2801 SetGroupMappingOptions options) {
2802 CompositedLayerMapping* old_grouped_mapping = GroupedMapping();
2803 if (grouped_mapping == old_grouped_mapping)
2804 return;
2805
2806 if (options == kInvalidateLayerAndRemoveFromMapping && old_grouped_mapping) {
2807 old_grouped_mapping->SetNeedsGraphicsLayerUpdate(
2808 kGraphicsLayerUpdateSubtree);
2809 old_grouped_mapping->RemoveLayerFromSquashingGraphicsLayer(this);
2810 }
2811 if (rare_data_ || grouped_mapping)
2812 EnsureRareData().grouped_mapping = grouped_mapping;
2813 #if DCHECK_IS_ON()
2814 DCHECK(!grouped_mapping ||
2815 grouped_mapping->VerifyLayerInSquashingVector(this));
2816 #endif
2817 if (options == kInvalidateLayerAndRemoveFromMapping && grouped_mapping)
2818 grouped_mapping->SetNeedsGraphicsLayerUpdate(kGraphicsLayerUpdateSubtree);
2819 }
2820
NeedsCompositedScrolling() const2821 bool PaintLayer::NeedsCompositedScrolling() const {
2822 return scrollable_area_ && scrollable_area_->NeedsCompositedScrolling();
2823 }
2824
PaintsWithTransform(GlobalPaintFlags global_paint_flags) const2825 bool PaintLayer::PaintsWithTransform(
2826 GlobalPaintFlags global_paint_flags) const {
2827 return Transform() && !PaintsIntoOwnBacking(global_paint_flags);
2828 }
2829
PaintsIntoOwnBacking(GlobalPaintFlags global_paint_flags) const2830 bool PaintLayer::PaintsIntoOwnBacking(
2831 GlobalPaintFlags global_paint_flags) const {
2832 return !(global_paint_flags & kGlobalPaintFlattenCompositingLayers) &&
2833 GetCompositingState() == kPaintsIntoOwnBacking;
2834 }
2835
PaintsIntoOwnOrGroupedBacking(GlobalPaintFlags global_paint_flags) const2836 bool PaintLayer::PaintsIntoOwnOrGroupedBacking(
2837 GlobalPaintFlags global_paint_flags) const {
2838 return !(global_paint_flags & kGlobalPaintFlattenCompositingLayers) &&
2839 GetCompositingState() != kNotComposited;
2840 }
2841
SupportsSubsequenceCaching() const2842 bool PaintLayer::SupportsSubsequenceCaching() const {
2843 if (EnclosingPaginationLayer())
2844 return false;
2845
2846 // SVG paints atomically.
2847 if (GetLayoutObject().IsSVGRoot())
2848 return true;
2849
2850 // Don't create subsequence for the document element because the subsequence
2851 // for LayoutView serves the same purpose. This can avoid unnecessary paint
2852 // chunks that would otherwise be forced by the subsequence.
2853 if (GetLayoutObject().IsDocumentElement())
2854 return false;
2855
2856 // Create subsequence for only stacking contexts whose painting are atomic.
2857 return GetLayoutObject().StyleRef().IsStackingContext();
2858 }
2859
GetScrollingCoordinator()2860 ScrollingCoordinator* PaintLayer::GetScrollingCoordinator() {
2861 Page* page = GetLayoutObject().GetFrame()->GetPage();
2862 return (!page) ? nullptr : page->GetScrollingCoordinator();
2863 }
2864
CompositesWithTransform() const2865 bool PaintLayer::CompositesWithTransform() const {
2866 return TransformAncestor() || Transform();
2867 }
2868
CompositesWithOpacity() const2869 bool PaintLayer::CompositesWithOpacity() const {
2870 return OpacityAncestor() || GetLayoutObject().StyleRef().HasOpacity();
2871 }
2872
BackgroundIsKnownToBeOpaqueInRect(const PhysicalRect & local_rect,bool should_check_children) const2873 bool PaintLayer::BackgroundIsKnownToBeOpaqueInRect(
2874 const PhysicalRect& local_rect,
2875 bool should_check_children) const {
2876 if (PaintsWithTransparency(kGlobalPaintNormalPhase))
2877 return false;
2878
2879 // We can't use hasVisibleContent(), because that will be true if our
2880 // layoutObject is hidden, but some child is visible and that child doesn't
2881 // cover the entire rect.
2882 if (GetLayoutObject().StyleRef().Visibility() != EVisibility::kVisible)
2883 return false;
2884
2885 if (GetLayoutObject().HasMask() || GetLayoutObject().HasClipPath())
2886 return false;
2887
2888 if (PaintsWithFilters() &&
2889 GetLayoutObject().StyleRef().Filter().HasFilterThatAffectsOpacity())
2890 return false;
2891
2892 // FIXME: Handle simple transforms.
2893 if (Transform() && GetCompositingState() != kPaintsIntoOwnBacking)
2894 return false;
2895
2896 if (GetLayoutObject().StyleRef().GetPosition() == EPosition::kFixed &&
2897 GetCompositingState() != kPaintsIntoOwnBacking)
2898 return false;
2899
2900 // FIXME: We currently only check the immediate layoutObject,
2901 // which will miss many cases where additional layout objects paint
2902 // into this layer.
2903 if (GetLayoutObject().BackgroundIsKnownToBeOpaqueInRect(local_rect))
2904 return true;
2905
2906 if (!should_check_children)
2907 return false;
2908
2909 // We can't consult child layers if we clip, since they might cover
2910 // parts of the rect that are clipped out.
2911 if (GetLayoutObject().HasClipRelatedProperty())
2912 return false;
2913
2914 // TODO(schenney): This could be improved by unioning the opaque regions of
2915 // all the children. That would require a refactoring because currently
2916 // children just check they at least cover the given rect, but a unioning
2917 // method would require children to compute and report their rects.
2918 return ChildBackgroundIsKnownToBeOpaqueInRect(local_rect);
2919 }
2920
ChildBackgroundIsKnownToBeOpaqueInRect(const PhysicalRect & local_rect) const2921 bool PaintLayer::ChildBackgroundIsKnownToBeOpaqueInRect(
2922 const PhysicalRect& local_rect) const {
2923 PaintLayerPaintOrderReverseIterator reverse_iterator(*this, kAllChildren);
2924 while (PaintLayer* child_layer = reverse_iterator.Next()) {
2925 // Stop at composited paint boundaries and non-self-painting layers.
2926 if (child_layer->IsPaintInvalidationContainer())
2927 continue;
2928
2929 if (!child_layer->CanUseConvertToLayerCoords())
2930 continue;
2931
2932 PhysicalOffset child_offset;
2933 PhysicalRect child_local_rect(local_rect);
2934 child_layer->ConvertToLayerCoords(this, child_offset);
2935 child_local_rect.Move(-child_offset);
2936
2937 if (child_layer->BackgroundIsKnownToBeOpaqueInRect(child_local_rect, true))
2938 return true;
2939 }
2940 return false;
2941 }
2942
ShouldBeSelfPaintingLayer() const2943 bool PaintLayer::ShouldBeSelfPaintingLayer() const {
2944 return GetLayoutObject().LayerTypeRequired() == kNormalPaintLayer ||
2945 (scrollable_area_ && scrollable_area_->HasOverlayOverflowControls()) ||
2946 ScrollsOverflow();
2947 }
2948
UpdateSelfPaintingLayer()2949 void PaintLayer::UpdateSelfPaintingLayer() {
2950 bool is_self_painting_layer = ShouldBeSelfPaintingLayer();
2951 if (IsSelfPaintingLayer() == is_self_painting_layer)
2952 return;
2953
2954 // Invalidate the old subsequences which may no longer contain some
2955 // descendants of this layer because of the self painting status change.
2956 SetNeedsRepaint();
2957 is_self_painting_layer_ = is_self_painting_layer;
2958 self_painting_status_changed_ = true;
2959 // Self-painting change can change the compositing container chain;
2960 // invalidate the new chain in addition to the old one.
2961 MarkCompositingContainerChainForNeedsRepaint();
2962
2963 if (is_self_painting_layer)
2964 SetNeedsVisualOverflowRecalc();
2965
2966 if (PaintLayer* parent = Parent()) {
2967 parent->MarkAncestorChainForFlagsUpdate();
2968
2969 if (PaintLayer* enclosing_self_painting_layer =
2970 parent->EnclosingSelfPaintingLayer()) {
2971 if (is_self_painting_layer)
2972 MergeNeedsPaintPhaseFlagsFrom(*enclosing_self_painting_layer);
2973 else
2974 enclosing_self_painting_layer->MergeNeedsPaintPhaseFlagsFrom(*this);
2975 }
2976 }
2977 }
2978
EnclosingSelfPaintingLayer()2979 PaintLayer* PaintLayer::EnclosingSelfPaintingLayer() {
2980 PaintLayer* layer = this;
2981 while (layer && !layer->IsSelfPaintingLayer())
2982 layer = layer->Parent();
2983 return layer;
2984 }
2985
HasNonEmptyChildLayoutObjects() const2986 bool PaintLayer::HasNonEmptyChildLayoutObjects() const {
2987 // Some HTML can cause whitespace text nodes to have layoutObjects, like:
2988 // <div>
2989 // <img src=...>
2990 // </div>
2991 // so test for 0x0 LayoutTexts here
2992 for (LayoutObject* child = GetLayoutObject().SlowFirstChild(); child;
2993 child = child->NextSibling()) {
2994 if (!child->HasLayer()) {
2995 if (child->IsLayoutInline() || !child->IsBox())
2996 return true;
2997
2998 if (ToLayoutBox(child)->Size().Width() > 0 ||
2999 ToLayoutBox(child)->Size().Height() > 0)
3000 return true;
3001 }
3002 }
3003 return false;
3004 }
3005
HasBoxDecorationsOrBackground() const3006 bool PaintLayer::HasBoxDecorationsOrBackground() const {
3007 return GetLayoutObject().StyleRef().HasBoxDecorations() ||
3008 GetLayoutObject().StyleRef().HasBackground();
3009 }
3010
HasVisibleBoxDecorations() const3011 bool PaintLayer::HasVisibleBoxDecorations() const {
3012 if (!HasVisibleContent())
3013 return false;
3014
3015 return HasBoxDecorationsOrBackground() || HasOverflowControls();
3016 }
3017
UpdateFilters(const ComputedStyle * old_style,const ComputedStyle & new_style)3018 void PaintLayer::UpdateFilters(const ComputedStyle* old_style,
3019 const ComputedStyle& new_style) {
3020 if (!filter_on_effect_node_dirty_) {
3021 filter_on_effect_node_dirty_ =
3022 old_style ? !old_style->FilterDataEquivalent(new_style) ||
3023 !old_style->ReflectionDataEquivalent(new_style)
3024 : new_style.HasFilterInducingProperty();
3025 }
3026
3027 if (!new_style.HasFilterInducingProperty() &&
3028 (!old_style || !old_style->HasFilterInducingProperty()))
3029 return;
3030
3031 const bool had_resource_info = ResourceInfo();
3032 if (new_style.HasFilterInducingProperty())
3033 new_style.Filter().AddClient(EnsureResourceInfo());
3034 if (had_resource_info && old_style)
3035 old_style->Filter().RemoveClient(*ResourceInfo());
3036 }
3037
UpdateBackdropFilters(const ComputedStyle * old_style,const ComputedStyle & new_style)3038 void PaintLayer::UpdateBackdropFilters(const ComputedStyle* old_style,
3039 const ComputedStyle& new_style) {
3040 if (!backdrop_filter_on_effect_node_dirty_) {
3041 backdrop_filter_on_effect_node_dirty_ =
3042 old_style ? !old_style->BackdropFilterDataEquivalent(new_style)
3043 : new_style.HasBackdropFilter();
3044 }
3045 }
3046
UpdateClipPath(const ComputedStyle * old_style,const ComputedStyle & new_style)3047 void PaintLayer::UpdateClipPath(const ComputedStyle* old_style,
3048 const ComputedStyle& new_style) {
3049 ClipPathOperation* new_clip = new_style.ClipPath();
3050 ClipPathOperation* old_clip = old_style ? old_style->ClipPath() : nullptr;
3051 if (!new_clip && !old_clip)
3052 return;
3053 const bool had_resource_info = ResourceInfo();
3054 if (auto* reference_clip = DynamicTo<ReferenceClipPathOperation>(new_clip))
3055 reference_clip->AddClient(EnsureResourceInfo());
3056 if (had_resource_info) {
3057 if (auto* old_reference_clip =
3058 DynamicTo<ReferenceClipPathOperation>(old_clip))
3059 old_reference_clip->RemoveClient(*ResourceInfo());
3060 }
3061 }
3062
AttemptDirectCompositingUpdate(const StyleDifference & diff,const ComputedStyle * old_style)3063 bool PaintLayer::AttemptDirectCompositingUpdate(
3064 const StyleDifference& diff,
3065 const ComputedStyle* old_style) {
3066 CompositingReasons old_potential_compositing_reasons_from_style =
3067 PotentialCompositingReasonsFromStyle();
3068 if (Compositor() &&
3069 (diff.HasDifference() || needs_compositing_reasons_update_))
3070 Compositor()->UpdatePotentialCompositingReasonsFromStyle(*this);
3071 needs_compositing_reasons_update_ = false;
3072
3073 // This function implements an optimization for transforms and opacity.
3074 // A common pattern is for a touchmove handler to update the transform
3075 // and/or an opacity of an element every frame while the user moves their
3076 // finger across the screen. The conditions below recognize when the
3077 // compositing state is set up to receive a direct transform or opacity
3078 // update.
3079
3080 if (!diff.HasAtMostPropertySpecificDifferences(
3081 StyleDifference::kTransformChanged |
3082 StyleDifference::kOpacityChanged))
3083 return false;
3084 // The potentialCompositingReasonsFromStyle could have changed without
3085 // a corresponding StyleDifference if an animation started or ended.
3086 if (PotentialCompositingReasonsFromStyle() !=
3087 old_potential_compositing_reasons_from_style)
3088 return false;
3089 if (!rare_data_ || !rare_data_->composited_layer_mapping)
3090 return false;
3091
3092 // If a transform changed, we can't use the fast path.
3093 if (diff.TransformChanged())
3094 return false;
3095
3096 // We composite transparent Layers differently from non-transparent
3097 // Layers even when the non-transparent Layers are already a
3098 // stacking context.
3099 if (diff.OpacityChanged() &&
3100 layout_object_.StyleRef().HasOpacity() != old_style->HasOpacity())
3101 return false;
3102
3103 // Changes in pointer-events affect hit test visibility of the scrollable
3104 // area and its |m_scrollsOverflow| value which determines if the layer
3105 // requires composited scrolling or not.
3106 if (scrollable_area_ &&
3107 layout_object_.StyleRef().PointerEvents() != old_style->PointerEvents())
3108 return false;
3109
3110 UpdateTransform(old_style, GetLayoutObject().StyleRef());
3111
3112 // FIXME: Consider introducing a smaller graphics layer update scope
3113 // that just handles transforms and opacity. GraphicsLayerUpdateLocal
3114 // will also program bounds, clips, and many other properties that could
3115 // not possibly have changed.
3116 rare_data_->composited_layer_mapping->SetNeedsGraphicsLayerUpdate(
3117 kGraphicsLayerUpdateLocal);
3118 if (Compositor()) {
3119 Compositor()->SetNeedsCompositingUpdate(
3120 kCompositingUpdateAfterGeometryChange);
3121 }
3122
3123 if (RequiresScrollableArea()) {
3124 DCHECK(scrollable_area_);
3125 scrollable_area_->UpdateAfterStyleChange(old_style);
3126 }
3127
3128 return true;
3129 }
3130
StyleDidChange(StyleDifference diff,const ComputedStyle * old_style)3131 void PaintLayer::StyleDidChange(StyleDifference diff,
3132 const ComputedStyle* old_style) {
3133 UpdateScrollableArea();
3134
3135 if (AttemptDirectCompositingUpdate(diff, old_style)) {
3136 if (diff.HasDifference())
3137 GetLayoutObject().SetNeedsPaintPropertyUpdate();
3138 return;
3139 }
3140
3141 if (PaintLayerStackingNode::StyleDidChange(*this, old_style))
3142 MarkAncestorChainForFlagsUpdate();
3143
3144 if (RequiresScrollableArea()) {
3145 DCHECK(scrollable_area_);
3146 scrollable_area_->UpdateAfterStyleChange(old_style);
3147 }
3148
3149 // Overlay scrollbars can make this layer self-painting so we need
3150 // to recompute the bit once scrollbars have been updated.
3151 UpdateSelfPaintingLayer();
3152
3153 const ComputedStyle& new_style = GetLayoutObject().StyleRef();
3154
3155 if (diff.CompositingReasonsChanged()) {
3156 SetNeedsCompositingInputsUpdate();
3157 } else {
3158 // For querying stale GetCompositingState().
3159 DisableCompositingQueryAsserts disable;
3160
3161 // Compositing inputs update is required when the PaintLayer is currently
3162 // composited. This is because even style changes as simple as background
3163 // color change, or pointer-events state change, can update compositing
3164 // state.
3165 if (old_style && GetCompositingState() == kPaintsIntoOwnBacking)
3166 SetNeedsCompositingInputsUpdate();
3167 }
3168
3169 // HasAlphaChanged can affect whether a composited layer is opaque.
3170 if (diff.NeedsLayout() || diff.HasAlphaChanged())
3171 SetNeedsCompositingInputsUpdate();
3172
3173 // A scroller that changes background color might become opaque or not
3174 // opaque, which in turn affects whether it can be composited on low-DPI
3175 // screens.
3176 if (GetScrollableArea() && GetScrollableArea()->ScrollsOverflow() &&
3177 diff.HasDifference()) {
3178 SetNeedsCompositingInputsUpdate();
3179 }
3180
3181 if (diff.TransformChanged() || diff.OpacityChanged() ||
3182 diff.ZIndexChanged() || diff.FilterChanged() ||
3183 diff.BackdropFilterChanged() || diff.CssClipChanged() ||
3184 diff.BlendModeChanged() || diff.MaskChanged()) {
3185 GetLayoutObject().SetNeedsPaintPropertyUpdate();
3186 SetNeedsCompositingInputsUpdate();
3187 }
3188
3189 // HasNonContainedAbsolutePositionDescendant depends on position changes.
3190 if (!old_style || old_style->GetPosition() != new_style.GetPosition())
3191 MarkAncestorChainForFlagsUpdate();
3192
3193 UpdateTransform(old_style, new_style);
3194 UpdateFilters(old_style, new_style);
3195 UpdateBackdropFilters(old_style, new_style);
3196 UpdateClipPath(old_style, new_style);
3197
3198 if (!SelfNeedsRepaint()) {
3199 if (diff.ZIndexChanged()) {
3200 // We don't need to invalidate paint of objects when paint order
3201 // changes. However, we do need to repaint the containing stacking
3202 // context, in order to generate new paint chunks in the correct order.
3203 // Raster invalidation will be issued if needed during paint.
3204 SetNeedsRepaint();
3205 } else if (old_style &&
3206 !RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
3207 // Change of PaintedOutputInvisible() will affect existence of paint
3208 // chunks, so needs repaint.
3209 if (PaintLayerPainter::PaintedOutputInvisible(*old_style) !=
3210 PaintLayerPainter::PaintedOutputInvisible(new_style))
3211 SetNeedsRepaint();
3212 }
3213 }
3214 }
3215
PixelSnappedScrolledContentOffset() const3216 LayoutSize PaintLayer::PixelSnappedScrolledContentOffset() const {
3217 if (GetLayoutObject().HasOverflowClip())
3218 return GetLayoutBox()->PixelSnappedScrolledContentOffset();
3219 return LayoutSize();
3220 }
3221
Clipper(GeometryMapperOption geometry_mapper_option) const3222 PaintLayerClipper PaintLayer::Clipper(
3223 GeometryMapperOption geometry_mapper_option) const {
3224 return PaintLayerClipper(*this, geometry_mapper_option ==
3225 GeometryMapperOption::kUseGeometryMapper);
3226 }
3227
ScrollsOverflow() const3228 bool PaintLayer::ScrollsOverflow() const {
3229 if (PaintLayerScrollableArea* scrollable_area = GetScrollableArea())
3230 return scrollable_area->ScrollsOverflow();
3231
3232 return false;
3233 }
3234
FilterOperationsIncludingReflection() const3235 FilterOperations PaintLayer::FilterOperationsIncludingReflection() const {
3236 const auto& style = GetLayoutObject().StyleRef();
3237 FilterOperations filter_operations = style.Filter();
3238 if (GetLayoutObject().HasReflection() && GetLayoutObject().IsBox()) {
3239 BoxReflection reflection = BoxReflectionForPaintLayer(*this, style);
3240 filter_operations.Operations().push_back(
3241 MakeGarbageCollected<BoxReflectFilterOperation>(reflection));
3242 }
3243 return filter_operations;
3244 }
3245
UpdateCompositorFilterOperationsForFilter(CompositorFilterOperations & operations) const3246 void PaintLayer::UpdateCompositorFilterOperationsForFilter(
3247 CompositorFilterOperations& operations) const {
3248 auto filter = FilterOperationsIncludingReflection();
3249 FloatRect reference_box = FilterReferenceBox();
3250 if (!operations.IsEmpty() && !filter_on_effect_node_dirty_ &&
3251 reference_box == operations.ReferenceBox())
3252 return;
3253 float zoom = GetLayoutObject().StyleRef().EffectiveZoom();
3254 operations =
3255 FilterEffectBuilder(reference_box, zoom).BuildFilterOperations(filter);
3256 }
3257
UpdateCompositorFilterOperationsForBackdropFilter(CompositorFilterOperations & operations,base::Optional<gfx::RRectF> * backdrop_filter_bounds) const3258 void PaintLayer::UpdateCompositorFilterOperationsForBackdropFilter(
3259 CompositorFilterOperations& operations,
3260 base::Optional<gfx::RRectF>* backdrop_filter_bounds) const {
3261 DCHECK(backdrop_filter_bounds);
3262 const auto& style = GetLayoutObject().StyleRef();
3263 if (style.BackdropFilter().IsEmpty()) {
3264 operations.Clear();
3265 backdrop_filter_bounds->reset();
3266 return;
3267 }
3268 FloatRect reference_box = BackdropFilterReferenceBox();
3269 *backdrop_filter_bounds = BackdropFilterBounds(reference_box);
3270 if (operations.IsEmpty() || backdrop_filter_on_effect_node_dirty_ ||
3271 reference_box != operations.ReferenceBox()) {
3272 operations = CreateCompositorFilterOperationsForBackdropFilter();
3273 }
3274 }
3275
3276 CompositorFilterOperations
CreateCompositorFilterOperationsForBackdropFilter() const3277 PaintLayer::CreateCompositorFilterOperationsForBackdropFilter() const {
3278 const auto& style = GetLayoutObject().StyleRef();
3279 CompositorFilterOperations return_value;
3280 if (style.BackdropFilter().IsEmpty()) {
3281 return return_value;
3282 }
3283 float zoom = style.EffectiveZoom();
3284 FloatRect reference_box = BackdropFilterReferenceBox();
3285 // Tack on regular filter values here - they need to be applied to the
3286 // backdrop image as well, in addition to being applied to the painted content
3287 // and children of the element. This is a bit of a hack - according to the
3288 // spec, filters should apply to the entire render pass as a whole, including
3289 // the backdrop-filtered content. However, because in the case that we have
3290 // both filters and backdrop-filters on a single element, we create two effect
3291 // nodes, and two render surfaces, and the backdrop-filter node comes first.
3292 // To get around that, we add the "regular" filters to the backdrop filters to
3293 // approximate.
3294 FilterOperations filter_operations = style.BackdropFilter();
3295 filter_operations.Operations().AppendVector(style.Filter().Operations());
3296 // Use kClamp tile mode to avoid pixel moving filters bringing in black
3297 // transparent pixels from the viewport edge.
3298 return_value = FilterEffectBuilder(reference_box, zoom, nullptr, nullptr,
3299 SkBlurImageFilter::kClamp_TileMode)
3300 .BuildFilterOperations(filter_operations);
3301 // Note that return_value may be empty here, if the |filter_operations| list
3302 // contains only invalid filters (e.g. invalid reference filters). See
3303 // https://crbug.com/983157 for details.
3304 return return_value;
3305 }
3306
EnsureResourceInfo()3307 PaintLayerResourceInfo& PaintLayer::EnsureResourceInfo() {
3308 PaintLayerRareData& rare_data = EnsureRareData();
3309 if (!rare_data.resource_info) {
3310 rare_data.resource_info =
3311 MakeGarbageCollected<PaintLayerResourceInfo>(this);
3312 }
3313 return *rare_data.resource_info;
3314 }
3315
RemoveAncestorOverflowLayer(const PaintLayer * removed_layer)3316 void PaintLayer::RemoveAncestorOverflowLayer(const PaintLayer* removed_layer) {
3317 // If the current ancestor overflow layer does not match the removed layer
3318 // the ancestor overflow layer has changed so we can stop searching.
3319 if (AncestorOverflowLayer() && AncestorOverflowLayer() != removed_layer)
3320 return;
3321
3322 if (AncestorOverflowLayer()) {
3323 // If the previous AncestorOverflowLayer is the root and this object is a
3324 // sticky viewport constrained object, it is no longer known to be
3325 // constrained by the root.
3326 if (AncestorOverflowLayer()->IsRootLayer() &&
3327 GetLayoutObject().StyleRef().HasStickyConstrainedPosition()) {
3328 if (LocalFrameView* frame_view = GetLayoutObject().GetFrameView())
3329 frame_view->RemoveViewportConstrainedObject(GetLayoutObject());
3330 }
3331
3332 if (PaintLayerScrollableArea* ancestor_scrollable_area =
3333 AncestorOverflowLayer()->GetScrollableArea()) {
3334 // TODO(pdr): When CompositeAfterPaint is enabled, we will need to
3335 // invalidate the scroll paint property subtree for this so main thread
3336 // scroll reasons are recomputed.
3337 ancestor_scrollable_area->InvalidateStickyConstraintsFor(this);
3338 }
3339 }
3340 UpdateAncestorOverflowLayer(nullptr);
3341 PaintLayer* current = first_;
3342 while (current) {
3343 current->RemoveAncestorOverflowLayer(removed_layer);
3344 current = current->NextSibling();
3345 }
3346 }
3347
MapRectForFilter(const FloatRect & rect) const3348 FloatRect PaintLayer::MapRectForFilter(const FloatRect& rect) const {
3349 if (!HasFilterThatMovesPixels())
3350 return rect;
3351 return FilterOperationsIncludingReflection().MapRect(rect);
3352 }
3353
MapRectForFilter(const PhysicalRect & rect) const3354 PhysicalRect PaintLayer::MapRectForFilter(const PhysicalRect& rect) const {
3355 if (!HasFilterThatMovesPixels())
3356 return rect;
3357 return PhysicalRect::EnclosingRect(MapRectForFilter(FloatRect(rect)));
3358 }
3359
HasFilterThatMovesPixels() const3360 bool PaintLayer::HasFilterThatMovesPixels() const {
3361 if (!HasFilterInducingProperty())
3362 return false;
3363 const ComputedStyle& style = GetLayoutObject().StyleRef();
3364 if (style.HasFilter() && style.Filter().HasFilterThatMovesPixels())
3365 return true;
3366 if (GetLayoutObject().HasReflection())
3367 return true;
3368 return false;
3369 }
3370
SetNeedsRepaint()3371 void PaintLayer::SetNeedsRepaint() {
3372 SetSelfNeedsRepaint();
3373
3374 // If you need repaint, then you might issue raster invalidations, and in
3375 // Composite after Paint mode, we do these in PAC::Update().
3376 LocalFrameView* frame_view = GetLayoutObject().GetDocument().View();
3377 if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() && frame_view) {
3378 frame_view->SetPaintArtifactCompositorNeedsUpdate();
3379 }
3380
3381 // Do this unconditionally to ensure container chain is marked when
3382 // compositing status of the layer changes.
3383 MarkCompositingContainerChainForNeedsRepaint();
3384 }
3385
SetSelfNeedsRepaint()3386 void PaintLayer::SetSelfNeedsRepaint() {
3387 self_needs_repaint_ = true;
3388 // Invalidate as a display item client.
3389 static_cast<DisplayItemClient*>(this)->Invalidate();
3390 }
3391
MarkCompositingContainerChainForNeedsRepaint()3392 void PaintLayer::MarkCompositingContainerChainForNeedsRepaint() {
3393 // Need to access compositingState(). We've ensured correct flag setting when
3394 // compositingState() changes.
3395 DisableCompositingQueryAsserts disabler;
3396
3397 PaintLayer* layer = this;
3398 while (true) {
3399 if (layer->GetCompositingState() == kPaintsIntoOwnBacking)
3400 return;
3401 if (CompositedLayerMapping* grouped_mapping = layer->GroupedMapping()) {
3402 // TODO(wkorman): As we clean up the CompositedLayerMapping needsRepaint
3403 // logic to delegate to scrollbars, we may be able to remove the line
3404 // below as well.
3405 grouped_mapping->OwningLayer().SetNeedsRepaint();
3406 return;
3407 }
3408
3409 // For a non-self-painting layer having self-painting descendant, the
3410 // descendant will be painted through this layer's Parent() instead of
3411 // this layer's Container(), so in addition to the CompositingContainer()
3412 // chain, we also need to mark NeedsRepaint for Parent().
3413 // TODO(crbug.com/828103): clean up this.
3414 if (layer->Parent() && !layer->IsSelfPaintingLayer())
3415 layer->Parent()->SetNeedsRepaint();
3416
3417 PaintLayer* container = layer->CompositingContainer();
3418 if (!container) {
3419 auto* owner = layer->GetLayoutObject().GetFrame()->OwnerLayoutObject();
3420 if (!owner)
3421 break;
3422 container = owner->EnclosingLayer();
3423 }
3424
3425 if (container->descendant_needs_repaint_)
3426 break;
3427
3428 container->descendant_needs_repaint_ = true;
3429 layer = container;
3430 }
3431 }
3432
ClearNeedsRepaintRecursively()3433 void PaintLayer::ClearNeedsRepaintRecursively() {
3434 for (PaintLayer* child = FirstChild(); child; child = child->NextSibling())
3435 child->ClearNeedsRepaintRecursively();
3436 self_needs_repaint_ = false;
3437 descendant_needs_repaint_ = false;
3438 }
3439
CommonAncestor(const PaintLayer * other) const3440 const PaintLayer* PaintLayer::CommonAncestor(const PaintLayer* other) const {
3441 DCHECK(other);
3442 if (this == other)
3443 return this;
3444
3445 int this_depth = 0;
3446 for (auto* layer = this; layer; layer = layer->Parent()) {
3447 if (layer == other)
3448 return layer;
3449 this_depth++;
3450 }
3451 int other_depth = 0;
3452 for (auto* layer = other; layer; layer = layer->Parent()) {
3453 if (layer == this)
3454 return layer;
3455 other_depth++;
3456 }
3457
3458 const PaintLayer* this_iterator = this;
3459 const PaintLayer* other_iterator = other;
3460 for (; this_depth > other_depth; this_depth--)
3461 this_iterator = this_iterator->Parent();
3462 for (; other_depth > this_depth; other_depth--)
3463 other_iterator = other_iterator->Parent();
3464
3465 while (this_iterator) {
3466 if (this_iterator == other_iterator)
3467 return this_iterator;
3468 this_iterator = this_iterator->Parent();
3469 other_iterator = other_iterator->Parent();
3470 }
3471
3472 DCHECK(!this_iterator);
3473 DCHECK(!other_iterator);
3474 return nullptr;
3475 }
3476
DirtyStackingContextZOrderLists()3477 void PaintLayer::DirtyStackingContextZOrderLists() {
3478 auto* stacking_context = AncestorStackingContext();
3479 if (!stacking_context)
3480 return;
3481
3482 // This invalidation code intentionally refers to stale state.
3483 DisableCompositingQueryAsserts disabler;
3484
3485 // Changes of stacking may result in graphics layers changing size
3486 // due to new contents painting into them.
3487 if (auto* mapping = stacking_context->GetCompositedLayerMapping())
3488 mapping->SetNeedsGraphicsLayerUpdate(kGraphicsLayerUpdateSubtree);
3489
3490 if (stacking_context->StackingNode())
3491 stacking_context->StackingNode()->DirtyZOrderLists();
3492
3493 MarkAncestorChainForFlagsUpdate();
3494 }
3495
DisableCompositingQueryAsserts()3496 DisableCompositingQueryAsserts::DisableCompositingQueryAsserts()
3497 : disabler_(&g_compositing_query_mode, kCompositingQueriesAreAllowed) {}
3498
3499 } // namespace blink
3500
3501 #if DCHECK_IS_ON()
showLayerTree(const blink::PaintLayer * layer)3502 void showLayerTree(const blink::PaintLayer* layer) {
3503 blink::DisableCompositingQueryAsserts disabler;
3504 if (!layer) {
3505 LOG(ERROR) << "Cannot showLayerTree. Root is (nil)";
3506 return;
3507 }
3508
3509 if (blink::LocalFrame* frame = layer->GetLayoutObject().GetFrame()) {
3510 WTF::String output =
3511 ExternalRepresentation(frame,
3512 blink::kLayoutAsTextShowAllLayers |
3513 blink::kLayoutAsTextShowLayerNesting |
3514 blink::kLayoutAsTextShowCompositedLayers |
3515 blink::kLayoutAsTextShowAddresses |
3516 blink::kLayoutAsTextShowIDAndClass |
3517 blink::kLayoutAsTextDontUpdateLayout |
3518 blink::kLayoutAsTextShowLayoutState |
3519 blink::kLayoutAsTextShowPaintProperties,
3520 layer);
3521 LOG(ERROR) << output.Utf8();
3522 }
3523 }
3524
showLayerTree(const blink::LayoutObject * layoutObject)3525 void showLayerTree(const blink::LayoutObject* layoutObject) {
3526 if (!layoutObject) {
3527 LOG(ERROR) << "Cannot showLayerTree. Root is (nil)";
3528 return;
3529 }
3530 showLayerTree(layoutObject->EnclosingLayer());
3531 }
3532 #endif
3533