source: webkit/trunk/Source/WebCore/rendering/RenderLayerBacking.cpp

Last change on this file was 295718, checked in by Matt Woodrow, 3 years ago

Don't allocate device pixel ratio scaled backing stores for layers that contain only unscaled bitmap content
https://bugs.webkit.org/show_bug.cgi?id=241450

Reviewed by Simon Fraser.

  • Source/WebCore/platform/graphics/GraphicsLayer.cpp:

(WebCore::GraphicsLayer::GraphicsLayer):

  • Source/WebCore/platform/graphics/GraphicsLayer.h:

(WebCore::GraphicsLayer::setAppliesDeviceScale):
(WebCore::GraphicsLayer::appliesDeviceScale const):
(WebCore::GraphicsLayer::deviceScaleFactor const):

  • Source/WebCore/rendering/RenderLayerBacking.cpp:

(WebCore::PaintedContentsInfo::isUnscaledBitmapOnly):
(WebCore::PaintedContentsInfo::contentsTypeDetermination):
(WebCore::RenderLayerBacking::updateConfiguration):
(WebCore::RenderLayerBacking::isUnscaledBitmapOnly const):

  • Source/WebCore/rendering/RenderLayerBacking.h:

Adds isUnscaledBitmapOnly to check if a layer contains only a <canvas>/image,
and no other rasterized content, and that the bitmap is drawn unscaled.
If so, uses setAppliesDeviceScale to disable hidpi backing stores for this layer.

  • Source/WebCore/platform/graphics/LayerTreeAsTextOptions.h:
  • Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp:

(WebCore::GraphicsLayerCA::dumpAdditionalProperties const):

  • Source/WebCore/testing/Internals.cpp:

(WebCore::toLayerTreeAsTextOptions):

  • Source/WebCore/testing/Internals.h:
  • Source/WebCore/testing/Internals.idl:

Adds new internals.LAYER_TREE_INCLUDES_DEVICE_SCALE flag for layer tree dumping, in order
to test whether a layer has a high dpi backing store or not.

  • LayoutTests/compositing/canvas/hidpi-canvas-backing-store-expected.txt: Added.
  • LayoutTests/compositing/canvas/hidpi-canvas-backing-store-invalidation-expected.txt: Added.
  • LayoutTests/compositing/canvas/hidpi-canvas-backing-store-invalidation.html: Added.
  • LayoutTests/compositing/canvas/hidpi-canvas-backing-store.html: Added.

Adds new test for low-dpi backing store for a layer containing only a canvas, and an invalidation
test to check that we go back to hidpi when we add a rasterized outline.

Canonical link: https://commits.webkit.org/251723@main

  • Property svn:eol-style set to native
