1 /*
2 * Copyright (C) 2009, 2010, 2011 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
27
28 #include <memory>
29
30 #include "cc/layers/picture_layer.h"
31 #include "third_party/blink/renderer/core/accessibility/apply_dark_mode.h"
32 #include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
33 #include "third_party/blink/renderer/core/dom/dom_node_ids.h"
34 #include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h"
35 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
36 #include "third_party/blink/renderer/core/frame/remote_frame.h"
37 #include "third_party/blink/renderer/core/frame/settings.h"
38 #include "third_party/blink/renderer/core/frame/visual_viewport.h"
39 #include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h"
40 #include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h"
41 #include "third_party/blink/renderer/core/html/html_iframe_element.h"
42 #include "third_party/blink/renderer/core/html/html_image_element.h"
43 #include "third_party/blink/renderer/core/html/media/html_media_element.h"
44 #include "third_party/blink/renderer/core/html/media/html_video_element.h"
45 #include "third_party/blink/renderer/core/html_names.h"
46 #include "third_party/blink/renderer/core/layout/geometry/transform_state.h"
47 #include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
48 #include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
49 #include "third_party/blink/renderer/core/layout/layout_embedded_object.h"
50 #include "third_party/blink/renderer/core/layout/layout_html_canvas.h"
51 #include "third_party/blink/renderer/core/layout/layout_image.h"
52 #include "third_party/blink/renderer/core/layout/layout_inline.h"
53 #include "third_party/blink/renderer/core/layout/layout_shift_tracker.h"
54 #include "third_party/blink/renderer/core/layout/layout_video.h"
55 #include "third_party/blink/renderer/core/layout/layout_view.h"
56 #include "third_party/blink/renderer/core/loader/resource/image_resource_content.h"
57 #include "third_party/blink/renderer/core/page/chrome_client.h"
58 #include "third_party/blink/renderer/core/page/page.h"
59 #include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h"
60 #include "third_party/blink/renderer/core/page/scrolling/snap_coordinator.h"
61 #include "third_party/blink/renderer/core/page/scrolling/sticky_position_scrolling_constraints.h"
62 #include "third_party/blink/renderer/core/paint/clip_path_clipper.h"
63 #include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
64 #include "third_party/blink/renderer/core/paint/css_mask_painter.h"
65 #include "third_party/blink/renderer/core/paint/frame_paint_timing.h"
66 #include "third_party/blink/renderer/core/paint/object_paint_invalidator.h"
67 #include "third_party/blink/renderer/core/paint/paint_info.h"
68 #include "third_party/blink/renderer/core/paint/paint_layer_paint_order_iterator.h"
69 #include "third_party/blink/renderer/core/paint/paint_layer_painter.h"
70 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
71 #include "third_party/blink/renderer/core/paint/scrollable_area_painter.h"
72 #include "third_party/blink/renderer/core/probe/core_probes.h"
73 #include "third_party/blink/renderer/platform/fonts/font_cache.h"
74 #include "third_party/blink/renderer/platform/geometry/length_functions.h"
75 #include "third_party/blink/renderer/platform/graphics/bitmap_image.h"
76 #include "third_party/blink/renderer/platform/graphics/compositor_filter_operations.h"
77 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
78 #include "third_party/blink/renderer/platform/graphics/paint/cull_rect.h"
79 #include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
80 #include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
81 #include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
82 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
83 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
84
85 namespace blink {
86
ContentsRect(const LayoutObject & layout_object)87 static PhysicalRect ContentsRect(const LayoutObject& layout_object) {
88 if (!layout_object.IsBox())
89 return PhysicalRect();
90 if (layout_object.IsLayoutReplaced())
91 return ToLayoutReplaced(layout_object).ReplacedContentRect();
92 return ToLayoutBox(layout_object).PhysicalContentBoxRect();
93 }
94
BackgroundRect(const LayoutObject & layout_object)95 static PhysicalRect BackgroundRect(const LayoutObject& layout_object) {
96 if (!layout_object.IsBox())
97 return PhysicalRect();
98
99 const LayoutBox& box = ToLayoutBox(layout_object);
100 return box.PhysicalBackgroundRect(kBackgroundClipRect);
101 }
102
IsTextureLayerCanvas(const LayoutObject & layout_object)103 static inline bool IsTextureLayerCanvas(const LayoutObject& layout_object) {
104 if (layout_object.IsCanvas()) {
105 auto* canvas = To<HTMLCanvasElement>(layout_object.GetNode());
106 if (canvas->SurfaceLayerBridge())
107 return false;
108 if (CanvasRenderingContext* context = canvas->RenderingContext())
109 return context->IsComposited();
110 }
111 return false;
112 }
113
IsSurfaceLayerCanvas(const LayoutObject & layout_object)114 static inline bool IsSurfaceLayerCanvas(const LayoutObject& layout_object) {
115 if (layout_object.IsCanvas()) {
116 auto* canvas = To<HTMLCanvasElement>(layout_object.GetNode());
117 return canvas->SurfaceLayerBridge();
118 }
119 return false;
120 }
121
HasBoxDecorationsOrBackgroundImage(const ComputedStyle & style)122 static bool HasBoxDecorationsOrBackgroundImage(const ComputedStyle& style) {
123 return style.HasBoxDecorations() || style.HasBackgroundImage();
124 }
125
ContentLayerSupportsDirectBackgroundComposition(const LayoutObject & layout_object)126 static bool ContentLayerSupportsDirectBackgroundComposition(
127 const LayoutObject& layout_object) {
128 // No support for decorations - border, border-radius or outline.
129 // Only simple background - solid color or transparent.
130 if (HasBoxDecorationsOrBackgroundImage(layout_object.StyleRef()))
131 return false;
132
133 // If there is no background, there is nothing to support.
134 if (!layout_object.StyleRef().HasBackground())
135 return true;
136
137 // Simple background that is contained within the contents rect.
138 return ContentsRect(layout_object).Contains(BackgroundRect(layout_object));
139 }
140
GetPluginContainer(LayoutObject & layout_object)141 static WebPluginContainerImpl* GetPluginContainer(LayoutObject& layout_object) {
142 if (!layout_object.IsEmbeddedObject())
143 return nullptr;
144 return ToLayoutEmbeddedObject(layout_object).Plugin();
145 }
146
147 // Returns true if the compositor will be responsible for applying the sticky
148 // position offset for this composited layer.
UsesCompositedStickyPosition(PaintLayer & layer)149 static bool UsesCompositedStickyPosition(PaintLayer& layer) {
150 return layer.GetLayoutObject().StyleRef().HasStickyConstrainedPosition() &&
151 layer.AncestorOverflowLayer()->NeedsCompositedScrolling();
152 }
153
154 // Returns the sticky position offset that should be removed from a given layer
155 // for use in CompositedLayerMapping.
156 //
157 // If the layer is not using composited sticky position, this will return
158 // FloatPoint().
StickyPositionOffsetForLayer(PaintLayer & layer)159 static FloatPoint StickyPositionOffsetForLayer(PaintLayer& layer) {
160 if (!UsesCompositedStickyPosition(layer))
161 return FloatPoint();
162
163 const StickyConstraintsMap& constraints_map = layer.AncestorOverflowLayer()
164 ->GetScrollableArea()
165 ->GetStickyConstraintsMap();
166 const StickyPositionScrollingConstraints& constraints =
167 constraints_map.at(&layer);
168
169 return FloatPoint(constraints.GetOffsetForStickyPosition(constraints_map));
170 }
171
NeedsDecorationOutlineLayer(const PaintLayer & paint_layer,const LayoutObject & layout_object)172 static bool NeedsDecorationOutlineLayer(const PaintLayer& paint_layer,
173 const LayoutObject& layout_object) {
174 int min_border_width = std::min(
175 layout_object.StyleRef().BorderTopWidth(),
176 std::min(layout_object.StyleRef().BorderLeftWidth(),
177 std::min(layout_object.StyleRef().BorderRightWidth(),
178 layout_object.StyleRef().BorderBottomWidth())));
179
180 bool could_obscure_decorations =
181 (paint_layer.GetScrollableArea() &&
182 paint_layer.GetScrollableArea()->UsesCompositedScrolling()) ||
183 layout_object.IsCanvas() || IsA<LayoutVideo>(layout_object);
184
185 return could_obscure_decorations && layout_object.StyleRef().HasOutline() &&
186 layout_object.StyleRef().OutlineOffset() < -min_border_width;
187 }
188
CompositedLayerMapping(PaintLayer & layer)189 CompositedLayerMapping::CompositedLayerMapping(PaintLayer& layer)
190 : owning_layer_(layer),
191 pending_update_scope_(kGraphicsLayerUpdateNone),
192 scrolling_contents_are_empty_(false),
193 draws_background_onto_content_layer_(false) {
194 CreatePrimaryGraphicsLayer();
195 }
196
~CompositedLayerMapping()197 CompositedLayerMapping::~CompositedLayerMapping() {
198 // Do not leave the destroyed pointer dangling on any Layers that painted to
199 // this mapping's squashing layer.
200 for (wtf_size_t i = 0; i < squashed_layers_.size(); ++i) {
201 PaintLayer* old_squashed_layer = squashed_layers_[i].paint_layer;
202 // Assert on incorrect mappings between layers and groups
203 DCHECK_EQ(old_squashed_layer->GroupedMapping(), this);
204 if (old_squashed_layer->GroupedMapping() == this) {
205 old_squashed_layer->SetGroupedMapping(
206 nullptr, PaintLayer::kDoNotInvalidateLayerAndRemoveFromMapping);
207 old_squashed_layer->SetLostGroupedMapping(true);
208 }
209 }
210
211 UpdateOverflowControlsLayers(false, false, false);
212 UpdateForegroundLayer(false);
213 UpdateMaskLayer(false);
214 UpdateScrollingLayers(false);
215 UpdateSquashingLayers(false);
216 }
217
CreateGraphicsLayer(CompositingReasons reasons,SquashingDisallowedReasons squashing_disallowed_reasons)218 std::unique_ptr<GraphicsLayer> CompositedLayerMapping::CreateGraphicsLayer(
219 CompositingReasons reasons,
220 SquashingDisallowedReasons squashing_disallowed_reasons) {
221 auto graphics_layer = std::make_unique<GraphicsLayer>(*this);
222
223 graphics_layer->SetCompositingReasons(reasons);
224 graphics_layer->SetSquashingDisallowedReasons(squashing_disallowed_reasons);
225 if (Node* owning_node = owning_layer_.GetLayoutObject().GetNode()) {
226 graphics_layer->SetOwnerNodeId(
227 static_cast<int>(DOMNodeIds::IdForNode(owning_node)));
228 }
229
230 // Attempt to associate each layer with the frame owner's element ID.
231 Document* owner = nullptr;
232 if (GetLayoutObject().IsLayoutEmbeddedContent()) {
233 auto& embedded = ToLayoutEmbeddedContent(GetLayoutObject());
234 if (auto* frame_view =
235 DynamicTo<LocalFrameView>(embedded.GetEmbeddedContentView())) {
236 owner = frame_view->GetFrame().GetDocument();
237 } else {
238 // Ignore remote and plugin frames.
239 }
240 } else {
241 owner = &GetLayoutObject().GetDocument();
242 }
243 if (owner) {
244 graphics_layer->CcLayer()->SetFrameElementId(
245 CompositorElementIdFromUniqueObjectId(
246 DOMNodeIds::IdForNode(owner),
247 CompositorElementIdNamespace::kDOMNodeId));
248 }
249
250 return graphics_layer;
251 }
252
CreatePrimaryGraphicsLayer()253 void CompositedLayerMapping::CreatePrimaryGraphicsLayer() {
254 graphics_layer_ =
255 CreateGraphicsLayer(owning_layer_.GetCompositingReasons(),
256 owning_layer_.GetSquashingDisallowedReasons());
257
258 graphics_layer_->SetHitTestable(true);
259 }
260
UpdateContentsOpaque()261 void CompositedLayerMapping::UpdateContentsOpaque() {
262 // If there is a foreground layer, children paint into that layer and
263 // not graphics_layer_, and so don't contribute to the opaqueness of the
264 // latter.
265 bool should_check_children = !foreground_layer_.get();
266 if (IsTextureLayerCanvas(GetLayoutObject())) {
267 CanvasRenderingContext* context =
268 To<HTMLCanvasElement>(GetLayoutObject().GetNode())->RenderingContext();
269 cc::Layer* layer = context ? context->CcLayer() : nullptr;
270 // Determine whether the external texture layer covers the whole graphics
271 // layer. This may not be the case if there are box decorations or
272 // shadows.
273 if (layer && layer->bounds() == graphics_layer_->CcLayer()->bounds()) {
274 // Determine whether the rendering context's external texture layer is
275 // opaque.
276 if (!context->CreationAttributes().alpha) {
277 graphics_layer_->SetContentsOpaque(true);
278 } else {
279 graphics_layer_->SetContentsOpaque(
280 !Color(layer->background_color()).HasAlpha());
281 }
282 } else {
283 graphics_layer_->SetContentsOpaque(false);
284 }
285 } else if (IsSurfaceLayerCanvas(GetLayoutObject())) {
286 // TODO(crbug.com/705019): Contents could be opaque, but that cannot be
287 // determined from the main thread. Or can it?
288 graphics_layer_->SetContentsOpaque(false);
289 } else if (BackgroundPaintsOntoScrollingContentsLayer()) {
290 DCHECK(HasScrollingLayer());
291 // Backgrounds painted onto the foreground are clipped by the padding box
292 // rect.
293 // TODO(flackr): This should actually check the entire overflow rect
294 // within the scrolling contents layer but since we currently only trigger
295 // this for solid color backgrounds the answer will be the same.
296 scrolling_contents_layer_->SetContentsOpaque(
297 owning_layer_.BackgroundIsKnownToBeOpaqueInRect(
298 ToLayoutBox(GetLayoutObject()).PhysicalPaddingBoxRect(),
299 should_check_children));
300
301 if (BackgroundPaintsOntoGraphicsLayer()) {
302 graphics_layer_->SetContentsOpaque(
303 owning_layer_.BackgroundIsKnownToBeOpaqueInRect(
304 CompositedBounds(), should_check_children));
305 } else {
306 // If we only paint the background onto the scrolling contents layer we
307 // are going to leave a hole in the m_graphicsLayer where the background
308 // is so it is not opaque.
309 graphics_layer_->SetContentsOpaque(false);
310 }
311 } else {
312 DCHECK(BackgroundPaintsOntoGraphicsLayer());
313 if (HasScrollingLayer())
314 scrolling_contents_layer_->SetContentsOpaque(false);
315 graphics_layer_->SetContentsOpaque(
316 owning_layer_.BackgroundIsKnownToBeOpaqueInRect(CompositedBounds(),
317 should_check_children));
318 }
319 }
320
UpdateRasterizationPolicy()321 void CompositedLayerMapping::UpdateRasterizationPolicy() {
322 bool transformed_rasterization_allowed =
323 !(owning_layer_.GetCompositingReasons() &
324 CompositingReason::kComboAllDirectReasons);
325 graphics_layer_->CcLayer()->SetTransformedRasterizationAllowed(
326 transformed_rasterization_allowed);
327 if (squashing_layer_)
328 squashing_layer_->CcLayer()->SetTransformedRasterizationAllowed(true);
329 }
330
UpdateCompositedBounds()331 void CompositedLayerMapping::UpdateCompositedBounds() {
332 DCHECK_EQ(owning_layer_.Compositor()->Lifecycle().GetState(),
333 DocumentLifecycle::kInCompositingUpdate);
334 // FIXME: if this is really needed for performance, it would be better to
335 // store it on Layer.
336 composited_bounds_ = owning_layer_.BoundingBoxForCompositing();
337 }
338
UpdateCompositingReasons()339 void CompositedLayerMapping::UpdateCompositingReasons() {
340 // All other layers owned by this mapping will have the same compositing
341 // reason for their lifetime, so they are initialized only when created.
342 graphics_layer_->SetCompositingReasons(owning_layer_.GetCompositingReasons());
343 graphics_layer_->SetSquashingDisallowedReasons(
344 owning_layer_.GetSquashingDisallowedReasons());
345 }
346
UpdateGraphicsLayerConfiguration(const PaintLayer * compositing_container)347 bool CompositedLayerMapping::UpdateGraphicsLayerConfiguration(
348 const PaintLayer* compositing_container) {
349 DCHECK_EQ(owning_layer_.Compositor()->Lifecycle().GetState(),
350 DocumentLifecycle::kInCompositingUpdate);
351
352 // Note carefully: here we assume that the compositing state of all
353 // descendants have been updated already, so it is legitimate to compute and
354 // cache the composited bounds for this layer.
355 UpdateCompositedBounds();
356
357 PaintLayerCompositor* compositor = Compositor();
358 LayoutObject& layout_object = GetLayoutObject();
359 const ComputedStyle& style = layout_object.StyleRef();
360
361 bool layer_config_changed = false;
362
363 if (UpdateForegroundLayer(
364 compositor->NeedsContentsCompositingLayer(&owning_layer_)))
365 layer_config_changed = true;
366
367 if (UpdateScrollingLayers(owning_layer_.NeedsCompositedScrolling()))
368 layer_config_changed = true;
369
370 // If the outline needs to draw over the composited scrolling contents layer
371 // or scrollbar layers (or video or webgl) it needs to be drawn into a
372 // separate layer.
373 bool needs_decoration_outline_layer =
374 NeedsDecorationOutlineLayer(owning_layer_, layout_object);
375
376 if (UpdateDecorationOutlineLayer(needs_decoration_outline_layer))
377 layer_config_changed = true;
378
379 if (UpdateOverflowControlsLayers(RequiresHorizontalScrollbarLayer(),
380 RequiresVerticalScrollbarLayer(),
381 RequiresScrollCornerLayer()))
382 layer_config_changed = true;
383
384 if (UpdateSquashingLayers(!squashed_layers_.IsEmpty()))
385 layer_config_changed = true;
386
387 if (layer_config_changed)
388 UpdateInternalHierarchy();
389
390 // A mask layer is not part of the hierarchy proper, it's an auxiliary layer
391 // that's plugged into another GraphicsLayer that is part of the hierarchy.
392 // It has no parent or child GraphicsLayer. For that reason, we process it
393 // here, after the hierarchy has been updated.
394 bool has_mask =
395 CSSMaskPainter::MaskBoundingBox(GetLayoutObject(), PhysicalOffset())
396 .has_value();
397 bool has_clip_path =
398 ClipPathClipper::LocalClipPathBoundingBox(GetLayoutObject()).has_value();
399 if (UpdateMaskLayer(has_mask || has_clip_path)) {
400 graphics_layer_->SetMaskLayer(mask_layer_.get());
401 layer_config_changed = true;
402 }
403
404 UpdateBackgroundColor();
405
406 if (layout_object.IsImage()) {
407 if (IsDirectlyCompositedImage()) {
408 UpdateImageContents();
409 } else if (graphics_layer_->HasContentsLayer()) {
410 graphics_layer_->SetContentsToImage(nullptr, Image::kUnspecifiedDecode);
411 }
412 }
413
414 if (layout_object.IsLayoutEmbeddedContent()) {
415 if (WebPluginContainerImpl* plugin = GetPluginContainer(layout_object)) {
416 graphics_layer_->SetContentsToCcLayer(
417 plugin->CcLayer(), plugin->PreventContentsOpaqueChangesToCcLayer());
418 } else if (auto* frame_owner =
419 DynamicTo<HTMLFrameOwnerElement>(layout_object.GetNode())) {
420 if (auto* remote = DynamicTo<RemoteFrame>(frame_owner->ContentFrame())) {
421 graphics_layer_->SetContentsToCcLayer(
422 remote->GetCcLayer(), remote->WebLayerHasFixedContentsOpaque());
423 }
424 }
425 if (PaintLayerCompositor::AttachFrameContentLayersToIframeLayer(
426 ToLayoutEmbeddedContent(layout_object)))
427 layer_config_changed = true;
428 } else if (IsA<LayoutVideo>(layout_object)) {
429 auto* media_element = To<HTMLMediaElement>(layout_object.GetNode());
430 graphics_layer_->SetContentsToCcLayer(
431 media_element->CcLayer(),
432 /*prevent_contents_opaque_changes=*/true);
433 } else if (layout_object.IsCanvas()) {
434 graphics_layer_->SetContentsToCcLayer(
435 To<HTMLCanvasElement>(layout_object.GetNode())->ContentsCcLayer(),
436 /*prevent_contents_opaque_changes=*/false);
437 layer_config_changed = true;
438 }
439
440 if (layer_config_changed) {
441 // Changes to either the internal hierarchy or the mask layer have an impact
442 // on painting phases, so we need to update when either are updated.
443 UpdatePaintingPhases();
444 // Need to update paint LayerState of the changed GraphicsLayers.
445 // The pre-paint tree walk does this.
446 layout_object.SetNeedsPaintPropertyUpdate();
447 }
448
449 UpdateElementId();
450
451 graphics_layer_->SetHasWillChangeTransformHint(
452 style.HasWillChangeTransformHint());
453
454 if (style.Preserves3D() && style.HasOpacity() &&
455 owning_layer_.Has3DTransformedDescendant()) {
456 UseCounter::Count(layout_object.GetDocument(),
457 WebFeature::kOpacityWithPreserve3DQuirk);
458 }
459
460 return layer_config_changed;
461 }
462
ComputeOffsetFromCompositedAncestor(const PaintLayer * layer,const PaintLayer * composited_ancestor,const PhysicalOffset & local_representative_point_for_fragmentation,const FloatPoint & offset_for_sticky_position)463 static PhysicalOffset ComputeOffsetFromCompositedAncestor(
464 const PaintLayer* layer,
465 const PaintLayer* composited_ancestor,
466 const PhysicalOffset& local_representative_point_for_fragmentation,
467 const FloatPoint& offset_for_sticky_position) {
468 // Add in the offset of the composited bounds from the coordinate space of
469 // the PaintLayer, since visualOffsetFromAncestor() requires the pre-offset
470 // input to be in the space of the PaintLayer. We also need to add in this
471 // offset before computation of visualOffsetFromAncestor(), because it affects
472 // fragmentation offset if compositedAncestor crosses a pagination boundary.
473 //
474 // Currently, visual fragmentation for composited layers is not implemented.
475 // For fragmented contents, we paint in the logical coordinates of the flow
476 // thread, then split the result by fragment boundary and paste each part
477 // into each fragment's physical position.
478 // Since composited layers don't support visual fragmentation, we have to
479 // choose a "representative" fragment to position the painted contents. This
480 // is where localRepresentativePointForFragmentation comes into play.
481 // The fragment that the representative point resides in will be chosen as
482 // the representative fragment for layer position purpose.
483 // For layers that are not fragmented, the point doesn't affect behavior as
484 // there is one and only one fragment.
485 PhysicalOffset offset = layer->VisualOffsetFromAncestor(
486 composited_ancestor, local_representative_point_for_fragmentation);
487 if (composited_ancestor)
488 offset += composited_ancestor->SubpixelAccumulation();
489 offset -= local_representative_point_for_fragmentation;
490 offset -= PhysicalOffset::FromFloatPointRound(offset_for_sticky_position);
491 return offset;
492 }
493
ComputeBoundsOfOwningLayer(const PaintLayer * composited_ancestor,IntRect & local_bounds,IntPoint & snapped_offset_from_composited_ancestor)494 void CompositedLayerMapping::ComputeBoundsOfOwningLayer(
495 const PaintLayer* composited_ancestor,
496 IntRect& local_bounds,
497 IntPoint& snapped_offset_from_composited_ancestor) {
498 // HACK(chrishtr): adjust for position of inlines.
499 PhysicalOffset local_representative_point_for_fragmentation;
500 if (owning_layer_.GetLayoutObject().IsLayoutInline()) {
501 local_representative_point_for_fragmentation =
502 ToLayoutInline(owning_layer_.GetLayoutObject()).FirstLineBoxTopLeft();
503 }
504 // Blink will already have applied any necessary offset for sticky positioned
505 // elements. If the compositor is handling sticky offsets for this layer, we
506 // need to remove the Blink-side offset to avoid double-counting.
507 FloatPoint offset_for_sticky_position =
508 StickyPositionOffsetForLayer(owning_layer_);
509 PhysicalOffset offset_from_composited_ancestor =
510 ComputeOffsetFromCompositedAncestor(
511 &owning_layer_, composited_ancestor,
512 local_representative_point_for_fragmentation,
513 offset_for_sticky_position);
514 snapped_offset_from_composited_ancestor =
515 RoundedIntPoint(offset_from_composited_ancestor);
516
517 PhysicalOffset subpixel_accumulation;
518 if (!owning_layer_.Transform() ||
519 owning_layer_.Transform()->IsIdentityOrTranslation()) {
520 subpixel_accumulation =
521 offset_from_composited_ancestor -
522 PhysicalOffset(snapped_offset_from_composited_ancestor);
523 }
524
525 // Invalidate the whole layer when subpixel accumulation changes, since
526 // the previous subpixel accumulation is baked into the dispay list.
527 // However, don't do so for directly composited layers, to avoid impacting
528 // performance.
529 if (subpixel_accumulation != owning_layer_.SubpixelAccumulation()) {
530 // Always invalidate if under-invalidation checking is on, to avoid
531 // false positives.
532 if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled())
533 SetContentsNeedDisplay();
534 else if (!(owning_layer_.GetCompositingReasons() &
535 CompositingReason::kComboAllDirectReasons))
536 SetContentsNeedDisplay();
537 }
538
539 // Otherwise discard the sub-pixel remainder because paint offset can't be
540 // transformed by a non-translation transform.
541 owning_layer_.SetSubpixelAccumulation(subpixel_accumulation);
542
543 base::Optional<IntRect> mask_bounding_box =
544 CSSMaskPainter::MaskBoundingBox(GetLayoutObject(), subpixel_accumulation);
545 base::Optional<FloatRect> clip_path_bounding_box =
546 ClipPathClipper::LocalClipPathBoundingBox(GetLayoutObject());
547 if (clip_path_bounding_box)
548 clip_path_bounding_box->MoveBy(FloatPoint(subpixel_accumulation));
549
550 // Override graphics layer size to the bound of mask layer, this is because
551 // the compositor implementation requires mask layer bound to match its
552 // host layer.
553 if (mask_bounding_box) {
554 local_bounds = *mask_bounding_box;
555 if (clip_path_bounding_box)
556 local_bounds.Intersect(EnclosingIntRect(*clip_path_bounding_box));
557 } else if (clip_path_bounding_box) {
558 local_bounds = EnclosingIntRect(*clip_path_bounding_box);
559 } else {
560 // Move the bounds by the subpixel accumulation so that it pixel-snaps
561 // relative to absolute pixels instead of local coordinates.
562 PhysicalRect local_raw_compositing_bounds = CompositedBounds();
563 local_raw_compositing_bounds.Move(subpixel_accumulation);
564 local_bounds = PixelSnappedIntRect(local_raw_compositing_bounds);
565 }
566 }
567
UpdateSquashingLayerGeometry(const PaintLayer * compositing_container,const IntPoint & snapped_offset_from_composited_ancestor,Vector<GraphicsLayerPaintInfo> & layers,Vector<PaintLayer * > & layers_needing_paint_invalidation)568 void CompositedLayerMapping::UpdateSquashingLayerGeometry(
569 const PaintLayer* compositing_container,
570 const IntPoint& snapped_offset_from_composited_ancestor,
571 Vector<GraphicsLayerPaintInfo>& layers,
572 Vector<PaintLayer*>& layers_needing_paint_invalidation) {
573 if (!squashing_layer_)
574 return;
575
576 IntPoint graphics_layer_parent_location;
577 ComputeGraphicsLayerParentLocation(compositing_container,
578 graphics_layer_parent_location);
579
580 PhysicalOffset compositing_container_offset_from_parent_graphics_layer(
581 -graphics_layer_parent_location);
582 if (compositing_container) {
583 compositing_container_offset_from_parent_graphics_layer +=
584 compositing_container->SubpixelAccumulation();
585 }
586
587 const PaintLayer* common_transform_ancestor = nullptr;
588 if (compositing_container && compositing_container->Transform()) {
589 common_transform_ancestor = compositing_container;
590 } else if (compositing_container) {
591 common_transform_ancestor =
592 &compositing_container->TransformAncestorOrRoot();
593 } else {
594 common_transform_ancestor = owning_layer_.Root();
595 }
596
597 // FIXME: Cache these offsets.
598 PhysicalOffset compositing_container_offset_from_transformed_ancestor;
599 if (compositing_container) {
600 compositing_container_offset_from_transformed_ancestor =
601 compositing_container->ComputeOffsetFromAncestor(
602 *common_transform_ancestor);
603 }
604
605 PhysicalRect total_squash_bounds;
606 for (wtf_size_t i = 0; i < layers.size(); ++i) {
607 PhysicalRect squashed_bounds =
608 layers[i].paint_layer->BoundingBoxForCompositing();
609
610 // Store the local bounds of the Layer subtree before applying the offset.
611 layers[i].composited_bounds = squashed_bounds;
612
613 PhysicalOffset squashed_layer_offset_from_transformed_ancestor =
614 layers[i].paint_layer->ComputeOffsetFromAncestor(
615 *common_transform_ancestor);
616 PhysicalOffset squashed_layer_offset_from_compositing_container =
617 squashed_layer_offset_from_transformed_ancestor -
618 compositing_container_offset_from_transformed_ancestor;
619
620 squashed_bounds.Move(squashed_layer_offset_from_compositing_container);
621 total_squash_bounds.Unite(squashed_bounds);
622 }
623
624 // The totalSquashBounds is positioned with respect to compositingContainer.
625 // But the squashingLayer needs to be positioned with respect to the
626 // graphicsLayerParent. The conversion between compositingContainer and the
627 // graphicsLayerParent is already computed as
628 // compositingContainerOffsetFromParentGraphicsLayer.
629 total_squash_bounds.Move(
630 compositing_container_offset_from_parent_graphics_layer);
631 const IntRect squash_layer_bounds = EnclosingIntRect(total_squash_bounds);
632 const IntPoint squash_layer_origin = squash_layer_bounds.Location();
633 const PhysicalOffset squash_layer_origin_in_compositing_container_space =
634 PhysicalOffset(squash_layer_origin) -
635 compositing_container_offset_from_parent_graphics_layer;
636
637 // Now that the squashing bounds are known, we can convert the PaintLayer
638 // painting offsets from compositingContainer space to the squashing layer
639 // space.
640 //
641 // The painting offset we want to compute for each squashed PaintLayer is
642 // essentially the position of the squashed PaintLayer described w.r.t.
643 // compositingContainer's origin. So we just need to convert that point from
644 // compositingContainer space to the squashing layer's space. This is done by
645 // subtracting squashLayerOriginInCompositingContainerSpace, but then the
646 // offset overall needs to be negated because that's the direction that the
647 // painting code expects the offset to be.
648 for (wtf_size_t i = 0; i < layers.size(); ++i) {
649 const PhysicalOffset squashed_layer_offset_from_transformed_ancestor =
650 layers[i].paint_layer->ComputeOffsetFromAncestor(
651 *common_transform_ancestor);
652 const PhysicalOffset offset_from_squash_layer_origin =
653 (squashed_layer_offset_from_transformed_ancestor -
654 compositing_container_offset_from_transformed_ancestor) -
655 squash_layer_origin_in_compositing_container_space;
656
657 IntSize new_offset_from_layout_object =
658 -ToIntSize(RoundedIntPoint(offset_from_squash_layer_origin));
659 PhysicalOffset subpixel_accumulation =
660 offset_from_squash_layer_origin +
661 PhysicalOffset(new_offset_from_layout_object);
662 if (layers[i].offset_from_layout_object_set &&
663 layers[i].offset_from_layout_object != new_offset_from_layout_object) {
664 ObjectPaintInvalidator(layers[i].paint_layer->GetLayoutObject())
665 .InvalidatePaintIncludingNonCompositingDescendants();
666 layers_needing_paint_invalidation.push_back(layers[i].paint_layer);
667 }
668 layers[i].offset_from_layout_object = new_offset_from_layout_object;
669 layers[i].offset_from_layout_object_set = true;
670
671 layers[i].paint_layer->SetSubpixelAccumulation(subpixel_accumulation);
672 }
673
674 squashing_layer_->SetSize(gfx::Size(squash_layer_bounds.Size()));
675 // We can't squashing_layer_->SetOffsetFromLayoutObject().
676 // Squashing layer has special paint and invalidation logic that already
677 // compensated for compositing bounds, setting it here would end up
678 // double adjustment.
679 auto new_offset = squash_layer_bounds.Location() -
680 snapped_offset_from_composited_ancestor +
681 ToIntSize(graphics_layer_parent_location);
682 if (new_offset != squashing_layer_offset_from_layout_object_) {
683 squashing_layer_offset_from_layout_object_ = new_offset;
684 // Need to update squashing LayerState according to the new offset.
685 // The pre-paint tree walk does this.
686 GetLayoutObject().SetNeedsPaintPropertyUpdate();
687 }
688
689 for (wtf_size_t i = 0; i < layers.size(); ++i) {
690 LocalClipRectForSquashedLayer(owning_layer_, layers, layers[i]);
691 }
692 }
693
UpdateGraphicsLayerGeometry(const PaintLayer * compositing_container,Vector<PaintLayer * > & layers_needing_paint_invalidation)694 void CompositedLayerMapping::UpdateGraphicsLayerGeometry(
695 const PaintLayer* compositing_container,
696 Vector<PaintLayer*>& layers_needing_paint_invalidation) {
697 DCHECK_EQ(owning_layer_.Compositor()->Lifecycle().GetState(),
698 DocumentLifecycle::kInCompositingUpdate);
699
700 IntRect local_compositing_bounds;
701 IntPoint snapped_offset_from_composited_ancestor;
702 ComputeBoundsOfOwningLayer(compositing_container, local_compositing_bounds,
703 snapped_offset_from_composited_ancestor);
704
705 UpdateMainGraphicsLayerGeometry(local_compositing_bounds);
706 UpdateOverflowControlsHostLayerGeometry(compositing_container);
707 UpdateSquashingLayerGeometry(
708 compositing_container, snapped_offset_from_composited_ancestor,
709 squashed_layers_, layers_needing_paint_invalidation);
710
711 UpdateMaskLayerGeometry();
712 // TODO(yigu): Currently the decoration layer uses the same contentSize
713 // as the foreground layer. There are scenarios where the sizes could be
714 // different so the decoration layer size should be calculated separately.
715 UpdateDecorationOutlineLayerGeometry(local_compositing_bounds.Size());
716 UpdateScrollingLayerGeometry();
717 UpdateForegroundLayerGeometry();
718
719 if (owning_layer_.GetScrollableArea() &&
720 owning_layer_.GetScrollableArea()->ScrollsOverflow())
721 owning_layer_.GetScrollableArea()->PositionOverflowControls();
722
723 UpdateContentsRect();
724 UpdateBackgroundColor();
725 UpdateDrawsContentAndPaintsHitTest();
726 UpdateElementId();
727 UpdateContentsOpaque();
728 UpdateRasterizationPolicy();
729 UpdateCompositingReasons();
730 }
731
UpdateMainGraphicsLayerGeometry(const IntRect & local_compositing_bounds)732 void CompositedLayerMapping::UpdateMainGraphicsLayerGeometry(
733 const IntRect& local_compositing_bounds) {
734 graphics_layer_->SetOffsetFromLayoutObject(
735 ToIntSize(local_compositing_bounds.Location()));
736 graphics_layer_->SetSize(gfx::Size(local_compositing_bounds.Size()));
737
738 // m_graphicsLayer is the corresponding GraphicsLayer for this PaintLayer and
739 // its non-compositing descendants. So, the visibility flag for
740 // m_graphicsLayer should be true if there are any non-compositing visible
741 // layers.
742 bool contents_visible = owning_layer_.HasVisibleContent() ||
743 HasVisibleNonCompositingDescendant(&owning_layer_);
744 // TODO(sunxd): Investigate and possibly implement computing hit test regions
745 // in PaintTouchActionRects code path, so that cc has correct pointer-events
746 // information.
747 // For now, there is no need to set graphics_layer_'s hit testable bit here,
748 // because it is always hit testable from cc's perspective.
749 graphics_layer_->SetContentsVisible(contents_visible);
750 }
751
ComputeGraphicsLayerParentLocation(const PaintLayer * compositing_container,IntPoint & graphics_layer_parent_location)752 void CompositedLayerMapping::ComputeGraphicsLayerParentLocation(
753 const PaintLayer* compositing_container,
754 IntPoint& graphics_layer_parent_location) {
755 if (compositing_container) {
756 graphics_layer_parent_location =
757 IntPoint(compositing_container->GetCompositedLayerMapping()
758 ->ParentForSublayers()
759 ->OffsetFromLayoutObject());
760 } else if (!GetLayoutObject().GetFrame()->IsLocalRoot()) { // TODO(oopif)
761 DCHECK(!compositing_container);
762 graphics_layer_parent_location = IntPoint();
763 }
764
765 if (compositing_container &&
766 compositing_container->NeedsCompositedScrolling()) {
767 LayoutBox& layout_box =
768 ToLayoutBox(compositing_container->GetLayoutObject());
769 IntSize scroll_offset =
770 FlooredIntSize(layout_box.PixelSnappedScrolledContentOffset());
771 IntPoint scroll_origin =
772 compositing_container->GetScrollableArea()->ScrollOrigin();
773 scroll_origin.Move(-layout_box.OriginAdjustmentForScrollbars());
774 scroll_origin.Move(-layout_box.BorderLeft().ToInt(),
775 -layout_box.BorderTop().ToInt());
776 graphics_layer_parent_location = -(scroll_origin + scroll_offset);
777 }
778 }
779
UpdateOverflowControlsHostLayerGeometry(const PaintLayer * compositing_container)780 void CompositedLayerMapping::UpdateOverflowControlsHostLayerGeometry(
781 const PaintLayer* compositing_container) {
782 if (!overflow_controls_host_layer_)
783 return;
784
785 // To clip the scrollbars correctly, overflow_controls_host_layer_ should
786 // match our border box size.
787 const IntSize border_box_size =
788 owning_layer_.GetLayoutBox()->PixelSnappedBorderBoxSize(
789 PhysicalOffset(owning_layer_.SubpixelAccumulation() +
790 owning_layer_.GetLayoutBox()->PhysicalLocation()));
791 overflow_controls_host_layer_->SetSize(gfx::Size(border_box_size));
792 }
793
UpdateMaskLayerGeometry()794 void CompositedLayerMapping::UpdateMaskLayerGeometry() {
795 if (!mask_layer_)
796 return;
797
798 if (mask_layer_->Size() != graphics_layer_->Size()) {
799 mask_layer_->SetSize(graphics_layer_->Size());
800 mask_layer_->SetNeedsDisplay();
801 }
802 mask_layer_->SetOffsetFromLayoutObject(
803 graphics_layer_->OffsetFromLayoutObject());
804 }
805
UpdateScrollingLayerGeometry()806 void CompositedLayerMapping::UpdateScrollingLayerGeometry() {
807 if (!scrolling_layer_)
808 return;
809
810 DCHECK(scrolling_contents_layer_);
811 LayoutBox& layout_box = ToLayoutBox(GetLayoutObject());
812 IntRect overflow_clip_rect = PixelSnappedIntRect(
813 layout_box.OverflowClipRect(owning_layer_.SubpixelAccumulation()));
814
815 auto old_scroll_container_size = scrolling_layer_->Size();
816 scrolling_layer_->SetSize(gfx::Size(overflow_clip_rect.Size()));
817 bool scroll_container_size_changed =
818 old_scroll_container_size != scrolling_layer_->Size();
819
820 scrolling_layer_->SetOffsetFromLayoutObject(
821 ToIntSize(overflow_clip_rect.Location()));
822
823 PaintLayerScrollableArea* scrollable_area = owning_layer_.GetScrollableArea();
824 IntSize scroll_size = scrollable_area->PixelSnappedContentsSize(
825 owning_layer_.SubpixelAccumulation());
826
827 // Ensure scrolling contents are at least as large as the scroll clip
828 scroll_size = scroll_size.ExpandedTo(overflow_clip_rect.Size());
829
830 auto* scrolling_coordinator = owning_layer_.GetScrollingCoordinator();
831 scrolling_coordinator->UpdateCompositorScrollOffset(*layout_box.GetFrame(),
832 *scrollable_area);
833
834 if (gfx::Size(scroll_size) != scrolling_contents_layer_->Size() ||
835 scroll_container_size_changed) {
836 scrolling_coordinator->ScrollableAreaScrollLayerDidChange(scrollable_area);
837 }
838
839 scrolling_contents_layer_->SetSize(gfx::Size(scroll_size));
840
841 scrolling_contents_layer_->SetOffsetFromLayoutObject(
842 overflow_clip_rect.Location() - scrollable_area->ScrollOrigin());
843 }
844
RequiresHorizontalScrollbarLayer() const845 bool CompositedLayerMapping::RequiresHorizontalScrollbarLayer() const {
846 return owning_layer_.GetScrollableArea() &&
847 owning_layer_.GetScrollableArea()->HorizontalScrollbar();
848 }
849
RequiresVerticalScrollbarLayer() const850 bool CompositedLayerMapping::RequiresVerticalScrollbarLayer() const {
851 return owning_layer_.GetScrollableArea() &&
852 owning_layer_.GetScrollableArea()->VerticalScrollbar();
853 }
854
RequiresScrollCornerLayer() const855 bool CompositedLayerMapping::RequiresScrollCornerLayer() const {
856 return owning_layer_.GetScrollableArea() &&
857 !owning_layer_.GetScrollableArea()
858 ->ScrollCornerAndResizerRect()
859 .IsEmpty();
860 }
861
UpdateForegroundLayerGeometry()862 void CompositedLayerMapping::UpdateForegroundLayerGeometry() {
863 if (!foreground_layer_)
864 return;
865
866 // Should be equivalent to local_compositing_bounds.
867 IntRect compositing_bounds(
868 IntPoint(graphics_layer_->OffsetFromLayoutObject()),
869 IntSize(graphics_layer_->Size()));
870 if (scrolling_layer_) {
871 // Override compositing bounds to include full overflow if composited
872 // scrolling is used.
873 compositing_bounds =
874 IntRect(IntPoint(scrolling_contents_layer_->OffsetFromLayoutObject()),
875 IntSize(scrolling_contents_layer_->Size()));
876 }
877
878 IntRect old_compositing_bounds(
879 IntPoint(foreground_layer_->OffsetFromLayoutObject()),
880 IntSize(foreground_layer_->Size()));
881 if (compositing_bounds != old_compositing_bounds) {
882 foreground_layer_->SetOffsetFromLayoutObject(
883 ToIntSize(compositing_bounds.Location()));
884 foreground_layer_->SetSize(gfx::Size(compositing_bounds.Size()));
885 foreground_layer_->SetNeedsDisplay();
886 }
887 }
888
UpdateDecorationOutlineLayerGeometry(const IntSize & relative_compositing_bounds_size)889 void CompositedLayerMapping::UpdateDecorationOutlineLayerGeometry(
890 const IntSize& relative_compositing_bounds_size) {
891 if (!decoration_outline_layer_)
892 return;
893 const auto& decoration_size = relative_compositing_bounds_size;
894 if (gfx::Size(decoration_size) != decoration_outline_layer_->Size()) {
895 decoration_outline_layer_->SetSize(gfx::Size(decoration_size));
896 decoration_outline_layer_->SetNeedsDisplay();
897 }
898 decoration_outline_layer_->SetOffsetFromLayoutObject(
899 graphics_layer_->OffsetFromLayoutObject());
900 }
901
UpdateInternalHierarchy()902 void CompositedLayerMapping::UpdateInternalHierarchy() {
903 // m_foregroundLayer has to be inserted in the correct order with child
904 // layers, so it's not inserted here.
905 graphics_layer_->RemoveFromParent();
906
907 // Layer to which children should be attached as we build the hierarchy.
908 GraphicsLayer* bottom_layer = graphics_layer_.get();
909 auto update_bottom_layer = [&bottom_layer](GraphicsLayer* layer) {
910 if (layer) {
911 bottom_layer->AddChild(layer);
912 bottom_layer = layer;
913 }
914 };
915
916 update_bottom_layer(scrolling_layer_.get());
917
918 // Now constructing the subtree for the overflow controls.
919 bottom_layer = graphics_layer_.get();
920 update_bottom_layer(overflow_controls_host_layer_.get());
921 if (layer_for_horizontal_scrollbar_) {
922 overflow_controls_host_layer_->AddChild(
923 layer_for_horizontal_scrollbar_.get());
924 }
925 if (layer_for_vertical_scrollbar_) {
926 overflow_controls_host_layer_->AddChild(
927 layer_for_vertical_scrollbar_.get());
928 }
929 if (layer_for_scroll_corner_)
930 overflow_controls_host_layer_->AddChild(layer_for_scroll_corner_.get());
931
932 // Now add the DecorationOutlineLayer as a subtree to GraphicsLayer
933 if (decoration_outline_layer_.get())
934 graphics_layer_->AddChild(decoration_outline_layer_.get());
935
936 // The squashing containment layer, if it exists, becomes a no-op parent.
937 if (squashing_layer_) {
938 if (squashing_containment_layer_) {
939 squashing_containment_layer_->RemoveAllChildren();
940 squashing_containment_layer_->AddChild(graphics_layer_.get());
941 squashing_containment_layer_->AddChild(squashing_layer_.get());
942 }
943 }
944 }
945
UpdatePaintingPhases()946 void CompositedLayerMapping::UpdatePaintingPhases() {
947 graphics_layer_->SetPaintingPhase(PaintingPhaseForPrimaryLayer());
948 if (scrolling_contents_layer_) {
949 GraphicsLayerPaintingPhase paint_phase =
950 kGraphicsLayerPaintOverflowContents |
951 kGraphicsLayerPaintCompositedScroll;
952 if (!foreground_layer_)
953 paint_phase |= kGraphicsLayerPaintForeground;
954 scrolling_contents_layer_->SetPaintingPhase(paint_phase);
955 }
956 if (foreground_layer_) {
957 GraphicsLayerPaintingPhase paint_phase = kGraphicsLayerPaintForeground;
958 if (scrolling_contents_layer_)
959 paint_phase |= kGraphicsLayerPaintOverflowContents;
960 foreground_layer_->SetPaintingPhase(paint_phase);
961 }
962 }
963
UpdateContentsRect()964 void CompositedLayerMapping::UpdateContentsRect() {
965 graphics_layer_->SetContentsRect(PixelSnappedIntRect(ContentsBox()));
966 }
967
UpdateDrawsContentAndPaintsHitTest()968 void CompositedLayerMapping::UpdateDrawsContentAndPaintsHitTest() {
969 bool in_overlay_fullscreen_video = false;
970 if (IsA<LayoutVideo>(GetLayoutObject())) {
971 auto* video_element = To<HTMLVideoElement>(GetLayoutObject().GetNode());
972 if (video_element->IsFullscreen() &&
973 video_element->UsesOverlayFullscreenVideo())
974 in_overlay_fullscreen_video = true;
975 }
976 bool has_painted_content =
977 in_overlay_fullscreen_video ? false : ContainsPaintedContent();
978 graphics_layer_->SetDrawsContent(has_painted_content);
979
980 // |has_painted_content| is conservative (e.g., will be true if any descendant
981 // paints content, regardless of whether the descendant content is a hit test)
982 // but an exhaustive check of descendants that paint hit tests would be too
983 // expensive.
984 bool paints_hit_test =
985 has_painted_content || GetLayoutObject().HasEffectiveAllowedTouchAction();
986 bool paints_scroll_hit_test =
987 ((owning_layer_.GetScrollableArea() &&
988 owning_layer_.GetScrollableArea()->ScrollsOverflow()) ||
989 (GetPluginContainer(GetLayoutObject()) &&
990 GetPluginContainer(GetLayoutObject())->WantsWheelEvents()));
991 graphics_layer_->SetPaintsHitTest(paints_hit_test || paints_scroll_hit_test);
992
993 if (scrolling_layer_) {
994 // m_scrollingLayer never has backing store.
995 // m_scrollingContentsLayer only needs backing store if the scrolled
996 // contents need to paint.
997 scrolling_contents_are_empty_ =
998 !owning_layer_.HasVisibleContent() ||
999 !(GetLayoutObject().StyleRef().HasBackground() ||
1000 GetLayoutObject().HasBackdropFilter() || PaintsChildren());
1001 scrolling_contents_layer_->SetDrawsContent(!scrolling_contents_are_empty_);
1002 scrolling_contents_layer_->SetPaintsHitTest(paints_hit_test);
1003 }
1004
1005 draws_background_onto_content_layer_ = false;
1006
1007 if (has_painted_content && IsTextureLayerCanvas(GetLayoutObject())) {
1008 CanvasRenderingContext* context =
1009 To<HTMLCanvasElement>(GetLayoutObject().GetNode())->RenderingContext();
1010 // Content layer may be null if context is lost.
1011 if (cc::Layer* content_layer = context->CcLayer()) {
1012 Color bg_color(Color::kTransparent);
1013 if (ContentLayerSupportsDirectBackgroundComposition(GetLayoutObject())) {
1014 bg_color = LayoutObjectBackgroundColor();
1015 has_painted_content = false;
1016 draws_background_onto_content_layer_ = true;
1017 }
1018 content_layer->SetBackgroundColor(bg_color.Rgb());
1019 }
1020 }
1021
1022 // FIXME: we could refine this to only allocate backings for one of these
1023 // layers if possible.
1024 if (foreground_layer_) {
1025 foreground_layer_->SetDrawsContent(has_painted_content);
1026 foreground_layer_->SetPaintsHitTest(paints_hit_test);
1027 }
1028
1029 if (decoration_outline_layer_)
1030 decoration_outline_layer_->SetDrawsContent(true);
1031
1032 if (mask_layer_)
1033 mask_layer_->SetDrawsContent(true);
1034 }
1035
ToggleScrollbarLayerIfNeeded(std::unique_ptr<GraphicsLayer> & layer,bool needs_layer,CompositingReasons reason)1036 bool CompositedLayerMapping::ToggleScrollbarLayerIfNeeded(
1037 std::unique_ptr<GraphicsLayer>& layer,
1038 bool needs_layer,
1039 CompositingReasons reason) {
1040 if (needs_layer == !!layer)
1041 return false;
1042 layer = needs_layer ? CreateGraphicsLayer(reason) : nullptr;
1043
1044 if (PaintLayerScrollableArea* scrollable_area =
1045 owning_layer_.GetScrollableArea()) {
1046 if (ScrollingCoordinator* scrolling_coordinator =
1047 owning_layer_.GetScrollingCoordinator()) {
1048 if (reason == CompositingReason::kLayerForHorizontalScrollbar) {
1049 scrolling_coordinator->ScrollableAreaScrollbarLayerDidChange(
1050 scrollable_area, kHorizontalScrollbar);
1051 } else if (reason == CompositingReason::kLayerForVerticalScrollbar) {
1052 scrolling_coordinator->ScrollableAreaScrollbarLayerDidChange(
1053 scrollable_area, kVerticalScrollbar);
1054 }
1055 }
1056 }
1057 return true;
1058 }
1059
UpdateOverflowControlsLayers(bool needs_horizontal_scrollbar_layer,bool needs_vertical_scrollbar_layer,bool needs_scroll_corner_layer)1060 bool CompositedLayerMapping::UpdateOverflowControlsLayers(
1061 bool needs_horizontal_scrollbar_layer,
1062 bool needs_vertical_scrollbar_layer,
1063 bool needs_scroll_corner_layer) {
1064 if (PaintLayerScrollableArea* scrollable_area =
1065 owning_layer_.GetScrollableArea()) {
1066 // If the scrollable area is marked as needing a new scrollbar layer,
1067 // destroy the layer now so that it will be created again below.
1068 if (layer_for_horizontal_scrollbar_ && needs_horizontal_scrollbar_layer &&
1069 scrollable_area->ShouldRebuildHorizontalScrollbarLayer()) {
1070 ToggleScrollbarLayerIfNeeded(
1071 layer_for_horizontal_scrollbar_, false,
1072 CompositingReason::kLayerForHorizontalScrollbar);
1073 }
1074 if (layer_for_vertical_scrollbar_ && needs_vertical_scrollbar_layer &&
1075 scrollable_area->ShouldRebuildVerticalScrollbarLayer()) {
1076 ToggleScrollbarLayerIfNeeded(
1077 layer_for_vertical_scrollbar_, false,
1078 CompositingReason::kLayerForVerticalScrollbar);
1079 }
1080 scrollable_area->ResetRebuildScrollbarLayerFlags();
1081
1082 if (scrolling_contents_layer_ &&
1083 scrollable_area->NeedsShowScrollbarLayers()) {
1084 scrolling_contents_layer_->CcLayer()->ShowScrollbars();
1085 scrollable_area->DidShowScrollbarLayers();
1086 }
1087 }
1088
1089 // If the subtree is invisible, we don't actually need scrollbar layers.
1090 // Only do this check if at least one of the bits is currently true.
1091 // This is important because this method is called during the destructor
1092 // of CompositedLayerMapping, which may happen during style recalc,
1093 // and therefore visible content status may be invalid.
1094 if (needs_horizontal_scrollbar_layer || needs_vertical_scrollbar_layer ||
1095 needs_scroll_corner_layer) {
1096 bool invisible = owning_layer_.SubtreeIsInvisible();
1097 needs_horizontal_scrollbar_layer &= !invisible;
1098 needs_vertical_scrollbar_layer &= !invisible;
1099 needs_scroll_corner_layer &= !invisible;
1100 }
1101
1102 bool horizontal_scrollbar_layer_changed = ToggleScrollbarLayerIfNeeded(
1103 layer_for_horizontal_scrollbar_, needs_horizontal_scrollbar_layer,
1104 CompositingReason::kLayerForHorizontalScrollbar);
1105 bool vertical_scrollbar_layer_changed = ToggleScrollbarLayerIfNeeded(
1106 layer_for_vertical_scrollbar_, needs_vertical_scrollbar_layer,
1107 CompositingReason::kLayerForVerticalScrollbar);
1108 bool scroll_corner_layer_changed = ToggleScrollbarLayerIfNeeded(
1109 layer_for_scroll_corner_, needs_scroll_corner_layer,
1110 CompositingReason::kLayerForScrollCorner);
1111
1112 bool needs_overflow_controls_host_layer = needs_horizontal_scrollbar_layer ||
1113 needs_vertical_scrollbar_layer ||
1114 needs_scroll_corner_layer;
1115 ToggleScrollbarLayerIfNeeded(
1116 overflow_controls_host_layer_, needs_overflow_controls_host_layer,
1117 CompositingReason::kLayerForOverflowControlsHost);
1118
1119 return horizontal_scrollbar_layer_changed ||
1120 vertical_scrollbar_layer_changed || scroll_corner_layer_changed;
1121 }
1122
PositionOverflowControlsLayers()1123 void CompositedLayerMapping::PositionOverflowControlsLayers() {
1124 if (GraphicsLayer* layer = LayerForHorizontalScrollbar()) {
1125 Scrollbar* h_bar = owning_layer_.GetScrollableArea()->HorizontalScrollbar();
1126 if (h_bar) {
1127 IntRect frame_rect = h_bar->FrameRect();
1128 layer->SetOffsetFromLayoutObject(ToIntSize(frame_rect.Location()));
1129 layer->SetSize(gfx::Size(frame_rect.Size()));
1130 if (layer->HasContentsLayer())
1131 layer->SetContentsRect(IntRect(IntPoint(), frame_rect.Size()));
1132 }
1133 bool h_bar_visible = h_bar && !layer->HasContentsLayer();
1134 layer->SetDrawsContent(h_bar_visible);
1135 layer->SetHitTestable(h_bar_visible);
1136 }
1137
1138 if (GraphicsLayer* layer = LayerForVerticalScrollbar()) {
1139 Scrollbar* v_bar = owning_layer_.GetScrollableArea()->VerticalScrollbar();
1140 if (v_bar) {
1141 IntRect frame_rect = v_bar->FrameRect();
1142 layer->SetOffsetFromLayoutObject(ToIntSize(frame_rect.Location()));
1143 layer->SetSize(gfx::Size(frame_rect.Size()));
1144 if (layer->HasContentsLayer())
1145 layer->SetContentsRect(IntRect(IntPoint(), frame_rect.Size()));
1146 }
1147 bool v_bar_visible = v_bar && !layer->HasContentsLayer();
1148 layer->SetDrawsContent(v_bar_visible);
1149 layer->SetHitTestable(v_bar_visible);
1150 }
1151
1152 if (GraphicsLayer* layer = LayerForScrollCorner()) {
1153 const IntRect& scroll_corner_and_resizer =
1154 owning_layer_.GetScrollableArea()->ScrollCornerAndResizerRect();
1155 layer->SetOffsetFromLayoutObject(
1156 ToIntSize(scroll_corner_and_resizer.Location()));
1157 layer->SetSize(gfx::Size(scroll_corner_and_resizer.Size()));
1158 layer->SetDrawsContent(!scroll_corner_and_resizer.IsEmpty());
1159 layer->SetHitTestable(!scroll_corner_and_resizer.IsEmpty());
1160 }
1161 }
1162
1163 enum ApplyToGraphicsLayersModeFlags {
1164 kApplyToLayersAffectedByPreserve3D = (1 << 0),
1165 kApplyToSquashingLayer = (1 << 1),
1166 kApplyToScrollbarLayers = (1 << 2),
1167 kApplyToMaskLayers = (1 << 3),
1168 kApplyToContentLayers = (1 << 4),
1169 kApplyToChildContainingLayers =
1170 (1 << 5), // layers between m_graphicsLayer and children
1171 kApplyToNonScrollingContentLayers = (1 << 6),
1172 kApplyToScrollingContentLayers = (1 << 7),
1173 kApplyToDecorationOutlineLayer = (1 << 8),
1174 kApplyToAllGraphicsLayers =
1175 (kApplyToSquashingLayer | kApplyToScrollbarLayers | kApplyToMaskLayers |
1176 kApplyToLayersAffectedByPreserve3D | kApplyToContentLayers |
1177 kApplyToScrollingContentLayers | kApplyToDecorationOutlineLayer)
1178 };
1179 typedef unsigned ApplyToGraphicsLayersMode;
1180
1181 // Flags to layers mapping matrix:
1182 // bit 0 1 2 3 4 5 6 7 8
1183 // ChildTransform * *
1184 // Main * * *
1185 // Clipping * *
1186 // Scrolling * *
1187 // ScrollingContents * * * *
1188 // Foreground * * *
1189 // Squashing *
1190 // Mask * * *
1191 // HorizontalScrollbar *
1192 // VerticalScrollbar *
1193 // ScrollCorner *
1194 // DecorationOutline * *
1195 template <typename Func>
ApplyToGraphicsLayers(const CompositedLayerMapping * mapping,const Func & f,ApplyToGraphicsLayersMode mode)1196 static void ApplyToGraphicsLayers(const CompositedLayerMapping* mapping,
1197 const Func& f,
1198 ApplyToGraphicsLayersMode mode) {
1199 DCHECK(mode);
1200
1201 if (((mode & kApplyToLayersAffectedByPreserve3D) ||
1202 (mode & kApplyToContentLayers) ||
1203 (mode & kApplyToNonScrollingContentLayers)) &&
1204 mapping->MainGraphicsLayer())
1205 f(mapping->MainGraphicsLayer());
1206 if (((mode & kApplyToLayersAffectedByPreserve3D) ||
1207 (mode & kApplyToChildContainingLayers)) &&
1208 mapping->ScrollingLayer())
1209 f(mapping->ScrollingLayer());
1210 if (((mode & kApplyToLayersAffectedByPreserve3D) ||
1211 (mode & kApplyToContentLayers) ||
1212 (mode & kApplyToChildContainingLayers) ||
1213 (mode & kApplyToScrollingContentLayers)) &&
1214 mapping->ScrollingContentsLayer())
1215 f(mapping->ScrollingContentsLayer());
1216 if (((mode & kApplyToLayersAffectedByPreserve3D) ||
1217 (mode & kApplyToContentLayers) ||
1218 (mode & kApplyToScrollingContentLayers)) &&
1219 mapping->ForegroundLayer())
1220 f(mapping->ForegroundLayer());
1221
1222 if ((mode & kApplyToSquashingLayer) && mapping->SquashingLayer())
1223 f(mapping->SquashingLayer());
1224
1225 if (((mode & kApplyToMaskLayers) || (mode & kApplyToContentLayers) ||
1226 (mode & kApplyToNonScrollingContentLayers)) &&
1227 mapping->MaskLayer())
1228 f(mapping->MaskLayer());
1229
1230 if ((mode & kApplyToScrollbarLayers) &&
1231 mapping->LayerForHorizontalScrollbar())
1232 f(mapping->LayerForHorizontalScrollbar());
1233 if ((mode & kApplyToScrollbarLayers) && mapping->LayerForVerticalScrollbar())
1234 f(mapping->LayerForVerticalScrollbar());
1235 if ((mode & kApplyToScrollbarLayers) && mapping->LayerForScrollCorner())
1236 f(mapping->LayerForScrollCorner());
1237
1238 if (((mode & kApplyToDecorationOutlineLayer) ||
1239 (mode & kApplyToNonScrollingContentLayers)) &&
1240 mapping->DecorationOutlineLayer())
1241 f(mapping->DecorationOutlineLayer());
1242 }
1243
1244 // You receive an element id if you have an animation, or you're a scroller (and
1245 // might impl animate).
1246 //
1247 // The element id for the scroll layers is assigned when they're constructed,
1248 // since this is unconditional. However, the element id for the primary layer
1249 // may change according to the rules above so we update those values here.
UpdateElementId()1250 void CompositedLayerMapping::UpdateElementId() {
1251 CompositorElementId element_id = CompositorElementIdFromUniqueObjectId(
1252 owning_layer_.GetLayoutObject().UniqueId(),
1253 CompositorElementIdNamespace::kPrimary);
1254
1255 graphics_layer_->SetElementId(element_id);
1256 }
1257
UpdateForegroundLayer(bool needs_foreground_layer)1258 bool CompositedLayerMapping::UpdateForegroundLayer(
1259 bool needs_foreground_layer) {
1260 bool layer_changed = false;
1261 if (needs_foreground_layer) {
1262 if (!foreground_layer_) {
1263 foreground_layer_ =
1264 CreateGraphicsLayer(CompositingReason::kLayerForForeground);
1265 foreground_layer_->SetHitTestable(true);
1266 layer_changed = true;
1267 }
1268 } else if (foreground_layer_) {
1269 foreground_layer_->RemoveFromParent();
1270 foreground_layer_ = nullptr;
1271 layer_changed = true;
1272 }
1273
1274 return layer_changed;
1275 }
1276
UpdateDecorationOutlineLayer(bool needs_decoration_outline_layer)1277 bool CompositedLayerMapping::UpdateDecorationOutlineLayer(
1278 bool needs_decoration_outline_layer) {
1279 bool layer_changed = false;
1280 if (needs_decoration_outline_layer) {
1281 if (!decoration_outline_layer_) {
1282 decoration_outline_layer_ =
1283 CreateGraphicsLayer(CompositingReason::kLayerForDecoration);
1284 decoration_outline_layer_->SetPaintingPhase(
1285 kGraphicsLayerPaintDecoration);
1286 layer_changed = true;
1287 }
1288 } else if (decoration_outline_layer_) {
1289 decoration_outline_layer_ = nullptr;
1290 layer_changed = true;
1291 }
1292
1293 return layer_changed;
1294 }
1295
UpdateMaskLayer(bool needs_mask_layer)1296 bool CompositedLayerMapping::UpdateMaskLayer(bool needs_mask_layer) {
1297 bool layer_changed = false;
1298 if (needs_mask_layer) {
1299 if (!mask_layer_) {
1300 mask_layer_ = CreateGraphicsLayer(CompositingReason::kLayerForMask);
1301 mask_layer_->SetPaintingPhase(kGraphicsLayerPaintMask);
1302 CompositorElementId element_id = CompositorElementIdFromUniqueObjectId(
1303 GetLayoutObject().UniqueId(),
1304 CompositorElementIdNamespace::kEffectMask);
1305 mask_layer_->SetElementId(element_id);
1306 if (GetLayoutObject().HasBackdropFilter())
1307 mask_layer_->CcLayer()->SetIsBackdropFilterMask(true);
1308 layer_changed = true;
1309 }
1310 } else if (mask_layer_) {
1311 mask_layer_ = nullptr;
1312 layer_changed = true;
1313 }
1314
1315 return layer_changed;
1316 }
1317
UpdateScrollingLayers(bool needs_scrolling_layers)1318 bool CompositedLayerMapping::UpdateScrollingLayers(
1319 bool needs_scrolling_layers) {
1320 ScrollingCoordinator* scrolling_coordinator =
1321 owning_layer_.GetScrollingCoordinator();
1322
1323 auto* scrollable_area = owning_layer_.GetScrollableArea();
1324 if (scrollable_area)
1325 scrollable_area->SetUsesCompositedScrolling(needs_scrolling_layers);
1326
1327 bool layer_changed = false;
1328 if (needs_scrolling_layers) {
1329 if (!scrolling_layer_) {
1330 // Outer layer which corresponds with the scroll view.
1331 scrolling_layer_ =
1332 CreateGraphicsLayer(CompositingReason::kLayerForScrollingContainer);
1333 scrolling_layer_->SetDrawsContent(false);
1334 scrolling_layer_->SetHitTestable(false);
1335
1336 // Inner layer which renders the content that scrolls.
1337 scrolling_contents_layer_ =
1338 CreateGraphicsLayer(CompositingReason::kLayerForScrollingContents);
1339 scrolling_contents_layer_->SetHitTestable(true);
1340
1341 auto element_id = scrollable_area->GetScrollElementId();
1342 scrolling_contents_layer_->SetElementId(element_id);
1343
1344 scrolling_layer_->AddChild(scrolling_contents_layer_.get());
1345
1346 layer_changed = true;
1347 if (scrolling_coordinator && scrollable_area) {
1348 scrolling_coordinator->ScrollableAreaScrollLayerDidChange(
1349 scrollable_area);
1350 const auto& object = GetLayoutObject();
1351 if (auto* layout_view = DynamicTo<LayoutView>(object))
1352 layout_view->GetFrameView()->ScrollableAreasDidChange();
1353 }
1354 }
1355 } else if (scrolling_layer_) {
1356 scrolling_layer_ = nullptr;
1357 scrolling_contents_layer_ = nullptr;
1358 layer_changed = true;
1359 if (scrolling_coordinator && scrollable_area) {
1360 scrolling_coordinator->ScrollableAreaScrollLayerDidChange(
1361 scrollable_area);
1362 const auto& object = GetLayoutObject();
1363 if (auto* layout_view = DynamicTo<LayoutView>(object))
1364 layout_view->GetFrameView()->ScrollableAreasDidChange();
1365 }
1366 }
1367
1368 return layer_changed;
1369 }
1370
UpdateSquashingLayers(bool needs_squashing_layers)1371 bool CompositedLayerMapping::UpdateSquashingLayers(
1372 bool needs_squashing_layers) {
1373 bool layers_changed = false;
1374
1375 if (needs_squashing_layers) {
1376 if (!squashing_layer_) {
1377 squashing_layer_ =
1378 CreateGraphicsLayer(CompositingReason::kLayerForSquashingContents);
1379 squashing_layer_->SetDrawsContent(true);
1380 squashing_layer_->SetHitTestable(true);
1381 layers_changed = true;
1382 }
1383 if (!squashing_containment_layer_) {
1384 squashing_containment_layer_ =
1385 CreateGraphicsLayer(CompositingReason::kLayerForSquashingContainer);
1386 layers_changed = true;
1387 }
1388 DCHECK(squashing_layer_);
1389 } else {
1390 if (squashing_layer_) {
1391 squashing_layer_->RemoveFromParent();
1392 squashing_layer_ = nullptr;
1393 layers_changed = true;
1394 }
1395 if (squashing_containment_layer_) {
1396 squashing_containment_layer_->RemoveFromParent();
1397 squashing_containment_layer_ = nullptr;
1398 layers_changed = true;
1399 }
1400 DCHECK(!squashing_layer_);
1401 DCHECK(!squashing_containment_layer_);
1402 }
1403
1404 return layers_changed;
1405 }
1406
1407 GraphicsLayerPaintingPhase
PaintingPhaseForPrimaryLayer() const1408 CompositedLayerMapping::PaintingPhaseForPrimaryLayer() const {
1409 unsigned phase = kGraphicsLayerPaintBackground;
1410 if (!foreground_layer_)
1411 phase |= kGraphicsLayerPaintForeground;
1412 if (!mask_layer_)
1413 phase |= kGraphicsLayerPaintMask;
1414 if (!decoration_outline_layer_)
1415 phase |= kGraphicsLayerPaintDecoration;
1416
1417 if (scrolling_contents_layer_) {
1418 phase &= ~kGraphicsLayerPaintForeground;
1419 phase |= kGraphicsLayerPaintCompositedScroll;
1420 }
1421
1422 return static_cast<GraphicsLayerPaintingPhase>(phase);
1423 }
1424
LayoutObjectBackgroundColor() const1425 Color CompositedLayerMapping::LayoutObjectBackgroundColor() const {
1426 const auto& object = GetLayoutObject();
1427 auto background_color = object.ResolveColor(GetCSSPropertyBackgroundColor());
1428 auto* layout_view = DynamicTo<LayoutView>(object);
1429 if (layout_view && object.GetDocument().IsInMainFrame()) {
1430 return layout_view->GetFrameView()->BaseBackgroundColor().Blend(
1431 background_color);
1432 }
1433 return background_color;
1434 }
1435
UpdateBackgroundColor()1436 void CompositedLayerMapping::UpdateBackgroundColor() {
1437 auto color = LayoutObjectBackgroundColor().Rgb();
1438 graphics_layer_->SetBackgroundColor(color);
1439 if (scrolling_contents_layer_)
1440 scrolling_contents_layer_->SetBackgroundColor(color);
1441 }
1442
PaintsChildren() const1443 bool CompositedLayerMapping::PaintsChildren() const {
1444 if (owning_layer_.HasVisibleContent() &&
1445 owning_layer_.HasNonEmptyChildLayoutObjects())
1446 return true;
1447
1448 if (HasVisibleNonCompositingDescendant(&owning_layer_))
1449 return true;
1450
1451 return false;
1452 }
1453
IsCompositedPlugin(LayoutObject & layout_object)1454 static bool IsCompositedPlugin(LayoutObject& layout_object) {
1455 return layout_object.IsEmbeddedObject() &&
1456 ToLayoutEmbeddedObject(layout_object).RequiresAcceleratedCompositing();
1457 }
1458
HasVisibleNonCompositingDescendant(PaintLayer * parent)1459 bool CompositedLayerMapping::HasVisibleNonCompositingDescendant(
1460 PaintLayer* parent) {
1461 if (!parent->HasVisibleDescendant())
1462 return false;
1463
1464 PaintLayerPaintOrderIterator iterator(*parent, kAllChildren);
1465 while (PaintLayer* child_layer = iterator.Next()) {
1466 if (child_layer->HasCompositedLayerMapping())
1467 continue;
1468 if (child_layer->HasVisibleContent() ||
1469 HasVisibleNonCompositingDescendant(child_layer))
1470 return true;
1471 }
1472
1473 return false;
1474 }
1475
ContainsPaintedContent() const1476 bool CompositedLayerMapping::ContainsPaintedContent() const {
1477 if (CompositedBounds().IsEmpty())
1478 return false;
1479
1480 if (GetLayoutObject().IsImage() && IsDirectlyCompositedImage())
1481 return false;
1482
1483 LayoutObject& layout_object = GetLayoutObject();
1484 // FIXME: we could optimize cases where the image, video or canvas is known to
1485 // fill the border box entirely, and set background color on the layer in that
1486 // case, instead of allocating backing store and painting.
1487 auto* layout_video = DynamicTo<LayoutVideo>(layout_object);
1488 if (layout_video && layout_video->ShouldDisplayVideo())
1489 return owning_layer_.HasBoxDecorationsOrBackground();
1490
1491 if (layout_object.GetNode() && layout_object.GetNode()->IsDocumentNode()) {
1492 if (owning_layer_.NeedsCompositedScrolling())
1493 return BackgroundPaintsOntoGraphicsLayer();
1494
1495 // Look to see if the root object has a non-simple background
1496 LayoutObject* root_object =
1497 layout_object.GetDocument().documentElement()
1498 ? layout_object.GetDocument().documentElement()->GetLayoutObject()
1499 : nullptr;
1500 // Reject anything that has a border, a border-radius or outline,
1501 // or is not a simple background (no background, or solid color).
1502 if (root_object &&
1503 HasBoxDecorationsOrBackgroundImage(root_object->StyleRef()))
1504 return true;
1505
1506 // Now look at the body's layoutObject.
1507 HTMLElement* body = layout_object.GetDocument().body();
1508 LayoutObject* body_object =
1509 IsA<HTMLBodyElement>(body) ? body->GetLayoutObject() : nullptr;
1510 if (body_object &&
1511 HasBoxDecorationsOrBackgroundImage(body_object->StyleRef()))
1512 return true;
1513 }
1514
1515 if (owning_layer_.HasVisibleBoxDecorations())
1516 return true;
1517
1518 if (layout_object.HasMask()) // masks require special treatment
1519 return true;
1520
1521 if (layout_object.IsAtomicInlineLevel() && !IsCompositedPlugin(layout_object))
1522 return true;
1523
1524 if (layout_object.IsLayoutMultiColumnSet())
1525 return true;
1526
1527 // FIXME: it's O(n^2). A better solution is needed.
1528 return PaintsChildren();
1529 }
1530
1531 // An image can be directly composited if it's the sole content of the layer,
1532 // and has no box decorations or clipping that require painting. Direct
1533 // compositing saves a backing store.
IsDirectlyCompositedImage() const1534 bool CompositedLayerMapping::IsDirectlyCompositedImage() const {
1535 DCHECK(GetLayoutObject().IsImage());
1536
1537 LayoutImage& image_layout_object = ToLayoutImage(GetLayoutObject());
1538
1539 if (owning_layer_.HasBoxDecorationsOrBackground() ||
1540 image_layout_object.HasClip() || image_layout_object.HasClipPath() ||
1541 image_layout_object.HasObjectFit())
1542 return false;
1543
1544 if (ImageResourceContent* cached_image = image_layout_object.CachedImage()) {
1545 if (!cached_image->HasImage())
1546 return false;
1547
1548 if (!IsA<BitmapImage>(cached_image->GetImage()))
1549 return false;
1550
1551 UseCounter::Count(GetLayoutObject().GetDocument(),
1552 WebFeature::kDirectlyCompositedImage);
1553 return true;
1554 }
1555
1556 return false;
1557 }
1558
ContentChanged(ContentChangeType change_type)1559 void CompositedLayerMapping::ContentChanged(ContentChangeType change_type) {
1560 if ((change_type == kImageChanged) && GetLayoutObject().IsImage() &&
1561 IsDirectlyCompositedImage()) {
1562 SetNeedsGraphicsLayerUpdate(kGraphicsLayerUpdateLocal);
1563 Compositor()->SetNeedsCompositingUpdate(
1564 kCompositingUpdateAfterGeometryChange);
1565 return;
1566 }
1567
1568 if (change_type == kCanvasChanged &&
1569 IsTextureLayerCanvas(GetLayoutObject())) {
1570 graphics_layer_->SetContentsNeedsDisplay();
1571 return;
1572 }
1573 }
1574
UpdateImageContents()1575 void CompositedLayerMapping::UpdateImageContents() {
1576 DCHECK_EQ(owning_layer_.Compositor()->Lifecycle().GetState(),
1577 DocumentLifecycle::kInCompositingUpdate);
1578
1579 DCHECK(GetLayoutObject().IsImage());
1580 LayoutImage& image_layout_object = ToLayoutImage(GetLayoutObject());
1581
1582 ImageResourceContent* cached_image = image_layout_object.CachedImage();
1583 if (!cached_image)
1584 return;
1585
1586 Image* image = cached_image->GetImage();
1587 if (!image)
1588 return;
1589
1590 auto* html_image_element =
1591 DynamicTo<HTMLImageElement>(image_layout_object.GetNode());
1592 Image::ImageDecodingMode decode_mode =
1593 html_image_element ? html_image_element->GetDecodingModeForPainting(
1594 image->paint_image_id())
1595 : Image::kUnspecifiedDecode;
1596
1597 // This is a no-op if the layer doesn't have an inner layer for the image.
1598 graphics_layer_->SetContentsToImage(
1599 image, decode_mode,
1600 LayoutObject::ShouldRespectImageOrientation(&image_layout_object));
1601
1602 graphics_layer_->SetFilterQuality(
1603 GetLayoutObject().StyleRef().ImageRendering() ==
1604 EImageRendering::kPixelated
1605 ? kNone_SkFilterQuality
1606 : kLow_SkFilterQuality);
1607
1608 // Prevent double-drawing: https://bugs.webkit.org/show_bug.cgi?id=58632
1609 UpdateDrawsContentAndPaintsHitTest();
1610
1611 // Image animation is "lazy", in that it automatically stops unless someone is
1612 // drawing the image. So we have to kick the animation each time; this has the
1613 // downside that the image will keep animating, even if its layer is not
1614 // visible.
1615 image->StartAnimation();
1616 }
1617
ComputeTransformOrigin(const IntRect & border_box) const1618 FloatPoint3D CompositedLayerMapping::ComputeTransformOrigin(
1619 const IntRect& border_box) const {
1620 const ComputedStyle& style = GetLayoutObject().StyleRef();
1621
1622 FloatPoint3D origin;
1623 origin.SetX(
1624 FloatValueForLength(style.TransformOriginX(), border_box.Width()));
1625 origin.SetY(
1626 FloatValueForLength(style.TransformOriginY(), border_box.Height()));
1627 origin.SetZ(style.TransformOriginZ());
1628
1629 return origin;
1630 }
1631
1632 // Return the offset from the top-left of this compositing layer at which the
1633 // LayoutObject's contents are painted.
ContentOffsetInCompositingLayer() const1634 PhysicalOffset CompositedLayerMapping::ContentOffsetInCompositingLayer() const {
1635 return owning_layer_.SubpixelAccumulation() -
1636 PhysicalOffset(graphics_layer_->OffsetFromLayoutObject());
1637 }
1638
ContentsBox() const1639 PhysicalRect CompositedLayerMapping::ContentsBox() const {
1640 PhysicalRect contents_box = ContentsRect(GetLayoutObject());
1641 contents_box.Move(ContentOffsetInCompositingLayer());
1642 return contents_box;
1643 }
1644
NeedsToReparentOverflowControls() const1645 bool CompositedLayerMapping::NeedsToReparentOverflowControls() const {
1646 return owning_layer_.NeedsReorderOverlayOverflowControls();
1647 }
1648
DetachLayerForOverflowControls()1649 GraphicsLayer* CompositedLayerMapping::DetachLayerForOverflowControls() {
1650 if (overflow_controls_host_layer_)
1651 overflow_controls_host_layer_->RemoveFromParent();
1652 return overflow_controls_host_layer_.get();
1653 }
1654
DetachLayerForDecorationOutline()1655 GraphicsLayer* CompositedLayerMapping::DetachLayerForDecorationOutline() {
1656 if (!decoration_outline_layer_.get())
1657 return nullptr;
1658 decoration_outline_layer_->RemoveFromParent();
1659 return decoration_outline_layer_.get();
1660 }
1661
ParentForSublayers() const1662 GraphicsLayer* CompositedLayerMapping::ParentForSublayers() const {
1663 if (scrolling_contents_layer_)
1664 return scrolling_contents_layer_.get();
1665
1666 return graphics_layer_.get();
1667 }
1668
SetSublayers(const GraphicsLayerVector & sublayers)1669 void CompositedLayerMapping::SetSublayers(
1670 const GraphicsLayerVector& sublayers) {
1671 GraphicsLayer* overflow_controls_container =
1672 overflow_controls_host_layer_.get();
1673 GraphicsLayer* parent = ParentForSublayers();
1674 bool needs_overflow_controls_reattached =
1675 overflow_controls_container &&
1676 overflow_controls_container->Parent() == parent;
1677
1678 parent->SetChildren(sublayers);
1679
1680 // If we have scrollbars, but are not using composited scrolling, then
1681 // parentForSublayers may return m_graphicsLayer. In that case, the above
1682 // call to setChildren has clobbered the overflow controls host layer, so we
1683 // need to reattach it.
1684 if (needs_overflow_controls_reattached)
1685 parent->AddChild(overflow_controls_container);
1686 }
1687
ChildForSuperlayers() const1688 GraphicsLayer* CompositedLayerMapping::ChildForSuperlayers() const {
1689 if (squashing_containment_layer_)
1690 return squashing_containment_layer_.get();
1691
1692 return graphics_layer_.get();
1693 }
1694
UpdateTypeForChildren(GraphicsLayerUpdater::UpdateType update_type) const1695 GraphicsLayerUpdater::UpdateType CompositedLayerMapping::UpdateTypeForChildren(
1696 GraphicsLayerUpdater::UpdateType update_type) const {
1697 if (pending_update_scope_ >= kGraphicsLayerUpdateSubtree)
1698 return GraphicsLayerUpdater::kForceUpdate;
1699 return update_type;
1700 }
1701
1702 struct SetContentsNeedsDisplayFunctor {
operator ()blink::SetContentsNeedsDisplayFunctor1703 void operator()(GraphicsLayer* layer) const {
1704 if (layer->PaintsContentOrHitTest())
1705 layer->SetNeedsDisplay();
1706 }
1707 };
1708
SetSquashingContentsNeedDisplay()1709 void CompositedLayerMapping::SetSquashingContentsNeedDisplay() {
1710 ApplyToGraphicsLayers(this, SetContentsNeedsDisplayFunctor(),
1711 kApplyToSquashingLayer);
1712 }
1713
SetContentsNeedDisplay()1714 void CompositedLayerMapping::SetContentsNeedDisplay() {
1715 // FIXME: need to split out paint invalidations for the background.
1716 ApplyToGraphicsLayers(this, SetContentsNeedsDisplayFunctor(),
1717 kApplyToContentLayers);
1718 }
1719
SetNeedsCheckRasterInvalidation()1720 void CompositedLayerMapping::SetNeedsCheckRasterInvalidation() {
1721 ApplyToGraphicsLayers(
1722 this,
1723 [](GraphicsLayer* graphics_layer) {
1724 if (graphics_layer->DrawsContent())
1725 graphics_layer->SetNeedsCheckRasterInvalidation();
1726 },
1727 kApplyToAllGraphicsLayers);
1728 }
1729
ContainingSquashedLayer(const LayoutObject * layout_object,const Vector<GraphicsLayerPaintInfo> & layers,unsigned max_squashed_layer_index)1730 const GraphicsLayerPaintInfo* CompositedLayerMapping::ContainingSquashedLayer(
1731 const LayoutObject* layout_object,
1732 const Vector<GraphicsLayerPaintInfo>& layers,
1733 unsigned max_squashed_layer_index) {
1734 if (!layout_object)
1735 return nullptr;
1736 for (wtf_size_t i = 0; i < layers.size() && i < max_squashed_layer_index;
1737 ++i) {
1738 if (layout_object->IsDescendantOf(
1739 &layers[i].paint_layer->GetLayoutObject()))
1740 return &layers[i];
1741 }
1742 return nullptr;
1743 }
1744
ContainingSquashedLayer(const LayoutObject * layout_object,unsigned max_squashed_layer_index)1745 const GraphicsLayerPaintInfo* CompositedLayerMapping::ContainingSquashedLayer(
1746 const LayoutObject* layout_object,
1747 unsigned max_squashed_layer_index) {
1748 return CompositedLayerMapping::ContainingSquashedLayer(
1749 layout_object, squashed_layers_, max_squashed_layer_index);
1750 }
1751
LocalClipRectForSquashedLayer(const PaintLayer & reference_layer,const Vector<GraphicsLayerPaintInfo> & layers,GraphicsLayerPaintInfo & paint_info)1752 void CompositedLayerMapping::LocalClipRectForSquashedLayer(
1753 const PaintLayer& reference_layer,
1754 const Vector<GraphicsLayerPaintInfo>& layers,
1755 GraphicsLayerPaintInfo& paint_info) {
1756 const LayoutObject* clipping_container =
1757 paint_info.paint_layer->ClippingContainer();
1758 if (clipping_container == reference_layer.ClippingContainer()) {
1759 paint_info.local_clip_rect_for_squashed_layer =
1760 ClipRect(PhysicalRect(LayoutRect::InfiniteIntRect()));
1761 paint_info.offset_from_clip_rect_root = PhysicalOffset();
1762 paint_info.local_clip_rect_root = paint_info.paint_layer;
1763 return;
1764 }
1765
1766 DCHECK(clipping_container);
1767
1768 const GraphicsLayerPaintInfo* ancestor_paint_info =
1769 ContainingSquashedLayer(clipping_container, layers, layers.size());
1770 // Must be there, otherwise
1771 // CompositingLayerAssigner::canSquashIntoCurrentSquashingOwner would have
1772 // disallowed squashing.
1773 DCHECK(ancestor_paint_info);
1774
1775 // FIXME: this is a potential performance issue. We should consider caching
1776 // these clip rects or otherwise optimizing.
1777 ClipRectsContext clip_rects_context(
1778 ancestor_paint_info->paint_layer,
1779 &ancestor_paint_info->paint_layer->GetLayoutObject().FirstFragment(),
1780 kUncachedClipRects);
1781 ClipRect parent_clip_rect;
1782 paint_info.paint_layer
1783 ->Clipper(PaintLayer::GeometryMapperOption::kDoNotUseGeometryMapper)
1784 .CalculateBackgroundClipRect(clip_rects_context, parent_clip_rect);
1785
1786 // Convert from ancestor to local coordinates.
1787 IntSize ancestor_to_local_offset =
1788 paint_info.offset_from_layout_object -
1789 ancestor_paint_info->offset_from_layout_object;
1790 parent_clip_rect.Move(PhysicalOffset(ancestor_to_local_offset));
1791 paint_info.local_clip_rect_for_squashed_layer = parent_clip_rect;
1792 paint_info.offset_from_clip_rect_root =
1793 PhysicalOffset(ancestor_to_local_offset);
1794 paint_info.local_clip_rect_root = ancestor_paint_info->paint_layer;
1795 }
1796
DoPaintTask(const GraphicsLayerPaintInfo & paint_info,const GraphicsLayer & graphics_layer,PaintLayerFlags paint_layer_flags,GraphicsContext & context,const IntRect & clip) const1797 void CompositedLayerMapping::DoPaintTask(
1798 const GraphicsLayerPaintInfo& paint_info,
1799 const GraphicsLayer& graphics_layer,
1800 PaintLayerFlags paint_layer_flags,
1801 GraphicsContext& context,
1802 const IntRect& clip /* In the coords of rootLayer */) const {
1803 FontCachePurgePreventer font_cache_purge_preventer;
1804
1805 IntSize offset = paint_info.offset_from_layout_object;
1806 // The dirtyRect is in the coords of the painting root.
1807 IntRect dirty_rect(clip);
1808 dirty_rect.Move(offset);
1809
1810 if (paint_layer_flags & (kPaintLayerPaintingOverflowContents)) {
1811 dirty_rect.MoveBy(
1812 RoundedIntPoint(paint_info.paint_layer->SubpixelAccumulation()));
1813 } else {
1814 PhysicalRect bounds = paint_info.composited_bounds;
1815 bounds.Move(paint_info.paint_layer->SubpixelAccumulation());
1816 dirty_rect.Intersect(PixelSnappedIntRect(bounds));
1817 }
1818
1819 #if DCHECK_IS_ON()
1820 if (!GetLayoutObject().View()->GetFrame() ||
1821 !GetLayoutObject().View()->GetFrame()->ShouldThrottleRendering())
1822 paint_info.paint_layer->GetLayoutObject().AssertSubtreeIsLaidOut();
1823 #endif
1824
1825 float device_scale_factor = blink::DeviceScaleFactorDeprecated(
1826 paint_info.paint_layer->GetLayoutObject().GetFrame());
1827 context.SetDeviceScaleFactor(device_scale_factor);
1828
1829 Settings* settings = GetLayoutObject().GetFrame()->GetSettings();
1830 context.SetDarkMode(
1831 BuildDarkModeSettings(*settings, *GetLayoutObject().View()));
1832
1833 if (paint_info.paint_layer->GetCompositingState() !=
1834 kPaintsIntoGroupedBacking) {
1835 // FIXME: GraphicsLayers need a way to split for multicol.
1836 PaintLayerPaintingInfo painting_info(
1837 paint_info.paint_layer, CullRect(dirty_rect), kGlobalPaintNormalPhase,
1838 paint_info.paint_layer->SubpixelAccumulation());
1839 PaintLayerPainter(*paint_info.paint_layer)
1840 .PaintLayerContents(context, painting_info, paint_layer_flags);
1841 } else {
1842 PaintLayerPaintingInfo painting_info(
1843 paint_info.paint_layer, CullRect(dirty_rect), kGlobalPaintNormalPhase,
1844 paint_info.paint_layer->SubpixelAccumulation());
1845 PaintLayerPainter(*paint_info.paint_layer)
1846 .Paint(context, painting_info, paint_layer_flags);
1847 }
1848 }
1849
1850 // TODO(eseckler): Make recording distance configurable, e.g. for use in
1851 // headless, where we would like to record an exact area.
1852 // Note however that the minimum value for this constant is the size of a
1853 // raster tile. This is because the raster system is not able to raster a
1854 // tile that is not completely covered by a display list. If the constant
1855 // were less than the size of a tile, then a tile which partially overlaps
1856 // the screen may not be rastered.
1857 static const int kPixelDistanceToRecord = 4000;
1858
RecomputeInterestRect(const GraphicsLayer * graphics_layer) const1859 IntRect CompositedLayerMapping::RecomputeInterestRect(
1860 const GraphicsLayer* graphics_layer) const {
1861 IntRect graphics_layer_bounds(IntPoint(), IntSize(graphics_layer->Size()));
1862
1863 FloatClipRect mapping_rect((FloatRect(graphics_layer_bounds)));
1864
1865 PropertyTreeState source_state = graphics_layer->GetPropertyTreeState();
1866
1867 LayoutView* root_view = owning_layer_.GetLayoutObject().View();
1868 while (root_view->GetFrame()->OwnerLayoutObject())
1869 root_view = root_view->GetFrame()->OwnerLayoutObject()->View();
1870
1871 PropertyTreeState root_view_contents_state =
1872 root_view->FirstFragment().ContentsProperties();
1873 PropertyTreeState root_view_border_box_state =
1874 root_view->FirstFragment().LocalBorderBoxProperties();
1875
1876 // 1. Move into local transform space.
1877 mapping_rect.MoveBy(FloatPoint(graphics_layer->GetOffsetFromTransformNode()));
1878 // 2. Map into contents space of the root LayoutView.
1879 GeometryMapper::LocalToAncestorVisualRect(
1880 source_state, root_view_contents_state, mapping_rect);
1881
1882 FloatRect visible_content_rect(EnclosingIntRect(mapping_rect.Rect()));
1883
1884 // 3. Move into local border box transform space of the root LayoutView.
1885 // Note that the overflow clip has *not* been applied.
1886 GeometryMapper::SourceToDestinationRect(
1887 root_view_contents_state.Transform(),
1888 root_view_border_box_state.Transform(), visible_content_rect);
1889
1890 // 4. Apply overflow clip, or adjusted version if necessary.
1891 root_view->GetFrameView()->ClipPaintRect(&visible_content_rect);
1892
1893 FloatRect local_interest_rect;
1894 // If the visible content rect is empty, then it makes no sense to map it back
1895 // since there is nothing to map.
1896 if (!visible_content_rect.IsEmpty()) {
1897 local_interest_rect = visible_content_rect;
1898 // 5. Map the visible content rect from root view space to local graphics
1899 // layer space.
1900 GeometryMapper::SourceToDestinationRect(
1901 root_view_border_box_state.Transform(), source_state.Transform(),
1902 local_interest_rect);
1903 local_interest_rect.MoveBy(
1904 -FloatPoint(graphics_layer->GetOffsetFromTransformNode()));
1905
1906 // TODO(chrishtr): the code below is a heuristic. Instead we should detect
1907 // and return whether the mapping failed. In some cases,
1908 // absoluteToLocalQuad can fail to map back to the local space, due to
1909 // passing through non-invertible transforms or floating-point accuracy
1910 // issues. Examples include rotation near 90 degrees or perspective. In such
1911 // cases, fall back to painting the first kPixelDistanceToRecord pixels in
1912 // each direction.
1913
1914 // Note that since the interest rect mapping above can produce extremely
1915 // large numbers in cases of perspective, try our best to "normalize" the
1916 // result by ensuring that none of the rect dimensions exceed some large,
1917 // but reasonable, limit.
1918 const float reasonable_pixel_limit = std::numeric_limits<int>::max() / 2.f;
1919 auto unpadded_intersection = local_interest_rect;
1920
1921 // Note that by clamping X and Y, we are effectively moving the rect right /
1922 // down. However, this will at most make us paint more content, which is
1923 // better than erroneously deciding that the rect produced here is far
1924 // offscreen.
1925 if (unpadded_intersection.X() < -reasonable_pixel_limit)
1926 unpadded_intersection.SetX(-reasonable_pixel_limit);
1927 if (unpadded_intersection.Y() < -reasonable_pixel_limit)
1928 unpadded_intersection.SetY(-reasonable_pixel_limit);
1929 if (unpadded_intersection.MaxX() > reasonable_pixel_limit) {
1930 unpadded_intersection.SetWidth(reasonable_pixel_limit -
1931 unpadded_intersection.X());
1932 }
1933 if (unpadded_intersection.MaxY() > reasonable_pixel_limit) {
1934 unpadded_intersection.SetHeight(reasonable_pixel_limit -
1935 unpadded_intersection.Y());
1936 }
1937
1938 unpadded_intersection.Intersect(FloatRect(graphics_layer_bounds));
1939 // If our unpadded intersection is not empty, then use that before padding,
1940 // since it can produce more stable results, and it would not produce any
1941 // smaller area than if we used the original local interest rect.
1942 if (!unpadded_intersection.IsEmpty())
1943 local_interest_rect = unpadded_intersection;
1944
1945 // Expand by interest rect padding amount, scaled by the approximate scale
1946 // of the GraphicsLayer relative to screen pixels. If width or height
1947 // are zero or nearly zero, fall back to kPixelDistanceToRecord.
1948 // This is the same as the else clause below.
1949 float x_scale =
1950 visible_content_rect.Width() > std::numeric_limits<float>::epsilon()
1951 ? local_interest_rect.Width() / visible_content_rect.Width()
1952 : 1.0f;
1953 float y_scale =
1954 visible_content_rect.Height() > std::numeric_limits<float>::epsilon()
1955 ? local_interest_rect.Height() / visible_content_rect.Height()
1956 : 1.0f;
1957 // Take the max, to account for situations like rotation transforms, which
1958 // swap x and y.
1959 // Since at this point we can also have an extremely large scale due to
1960 // perspective (see the comments above), cap it to something reasonable.
1961 float scale = std::min(std::max(x_scale, y_scale),
1962 reasonable_pixel_limit / kPixelDistanceToRecord);
1963 local_interest_rect.Inflate(kPixelDistanceToRecord * scale);
1964 } else {
1965 // Expand by interest rect padding amount.
1966 local_interest_rect.Inflate(kPixelDistanceToRecord);
1967 }
1968 return Intersection(EnclosingIntRect(local_interest_rect),
1969 graphics_layer_bounds);
1970 }
1971
1972 static const int kMinimumDistanceBeforeRepaint = 512;
1973
InterestRectChangedEnoughToRepaint(const IntRect & previous_interest_rect,const IntRect & new_interest_rect,const IntSize & layer_size)1974 bool CompositedLayerMapping::InterestRectChangedEnoughToRepaint(
1975 const IntRect& previous_interest_rect,
1976 const IntRect& new_interest_rect,
1977 const IntSize& layer_size) {
1978 if (previous_interest_rect.IsEmpty() && new_interest_rect.IsEmpty())
1979 return false;
1980
1981 // Repaint when going from empty to not-empty, to cover cases where the layer
1982 // is painted for the first time, or otherwise becomes visible.
1983 if (previous_interest_rect.IsEmpty())
1984 return true;
1985
1986 // Repaint if the new interest rect includes area outside of a skirt around
1987 // the existing interest rect.
1988 IntRect expanded_previous_interest_rect(previous_interest_rect);
1989 expanded_previous_interest_rect.Inflate(kMinimumDistanceBeforeRepaint);
1990 if (!expanded_previous_interest_rect.Contains(new_interest_rect))
1991 return true;
1992
1993 // Even if the new interest rect doesn't include enough new area to satisfy
1994 // the condition above, repaint anyway if it touches a layer edge not touched
1995 // by the existing interest rect. Because it's impossible to expose more area
1996 // in the direction, repainting cannot be deferred until the exposed new area
1997 // satisfies the condition above.
1998 if (new_interest_rect.X() == 0 && previous_interest_rect.X() != 0)
1999 return true;
2000 if (new_interest_rect.Y() == 0 && previous_interest_rect.Y() != 0)
2001 return true;
2002 if (new_interest_rect.MaxX() == layer_size.Width() &&
2003 previous_interest_rect.MaxX() != layer_size.Width())
2004 return true;
2005 if (new_interest_rect.MaxY() == layer_size.Height() &&
2006 previous_interest_rect.MaxY() != layer_size.Height())
2007 return true;
2008
2009 return false;
2010 }
2011
ComputeInterestRect(const GraphicsLayer * graphics_layer,const IntRect & previous_interest_rect) const2012 IntRect CompositedLayerMapping::ComputeInterestRect(
2013 const GraphicsLayer* graphics_layer,
2014 const IntRect& previous_interest_rect) const {
2015 // Use the previous interest rect if it covers the whole layer.
2016 IntRect whole_layer_rect =
2017 IntRect(IntPoint(), IntSize(graphics_layer->Size()));
2018 if (!NeedsRepaint(*graphics_layer) &&
2019 previous_interest_rect == whole_layer_rect)
2020 return previous_interest_rect;
2021
2022 if (graphics_layer != graphics_layer_.get() &&
2023 graphics_layer != squashing_layer_.get() &&
2024 graphics_layer != scrolling_contents_layer_.get())
2025 return whole_layer_rect;
2026
2027 IntRect new_interest_rect = RecomputeInterestRect(graphics_layer);
2028 if (NeedsRepaint(*graphics_layer) ||
2029 InterestRectChangedEnoughToRepaint(previous_interest_rect,
2030 new_interest_rect,
2031 IntSize(graphics_layer->Size())))
2032 return new_interest_rect;
2033 return previous_interest_rect;
2034 }
2035
SubpixelAccumulation() const2036 LayoutSize CompositedLayerMapping::SubpixelAccumulation() const {
2037 return owning_layer_.SubpixelAccumulation().ToLayoutSize();
2038 }
2039
NeedsRepaint(const GraphicsLayer & graphics_layer) const2040 bool CompositedLayerMapping::NeedsRepaint(
2041 const GraphicsLayer& graphics_layer) const {
2042 return IsScrollableAreaLayerWhichNeedsRepaint(&graphics_layer) ||
2043 owning_layer_.SelfOrDescendantNeedsRepaint();
2044 }
2045
AdjustForCompositedScrolling(const GraphicsLayer * graphics_layer,IntSize & offset) const2046 bool CompositedLayerMapping::AdjustForCompositedScrolling(
2047 const GraphicsLayer* graphics_layer,
2048 IntSize& offset) const {
2049 if (graphics_layer == scrolling_contents_layer_.get() ||
2050 graphics_layer == foreground_layer_.get()) {
2051 if (PaintLayerScrollableArea* scrollable_area =
2052 owning_layer_.GetScrollableArea()) {
2053 if (scrollable_area->UsesCompositedScrolling()) {
2054 // Note: this is the offset from the beginning of flow of the block, not
2055 // the offset from the top/left of the overflow rect.
2056 // offsetFromLayoutObject adds the origin offset from top/left to the
2057 // beginning of flow.
2058 ScrollOffset scroll_offset = scrollable_area->GetScrollOffset();
2059 offset.Expand(-scroll_offset.Width(), -scroll_offset.Height());
2060 return true;
2061 }
2062 }
2063 }
2064 return false;
2065 }
2066
PaintContents(const GraphicsLayer * graphics_layer,GraphicsContext & context,GraphicsLayerPaintingPhase graphics_layer_painting_phase,const IntRect & interest_rect) const2067 void CompositedLayerMapping::PaintContents(
2068 const GraphicsLayer* graphics_layer,
2069 GraphicsContext& context,
2070 GraphicsLayerPaintingPhase graphics_layer_painting_phase,
2071 const IntRect& interest_rect) const {
2072 FramePaintTiming frame_paint_timing(context, GetLayoutObject().GetFrame());
2073
2074 // https://code.google.com/p/chromium/issues/detail?id=343772
2075 DisableCompositingQueryAsserts disabler;
2076 // Allow throttling to make sure no painting paths (e.g.,
2077 // GraphicsLayer::PaintContents) try to paint throttled content.
2078 DocumentLifecycle::AllowThrottlingScope allow_throttling(
2079 owning_layer_.GetLayoutObject().GetDocument().Lifecycle());
2080 #if DCHECK_IS_ON()
2081 // FIXME: once the state machine is ready, this can be removed and we can
2082 // refer to that instead.
2083 if (Page* page = GetLayoutObject().GetFrame()->GetPage())
2084 page->SetIsPainting(true);
2085 #endif
2086
2087 TRACE_EVENT1(
2088 "devtools.timeline,rail", "Paint", "data",
2089 inspector_paint_event::Data(&owning_layer_.GetLayoutObject(),
2090 PhysicalRect(interest_rect), graphics_layer));
2091
2092 PaintLayerFlags paint_layer_flags = 0;
2093 if (graphics_layer_painting_phase & kGraphicsLayerPaintBackground)
2094 paint_layer_flags |= kPaintLayerPaintingCompositingBackgroundPhase;
2095 else
2096 paint_layer_flags |= kPaintLayerPaintingSkipRootBackground;
2097 if (graphics_layer_painting_phase & kGraphicsLayerPaintForeground)
2098 paint_layer_flags |= kPaintLayerPaintingCompositingForegroundPhase;
2099 if (graphics_layer_painting_phase & kGraphicsLayerPaintMask)
2100 paint_layer_flags |= kPaintLayerPaintingCompositingMaskPhase;
2101 if (graphics_layer_painting_phase & kGraphicsLayerPaintOverflowContents)
2102 paint_layer_flags |= kPaintLayerPaintingOverflowContents;
2103 if (graphics_layer_painting_phase & kGraphicsLayerPaintCompositedScroll)
2104 paint_layer_flags |= kPaintLayerPaintingCompositingScrollingPhase;
2105 if (graphics_layer_painting_phase & kGraphicsLayerPaintDecoration)
2106 paint_layer_flags |= kPaintLayerPaintingCompositingDecorationPhase;
2107
2108 if (graphics_layer == graphics_layer_.get() ||
2109 graphics_layer == foreground_layer_.get() ||
2110 graphics_layer == mask_layer_.get() ||
2111 graphics_layer == scrolling_contents_layer_.get() ||
2112 graphics_layer == decoration_outline_layer_.get()) {
2113 if (BackgroundPaintsOntoScrollingContentsLayer()) {
2114 if (graphics_layer == scrolling_contents_layer_.get())
2115 paint_layer_flags &= ~kPaintLayerPaintingSkipRootBackground;
2116 else if (!BackgroundPaintsOntoGraphicsLayer())
2117 paint_layer_flags |= kPaintLayerPaintingSkipRootBackground;
2118 }
2119
2120 GraphicsLayerPaintInfo paint_info;
2121 paint_info.paint_layer = &owning_layer_;
2122 paint_info.composited_bounds = CompositedBounds();
2123 paint_info.offset_from_layout_object =
2124 graphics_layer->OffsetFromLayoutObject();
2125 AdjustForCompositedScrolling(graphics_layer,
2126 paint_info.offset_from_layout_object);
2127
2128 // We have to use the same root as for hit testing, because both methods can
2129 // compute and cache clipRects.
2130 DoPaintTask(paint_info, *graphics_layer, paint_layer_flags, context,
2131 interest_rect);
2132 } else if (graphics_layer == squashing_layer_.get()) {
2133 for (wtf_size_t i = 0; i < squashed_layers_.size(); ++i) {
2134 DoPaintTask(squashed_layers_[i], *graphics_layer, paint_layer_flags,
2135 context, interest_rect);
2136 }
2137 } else if (IsScrollableAreaLayer(graphics_layer)) {
2138 PaintScrollableArea(graphics_layer, context, interest_rect);
2139 }
2140
2141 #if DCHECK_IS_ON()
2142 if (Page* page = GetLayoutObject().GetFrame()->GetPage())
2143 page->SetIsPainting(false);
2144 #endif
2145 }
2146
PaintScrollableArea(const GraphicsLayer * graphics_layer,GraphicsContext & context,const IntRect & interest_rect) const2147 void CompositedLayerMapping::PaintScrollableArea(
2148 const GraphicsLayer* graphics_layer,
2149 GraphicsContext& context,
2150 const IntRect& interest_rect) const {
2151 // cull_rect is in the space of the containing scrollable area in which
2152 // Scrollbar::Paint() will paint the scrollbar.
2153 CullRect cull_rect(interest_rect);
2154 cull_rect.Move(graphics_layer->OffsetFromLayoutObject());
2155 PaintLayerScrollableArea* scrollable_area = owning_layer_.GetScrollableArea();
2156 if (graphics_layer == LayerForHorizontalScrollbar()) {
2157 if (const Scrollbar* scrollbar = scrollable_area->HorizontalScrollbar()) {
2158 if (cull_rect.Intersects(scrollbar->FrameRect()))
2159 scrollbar->Paint(context, IntPoint());
2160 }
2161 } else if (graphics_layer == LayerForVerticalScrollbar()) {
2162 if (const Scrollbar* scrollbar = scrollable_area->VerticalScrollbar()) {
2163 if (cull_rect.Intersects(scrollbar->FrameRect()))
2164 scrollbar->Paint(context, IntPoint());
2165 }
2166 } else if (graphics_layer == LayerForScrollCorner()) {
2167 ScrollableAreaPainter painter(*scrollable_area);
2168 painter.PaintScrollCorner(context, IntPoint(), cull_rect);
2169 painter.PaintResizer(context, IntPoint(), cull_rect);
2170 }
2171 }
2172
IsScrollableAreaLayer(const GraphicsLayer * graphics_layer) const2173 bool CompositedLayerMapping::IsScrollableAreaLayer(
2174 const GraphicsLayer* graphics_layer) const {
2175 return graphics_layer == LayerForHorizontalScrollbar() ||
2176 graphics_layer == LayerForVerticalScrollbar() ||
2177 graphics_layer == LayerForScrollCorner();
2178 }
2179
IsScrollableAreaLayerWhichNeedsRepaint(const GraphicsLayer * graphics_layer) const2180 bool CompositedLayerMapping::IsScrollableAreaLayerWhichNeedsRepaint(
2181 const GraphicsLayer* graphics_layer) const {
2182 if (PaintLayerScrollableArea* scrollable_area =
2183 owning_layer_.GetScrollableArea()) {
2184 if (graphics_layer == LayerForHorizontalScrollbar())
2185 return scrollable_area->HorizontalScrollbarNeedsPaintInvalidation();
2186
2187 if (graphics_layer == LayerForVerticalScrollbar())
2188 return scrollable_area->VerticalScrollbarNeedsPaintInvalidation();
2189
2190 if (graphics_layer == LayerForScrollCorner())
2191 return scrollable_area->ScrollCornerNeedsPaintInvalidation();
2192 }
2193
2194 return false;
2195 }
2196
ShouldThrottleRendering() const2197 bool CompositedLayerMapping::ShouldThrottleRendering() const {
2198 return GetLayoutObject().GetFrame()->ShouldThrottleRendering();
2199 }
2200
IsUnderSVGHiddenContainer() const2201 bool CompositedLayerMapping::IsUnderSVGHiddenContainer() const {
2202 return owning_layer_.IsUnderSVGHiddenContainer();
2203 }
2204
IsTrackingRasterInvalidations() const2205 bool CompositedLayerMapping::IsTrackingRasterInvalidations() const {
2206 return GetLayoutObject().GetFrameView()->IsTrackingRasterInvalidations();
2207 }
2208
GraphicsLayersDidChange()2209 void CompositedLayerMapping::GraphicsLayersDidChange() {
2210 LocalFrameView* frame_view = GetLayoutObject().GetFrameView();
2211 DCHECK(frame_view);
2212 frame_view->SetForeignLayerListNeedsUpdate();
2213 }
2214
PaintBlockedByDisplayLockIncludingAncestors(DisplayLockContextLifecycleTarget target) const2215 bool CompositedLayerMapping::PaintBlockedByDisplayLockIncludingAncestors(
2216 DisplayLockContextLifecycleTarget target) const {
2217 auto* node = GetLayoutObject().GetNode();
2218 if (node) {
2219 auto* element = DynamicTo<Element>(node);
2220 if (target == DisplayLockContextLifecycleTarget::kSelf && element) {
2221 if (auto* context = element->GetDisplayLockContext()) {
2222 if (!context->ShouldPaint(DisplayLockLifecycleTarget::kSelf))
2223 return true;
2224 }
2225 }
2226 }
2227 return DisplayLockUtilities::NearestLockedExclusiveAncestor(
2228 GetLayoutObject());
2229 }
2230
NotifyDisplayLockNeedsGraphicsLayerCollection()2231 void CompositedLayerMapping::NotifyDisplayLockNeedsGraphicsLayerCollection() {
2232 if (auto* locked_element =
2233 DisplayLockUtilities::NearestLockedInclusiveAncestor(
2234 GetLayoutObject())) {
2235 locked_element->GetDisplayLockContext()
2236 ->NotifyNeedsGraphicsLayerCollection();
2237 }
2238 }
2239
2240 #if DCHECK_IS_ON()
VerifyNotPainting()2241 void CompositedLayerMapping::VerifyNotPainting() {
2242 DCHECK(!GetLayoutObject().GetFrame()->GetPage() ||
2243 !GetLayoutObject().GetFrame()->GetPage()->IsPainting());
2244 }
2245 #endif
2246
InvalidateLayerIfNoPrecedingEntry(wtf_size_t index_to_clear)2247 bool CompositedLayerMapping::InvalidateLayerIfNoPrecedingEntry(
2248 wtf_size_t index_to_clear) {
2249 PaintLayer* layer_to_remove = squashed_layers_[index_to_clear].paint_layer;
2250 wtf_size_t previous_index = 0;
2251 for (; previous_index < index_to_clear; ++previous_index) {
2252 if (squashed_layers_[previous_index].paint_layer == layer_to_remove)
2253 break;
2254 }
2255 if (previous_index == index_to_clear &&
2256 layer_to_remove->GroupedMapping() == this) {
2257 Compositor()->PaintInvalidationOnCompositingChange(layer_to_remove);
2258 return true;
2259 }
2260 return false;
2261 }
2262
UpdateSquashingLayerAssignment(PaintLayer * squashed_layer,wtf_size_t next_squashed_layer_index)2263 bool CompositedLayerMapping::UpdateSquashingLayerAssignment(
2264 PaintLayer* squashed_layer,
2265 wtf_size_t next_squashed_layer_index) {
2266 GraphicsLayerPaintInfo paint_info;
2267 paint_info.paint_layer = squashed_layer;
2268 // NOTE: composited bounds are updated elsewhere
2269 // NOTE: offsetFromLayoutObject is updated elsewhere
2270
2271 // Change tracking on squashing layers: at the first sign of something
2272 // changed, just invalidate the layer.
2273 // FIXME: Perhaps we can find a tighter more clever mechanism later.
2274 if (next_squashed_layer_index < squashed_layers_.size()) {
2275 if (paint_info.paint_layer ==
2276 squashed_layers_[next_squashed_layer_index].paint_layer)
2277 return false;
2278
2279 // Must invalidate before adding the squashed layer to the mapping.
2280 Compositor()->PaintInvalidationOnCompositingChange(squashed_layer);
2281
2282 // If the layer which was previously at |nextSquashedLayerIndex| is not
2283 // earlier in the grouped mapping, invalidate its current backing now, since
2284 // it will move later or be removed from the squashing layer.
2285 InvalidateLayerIfNoPrecedingEntry(next_squashed_layer_index);
2286
2287 squashed_layers_.insert(next_squashed_layer_index, paint_info);
2288 } else {
2289 // Must invalidate before adding the squashed layer to the mapping.
2290 Compositor()->PaintInvalidationOnCompositingChange(squashed_layer);
2291 squashed_layers_.push_back(paint_info);
2292 }
2293 squashed_layer->SetGroupedMapping(
2294 this, PaintLayer::kInvalidateLayerAndRemoveFromMapping);
2295
2296 return true;
2297 }
2298
RemoveLayerFromSquashingGraphicsLayer(const PaintLayer * layer)2299 void CompositedLayerMapping::RemoveLayerFromSquashingGraphicsLayer(
2300 const PaintLayer* layer) {
2301 wtf_size_t layer_index = 0;
2302 for (; layer_index < squashed_layers_.size(); ++layer_index) {
2303 if (squashed_layers_[layer_index].paint_layer == layer)
2304 break;
2305 }
2306
2307 // Assert on incorrect mappings between layers and groups
2308 DCHECK_LT(layer_index, squashed_layers_.size());
2309 if (layer_index == squashed_layers_.size())
2310 return;
2311
2312 squashed_layers_.EraseAt(layer_index);
2313 }
2314
2315 #if DCHECK_IS_ON()
VerifyLayerInSquashingVector(const PaintLayer * layer)2316 bool CompositedLayerMapping::VerifyLayerInSquashingVector(
2317 const PaintLayer* layer) {
2318 for (wtf_size_t layer_index = 0; layer_index < squashed_layers_.size();
2319 ++layer_index) {
2320 if (squashed_layers_[layer_index].paint_layer == layer)
2321 return true;
2322 }
2323
2324 return false;
2325 }
2326 #endif
2327
FinishAccumulatingSquashingLayers(wtf_size_t next_squashed_layer_index,Vector<PaintLayer * > & layers_needing_paint_invalidation)2328 void CompositedLayerMapping::FinishAccumulatingSquashingLayers(
2329 wtf_size_t next_squashed_layer_index,
2330 Vector<PaintLayer*>& layers_needing_paint_invalidation) {
2331 if (next_squashed_layer_index < squashed_layers_.size()) {
2332 // Any additional squashed Layers in the array no longer belong here, but
2333 // they might have been added already at an earlier index. Clear pointers on
2334 // those that do not appear in the valid set before removing all the extra
2335 // entries.
2336 for (wtf_size_t i = next_squashed_layer_index; i < squashed_layers_.size();
2337 ++i) {
2338 if (InvalidateLayerIfNoPrecedingEntry(i)) {
2339 squashed_layers_[i].paint_layer->SetGroupedMapping(
2340 nullptr, PaintLayer::kDoNotInvalidateLayerAndRemoveFromMapping);
2341 squashed_layers_[i].paint_layer->SetLostGroupedMapping(true);
2342 }
2343 layers_needing_paint_invalidation.push_back(
2344 squashed_layers_[i].paint_layer);
2345 }
2346
2347 squashed_layers_.EraseAt(
2348 next_squashed_layer_index,
2349 squashed_layers_.size() - next_squashed_layer_index);
2350 }
2351 }
2352
DebugName(const GraphicsLayer * graphics_layer) const2353 String CompositedLayerMapping::DebugName(
2354 const GraphicsLayer* graphics_layer) const {
2355 String name;
2356 if (graphics_layer == graphics_layer_.get()) {
2357 name = owning_layer_.DebugName();
2358 } else if (graphics_layer == squashing_containment_layer_.get()) {
2359 name = "Squashing Containment Layer";
2360 } else if (graphics_layer == squashing_layer_.get()) {
2361 name = "Squashing Layer (first squashed layer: " +
2362 (squashed_layers_.size() > 0
2363 ? squashed_layers_[0].paint_layer->DebugName()
2364 : "") +
2365 ")";
2366 } else if (graphics_layer == foreground_layer_.get()) {
2367 name = owning_layer_.DebugName() + " (foreground) Layer";
2368 } else if (graphics_layer == mask_layer_.get()) {
2369 name = "Mask Layer";
2370 } else if (graphics_layer == layer_for_horizontal_scrollbar_.get()) {
2371 name = "Horizontal Scrollbar Layer";
2372 } else if (graphics_layer == layer_for_vertical_scrollbar_.get()) {
2373 name = "Vertical Scrollbar Layer";
2374 } else if (graphics_layer == layer_for_scroll_corner_.get()) {
2375 name = "Scroll Corner Layer";
2376 } else if (graphics_layer == overflow_controls_host_layer_.get()) {
2377 name = "Overflow Controls Host Layer";
2378 } else if (graphics_layer == scrolling_layer_.get()) {
2379 name = "Scrolling Layer";
2380 } else if (graphics_layer == scrolling_contents_layer_.get()) {
2381 name = "Scrolling Contents Layer";
2382 } else if (graphics_layer == decoration_outline_layer_.get()) {
2383 name = "Decoration Layer";
2384 } else {
2385 NOTREACHED();
2386 }
2387
2388 return name;
2389 }
2390
GetScrollableAreaForTesting(const GraphicsLayer * layer) const2391 const ScrollableArea* CompositedLayerMapping::GetScrollableAreaForTesting(
2392 const GraphicsLayer* layer) const {
2393 if (layer == scrolling_contents_layer_.get())
2394 return owning_layer_.GetScrollableArea();
2395 return nullptr;
2396 }
2397
2398 } // namespace blink
2399