File size: 164.4 KB
Line 
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 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 "config.h"
27
28#include "RenderLayerBacking.h"
29
30#include "BitmapImage.h"
31#include "CanvasRenderingContext.h"
32#include "CSSPropertyNames.h"
33#include "CachedImage.h"
34#include "Chrome.h"
35#include "DebugOverlayRegions.h"
36#include "EventRegion.h"
37#include "Frame.h"
38#include "FrameView.h"
39#include "GraphicsContext.h"
40#include "GraphicsLayer.h"
41#include "HTMLBodyElement.h"
42#include "HTMLCanvasElement.h"
43#include "HTMLIFrameElement.h"
44#include "HTMLMediaElement.h"
45#include "HTMLModelElement.h"
46#include "HTMLNames.h"
47#include "HTMLPlugInElement.h"
48#include "InspectorInstrumentation.h"
49#include "KeyframeList.h"
50#include "LayerAncestorClippingStack.h"
51#include "Logging.h"
52#include "Model.h"
53#include "NullGraphicsContext.h"
54#include "Page.h"
55#include "PerformanceLoggingClient.h"
56#include "PluginViewBase.h"
57#include "ProgressTracker.h"
58#include "RenderEmbeddedObject.h"
59#include "RenderFragmentContainer.h"
60#include "RenderFragmentedFlow.h"
61#include "RenderHTMLCanvas.h"
62#include "RenderIFrame.h"
63#include "RenderImage.h"
64#include "RenderLayerCompositor.h"
65#include "RenderLayerScrollableArea.h"
66#include "RenderMedia.h"
67#include "RenderModel.h"
68#include "RenderSVGModelObject.h"
69#include "RenderVideo.h"
70#include "RenderView.h"
71#include "RuntimeEnabledFeatures.h"
72#include "ScrollingCoordinator.h"
73#include "Settings.h"
74#include "StyleResolver.h"
75#include "Styleable.h"
76#include "TiledBacking.h"
77#include <wtf/SystemTracing.h>
78#include <wtf/text/TextStream.h>
79
80#if PLATFORM(IOS_FAMILY)
81#include "RuntimeApplicationChecks.h"
82#endif
83
84#if PLATFORM(MAC)
85#include "LocalDefaultSystemAppearance.h"
86#endif
87
88namespace WebCore {
89
90using namespace HTMLNames;
91
92CanvasCompositingStrategy canvasCompositingStrategy(const RenderObject& renderer)
93{
94 ASSERT(renderer.isCanvas());
95
96 const HTMLCanvasElement* canvas = downcast<HTMLCanvasElement>(renderer.node());
97 auto* context = canvas->renderingContext();
98 if (!context || !context->isAccelerated())
99 return UnacceleratedCanvas;
100
101 if (context->isGPUBased())
102 return CanvasAsLayerContents;
103
104 return CanvasPaintedToLayer; // On Mac and iOS we paint accelerated canvases into their layers.
105}
106
107// This acts as a cache of what we know about what is painting into this RenderLayerBacking.
108class PaintedContentsInfo {
109public:
110 enum class ContentsTypeDetermination {
111 Unknown,
112 SimpleContainer,
113 DirectlyCompositedImage,
114 UnscaledBitmapOnly,
115 Painted,
116 };
117
118 PaintedContentsInfo(RenderLayerBacking& inBacking)
119 : m_backing(inBacking)
120 {
121 }
122
123 void setWantsSubpixelAntialiasedTextState(bool wantsSubpixelAntialiasedTextState)
124 {
125 m_subpixelAntialiasedText = wantsSubpixelAntialiasedTextState ? RequestState::Unknown : RequestState::DontCare;
126 }
127
128 RequestState paintsBoxDecorationsDetermination();
129 bool paintsBoxDecorations()
130 {
131 RequestState state = paintsBoxDecorationsDetermination();
132 return state == RequestState::True || state == RequestState::Undetermined;
133 }
134
135 RequestState paintsContentDetermination();
136 bool paintsContent()
137 {
138 RequestState state = paintsContentDetermination();
139 return state == RequestState::True || state == RequestState::Undetermined;
140 }
141
142 RequestState paintsSubpixelAntialiasedTextDetermination();
143 bool paintsSubpixelAntialiasedText()
144 {
145 RequestState state = paintsSubpixelAntialiasedTextDetermination();
146 return state == RequestState::True || state == RequestState::Undetermined;
147 }
148
149 ContentsTypeDetermination contentsTypeDetermination();
150 bool isSimpleContainer()
151 {
152 return contentsTypeDetermination() == ContentsTypeDetermination::SimpleContainer;
153 }
154
155 bool isDirectlyCompositedImage()
156 {
157 return contentsTypeDetermination() == ContentsTypeDetermination::DirectlyCompositedImage;
158 }
159
160 bool isUnscaledBitmapOnly()
161 {
162 return contentsTypeDetermination() == ContentsTypeDetermination::UnscaledBitmapOnly;
163 }
164
165 RenderLayerBacking& m_backing;
166 RequestState m_boxDecorations { RequestState::Unknown };
167 RequestState m_content { RequestState::Unknown };
168 RequestState m_subpixelAntialiasedText { RequestState::DontCare };
169
170 ContentsTypeDetermination m_contentsType { ContentsTypeDetermination::Unknown };
171};
172
173RequestState PaintedContentsInfo::paintsBoxDecorationsDetermination()
174{
175 if (m_boxDecorations != RequestState::Unknown)
176 return m_boxDecorations;
177
178 m_boxDecorations = m_backing.paintsBoxDecorations() ? RequestState::True : RequestState::False;
179 return m_boxDecorations;
180}
181
182RequestState PaintedContentsInfo::paintsContentDetermination()
183{
184 if (m_content != RequestState::Unknown && m_subpixelAntialiasedText != RequestState::Unknown)
185 return m_content;
186
187 RenderLayer::PaintedContentRequest contentRequest;
188 if (m_subpixelAntialiasedText == RequestState::Unknown)
189 contentRequest.hasSubpixelAntialiasedText = RequestState::Unknown;
190
191 m_content = m_backing.paintsContent(contentRequest) ? RequestState::True : RequestState::False;
192
193 if (m_subpixelAntialiasedText == RequestState::Unknown)
194 m_subpixelAntialiasedText = contentRequest.hasSubpixelAntialiasedText;
195
196 return m_content;
197}
198
199RequestState PaintedContentsInfo::paintsSubpixelAntialiasedTextDetermination()
200{
201 if (m_subpixelAntialiasedText != RequestState::Unknown)
202 return m_subpixelAntialiasedText;
203
204 paintsContentDetermination();
205
206 return m_subpixelAntialiasedText;
207}
208
209PaintedContentsInfo::ContentsTypeDetermination PaintedContentsInfo::contentsTypeDetermination()
210{
211 if (m_contentsType != ContentsTypeDetermination::Unknown)
212 return m_contentsType;
213
214 if (m_backing.isSimpleContainerCompositingLayer(*this))
215 m_contentsType = ContentsTypeDetermination::SimpleContainer;
216 else if (m_backing.isDirectlyCompositedImage())
217 m_contentsType = ContentsTypeDetermination::DirectlyCompositedImage;
218 else if (m_backing.isUnscaledBitmapOnly())
219 m_contentsType = ContentsTypeDetermination::UnscaledBitmapOnly;
220 else
221 m_contentsType = ContentsTypeDetermination::Painted;
222
223 return m_contentsType;
224}
225
226
227RenderLayerBacking::RenderLayerBacking(RenderLayer& layer)
228 : m_owningLayer(layer)
229{
230 if (layer.isRenderViewLayer()) {
231 m_isMainFrameRenderViewLayer = renderer().frame().isMainFrame();
232 m_isFrameLayerWithTiledBacking = renderer().page().chrome().client().shouldUseTiledBackingForFrameView(renderer().view().frameView());
233 }
234
235 createPrimaryGraphicsLayer();
236#if ENABLE(FULLSCREEN_API)
237 setRequiresBackgroundLayer(layer.renderer().isRenderFullScreen());
238#endif
239
240 if (auto* tiledBacking = this->tiledBacking()) {
241 tiledBacking->setIsInWindow(renderer().page().isInWindow());
242
243 if (m_isFrameLayerWithTiledBacking) {
244 tiledBacking->setScrollingPerformanceTestingEnabled(renderer().settings().scrollingPerformanceTestingEnabled());
245 adjustTiledBackingCoverage();
246 }
247 }
248}
249
250RenderLayerBacking::~RenderLayerBacking()
251{
252#if USE(OWNING_LAYER_BEAR_TRAP)
253 RELEASE_ASSERT_WITH_MESSAGE(m_owningLayerBearTrap == BEAR_TRAP_VALUE, "~RenderLayerBacking: m_owningLayerBearTrap caught the bear (55699292)");
254 RELEASE_ASSERT_WITH_MESSAGE(&m_owningLayer, "~RenderLayerBacking: m_owningLayer is null (55699292)");
255#endif
256 // Note that m_owningLayer->backing() is null here.
257 updateAncestorClipping(false, nullptr);
258 updateChildClippingStrategy(false);
259 updateDescendantClippingLayer(false);
260 updateOverflowControlsLayers(false, false, false);
261 updateForegroundLayer(false);
262 updateBackgroundLayer(false);
263 updateMaskingLayer(false, false);
264 updateScrollingLayers(false);
265
266 ASSERT(!m_viewportConstrainedNodeID);
267 ASSERT(!m_scrollingNodeID);
268 ASSERT(!m_frameHostingNodeID);
269 ASSERT(!m_positioningNodeID);
270
271 destroyGraphicsLayers();
272}
273
274void RenderLayerBacking::willBeDestroyed()
275{
276#if USE(OWNING_LAYER_BEAR_TRAP)
277 RELEASE_ASSERT_WITH_MESSAGE(m_owningLayerBearTrap == BEAR_TRAP_VALUE, "RenderLayerBacking::willBeDestroyed(): m_owningLayerBearTrap caught the bear (55699292)");
278 RELEASE_ASSERT_WITH_MESSAGE(&m_owningLayer, "RenderLayerBacking::willBeDestroyed(): m_owningLayer is null (55699292)");
279#endif
280
281 ASSERT(m_owningLayer.backing() == this);
282 compositor().removeFromScrollCoordinatedLayers(m_owningLayer);
283
284 clearBackingSharingLayers();
285}
286
287void RenderLayerBacking::willDestroyLayer(const GraphicsLayer* layer)
288{
289 if (layer && layer->type() == GraphicsLayer::Type::Normal && layer->tiledBacking())
290 compositor().layerTiledBackingUsageChanged(layer, false);
291}
292
293static void clearBackingSharingLayerProviders(Vector<WeakPtr<RenderLayer>>& sharingLayers, const RenderLayer& providerLayer)
294{
295 for (auto& layerWeakPtr : sharingLayers) {
296 if (!layerWeakPtr)
297 continue;
298 if (layerWeakPtr->backingProviderLayer() == &providerLayer)
299 layerWeakPtr->setBackingProviderLayer(nullptr);
300 }
301}
302
303void RenderLayerBacking::setBackingSharingLayers(Vector<WeakPtr<RenderLayer>>&& sharingLayers)
304{
305 bool sharingLayersChanged = m_backingSharingLayers != sharingLayers;
306 if (sharingLayersChanged) {
307 // For layers that used to share and no longer do, and are not composited, recompute repaint rects.
308 for (auto& oldSharingLayer : m_backingSharingLayers) {
309 // Layers that go from shared to composited have their repaint rects recomputed in RenderLayerCompositor::updateBacking().
310 // FIXME: Two O(n^2) traversals in this funtion. Probably OK because sharing lists are usually small, but still.
311 if (!sharingLayers.contains(oldSharingLayer) && !oldSharingLayer->isComposited())
312 oldSharingLayer->computeRepaintRectsIncludingDescendants();
313 }
314 }
315
316 clearBackingSharingLayerProviders(m_backingSharingLayers, m_owningLayer);
317
318 if (sharingLayers != m_backingSharingLayers) {
319 if (sharingLayers.size())
320 setRequiresOwnBackingStore(true);
321 setContentsNeedDisplay(); // This could be optimized to only repaint rects for changed layers.
322 }
323
324 auto oldSharingLayers = WTFMove(m_backingSharingLayers);
325 m_backingSharingLayers = WTFMove(sharingLayers);
326
327 for (auto& layerWeakPtr : m_backingSharingLayers)
328 layerWeakPtr->setBackingProviderLayer(&m_owningLayer);
329
330 if (sharingLayersChanged) {
331 // For layers that are newly sharing, recompute repaint rects.
332 for (auto& currentSharingLayer : m_backingSharingLayers) {
333 if (!oldSharingLayers.contains(currentSharingLayer))
334 currentSharingLayer->computeRepaintRectsIncludingDescendants();
335 }
336 }
337}
338
339void RenderLayerBacking::removeBackingSharingLayer(RenderLayer& layer)
340{
341 layer.setBackingProviderLayer(nullptr);
342 m_backingSharingLayers.removeAll(&layer);
343}
344
345void RenderLayerBacking::clearBackingSharingLayers()
346{
347 clearBackingSharingLayerProviders(m_backingSharingLayers, m_owningLayer);
348 m_backingSharingLayers.clear();
349}
350
351Ref<GraphicsLayer> RenderLayerBacking::createGraphicsLayer(const String& name, GraphicsLayer::Type layerType)
352{
353 auto* graphicsLayerFactory = renderer().page().chrome().client().graphicsLayerFactory();
354
355 auto graphicsLayer = GraphicsLayer::create(graphicsLayerFactory, *this, layerType);
356
357 graphicsLayer->setName(name);
358
359#if PLATFORM(COCOA) && USE(CA)
360 graphicsLayer->setAcceleratesDrawing(compositor().acceleratedDrawingEnabled());
361 graphicsLayer->setUsesDisplayListDrawing(compositor().displayListDrawingEnabled());
362#endif
363
364 return graphicsLayer;
365}
366
367void RenderLayerBacking::setUsesDisplayListDrawing(bool usesDisplayListDrawing)
368{
369 // Note that this only affects the primary layer.
370 if (usesDisplayListDrawing == m_graphicsLayer->usesDisplayListDrawing())
371 return;
372
373 m_graphicsLayer->setUsesDisplayListDrawing(usesDisplayListDrawing);
374 if (m_graphicsLayer->drawsContent())
375 m_graphicsLayer->setNeedsDisplay();
376}
377
378String RenderLayerBacking::displayListAsText(OptionSet<DisplayList::AsTextFlag> flags) const
379{
380 return m_graphicsLayer->displayListAsText(flags);
381}
382
383void RenderLayerBacking::setIsTrackingDisplayListReplay(bool isTrackingReplay)
384{
385 m_graphicsLayer->setIsTrackingDisplayListReplay(isTrackingReplay);
386}
387
388String RenderLayerBacking::replayDisplayListAsText(OptionSet<DisplayList::AsTextFlag> flags) const
389{
390 return m_graphicsLayer->replayDisplayListAsText(flags);
391}
392
393void RenderLayerBacking::tiledBackingUsageChanged(const GraphicsLayer* layer, bool usingTiledBacking)
394{
395 compositor().layerTiledBackingUsageChanged(layer, usingTiledBacking);
396}
397
398TiledBacking* RenderLayerBacking::tiledBacking() const
399{
400 return m_graphicsLayer->tiledBacking();
401}
402
403static TiledBacking::TileCoverage computePageTiledBackingCoverage(const RenderLayer& layer)
404{
405 // If the page is non-visible, don't incur the cost of keeping extra tiles for scrolling.
406 if (!layer.page().isVisible())
407 return TiledBacking::CoverageForVisibleArea;
408
409 auto& frameView = layer.renderer().view().frameView();
410
411 TiledBacking::TileCoverage tileCoverage = TiledBacking::CoverageForVisibleArea;
412 bool useMinimalTilesDuringLiveResize = frameView.inLiveResize();
413 if (frameView.speculativeTilingEnabled() && !useMinimalTilesDuringLiveResize) {
414 bool clipsToExposedRect = static_cast<bool>(frameView.viewExposedRect());
415 if (frameView.horizontalScrollbarMode() != ScrollbarMode::AlwaysOff || clipsToExposedRect)
416 tileCoverage |= TiledBacking::CoverageForHorizontalScrolling;
417
418 if (frameView.verticalScrollbarMode() != ScrollbarMode::AlwaysOff || clipsToExposedRect)
419 tileCoverage |= TiledBacking::CoverageForVerticalScrolling;
420 }
421 return tileCoverage;
422}
423
424static TiledBacking::TileCoverage computeOverflowTiledBackingCoverage(const RenderLayer& layer)
425{
426 // If the page is non-visible, don't incur the cost of keeping extra tiles for scrolling.
427 if (!layer.page().isVisible())
428 return TiledBacking::CoverageForVisibleArea;
429
430 auto& frameView = layer.renderer().view().frameView();
431
432 TiledBacking::TileCoverage tileCoverage = TiledBacking::CoverageForVisibleArea;
433 bool useMinimalTilesDuringLiveResize = frameView.inLiveResize();
434 if (!useMinimalTilesDuringLiveResize) {
435 if (auto* scrollableArea = layer.scrollableArea()) {
436 if (scrollableArea->hasScrollableHorizontalOverflow())
437 tileCoverage |= TiledBacking::CoverageForHorizontalScrolling;
438
439 if (scrollableArea->hasScrollableVerticalOverflow())
440 tileCoverage |= TiledBacking::CoverageForVerticalScrolling;
441 }
442 }
443 return tileCoverage;
444}
445
446void RenderLayerBacking::adjustTiledBackingCoverage()
447{
448 if (m_isFrameLayerWithTiledBacking) {
449 auto tileCoverage = computePageTiledBackingCoverage(m_owningLayer);
450 if (auto* tiledBacking = this->tiledBacking())
451 tiledBacking->setTileCoverage(tileCoverage);
452 }
453
454 if (m_owningLayer.hasCompositedScrollableOverflow() && m_scrolledContentsLayer) {
455 if (auto* tiledBacking = m_scrolledContentsLayer->tiledBacking()) {
456 auto tileCoverage = computeOverflowTiledBackingCoverage(m_owningLayer);
457 tiledBacking->setTileCoverage(tileCoverage);
458 }
459 }
460}
461
462void RenderLayerBacking::setTiledBackingHasMargins(bool hasExtendedBackgroundOnLeftAndRight, bool hasExtendedBackgroundOnTopAndBottom)
463{
464 if (!m_isFrameLayerWithTiledBacking)
465 return;
466
467 tiledBacking()->setHasMargins(hasExtendedBackgroundOnTopAndBottom, hasExtendedBackgroundOnTopAndBottom, hasExtendedBackgroundOnLeftAndRight, hasExtendedBackgroundOnLeftAndRight);
468}
469
470void RenderLayerBacking::updateDebugIndicators(bool showBorder, bool showRepaintCounter)
471{
472 m_graphicsLayer->setShowDebugBorder(showBorder);
473 m_graphicsLayer->setShowRepaintCounter(showRepaintCounter);
474
475 if (m_ancestorClippingStack) {
476 for (auto& entry : m_ancestorClippingStack->stack())
477 entry.clippingLayer->setShowDebugBorder(showBorder);
478 }
479
480 if (m_foregroundLayer) {
481 m_foregroundLayer->setShowDebugBorder(showBorder);
482 m_foregroundLayer->setShowRepaintCounter(showRepaintCounter);
483 }
484
485 if (m_contentsContainmentLayer)
486 m_contentsContainmentLayer->setShowDebugBorder(showBorder);
487
488 if (m_childContainmentLayer)
489 m_childContainmentLayer->setShowDebugBorder(showBorder);
490
491 if (m_backgroundLayer) {
492 m_backgroundLayer->setShowDebugBorder(showBorder);
493 m_backgroundLayer->setShowRepaintCounter(showRepaintCounter);
494 }
495
496 if (m_maskLayer) {
497 m_maskLayer->setShowDebugBorder(showBorder);
498 m_maskLayer->setShowRepaintCounter(showRepaintCounter);
499 }
500
501 if (m_layerForHorizontalScrollbar)
502 m_layerForHorizontalScrollbar->setShowDebugBorder(showBorder);
503
504 if (m_layerForVerticalScrollbar)
505 m_layerForVerticalScrollbar->setShowDebugBorder(showBorder);
506
507 if (m_layerForScrollCorner)
508 m_layerForScrollCorner->setShowDebugBorder(showBorder);
509
510 if (m_scrollContainerLayer)
511 m_scrollContainerLayer->setShowDebugBorder(showBorder);
512
513 if (m_scrolledContentsLayer) {
514 m_scrolledContentsLayer->setShowDebugBorder(showBorder);
515 m_scrolledContentsLayer->setShowRepaintCounter(showRepaintCounter);
516 }
517
518 if (m_overflowControlsContainer)
519 m_overflowControlsContainer->setShowDebugBorder(showBorder);
520}
521
522void RenderLayerBacking::createPrimaryGraphicsLayer()
523{
524 String layerName = m_owningLayer.name();
525 const unsigned maxLayerNameLength = 100;
526 if (layerName.length() > maxLayerNameLength)
527 layerName = makeString(StringView(layerName).left(maxLayerNameLength), "..."_s);
528 m_graphicsLayer = createGraphicsLayer(layerName, m_isFrameLayerWithTiledBacking ? GraphicsLayer::Type::PageTiledBacking : GraphicsLayer::Type::Normal);
529
530 if (m_isFrameLayerWithTiledBacking) {
531 m_childContainmentLayer = createGraphicsLayer("Page TiledBacking containment"_s);
532 m_graphicsLayer->addChild(*m_childContainmentLayer);
533 }
534
535#if !PLATFORM(IOS_FAMILY)
536 if (m_isMainFrameRenderViewLayer) {
537 // Page scale is applied above the RenderView on iOS.
538 m_graphicsLayer->setContentsOpaque(!compositor().viewHasTransparentBackground());
539 m_graphicsLayer->setAppliesPageScale();
540 }
541#endif
542
543#if PLATFORM(COCOA) && USE(CA)
544 if (!compositor().acceleratedDrawingEnabled() && renderer().isCanvas()) {
545 const HTMLCanvasElement* canvas = downcast<HTMLCanvasElement>(renderer().element());
546 if (canvas->shouldAccelerate(canvas->size()))
547 m_graphicsLayer->setAcceleratesDrawing(true);
548 }
549#endif
550 auto& style = renderer().style();
551 updateOpacity(style);
552 updateTransform(style);
553 updateFilters(style);
554#if ENABLE(FILTERS_LEVEL_2)
555 updateBackdropFilters(style);
556#endif
557#if ENABLE(CSS_COMPOSITING)
558 updateBlendMode(style);
559#endif
560 updateContentsScalingFilters(style);
561}
562
563#if PLATFORM(IOS_FAMILY)
564void RenderLayerBacking::layerWillBeDestroyed()
565{
566 auto& renderer = this->renderer();
567 if (is<RenderEmbeddedObject>(renderer) && downcast<RenderEmbeddedObject>(renderer).allowsAcceleratedCompositing()) {
568 auto* pluginViewBase = downcast<PluginViewBase>(downcast<RenderWidget>(renderer).widget());
569 if (pluginViewBase && m_graphicsLayer->contentsLayerForMedia())
570 pluginViewBase->detachPluginLayer();
571 }
572}
573
574bool RenderLayerBacking::needsIOSDumpRenderTreeMainFrameRenderViewLayerIsAlwaysOpaqueHack(const GraphicsLayer& layer) const
575{
576 if (m_isMainFrameRenderViewLayer && IOSApplication::isDumpRenderTree()) {
577 // In iOS WebKit1 the main frame's RenderView layer is always transparent. We lie that it is opaque so that
578 // internals.layerTreeAsText() tests succeed.
579 ASSERT_UNUSED(layer, !layer.contentsOpaque());
580 return true;
581 }
582 return false;
583}
584#endif
585
586void RenderLayerBacking::destroyGraphicsLayers()
587{
588 if (m_graphicsLayer) {
589 m_graphicsLayer->setMaskLayer(nullptr);
590 m_graphicsLayer->setReplicatedByLayer(nullptr);
591 willDestroyLayer(m_graphicsLayer.get());
592 }
593
594 GraphicsLayer::clear(m_maskLayer);
595
596 if (m_ancestorClippingStack)
597 removeClippingStackLayers(*m_ancestorClippingStack);
598
599 if (m_overflowControlsHostLayerAncestorClippingStack)
600 removeClippingStackLayers(*m_overflowControlsHostLayerAncestorClippingStack);
601
602 GraphicsLayer::unparentAndClear(m_contentsContainmentLayer);
603 GraphicsLayer::unparentAndClear(m_foregroundLayer);
604 GraphicsLayer::unparentAndClear(m_backgroundLayer);
605 GraphicsLayer::unparentAndClear(m_childContainmentLayer);
606 GraphicsLayer::unparentAndClear(m_childClippingMaskLayer);
607 GraphicsLayer::unparentAndClear(m_scrollContainerLayer);
608 GraphicsLayer::unparentAndClear(m_scrolledContentsLayer);
609 GraphicsLayer::unparentAndClear(m_graphicsLayer);
610}
611
612static LayoutRect scrollContainerLayerBox(const RenderBox& renderBox)
613{
614 return renderBox.paddingBoxRect();
615}
616
617static LayoutRect clippingLayerBox(const RenderLayerModelObject& renderer)
618{
619 LayoutRect result = LayoutRect::infiniteRect();
620 if (renderer.hasNonVisibleOverflow()) {
621 if (is<RenderBox>(renderer))
622 result = downcast<RenderBox>(renderer).overflowClipRect({ }, 0); // FIXME: Incorrect for CSS regions.
623#if ENABLE(LAYER_BASED_SVG_ENGINE)
624 else if (is<RenderSVGModelObject>(renderer))
625 result = downcast<RenderSVGModelObject>(renderer).overflowClipRect({ }, 0); // FIXME: Incorrect for CSS regions.
626#endif
627 }
628
629 if (renderer.hasClip() && is<RenderBox>(renderer))
630 result.intersect(downcast<RenderBox>(renderer).clipRect({ }, 0)); // FIXME: Incorrect for CSS regions.
631
632 return result;
633}
634
635static LayoutRect overflowControlsHostLayerRect(const RenderBox& renderBox)
636{
637 return renderBox.paddingBoxRectIncludingScrollbar();
638}
639
640void RenderLayerBacking::updateOpacity(const RenderStyle& style)
641{
642 m_graphicsLayer->setOpacity(compositingOpacity(style.opacity()));
643}
644
645void RenderLayerBacking::updateTransform(const RenderStyle& style)
646{
647 TransformationMatrix t;
648 if (m_owningLayer.hasTransform())
649 m_owningLayer.updateTransformFromStyle(t, style, RenderStyle::individualTransformOperations);
650
651 if (m_contentsContainmentLayer) {
652 m_contentsContainmentLayer->setTransform(t);
653 m_graphicsLayer->setTransform({ });
654 } else
655 m_graphicsLayer->setTransform(t);
656}
657
658void RenderLayerBacking::updateChildrenTransformAndAnchorPoint(const LayoutRect& primaryGraphicsLayerRect, LayoutSize offsetFromParentGraphicsLayer)
659{
660 auto defaultAnchorPoint = FloatPoint3D { 0.5, 0.5, 0 };
661 if (!renderer().hasTransformRelatedProperty()) {
662 m_graphicsLayer->setAnchorPoint(defaultAnchorPoint);
663 if (m_contentsContainmentLayer)
664 m_contentsContainmentLayer->setAnchorPoint(defaultAnchorPoint);
665
666 if (m_childContainmentLayer)
667 m_childContainmentLayer->setAnchorPoint(defaultAnchorPoint);
668
669 if (m_scrollContainerLayer)
670 m_scrollContainerLayer->setAnchorPoint(defaultAnchorPoint);
671
672 if (m_scrolledContentsLayer)
673 m_scrolledContentsLayer->setPreserves3D(false);
674 return;
675 }
676
677 const auto deviceScaleFactor = this->deviceScaleFactor();
678 auto transformOrigin = m_owningLayer.transformOriginPixelSnappedIfNeeded();
679 auto layerOffset = roundPointToDevicePixels(toLayoutPoint(offsetFromParentGraphicsLayer), deviceScaleFactor);
680 auto anchor = FloatPoint3D {
681 primaryGraphicsLayerRect.width() ? ((layerOffset.x() - primaryGraphicsLayerRect.x()) + transformOrigin.x()) / primaryGraphicsLayerRect.width() : 0.5f,
682 primaryGraphicsLayerRect.height() ? ((layerOffset.y() - primaryGraphicsLayerRect.y())+ transformOrigin.y()) / primaryGraphicsLayerRect.height() : 0.5f,
683 transformOrigin.z()
684 };
685
686 if (m_contentsContainmentLayer)
687 m_contentsContainmentLayer->setAnchorPoint(anchor);
688 else
689 m_graphicsLayer->setAnchorPoint(anchor);
690
691 auto removeChildrenTransformFromLayers = [&](GraphicsLayer* layerToIgnore = nullptr) {
692 auto* clippingLayer = this->clippingLayer();
693 if (clippingLayer && clippingLayer != layerToIgnore) {
694 clippingLayer->setChildrenTransform({ });
695 clippingLayer->setAnchorPoint(defaultAnchorPoint);
696 }
697
698 if (m_scrollContainerLayer && m_scrollContainerLayer != layerToIgnore) {
699 m_scrollContainerLayer->setChildrenTransform({ });
700 m_scrollContainerLayer->setAnchorPoint(defaultAnchorPoint);
701 m_scrolledContentsLayer->setPreserves3D(false);
702 }
703
704 if (m_graphicsLayer != layerToIgnore)
705 m_graphicsLayer->setChildrenTransform({ });
706 };
707
708 if (!renderer().style().hasPerspective()) {
709 removeChildrenTransformFromLayers();
710 return;
711 }
712
713 auto layerForChildrenTransform = [&]() -> std::tuple<GraphicsLayer*, FloatRect> {
714 if (m_scrollContainerLayer) {
715 ASSERT(is<RenderBox>(renderer())); // Scroll container layers are only created for RenderBox derived renderers.
716 return std::make_tuple(m_scrollContainerLayer.get(), scrollContainerLayerBox(downcast<RenderBox>(renderer())));
717 }
718 if (auto* layer = clippingLayer())
719 return std::make_tuple(layer, clippingLayerBox(renderer()));
720
721 return std::make_tuple(m_graphicsLayer.get(), renderer().transformReferenceBoxRect());
722 };
723
724 auto [layerForPerspective, layerForPerspectiveRect] = layerForChildrenTransform();
725 if (layerForPerspective != m_graphicsLayer) {
726 // If we have scrolling layers, we need the children transform on m_scrollContainerLayer to
727 // affect children of m_scrolledContentsLayer, so set setPreserves3D(true).
728 if (layerForPerspective == m_scrollContainerLayer)
729 m_scrolledContentsLayer->setPreserves3D(true);
730
731 auto perspectiveAnchorPoint = FloatPoint3D {
732 layerForPerspectiveRect.width() ? (transformOrigin.x() - layerForPerspectiveRect.x()) / layerForPerspectiveRect.width() : 0.5f,
733 layerForPerspectiveRect.height() ? (transformOrigin.y() - layerForPerspectiveRect.y()) / layerForPerspectiveRect.height() : 0.5f,
734 transformOrigin.z()
735 };
736
737 layerForPerspective->setAnchorPoint(perspectiveAnchorPoint);
738 }
739
740 layerForPerspective->setChildrenTransform(m_owningLayer.perspectiveTransform());
741 removeChildrenTransformFromLayers(layerForPerspective);
742}
743
744void RenderLayerBacking::updateFilters(const RenderStyle& style)
745{
746 m_canCompositeFilters = m_graphicsLayer->setFilters(style.filter());
747}
748
749#if ENABLE(FILTERS_LEVEL_2)
750void RenderLayerBacking::updateBackdropFilters(const RenderStyle& style)
751{
752 m_canCompositeBackdropFilters = m_graphicsLayer->setBackdropFilters(style.backdropFilter());
753}
754
755void RenderLayerBacking::updateBackdropFiltersGeometry()
756{
757 if (!m_canCompositeBackdropFilters)
758 return;
759
760 if (!is<RenderBox>(renderer()))
761 return;
762
763 auto& renderBox = downcast<RenderBox>(this->renderer());
764
765 FloatRoundedRect backdropFiltersRect;
766 if (renderBox.style().hasBorderRadius() && !renderBox.hasClip()) {
767 auto roundedBoxRect = renderBox.roundedBorderBoxRect();
768 roundedBoxRect.move(contentOffsetInCompositingLayer());
769 backdropFiltersRect = roundedBoxRect.pixelSnappedRoundedRectForPainting(deviceScaleFactor());
770 } else {
771 auto boxRect = renderBox.borderBoxRect();
772 if (renderBox.hasClip())
773 boxRect.intersect(renderBox.clipRect(LayoutPoint(), nullptr));
774 boxRect.move(contentOffsetInCompositingLayer());
775 backdropFiltersRect = FloatRoundedRect(snapRectToDevicePixels(boxRect, deviceScaleFactor()));
776 }
777
778 m_graphicsLayer->setBackdropFiltersRect(backdropFiltersRect);
779}
780#endif
781
782#if ENABLE(CSS_COMPOSITING)
783void RenderLayerBacking::updateBlendMode(const RenderStyle& style)
784{
785 // FIXME: where is the blend mode updated when m_ancestorClippingStacks come and go?
786 if (m_ancestorClippingStack) {
787 m_ancestorClippingStack->stack().first().clippingLayer->setBlendMode(style.blendMode());
788 m_graphicsLayer->setBlendMode(BlendMode::Normal);
789 } else
790 m_graphicsLayer->setBlendMode(style.blendMode());
791}
792#endif
793
794void RenderLayerBacking::updateContentsScalingFilters(const RenderStyle& style)
795{
796 if (!renderer().isCanvas() || canvasCompositingStrategy(renderer()) != CanvasAsLayerContents)
797 return;
798 auto minificationFilter = GraphicsLayer::ScalingFilter::Linear;
799 auto magnificationFilter = GraphicsLayer::ScalingFilter::Linear;
800 switch (style.imageRendering()) {
801 case ImageRendering::CrispEdges:
802 case ImageRendering::Pixelated:
803 // FIXME: In order to match other code-paths, we treat these the same.
804 minificationFilter = GraphicsLayer::ScalingFilter::Nearest;
805 magnificationFilter = GraphicsLayer::ScalingFilter::Nearest;
806 break;
807 default:
808 break;
809 }
810 m_graphicsLayer->setContentsMinificationFilter(minificationFilter);
811 m_graphicsLayer->setContentsMagnificationFilter(magnificationFilter);
812}
813
814static bool layerOrAncestorIsTransformedOrUsingCompositedScrolling(RenderLayer& layer)
815{
816 for (auto* curr = &layer; curr; curr = curr->parent()) {
817 if (curr->hasTransform() || curr->hasCompositedScrollableOverflow())
818 return true;
819 }
820
821 return false;
822}
823
824bool RenderLayerBacking::shouldClipCompositedBounds() const
825{
826#if !PLATFORM(IOS_FAMILY)
827 // Scrollbar layers use this layer for relative positioning, so don't clip.
828 if (layerForHorizontalScrollbar() || layerForVerticalScrollbar())
829 return false;
830#endif
831
832 if (m_isFrameLayerWithTiledBacking)
833 return false;
834
835 if (layerOrAncestorIsTransformedOrUsingCompositedScrolling(m_owningLayer))
836 return false;
837
838 return true;
839}
840
841static bool hasNonZeroTransformOrigin(const RenderObject& renderer)
842{
843 const RenderStyle& style = renderer.style();
844 return (style.transformOriginX().isFixed() && style.transformOriginX().value())
845 || (style.transformOriginY().isFixed() && style.transformOriginY().value());
846}
847
848bool RenderLayerBacking::updateCompositedBounds()
849{
850#if USE(OWNING_LAYER_BEAR_TRAP)
851 RELEASE_ASSERT_WITH_MESSAGE(m_owningLayerBearTrap == BEAR_TRAP_VALUE, "RenderLayerBacking::updateCompositedBounds(): m_owningLayerBearTrap caught the bear (55699292)");
852 RELEASE_ASSERT_WITH_MESSAGE(&m_owningLayer, "RenderLayerBacking::updateCompositedBounds(): m_owningLayer is null (55699292)");
853#endif
854
855 LayoutRect layerBounds = m_owningLayer.calculateLayerBounds(&m_owningLayer, { }, RenderLayer::defaultCalculateLayerBoundsFlags() | RenderLayer::ExcludeHiddenDescendants | RenderLayer::DontConstrainForMask);
856 // Clip to the size of the document or enclosing overflow-scroll layer.
857 // If this or an ancestor is transformed, we can't currently compute the correct rect to intersect with.
858 // We'd need RenderObject::convertContainerToLocalQuad(), which doesn't yet exist.
859 if (shouldClipCompositedBounds()) {
860 auto& view = renderer().view();
861 auto* rootLayer = view.layer();
862
863 LayoutRect clippingBounds;
864 if (renderer().isFixedPositioned() && renderer().container() == &view)
865 clippingBounds = view.frameView().rectForFixedPositionLayout();
866 else
867 clippingBounds = view.unscaledDocumentRect();
868
869 if (&m_owningLayer != rootLayer)
870 clippingBounds.intersect(m_owningLayer.backgroundClipRect(RenderLayer::ClipRectsContext(rootLayer, AbsoluteClipRects)).rect()); // FIXME: Incorrect for CSS regions.
871
872 LayoutPoint delta = m_owningLayer.convertToLayerCoords(rootLayer, LayoutPoint(), RenderLayer::AdjustForColumns);
873 clippingBounds.move(-delta.x(), -delta.y());
874
875 layerBounds.intersect(clippingBounds);
876 }
877
878 // If the backing provider has overflow:clip, we know all sharing layers are affected by the clip because they are containing-block descendants.
879 if (!renderer().hasNonVisibleOverflow()) {
880 for (auto& layerWeakPtr : m_backingSharingLayers) {
881 auto* boundsRootLayer = &m_owningLayer;
882 ASSERT(layerWeakPtr->isDescendantOf(m_owningLayer));
883 auto offset = layerWeakPtr->offsetFromAncestor(&m_owningLayer);
884 auto bounds = layerWeakPtr->calculateLayerBounds(boundsRootLayer, offset, RenderLayer::defaultCalculateLayerBoundsFlags() | RenderLayer::ExcludeHiddenDescendants | RenderLayer::DontConstrainForMask);
885 layerBounds.unite(bounds);
886 }
887 }
888
889 // If the element has a transform-origin that has fixed lengths, and the renderer has zero size,
890 // then we need to ensure that the compositing layer has non-zero size so that we can apply
891 // the transform-origin via the GraphicsLayer anchorPoint (which is expressed as a fractional value).
892 if (layerBounds.isEmpty() && (hasNonZeroTransformOrigin(renderer()) || renderer().style().hasPerspective())) {
893 layerBounds.setWidth(1);
894 layerBounds.setHeight(1);
895 m_artificiallyInflatedBounds = true;
896 } else
897 m_artificiallyInflatedBounds = false;
898
899 return setCompositedBounds(layerBounds);
900}
901
902void RenderLayerBacking::updateAllowsBackingStoreDetaching(const LayoutRect& absoluteBounds)
903{
904 auto setAllowsBackingStoreDetaching = [&](bool allowDetaching) {
905 m_graphicsLayer->setAllowsBackingStoreDetaching(allowDetaching);
906 if (m_foregroundLayer)
907 m_foregroundLayer->setAllowsBackingStoreDetaching(allowDetaching);
908 if (m_backgroundLayer)
909 m_backgroundLayer->setAllowsBackingStoreDetaching(allowDetaching);
910 if (m_scrolledContentsLayer)
911 m_scrolledContentsLayer->setAllowsBackingStoreDetaching(allowDetaching);
912 };
913
914 if (!m_owningLayer.behavesAsFixed()) {
915 setAllowsBackingStoreDetaching(true);
916 return;
917 }
918
919 // We'll allow detaching if the layer is outside the layout viewport. Fixed layers inside
920 // the layout viewport can be revealed by async scrolling, so we want to pin their backing store.
921 FrameView& frameView = renderer().view().frameView();
922 LayoutRect fixedLayoutRect;
923 if (frameView.useFixedLayout())
924 fixedLayoutRect = renderer().view().unscaledDocumentRect();
925 else
926 fixedLayoutRect = frameView.rectForFixedPositionLayout();
927
928 bool allowDetaching = !fixedLayoutRect.intersects(absoluteBounds);
929 LOG_WITH_STREAM(Compositing, stream << "RenderLayerBacking (layer " << &m_owningLayer << ") updateAllowsBackingStoreDetaching - absoluteBounds " << absoluteBounds << " layoutViewportRect " << fixedLayoutRect << ", allowDetaching " << allowDetaching);
930 setAllowsBackingStoreDetaching(allowDetaching);
931}
932
933void RenderLayerBacking::updateAfterWidgetResize()
934{
935 if (!is<RenderWidget>(renderer()))
936 return;
937
938 if (auto* innerCompositor = RenderLayerCompositor::frameContentsCompositor(downcast<RenderWidget>(renderer()))) {
939 innerCompositor->frameViewDidChangeSize();
940 innerCompositor->frameViewDidChangeLocation(flooredIntPoint(contentsBox().location()));
941 }
942}
943
944void RenderLayerBacking::updateAfterLayout(bool needsClippingUpdate, bool needsFullRepaint)
945{
946#if USE(OWNING_LAYER_BEAR_TRAP)
947 RELEASE_ASSERT_WITH_MESSAGE(m_owningLayerBearTrap == BEAR_TRAP_VALUE, "RenderLayerBacking::updateAfterLayout(): m_owningLayerBearTrap caught the bear (55699292)");
948 RELEASE_ASSERT_WITH_MESSAGE(&m_owningLayer, "RenderLayerBacking::updateAfterLayout(): m_owningLayer is null (55699292)");
949#endif
950
951 LOG_WITH_STREAM(Compositing, stream << "RenderLayerBacking::updateAfterLayout (layer " << &m_owningLayer << " needsClippingUpdate " << needsClippingUpdate << " needsFullRepaint " << needsFullRepaint);
952
953 // This is the main trigger for layout changing layer geometry, but we have to do the work again in updateBackingAndHierarchy()
954 // when we know the final compositing hierarchy. We can't just set dirty bits from RenderLayer::setSize() because that doesn't
955 // take overflow into account.
956 if (updateCompositedBounds()) {
957 m_owningLayer.setNeedsCompositingGeometryUpdate();
958 // This layer's geometry affects those of its children.
959 m_owningLayer.setChildrenNeedCompositingGeometryUpdate();
960 } else if (needsClippingUpdate) {
961 m_owningLayer.setNeedsCompositingConfigurationUpdate();
962 m_owningLayer.setNeedsCompositingGeometryUpdate();
963 }
964
965 if (needsFullRepaint && canIssueSetNeedsDisplay())
966 setContentsNeedDisplay();
967}
968
969// This can only update things that don't require up-to-date layout.
970void RenderLayerBacking::updateConfigurationAfterStyleChange()
971{
972 updateMaskingLayer(renderer().hasMask(), renderer().hasClipPath());
973
974 if (m_owningLayer.hasReflection()) {
975 if (m_owningLayer.reflectionLayer()->backing()) {
976 auto* reflectionLayer = m_owningLayer.reflectionLayer()->backing()->graphicsLayer();
977 m_graphicsLayer->setReplicatedByLayer(reflectionLayer);
978 }
979 } else
980 m_graphicsLayer->setReplicatedByLayer(nullptr);
981
982 // FIXME: do we care if opacity is animating?
983 auto& style = renderer().style();
984 updateOpacity(style);
985 updateFilters(style);
986
987#if ENABLE(FILTERS_LEVEL_2)
988 updateBackdropFilters(style);
989#endif
990#if ENABLE(CSS_COMPOSITING)
991 updateBlendMode(style);
992#endif
993 updateContentsScalingFilters(style);
994}
995
996bool RenderLayerBacking::updateConfiguration(const RenderLayer* compositingAncestor)
997{
998 ASSERT(!m_owningLayer.normalFlowListDirty());
999 ASSERT(!m_owningLayer.zOrderListsDirty());
1000 ASSERT(!renderer().view().needsLayout());
1001
1002 bool layerConfigChanged = false;
1003 auto& compositor = this->compositor();
1004
1005 setBackgroundLayerPaintsFixedRootBackground(compositor.needsFixedRootBackgroundLayer(m_owningLayer));
1006
1007 if (updateBackgroundLayer(m_backgroundLayerPaintsFixedRootBackground || m_requiresBackgroundLayer))
1008 layerConfigChanged = true;
1009
1010 if (updateForegroundLayer(compositor.needsContentsCompositingLayer(m_owningLayer)))
1011 layerConfigChanged = true;
1012
1013 bool needsDescendantsClippingLayer = false;
1014 bool usesCompositedScrolling = m_owningLayer.hasCompositedScrollableOverflow();
1015
1016 if (usesCompositedScrolling) {
1017 // If it's scrollable, it has to be a box.
1018 FloatRoundedRect contentsClippingRect = downcast<RenderBox>(renderer()).roundedBorderBoxRect().pixelSnappedRoundedRectForPainting(deviceScaleFactor());
1019 needsDescendantsClippingLayer = contentsClippingRect.isRounded();
1020 } else
1021 needsDescendantsClippingLayer = RenderLayerCompositor::clipsCompositingDescendants(m_owningLayer);
1022
1023 if (updateScrollingLayers(usesCompositedScrolling))
1024 layerConfigChanged = true;
1025
1026 if (updateDescendantClippingLayer(needsDescendantsClippingLayer))
1027 layerConfigChanged = true;
1028
1029 ASSERT(compositingAncestor == m_owningLayer.ancestorCompositingLayer());
1030 if (updateAncestorClipping(compositor.clippedByAncestor(m_owningLayer, compositingAncestor), compositingAncestor))
1031 layerConfigChanged = true;
1032
1033 if (updateOverflowControlsLayers(requiresHorizontalScrollbarLayer(), requiresVerticalScrollbarLayer(), requiresScrollCornerLayer()))
1034 layerConfigChanged = true;
1035
1036 if (layerConfigChanged)
1037 updateInternalHierarchy();
1038
1039 // RenderLayerCompositor::adjustOverflowScrollbarContainerLayers() may have reparented the overflowControlsContainer
1040 // in an earlier update, so always put it back here. We don't yet know if it will get reparented again.
1041 if (m_overflowControlsContainer && m_overflowControlsContainer->parent() != m_graphicsLayer.get()) {
1042 m_graphicsLayer->addChild(*m_overflowControlsContainer);
1043 // Ensure that we fix up the position of m_overflowControlsContainer.
1044 m_owningLayer.setNeedsCompositingGeometryUpdate();
1045 }
1046
1047 // FIXME: Overlow controls need to be above the flattening layer?
1048 if (auto* flatteningLayer = tileCacheFlatteningLayer()) {
1049 if (layerConfigChanged || flatteningLayer->parent() != m_graphicsLayer.get())
1050 m_graphicsLayer->addChild(*flatteningLayer);
1051 }
1052
1053 if (updateMaskingLayer(renderer().hasMask(), renderer().hasClipPath()))
1054 layerConfigChanged = true;
1055
1056 updateChildClippingStrategy(needsDescendantsClippingLayer);
1057
1058 if (m_owningLayer.hasReflection()) {
1059 if (m_owningLayer.reflectionLayer()->backing()) {
1060 auto* reflectionLayer = m_owningLayer.reflectionLayer()->backing()->graphicsLayer();
1061 m_graphicsLayer->setReplicatedByLayer(reflectionLayer);
1062 }
1063 } else
1064 m_graphicsLayer->setReplicatedByLayer(nullptr);
1065
1066 PaintedContentsInfo contentsInfo(*this);
1067
1068 // Requires layout.
1069 if (!m_owningLayer.isRenderViewLayer()) {
1070 bool didUpdateContentsRect = false;
1071 updateDirectlyCompositedBoxDecorations(contentsInfo, didUpdateContentsRect);
1072 } else
1073 updateRootLayerConfiguration();
1074
1075 // Requires layout.
1076 if (contentsInfo.isDirectlyCompositedImage())
1077 updateImageContents(contentsInfo);
1078
1079 bool unscaledBitmap = contentsInfo.isUnscaledBitmapOnly();
1080 if (unscaledBitmap == m_graphicsLayer->appliesDeviceScale()) {
1081 m_graphicsLayer->setAppliesDeviceScale(!unscaledBitmap);
1082 layerConfigChanged = true;
1083 }
1084
1085 if (is<RenderEmbeddedObject>(renderer()) && downcast<RenderEmbeddedObject>(renderer()).allowsAcceleratedCompositing()) {
1086 auto* pluginViewBase = downcast<PluginViewBase>(downcast<RenderWidget>(renderer()).widget());
1087#if PLATFORM(IOS_FAMILY)
1088 if (pluginViewBase && !m_graphicsLayer->contentsLayerForMedia()) {
1089 pluginViewBase->detachPluginLayer();
1090 pluginViewBase->attachPluginLayer();
1091 }
1092#else
1093 m_graphicsLayer->setContentsToPlatformLayer(pluginViewBase->platformLayer(), GraphicsLayer::ContentsLayerPurpose::Plugin);
1094#endif
1095 }
1096#if ENABLE(VIDEO)
1097 else if (is<RenderVideo>(renderer()) && downcast<RenderVideo>(renderer()).shouldDisplayVideo()) {
1098 auto* mediaElement = downcast<HTMLMediaElement>(renderer().element());
1099 m_graphicsLayer->setContentsToPlatformLayer(mediaElement->platformLayer(), GraphicsLayer::ContentsLayerPurpose::Media);
1100 updateContentsRects();
1101 }
1102#endif
1103#if ENABLE(WEBGL) || ENABLE(OFFSCREEN_CANVAS)
1104 else if (renderer().isCanvas() && canvasCompositingStrategy(renderer()) == CanvasAsLayerContents) {
1105 const HTMLCanvasElement* canvas = downcast<HTMLCanvasElement>(renderer().element());
1106 if (auto* context = canvas->renderingContext())
1107 m_graphicsLayer->setContentsDisplayDelegate(context->layerContentsDisplayDelegate(), GraphicsLayer::ContentsLayerPurpose::Canvas);
1108
1109 layerConfigChanged = true;
1110 }
1111#endif
1112#if ENABLE(MODEL_ELEMENT)
1113 else if (is<RenderModel>(renderer())) {
1114 auto element = downcast<HTMLModelElement>(renderer().element());
1115
1116 // Some ModelPlayers use a platformLayer() and some pass the Model to the layer as contents,
1117 // but this is a runtime decision.
1118 if (element->usesPlatformLayer())
1119 m_graphicsLayer->setContentsToPlatformLayer(element->platformLayer(), GraphicsLayer::ContentsLayerPurpose::Model);
1120 else if (auto model = element->model())
1121 m_graphicsLayer->setContentsToModel(WTFMove(model), element->isInteractive() ? GraphicsLayer::ModelInteraction::Enabled : GraphicsLayer::ModelInteraction::Disabled);
1122
1123 element->sizeMayHaveChanged();
1124
1125 layerConfigChanged = true;
1126 }
1127#endif
1128 if (is<RenderWidget>(renderer()) && compositor.parentFrameContentLayers(downcast<RenderWidget>(renderer()))) {
1129 m_owningLayer.setNeedsCompositingGeometryUpdate();
1130 layerConfigChanged = true;
1131 }
1132
1133 if (RenderLayerCompositor::isCompositedSubframeRenderer(renderer())) {
1134 m_graphicsLayer->setContentsRectClipsDescendants(true);
1135 updateContentsRects();
1136 }
1137
1138 if (layerConfigChanged)
1139 updatePaintingPhases();
1140
1141#if USE(OWNING_LAYER_BEAR_TRAP)
1142 RELEASE_ASSERT_WITH_MESSAGE(m_owningLayerBearTrap == BEAR_TRAP_VALUE, "RenderLayerBacking::updateConfiguration(): m_owningLayerBearTrap caught the bear (55699292)");
1143 RELEASE_ASSERT_WITH_MESSAGE(&m_owningLayer, "RenderLayerBacking::updateConfiguration(): m_owningLayer is null (55699292)");
1144#endif
1145
1146 return layerConfigChanged;
1147}
1148
1149static bool subpixelOffsetFromRendererChanged(const LayoutSize& oldSubpixelOffsetFromRenderer, const LayoutSize& newSubpixelOffsetFromRenderer, float deviceScaleFactor)
1150{
1151 FloatSize previous = snapSizeToDevicePixel(oldSubpixelOffsetFromRenderer, LayoutPoint(), deviceScaleFactor);
1152 FloatSize current = snapSizeToDevicePixel(newSubpixelOffsetFromRenderer, LayoutPoint(), deviceScaleFactor);
1153 return previous != current;
1154}
1155
1156static FloatSize subpixelForLayerPainting(const LayoutPoint& point, float pixelSnappingFactor)
1157{
1158 LayoutUnit x = point.x();
1159 LayoutUnit y = point.y();
1160 x = x >= 0 ? floorToDevicePixel(x, pixelSnappingFactor) : ceilToDevicePixel(x, pixelSnappingFactor);
1161 y = y >= 0 ? floorToDevicePixel(y, pixelSnappingFactor) : ceilToDevicePixel(y, pixelSnappingFactor);
1162 return point - LayoutPoint(x, y);
1163}
1164
1165struct OffsetFromRenderer {
1166 // 1.2px - > { m_devicePixelOffset = 1px m_subpixelOffset = 0.2px }
1167 LayoutSize m_devicePixelOffset;
1168 LayoutSize m_subpixelOffset;
1169};
1170
1171static OffsetFromRenderer computeOffsetFromRenderer(const LayoutSize& offset, float deviceScaleFactor)
1172{
1173 OffsetFromRenderer offsetFromRenderer;
1174 offsetFromRenderer.m_subpixelOffset = LayoutSize(subpixelForLayerPainting(toLayoutPoint(offset), deviceScaleFactor));
1175 offsetFromRenderer.m_devicePixelOffset = offset - offsetFromRenderer.m_subpixelOffset;
1176 return offsetFromRenderer;
1177}
1178
1179struct SnappedRectInfo {
1180 LayoutRect m_snappedRect;
1181 LayoutSize m_snapDelta;
1182};
1183
1184static SnappedRectInfo snappedGraphicsLayer(const LayoutSize& offset, const LayoutSize& size, float deviceScaleFactor)
1185{
1186 SnappedRectInfo snappedGraphicsLayer;
1187 LayoutRect graphicsLayerRect = LayoutRect(toLayoutPoint(offset), size);
1188 snappedGraphicsLayer.m_snappedRect = LayoutRect(snapRectToDevicePixels(graphicsLayerRect, deviceScaleFactor));
1189 snappedGraphicsLayer.m_snapDelta = snappedGraphicsLayer.m_snappedRect.location() - toLayoutPoint(offset);
1190 return snappedGraphicsLayer;
1191}
1192
1193static LayoutSize computeOffsetFromAncestorGraphicsLayer(const RenderLayer* compositedAncestor, const LayoutPoint& location, float deviceScaleFactor)
1194{
1195 if (!compositedAncestor)
1196 return toLayoutSize(location);
1197
1198 // FIXME: This is a workaround until after webkit.org/b/162634 gets fixed. ancestorSubpixelOffsetFromRenderer
1199 // could be stale when a dynamic composited state change triggers a pre-order updateGeometry() traversal.
1200 LayoutSize ancestorSubpixelOffsetFromRenderer = compositedAncestor->backing()->subpixelOffsetFromRenderer();
1201 LayoutRect ancestorCompositedBounds = compositedAncestor->backing()->compositedBounds();
1202 LayoutSize floored = toLayoutSize(LayoutPoint(floorPointToDevicePixels(ancestorCompositedBounds.location() - ancestorSubpixelOffsetFromRenderer, deviceScaleFactor)));
1203 LayoutSize ancestorRendererOffsetFromAncestorGraphicsLayer = -(floored + ancestorSubpixelOffsetFromRenderer);
1204 return ancestorRendererOffsetFromAncestorGraphicsLayer + toLayoutSize(location);
1205}
1206
1207class ComputedOffsets {
1208public:
1209 ComputedOffsets(const RenderLayer& renderLayer, const RenderLayer* compositingAncestor, const LayoutRect& localRect, const LayoutRect& parentGraphicsLayerRect, const LayoutRect& primaryGraphicsLayerRect)
1210 : m_renderLayer(renderLayer)
1211 , m_compositingAncestor(compositingAncestor)
1212 , m_location(localRect.location())
1213 , m_parentGraphicsLayerOffset(toLayoutSize(parentGraphicsLayerRect.location()))
1214 , m_primaryGraphicsLayerOffset(toLayoutSize(primaryGraphicsLayerRect.location()))
1215 , m_deviceScaleFactor(renderLayer.renderer().document().deviceScaleFactor())
1216 {
1217 }
1218
1219 LayoutSize fromParentGraphicsLayer()
1220 {
1221 if (!m_fromParentGraphicsLayer)
1222 m_fromParentGraphicsLayer = fromAncestorGraphicsLayer() - m_parentGraphicsLayerOffset;
1223 return m_fromParentGraphicsLayer.value();
1224 }
1225
1226 LayoutSize fromPrimaryGraphicsLayer()
1227 {
1228 if (!m_fromPrimaryGraphicsLayer)
1229 m_fromPrimaryGraphicsLayer = fromAncestorGraphicsLayer() - m_parentGraphicsLayerOffset - m_primaryGraphicsLayerOffset;
1230 return m_fromPrimaryGraphicsLayer.value();
1231 }
1232
1233private:
1234 LayoutSize fromAncestorGraphicsLayer()
1235 {
1236 if (!m_fromAncestorGraphicsLayer) {
1237 LayoutPoint localPointInAncestorRenderLayerCoords = m_renderLayer.convertToLayerCoords(m_compositingAncestor, m_location, RenderLayer::AdjustForColumns);
1238 m_fromAncestorGraphicsLayer = computeOffsetFromAncestorGraphicsLayer(m_compositingAncestor, localPointInAncestorRenderLayerCoords, m_deviceScaleFactor);
1239 }
1240 return m_fromAncestorGraphicsLayer.value();
1241 }
1242
1243 std::optional<LayoutSize> m_fromAncestorGraphicsLayer;
1244 std::optional<LayoutSize> m_fromParentGraphicsLayer;
1245 std::optional<LayoutSize> m_fromPrimaryGraphicsLayer;
1246
1247 const RenderLayer& m_renderLayer;
1248 const RenderLayer* m_compositingAncestor;
1249 // Location is relative to the renderer.
1250 const LayoutPoint m_location;
1251 const LayoutSize m_parentGraphicsLayerOffset;
1252 const LayoutSize m_primaryGraphicsLayerOffset;
1253 float m_deviceScaleFactor;
1254};
1255
1256LayoutRect RenderLayerBacking::computePrimaryGraphicsLayerRect(const RenderLayer* compositedAncestor, const LayoutRect& parentGraphicsLayerRect) const
1257{
1258 ComputedOffsets compositedBoundsOffset(m_owningLayer, compositedAncestor, compositedBounds(), parentGraphicsLayerRect, { });
1259 return LayoutRect(encloseRectToDevicePixels(LayoutRect(toLayoutPoint(compositedBoundsOffset.fromParentGraphicsLayer()), compositedBounds().size()),
1260 deviceScaleFactor()));
1261}
1262
1263// FIXME: See if we need this now that updateGeometry() is always called in post-order traversal.
1264LayoutRect RenderLayerBacking::computeParentGraphicsLayerRect(const RenderLayer* compositedAncestor) const
1265{
1266 if (!compositedAncestor || !compositedAncestor->backing())
1267 return renderer().view().documentRect();
1268
1269 auto* ancestorBacking = compositedAncestor->backing();
1270 LayoutRect parentGraphicsLayerRect;
1271 if (m_owningLayer.isInsideFragmentedFlow()) {
1272 // FIXME: flows/columns need work.
1273 LayoutRect ancestorCompositedBounds = ancestorBacking->compositedBounds();
1274 ancestorCompositedBounds.setLocation(LayoutPoint());
1275 parentGraphicsLayerRect = ancestorCompositedBounds;
1276 }
1277
1278 if (!is<RenderBox>(compositedAncestor->renderer()))
1279 return parentGraphicsLayerRect;
1280
1281 auto& ancestorRenderBox = downcast<RenderBox>(compositedAncestor->renderer());
1282
1283 if (ancestorBacking->hasClippingLayer()) {
1284 // If the compositing ancestor has a layer to clip children, we parent in that, and therefore position relative to it.
1285 LayoutRect clippingBox = clippingLayerBox(ancestorRenderBox);
1286 LayoutSize clippingBoxOffset = computeOffsetFromAncestorGraphicsLayer(compositedAncestor, clippingBox.location(), deviceScaleFactor());
1287 parentGraphicsLayerRect = snappedGraphicsLayer(clippingBoxOffset, clippingBox.size(), deviceScaleFactor()).m_snappedRect;
1288 }
1289
1290 if (compositedAncestor->hasCompositedScrollableOverflow()) {
1291 auto* scrollableArea = compositedAncestor->scrollableArea();
1292 ASSERT(scrollableArea);
1293
1294 LayoutRect ancestorCompositedBounds = ancestorBacking->compositedBounds();
1295 LayoutRect scrollContainerBox = scrollContainerLayerBox(ancestorRenderBox);
1296 ScrollOffset scrollOffset = scrollableArea->scrollOffset();
1297 parentGraphicsLayerRect = LayoutRect((scrollContainerBox.location() - toLayoutSize(ancestorCompositedBounds.location()) - toLayoutSize(scrollOffset)), scrollContainerBox.size());
1298 }
1299
1300 return parentGraphicsLayerRect;
1301}
1302
1303void RenderLayerBacking::updateGeometry(const RenderLayer* compositedAncestor)
1304{
1305 ASSERT(!m_owningLayer.normalFlowListDirty());
1306 ASSERT(!m_owningLayer.zOrderListsDirty());
1307 ASSERT(!m_owningLayer.descendantDependentFlagsAreDirty());
1308 ASSERT(!renderer().view().needsLayout());
1309
1310 const RenderStyle& style = renderer().style();
1311 const auto deviceScaleFactor = this->deviceScaleFactor();
1312
1313 bool isRunningAcceleratedTransformAnimation = false;
1314 if (auto styleable = Styleable::fromRenderer(renderer()))
1315 isRunningAcceleratedTransformAnimation = styleable->isRunningAcceleratedTransformAnimation();
1316
1317 updateTransform(style);
1318 updateOpacity(style);
1319 updateFilters(style);
1320#if ENABLE(FILTERS_LEVEL_2)
1321 updateBackdropFilters(style);
1322#endif
1323#if ENABLE(CSS_COMPOSITING)
1324 updateBlendMode(style);
1325#endif
1326 updateContentsScalingFilters(style);
1327
1328 ASSERT(compositedAncestor == m_owningLayer.ancestorCompositingLayer());
1329 LayoutRect parentGraphicsLayerRect = computeParentGraphicsLayerRect(compositedAncestor);
1330
1331 if (m_ancestorClippingStack)
1332 updateClippingStackLayerGeometry(*m_ancestorClippingStack, compositedAncestor, parentGraphicsLayerRect);
1333
1334 LayoutRect primaryGraphicsLayerRect = computePrimaryGraphicsLayerRect(compositedAncestor, parentGraphicsLayerRect);
1335
1336 ComputedOffsets compositedBoundsOffset(m_owningLayer, compositedAncestor, compositedBounds(), parentGraphicsLayerRect, primaryGraphicsLayerRect);
1337 ComputedOffsets rendererOffset(m_owningLayer, compositedAncestor, { }, parentGraphicsLayerRect, primaryGraphicsLayerRect);
1338
1339 m_compositedBoundsOffsetFromGraphicsLayer = compositedBoundsOffset.fromPrimaryGraphicsLayer();
1340
1341 auto primaryLayerPosition = primaryGraphicsLayerRect.location();
1342
1343 // FIXME: reflections should force transform-style to be flat in the style: https://bugs.webkit.org/show_bug.cgi?id=106959
1344 bool preserves3D = style.preserves3D() && !renderer().hasReflection();
1345 if (m_contentsContainmentLayer) {
1346 m_contentsContainmentLayer->setPreserves3D(preserves3D);
1347 m_contentsContainmentLayer->setPosition(primaryLayerPosition);
1348 primaryLayerPosition = { };
1349 // Use the same size as m_graphicsLayer so transforms behave correctly.
1350 m_contentsContainmentLayer->setSize(primaryGraphicsLayerRect.size());
1351 }
1352
1353 auto computeAnimationExtent = [&] () -> std::optional<FloatRect> {
1354 LayoutRect animatedBounds;
1355 if (isRunningAcceleratedTransformAnimation && m_owningLayer.getOverlapBoundsIncludingChildrenAccountingForTransformAnimations(animatedBounds, RenderLayer::IncludeCompositedDescendants))
1356 return FloatRect(animatedBounds);
1357 return { };
1358 };
1359 m_graphicsLayer->setAnimationExtent(computeAnimationExtent());
1360 m_graphicsLayer->setPreserves3D(preserves3D);
1361 m_graphicsLayer->setBackfaceVisibility(style.backfaceVisibility() == BackfaceVisibility::Visible);
1362
1363 m_graphicsLayer->setPosition(primaryLayerPosition);
1364 m_graphicsLayer->setSize(primaryGraphicsLayerRect.size());
1365
1366#if ENABLE(CSS_TRANSFORM_STYLE_OPTIMIZED_3D)
1367 // FIXME: Take ancestry into account and remove unnecessary structural layers.
1368 m_graphicsLayer->setIsSeparated(style.usedTransformStyle3D() == TransformStyle3D::Optimized3D);
1369#endif
1370
1371 // Compute renderer offset from primary graphics layer. Note that primaryGraphicsLayerRect is in parentGraphicsLayer's coordinate system which is not necessarily
1372 // the same as the ancestor graphics layer.
1373 OffsetFromRenderer primaryGraphicsLayerOffsetFromRenderer;
1374 LayoutSize oldSubpixelOffsetFromRenderer = m_subpixelOffsetFromRenderer;
1375 primaryGraphicsLayerOffsetFromRenderer = computeOffsetFromRenderer(-rendererOffset.fromPrimaryGraphicsLayer(), deviceScaleFactor);
1376 m_subpixelOffsetFromRenderer = primaryGraphicsLayerOffsetFromRenderer.m_subpixelOffset;
1377 m_hasSubpixelRounding = !m_subpixelOffsetFromRenderer.isZero() || compositedBounds().size() != primaryGraphicsLayerRect.size();
1378
1379 if (primaryGraphicsLayerOffsetFromRenderer.m_devicePixelOffset != m_graphicsLayer->offsetFromRenderer())
1380 m_graphicsLayer->setOffsetFromRenderer(primaryGraphicsLayerOffsetFromRenderer.m_devicePixelOffset);
1381
1382 // If we have a layer that clips children, position it.
1383 LayoutRect clippingBox;
1384 if (auto* clipLayer = clippingLayer()) {
1385 // clipLayer is the m_childContainmentLayer.
1386 clippingBox = clippingLayerBox(renderer());
1387 // Clipping layer is parented in the primary graphics layer.
1388 LayoutSize clipBoxOffsetFromGraphicsLayer = toLayoutSize(clippingBox.location()) + rendererOffset.fromPrimaryGraphicsLayer();
1389 SnappedRectInfo snappedClippingGraphicsLayer = snappedGraphicsLayer(clipBoxOffsetFromGraphicsLayer, clippingBox.size(), deviceScaleFactor);
1390 clipLayer->setPosition(snappedClippingGraphicsLayer.m_snappedRect.location());
1391 clipLayer->setSize(snappedClippingGraphicsLayer.m_snappedRect.size());
1392 clipLayer->setOffsetFromRenderer(toLayoutSize(clippingBox.location() - snappedClippingGraphicsLayer.m_snapDelta));
1393
1394 auto computeMasksToBoundsRect = [&] {
1395 if ((renderer().style().clipPath() || renderer().style().hasBorderRadius()) && !m_childClippingMaskLayer) {
1396 auto contentsClippingRect = FloatRoundedRect(renderer().style().getRoundedInnerBorderFor(m_owningLayer.rendererBorderBoxRect()));
1397 contentsClippingRect.move(LayoutSize(-clipLayer->offsetFromRenderer()));
1398 return contentsClippingRect;
1399 }
1400
1401 return FloatRoundedRect { FloatRect { { }, snappedClippingGraphicsLayer.m_snappedRect.size() } };
1402 };
1403
1404 clipLayer->setMasksToBoundsRect(computeMasksToBoundsRect());
1405
1406 if (m_childClippingMaskLayer && !m_scrollContainerLayer) {
1407 m_childClippingMaskLayer->setSize(clipLayer->size());
1408 m_childClippingMaskLayer->setPosition({ });
1409 m_childClippingMaskLayer->setOffsetFromRenderer(clipLayer->offsetFromRenderer());
1410 }
1411 }
1412
1413 if (m_maskLayer)
1414 updateMaskingLayerGeometry();
1415
1416 updateChildrenTransformAndAnchorPoint(primaryGraphicsLayerRect, rendererOffset.fromParentGraphicsLayer());
1417
1418 if (m_owningLayer.reflectionLayer() && m_owningLayer.reflectionLayer()->isComposited()) {
1419 auto* reflectionBacking = m_owningLayer.reflectionLayer()->backing();
1420 reflectionBacking->updateGeometry(&m_owningLayer);
1421
1422 // The reflection layer has the bounds of m_owningLayer.reflectionLayer(),
1423 // but the reflected layer is the bounds of this layer, so we need to position it appropriately.
1424 FloatRect layerBounds = this->compositedBounds();
1425 FloatRect reflectionLayerBounds = reflectionBacking->compositedBounds();
1426 reflectionBacking->graphicsLayer()->setReplicatedLayerPosition(FloatPoint(layerBounds.location() - reflectionLayerBounds.location()));
1427 }
1428
1429 if (m_scrollContainerLayer) {
1430 ASSERT(m_scrolledContentsLayer);
1431 LayoutRect scrollContainerBox = scrollContainerLayerBox(downcast<RenderBox>(renderer()));
1432 LayoutRect parentLayerBounds = clippingLayer() ? scrollContainerBox : compositedBounds();
1433
1434 // FIXME: need to do some pixel snapping here.
1435 m_scrollContainerLayer->setPosition(FloatPoint(scrollContainerBox.location() - parentLayerBounds.location()));
1436 m_scrollContainerLayer->setSize(roundedIntSize(LayoutSize(scrollContainerBox.width(), scrollContainerBox.height())));
1437
1438 auto* scrollableArea = m_owningLayer.scrollableArea();
1439 ASSERT(scrollableArea);
1440
1441 ScrollOffset scrollOffset = scrollableArea->scrollOffset();
1442 updateScrollOffset(scrollOffset);
1443
1444 FloatSize oldScrollingLayerOffset = m_scrollContainerLayer->offsetFromRenderer();
1445 m_scrollContainerLayer->setOffsetFromRenderer(toFloatSize(scrollContainerBox.location()));
1446
1447 if (m_childClippingMaskLayer) {
1448 m_childClippingMaskLayer->setPosition(m_scrollContainerLayer->position());
1449 m_childClippingMaskLayer->setSize(m_scrollContainerLayer->size());
1450 m_childClippingMaskLayer->setOffsetFromRenderer(toFloatSize(scrollContainerBox.location()));
1451 }
1452
1453 bool paddingBoxOffsetChanged = oldScrollingLayerOffset != m_scrollContainerLayer->offsetFromRenderer();
1454
1455 IntSize scrollSize;
1456 if (scrollableArea)
1457 scrollSize = IntSize(scrollableArea->scrollWidth(), scrollableArea->scrollHeight());
1458 if (scrollSize != m_scrolledContentsLayer->size() || paddingBoxOffsetChanged)
1459 m_scrolledContentsLayer->setNeedsDisplay();
1460
1461 m_scrolledContentsLayer->setSize(scrollSize);
1462 m_scrolledContentsLayer->setScrollOffset(scrollOffset, GraphicsLayer::DontSetNeedsDisplay);
1463 m_scrolledContentsLayer->setOffsetFromRenderer(toLayoutSize(scrollContainerBox.location()), GraphicsLayer::DontSetNeedsDisplay);
1464
1465 adjustTiledBackingCoverage();
1466 }
1467
1468 if (m_overflowControlsContainer) {
1469 LayoutRect overflowControlsBox = overflowControlsHostLayerRect(downcast<RenderBox>(renderer()));
1470 LayoutSize boxOffsetFromGraphicsLayer = toLayoutSize(overflowControlsBox.location()) + rendererOffset.fromPrimaryGraphicsLayer();
1471 SnappedRectInfo snappedBoxInfo = snappedGraphicsLayer(boxOffsetFromGraphicsLayer, overflowControlsBox.size(), deviceScaleFactor);
1472
1473 m_overflowControlsContainer->setPosition(snappedBoxInfo.m_snappedRect.location());
1474 m_overflowControlsContainer->setSize(snappedBoxInfo.m_snappedRect.size());
1475 m_overflowControlsContainer->setMasksToBounds(true);
1476 }
1477
1478 if (m_foregroundLayer) {
1479 FloatSize foregroundSize;
1480 FloatSize foregroundOffset;
1481 GraphicsLayer::ShouldSetNeedsDisplay needsDisplayOnOffsetChange = GraphicsLayer::SetNeedsDisplay;
1482 if (m_scrolledContentsLayer) {
1483 foregroundSize = m_scrolledContentsLayer->size();
1484 foregroundOffset = m_scrolledContentsLayer->offsetFromRenderer() - toLayoutSize(m_scrolledContentsLayer->scrollOffset());
1485 needsDisplayOnOffsetChange = GraphicsLayer::DontSetNeedsDisplay;
1486 } else if (hasClippingLayer()) {
1487 // If we have a clipping layer (which clips descendants), then the foreground layer is a child of it,
1488 // so that it gets correctly sorted with children. In that case, position relative to the clipping layer.
1489 foregroundSize = FloatSize(clippingBox.size());
1490 foregroundOffset = toFloatSize(clippingBox.location());
1491 } else {
1492 foregroundSize = primaryGraphicsLayerRect.size();
1493 foregroundOffset = m_graphicsLayer->offsetFromRenderer();
1494 }
1495
1496 m_foregroundLayer->setPosition({ });
1497 m_foregroundLayer->setSize(foregroundSize);
1498 m_foregroundLayer->setOffsetFromRenderer(foregroundOffset, needsDisplayOnOffsetChange);
1499 }
1500
1501 if (m_backgroundLayer) {
1502 FloatPoint backgroundPosition;
1503 FloatSize backgroundSize = primaryGraphicsLayerRect.size();
1504 if (backgroundLayerPaintsFixedRootBackground()) {
1505 const FrameView& frameView = renderer().view().frameView();
1506 backgroundPosition = frameView.scrollPositionForFixedPosition();
1507 backgroundSize = frameView.layoutSize();
1508 } else {
1509 auto boundingBox = renderer().objectBoundingBox();
1510 backgroundPosition = boundingBox.location();
1511 backgroundSize = boundingBox.size();
1512 }
1513 m_backgroundLayer->setPosition(backgroundPosition);
1514 m_backgroundLayer->setSize(backgroundSize);
1515 m_backgroundLayer->setOffsetFromRenderer(m_graphicsLayer->offsetFromRenderer());
1516 }
1517
1518 // If this layer was created just for clipping or to apply perspective, it doesn't need its own backing store.
1519 LayoutRect ancestorCompositedBounds = compositedAncestor ? compositedAncestor->backing()->compositedBounds() : LayoutRect();
1520 setRequiresOwnBackingStore(compositor().requiresOwnBackingStore(m_owningLayer, compositedAncestor,
1521 LayoutRect(toLayoutPoint(compositedBoundsOffset.fromParentGraphicsLayer()), compositedBounds().size()), ancestorCompositedBounds));
1522#if ENABLE(FILTERS_LEVEL_2)
1523 updateBackdropFiltersGeometry();
1524#endif
1525 updateAfterWidgetResize();
1526
1527 positionOverflowControlsLayers();
1528
1529 if (subpixelOffsetFromRendererChanged(oldSubpixelOffsetFromRenderer, m_subpixelOffsetFromRenderer, deviceScaleFactor) && canIssueSetNeedsDisplay())
1530 setContentsNeedDisplay();
1531
1532#if ENABLE(MODEL_ELEMENT)
1533 if (is<RenderModel>(renderer()))
1534 downcast<HTMLModelElement>(renderer().element())->sizeMayHaveChanged();
1535#endif
1536}
1537
1538void RenderLayerBacking::adjustOverflowControlsPositionRelativeToAncestor(const RenderLayer& ancestorLayer)
1539{
1540 ASSERT(m_overflowControlsContainer);
1541 ASSERT(ancestorLayer.isComposited());
1542 auto ancestorBacking = ancestorLayer.backing();
1543 if (!ancestorBacking)
1544 return;
1545
1546 LayoutRect parentGraphicsLayerRect = computeParentGraphicsLayerRect(&ancestorLayer);
1547 LayoutRect primaryGraphicsLayerRect = computePrimaryGraphicsLayerRect(&ancestorLayer, parentGraphicsLayerRect);
1548
1549 auto overflowControlsRect = overflowControlsHostLayerRect(downcast<RenderBox>(renderer()));
1550
1551 if (overflowControlsHostLayerAncestorClippingStack())
1552 updateClippingStackLayerGeometry(*m_overflowControlsHostLayerAncestorClippingStack, &ancestorLayer, parentGraphicsLayerRect);
1553
1554 ComputedOffsets rendererOffset(m_owningLayer, &ancestorLayer, { }, parentGraphicsLayerRect, primaryGraphicsLayerRect);
1555
1556 LayoutSize boxOffsetFromGraphicsLayer = toLayoutSize(overflowControlsRect.location()) + rendererOffset.fromParentGraphicsLayer();
1557 SnappedRectInfo snappedBoxInfo = snappedGraphicsLayer(boxOffsetFromGraphicsLayer, overflowControlsRect.size(), deviceScaleFactor());
1558
1559 m_overflowControlsContainer->setPosition(snappedBoxInfo.m_snappedRect.location());
1560 m_overflowControlsContainer->setSize(snappedBoxInfo.m_snappedRect.size());
1561}
1562
1563void RenderLayerBacking::setLocationOfScrolledContents(ScrollOffset scrollOffset, ScrollingLayerPositionAction setOrSync)
1564{
1565 if (setOrSync == ScrollingLayerPositionAction::Sync)
1566 m_scrollContainerLayer->syncBoundsOrigin(scrollOffset);
1567 else
1568 m_scrollContainerLayer->setBoundsOrigin(scrollOffset);
1569}
1570
1571void RenderLayerBacking::updateScrollOffset(ScrollOffset scrollOffset)
1572{
1573 auto* scrollableArea = m_owningLayer.scrollableArea();
1574 ASSERT(scrollableArea);
1575
1576 if (scrollableArea->currentScrollType() == ScrollType::User) {
1577 // If scrolling is happening externally, we don't want to touch the layer bounds origin here because that will cause jitter.
1578 setLocationOfScrolledContents(scrollOffset, ScrollingLayerPositionAction::Sync);
1579 scrollableArea->setRequiresScrollPositionReconciliation(true);
1580 } else {
1581 // Note that we implement the contents offset via the bounds origin on this layer, rather than a position on the sublayer.
1582 setLocationOfScrolledContents(scrollOffset, ScrollingLayerPositionAction::Set);
1583 scrollableArea->setRequiresScrollPositionReconciliation(false);
1584 }
1585
1586 ASSERT(m_scrolledContentsLayer->position().isZero());
1587}
1588
1589void RenderLayerBacking::updateAfterDescendants()
1590{
1591 // FIXME: this potentially duplicates work we did in updateConfiguration().
1592 PaintedContentsInfo contentsInfo(*this);
1593 contentsInfo.setWantsSubpixelAntialiasedTextState(GraphicsLayer::supportsSubpixelAntialiasedLayerText() && FontCascade::isSubpixelAntialiasingAvailable());
1594
1595 if (!m_owningLayer.isRenderViewLayer()) {
1596 bool didUpdateContentsRect = false;
1597 updateDirectlyCompositedBoxDecorations(contentsInfo, didUpdateContentsRect);
1598 if (!didUpdateContentsRect && m_graphicsLayer->usesContentsLayer())
1599 resetContentsRect();
1600 }
1601
1602 updateDrawsContent(contentsInfo);
1603
1604 if (!m_isMainFrameRenderViewLayer && !m_isFrameLayerWithTiledBacking && !m_requiresBackgroundLayer) {
1605 // For non-root layers, background is always painted by the primary graphics layer.
1606 ASSERT(!m_backgroundLayer);
1607 m_graphicsLayer->setContentsOpaque(!m_hasSubpixelRounding && m_owningLayer.backgroundIsKnownToBeOpaqueInRect(compositedBounds()));
1608 }
1609
1610 m_graphicsLayer->setContentsVisible(m_owningLayer.hasVisibleContent() || hasVisibleNonCompositedDescendants());
1611 if (m_scrollContainerLayer) {
1612 m_scrollContainerLayer->setContentsVisible(renderer().style().visibility() == Visibility::Visible);
1613
1614 bool userInteractive = renderer().visibleToHitTesting();
1615 m_scrollContainerLayer->setUserInteractionEnabled(userInteractive);
1616 if (m_layerForHorizontalScrollbar)
1617 m_layerForHorizontalScrollbar->setUserInteractionEnabled(userInteractive);
1618 if (m_layerForVerticalScrollbar)
1619 m_layerForVerticalScrollbar->setUserInteractionEnabled(userInteractive);
1620 if (m_layerForScrollCorner)
1621 m_layerForScrollCorner->setUserInteractionEnabled(userInteractive);
1622 }
1623
1624#if USE(OWNING_LAYER_BEAR_TRAP)
1625 RELEASE_ASSERT_WITH_MESSAGE(m_owningLayerBearTrap == BEAR_TRAP_VALUE, "RenderLayerBacking::updateAfterDescendants(): m_owningLayerBearTrap caught the bear (55699292)");
1626 RELEASE_ASSERT_WITH_MESSAGE(&m_owningLayer, "RenderLayerBacking::updateAfterDescendants(): m_owningLayer is null (55699292)");
1627#endif
1628}
1629
1630// FIXME: Avoid repaints when clip path changes.
1631void RenderLayerBacking::updateMaskingLayerGeometry()
1632{
1633 m_maskLayer->setSize(m_graphicsLayer->size());
1634 m_maskLayer->setPosition(FloatPoint());
1635 m_maskLayer->setOffsetFromRenderer(m_graphicsLayer->offsetFromRenderer());
1636
1637 if (!m_maskLayer->drawsContent()) {
1638 if (renderer().hasClipPath()) {
1639 ASSERT(renderer().style().clipPath()->type() != PathOperation::Reference);
1640
1641 // FIXME: Use correct reference box for inlines: https://bugs.webkit.org/show_bug.cgi?id=129047, https://github.com/w3c/csswg-drafts/issues/6383
1642 LayoutRect boundingBox = m_owningLayer.boundingBox(&m_owningLayer);
1643 LayoutRect referenceBoxForClippedInline = LayoutRect(snapRectToDevicePixels(boundingBox, deviceScaleFactor()));
1644 LayoutSize offset = LayoutSize(snapSizeToDevicePixel(-m_subpixelOffsetFromRenderer, LayoutPoint(), deviceScaleFactor()));
1645 auto [clipPath, windRule] = m_owningLayer.computeClipPath(offset, referenceBoxForClippedInline);
1646
1647 FloatSize pathOffset = m_maskLayer->offsetFromRenderer();
1648 if (!pathOffset.isZero())
1649 clipPath.translate(-pathOffset);
1650
1651 m_maskLayer->setShapeLayerPath(clipPath);
1652 m_maskLayer->setShapeLayerWindRule(windRule);
1653 }
1654 }
1655}
1656
1657void RenderLayerBacking::updateDirectlyCompositedBoxDecorations(PaintedContentsInfo& contentsInfo, bool& didUpdateContentsRect)
1658{
1659 if (!m_owningLayer.hasVisibleContent())
1660 return;
1661
1662 // The order of operations here matters, since the last valid type of contents needs
1663 // to also update the contentsRect.
1664 updateDirectlyCompositedBackgroundColor(contentsInfo, didUpdateContentsRect);
1665 updateDirectlyCompositedBackgroundImage(contentsInfo, didUpdateContentsRect);
1666}
1667
1668void RenderLayerBacking::updateInternalHierarchy()
1669{
1670 // m_foregroundLayer has to be inserted in the correct order with child layers,
1671 // so it's not inserted here.
1672 GraphicsLayer* lastClippingLayer = nullptr;
1673 if (m_ancestorClippingStack) {
1674 connectClippingStackLayers(*m_ancestorClippingStack);
1675 lastClippingLayer = m_ancestorClippingStack->lastClippingLayer();
1676 }
1677
1678 if (m_contentsContainmentLayer) {
1679 m_contentsContainmentLayer->removeAllChildren();
1680 if (lastClippingLayer)
1681 lastClippingLayer->addChild(*m_contentsContainmentLayer);
1682 }
1683
1684 if (m_backgroundLayer)
1685 m_contentsContainmentLayer->addChild(*m_backgroundLayer);
1686
1687 if (m_contentsContainmentLayer)
1688 m_contentsContainmentLayer->addChild(*m_graphicsLayer);
1689 else if (lastClippingLayer)
1690 lastClippingLayer->addChild(*m_graphicsLayer);
1691
1692 if (m_childContainmentLayer)
1693 m_graphicsLayer->addChild(*m_childContainmentLayer);
1694
1695 if (m_scrollContainerLayer) {
1696 auto* superlayer = m_childContainmentLayer ? m_childContainmentLayer.get() : m_graphicsLayer.get();
1697 superlayer->addChild(*m_scrollContainerLayer);
1698 }
1699
1700 // The clip for child layers does not include space for overflow controls, so they exist as
1701 // siblings of the clipping layer if we have one. Normal children of this layer are set as
1702 // children of the clipping layer.
1703 if (m_overflowControlsContainer) {
1704 if (m_layerForHorizontalScrollbar)
1705 m_overflowControlsContainer->addChild(*m_layerForHorizontalScrollbar);
1706
1707 if (m_layerForVerticalScrollbar)
1708 m_overflowControlsContainer->addChild(*m_layerForVerticalScrollbar);
1709
1710 if (m_layerForScrollCorner)
1711 m_overflowControlsContainer->addChild(*m_layerForScrollCorner);
1712
1713 // m_overflowControlsContainer may get reparented later.
1714 m_graphicsLayer->addChild(*m_overflowControlsContainer);
1715 }
1716}
1717
1718void RenderLayerBacking::updateContentsRects()
1719{
1720 m_graphicsLayer->setContentsRect(snapRectToDevicePixels(contentsBox(), deviceScaleFactor()));
1721
1722 if (is<RenderReplaced>(renderer())) {
1723 FloatRoundedRect contentsClippingRect = downcast<RenderReplaced>(renderer()).roundedContentBoxRect().pixelSnappedRoundedRectForPainting(deviceScaleFactor());
1724 contentsClippingRect.move(contentOffsetInCompositingLayer());
1725 m_graphicsLayer->setContentsClippingRect(contentsClippingRect);
1726 }
1727}
1728
1729void RenderLayerBacking::resetContentsRect()
1730{
1731 updateContentsRects();
1732 m_graphicsLayer->setContentsTileSize(IntSize());
1733 m_graphicsLayer->setContentsTilePhase(IntSize());
1734}
1735
1736void RenderLayerBacking::updateDrawsContent()
1737{
1738 PaintedContentsInfo contentsInfo(*this);
1739 contentsInfo.setWantsSubpixelAntialiasedTextState(GraphicsLayer::supportsSubpixelAntialiasedLayerText());
1740
1741 updateDrawsContent(contentsInfo);
1742}
1743
1744void RenderLayerBacking::updateDrawsContent(PaintedContentsInfo& contentsInfo)
1745{
1746 if (m_scrollContainerLayer) {
1747 // We don't have to consider overflow controls, because we know that the scrollbars are drawn elsewhere.
1748 // m_graphicsLayer only needs backing store if the non-scrolling parts (background, outlines, borders, shadows etc) need to paint.
1749 // m_scrollContainerLayer never has backing store.
1750 // m_scrolledContentsLayer only needs backing store if the scrolled contents need to paint.
1751 bool hasNonScrollingPaintedContent = m_owningLayer.hasVisibleContent() && m_owningLayer.hasVisibleBoxDecorationsOrBackground();
1752 m_graphicsLayer->setDrawsContent(hasNonScrollingPaintedContent);
1753
1754 bool hasScrollingPaintedContent = hasBackingSharingLayers() || (m_owningLayer.hasVisibleContent() && (renderer().hasBackground() || contentsInfo.paintsContent()));
1755 m_scrolledContentsLayer->setDrawsContent(hasScrollingPaintedContent);
1756 return;
1757 }
1758
1759 bool hasPaintedContent = containsPaintedContent(contentsInfo);
1760
1761 m_paintsSubpixelAntialiasedText = renderer().settings().subpixelAntialiasedLayerTextEnabled() && contentsInfo.paintsSubpixelAntialiasedText();
1762
1763 // FIXME: we could refine this to only allocate backing for one of these layers if possible.
1764 m_graphicsLayer->setDrawsContent(hasPaintedContent);
1765 if (m_foregroundLayer) {
1766 m_foregroundLayer->setDrawsContent(hasPaintedContent);
1767 m_foregroundLayer->setSupportsSubpixelAntialiasedText(m_paintsSubpixelAntialiasedText);
1768 // The text content is painted into the foreground layer.
1769 // FIXME: this ignores SVG background images which may contain text.
1770 m_graphicsLayer->setSupportsSubpixelAntialiasedText(false);
1771 } else
1772 m_graphicsLayer->setSupportsSubpixelAntialiasedText(m_paintsSubpixelAntialiasedText);
1773
1774 if (m_backgroundLayer)
1775 m_backgroundLayer->setDrawsContent(m_backgroundLayerPaintsFixedRootBackground ? hasPaintedContent : contentsInfo.paintsBoxDecorations());
1776}
1777
1778#if ENABLE(ASYNC_SCROLLING)
1779bool RenderLayerBacking::maintainsEventRegion() const
1780{
1781 if (!m_owningLayer.page().scrollingCoordinator())
1782 return false;
1783
1784 if (paintsIntoCompositedAncestor())
1785 return false;
1786
1787 if (renderer().view().needsEventRegionUpdateForNonCompositedFrame())
1788 return true;
1789
1790#if ENABLE(TOUCH_ACTION_REGIONS)
1791 if (renderer().document().mayHaveElementsWithNonAutoTouchAction())
1792 return true;
1793#endif
1794#if ENABLE(EDITABLE_REGION)
1795 LOG_WITH_STREAM(EventRegions, stream << "RenderLayerBacking: " << this << " maintainsEventRegion - mayHaveEditableElements: " << renderer().document().mayHaveEditableElements() << " shouldBuildEditableRegion: " << renderer().page().shouldBuildEditableRegion());
1796 if (renderer().document().mayHaveEditableElements() && renderer().page().shouldBuildEditableRegion())
1797 return true;
1798#endif
1799#if ENABLE(WHEEL_EVENT_REGIONS)
1800 if (renderer().document().hasWheelEventHandlers())
1801 return true;
1802#endif
1803#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
1804 if (renderer().page().shouldBuildInteractionRegions())
1805 return true;
1806#endif
1807
1808 if (m_owningLayer.isRenderViewLayer())
1809 return false;
1810
1811 auto& settings = renderer().settings();
1812 if (!settings.asyncFrameScrollingEnabled() && !settings.asyncOverflowScrollingEnabled())
1813 return false;
1814
1815 if (!m_owningLayer.page().scrollingCoordinator()->hasSubscrollers())
1816 return false;
1817
1818 return true;
1819}
1820
1821void RenderLayerBacking::updateEventRegion()
1822{
1823 LOG_WITH_STREAM(EventRegions, stream << m_owningLayer << " " << this << " updateEventRegion (needs update: " << needsEventRegionUpdate() << ", maintainsEventRegion: " << maintainsEventRegion() << ")");
1824
1825 if (!maintainsEventRegion())
1826 return;
1827
1828 if (!needsEventRegionUpdate())
1829 return;
1830
1831 TraceScope scope(ComputeEventRegionsStart, ComputeEventRegionsEnd);
1832
1833 auto visibleToHitTesting = renderer().visibleToHitTesting();
1834
1835 auto setEventRegionToLayerBounds = [&](GraphicsLayer* graphicsLayer) {
1836 if (!graphicsLayer)
1837 return;
1838
1839 EventRegion eventRegion;
1840 auto eventRegionContext = eventRegion.makeContext();
1841 if (visibleToHitTesting)
1842 eventRegionContext.unite(enclosingIntRect(FloatRect({ }, graphicsLayer->size())), renderer(), renderer().style());
1843
1844#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
1845 eventRegionContext.copyInteractionRegionsToEventRegion();
1846#endif
1847 graphicsLayer->setEventRegion(WTFMove(eventRegion));
1848 };
1849
1850 auto updateEventRegionForLayer = [&](GraphicsLayer& graphicsLayer) {
1851 NullGraphicsContext nullContext;
1852 EventRegion eventRegion;
1853#if ENABLE(EDITABLE_REGION)
1854 if (renderer().page().shouldBuildEditableRegion())
1855 eventRegion.ensureEditableRegion();
1856#endif
1857 auto eventRegionContext = eventRegion.makeContext();
1858 auto layerOffset = graphicsLayer.scrollOffset() - roundedIntSize(graphicsLayer.offsetFromRenderer());
1859 auto layerBounds = enclosingIntRect(FloatRect(-layerOffset, graphicsLayer.size()));
1860
1861 if (visibleToHitTesting) {
1862 if (&graphicsLayer == m_scrolledContentsLayer) {
1863 // Initialize scrolled contents layer with layer-sized event region as it can all used for scrolling.
1864 // This avoids generating unnecessarily complex event regions. We still need to to do the paint to capture touch-action regions.
1865 eventRegionContext.unite(layerBounds, renderer(), renderer().style());
1866 }
1867 }
1868
1869 if (m_owningLayer.isRenderViewLayer() && (&graphicsLayer == m_graphicsLayer || &graphicsLayer == m_foregroundLayer)) {
1870 // Event handlers on the root cover the entire layer.
1871 eventRegionContext.unite(layerBounds, renderer(), renderer().style());
1872 }
1873
1874 auto dirtyRect = enclosingIntRect(FloatRect(FloatPoint(graphicsLayer.offsetFromRenderer()), graphicsLayer.size()));
1875 paintIntoLayer(&graphicsLayer, nullContext, dirtyRect, { }, &eventRegionContext);
1876
1877#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
1878 eventRegionContext.copyInteractionRegionsToEventRegion();
1879#endif
1880 eventRegion.translate(toIntSize(layerOffset));
1881 graphicsLayer.setEventRegion(WTFMove(eventRegion));
1882 };
1883
1884 updateEventRegionForLayer(*m_graphicsLayer);
1885
1886 setEventRegionToLayerBounds(m_scrollContainerLayer.get());
1887 setEventRegionToLayerBounds(m_layerForHorizontalScrollbar.get());
1888 setEventRegionToLayerBounds(m_layerForVerticalScrollbar.get());
1889 setEventRegionToLayerBounds(m_layerForScrollCorner.get());
1890
1891 if (m_scrolledContentsLayer)
1892 updateEventRegionForLayer(*m_scrolledContentsLayer);
1893
1894 if (m_foregroundLayer)
1895 updateEventRegionForLayer(*m_foregroundLayer);
1896
1897 renderer().view().setNeedsEventRegionUpdateForNonCompositedFrame(false);
1898
1899 setNeedsEventRegionUpdate(false);
1900}
1901#endif
1902
1903bool RenderLayerBacking::updateAncestorClippingStack(Vector<CompositedClipData>&& clippingData)
1904{
1905 if (!m_ancestorClippingStack && clippingData.isEmpty())
1906 return false;
1907
1908 auto* scrollingCoordinator = m_owningLayer.page().scrollingCoordinator();
1909
1910 if (m_ancestorClippingStack && clippingData.isEmpty()) {
1911 m_ancestorClippingStack->clear(scrollingCoordinator);
1912 m_ancestorClippingStack = nullptr;
1913
1914 if (m_overflowControlsHostLayerAncestorClippingStack) {
1915 m_overflowControlsHostLayerAncestorClippingStack->clear(scrollingCoordinator);
1916 m_overflowControlsHostLayerAncestorClippingStack = nullptr;
1917 }
1918 return true;
1919 }
1920
1921 if (!m_ancestorClippingStack) {
1922 m_ancestorClippingStack = makeUnique<LayerAncestorClippingStack>(WTFMove(clippingData));
1923 LOG_WITH_STREAM(Compositing, stream << "layer " << &m_owningLayer << " ancestorClippingStack " << *m_ancestorClippingStack);
1924 return true;
1925 }
1926
1927 if (m_ancestorClippingStack->equalToClipData(clippingData)) {
1928 LOG_WITH_STREAM(Compositing, stream << "layer " << &m_owningLayer << " ancestorClippingStack " << *m_ancestorClippingStack);
1929 return false;
1930 }
1931
1932 m_ancestorClippingStack->updateWithClipData(scrollingCoordinator, WTFMove(clippingData));
1933 LOG_WITH_STREAM(Compositing, stream << "layer " << &m_owningLayer << " ancestorClippingStack " << *m_ancestorClippingStack);
1934 if (m_overflowControlsHostLayerAncestorClippingStack)
1935 m_overflowControlsHostLayerAncestorClippingStack->updateWithClipData(scrollingCoordinator, WTFMove(clippingData));
1936 return true;
1937}
1938
1939void RenderLayerBacking::ensureOverflowControlsHostLayerAncestorClippingStack(const RenderLayer* compositedAncestor)
1940{
1941 auto* scrollingCoordinator = m_owningLayer.page().scrollingCoordinator();
1942 auto clippingData = m_ancestorClippingStack->compositedClipData();
1943
1944 if (m_overflowControlsHostLayerAncestorClippingStack)
1945 m_overflowControlsHostLayerAncestorClippingStack->updateWithClipData(scrollingCoordinator, WTFMove(clippingData));
1946 else
1947 m_overflowControlsHostLayerAncestorClippingStack = makeUnique<LayerAncestorClippingStack>(WTFMove(clippingData));
1948
1949 ensureClippingStackLayers(*m_overflowControlsHostLayerAncestorClippingStack);
1950
1951 LayoutRect parentGraphicsLayerRect = computeParentGraphicsLayerRect(compositedAncestor);
1952 updateClippingStackLayerGeometry(*m_overflowControlsHostLayerAncestorClippingStack, compositedAncestor, parentGraphicsLayerRect);
1953
1954 connectClippingStackLayers(*m_overflowControlsHostLayerAncestorClippingStack);
1955}
1956
1957void RenderLayerBacking::ensureClippingStackLayers(LayerAncestorClippingStack& clippingStack)
1958{
1959 for (auto& entry : clippingStack.stack()) {
1960 if (!entry.clippingLayer) {
1961 entry.clippingLayer = createGraphicsLayer(entry.clipData.isOverflowScroll ? "clip for scroller"_s : "ancestor clipping"_s);
1962 entry.clippingLayer->setMasksToBounds(true);
1963 entry.clippingLayer->setPaintingPhase({ });
1964 }
1965 }
1966}
1967
1968void RenderLayerBacking::removeClippingStackLayers(LayerAncestorClippingStack& clippingStack)
1969{
1970 for (auto& entry : clippingStack.stack())
1971 GraphicsLayer::unparentAndClear(entry.clippingLayer);
1972}
1973
1974void RenderLayerBacking::connectClippingStackLayers(LayerAncestorClippingStack& clippingStack)
1975{
1976 auto& clippingEntryStack = clippingStack.stack();
1977 for (unsigned i = 0; i < clippingEntryStack.size() - 1; ++i) {
1978 auto& entry = clippingEntryStack.at(i);
1979 entry.clippingLayer->setChildren({ Ref { *clippingEntryStack.at(i + 1).clippingLayer } });
1980 }
1981
1982 clippingEntryStack.last().clippingLayer->removeAllChildren();
1983}
1984
1985void RenderLayerBacking::updateClippingStackLayerGeometry(LayerAncestorClippingStack& clippingStack, const RenderLayer* compositedAncestor, LayoutRect& parentGraphicsLayerRect)
1986{
1987 // All clipRects in the stack are computed relative to m_owningLayer, so convert them back to compositedAncestor.
1988 auto offsetFromCompositedAncestor = toLayoutSize(m_owningLayer.convertToLayerCoords(compositedAncestor, { }, RenderLayer::AdjustForColumns));
1989 LayoutRect lastClipLayerRect = parentGraphicsLayerRect;
1990
1991 auto deviceScaleFactor = this->deviceScaleFactor();
1992 for (auto& entry : clippingStack.stack()) {
1993 auto clipRect = entry.clipData.clipRect;
1994 LayoutSize clippingOffset = computeOffsetFromAncestorGraphicsLayer(compositedAncestor, clipRect.location() + offsetFromCompositedAncestor, deviceScaleFactor);
1995 LayoutRect snappedClippingLayerRect = snappedGraphicsLayer(clippingOffset, clipRect.size(), deviceScaleFactor).m_snappedRect;
1996
1997 entry.clippingLayer->setPosition(toLayoutPoint(snappedClippingLayerRect.location() - lastClipLayerRect.location()));
1998 lastClipLayerRect = snappedClippingLayerRect;
1999
2000 entry.clippingLayer->setSize(snappedClippingLayerRect.size());
2001
2002 if (entry.clipData.isOverflowScroll) {
2003 ScrollOffset scrollOffset;
2004 if (auto* scrollableArea = entry.clipData.clippingLayer ? entry.clipData.clippingLayer->scrollableArea() : nullptr)
2005 scrollOffset = scrollableArea->scrollOffset();
2006
2007 entry.clippingLayer->setBoundsOrigin(scrollOffset);
2008 lastClipLayerRect.moveBy(-scrollOffset);
2009 } else
2010 entry.clippingLayer->setBoundsOrigin({ });
2011 }
2012
2013 parentGraphicsLayerRect = lastClipLayerRect;
2014}
2015
2016// Return true if the layer changed.
2017bool RenderLayerBacking::updateAncestorClipping(bool needsAncestorClip, const RenderLayer* compositingAncestor)
2018{
2019 bool layersChanged = false;
2020
2021 if (needsAncestorClip) {
2022 if (compositor().updateAncestorClippingStack(m_owningLayer, compositingAncestor)) {
2023 if (m_ancestorClippingStack)
2024 ensureClippingStackLayers(*m_ancestorClippingStack);
2025
2026 layersChanged = true;
2027 }
2028 } else if (m_ancestorClippingStack) {
2029 removeClippingStackLayers(*m_ancestorClippingStack);
2030 m_ancestorClippingStack = nullptr;
2031
2032 if (m_overflowControlsHostLayerAncestorClippingStack) {
2033 removeClippingStackLayers(*m_overflowControlsHostLayerAncestorClippingStack);
2034 m_overflowControlsHostLayerAncestorClippingStack = nullptr;
2035 }
2036
2037 layersChanged = true;
2038 }
2039
2040 return layersChanged;
2041}
2042
2043// Return true if the layer changed.
2044bool RenderLayerBacking::updateDescendantClippingLayer(bool needsDescendantClip)
2045{
2046 bool layersChanged = false;
2047
2048 if (needsDescendantClip) {
2049 if (!m_childContainmentLayer && !m_isFrameLayerWithTiledBacking) {
2050 m_childContainmentLayer = createGraphicsLayer("child clipping"_s);
2051 m_childContainmentLayer->setMasksToBounds(true);
2052 layersChanged = true;
2053 }
2054 } else if (hasClippingLayer()) {
2055 willDestroyLayer(m_childContainmentLayer.get());
2056 GraphicsLayer::unparentAndClear(m_childContainmentLayer);
2057 layersChanged = true;
2058 }
2059
2060 return layersChanged;
2061}
2062
2063bool RenderLayerBacking::needsRepaintOnCompositedScroll() const
2064{
2065 if (!hasScrollingLayer())
2066 return false;
2067
2068 if (renderer().style().hasAnyLocalBackground())
2069 return true;
2070
2071 if (auto scrollingCoordinator = m_owningLayer.page().scrollingCoordinator())
2072 return scrollingCoordinator->hasSynchronousScrollingReasons(m_scrollingNodeID);
2073
2074 return false;
2075}
2076
2077void RenderLayerBacking::setBackgroundLayerPaintsFixedRootBackground(bool backgroundLayerPaintsFixedRootBackground)
2078{
2079 if (backgroundLayerPaintsFixedRootBackground == m_backgroundLayerPaintsFixedRootBackground)
2080 return;
2081
2082 m_backgroundLayerPaintsFixedRootBackground = backgroundLayerPaintsFixedRootBackground;
2083
2084 if (m_backgroundLayerPaintsFixedRootBackground) {
2085 ASSERT(m_isFrameLayerWithTiledBacking);
2086 renderer().view().frameView().removeSlowRepaintObject(*renderer().view().rendererForRootBackground());
2087 }
2088}
2089
2090void RenderLayerBacking::setRequiresBackgroundLayer(bool requiresBackgroundLayer)
2091{
2092 if (requiresBackgroundLayer == m_requiresBackgroundLayer)
2093 return;
2094
2095 m_requiresBackgroundLayer = requiresBackgroundLayer;
2096 m_owningLayer.setNeedsCompositingConfigurationUpdate();
2097}
2098
2099bool RenderLayerBacking::requiresLayerForScrollbar(Scrollbar* scrollbar) const
2100{
2101 return scrollbar && (scrollbar->isOverlayScrollbar()
2102#if !PLATFORM(IOS_FAMILY) // FIXME: This should be an #if ENABLE(): webkit.org/b/210460
2103 || renderer().settings().asyncOverflowScrollingEnabled()
2104#endif
2105 );
2106}
2107
2108bool RenderLayerBacking::requiresHorizontalScrollbarLayer() const
2109{
2110 if (auto* scrollableArea = m_owningLayer.scrollableArea())
2111 return requiresLayerForScrollbar(scrollableArea->horizontalScrollbar());
2112 return false;
2113}
2114
2115bool RenderLayerBacking::requiresVerticalScrollbarLayer() const
2116{
2117 if (auto* scrollableArea = m_owningLayer.scrollableArea())
2118 return requiresLayerForScrollbar(scrollableArea->verticalScrollbar());
2119 return false;
2120}
2121
2122bool RenderLayerBacking::requiresScrollCornerLayer() const
2123{
2124 if (!is<RenderBox>(m_owningLayer.renderer()))
2125 return false;
2126
2127 auto* scrollableArea = m_owningLayer.scrollableArea();
2128 if (!scrollableArea)
2129 return false;
2130
2131 auto cornerRect = scrollableArea->overflowControlsRects().scrollCornerOrResizerRect();
2132 if (cornerRect.isEmpty())
2133 return false;
2134
2135 auto verticalScrollbar = scrollableArea->verticalScrollbar();
2136 auto scrollbar = verticalScrollbar ? verticalScrollbar : scrollableArea->horizontalScrollbar();
2137 return requiresLayerForScrollbar(scrollbar);
2138}
2139
2140bool RenderLayerBacking::updateOverflowControlsLayers(bool needsHorizontalScrollbarLayer, bool needsVerticalScrollbarLayer, bool needsScrollCornerLayer)
2141{
2142 auto createOrDestroyLayer = [&](RefPtr<GraphicsLayer>& layer, bool needLayer, bool drawsContent, ASCIILiteral layerName) {
2143 if (needLayer == !!layer)
2144 return false;
2145
2146 if (needLayer) {
2147 layer = createGraphicsLayer(layerName);
2148 if (drawsContent) {
2149 layer->setAllowsBackingStoreDetaching(false);
2150 layer->setAllowsTiling(false);
2151 } else {
2152 layer->setPaintingPhase({ });
2153 layer->setDrawsContent(false);
2154 }
2155 } else {
2156 willDestroyLayer(layer.get());
2157 GraphicsLayer::unparentAndClear(layer);
2158 }
2159 return true;
2160 };
2161
2162 bool layersChanged = createOrDestroyLayer(m_overflowControlsContainer, needsHorizontalScrollbarLayer || needsVerticalScrollbarLayer || needsScrollCornerLayer, false, "overflow controls container"_s);
2163
2164 bool horizontalScrollbarLayerChanged = createOrDestroyLayer(m_layerForHorizontalScrollbar, needsHorizontalScrollbarLayer, true, "horizontal scrollbar"_s);
2165 layersChanged |= horizontalScrollbarLayerChanged;
2166
2167 bool verticalScrollbarLayerChanged = createOrDestroyLayer(m_layerForVerticalScrollbar, needsVerticalScrollbarLayer, true, "vertical scrollbar"_s);
2168 layersChanged |= verticalScrollbarLayerChanged;
2169
2170 layersChanged |= createOrDestroyLayer(m_layerForScrollCorner, needsScrollCornerLayer, true, "scroll corner"_s);
2171
2172 if (auto* scrollingCoordinator = m_owningLayer.page().scrollingCoordinator()) {
2173 if (auto* scrollableArea = m_owningLayer.scrollableArea()) {
2174 if (horizontalScrollbarLayerChanged)
2175 scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(*scrollableArea, ScrollbarOrientation::Horizontal);
2176 if (verticalScrollbarLayerChanged)
2177 scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(*scrollableArea, ScrollbarOrientation::Vertical);
2178 }
2179 }
2180
2181 return layersChanged;
2182}
2183
2184void RenderLayerBacking::positionOverflowControlsLayers()
2185{
2186 auto* scrollableArea = m_owningLayer.scrollableArea();
2187 if (!scrollableArea || !scrollableArea->hasScrollbars())
2188 return;
2189 // FIXME: Should do device-pixel snapping.
2190 auto box = renderBox();
2191 auto borderBox = snappedIntRect(box->borderBoxRect());
2192
2193 // m_overflowControlsContainer is positioned using the paddingBoxRectIncludingScrollbar.
2194 auto paddingBox = snappedIntRect(box->paddingBoxRectIncludingScrollbar());
2195 auto paddingBoxInset = paddingBox.location() - borderBox.location();
2196
2197 auto positionScrollbarLayer = [](GraphicsLayer& layer, const IntRect& scrollbarRect, IntSize paddingBoxInset) {
2198 layer.setPosition(scrollbarRect.location() - paddingBoxInset);
2199 layer.setSize(scrollbarRect.size());
2200 if (layer.usesContentsLayer()) {
2201 IntRect barRect = IntRect(IntPoint(), scrollbarRect.size());
2202 layer.setContentsRect(barRect);
2203 layer.setContentsClippingRect(FloatRoundedRect(barRect));
2204 }
2205 };
2206
2207 // These rects are relative to the borderBoxRect.
2208 auto rects = scrollableArea->overflowControlsRects();
2209 if (auto* layer = layerForHorizontalScrollbar()) {
2210 positionScrollbarLayer(*layer, rects.horizontalScrollbar, paddingBoxInset);
2211 layer->setDrawsContent(scrollableArea->horizontalScrollbar() && !layer->usesContentsLayer());
2212 }
2213
2214 if (auto* layer = layerForVerticalScrollbar()) {
2215 positionScrollbarLayer(*layer, rects.verticalScrollbar, paddingBoxInset);
2216 layer->setDrawsContent(scrollableArea->verticalScrollbar() && !layer->usesContentsLayer());
2217 }
2218
2219 if (auto* layer = layerForScrollCorner()) {
2220 auto cornerRect = rects.scrollCornerOrResizerRect();
2221 layer->setPosition(cornerRect.location() - paddingBoxInset);
2222 layer->setSize(cornerRect.size());
2223 layer->setDrawsContent(!cornerRect.isEmpty());
2224 }
2225}
2226
2227bool RenderLayerBacking::updateForegroundLayer(bool needsForegroundLayer)
2228{
2229 bool layerChanged = false;
2230 if (needsForegroundLayer) {
2231 if (!m_foregroundLayer) {
2232 String layerName = m_owningLayer.name() + " (foreground)";
2233 m_foregroundLayer = createGraphicsLayer(layerName);
2234 m_foregroundLayer->setDrawsContent(true);
2235 layerChanged = true;
2236 }
2237 } else if (m_foregroundLayer) {
2238 willDestroyLayer(m_foregroundLayer.get());
2239 GraphicsLayer::unparentAndClear(m_foregroundLayer);
2240 layerChanged = true;
2241 }
2242
2243 return layerChanged;
2244}
2245
2246bool RenderLayerBacking::updateBackgroundLayer(bool needsBackgroundLayer)
2247{
2248 bool layerChanged = false;
2249 if (needsBackgroundLayer) {
2250 if (!m_backgroundLayer) {
2251 String layerName = m_owningLayer.name() + " (background)";
2252 m_backgroundLayer = createGraphicsLayer(layerName);
2253 m_backgroundLayer->setDrawsContent(true);
2254 m_backgroundLayer->setAnchorPoint(FloatPoint3D());
2255 layerChanged = true;
2256 }
2257
2258 if (!m_contentsContainmentLayer) {
2259 String layerName = m_owningLayer.name() + " (contents containment)";
2260 m_contentsContainmentLayer = createGraphicsLayer(layerName);
2261 m_contentsContainmentLayer->setAppliesPageScale(true);
2262 m_graphicsLayer->setAppliesPageScale(false);
2263 layerChanged = true;
2264 }
2265 } else {
2266 if (m_backgroundLayer) {
2267 willDestroyLayer(m_backgroundLayer.get());
2268 GraphicsLayer::unparentAndClear(m_backgroundLayer);
2269 layerChanged = true;
2270 }
2271 if (m_contentsContainmentLayer) {
2272 willDestroyLayer(m_contentsContainmentLayer.get());
2273 GraphicsLayer::unparentAndClear(m_contentsContainmentLayer);
2274 layerChanged = true;
2275 m_graphicsLayer->setAppliesPageScale(true);
2276 }
2277 }
2278
2279 return layerChanged;
2280}
2281
2282// Masking layer is used for masks or clip-path.
2283bool RenderLayerBacking::updateMaskingLayer(bool hasMask, bool hasClipPath)
2284{
2285 bool layerChanged = false;
2286 if (hasMask || hasClipPath) {
2287 OptionSet<GraphicsLayerPaintingPhase> maskPhases;
2288 if (hasMask)
2289 maskPhases = GraphicsLayerPaintingPhase::Mask;
2290
2291 if (hasClipPath) {
2292 // If we have a mask, we need to paint the combined clip-path and mask into the mask layer.
2293 if (hasMask || renderer().style().clipPath()->type() == PathOperation::Reference || !GraphicsLayer::supportsLayerType(GraphicsLayer::Type::Shape))
2294 maskPhases.add(GraphicsLayerPaintingPhase::ClipPath);
2295 }
2296
2297 bool paintsContent = !maskPhases.isEmpty();
2298 GraphicsLayer::Type requiredLayerType = paintsContent ? GraphicsLayer::Type::Normal : GraphicsLayer::Type::Shape;
2299 if (m_maskLayer && m_maskLayer->type() != requiredLayerType) {
2300 m_graphicsLayer->setMaskLayer(nullptr);
2301 willDestroyLayer(m_maskLayer.get());
2302 GraphicsLayer::clear(m_maskLayer);
2303 }
2304
2305 if (!m_maskLayer) {
2306 m_maskLayer = createGraphicsLayer("mask"_s, requiredLayerType);
2307 layerChanged = true;
2308 m_graphicsLayer->setMaskLayer(m_maskLayer.copyRef());
2309 // We need a geometry update to size the new mask layer.
2310 m_owningLayer.setNeedsCompositingGeometryUpdate();
2311 }
2312 m_maskLayer->setDrawsContent(paintsContent);
2313 m_maskLayer->setPaintingPhase(maskPhases);
2314 } else if (m_maskLayer) {
2315 m_graphicsLayer->setMaskLayer(nullptr);
2316 willDestroyLayer(m_maskLayer.get());
2317 GraphicsLayer::clear(m_maskLayer);
2318 layerChanged = true;
2319 }
2320
2321 return layerChanged;
2322}
2323
2324void RenderLayerBacking::updateChildClippingStrategy(bool needsDescendantsClippingLayer)
2325{
2326 auto needsClipMaskLayer = [&] {
2327 return needsDescendantsClippingLayer && !GraphicsLayer::supportsRoundedClip() && is<RenderBox>(renderer()) && (renderer().style().hasBorderRadius() || renderer().style().clipPath());
2328 };
2329
2330 auto* clippingLayer = this->clippingLayer();
2331 if (needsClipMaskLayer()) {
2332 m_childClippingMaskLayer = createGraphicsLayer("child clipping mask"_s);
2333 m_childClippingMaskLayer->setDrawsContent(true);
2334 m_childClippingMaskLayer->setPaintingPhase({ GraphicsLayerPaintingPhase::ChildClippingMask });
2335 if (clippingLayer)
2336 clippingLayer->setMaskLayer(m_childClippingMaskLayer.copyRef());
2337 } else if (m_childClippingMaskLayer) {
2338 if (clippingLayer)
2339 clippingLayer->setMaskLayer(nullptr);
2340 GraphicsLayer::clear(m_childClippingMaskLayer);
2341 }
2342}
2343
2344bool RenderLayerBacking::updateScrollingLayers(bool needsScrollingLayers)
2345{
2346 if (needsScrollingLayers == !!m_scrollContainerLayer)
2347 return false;
2348
2349 if (!m_scrollContainerLayer) {
2350 // Outer layer which corresponds with the scroll view. This never paints content.
2351 m_scrollContainerLayer = createGraphicsLayer("scroll container"_s, GraphicsLayer::Type::ScrollContainer);
2352 m_scrollContainerLayer->setPaintingPhase({ });
2353 m_scrollContainerLayer->setDrawsContent(false);
2354 m_scrollContainerLayer->setMasksToBounds(true);
2355
2356 // Inner layer which renders the content that scrolls.
2357 m_scrolledContentsLayer = createGraphicsLayer("scrolled contents"_s, GraphicsLayer::Type::ScrolledContents);
2358 m_scrolledContentsLayer->setDrawsContent(true);
2359 m_scrolledContentsLayer->setAnchorPoint({ });
2360 m_scrollContainerLayer->addChild(*m_scrolledContentsLayer);
2361 } else {
2362 compositor().willRemoveScrollingLayerWithBacking(m_owningLayer, *this);
2363
2364 willDestroyLayer(m_scrollContainerLayer.get());
2365 willDestroyLayer(m_scrolledContentsLayer.get());
2366
2367 GraphicsLayer::unparentAndClear(m_scrollContainerLayer);
2368 GraphicsLayer::unparentAndClear(m_scrolledContentsLayer);
2369 }
2370
2371 if (m_scrollContainerLayer)
2372 compositor().didAddScrollingLayer(m_owningLayer);
2373
2374 return true;
2375}
2376
2377void RenderLayerBacking::detachFromScrollingCoordinator(OptionSet<ScrollCoordinationRole> roles)
2378{
2379 if (!m_scrollingNodeID && !m_ancestorClippingStack && !m_frameHostingNodeID && !m_viewportConstrainedNodeID && !m_positioningNodeID)
2380 return;
2381
2382 auto* scrollingCoordinator = m_owningLayer.page().scrollingCoordinator();
2383 if (!scrollingCoordinator)
2384 return;
2385
2386 if (roles.contains(ScrollCoordinationRole::Scrolling) && m_scrollingNodeID) {
2387 LOG_WITH_STREAM(Compositing, stream << "Detaching Scrolling node " << m_scrollingNodeID);
2388 scrollingCoordinator->unparentChildrenAndDestroyNode(m_scrollingNodeID);
2389 m_scrollingNodeID = 0;
2390
2391#if ENABLE(SCROLLING_THREAD)
2392 if (m_scrollContainerLayer)
2393 m_scrollContainerLayer->setScrollingNodeID(0);
2394 if (m_layerForHorizontalScrollbar)
2395 m_layerForHorizontalScrollbar->setScrollingNodeID(0);
2396 if (m_layerForVerticalScrollbar)
2397 m_layerForVerticalScrollbar->setScrollingNodeID(0);
2398 if (m_layerForScrollCorner)
2399 m_layerForScrollCorner->setScrollingNodeID(0);
2400#endif
2401 }
2402
2403 if (roles.contains(ScrollCoordinationRole::ScrollingProxy) && m_ancestorClippingStack) {
2404 m_ancestorClippingStack->detachFromScrollingCoordinator(*scrollingCoordinator);
2405 LOG_WITH_STREAM(Compositing, stream << "Detaching nodes in ancestor clipping stack");
2406 }
2407
2408 if (roles.contains(ScrollCoordinationRole::FrameHosting) && m_frameHostingNodeID) {
2409 LOG_WITH_STREAM(Compositing, stream << "Detaching FrameHosting node " << m_frameHostingNodeID);
2410 scrollingCoordinator->unparentChildrenAndDestroyNode(m_frameHostingNodeID);
2411 m_frameHostingNodeID = 0;
2412 }
2413
2414 if (roles.contains(ScrollCoordinationRole::ViewportConstrained) && m_viewportConstrainedNodeID) {
2415 LOG_WITH_STREAM(Compositing, stream << "Detaching ViewportConstrained node " << m_viewportConstrainedNodeID);
2416 scrollingCoordinator->unparentChildrenAndDestroyNode(m_viewportConstrainedNodeID);
2417 m_viewportConstrainedNodeID = 0;
2418 }
2419
2420 if (roles.contains(ScrollCoordinationRole::Positioning) && m_positioningNodeID) {
2421 LOG_WITH_STREAM(Compositing, stream << "Detaching Positioned node " << m_positioningNodeID);
2422 scrollingCoordinator->unparentChildrenAndDestroyNode(m_positioningNodeID);
2423 m_positioningNodeID = 0;
2424#if ENABLE(SCROLLING_THREAD)
2425 m_graphicsLayer->setScrollingNodeID(0);
2426#endif
2427 }
2428}
2429
2430void RenderLayerBacking::setScrollingNodeIDForRole(ScrollingNodeID nodeID, ScrollCoordinationRole role)
2431{
2432 switch (role) {
2433 case ScrollCoordinationRole::Scrolling:
2434 m_scrollingNodeID = nodeID;
2435#if ENABLE(SCROLLING_THREAD)
2436 if (m_scrollContainerLayer)
2437 m_scrollContainerLayer->setScrollingNodeID(m_scrollingNodeID);
2438
2439 if (m_layerForHorizontalScrollbar)
2440 m_layerForHorizontalScrollbar->setScrollingNodeID(m_scrollingNodeID);
2441 if (m_layerForVerticalScrollbar)
2442 m_layerForVerticalScrollbar->setScrollingNodeID(m_scrollingNodeID);
2443 if (m_layerForScrollCorner)
2444 m_layerForScrollCorner->setScrollingNodeID(m_scrollingNodeID);
2445#endif
2446 break;
2447 case ScrollCoordinationRole::ScrollingProxy:
2448 // These nodeIDs are stored in m_ancestorClippingStack.
2449 ASSERT_NOT_REACHED();
2450 break;
2451 case ScrollCoordinationRole::FrameHosting:
2452 m_frameHostingNodeID = nodeID;
2453 break;
2454 case ScrollCoordinationRole::ViewportConstrained:
2455 m_viewportConstrainedNodeID = nodeID;
2456 break;
2457 case ScrollCoordinationRole::Positioning:
2458 m_positioningNodeID = nodeID;
2459#if ENABLE(SCROLLING_THREAD)
2460 m_graphicsLayer->setScrollingNodeID(m_positioningNodeID);
2461#endif
2462 break;
2463 }
2464}
2465
2466ScrollingNodeID RenderLayerBacking::scrollingNodeIDForChildren() const
2467{
2468 if (m_frameHostingNodeID)
2469 return m_frameHostingNodeID;
2470
2471 if (m_scrollingNodeID)
2472 return m_scrollingNodeID;
2473
2474 if (m_viewportConstrainedNodeID)
2475 return m_viewportConstrainedNodeID;
2476
2477 if (m_ancestorClippingStack) {
2478 if (auto lastOverflowScrollProxyNode = m_ancestorClippingStack->lastOverflowScrollProxyNodeID())
2479 return lastOverflowScrollProxyNode;
2480 }
2481
2482 return m_positioningNodeID;
2483}
2484
2485float RenderLayerBacking::compositingOpacity(float rendererOpacity) const
2486{
2487 float finalOpacity = rendererOpacity;
2488
2489 for (auto* curr = m_owningLayer.stackingContext(); curr; curr = curr->stackingContext()) {
2490 // If we found a compositing layer, we want to compute opacity
2491 // relative to it. So we can break here.
2492 if (curr->isComposited())
2493 break;
2494
2495 finalOpacity *= curr->renderer().opacity();
2496 }
2497
2498 return finalOpacity;
2499}
2500
2501// FIXME: Code is duplicated in RenderLayer. Also, we should probably not consider filters a box decoration here.
2502static inline bool hasVisibleBoxDecorations(const RenderStyle& style)
2503{
2504 return style.hasVisibleBorder() || style.hasBorderRadius() || style.hasOutline() || style.hasEffectiveAppearance() || style.boxShadow() || style.hasFilter();
2505}
2506
2507static bool canDirectlyCompositeBackgroundBackgroundImage(const RenderStyle& style)
2508{
2509 if (!GraphicsLayer::supportsContentsTiling())
2510 return false;
2511
2512 auto& fillLayer = style.backgroundLayers();
2513 if (fillLayer.next())
2514 return false;
2515
2516 if (!fillLayer.imagesAreLoaded())
2517 return false;
2518
2519 if (fillLayer.attachment() != FillAttachment::ScrollBackground)
2520 return false;
2521
2522 // FIXME: Allow color+image compositing when it makes sense.
2523 // For now bailing out.
2524 if (style.visitedDependentColorWithColorFilter(CSSPropertyBackgroundColor).isVisible())
2525 return false;
2526
2527 // FIXME: support gradients with isGeneratedImage.
2528 auto* styleImage = fillLayer.image();
2529 if (!styleImage->hasCachedImage())
2530 return false;
2531
2532 auto* image = styleImage->cachedImage()->image();
2533 if (!image->isBitmapImage())
2534 return false;
2535
2536 return true;
2537}
2538
2539static bool hasPaintedBoxDecorationsOrBackgroundImage(const RenderStyle& style)
2540{
2541 if (hasVisibleBoxDecorations(style))
2542 return true;
2543
2544 if (!style.hasBackgroundImage())
2545 return false;
2546
2547 return !canDirectlyCompositeBackgroundBackgroundImage(style);
2548}
2549
2550static inline bool hasPerspectiveOrPreserves3D(const RenderStyle& style)
2551{
2552 return style.hasPerspective() || style.preserves3D();
2553}
2554
2555Color RenderLayerBacking::rendererBackgroundColor() const
2556{
2557 RenderElement* backgroundRenderer = nullptr;
2558 if (renderer().isDocumentElementRenderer())
2559 backgroundRenderer = renderer().view().rendererForRootBackground();
2560
2561 if (!backgroundRenderer)
2562 backgroundRenderer = &renderer();
2563
2564 return backgroundRenderer->style().visitedDependentColorWithColorFilter(CSSPropertyBackgroundColor);
2565}
2566
2567void RenderLayerBacking::updateDirectlyCompositedBackgroundColor(PaintedContentsInfo& contentsInfo, bool& didUpdateContentsRect)
2568{
2569 if (m_backgroundLayer && !m_backgroundLayerPaintsFixedRootBackground && !contentsInfo.paintsBoxDecorations()) {
2570 m_graphicsLayer->setContentsToSolidColor(Color());
2571 m_backgroundLayer->setContentsToSolidColor(rendererBackgroundColor());
2572
2573 FloatRect contentsRect = backgroundBoxForSimpleContainerPainting();
2574 // NOTE: This is currently only used by RenderFullScreen, which we want to be
2575 // big enough to hide overflow areas of the root.
2576 contentsRect.inflate(contentsRect.size());
2577 m_backgroundLayer->setContentsRect(contentsRect);
2578 m_backgroundLayer->setContentsClippingRect(FloatRoundedRect(contentsRect));
2579 return;
2580 }
2581
2582 if (!contentsInfo.isSimpleContainer() || (is<RenderBox>(renderer()) && !downcast<RenderBox>(renderer()).paintsOwnBackground())) {
2583 m_graphicsLayer->setContentsToSolidColor(Color());
2584 return;
2585 }
2586
2587 Color backgroundColor = rendererBackgroundColor();
2588
2589 // An unset (invalid) color will remove the solid color.
2590 m_graphicsLayer->setContentsToSolidColor(backgroundColor);
2591 FloatRect contentsRect = backgroundBoxForSimpleContainerPainting();
2592 m_graphicsLayer->setContentsRect(contentsRect);
2593 m_graphicsLayer->setContentsClippingRect(FloatRoundedRect(contentsRect));
2594 didUpdateContentsRect = true;
2595}
2596
2597void RenderLayerBacking::updateDirectlyCompositedBackgroundImage(PaintedContentsInfo& contentsInfo, bool& didUpdateContentsRect)
2598{
2599 if (!GraphicsLayer::supportsContentsTiling())
2600 return;
2601
2602 if (contentsInfo.isDirectlyCompositedImage())
2603 return;
2604
2605 auto& style = renderer().style();
2606 if (!contentsInfo.isSimpleContainer() || !style.hasBackgroundImage()) {
2607 m_graphicsLayer->setContentsToImage(nullptr);
2608 return;
2609 }
2610
2611 auto destRect = backgroundBoxForSimpleContainerPainting();
2612 FloatSize phase;
2613 FloatSize tileSize;
2614 // FIXME: Absolute paint location is required here.
2615 downcast<RenderBox>(renderer()).getGeometryForBackgroundImage(&renderer(), LayoutPoint(), destRect, phase, tileSize);
2616
2617 m_graphicsLayer->setContentsTileSize(tileSize);
2618 m_graphicsLayer->setContentsTilePhase(phase);
2619 m_graphicsLayer->setContentsRect(destRect);
2620 m_graphicsLayer->setContentsClippingRect(FloatRoundedRect(destRect));
2621 m_graphicsLayer->setContentsToImage(style.backgroundLayers().image()->cachedImage()->image());
2622
2623 didUpdateContentsRect = true;
2624}
2625
2626void RenderLayerBacking::updateRootLayerConfiguration()
2627{
2628 if (!m_isFrameLayerWithTiledBacking)
2629 return;
2630
2631 Color backgroundColor;
2632 bool viewIsTransparent = compositor().viewHasTransparentBackground(&backgroundColor);
2633
2634 if (m_backgroundLayerPaintsFixedRootBackground && m_backgroundLayer) {
2635 if (m_isMainFrameRenderViewLayer) {
2636 m_backgroundLayer->setBackgroundColor(backgroundColor);
2637 m_backgroundLayer->setContentsOpaque(!viewIsTransparent);
2638 }
2639
2640 m_graphicsLayer->setBackgroundColor(Color());
2641 m_graphicsLayer->setContentsOpaque(false);
2642 } else if (m_isMainFrameRenderViewLayer) {
2643 m_graphicsLayer->setBackgroundColor(backgroundColor);
2644 m_graphicsLayer->setContentsOpaque(!viewIsTransparent);
2645 }
2646}
2647
2648void RenderLayerBacking::updatePaintingPhases()
2649{
2650 // Phases for m_childClippingMaskLayer and m_maskLayer are set elsewhere.
2651 OptionSet<GraphicsLayerPaintingPhase> primaryLayerPhases = { GraphicsLayerPaintingPhase::Background, GraphicsLayerPaintingPhase::Foreground };
2652
2653 if (m_foregroundLayer) {
2654 OptionSet<GraphicsLayerPaintingPhase> foregroundLayerPhases { GraphicsLayerPaintingPhase::Foreground };
2655
2656 if (m_scrolledContentsLayer)
2657 foregroundLayerPhases.add(GraphicsLayerPaintingPhase::OverflowContents);
2658
2659 m_foregroundLayer->setPaintingPhase(foregroundLayerPhases);
2660 primaryLayerPhases.remove(GraphicsLayerPaintingPhase::Foreground);
2661 }
2662
2663 if (m_backgroundLayer) {
2664 m_backgroundLayer->setPaintingPhase(GraphicsLayerPaintingPhase::Background);
2665 primaryLayerPhases.remove(GraphicsLayerPaintingPhase::Background);
2666 }
2667
2668 if (m_scrolledContentsLayer) {
2669 OptionSet<GraphicsLayerPaintingPhase> scrolledContentLayerPhases = { GraphicsLayerPaintingPhase::OverflowContents, GraphicsLayerPaintingPhase::CompositedScroll };
2670 if (!m_foregroundLayer)
2671 scrolledContentLayerPhases.add(GraphicsLayerPaintingPhase::Foreground);
2672 m_scrolledContentsLayer->setPaintingPhase(scrolledContentLayerPhases);
2673
2674 primaryLayerPhases.remove(GraphicsLayerPaintingPhase::Foreground);
2675 primaryLayerPhases.add(GraphicsLayerPaintingPhase::CompositedScroll);
2676 }
2677
2678 m_graphicsLayer->setPaintingPhase(primaryLayerPhases);
2679}
2680
2681static bool supportsDirectlyCompositedBoxDecorations(const RenderLayerModelObject& renderer)
2682{
2683 if (!GraphicsLayer::supportsBackgroundColorContent())
2684 return false;
2685
2686 const RenderStyle& style = renderer.style();
2687 if (renderer.hasClip())
2688 return false;
2689
2690 if (hasPaintedBoxDecorationsOrBackgroundImage(style))
2691 return false;
2692
2693 // FIXME: We can't create a directly composited background if this
2694 // layer will have children that intersect with the background layer.
2695 // A better solution might be to introduce a flattening layer if
2696 // we do direct box decoration composition.
2697 // https://bugs.webkit.org/show_bug.cgi?id=119461
2698 if (hasPerspectiveOrPreserves3D(style))
2699 return false;
2700
2701 return true;
2702}
2703
2704bool RenderLayerBacking::paintsBoxDecorations() const
2705{
2706 if (!m_owningLayer.hasVisibleBoxDecorations())
2707 return false;
2708
2709 return !supportsDirectlyCompositedBoxDecorations(renderer());
2710}
2711
2712bool RenderLayerBacking::paintsContent(RenderLayer::PaintedContentRequest& request) const
2713{
2714 m_owningLayer.updateDescendantDependentFlags();
2715
2716 bool paintsContent = false;
2717
2718 if (m_owningLayer.hasVisibleContent() && m_owningLayer.hasNonEmptyChildRenderers(request))
2719 paintsContent = true;
2720
2721 if (request.isSatisfied())
2722 return paintsContent;
2723
2724 if (isPaintDestinationForDescendantLayers(request))
2725 paintsContent = true;
2726
2727 if (request.isSatisfied())
2728 return paintsContent;
2729
2730 if (request.hasPaintedContent == RequestState::Unknown)
2731 request.hasPaintedContent = RequestState::False;
2732
2733 if (request.hasSubpixelAntialiasedText == RequestState::Unknown)
2734 request.hasSubpixelAntialiasedText = RequestState::False;
2735
2736 return paintsContent;
2737}
2738
2739static bool isCompositedPlugin(RenderObject& renderer)
2740{
2741 return is<RenderEmbeddedObject>(renderer) && downcast<RenderEmbeddedObject>(renderer).allowsAcceleratedCompositing();
2742}
2743
2744// A "simple container layer" is a RenderLayer which has no visible content to render.
2745// It may have no children, or all its children may be themselves composited.
2746// This is a useful optimization, because it allows us to avoid allocating backing store.
2747bool RenderLayerBacking::isSimpleContainerCompositingLayer(PaintedContentsInfo& contentsInfo) const
2748{
2749 if (m_owningLayer.isRenderViewLayer())
2750 return false;
2751
2752 if (hasBackingSharingLayers())
2753 return false;
2754
2755 if (renderer().isRenderReplaced() && !isCompositedPlugin(renderer()))
2756 return false;
2757
2758 if (renderer().isTextControl())
2759 return false;
2760
2761 if (contentsInfo.paintsBoxDecorations() || contentsInfo.paintsContent())
2762 return false;
2763
2764 if (renderer().style().backgroundClip() == FillBox::Text)
2765 return false;
2766
2767 if (renderer().isDocumentElementRenderer() && m_owningLayer.isolatesCompositedBlending())
2768 return false;
2769
2770 return true;
2771}
2772
2773// Returning true stops the traversal.
2774enum class LayerTraversal { Continue, Stop };
2775
2776static LayerTraversal traverseVisibleNonCompositedDescendantLayers(RenderLayer& parent, const Function<LayerTraversal(const RenderLayer&)>& layerFunc)
2777{
2778 // FIXME: We shouldn't be called with a stale z-order lists. See bug 85512.
2779 parent.updateLayerListsIfNeeded();
2780
2781#if ASSERT_ENABLED
2782 LayerListMutationDetector mutationChecker(parent);
2783#endif
2784
2785 for (auto* childLayer : parent.normalFlowLayers()) {
2786 if (compositedWithOwnBackingStore(*childLayer))
2787 continue;
2788
2789 if (layerFunc(*childLayer) == LayerTraversal::Stop)
2790 return LayerTraversal::Stop;
2791
2792 if (traverseVisibleNonCompositedDescendantLayers(*childLayer, layerFunc) == LayerTraversal::Stop)
2793 return LayerTraversal::Stop;
2794 }
2795
2796 if (parent.isStackingContext() && !parent.hasVisibleDescendant())
2797 return LayerTraversal::Continue;
2798
2799 // Use the m_hasCompositingDescendant bit to optimize?
2800 for (auto* childLayer : parent.negativeZOrderLayers()) {
2801 if (compositedWithOwnBackingStore(*childLayer))
2802 continue;
2803
2804 if (layerFunc(*childLayer) == LayerTraversal::Stop)
2805 return LayerTraversal::Stop;
2806
2807 if (traverseVisibleNonCompositedDescendantLayers(*childLayer, layerFunc) == LayerTraversal::Stop)
2808 return LayerTraversal::Stop;
2809 }
2810
2811 for (auto* childLayer : parent.positiveZOrderLayers()) {
2812 if (compositedWithOwnBackingStore(*childLayer))
2813 continue;
2814
2815 if (layerFunc(*childLayer) == LayerTraversal::Stop)
2816 return LayerTraversal::Stop;
2817
2818 if (traverseVisibleNonCompositedDescendantLayers(*childLayer, layerFunc) == LayerTraversal::Stop)
2819 return LayerTraversal::Stop;
2820 }
2821
2822 return LayerTraversal::Continue;
2823}
2824
2825static std::optional<bool> intersectsWithAncestor(const RenderLayer& child, const RenderLayer& ancestor, const LayoutRect& ancestorCompositedBounds)
2826{
2827 // If any layers between child and ancestor are transformed, then adjusting the offset is
2828 // insufficient to convert coordinates into ancestor's coordinate space.
2829 for (auto* layer = &child; layer != &ancestor; layer = layer->parent()) {
2830 if (!layer->canUseOffsetFromAncestor())
2831 return std::nullopt;
2832 }
2833
2834 auto overlap = child.boundingBox(&ancestor, child.offsetFromAncestor(&ancestor), RenderLayer::UseFragmentBoxesExcludingCompositing);
2835 return overlap.intersects(ancestorCompositedBounds);
2836}
2837
2838// Conservative test for having no rendered children.
2839bool RenderLayerBacking::isPaintDestinationForDescendantLayers(RenderLayer::PaintedContentRequest& request) const
2840{
2841 bool hasPaintingDescendant = false;
2842 traverseVisibleNonCompositedDescendantLayers(m_owningLayer, [&hasPaintingDescendant, &request, this](const RenderLayer& layer) {
2843 RenderLayer::PaintedContentRequest localRequest;
2844 if (layer.isVisuallyNonEmpty(&localRequest)) {
2845 bool mayIntersect = intersectsWithAncestor(layer, m_owningLayer, compositedBounds()).value_or(true);
2846 if (mayIntersect) {
2847 hasPaintingDescendant = true;
2848 request.setHasPaintedContent();
2849 }
2850 }
2851 return (hasPaintingDescendant && request.isSatisfied()) ? LayerTraversal::Stop : LayerTraversal::Continue;
2852 });
2853
2854 return hasPaintingDescendant;
2855}
2856
2857bool RenderLayerBacking::hasVisibleNonCompositedDescendants() const
2858{
2859 bool hasVisibleDescendant = false;
2860 traverseVisibleNonCompositedDescendantLayers(m_owningLayer, [&hasVisibleDescendant](const RenderLayer& layer) {
2861 hasVisibleDescendant |= layer.hasVisibleContent();
2862 return hasVisibleDescendant ? LayerTraversal::Stop : LayerTraversal::Continue;
2863 });
2864
2865 return hasVisibleDescendant;
2866}
2867
2868bool RenderLayerBacking::containsPaintedContent(PaintedContentsInfo& contentsInfo) const
2869{
2870 if (contentsInfo.isSimpleContainer() || paintsIntoWindow() || paintsIntoCompositedAncestor() || m_artificiallyInflatedBounds || m_owningLayer.isReflection())
2871 return false;
2872
2873 if (contentsInfo.isDirectlyCompositedImage())
2874 return false;
2875
2876 // FIXME: we could optimize cases where the image, video or canvas is known to fill the border box entirely,
2877 // and set background color on the layer in that case, instead of allocating backing store and painting.
2878#if ENABLE(VIDEO)
2879 if (is<RenderVideo>(renderer()) && downcast<RenderVideo>(renderer()).shouldDisplayVideo())
2880 return m_owningLayer.hasVisibleBoxDecorationsOrBackground() || (!(downcast<RenderVideo>(renderer()).supportsAcceleratedRendering()) && m_requiresOwnBackingStore);
2881#endif
2882
2883#if ENABLE(WEBGL) || ENABLE(OFFSCREEN_CANVAS)
2884 if (is<RenderHTMLCanvas>(renderer()) && canvasCompositingStrategy(renderer()) == CanvasAsLayerContents)
2885 return m_owningLayer.hasVisibleBoxDecorationsOrBackground();
2886#endif
2887
2888 return true;
2889}
2890
2891// An image can be directly compositing if it's the sole content of the layer, and has no box decorations
2892// that require painting. Direct compositing saves backing store.
2893bool RenderLayerBacking::isDirectlyCompositedImage() const
2894{
2895 if (!is<RenderImage>(renderer()) || m_owningLayer.hasVisibleBoxDecorationsOrBackground() || m_owningLayer.paintsWithFilters() || renderer().hasClip())
2896 return false;
2897
2898#if ENABLE(VIDEO)
2899 if (is<RenderMedia>(renderer()))
2900 return false;
2901#endif
2902
2903 auto& imageRenderer = downcast<RenderImage>(renderer());
2904 if (auto* cachedImage = imageRenderer.cachedImage()) {
2905 if (!cachedImage->hasImage())
2906 return false;
2907
2908 auto* image = cachedImage->imageForRenderer(&imageRenderer);
2909 if (!is<BitmapImage>(image))
2910 return false;
2911
2912 if (downcast<BitmapImage>(*image).orientationForCurrentFrame() != ImageOrientation::None)
2913 return false;
2914
2915#if (PLATFORM(GTK) || PLATFORM(WPE))
2916 // GTK and WPE ports don't support rounded rect clipping at TextureMapper level, so they cannot
2917 // directly composite images that have border-radius propery. Draw them as non directly composited
2918 // content instead. See https://bugs.webkit.org/show_bug.cgi?id=174157.
2919 if (imageRenderer.style().hasBorderRadius())
2920 return false;
2921#endif
2922
2923 return m_graphicsLayer->shouldDirectlyCompositeImage(image);
2924 }
2925
2926 return false;
2927}
2928
2929bool RenderLayerBacking::isUnscaledBitmapOnly() const
2930{
2931 if (!is<RenderImage>(renderer()) && !is<RenderHTMLCanvas>(renderer()))
2932 return false;
2933
2934 if (m_owningLayer.hasVisibleBoxDecorationsOrBackground())
2935 return false;
2936
2937 auto contents = contentsBox();
2938 if (contents.location() != LayoutPoint(0, 0))
2939 return false;
2940
2941 if (is<RenderImage>(renderer())) {
2942 auto& imageRenderer = downcast<RenderImage>(renderer());
2943 if (auto* cachedImage = imageRenderer.cachedImage()) {
2944 if (!cachedImage->hasImage())
2945 return false;
2946
2947 auto* image = cachedImage->imageForRenderer(&imageRenderer);
2948 if (!is<BitmapImage>(image))
2949 return false;
2950
2951 if (downcast<BitmapImage>(*image).orientationForCurrentFrame() != ImageOrientation::None)
2952 return false;
2953
2954 return contents.size() == image->size();
2955 }
2956 return false;
2957 }
2958
2959 auto& canvasRenderer = downcast<RenderHTMLCanvas>(renderer());
2960 if (snappedIntRect(contents).size() == canvasRenderer.canvasElement().size())
2961 return true;
2962 return false;
2963}
2964
2965void RenderLayerBacking::contentChanged(ContentChangeType changeType)
2966{
2967 PaintedContentsInfo contentsInfo(*this);
2968 if (changeType == ImageChanged) {
2969 if (contentsInfo.isDirectlyCompositedImage()) {
2970 updateImageContents(contentsInfo);
2971 return;
2972 }
2973 if (contentsInfo.isUnscaledBitmapOnly()) {
2974 compositor().scheduleCompositingLayerUpdate();
2975 return;
2976 }
2977 }
2978
2979 if (changeType == VideoChanged) {
2980 compositor().scheduleCompositingLayerUpdate();
2981 return;
2982 }
2983
2984#if ENABLE(MODEL_ELEMENT)
2985 if (changeType == ModelChanged) {
2986 compositor().scheduleCompositingLayerUpdate();
2987 return;
2988 }
2989#endif
2990
2991 if ((changeType == BackgroundImageChanged) && canDirectlyCompositeBackgroundBackgroundImage(renderer().style()))
2992 m_owningLayer.setNeedsCompositingConfigurationUpdate();
2993
2994 if ((changeType == MaskImageChanged) && m_maskLayer)
2995 m_owningLayer.setNeedsCompositingConfigurationUpdate();
2996
2997#if ENABLE(WEBGL) || ENABLE(OFFSCREEN_CANVAS)
2998 if ((changeType == CanvasChanged || changeType == CanvasPixelsChanged) && renderer().isCanvas() && canvasCompositingStrategy(renderer()) == CanvasAsLayerContents) {
2999 if (changeType == CanvasChanged)
3000 compositor().scheduleCompositingLayerUpdate();
3001
3002 m_graphicsLayer->setContentsNeedsDisplay();
3003 return;
3004 }
3005#endif
3006}
3007
3008void RenderLayerBacking::updateImageContents(PaintedContentsInfo& contentsInfo)
3009{
3010 auto& imageRenderer = downcast<RenderImage>(renderer());
3011
3012 auto* cachedImage = imageRenderer.cachedImage();
3013 if (!cachedImage)
3014 return;
3015
3016 auto* image = cachedImage->imageForRenderer(&imageRenderer);
3017 if (!image)
3018 return;
3019
3020 // We have to wait until the image is fully loaded before setting it on the layer.
3021 if (!cachedImage->isLoaded())
3022 return;
3023
3024 updateContentsRects();
3025 m_graphicsLayer->setContentsToImage(image);
3026
3027 updateDrawsContent(contentsInfo);
3028
3029 // Image animation is "lazy", in that it automatically stops unless someone is drawing
3030 // the image. So we have to kick the animation each time; this has the downside that the
3031 // image will keep animating, even if its layer is not visible.
3032 image->startAnimation();
3033}
3034
3035// Return the offset from the top-left of this compositing layer at which the renderer's contents are painted.
3036LayoutSize RenderLayerBacking::contentOffsetInCompositingLayer() const
3037{
3038 return LayoutSize(-m_compositedBounds.x() + m_compositedBoundsOffsetFromGraphicsLayer.width(), -m_compositedBounds.y() + m_compositedBoundsOffsetFromGraphicsLayer.height());
3039}
3040
3041LayoutRect RenderLayerBacking::contentsBox() const
3042{
3043 if (!is<RenderBox>(renderer()))
3044 return LayoutRect();
3045
3046 auto& renderBox = downcast<RenderBox>(renderer());
3047 LayoutRect contentsRect;
3048#if ENABLE(VIDEO)
3049 if (is<RenderVideo>(renderBox))
3050 contentsRect = downcast<RenderVideo>(renderBox).videoBox();
3051 else
3052#endif
3053
3054 if (is<RenderReplaced>(renderBox) && !is<RenderWidget>(renderBox)) {
3055 RenderReplaced& renderReplaced = downcast<RenderReplaced>(renderBox);
3056 contentsRect = renderReplaced.replacedContentRect();
3057 } else
3058 contentsRect = renderBox.contentBoxRect();
3059
3060 contentsRect.move(contentOffsetInCompositingLayer());
3061 return contentsRect;
3062}
3063
3064static LayoutRect backgroundRectForBox(const RenderBox& box)
3065{
3066 switch (box.style().backgroundClip()) {
3067 case FillBox::Border:
3068 return box.borderBoxRect();
3069 case FillBox::Padding:
3070 return box.paddingBoxRect();
3071 case FillBox::Content:
3072 return box.contentBoxRect();
3073 default:
3074 break;
3075 }
3076
3077 ASSERT_NOT_REACHED();
3078 return { };
3079}
3080
3081FloatRect RenderLayerBacking::backgroundBoxForSimpleContainerPainting() const
3082{
3083 if (!is<RenderBox>(renderer()))
3084 return FloatRect();
3085
3086 LayoutRect backgroundBox = backgroundRectForBox(downcast<RenderBox>(renderer()));
3087 backgroundBox.move(contentOffsetInCompositingLayer());
3088 return snapRectToDevicePixels(backgroundBox, deviceScaleFactor());
3089}
3090
3091GraphicsLayer* RenderLayerBacking::parentForSublayers() const
3092{
3093 if (m_scrolledContentsLayer)
3094 return m_scrolledContentsLayer.get();
3095
3096 return m_childContainmentLayer ? m_childContainmentLayer.get() : m_graphicsLayer.get();
3097}
3098
3099GraphicsLayer* RenderLayerBacking::childForSuperlayers() const
3100{
3101 if (m_ancestorClippingStack)
3102 return m_ancestorClippingStack->firstClippingLayer();
3103
3104 if (m_contentsContainmentLayer)
3105 return m_contentsContainmentLayer.get();
3106
3107 return m_graphicsLayer.get();
3108}
3109
3110LayoutSize RenderLayerBacking::offsetRelativeToRendererOriginForDescendantLayers() const
3111{
3112 if (m_scrolledContentsLayer)
3113 return toLayoutSize(scrollContainerLayerBox(downcast<RenderBox>(renderer())).location());
3114
3115 if (hasClippingLayer())
3116 return toLayoutSize(clippingLayerBox(renderer()).location());
3117
3118 return { };
3119}
3120
3121bool RenderLayerBacking::paintsIntoWindow() const
3122{
3123#if USE(COORDINATED_GRAPHICS)
3124 return false;
3125#endif
3126
3127 if (m_isFrameLayerWithTiledBacking)
3128 return false;
3129
3130 if (m_owningLayer.isRenderViewLayer()) {
3131#if PLATFORM(IOS_FAMILY) || USE(COORDINATED_GRAPHICS)
3132 if (compositor().inForcedCompositingMode())
3133 return false;
3134#endif
3135
3136 return compositor().rootLayerAttachment() != RenderLayerCompositor::RootLayerAttachedViaEnclosingFrame;
3137 }
3138
3139 return false;
3140}
3141
3142void RenderLayerBacking::setRequiresOwnBackingStore(bool requiresOwnBacking)
3143{
3144 if (requiresOwnBacking == m_requiresOwnBackingStore)
3145 return;
3146
3147 m_requiresOwnBackingStore = requiresOwnBacking;
3148
3149 // This affects the answer to paintsIntoCompositedAncestor(), which in turn affects
3150 // cached clip rects, so when it changes we have to clear clip rects on descendants.
3151 m_owningLayer.clearClipRectsIncludingDescendants(PaintingClipRects);
3152 m_owningLayer.computeRepaintRectsIncludingDescendants();
3153
3154 compositor().repaintInCompositedAncestor(m_owningLayer, compositedBounds());
3155}
3156
3157void RenderLayerBacking::setContentsNeedDisplay(GraphicsLayer::ShouldClipToLayer shouldClip)
3158{
3159 ASSERT(!paintsIntoCompositedAncestor());
3160
3161 // Use the repaint as a trigger to re-evaluate direct compositing (which is never used on the root layer).
3162 if (!m_owningLayer.isRenderViewLayer())
3163 m_owningLayer.setNeedsCompositingConfigurationUpdate();
3164
3165 m_owningLayer.invalidateEventRegion(RenderLayer::EventRegionInvalidationReason::Paint);
3166
3167 auto& frameView = renderer().view().frameView();
3168 if (m_isMainFrameRenderViewLayer && frameView.isTrackingRepaints())
3169 frameView.addTrackedRepaintRect(owningLayer().absoluteBoundingBoxForPainting());
3170
3171 if (m_graphicsLayer && m_graphicsLayer->drawsContent()) {
3172 // By default, setNeedsDisplay will clip to the size of the GraphicsLayer, which does not include margin tiles.
3173 // So if the TiledBacking has a margin that needs to be invalidated, we need to send in a rect to setNeedsDisplayInRect
3174 // that is large enough to include the margin. TiledBacking::bounds() includes the margin.
3175 auto* tiledBacking = this->tiledBacking();
3176 FloatRect rectToRepaint = tiledBacking ? tiledBacking->bounds() : FloatRect(FloatPoint(0, 0), m_graphicsLayer->size());
3177 m_graphicsLayer->setNeedsDisplayInRect(rectToRepaint, shouldClip);
3178 }
3179
3180 if (m_foregroundLayer && m_foregroundLayer->drawsContent())
3181 m_foregroundLayer->setNeedsDisplay();
3182
3183 if (m_backgroundLayer && m_backgroundLayer->drawsContent())
3184 m_backgroundLayer->setNeedsDisplay();
3185
3186 if (m_maskLayer && m_maskLayer->drawsContent())
3187 m_maskLayer->setNeedsDisplay();
3188
3189 if (m_childClippingMaskLayer && m_childClippingMaskLayer->drawsContent())
3190 m_childClippingMaskLayer->setNeedsDisplay();
3191
3192 if (m_scrolledContentsLayer && m_scrolledContentsLayer->drawsContent())
3193 m_scrolledContentsLayer->setNeedsDisplay();
3194}
3195
3196// r is in the coordinate space of the layer's render object
3197void RenderLayerBacking::setContentsNeedDisplayInRect(const LayoutRect& r, GraphicsLayer::ShouldClipToLayer shouldClip)
3198{
3199 ASSERT(!paintsIntoCompositedAncestor());
3200
3201 // Use the repaint as a trigger to re-evaluate direct compositing (which is never used on the root layer).
3202 if (!m_owningLayer.isRenderViewLayer())
3203 m_owningLayer.setNeedsCompositingConfigurationUpdate();
3204
3205 m_owningLayer.invalidateEventRegion(RenderLayer::EventRegionInvalidationReason::Paint);
3206
3207 FloatRect pixelSnappedRectForPainting = snapRectToDevicePixels(r, deviceScaleFactor());
3208 auto& frameView = renderer().view().frameView();
3209 if (m_isMainFrameRenderViewLayer && frameView.isTrackingRepaints())
3210 frameView.addTrackedRepaintRect(pixelSnappedRectForPainting);
3211
3212 if (m_graphicsLayer && m_graphicsLayer->drawsContent()) {
3213 FloatRect layerDirtyRect = pixelSnappedRectForPainting;
3214 layerDirtyRect.move(-m_graphicsLayer->offsetFromRenderer() - m_subpixelOffsetFromRenderer);
3215 m_graphicsLayer->setNeedsDisplayInRect(layerDirtyRect, shouldClip);
3216 }
3217
3218 if (m_foregroundLayer && m_foregroundLayer->drawsContent()) {
3219 FloatRect layerDirtyRect = pixelSnappedRectForPainting;
3220 layerDirtyRect.move(-m_foregroundLayer->offsetFromRenderer() - m_subpixelOffsetFromRenderer);
3221 m_foregroundLayer->setNeedsDisplayInRect(layerDirtyRect, shouldClip);
3222 }
3223
3224 // FIXME: need to split out repaints for the background.
3225 if (m_backgroundLayer && m_backgroundLayer->drawsContent()) {
3226 FloatRect layerDirtyRect = pixelSnappedRectForPainting;
3227 layerDirtyRect.move(-m_backgroundLayer->offsetFromRenderer() - m_subpixelOffsetFromRenderer);
3228 m_backgroundLayer->setNeedsDisplayInRect(layerDirtyRect, shouldClip);
3229 }
3230
3231 if (m_maskLayer && m_maskLayer->drawsContent()) {
3232 FloatRect layerDirtyRect = pixelSnappedRectForPainting;
3233 layerDirtyRect.move(-m_maskLayer->offsetFromRenderer() - m_subpixelOffsetFromRenderer);
3234 m_maskLayer->setNeedsDisplayInRect(layerDirtyRect, shouldClip);
3235 }
3236
3237 if (m_childClippingMaskLayer && m_childClippingMaskLayer->drawsContent()) {
3238 FloatRect layerDirtyRect = r;
3239 layerDirtyRect.move(-m_childClippingMaskLayer->offsetFromRenderer());
3240 m_childClippingMaskLayer->setNeedsDisplayInRect(layerDirtyRect);
3241 }
3242
3243 if (m_scrolledContentsLayer && m_scrolledContentsLayer->drawsContent()) {
3244 FloatRect layerDirtyRect = pixelSnappedRectForPainting;
3245 ScrollOffset scrollOffset;
3246 if (auto* scrollableArea = m_owningLayer.scrollableArea())
3247 scrollOffset = scrollableArea->scrollOffset();
3248 layerDirtyRect.move(-m_scrolledContentsLayer->offsetFromRenderer() + toLayoutSize(scrollOffset) - m_subpixelOffsetFromRenderer);
3249 m_scrolledContentsLayer->setNeedsDisplayInRect(layerDirtyRect, shouldClip);
3250 }
3251}
3252
3253void RenderLayerBacking::paintIntoLayer(const GraphicsLayer* graphicsLayer, GraphicsContext& context,
3254 const IntRect& paintDirtyRect, // In the coords of rootLayer.
3255 OptionSet<PaintBehavior> paintBehavior, EventRegionContext* eventRegionContext)
3256{
3257#if USE(OWNING_LAYER_BEAR_TRAP)
3258 RELEASE_ASSERT_WITH_MESSAGE(m_owningLayerBearTrap == BEAR_TRAP_VALUE, "RenderLayerBacking::paintIntoLayer(): m_owningLayerBearTrap caught the bear (55699292)");
3259 RELEASE_ASSERT_WITH_MESSAGE(&m_owningLayer, "RenderLayerBacking::paintIntoLayer(): m_owningLayer is null (55699292)");
3260#endif
3261
3262 if ((paintsIntoWindow() || paintsIntoCompositedAncestor()) && graphicsLayer->paintingPhase() != OptionSet<GraphicsLayerPaintingPhase>(GraphicsLayerPaintingPhase::ChildClippingMask)) {
3263#if !PLATFORM(IOS_FAMILY) && !OS(WINDOWS)
3264 // FIXME: Looks like the CALayer tree is out of sync with the GraphicsLayer heirarchy
3265 // when pages are restored from the BackForwardCache.
3266 // <rdar://problem/8712587> ASSERT: When Going Back to Page with Plugins in BackForwardCache
3267 ASSERT_NOT_REACHED();
3268#endif
3269 return;
3270 }
3271
3272 auto paintFlags = paintFlagsForLayer(*graphicsLayer);
3273
3274 if (eventRegionContext)
3275 paintFlags.add(RenderLayer::PaintLayerFlag::CollectingEventRegion);
3276
3277 RenderObject::SetLayoutNeededForbiddenScope forbidSetNeedsLayout(renderer());
3278
3279 auto paintOneLayer = [&](RenderLayer& layer, OptionSet<RenderLayer::PaintLayerFlag> paintFlags) {
3280 FrameView::PaintingState paintingState;
3281 if (!eventRegionContext) {
3282 InspectorInstrumentation::willPaint(layer.renderer());
3283
3284 if (layer.isRenderViewLayer())
3285 renderer().view().frameView().willPaintContents(context, paintDirtyRect, paintingState);
3286 }
3287
3288 RenderLayer::LayerPaintingInfo paintingInfo(&m_owningLayer, paintDirtyRect, paintBehavior, -m_subpixelOffsetFromRenderer);
3289 paintingInfo.eventRegionContext = eventRegionContext;
3290
3291 if (&layer == &m_owningLayer) {
3292 layer.paintLayerContents(context, paintingInfo, paintFlags);
3293
3294 auto* scrollableArea = layer.scrollableArea();
3295 if (scrollableArea && scrollableArea->containsDirtyOverlayScrollbars() && !eventRegionContext)
3296 layer.paintLayerContents(context, paintingInfo, paintFlags | RenderLayer::PaintLayerFlag::PaintingOverlayScrollbars);
3297 } else
3298 layer.paintLayerWithEffects(context, paintingInfo, paintFlags);
3299
3300 if (!eventRegionContext) {
3301 if (layer.isRenderViewLayer())
3302 renderer().view().frameView().didPaintContents(context, paintDirtyRect, paintingState);
3303
3304 InspectorInstrumentation::didPaint(layer.renderer(), paintDirtyRect);
3305 }
3306
3307 ASSERT(!m_owningLayer.m_usedTransparency);
3308 };
3309
3310 paintOneLayer(m_owningLayer, paintFlags);
3311
3312 // FIXME: Need to check m_foregroundLayer, masking etc. webkit.org/b/197565.
3313 GraphicsLayer* destinationForSharingLayers = m_scrolledContentsLayer ? m_scrolledContentsLayer.get() : m_graphicsLayer.get();
3314
3315 if (graphicsLayer == destinationForSharingLayers) {
3316 OptionSet<RenderLayer::PaintLayerFlag> sharingLayerPaintFlags = {
3317 RenderLayer::PaintLayerFlag::PaintingCompositingBackgroundPhase,
3318 RenderLayer::PaintLayerFlag::PaintingCompositingForegroundPhase };
3319
3320 if (graphicsLayer->paintingPhase().contains(GraphicsLayerPaintingPhase::OverflowContents))
3321 sharingLayerPaintFlags.add(RenderLayer::PaintLayerFlag::PaintingOverflowContents);
3322 if (eventRegionContext)
3323 sharingLayerPaintFlags.add(RenderLayer::PaintLayerFlag::CollectingEventRegion);
3324
3325 for (auto& layerWeakPtr : m_backingSharingLayers)
3326 paintOneLayer(*layerWeakPtr, sharingLayerPaintFlags);
3327 }
3328
3329 if (!eventRegionContext)
3330 compositor().didPaintBacking(this);
3331
3332#if USE(OWNING_LAYER_BEAR_TRAP)
3333 RELEASE_ASSERT_WITH_MESSAGE(m_owningLayerBearTrap == BEAR_TRAP_VALUE, "RenderLayerBacking::paintIntoLayer() end: m_owningLayerBearTrap caught the bear (55699292)");
3334 RELEASE_ASSERT_WITH_MESSAGE(&m_owningLayer, "RenderLayerBacking::paintIntoLayer() end: m_owningLayer is null (55699292)");
3335#endif
3336}
3337
3338OptionSet<RenderLayer::PaintLayerFlag> RenderLayerBacking::paintFlagsForLayer(const GraphicsLayer& graphicsLayer) const
3339{
3340 OptionSet<RenderLayer::PaintLayerFlag> paintFlags;
3341
3342 auto paintingPhase = graphicsLayer.paintingPhase();
3343 if (paintingPhase.contains(GraphicsLayerPaintingPhase::Background))
3344 paintFlags.add(RenderLayer::PaintLayerFlag::PaintingCompositingBackgroundPhase);
3345 if (paintingPhase.contains(GraphicsLayerPaintingPhase::Foreground))
3346 paintFlags.add(RenderLayer::PaintLayerFlag::PaintingCompositingForegroundPhase);
3347 if (paintingPhase.contains(GraphicsLayerPaintingPhase::Mask))
3348 paintFlags.add(RenderLayer::PaintLayerFlag::PaintingCompositingMaskPhase);
3349 if (paintingPhase.contains(GraphicsLayerPaintingPhase::ClipPath))
3350 paintFlags.add(RenderLayer::PaintLayerFlag::PaintingCompositingClipPathPhase);
3351 if (paintingPhase.contains(GraphicsLayerPaintingPhase::ChildClippingMask))
3352 paintFlags.add(RenderLayer::PaintLayerFlag::PaintingChildClippingMaskPhase);
3353 if (paintingPhase.contains(GraphicsLayerPaintingPhase::OverflowContents))
3354 paintFlags.add(RenderLayer::PaintLayerFlag::PaintingOverflowContents);
3355 if (paintingPhase.contains(GraphicsLayerPaintingPhase::CompositedScroll))
3356 paintFlags.add(RenderLayer::PaintLayerFlag::PaintingCompositingScrollingPhase);
3357
3358 if (&graphicsLayer == m_backgroundLayer.get() && m_backgroundLayerPaintsFixedRootBackground)
3359 paintFlags.add({ RenderLayer::PaintLayerFlag::PaintingRootBackgroundOnly, RenderLayer::PaintLayerFlag::PaintingCompositingForegroundPhase }); // Need PaintLayerFlag::PaintingCompositingForegroundPhase to walk child layers.
3360 else if (compositor().fixedRootBackgroundLayer())
3361 paintFlags.add(RenderLayer::PaintLayerFlag::PaintingSkipRootBackground);
3362
3363 return paintFlags;
3364}
3365
3366#if ENABLE(TOUCH_ACTION_REGIONS) || ENABLE(WHEEL_EVENT_REGIONS)
3367struct PatternDescription {
3368 ASCIILiteral name;
3369 FloatSize phase;
3370 SRGBA<uint8_t> fillColor;
3371};
3372
3373static RefPtr<Pattern> patternForDescription(PatternDescription description, FloatSize contentOffset, GraphicsContext& destContext)
3374{
3375 const FloatSize tileSize { 32, 18 };
3376
3377 auto imageBuffer = destContext.createAlignedImageBuffer(tileSize);
3378 if (!imageBuffer)
3379 return nullptr;
3380
3381 {
3382 GraphicsContext& imageContext = imageBuffer->context();
3383
3384 FontCascadeDescription fontDescription;
3385 fontDescription.setOneFamily("Helvetica"_s);
3386 fontDescription.setSpecifiedSize(10);
3387 fontDescription.setComputedSize(10);
3388 fontDescription.setWeight(FontSelectionValue(500));
3389 FontCascade font(WTFMove(fontDescription), 0, 0);
3390 font.update(nullptr);
3391
3392 TextRun textRun = TextRun(StringView { description.name });
3393 imageContext.setFillColor(description.fillColor);
3394
3395 constexpr float textGap = 4;
3396 constexpr float yOffset = 12;
3397 imageContext.drawText(font, textRun, { textGap, yOffset }, 0);
3398 }
3399
3400 AffineTransform patternOffsetTransform;
3401 patternOffsetTransform.translate(contentOffset + description.phase);
3402 patternOffsetTransform.scale(1 / destContext.scaleFactor());
3403
3404 return Pattern::create({ imageBuffer.releaseNonNull() }, { true, true, patternOffsetTransform });
3405};
3406#endif
3407
3408#if ENABLE(TOUCH_ACTION_REGIONS)
3409static RefPtr<Pattern> patternForTouchAction(TouchAction touchAction, FloatSize contentOffset, GraphicsContext& destContext)
3410{
3411 auto toIndex = [](TouchAction touchAction) -> unsigned {
3412 switch (touchAction) {
3413 case TouchAction::None:
3414 return 1;
3415 case TouchAction::Manipulation:
3416 return 2;
3417 case TouchAction::PanX:
3418 return 3;
3419 case TouchAction::PanY:
3420 return 4;
3421 case TouchAction::PinchZoom:
3422 return 5;
3423 case TouchAction::Auto:
3424 break;
3425 }
3426 return 0;
3427 };
3428
3429 constexpr auto fillColor = Color::black.colorWithAlphaByte(128);
3430
3431 static const PatternDescription patternDescriptions[] = {
3432 { "auto"_s, { }, fillColor },
3433 { "none"_s, { }, fillColor },
3434 { "manip"_s, { }, fillColor },
3435 { "pan-x"_s, { }, fillColor },
3436 { "pan-y"_s, { 0, 9 }, fillColor },
3437 { "p-z"_s, { 16, 4.5 }, fillColor },
3438 };
3439
3440 auto actionIndex = toIndex(touchAction);
3441 if (!actionIndex || actionIndex >= ARRAY_SIZE(patternDescriptions))
3442 return nullptr;
3443
3444 return patternForDescription(patternDescriptions[actionIndex], contentOffset, destContext);
3445}
3446#endif
3447
3448#if ENABLE(WHEEL_EVENT_REGIONS)
3449static RefPtr<Pattern> patternForEventListenerRegionType(EventListenerRegionType type, FloatSize contentOffset, GraphicsContext& destContext)
3450{
3451 auto patternAndPhase = [&]() -> PatternDescription {
3452 switch (type) {
3453 case EventListenerRegionType::Wheel:
3454 return { "wheel"_s, { }, Color::darkGreen.colorWithAlphaByte(128) };
3455 case EventListenerRegionType::NonPassiveWheel:
3456 return { "sync"_s, { 0, 9 }, SRGBA<uint8_t> { 200, 0, 0, 128 } };
3457 case EventListenerRegionType::MouseClick:
3458 break;
3459 }
3460 ASSERT_NOT_REACHED();
3461 return { ""_s, { }, Color::black };
3462 }();
3463
3464 return patternForDescription(patternAndPhase, contentOffset, destContext);
3465}
3466#endif
3467
3468void RenderLayerBacking::paintDebugOverlays(const GraphicsLayer* graphicsLayer, GraphicsContext& context)
3469{
3470 auto& eventRegion = graphicsLayer->eventRegion();
3471 if (eventRegion.isEmpty())
3472 return;
3473
3474 GraphicsContextStateSaver stateSaver(context);
3475
3476 // The region is offset by offsetFromRenderer() so undo that.
3477 auto contentOffset = roundedIntSize(graphicsLayer->offsetFromRenderer());
3478 context.translate(contentOffset);
3479
3480 auto visibleDebugOverlayRegions = OptionSet<DebugOverlayRegions>::fromRaw(renderer().settings().visibleDebugOverlayRegions());
3481 if (visibleDebugOverlayRegions.containsAny({ DebugOverlayRegions::TouchActionRegion, DebugOverlayRegions::WheelEventHandlerRegion })) {
3482 constexpr auto regionColor = Color::blue.colorWithAlphaByte(50);
3483 context.setFillColor(regionColor);
3484 for (auto rect : eventRegion.region().rects())
3485 context.fillRect(rect);
3486 }
3487
3488#if ENABLE(TOUCH_ACTION_REGIONS)
3489 if (visibleDebugOverlayRegions.contains(DebugOverlayRegions::TouchActionRegion)) {
3490 const TouchAction touchActionList[] = {
3491 TouchAction::None,
3492 TouchAction::Manipulation,
3493 TouchAction::PanX,
3494 TouchAction::PanY,
3495 TouchAction::PinchZoom,
3496 };
3497
3498 for (auto action : touchActionList) {
3499 auto* actionRegion = graphicsLayer->eventRegion().regionForTouchAction(action);
3500 if (!actionRegion)
3501 continue;
3502
3503 auto fillPattern = patternForTouchAction(action, contentOffsetInCompositingLayer(), context);
3504 if (!fillPattern)
3505 continue;
3506
3507 context.setFillPattern(fillPattern.releaseNonNull());
3508 for (auto rect : actionRegion->rects())
3509 context.fillRect(rect);
3510 }
3511 }
3512#endif
3513
3514#if ENABLE(WHEEL_EVENT_REGIONS)
3515 if (visibleDebugOverlayRegions.contains(DebugOverlayRegions::WheelEventHandlerRegion)) {
3516 for (auto type : { EventListenerRegionType::Wheel, EventListenerRegionType::NonPassiveWheel }) {
3517 auto fillPattern = patternForEventListenerRegionType(type, graphicsLayer->offsetFromRenderer(), context);
3518 context.setFillPattern(fillPattern.releaseNonNull());
3519
3520 auto& region = graphicsLayer->eventRegion().eventListenerRegionForType(type);
3521 for (auto rect : region.rects())
3522 context.fillRect(rect);
3523 }
3524 }
3525#endif
3526
3527#if ENABLE(EDITABLE_REGION)
3528 if (visibleDebugOverlayRegions.contains(DebugOverlayRegions::EditableElementRegion)) {
3529 context.setFillColor(SRGBA<uint8_t> { 128, 0, 128, 50 });
3530 for (auto rect : eventRegion.rectsForEditableElements())
3531 context.fillRect(rect);
3532 }
3533#endif
3534
3535#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)
3536 if (DebugPageOverlays::shouldPaintOverlayIntoLayerForRegionType(renderer().page(), DebugPageOverlays::RegionType::InteractionRegion)) {
3537 context.setStrokeColor(Color::green);
3538 context.setStrokeThickness(1);
3539
3540 for (const auto& region : eventRegion.interactionRegions()) {
3541 for (auto rect : region.regionInLayerCoordinates.rects()) {
3542 Path path;
3543 path.addRoundedRect(rect, { region.borderRadius, region.borderRadius });
3544 context.strokePath(path);
3545 }
3546 }
3547 }
3548#endif
3549}
3550
3551// Up-call from compositing layer drawing callback.
3552void RenderLayerBacking::paintContents(const GraphicsLayer* graphicsLayer, GraphicsContext& context, const FloatRect& clip, GraphicsLayerPaintBehavior layerPaintBehavior)
3553{
3554#ifndef NDEBUG
3555 renderer().page().setIsPainting(true);
3556#endif
3557
3558#if PLATFORM(MAC)
3559 LocalDefaultSystemAppearance localAppearance(renderer().useDarkAppearance());
3560#endif
3561
3562 // The dirtyRect is in the coords of the painting root.
3563 FloatRect adjustedClipRect = clip;
3564 adjustedClipRect.move(m_subpixelOffsetFromRenderer);
3565 IntRect dirtyRect = enclosingIntRect(adjustedClipRect);
3566
3567 if (!graphicsLayer->repaintCount())
3568 layerPaintBehavior |= GraphicsLayerPaintFirstTilePaint;
3569
3570 if (graphicsLayer == m_graphicsLayer.get()
3571 || graphicsLayer == m_foregroundLayer.get()
3572 || graphicsLayer == m_backgroundLayer.get()
3573 || graphicsLayer == m_maskLayer.get()
3574 || graphicsLayer == m_childClippingMaskLayer.get()
3575 || graphicsLayer == m_scrolledContentsLayer.get()) {
3576
3577 if (!graphicsLayer->paintingPhase().contains(GraphicsLayerPaintingPhase::OverflowContents))
3578 dirtyRect.intersect(enclosingIntRect(compositedBoundsIncludingMargin()));
3579
3580 // We have to use the same root as for hit testing, because both methods can compute and cache clipRects.
3581 OptionSet<PaintBehavior> behavior = PaintBehavior::Normal;
3582 if (layerPaintBehavior == GraphicsLayerPaintSnapshotting)
3583 behavior.add(PaintBehavior::Snapshotting);
3584
3585 if (layerPaintBehavior == GraphicsLayerPaintFirstTilePaint)
3586 behavior.add(PaintBehavior::TileFirstPaint);
3587
3588 paintIntoLayer(graphicsLayer, context, dirtyRect, behavior);
3589
3590 auto visibleDebugOverlayRegions = OptionSet<DebugOverlayRegions>::fromRaw(renderer().settings().visibleDebugOverlayRegions());
3591 if (visibleDebugOverlayRegions.containsAny({ DebugOverlayRegions::TouchActionRegion, DebugOverlayRegions::EditableElementRegion, DebugOverlayRegions::WheelEventHandlerRegion, DebugOverlayRegions::InteractionRegion }))
3592 paintDebugOverlays(graphicsLayer, context);
3593
3594 } else if (graphicsLayer == layerForHorizontalScrollbar()) {
3595 if (m_owningLayer.hasVisibleContent()) {
3596 auto* scrollableArea = m_owningLayer.scrollableArea();
3597 ASSERT(scrollableArea);
3598
3599 paintScrollbar(scrollableArea->horizontalScrollbar(), context, dirtyRect);
3600 }
3601 } else if (graphicsLayer == layerForVerticalScrollbar()) {
3602 if (m_owningLayer.hasVisibleContent()) {
3603 auto* scrollableArea = m_owningLayer.scrollableArea();
3604 ASSERT(scrollableArea);
3605
3606 paintScrollbar(scrollableArea->verticalScrollbar(), context, dirtyRect);
3607 }
3608 } else if (graphicsLayer == layerForScrollCorner()) {
3609 auto* scrollableArea = m_owningLayer.scrollableArea();
3610 ASSERT(scrollableArea);
3611
3612 auto cornerRect = scrollableArea->overflowControlsRects().scrollCornerOrResizerRect();
3613 GraphicsContextStateSaver stateSaver(context);
3614 context.translate(-cornerRect.location());
3615 LayoutRect transformedClip = LayoutRect(clip);
3616 transformedClip.moveBy(cornerRect.location());
3617 scrollableArea->paintScrollCorner(context, IntPoint(), snappedIntRect(transformedClip));
3618 scrollableArea->paintResizer(context, IntPoint(), transformedClip);
3619 }
3620#ifndef NDEBUG
3621 renderer().page().setIsPainting(false);
3622#endif
3623}
3624
3625float RenderLayerBacking::pageScaleFactor() const
3626{
3627 return compositor().pageScaleFactor();
3628}
3629
3630float RenderLayerBacking::zoomedOutPageScaleFactor() const
3631{
3632 return compositor().zoomedOutPageScaleFactor();
3633}
3634
3635float RenderLayerBacking::deviceScaleFactor() const
3636{
3637 return compositor().deviceScaleFactor();
3638}
3639
3640float RenderLayerBacking::contentsScaleMultiplierForNewTiles(const GraphicsLayer* layer) const
3641{
3642 return compositor().contentsScaleMultiplierForNewTiles(layer);
3643}
3644
3645bool RenderLayerBacking::paintsOpaquelyAtNonIntegralScales(const GraphicsLayer*) const
3646{
3647 return m_isMainFrameRenderViewLayer;
3648}
3649
3650void RenderLayerBacking::didChangePlatformLayerForLayer(const GraphicsLayer* layer)
3651{
3652 compositor().didChangePlatformLayerForLayer(m_owningLayer, layer);
3653}
3654
3655bool RenderLayerBacking::getCurrentTransform(const GraphicsLayer* graphicsLayer, TransformationMatrix& transform) const
3656{
3657 auto* transformedLayer = m_contentsContainmentLayer.get() ? m_contentsContainmentLayer.get() : m_graphicsLayer.get();
3658 if (graphicsLayer != transformedLayer)
3659 return false;
3660
3661 if (m_owningLayer.hasTransform()) {
3662 transform = m_owningLayer.currentTransform(RenderStyle::individualTransformOperations);
3663 return true;
3664 }
3665 return false;
3666}
3667
3668bool RenderLayerBacking::isTrackingRepaints() const
3669{
3670 return static_cast<GraphicsLayerClient&>(compositor()).isTrackingRepaints();
3671}
3672
3673bool RenderLayerBacking::shouldSkipLayerInDump(const GraphicsLayer* layer, OptionSet<LayerTreeAsTextOptions> options) const
3674{
3675 if (options & LayerTreeAsTextOptions::Debug)
3676 return false;
3677
3678 // Skip the root tile cache's flattening layer.
3679 return m_isMainFrameRenderViewLayer && layer && layer == m_childContainmentLayer.get();
3680}
3681
3682bool RenderLayerBacking::shouldDumpPropertyForLayer(const GraphicsLayer* layer, const char* propertyName, OptionSet<LayerTreeAsTextOptions> options) const
3683{
3684 // For backwards compatibility with WebKit1 and other platforms,
3685 // skip some properties on the root tile cache.
3686 if (m_isMainFrameRenderViewLayer && layer == m_graphicsLayer.get() && !(options & LayerTreeAsTextOptions::IncludeRootLayerProperties)) {
3687 if (!strcmp(propertyName, "drawsContent"))
3688 return false;
3689
3690 // Background color could be of interest to tests or other dumpers if it's non-white.
3691 if (!strcmp(propertyName, "backgroundColor") && Color::isWhiteColor(layer->backgroundColor()))
3692 return false;
3693
3694 // The root tile cache's repaints will show up at the top with FrameView's,
3695 // so don't dump them twice.
3696 if (!strcmp(propertyName, "repaintRects"))
3697 return false;
3698 }
3699
3700 return true;
3701}
3702
3703bool RenderLayerBacking::shouldAggressivelyRetainTiles(const GraphicsLayer*) const
3704{
3705 // Only the main frame TileController has enough information about in-window state to
3706 // correctly implement aggressive tile retention.
3707 if (!m_isMainFrameRenderViewLayer)
3708 return false;
3709
3710 return renderer().settings().aggressiveTileRetentionEnabled();
3711}
3712
3713bool RenderLayerBacking::shouldTemporarilyRetainTileCohorts(const GraphicsLayer*) const
3714{
3715 return renderer().settings().temporaryTileCohortRetentionEnabled();
3716}
3717
3718bool RenderLayerBacking::useGiantTiles() const
3719{
3720 return renderer().settings().useGiantTiles();
3721}
3722
3723void RenderLayerBacking::logFilledVisibleFreshTile(unsigned blankPixelCount)
3724{
3725 if (auto* loggingClient = renderer().page().performanceLoggingClient())
3726 loggingClient->logScrollingEvent(PerformanceLoggingClient::ScrollingEvent::FilledTile, MonotonicTime::now(), blankPixelCount);
3727}
3728
3729#ifndef NDEBUG
3730void RenderLayerBacking::verifyNotPainting()
3731{
3732 ASSERT(!renderer().page().isPainting());
3733}
3734#endif
3735
3736bool RenderLayerBacking::startAnimation(double timeOffset, const Animation& animation, const KeyframeList& keyframes)
3737{
3738 bool hasOpacity = keyframes.containsProperty(CSSPropertyOpacity);
3739 bool hasRotate = renderer().isBox() && keyframes.containsProperty(CSSPropertyRotate);
3740 bool hasScale = renderer().isBox() && keyframes.containsProperty(CSSPropertyScale);
3741 bool hasTranslate = renderer().isBox() && keyframes.containsProperty(CSSPropertyTranslate);
3742 bool hasTransform = renderer().isBox() && keyframes.containsProperty(CSSPropertyTransform);
3743 bool hasFilter = keyframes.containsProperty(CSSPropertyFilter);
3744
3745 bool hasBackdropFilter = false;
3746#if ENABLE(FILTERS_LEVEL_2)
3747 hasBackdropFilter = keyframes.containsProperty(CSSPropertyWebkitBackdropFilter);
3748#endif
3749
3750 if (!hasOpacity && !hasRotate && !hasScale && !hasTranslate && !hasTransform && !hasFilter && !hasBackdropFilter)
3751 return false;
3752
3753 KeyframeValueList rotateVector(AnimatedPropertyRotate);
3754 KeyframeValueList scaleVector(AnimatedPropertyScale);
3755 KeyframeValueList translateVector(AnimatedPropertyTranslate);
3756 KeyframeValueList transformVector(AnimatedPropertyTransform);
3757 KeyframeValueList opacityVector(AnimatedPropertyOpacity);
3758 KeyframeValueList filterVector(AnimatedPropertyFilter);
3759#if ENABLE(FILTERS_LEVEL_2)
3760 KeyframeValueList backdropFilterVector(AnimatedPropertyWebkitBackdropFilter);
3761#endif
3762
3763 for (auto& currentKeyframe : keyframes) {
3764 const RenderStyle* keyframeStyle = currentKeyframe.style();
3765 double key = currentKeyframe.key();
3766
3767 if (!keyframeStyle)
3768 continue;
3769
3770 auto* tf = currentKeyframe.timingFunction();
3771
3772 if (currentKeyframe.containsProperty(CSSPropertyRotate))
3773 rotateVector.insert(makeUnique<TransformAnimationValue>(key, keyframeStyle->rotate(), tf));
3774
3775 if (currentKeyframe.containsProperty(CSSPropertyScale))
3776 scaleVector.insert(makeUnique<TransformAnimationValue>(key, keyframeStyle->scale(), tf));
3777
3778 if (currentKeyframe.containsProperty(CSSPropertyTranslate))
3779 translateVector.insert(makeUnique<TransformAnimationValue>(key, keyframeStyle->translate(), tf));
3780
3781 if (currentKeyframe.containsProperty(CSSPropertyTransform))
3782 transformVector.insert(makeUnique<TransformAnimationValue>(key, keyframeStyle->transform(), tf));
3783
3784 if (currentKeyframe.containsProperty(CSSPropertyOpacity))
3785 opacityVector.insert(makeUnique<FloatAnimationValue>(key, keyframeStyle->opacity(), tf));
3786
3787 if (currentKeyframe.containsProperty(CSSPropertyFilter))
3788 filterVector.insert(makeUnique<FilterAnimationValue>(key, keyframeStyle->filter(), tf));
3789
3790#if ENABLE(FILTERS_LEVEL_2)
3791 if (currentKeyframe.containsProperty(CSSPropertyWebkitBackdropFilter))
3792 backdropFilterVector.insert(makeUnique<FilterAnimationValue>(key, keyframeStyle->backdropFilter(), tf));
3793#endif
3794 }
3795
3796 if (!renderer().settings().acceleratedCompositedAnimationsEnabled())
3797 return false;
3798
3799 bool didAnimate = false;
3800
3801 if (hasRotate && m_graphicsLayer->addAnimation(rotateVector, snappedIntRect(m_owningLayer.rendererBorderBoxRect()).size(), &animation, keyframes.animationName(), timeOffset))
3802 didAnimate = true;
3803
3804 if (hasScale && m_graphicsLayer->addAnimation(scaleVector, snappedIntRect(m_owningLayer.rendererBorderBoxRect()).size(), &animation, keyframes.animationName(), timeOffset))
3805 didAnimate = true;
3806
3807 if (hasTranslate && m_graphicsLayer->addAnimation(translateVector, snappedIntRect(m_owningLayer.rendererBorderBoxRect()).size(), &animation, keyframes.animationName(), timeOffset))
3808 didAnimate = true;
3809
3810 if (hasTransform && m_graphicsLayer->addAnimation(transformVector, snappedIntRect(m_owningLayer.rendererBorderBoxRect()).size(), &animation, keyframes.animationName(), timeOffset))
3811 didAnimate = true;
3812
3813 if (hasOpacity && m_graphicsLayer->addAnimation(opacityVector, IntSize { }, &animation, keyframes.animationName(), timeOffset))
3814 didAnimate = true;
3815
3816 if (hasFilter && m_graphicsLayer->addAnimation(filterVector, IntSize { }, &animation, keyframes.animationName(), timeOffset))
3817 didAnimate = true;
3818
3819#if ENABLE(FILTERS_LEVEL_2)
3820 if (hasBackdropFilter && m_graphicsLayer->addAnimation(backdropFilterVector, IntSize { }, &animation, keyframes.animationName(), timeOffset))
3821 didAnimate = true;
3822#endif
3823
3824 if (didAnimate) {
3825 m_owningLayer.setNeedsPostLayoutCompositingUpdate();
3826 m_owningLayer.setNeedsCompositingGeometryUpdate();
3827 }
3828
3829 return didAnimate;
3830}
3831
3832void RenderLayerBacking::animationPaused(double timeOffset, const String& animationName)
3833{
3834 m_graphicsLayer->pauseAnimation(animationName, timeOffset);
3835}
3836
3837void RenderLayerBacking::animationFinished(const String& animationName)
3838{
3839 m_graphicsLayer->removeAnimation(animationName);
3840 m_owningLayer.setNeedsPostLayoutCompositingUpdate();
3841 m_owningLayer.setNeedsCompositingGeometryUpdate();
3842}
3843
3844void RenderLayerBacking::transformRelatedPropertyDidChange()
3845{
3846 m_graphicsLayer->transformRelatedPropertyDidChange();
3847}
3848
3849void RenderLayerBacking::notifyAnimationStarted(const GraphicsLayer*, const String&, MonotonicTime)
3850{
3851}
3852
3853void RenderLayerBacking::notifyFlushRequired(const GraphicsLayer* layer)
3854{
3855 if (renderer().renderTreeBeingDestroyed())
3856 return;
3857
3858 compositor().notifyFlushRequired(layer);
3859}
3860
3861void RenderLayerBacking::notifyFlushBeforeDisplayRefresh(const GraphicsLayer* layer)
3862{
3863 compositor().notifyFlushBeforeDisplayRefresh(layer);
3864}
3865
3866// This is used for the 'freeze' API, for testing only.
3867void RenderLayerBacking::suspendAnimations(MonotonicTime time)
3868{
3869 m_graphicsLayer->suspendAnimations(time);
3870}
3871
3872void RenderLayerBacking::resumeAnimations()
3873{
3874 m_graphicsLayer->resumeAnimations();
3875}
3876
3877LayoutRect RenderLayerBacking::compositedBounds() const
3878{
3879 return m_compositedBounds;
3880}
3881
3882bool RenderLayerBacking::setCompositedBounds(const LayoutRect& bounds)
3883{
3884 if (bounds == m_compositedBounds)
3885 return false;
3886
3887 m_compositedBounds = bounds;
3888 return true;
3889}
3890
3891LayoutRect RenderLayerBacking::compositedBoundsIncludingMargin() const
3892{
3893 auto* tiledBacking = this->tiledBacking();
3894 if (!tiledBacking || !tiledBacking->hasMargins())
3895 return compositedBounds();
3896
3897 LayoutRect boundsIncludingMargin = compositedBounds();
3898 LayoutUnit leftMarginWidth = tiledBacking->leftMarginWidth();
3899 LayoutUnit topMarginHeight = tiledBacking->topMarginHeight();
3900
3901 boundsIncludingMargin.moveBy(LayoutPoint(-leftMarginWidth, -topMarginHeight));
3902 boundsIncludingMargin.expand(leftMarginWidth + tiledBacking->rightMarginWidth(), topMarginHeight + tiledBacking->bottomMarginHeight());
3903
3904 return boundsIncludingMargin;
3905}
3906
3907CSSPropertyID RenderLayerBacking::graphicsLayerToCSSProperty(AnimatedPropertyID property)
3908{
3909 CSSPropertyID cssProperty = CSSPropertyInvalid;
3910 switch (property) {
3911 case AnimatedPropertyTranslate:
3912 cssProperty = CSSPropertyTranslate;
3913 break;
3914 case AnimatedPropertyScale:
3915 cssProperty = CSSPropertyScale;
3916 break;
3917 case AnimatedPropertyRotate:
3918 cssProperty = CSSPropertyRotate;
3919 break;
3920 case AnimatedPropertyTransform:
3921 cssProperty = CSSPropertyTransform;
3922 break;
3923 case AnimatedPropertyOpacity:
3924 cssProperty = CSSPropertyOpacity;
3925 break;
3926 case AnimatedPropertyBackgroundColor:
3927 cssProperty = CSSPropertyBackgroundColor;
3928 break;
3929 case AnimatedPropertyFilter:
3930 cssProperty = CSSPropertyFilter;
3931 break;
3932#if ENABLE(FILTERS_LEVEL_2)
3933 case AnimatedPropertyWebkitBackdropFilter:
3934 cssProperty = CSSPropertyWebkitBackdropFilter;
3935 break;
3936#endif
3937 case AnimatedPropertyInvalid:
3938 ASSERT_NOT_REACHED();
3939 }
3940 return cssProperty;
3941}
3942
3943AnimatedPropertyID RenderLayerBacking::cssToGraphicsLayerProperty(CSSPropertyID cssProperty)
3944{
3945 switch (cssProperty) {
3946 case CSSPropertyTranslate:
3947 return AnimatedPropertyTranslate;
3948 case CSSPropertyScale:
3949 return AnimatedPropertyScale;
3950 case CSSPropertyRotate:
3951 return AnimatedPropertyRotate;
3952 case CSSPropertyTransform:
3953 return AnimatedPropertyTransform;
3954 case CSSPropertyOpacity:
3955 return AnimatedPropertyOpacity;
3956 case CSSPropertyBackgroundColor:
3957 return AnimatedPropertyBackgroundColor;
3958 case CSSPropertyFilter:
3959 return AnimatedPropertyFilter;
3960#if ENABLE(FILTERS_LEVEL_2)
3961 case CSSPropertyWebkitBackdropFilter:
3962 return AnimatedPropertyWebkitBackdropFilter;
3963#endif
3964 default:
3965 // It's fine if we see other css properties here; they are just not accelerated.
3966 break;
3967 }
3968 return AnimatedPropertyInvalid;
3969}
3970
3971CompositingLayerType RenderLayerBacking::compositingLayerType() const
3972{
3973 if (m_graphicsLayer->usesContentsLayer())
3974 return MediaCompositingLayer;
3975
3976 if (m_graphicsLayer->drawsContent())
3977 return m_graphicsLayer->tiledBacking() ? TiledCompositingLayer : NormalCompositingLayer;
3978
3979 return ContainerCompositingLayer;
3980}
3981
3982double RenderLayerBacking::backingStoreMemoryEstimate() const
3983{
3984 double backingMemory;
3985
3986 // Layers in m_ancestorClippingStack, m_contentsContainmentLayer and m_childContainmentLayer are just used for masking or containment, so have no backing.
3987 backingMemory = m_graphicsLayer->backingStoreMemoryEstimate();
3988 if (m_foregroundLayer)
3989 backingMemory += m_foregroundLayer->backingStoreMemoryEstimate();
3990 if (m_backgroundLayer)
3991 backingMemory += m_backgroundLayer->backingStoreMemoryEstimate();
3992 if (m_maskLayer)
3993 backingMemory += m_maskLayer->backingStoreMemoryEstimate();
3994 if (m_childClippingMaskLayer)
3995 backingMemory += m_childClippingMaskLayer->backingStoreMemoryEstimate();
3996
3997 if (m_scrolledContentsLayer)
3998 backingMemory += m_scrolledContentsLayer->backingStoreMemoryEstimate();
3999
4000 if (m_layerForHorizontalScrollbar)
4001 backingMemory += m_layerForHorizontalScrollbar->backingStoreMemoryEstimate();
4002
4003 if (m_layerForVerticalScrollbar)
4004 backingMemory += m_layerForVerticalScrollbar->backingStoreMemoryEstimate();
4005
4006 if (m_layerForScrollCorner)
4007 backingMemory += m_layerForScrollCorner->backingStoreMemoryEstimate();
4008
4009 return backingMemory;
4010}
4011
4012TextStream& operator<<(TextStream& ts, const RenderLayerBacking& backing)
4013{
4014 ts << "RenderLayerBacking " << &backing << " bounds " << backing.compositedBounds();
4015
4016 if (backing.isFrameLayerWithTiledBacking())
4017 ts << " frame layer tiled backing";
4018 if (backing.paintsIntoWindow())
4019 ts << " paintsIntoWindow";
4020 if (backing.paintsIntoCompositedAncestor())
4021 ts << " paintsIntoCompositedAncestor";
4022
4023 ts << " primary layer ID " << backing.graphicsLayer()->primaryLayerID();
4024 if (auto nodeID = backing.scrollingNodeIDForRole(ScrollCoordinationRole::ViewportConstrained))
4025 ts << " viewport constrained scrolling node " << nodeID;
4026 if (auto nodeID = backing.scrollingNodeIDForRole(ScrollCoordinationRole::Scrolling))
4027 ts << " scrolling node " << nodeID;
4028
4029 if (backing.ancestorClippingStack())
4030 ts << " ancestor clip stack " << *backing.ancestorClippingStack();
4031
4032 if (auto nodeID = backing.scrollingNodeIDForRole(ScrollCoordinationRole::FrameHosting))
4033 ts << " frame hosting node " << nodeID;
4034 if (auto nodeID = backing.scrollingNodeIDForRole(ScrollCoordinationRole::Positioning))
4035 ts << " positioning node " << nodeID;
4036 return ts;
4037}
4038
4039TransformationMatrix RenderLayerBacking::transformMatrixForProperty(AnimatedPropertyID property) const
4040{
4041 TransformationMatrix matrix;
4042
4043 auto applyTransformOperation = [&](TransformOperation* operation) {
4044 if (operation)
4045 operation->apply(matrix, snappedIntRect(m_owningLayer.rendererBorderBoxRect()).size());
4046 };
4047
4048 if (property == AnimatedPropertyTranslate)
4049 applyTransformOperation(renderer().style().translate());
4050 else if (property == AnimatedPropertyScale)
4051 applyTransformOperation(renderer().style().scale());
4052 else if (property == AnimatedPropertyRotate)
4053 applyTransformOperation(renderer().style().rotate());
4054 else if (property == AnimatedPropertyTransform)
4055 renderer().style().transform().apply(snappedIntRect(m_owningLayer.rendererBorderBoxRect()).size(), matrix);
4056 else
4057 ASSERT_NOT_REACHED();
4058
4059 return matrix;
4060}
4061
4062} // namespace WebCore
Note: See TracBrowser for help on using the repository browser.