Bug Summary

File:Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore/rendering/RenderLayerBacking.cpp
Warning:line 1738, column 35
Local variable 'frameView' is uncounted and unsafe

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple arm64-apple-macosx15.5.0 -O2 -Wundef-prefix=TARGET_OS_ -Werror=undef-prefix -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name UnifiedSource413.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=osx -analyzer-checker=security.insecureAPI.decodeValueOfObjCType -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=non-leaf -ffp-contract=on -fno-rounding-math -target-sdk-version=15.5 -fcompatibility-qualified-id-block-type-checking -fvisibility-inlines-hidden-static-local-var -fno-modulemap-allow-subdirectory-search -fdefine-target-os-macros -enable-tlsdesc -target-cpu apple-m1 -target-feature +v8.4a -target-feature +aes -target-feature +altnzcv -target-feature +ccdp -target-feature +ccpp -target-feature +complxnum -target-feature +crc -target-feature +dotprod -target-feature +flagm -target-feature +fp-armv8 -target-feature +fp16fml -target-feature +fptoint -target-feature +fullfp16 -target-feature +jsconv -target-feature +lse -target-feature +neon -target-feature +pauth -target-feature +perfmon -target-feature +predres -target-feature +ras -target-feature +rcpc -target-feature +rdm -target-feature +sb -target-feature +sha2 -target-feature +sha3 -target-feature +specrestrict -target-feature +ssbs -target-abi darwinpcs -dwarf-ext-refs -fmodule-format=obj -debug-info-kind=standalone -dwarf-version=5 -debugger-tuning=lldb -fdebug-compilation-dir=/Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore -target-linker-version 1167.5 -fcoverage-compilation-dir=/Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore -resource-dir /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/llvm-project/build/lib/clang/21 -dependency-file /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/scan-build-output/StaticAnalyzer/WebCore/WebCore/normal/arm64/UnifiedSource413.d -skip-unused-modulemap-deps -MT dependencies -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk -iquote /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/WebCore-generated-files.hmap -iquote /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/WebCore-project-headers.hmap -isystem /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore/PAL/ThirdParty/dav1d/include -iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/System/Library/PrivateFrameworks -iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/System/Library/Frameworks -include-pch /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/PrecompiledHeaders/SharedPrecompiledHeaders/12902642326230122134/WebCorePrefix.h.gch -D _LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE -D CLANG_WEBKIT_BRANCH=1 -D NDEBUG -D BUILDING_WEBKIT -D GL_SILENCE_DEPRECATION=1 -D GLES_SILENCE_DEPRECATION=1 -D __clang_analyzer__ -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/WebCore-own-target-headers.hmap -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/WebCore-all-target-headers.hmap -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/include -I PAL -I ForwardingHeaders -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/include/libxslt -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/include/libxml2 -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/DerivedSources/WebCore -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include/WebKitAdditions -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/local/include/WebKitAdditions -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitLibraries/SDKs/macosx15.0-additions.sdk/usr/local/include -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/local/include -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include/webrtc -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/local/include/webrtc -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include/webm -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/local/include/webm -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/PAL.build/PAL.build/DerivedSources -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/PAL.build/Release/PAL.build/DerivedSources -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/DerivedSources-normal/arm64 -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/DerivedSources/arm64 -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/DerivedSources -F/Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release -I/usr/local/include -stdlib=libc++ -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/include/c++/v1 -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/local/include -internal-isystem /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/llvm-project/build/lib/clang/21/include -internal-externc-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/include -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/System/Library/Frameworks -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/System/Library/SubFrameworks -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/Library/Frameworks -Wno-trigraphs -Werror -Wno-missing-field-initializers -Wmissing-prototypes -Wunreachable-code -Wnon-virtual-dtor -Wno-overloaded-virtual -Wno-exit-time-destructors -Wno-missing-braces -Wparentheses -Wswitch -Wunused-function -Wno-unused-label -Wno-unused-parameter -Wunused-variable -Wunused-value -Wempty-body -Wuninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wconstant-conversion -Wint-conversion -Wbool-conversion -Wenum-conversion -Wno-float-conversion -Wnon-literal-null-conversion -Wobjc-literal-conversion -Wsign-compare -Wno-shorten-64-to-32 -Wnewline-eof -Wno-c++11-extensions -Wno-implicit-fallthrough -Wdeprecated-declarations -Winvalid-offsetof -Wno-sign-conversion -Winfinite-recursion -Wmove -Wcomma -Wblock-capture-autoreleasing -Wstrict-prototypes -Wrange-loop-analysis -Wno-semicolon-before-method-body -Wall -Wc99-designator -Wconditional-uninitialized -Wextra -Wdeprecated-enum-enum-conversion -Wdeprecated-enum-float-conversion -Wenum-float-conversion -Wfinal-dtor-non-final-class -Wformat=2 -Wmisleading-indentation -Wpointer-to-int-cast -Wreorder-init-list -Wundef -Wunused-but-set-variable -Wvla -Werror=unguarded-availability -Wno-elaborated-enum-base -Wcast-qual -Wchar-subscripts -Wextra-tokens -Winit-self -Wmissing-noreturn -Wpacked -Wpointer-arith -Wredundant-decls -Wwrite-strings -Wexit-time-destructors -Wglobal-constructors -Wtautological-compare -Wimplicit-fallthrough -Wvla -Wno-unknown-warning-option -Wliteral-conversion -Wthread-safety -Wno-profile-instr-out-of-date -Wno-profile-instr-unprofiled -Wno-backend-plugin -Wunsafe-buffer-usage -std=c++2b -fdeprecated-macro -ferror-limit 19 -fmacro-backtrace-limit=0 -fvisibility=hidden -fvisibility-inlines-hidden -stack-protector 1 -fblocks -fencode-extended-block-signature -fno-rtti -fregister-global-dtors-with-atexit -fgnuc-version=4.2.1 -fno-cxx-modules -fno-implicit-modules -fskip-odr-check-in-gmf -fpascal-strings -fmax-type-align=16 -fdiagnostics-show-note-include-stack -vectorize-loops -vectorize-slp -fsafe-buffer-usage-suggestions -analyzer-output=html -analyzer-config report-in-main-source-file=true -analyzer-config nullability:NoDiagnoseCallsToSystemHeaders=true -analyzer-checker optin.osx.cocoa.localizability.NonLocalizedStringChecker -analyzer-checker security.insecureAPI.UncheckedReturn -analyzer-checker security.insecureAPI.getpw -analyzer-checker security.insecureAPI.gets -analyzer-checker security.insecureAPI.mkstemp -analyzer-checker security.insecureAPI.mktemp -analyzer-disable-checker security.insecureAPI.rand -analyzer-disable-checker security.insecureAPI.strcpy -analyzer-checker security.insecureAPI.vfork -analyzer-disable-checker alpha,apiModeling,core,cplusplus,deadcode,debug,fuchsia,nullability,optin,osx,security,unix,webkit -analyzer-checker alpha.webkit.ForwardDeclChecker,alpha.webkit.MemoryUnsafeCastChecker,alpha.webkit.NoDeleteChecker,alpha.webkit.NoUncheckedPtrMemberChecker,alpha.webkit.NoUnretainedMemberChecker,alpha.webkit.RetainPtrCtorAdoptChecker,alpha.webkit.UncheckedCallArgsChecker,alpha.webkit.UncheckedLocalVarsChecker,alpha.webkit.UncountedCallArgsChecker,alpha.webkit.UncountedLocalVarsChecker,alpha.webkit.UnretainedCallArgsChecker,alpha.webkit.UnretainedLambdaCapturesChecker,alpha.webkit.UnretainedLocalVarsChecker,webkit.NoUncountedMemberChecker,webkit.RefCntblBaseVirtualDtor,webkit.UncountedLambdaCapturesChecker -analyzer-config max-nodes=10000000 -analyzer-config verbose-report-filename=true -fdwarf2-cfi-asm -o /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/scan-build-output/StaticAnalyzer/WebCore/WebCore/normal/arm64/UnifiedSource413.plist -x c++ /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/DerivedSources/WebCore/unified-sources/UnifiedSource413.cpp
1/*
2 * Copyright (C) 2009-2023 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 "BackgroundPainter.h"
31#include "BitmapImage.h"
32#include "BlendingKeyframes.h"
33#include "BorderShape.h"
34#include "CSSPropertyNames.h"
35#include "CachedImage.h"
36#include "CanvasRenderingContext2DBase.h"
37#include "Chrome.h"
38#include "ContainerNodeInlines.h"
39#include "DebugOverlayRegions.h"
40#include "DebugPageOverlays.h"
41#include "DocumentPage.h"
42#include "EventRegion.h"
43#include "GraphicsContext.h"
44#include "GraphicsLayer.h"
45#include "GraphicsLayerFilterAnimationValue.h"
46#include "GraphicsLayerFloatAnimationValue.h"
47#include "GraphicsLayerKeyframeValueList.h"
48#include "GraphicsLayerTransformAnimationValue.h"
49#include "HTMLBodyElement.h"
50#include "HTMLCanvasElement.h"
51#include "HTMLModelElement.h"
52#include "HTMLNames.h"
53#include "HTMLPlugInElement.h"
54#include "HTMLVideoElement.h"
55#include "InspectorInstrumentation.h"
56#include "LayerAncestorClippingStack.h"
57#include "LocalFrame.h"
58#include "LocalFrameView.h"
59#include "Logging.h"
60#include "Model.h"
61#include "NullGraphicsContext.h"
62#include "Page.h"
63#include "PathOperation.h"
64#include "PerformanceLoggingClient.h"
65#include "PluginViewBase.h"
66#include "ProgressTracker.h"
67#include "RemoteFrame.h"
68#include "RemoteFrameClient.h"
69#include "RenderAncestorIterator.h"
70#include "RenderBoxInlines.h"
71#include "RenderDescendantIterator.h"
72#include "RenderElementInlines.h"
73#include "RenderEmbeddedObject.h"
74#include "RenderFragmentContainer.h"
75#include "RenderFragmentedFlow.h"
76#include "RenderHTMLCanvas.h"
77#include "RenderImage.h"
78#include "RenderLayerCompositor.h"
79#include "RenderLayerInlines.h"
80#include "RenderLayerScrollableArea.h"
81#include "RenderMedia.h"
82#include "RenderModel.h"
83#include "RenderSVGHiddenContainer.h"
84#include "RenderSVGModelObject.h"
85#include "RenderVideo.h"
86#include "RenderView.h"
87#include "RenderViewTransitionCapture.h"
88#include "RotateTransformOperation.h"
89#include "SVGGraphicsElement.h"
90#include "ScaleTransformOperation.h"
91#include "ScrollingCoordinator.h"
92#include "Settings.h"
93#include "StyleResolver.h"
94#include "StyleTransformResolver.h"
95#include "Styleable.h"
96#include "TiledBacking.h"
97#include "ViewTransition.h"
98#include <wtf/SystemTracing.h>
99#include <wtf/TZoneMallocInlines.h>
100#include <wtf/text/MakeString.h>
101#include <wtf/text/TextStream.h>
102
103#if ENABLE(FULLSCREEN_API)(defined 1 && 1)
104#include "DocumentFullscreen.h"
105#endif
106
107#if PLATFORM(IOS_FAMILY)(defined WTF_PLATFORM_IOS_FAMILY && WTF_PLATFORM_IOS_FAMILY
)
108#include <wtf/RuntimeApplicationChecks.h>
109#endif
110
111#if PLATFORM(MAC)(defined 1 && 1)
112#include "LocalDefaultSystemAppearance.h"
113#endif
114
115#if ENABLE(THREADED_ANIMATIONS)(defined 1 && 1)
116#include "AcceleratedEffect.h"
117#include "AcceleratedEffectStack.h"
118#include "AcceleratedEffectValues.h"
119#include "KeyframeEffect.h"
120#include "KeyframeEffectStack.h"
121#include <wtf/WeakListHashSet.h>
122#endif
123
124#if ENABLE(MODEL_CONTEXT)(defined (0 || 0) && (0 || 0))
125#include "ModelContext.h"
126#endif
127
128namespace WebCore {
129
130WTF_MAKE_TZONE_ALLOCATED_IMPL(RenderLayerBacking)::bmalloc::api::HeapRef RenderLayerBacking::s_heapRef; const TZoneSpecification
RenderLayerBacking::s_heapSpec = { &RenderLayerBacking::
s_heapRef, TZoneSpecification::encodeSize<RenderLayerBacking
>(), TZoneSpecification::encodeAlignment<RenderLayerBacking
>(), TZoneSpecification::encodeCategory<RenderLayerBacking
>(), ::bmalloc::api::compactAllocationMode<RenderLayerBacking
>(), TZoneSpecification::encodeDescriptor<RenderLayerBacking
>(), }; void* RenderLayerBacking::operatorNewSlow(size_t size
) { if constexpr (::bmalloc::api::compactAllocationMode<RenderLayerBacking
>() == CompactAllocationMode::Compact) return ::bmalloc::api
::tzoneAllocateCompactSlow(size, s_heapSpec); return ::bmalloc
::api::tzoneAllocateNonCompactSlow(size, s_heapSpec); } using
__makeBtzoneMallocedInlineMacroSemicolonifier __attribute__(
(unused)) = int
;
131
132using namespace HTMLNames;
133
134CanvasCompositingStrategy canvasCompositingStrategy(const RenderObject& renderer)
135{
136 ASSERT(renderer.isRenderHTMLCanvas())((void)0);
137 RefPtr context = downcast<RenderHTMLCanvas>(renderer).canvasElement().renderingContext();
138 if (!context)
139 return CanvasPaintedToEnclosingLayer;
140 if (context->delegatesDisplay())
141 return CanvasAsLayerContents;
142 if (RefPtr context2D = dynamicDowncast<CanvasRenderingContext2DBase>(context)) {
143 if (context2D->isAccelerated())
144 return CanvasPaintedToLayer;
145 }
146 return CanvasPaintedToEnclosingLayer;
147}
148
149// This acts as a cache of what we know about what is painting into this RenderLayerBacking.
150class PaintedContentsInfo {
151public:
152 enum class ContentsType {
153 Unknown,
154 SimpleContainer,
155 DirectlyCompositedImage,
156 UnscaledBitmapOnly,
157 Painted,
158 };
159
160 PaintedContentsInfo(RenderLayerBacking& inBacking)
161 : m_backing(inBacking)
162 {
163 }
164
165#if HAVE(SUPPORT_HDR_DISPLAY)(defined 1 && 1)
166 void NODELETE[[clang::annotate_type("webkit.nodelete")]] setDetectsHDRContent()
167 {
168 m_hdrContent = RequestState::Unknown;
169 m_rendererHDRContent = RequestState::Unknown;
170 }
171#endif
172
173 void determinePaintsBoxDecorations();
174 bool paintsBoxDecorations()
175 {
176 determinePaintsBoxDecorations();
177 return m_boxDecorations == RequestState::True || m_boxDecorations == RequestState::Undetermined;
178 }
179
180
181 bool NODELETE[[clang::annotate_type("webkit.nodelete")]] isPaintsContentSatisfied() const
182 {
183#if HAVE(SUPPORT_HDR_DISPLAY)(defined 1 && 1)
184 if (m_hdrContent == RequestState::Unknown)
185 return false;
186#endif
187 return m_content != RequestState::Unknown;
188 }
189
190 void determinePaintsContent();
191 bool paintsContent()
192 {
193 determinePaintsContent();
194 return m_content == RequestState::True || m_content == RequestState::Undetermined;
195 }
196
197#if HAVE(SUPPORT_HDR_DISPLAY)(defined 1 && 1)
198 bool paintsHDRContent()
199 {
200 determinePaintsContent();
201 return m_hdrContent == RequestState::True;
202 }
203#endif
204
205 bool NODELETE[[clang::annotate_type("webkit.nodelete")]] isContentsTypeSatisfied() const
206 {
207#if HAVE(SUPPORT_HDR_DISPLAY)(defined 1 && 1)
208 if (m_rendererHDRContent == RequestState::Unknown)
209 return false;
210#endif
211 return m_contentsType != ContentsType::Unknown;
212 }
213
214 void determineContentsType();
215 bool isSimpleContainer()
216 {
217 determineContentsType();
218 return m_contentsType == ContentsType::SimpleContainer;
219 }
220
221 bool isDirectlyCompositedImage()
222 {
223 determineContentsType();
224 return m_contentsType == ContentsType::DirectlyCompositedImage;
225 }
226
227 bool isUnscaledBitmapOnly()
228 {
229 determineContentsType();
230 return m_contentsType == ContentsType::UnscaledBitmapOnly;
231 }
232
233#if HAVE(SUPPORT_HDR_DISPLAY)(defined 1 && 1)
234 bool rendererHasHDRContent() // FIXME: Why do we need this?
235 {
236 determineContentsType();
237 return m_rendererHDRContent == RequestState::True;
238 }
239#endif
240
241 RenderLayerBacking& m_backing;
242 RequestState m_boxDecorations { RequestState::Unknown };
243 RequestState m_content { RequestState::Unknown };
244#if HAVE(SUPPORT_HDR_DISPLAY)(defined 1 && 1)
245 RequestState m_hdrContent { RequestState::DontCare };
246 RequestState m_rendererHDRContent { RequestState::DontCare };
247#endif
248
249 ContentsType m_contentsType { ContentsType::Unknown };
250};
251
252void PaintedContentsInfo::determinePaintsBoxDecorations()
253{
254 if (m_boxDecorations != RequestState::Unknown)
255 return;
256
257 m_boxDecorations = m_backing.paintsBoxDecorations() ? RequestState::True : RequestState::False;
258}
259
260void PaintedContentsInfo::determinePaintsContent()
261{
262 if (isPaintsContentSatisfied())
263 return;
264
265 auto contentRequest = RenderLayer::PaintedContentRequest { };
266#if HAVE(SUPPORT_HDR_DISPLAY)(defined 1 && 1)
267 contentRequest.setHDRRequestState(m_hdrContent);
268#endif
269
270 m_backing.determinePaintsContent(contentRequest);
271 m_content = contentRequest.hasPaintedContent;
272#if HAVE(SUPPORT_HDR_DISPLAY)(defined 1 && 1)
273 m_hdrContent = contentRequest.hasHDRContent;
274#endif
275}
276
277void PaintedContentsInfo::determineContentsType()
278{
279 if (isContentsTypeSatisfied())
280 return;
281
282 if (m_backing.isSimpleContainerCompositingLayer(*this))
283 m_contentsType = ContentsType::SimpleContainer;
284 else if (m_backing.isDirectlyCompositedImage())
285 m_contentsType = ContentsType::DirectlyCompositedImage;
286 else if (m_backing.isUnscaledBitmapOnly())
287 m_contentsType = ContentsType::UnscaledBitmapOnly;
288 else
289 m_contentsType = ContentsType::Painted;
290
291#if HAVE(SUPPORT_HDR_DISPLAY)(defined 1 && 1)
292 if (m_rendererHDRContent == RequestState::Unknown)
293 m_rendererHDRContent = m_backing.rendererHasHDRContent() ? RequestState::True : RequestState::False;
294#endif
295}
296
297
298RenderLayerBacking::RenderLayerBacking(RenderLayer& layer)
299 : m_owningLayer(layer)
300{
301 if (layer.isRenderViewLayer()) {
302 m_isMainFrameRenderViewLayer = renderer().frame().isMainFrame();
303 m_isRootFrameRenderViewLayer = renderer().frame().isRootFrame();
304 m_isFrameLayerWithTiledBacking = renderer().page().chrome().client().shouldUseTiledBackingForFrameView(renderer().view().frameView());
305 }
306
307 createPrimaryGraphicsLayer();
308#if ENABLE(FULLSCREEN_API)(defined 1 && 1)
309 auto isFullsizeBackdrop = [](const RenderElement& renderer) -> bool {
310 auto& style = renderer.style();
311 if (style.pseudoElementType() != PseudoElementType::Backdrop || style.position() != PositionType::Fixed)
312 return false;
313
314 if (!style.transform().isNone() || !style.offsetPath().isNone() || !style.clip().isAuto() || Style::hasImageInAnyLayer(style.maskLayers()) || !style.maskBorderSource().isNone())
315 return false;
316
317 auto* box = dynamicDowncast<RenderBox>(renderer);
318 if (!box)
319 return false;
320
321 // Only use background layers on the fullscreen element's backdrop.
322 RefPtr documentFullscreen = box->document().fullscreenIfExists();
323 if (!documentFullscreen)
324 return false;
325 RefPtr fullscreenElement = documentFullscreen->fullscreenElement();
326 if (!fullscreenElement || !fullscreenElement->renderer() || fullscreenElement->renderer()->pseudoElementRenderer(PseudoElementType::Backdrop) != &renderer)
327 return false;
328
329 auto rendererRect = box->frameRect();
330 return rendererRect == box->view().frameRect();
331 };
332 setRequiresBackgroundLayer(isFullsizeBackdrop(layer.renderer()));
333#endif
334
335 if (auto* tiledBacking = this->tiledBacking()) {
336 tiledBacking->setIsInWindow(renderer().page().isInWindow());
337
338 if (m_isFrameLayerWithTiledBacking) {
339 tiledBacking->setScrollingPerformanceTestingEnabled(renderer().settings().scrollingPerformanceTestingEnabled());
340 adjustTiledBackingCoverage();
341 }
342 }
343
344 m_owningLayer.setAncestorsHaveDescendantNeedingEventRegionUpdate();
345}
346
347RenderLayerBacking::~RenderLayerBacking()
348{
349 // Note that m_owningLayer->backing() is null here.
350 updateAncestorClipping(false, nullptr);
351 updateDescendantClippingLayer(false);
352 clearOverflowControlsLayers();
353 updateForegroundLayer(false);
354 updateBackgroundLayer(false);
355 updateMaskingLayer(false, false);
356 updateScrollingLayers(false);
357
358 ASSERT(!m_viewportConstrainedNodeID)((void)0);
359 ASSERT(!m_scrollingNodeID)((void)0);
360 ASSERT(!m_frameHostingNodeID)((void)0);
361 ASSERT(!m_pluginHostingNodeID)((void)0);
362 ASSERT(!m_positioningNodeID)((void)0);
363
364 destroyGraphicsLayers();
365}
366
367void RenderLayerBacking::willBeDestroyed(OptionSet<UpdateBackingSharingFlags> flags)
368{
369 ASSERT(m_owningLayer.backing() == this)((void)0);
370 compositor().removeFromScrollCoordinatedLayers(m_owningLayer);
371
372 clearBackingSharingLayers(flags);
373}
374
375void RenderLayerBacking::willDestroyLayer(const GraphicsLayer* layer)
376{
377 if (layer && layer->type() == GraphicsLayer::Type::Normal && layer->tiledBacking())
378 compositor().layerTiledBackingUsageChanged(layer, false);
379}
380
381static void clearBackingSharingLayerProviders(InlineWeakKeyListHashSet<RenderLayer>& sharingLayers, const RenderLayer& providerLayer, OptionSet<UpdateBackingSharingFlags> flags)
382{
383 for (CheckedRef layer : sharingLayers | dereferenceView) {
384 if (layer->backingProviderLayer() == &providerLayer)
385 layer->setBackingProviderLayer(nullptr, flags);
386 }
387}
388
389void RenderLayerBacking::setBackingSharingLayers(InlineWeakKeyListHashSet<RenderLayer>&& sharingLayers)
390{
391 bool sharingLayersChanged = m_backingSharingLayers.computeSize() != sharingLayers.computeSize();
392 clearBackingSharingLayerProviders(m_backingSharingLayers, m_owningLayer, { UpdateBackingSharingFlags::DuringCompositingUpdate });
393
394 for (CheckedRef oldSharingLayer : m_backingSharingLayers | dereferenceView) {
395 if (!sharingLayers.contains(oldSharingLayer))
396 sharingLayersChanged = true;
397 }
398
399 if (sharingLayersChanged) {
400 if (!sharingLayers.isEmptyIgnoringNullReferences())
401 setRequiresOwnBackingStore(true);
402 }
403
404 auto oldSharingLayers = std::exchange(m_backingSharingLayers, WTF::move(sharingLayers));
405
406 for (CheckedRef layer : m_backingSharingLayers | dereferenceView)
407 layer->setBackingProviderLayer(&m_owningLayer, { UpdateBackingSharingFlags::DuringCompositingUpdate });
408}
409
410void RenderLayerBacking::removeBackingSharingLayer(RenderLayer& layer, OptionSet<UpdateBackingSharingFlags> flags)
411{
412 layer.setBackingProviderLayer(nullptr, flags);
413 m_backingSharingLayers.remove(layer);
414}
415
416void RenderLayerBacking::clearBackingSharingLayers(OptionSet<UpdateBackingSharingFlags> flags)
417{
418 clearBackingSharingLayerProviders(m_backingSharingLayers, m_owningLayer, flags);
419 m_backingSharingLayers.clear();
420}
421
422Ref<GraphicsLayer> RenderLayerBacking::createGraphicsLayer(const String& name, GraphicsLayer::Type layerType)
423{
424 auto* graphicsLayerFactory = renderer().page().chrome().client().graphicsLayerFactory();
425
426 auto graphicsLayer = GraphicsLayer::create(graphicsLayerFactory, *this, layerType);
427
428 graphicsLayer->setName(name);
429
430#if USE(CA)(defined 1 && 1)
431 graphicsLayer->setAcceleratesDrawing(compositor().acceleratedDrawingEnabled());
432#endif
433
434 if (renderer().isSVGLayerAwareRenderer() && renderer().document().settings().layerBasedSVGEngineEnabled())
435 graphicsLayer->setShouldUpdateRootRelativeScaleFactor(true);
436
437 return graphicsLayer;
438}
439
440void RenderLayerBacking::setUsesDisplayListDrawing(bool usesDisplayListDrawing)
441{
442 // Note that this only affects the primary layer.
443 if (usesDisplayListDrawing == m_graphicsLayer->usesDisplayListDrawing())
444 return;
445
446 m_graphicsLayer->setUsesDisplayListDrawing(usesDisplayListDrawing);
447 if (m_graphicsLayer->drawsContent())
448 m_graphicsLayer->setNeedsDisplay();
449}
450
451String RenderLayerBacking::displayListAsText(OptionSet<DisplayList::AsTextFlag> flags) const
452{
453 return m_graphicsLayer->displayListAsText(flags);
454}
455
456void RenderLayerBacking::setIsTrackingDisplayListReplay(bool isTrackingReplay)
457{
458 m_graphicsLayer->setIsTrackingDisplayListReplay(isTrackingReplay);
459}
460
461String RenderLayerBacking::replayDisplayListAsText(OptionSet<DisplayList::AsTextFlag> flags) const
462{
463 return m_graphicsLayer->replayDisplayListAsText(flags);
464}
465
466void RenderLayerBacking::tiledBackingUsageChanged(const GraphicsLayer* layer, bool usingTiledBacking)
467{
468 compositor().layerTiledBackingUsageChanged(layer, usingTiledBacking);
469}
470
471TiledBacking* RenderLayerBacking::tiledBacking() const
472{
473 return m_graphicsLayer->tiledBacking();
474}
475
476static TiledBacking::TileCoverage computePageTiledBackingCoverage(const RenderLayer& layer)
477{
478 // If the page is non-visible, don't incur the cost of keeping extra tiles for scrolling.
479 if (!layer.page().isVisible())
480 return TiledBacking::CoverageForVisibleArea;
481
482 auto& frameView = layer.renderer().view().frameView();
483
484 TiledBacking::TileCoverage tileCoverage = TiledBacking::CoverageForVisibleArea;
485 bool useMinimalTilesDuringLiveResize = frameView.inLiveResize();
486 if (frameView.speculativeTilingEnabled() && !useMinimalTilesDuringLiveResize) {
487 bool clipsToExposedRect = static_cast<bool>(frameView.viewExposedRect());
488 if (frameView.horizontalScrollbarMode() != ScrollbarMode::AlwaysOff || clipsToExposedRect)
489 tileCoverage |= TiledBacking::CoverageForHorizontalScrolling;
490
491 if (frameView.verticalScrollbarMode() != ScrollbarMode::AlwaysOff || clipsToExposedRect)
492 tileCoverage |= TiledBacking::CoverageForVerticalScrolling;
493 }
494 return tileCoverage;
495}
496
497static TiledBacking::TileCoverage computeOverflowTiledBackingCoverage(const RenderLayer& layer)
498{
499 // If the page is non-visible, don't incur the cost of keeping extra tiles for scrolling.
500 if (!layer.page().isVisible())
501 return TiledBacking::CoverageForVisibleArea;
502
503 auto& frameView = layer.renderer().view().frameView();
504
505 TiledBacking::TileCoverage tileCoverage = TiledBacking::CoverageForVisibleArea;
506 bool useMinimalTilesDuringLiveResize = frameView.inLiveResize();
507 if (!useMinimalTilesDuringLiveResize) {
508 if (auto* scrollableArea = layer.scrollableArea()) {
509 if (scrollableArea->hasScrollableHorizontalOverflow())
510 tileCoverage |= TiledBacking::CoverageForHorizontalScrolling;
511
512 if (scrollableArea->hasScrollableVerticalOverflow())
513 tileCoverage |= TiledBacking::CoverageForVerticalScrolling;
514 }
515 }
516 return tileCoverage;
517}
518
519void RenderLayerBacking::adjustTiledBackingCoverage()
520{
521 if (m_isFrameLayerWithTiledBacking) {
522 auto tileCoverage = computePageTiledBackingCoverage(m_owningLayer);
523 if (auto* tiledBacking = this->tiledBacking())
524 tiledBacking->setTileCoverage(tileCoverage);
525 }
526
527 if (m_owningLayer.hasCompositedScrollableOverflow() && m_scrolledContentsLayer) {
528 auto tileCoverage = computeOverflowTiledBackingCoverage(m_owningLayer);
529 m_scrolledContentsLayer->setTileCoverage(tileCoverage);
530 }
531}
532
533void RenderLayerBacking::setTiledBackingHasMargins(BoxSideSet margins)
534{
535 if (!m_isFrameLayerWithTiledBacking)
536 return;
537
538 tiledBacking()->setHasMargins(margins.contains(BoxSide::Top), margins.contains(BoxSide::Bottom), margins.contains(BoxSide::Left), margins.contains(BoxSide::Right));
539}
540
541void RenderLayerBacking::updateDebugIndicators(bool showBorder, bool showRepaintCounter)
542{
543 m_graphicsLayer->setShowDebugBorder(showBorder);
544 m_graphicsLayer->setShowRepaintCounter(showRepaintCounter);
545
546 // m_viewportAnchorLayer can't show layer borders because it's a structural layer.
547
548 if (m_viewportClippingLayer)
549 m_viewportClippingLayer->setShowDebugBorder(showBorder);
550
551 if (m_ancestorClippingStack) {
552 for (auto& entry : m_ancestorClippingStack->stack())
553 entry.clippingLayer->setShowDebugBorder(showBorder);
554 }
555
556 if (m_foregroundLayer) {
557 m_foregroundLayer->setShowDebugBorder(showBorder);
558 m_foregroundLayer->setShowRepaintCounter(showRepaintCounter);
559 }
560
561 if (m_contentsContainmentLayer)
562 m_contentsContainmentLayer->setShowDebugBorder(showBorder);
563
564 if (m_childContainmentLayer) {
565 m_childContainmentLayer->setShowDebugBorder(showBorder);
566 m_childContainmentLayer->setShowFrameProcessBorders(renderer().settings().showFrameProcessBorders() && m_owningLayer.isRenderViewLayer());
567 }
568
569 if (m_backgroundLayer) {
570 m_backgroundLayer->setShowDebugBorder(showBorder);
571 m_backgroundLayer->setShowRepaintCounter(showRepaintCounter);
572 }
573
574 if (m_maskLayer) {
575 m_maskLayer->setShowDebugBorder(showBorder);
576 m_maskLayer->setShowRepaintCounter(showRepaintCounter);
577 }
578
579 if (m_layerForHorizontalScrollbar)
580 m_layerForHorizontalScrollbar->setShowDebugBorder(showBorder);
581
582 if (m_layerForVerticalScrollbar)
583 m_layerForVerticalScrollbar->setShowDebugBorder(showBorder);
584
585 if (m_layerForScrollCorner)
586 m_layerForScrollCorner->setShowDebugBorder(showBorder);
587
588 if (m_scrollContainerLayer)
589 m_scrollContainerLayer->setShowDebugBorder(showBorder);
590
591 if (m_scrolledContentsLayer) {
592 m_scrolledContentsLayer->setShowDebugBorder(showBorder);
593 m_scrolledContentsLayer->setShowRepaintCounter(showRepaintCounter);
594 }
595
596 if (m_overflowControlsContainer)
597 m_overflowControlsContainer->setShowDebugBorder(showBorder);
598}
599
600void RenderLayerBacking::createPrimaryGraphicsLayer()
601{
602 String layerName = m_owningLayer.name();
603 const unsigned maxLayerNameLength = 100;
604 if (layerName.length() > maxLayerNameLength)
605 layerName = makeString(StringView(layerName).left(maxLayerNameLength), "..."_s);
606 m_graphicsLayer = createGraphicsLayer(layerName, m_isFrameLayerWithTiledBacking ? GraphicsLayer::Type::PageTiledBacking : GraphicsLayer::Type::Normal);
607
608 if (m_isFrameLayerWithTiledBacking) {
609 m_childContainmentLayer = createGraphicsLayer("Page TiledBacking containment"_s);
610 m_graphicsLayer->addChild(*m_childContainmentLayer);
611 }
612
613#if !PLATFORM(IOS_FAMILY)(defined WTF_PLATFORM_IOS_FAMILY && WTF_PLATFORM_IOS_FAMILY
)
614 if (m_isMainFrameRenderViewLayer)
615 m_graphicsLayer->setContentsOpaque(!compositor().viewHasTransparentBackground());
616 // Page scale is applied above the RenderView on iOS.
617 if (m_isRootFrameRenderViewLayer)
618 m_graphicsLayer->setAppliesPageScale();
619#endif
620
621#if USE(CA)(defined 1 && 1)
622 if (!compositor().acceleratedDrawingEnabled() && renderer().isRenderHTMLCanvas()) {
623 const RefPtr canvas = downcast<HTMLCanvasElement>(renderer().element());
624 if (canvas->shouldAccelerate())
625 m_graphicsLayer->setAcceleratesDrawing(true);
626 }
627#endif
628 auto& style = renderer().style();
629 updateOpacity(style);
630 updateTransform(style);
631 updateFilters(style);
632 updateBackdropFilters(style);
633#if HAVE(CORE_MATERIAL)(defined 1 && 1)
634 updateAppleVisualEffect(style);
635#endif
636 updateBackdropRoot();
637 updateBlendMode(style);
638#if ENABLE(VIDEO)(defined 1 && 1)
639 updateVideoGravity(style);
640#endif
641 updateContentsScalingFilters(style);
642}
643
644bool RenderLayerBacking::shouldSetContentsDisplayDelegate() const
645{
646 if (!renderer().isRenderHTMLCanvas())
647 return false;
648
649 return canvasCompositingStrategy(renderer()) == CanvasAsLayerContents;
650}
651
652#if PLATFORM(IOS_FAMILY)(defined WTF_PLATFORM_IOS_FAMILY && WTF_PLATFORM_IOS_FAMILY
)
653bool RenderLayerBacking::needsIOSDumpRenderTreeMainFrameRenderViewLayerIsAlwaysOpaqueHack(const GraphicsLayer& layer) const
654{
655 if (m_isMainFrameRenderViewLayer && WTF::CocoaApplication::isDumpRenderTree()) {
656 // In iOS WebKit1 the main frame's RenderView layer is always transparent. We lie that it is opaque so that
657 // internals.layerTreeAsText() tests succeed.
658 ASSERT_UNUSED(layer, !layer.contentsOpaque())((void)layer);
659 return true;
660 }
661 return false;
662}
663#endif
664
665void RenderLayerBacking::destroyGraphicsLayers()
666{
667 if (m_graphicsLayer) {
668 m_graphicsLayer->setMaskLayer(nullptr);
669 m_graphicsLayer->setReplicatedByLayer(nullptr);
670 willDestroyLayer(m_graphicsLayer.get());
671 }
672
673 GraphicsLayer::clear(m_maskLayer);
674
675 if (m_ancestorClippingStack)
676 removeClippingStackLayers(*m_ancestorClippingStack);
677
678 if (m_overflowControlsHostLayerAncestorClippingStack)
679 removeClippingStackLayers(*m_overflowControlsHostLayerAncestorClippingStack);
680
681 GraphicsLayer::unparentAndClear(m_transformFlatteningLayer);
682 GraphicsLayer::unparentAndClear(m_viewportAnchorLayer);
683 GraphicsLayer::unparentAndClear(m_viewportClippingLayer);
684 GraphicsLayer::unparentAndClear(m_contentsContainmentLayer);
685 GraphicsLayer::unparentAndClear(m_foregroundLayer);
686 GraphicsLayer::unparentAndClear(m_backgroundLayer);
687 GraphicsLayer::unparentAndClear(m_childContainmentLayer);
688 GraphicsLayer::unparentAndClear(m_scrollContainerLayer);
689 GraphicsLayer::unparentAndClear(m_scrolledContentsLayer);
690 GraphicsLayer::unparentAndClear(m_graphicsLayer);
691}
692
693static LayoutRect scrollContainerLayerBox(const RenderBox& renderBox)
694{
695 return renderBox.paddingBoxRect();
696}
697
698static LayoutRect clippingLayerBox(const RenderLayerModelObject& renderer)
699{
700 LayoutRect result = LayoutRect::infiniteRect();
701 if (renderer.hasNonVisibleOverflow()) {
702 if (CheckedPtr box = dynamicDowncast<RenderBox>(renderer))
703 result = box->overflowClipRect({ });
704 else if (CheckedPtr modelObject = dynamicDowncast<RenderSVGModelObject>(renderer))
705 result = modelObject->overflowClipRect({ });
706 }
707
708 if (renderer.hasClip()) {
709 if (auto* box = dynamicDowncast<RenderBox>(renderer))
710 result.intersect(box->clipRect({ }));
711 }
712
713 return result;
714}
715
716static LayoutRect overflowControlsHostLayerRect(const RenderBox& renderBox)
717{
718 return renderBox.paddingBoxRectIncludingScrollbar();
719}
720
721void RenderLayerBacking::updateOpacity(const RenderStyle& style)
722{
723 m_graphicsLayer->setOpacity(compositingOpacity(style.opacity().value.value));
724}
725
726void RenderLayerBacking::updateTransform(const RenderStyle& style)
727{
728 TransformationMatrix t;
729 if (renderer().effectiveCapturedInViewTransition()) {
730 if (RefPtr activeViewTransition = renderer().document().activeViewTransition()) {
731 if (CheckedPtr viewTransitionCapture = activeViewTransition->viewTransitionNewPseudoForCapturedElement(renderer())) {
732 t.scaleNonUniform(viewTransitionCapture->scale().width(), viewTransitionCapture->scale().height());
733 t.translateRight(viewTransitionCapture->captureContentInset().x(), viewTransitionCapture->captureContentInset().y());
734 }
735 if (m_owningLayer.isRenderViewLayer()) {
736 auto scrollPosition = renderer().view().frameView().scrollPosition();
737 t.translate(-scrollPosition.x(), -scrollPosition.y());
738 }
739 }
740 } else if (m_owningLayer.isTransformed())
741 m_owningLayer.updateTransformFromStyle(t, style, Style::TransformResolver::individualTransformOperations);
742
743 if (m_contentsContainmentLayer) {
744 m_contentsContainmentLayer->setTransform(t);
745 m_graphicsLayer->setTransform({ });
746 } else
747 m_graphicsLayer->setTransform(t);
748}
749
750void RenderLayerBacking::updateChildrenTransformAndAnchorPoint(const LayoutRect& primaryGraphicsLayerRect, LayoutSize offsetFromParentGraphicsLayer)
751{
752 auto defaultAnchorPoint = FloatPoint3D { 0.5, 0.5, 0 };
753
754 if (m_owningLayer.isRenderViewLayer() || renderer().effectiveCapturedInViewTransition())
755 defaultAnchorPoint = { };
756
757 if (!renderer().hasTransformRelatedProperty() || renderer().effectiveCapturedInViewTransition()) {
758 m_graphicsLayer->setAnchorPoint(defaultAnchorPoint);
759 if (m_contentsContainmentLayer)
760 m_contentsContainmentLayer->setAnchorPoint(defaultAnchorPoint);
761
762 if (m_childContainmentLayer)
763 m_childContainmentLayer->setAnchorPoint(defaultAnchorPoint);
764
765 if (m_scrollContainerLayer)
766 m_scrollContainerLayer->setAnchorPoint(defaultAnchorPoint);
767
768 if (m_scrolledContentsLayer)
769 m_scrolledContentsLayer->setPreserves3D(false);
770 return;
771 }
772
773 const auto deviceScaleFactor = this->deviceScaleFactor();
774 auto transformOrigin = m_owningLayer.transformOriginPixelSnappedIfNeeded();
775 auto layerOffset = roundPointToDevicePixels(toLayoutPoint(offsetFromParentGraphicsLayer), deviceScaleFactor);
776 auto anchor = FloatPoint3D {
777 primaryGraphicsLayerRect.width() ? ((layerOffset.x() - primaryGraphicsLayerRect.x()) + transformOrigin.x()) / primaryGraphicsLayerRect.width() : 0.5f,
778 primaryGraphicsLayerRect.height() ? ((layerOffset.y() - primaryGraphicsLayerRect.y())+ transformOrigin.y()) / primaryGraphicsLayerRect.height() : 0.5f,
779 transformOrigin.z()
780 };
781
782 if (m_contentsContainmentLayer)
783 m_contentsContainmentLayer->setAnchorPoint(anchor);
784 else
785 m_graphicsLayer->setAnchorPoint(anchor);
786
787 auto removeChildrenTransformFromLayers = [&](GraphicsLayer* layerToIgnore = nullptr) {
788 RefPtr clippingLayer = this->clippingLayer();
789 if (clippingLayer && clippingLayer != layerToIgnore) {
790 clippingLayer->setChildrenTransform({ });
791 clippingLayer->setAnchorPoint(defaultAnchorPoint);
792 }
793
794 if (m_scrollContainerLayer && m_scrollContainerLayer != layerToIgnore) {
795 m_scrollContainerLayer->setChildrenTransform({ });
796 m_scrollContainerLayer->setAnchorPoint(defaultAnchorPoint);
797 m_scrolledContentsLayer->setPreserves3D(false);
798 }
799
800 if (m_graphicsLayer != layerToIgnore)
801 m_graphicsLayer->setChildrenTransform({ });
802 };
803
804 if (renderer().style().perspective().isNone()) {
805 removeChildrenTransformFromLayers();
806 return;
807 }
808
809 auto layerForChildrenTransform = [&]() -> std::tuple<GraphicsLayer*, FloatRect> {
810 if (m_scrollContainerLayer) {
811 // Scroll container layers are only created for RenderBox derived renderers.
812 return std::make_tuple(m_scrollContainerLayer.get(), scrollContainerLayerBox(downcast<RenderBox>(renderer())));
813 }
814 if (RefPtr layer = clippingLayer())
815 return std::make_tuple(layer, clippingLayerBox(renderer()));
816
817 return std::make_tuple(m_graphicsLayer.get(), renderer().transformReferenceBoxRect());
818 };
819
820 auto [layerForPerspective, layerForPerspectiveRect] = layerForChildrenTransform();
821 if (layerForPerspective != m_graphicsLayer) {
822 // If we have scrolling layers, we need the children transform on m_scrollContainerLayer to
823 // affect children of m_scrolledContentsLayer, so set setPreserves3D(true).
824 if (layerForPerspective == m_scrollContainerLayer)
825 m_scrolledContentsLayer->setPreserves3D(true);
826
827 auto perspectiveAnchorPoint = FloatPoint3D {
828 layerForPerspectiveRect.width() ? (transformOrigin.x() - layerForPerspectiveRect.x()) / layerForPerspectiveRect.width() : 0.5f,
829 layerForPerspectiveRect.height() ? (transformOrigin.y() - layerForPerspectiveRect.y()) / layerForPerspectiveRect.height() : 0.5f,
830 transformOrigin.z()
831 };
832
833 layerForPerspective->setAnchorPoint(perspectiveAnchorPoint);
834 }
835
836 layerForPerspective->setChildrenTransform(m_owningLayer.perspectiveTransform());
837 removeChildrenTransformFromLayers(layerForPerspective);
838}
839
840void RenderLayerBacking::updateFilters(const RenderStyle& style)
841{
842 m_canCompositeFilters = !style.filter().hasReferenceFilter() && m_graphicsLayer->setFilters(Style::toPlatform(style.filter(), style));
843}
844
845void RenderLayerBacking::updateBackdropFilters(const RenderStyle& style)
846{
847 m_canCompositeBackdropFilters = !style.backdropFilter().hasReferenceFilter() && m_graphicsLayer->setBackdropFilters(Style::toPlatform(style.backdropFilter(), style));
848}
849
850void RenderLayerBacking::updateBackdropFiltersGeometry()
851{
852 bool shouldUpdateBackdropFiltersGeometry = m_canCompositeBackdropFilters;
853#if HAVE(CORE_MATERIAL)(defined 1 && 1)
854 shouldUpdateBackdropFiltersGeometry |= renderer().hasAppleVisualEffectRequiringBackdropFilter();
855#endif
856 if (!shouldUpdateBackdropFiltersGeometry)
857 return;
858
859 CheckedPtr renderBox = dynamicDowncast<RenderBox>(this->renderer());
860 if (!renderBox)
861 return;
862
863 FloatRoundedRect backdropFiltersRect;
864 if (renderBox->style().border().hasBorderRadius() && !renderBox->hasClip()) {
865 auto borderShape = BorderShape::shapeForBorderRect(renderBox->style(), renderBox->borderBoxRect());
866 auto roundedBoxRect = borderShape.deprecatedRoundedRect();
867 roundedBoxRect.move(contentOffsetInCompositingLayer());
868 backdropFiltersRect = roundedBoxRect.pixelSnappedRoundedRectForPainting(deviceScaleFactor());
869 } else {
870 auto boxRect = renderBox->borderBoxRect();
871 if (renderBox->hasClip())
872 boxRect.intersect(renderBox->clipRect({ }));
873 boxRect.move(contentOffsetInCompositingLayer());
874 backdropFiltersRect = FloatRoundedRect(snapRectToDevicePixels(boxRect, deviceScaleFactor()));
875 }
876
877 m_graphicsLayer->setBackdropFiltersRect(backdropFiltersRect);
878}
879
880bool RenderLayerBacking::updateBackdropRoot()
881{
882 // Don't try to make the RenderView's layer a backdrop root if it's going to
883 // paint into the window since it won't work (WebKitLegacy only).
884 bool willBeBackdropRoot = m_owningLayer.isBackdropRoot() && !paintsIntoWindow();
885
886 // If the RenderView is opaque, then that will occlude any pixels behind it and we don't need
887 // to isolate it as a backdrop root.
888 //
889 // Always allow for the main frame so that clients can intentionally allow backdrop blending outside of the webview by setting it to transparent.
890 if (m_owningLayer.isRenderViewLayer() && (m_isMainFrameRenderViewLayer || !compositor().viewHasTransparentBackground()))
891 willBeBackdropRoot = false;
892
893 if (m_graphicsLayer->isBackdropRoot() == willBeBackdropRoot)
894 return false;
895
896 m_graphicsLayer->setIsBackdropRoot(willBeBackdropRoot);
897 return true;
898}
899
900void RenderLayerBacking::updateBlendMode(const RenderStyle& style)
901{
902 // FIXME: where is the blend mode updated when m_ancestorClippingStacks come and go?
903 if (m_ancestorClippingStack) {
904 m_ancestorClippingStack->stack().first().clippingLayer->setBlendMode(style.blendMode());
905 m_graphicsLayer->setBlendMode(BlendMode::Normal);
906 } else
907 m_graphicsLayer->setBlendMode(style.blendMode());
908}
909
910#if ENABLE(VIDEO)(defined 1 && 1)
911void RenderLayerBacking::updateVideoGravity(const RenderStyle& style)
912{
913 if (!renderer().isRenderVideo())
914 return;
915
916 MediaPlayerVideoGravity videoGravity;
917 switch (style.objectFit()) {
918 case ObjectFit::None:
919 case ObjectFit::ScaleDown:
920 // FIXME: Add support for "None" and "ScaleDown" with video gravity modes
921 [[fallthrough]];
922 case ObjectFit::Fill:
923 videoGravity = MediaPlayerVideoGravity::Resize;
924 break;
925 case ObjectFit::Contain:
926 videoGravity = MediaPlayerVideoGravity::ResizeAspect;
927 break;
928 case ObjectFit::Cover:
929 videoGravity = MediaPlayerVideoGravity::ResizeAspectFill;
930 break;
931 }
932 m_graphicsLayer->setVideoGravity(videoGravity);
933}
934#endif
935
936void RenderLayerBacking::updateContentsScalingFilters(const RenderStyle& style)
937{
938 if (!renderer().isRenderHTMLCanvas() || canvasCompositingStrategy(renderer()) != CanvasAsLayerContents)
939 return;
940 auto minificationFilter = GraphicsLayer::ScalingFilter::Linear;
941 auto magnificationFilter = GraphicsLayer::ScalingFilter::Linear;
942 switch (style.imageRendering()) {
943 case ImageRendering::CrispEdges:
944 case ImageRendering::Pixelated:
945 // FIXME: In order to match other code-paths, we treat these the same.
946 minificationFilter = GraphicsLayer::ScalingFilter::Nearest;
947 magnificationFilter = GraphicsLayer::ScalingFilter::Nearest;
948 break;
949 default:
950 break;
951 }
952 m_graphicsLayer->setContentsMinificationFilter(minificationFilter);
953 m_graphicsLayer->setContentsMagnificationFilter(magnificationFilter);
954}
955
956#if HAVE(CORE_MATERIAL)(defined 1 && 1)
957void RenderLayerBacking::updateAppleVisualEffect(const RenderStyle& style)
958{
959 AppleVisualEffectData visualEffectData;
960
961 visualEffectData.effect = style.appleVisualEffect();
962 visualEffectData.contextEffect = style.usedAppleVisualEffectForSubtree();
963 visualEffectData.colorScheme = renderer().document().useDarkAppearance(&style) ? AppleVisualEffectData::ColorScheme::Dark : AppleVisualEffectData::ColorScheme::Light;
964
965#if HAVE(MATERIAL_HOSTING)(defined HAVE_MATERIAL_HOSTING && HAVE_MATERIAL_HOSTING
)
966 if (appleVisualEffectIsHostedMaterial(style.appleVisualEffect())) {
967 if (CheckedPtr renderBox = dynamicDowncast<RenderBox>(renderer())) {
968 if (renderBox->style().border().hasBorderRadius()) {
969 auto borderShape = BorderShape::shapeForBorderRect(renderBox->style(), renderBox->borderBoxRect());
970 auto roundedBoxRect = borderShape.deprecatedRoundedRect();
971 roundedBoxRect.move(contentOffsetInCompositingLayer());
972 visualEffectData.borderRect = roundedBoxRect.pixelSnappedRoundedRectForPainting(deviceScaleFactor());
973 }
974 }
975 }
976#endif
977
978 m_graphicsLayer->setAppleVisualEffectData(visualEffectData);
979}
980#endif
981
982static bool NODELETE[[clang::annotate_type("webkit.nodelete")]] layerOrAncestorIsTransformedOrUsingCompositedScrolling(RenderLayer& layer)
983{
984 for (auto* curr = &layer; curr; curr = curr->parent()) {
985 if (curr->isTransformed() || curr->hasCompositedScrollableOverflow())
986 return true;
987 }
988
989 return false;
990}
991
992bool RenderLayerBacking::shouldClipCompositedBounds() const
993{
994#if !PLATFORM(IOS_FAMILY)(defined WTF_PLATFORM_IOS_FAMILY && WTF_PLATFORM_IOS_FAMILY
)
995 // Scrollbar layers use this layer for relative positioning, so don't clip.
996 if (layerForHorizontalScrollbar() || layerForVerticalScrollbar())
997 return false;
998#endif
999
1000 if (renderer().effectiveCapturedInViewTransition())
1001 return false;
1002 if (renderer().style().pseudoElementType() == PseudoElementType::ViewTransitionNew)
1003 return false;
1004
1005 if (m_isFrameLayerWithTiledBacking)
1006 return false;
1007
1008 if (layerOrAncestorIsTransformedOrUsingCompositedScrolling(m_owningLayer))
1009 return false;
1010
1011 return true;
1012}
1013
1014static bool hasNonZeroTransformOrigin(const RenderLayerModelObject& renderer)
1015{
1016 auto& style = renderer.style();
1017 auto fixedTransformOriginX = style.transformOriginX().tryFixed();
1018 auto fixedTransformOriginY = style.transformOriginY().tryFixed();
1019 return (fixedTransformOriginX && !fixedTransformOriginX->isZero())
1020 || (fixedTransformOriginY && !fixedTransformOriginY->isZero());
1021}
1022
1023bool RenderLayerBacking::updateCompositedBounds()
1024{
1025 LayoutRect layerBounds = m_owningLayer.calculateLayerBounds(&m_owningLayer, { }, RenderLayer::defaultCalculateLayerBoundsFlags() | RenderLayer::ExcludeHiddenDescendants | RenderLayer::DontConstrainForMask);
1026 // Clip to the size of the document or enclosing overflow-scroll layer.
1027 // If this or an ancestor is transformed, we can't currently compute the correct rect to intersect with.
1028 // We'd need RenderObject::convertContainerToLocalQuad(), which doesn't yet exist.
1029 if (shouldClipCompositedBounds()) {
1030 auto& view = renderer().view();
1031 CheckedPtr rootLayer = view.layer();
1032
1033 LayoutRect clippingBounds;
1034 if (renderer().isFixedPositioned() && renderer().container() == &view)
1035 clippingBounds = view.frameView().rectForFixedPositionLayout();
1036 else
1037 clippingBounds = view.unscaledDocumentRect();
1038
1039 if (&m_owningLayer != rootLayer)
1040 clippingBounds.intersect(m_owningLayer.backgroundClipRect(RenderLayer::ClipRectsContext(rootLayer, AbsoluteClipRects)).rect()); // FIXME: Incorrect for CSS regions.
1041
1042 LayoutPoint delta = m_owningLayer.convertToLayerCoords(rootLayer, LayoutPoint(), RenderLayer::AdjustForColumns);
1043 clippingBounds.move(-delta.x(), -delta.y());
1044
1045 layerBounds.intersect(clippingBounds);
1046 }
1047
1048 // If the backing provider has overflow:clip, we know all sharing layers are affected by the clip because they are containing-block descendants.
1049 if (!renderer().hasNonVisibleOverflow()) {
1050 for (CheckedRef layer : m_backingSharingLayers | dereferenceView) {
1051 CheckedPtr boundsRootLayer = &m_owningLayer;
1052 ASSERT(layer->isDescendantOf(m_owningLayer))((void)0);
1053 auto offset = layer->offsetFromAncestor(&m_owningLayer);
1054 auto bounds = layer->calculateLayerBounds(boundsRootLayer, offset, RenderLayer::defaultCalculateLayerBoundsFlags() | RenderLayer::ExcludeHiddenDescendants | RenderLayer::DontConstrainForMask);
1055 layerBounds.unite(bounds);
1056 }
1057 }
1058
1059 // If the element has a transform-origin that has fixed lengths, and the renderer has zero size,
1060 // then we need to ensure that the compositing layer has non-zero size so that we can apply
1061 // the transform-origin via the GraphicsLayer anchorPoint (which is expressed as a fractional value).
1062 if (layerBounds.isEmpty() && (hasNonZeroTransformOrigin(renderer()) || !renderer().style().perspective().isNone())) {
1063 layerBounds.setWidth(1);
1064 layerBounds.setHeight(1);
1065 m_artificiallyInflatedBounds = true;
1066 } else
1067 m_artificiallyInflatedBounds = false;
1068
1069 return setCompositedBounds(layerBounds);
1070}
1071
1072void RenderLayerBacking::updateAllowsBackingStoreDetaching(bool allowDetachingForFixed)
1073{
1074 auto setAllowsBackingStoreDetaching = [&](bool allowDetaching) {
1075 if (m_graphicsLayer->allowsBackingStoreDetaching() == allowDetaching)
1076 return;
1077
1078 // isDirectlyCompositedImage depends on this value
1079 m_owningLayer.setNeedsCompositingConfigurationUpdate();
1080
1081 m_graphicsLayer->setAllowsBackingStoreDetaching(allowDetaching);
1082 if (m_foregroundLayer)
1083 m_foregroundLayer->setAllowsBackingStoreDetaching(allowDetaching);
1084 if (m_backgroundLayer)
1085 m_backgroundLayer->setAllowsBackingStoreDetaching(allowDetaching);
1086 if (m_scrolledContentsLayer)
1087 m_scrolledContentsLayer->setAllowsBackingStoreDetaching(allowDetaching);
1088 };
1089
1090 if (!m_owningLayer.behavesAsFixed()) {
1091 setAllowsBackingStoreDetaching(true);
1092 return;
1093 }
1094
1095 setAllowsBackingStoreDetaching(allowDetachingForFixed);
1096}
1097
1098void RenderLayerBacking::updateAfterWidgetResize()
1099{
1100 CheckedPtr renderWidget = dynamicDowncast<RenderWidget>(renderer());
1101 if (!renderWidget)
1102 return;
1103
1104 if (auto* innerCompositor = RenderLayerCompositor::frameContentsCompositor(*renderWidget)) {
1105 innerCompositor->frameViewDidChangeSize();
1106 auto snappedContentOrigin = roundPointToDevicePixels(contentsBox().location(), deviceScaleFactor());
1107 innerCompositor->frameViewDidChangeLocation(snappedContentOrigin);
1108 }
1109
1110 if (RefPtr contentsLayer = layerForContents())
1111 contentsLayer->setPosition(flooredIntPoint(contentsBox().location()));
1112}
1113
1114void RenderLayerBacking::updateAfterLayout(bool needsClippingUpdate, bool needsFullRepaint)
1115{
1116 LOG_WITH_STREAM(Compositing, stream << "RenderLayerBacking::updateAfterLayout (layer " << &m_owningLayer << " needsClippingUpdate " << needsClippingUpdate << " needsFullRepaint " << needsFullRepaint)((void)0);
1117
1118 // This is the main trigger for layout changing layer geometry, but we have to do the work again in updateBackingAndHierarchy()
1119 // when we know the final compositing hierarchy. We can't just set dirty bits from RenderLayer::setSize() because that doesn't
1120 // take overflow into account.
1121 if (updateCompositedBounds()) {
1122 m_owningLayer.setNeedsCompositingGeometryUpdate();
1123 // This layer's geometry affects those of its children.
1124 m_owningLayer.setChildrenNeedCompositingGeometryUpdate();
1125 m_owningLayer.setSubsequentLayersNeedCompositingRequirementsTraversal();
1126 } else if (needsClippingUpdate) {
1127 m_owningLayer.setNeedsCompositingConfigurationUpdate();
1128 m_owningLayer.setNeedsCompositingGeometryUpdate();
1129 }
1130
1131 if (needsFullRepaint && canIssueSetNeedsDisplay())
1132 setContentsNeedDisplay();
1133}
1134
1135// This can only update things that don't require up-to-date layout.
1136void RenderLayerBacking::updateConfigurationAfterStyleChange()
1137{
1138 updateMaskingLayer(renderer().hasMask(), renderer().hasClipPath());
1139
1140 if (m_owningLayer.hasReflection()) {
1141 if (m_owningLayer.reflectionLayer()->backing()) {
1142 RefPtr reflectionLayer = m_owningLayer.reflectionLayer()->backing()->graphicsLayer();
1143 m_graphicsLayer->setReplicatedByLayer(WTF::move(reflectionLayer));
1144 }
1145 } else
1146 m_graphicsLayer->setReplicatedByLayer(nullptr);
1147
1148 // FIXME: do we care if opacity is animating?
1149 auto& style = renderer().style();
1150 updateOpacity(style);
1151 updateFilters(style);
1152
1153 updateBackdropFilters(style);
1154#if HAVE(CORE_MATERIAL)(defined 1 && 1)
1155 updateAppleVisualEffect(style);
1156#endif
1157 updateBackdropRoot();
1158 updateBlendMode(style);
1159 updateContentsScalingFilters(style);
1160
1161#if ENABLE(VIDEO)(defined 1 && 1)
1162 updateVideoGravity(style);
1163#endif
1164}
1165
1166bool RenderLayerBacking::updateConfiguration(const RenderLayer* compositingAncestor)
1167{
1168 ASSERT(!m_owningLayer.normalFlowListDirty())((void)0);
1169 ASSERT(!m_owningLayer.zOrderListsDirty())((void)0);
1170 ASSERT(!renderer().view().needsLayout())((void)0);
1171
1172 bool layerConfigChanged = false;
1173 auto& compositor = this->compositor();
1174
1175 if (updateTransformFlatteningLayer(compositingAncestor))
1176 layerConfigChanged = true;
1177
1178 if (updateViewportConstrainedSublayers(compositor.viewportConstrainedSublayers(m_owningLayer, compositingAncestor)))
1179 layerConfigChanged = true;
1180
1181 setBackgroundLayerPaintsFixedRootBackground(compositor.needsFixedRootBackgroundLayer(m_owningLayer));
1182
1183 if (updateBackgroundLayer(m_backgroundLayerPaintsFixedRootBackground || m_requiresBackgroundLayer))
1184 layerConfigChanged = true;
1185
1186 if (updateForegroundLayer(compositor.needsContentsCompositingLayer(m_owningLayer)))
1187 layerConfigChanged = true;
1188
1189 bool needsDescendantsClippingLayer = false;
1190 bool usesCompositedScrolling = m_owningLayer.hasCompositedScrollableOverflow();
1191
1192 if (usesCompositedScrolling) {
1193 // If it's scrollable, it has to be a box.
1194 auto& renderBox = downcast<RenderBox>(renderer());
1195 auto borderShape = BorderShape::shapeForBorderRect(renderBox.style(), renderBox.borderBoxRect());
1196 FloatRoundedRect contentsClippingRect = borderShape.deprecatedPixelSnappedInnerRoundedRect(deviceScaleFactor());
1197 needsDescendantsClippingLayer = contentsClippingRect.isRounded();
1198 } else
1199 needsDescendantsClippingLayer = RenderLayerCompositor::clipsCompositingDescendants(m_owningLayer);
1200
1201 if (updateScrollingLayers(usesCompositedScrolling))
1202 layerConfigChanged = true;
1203
1204 if (updateDescendantClippingLayer(needsDescendantsClippingLayer))
1205 layerConfigChanged = true;
1206
1207 ASSERT(compositingAncestor == m_owningLayer.ancestorCompositingLayer())((void)0);
1208 if (updateAncestorClipping(compositor.clippedByAncestor(m_owningLayer, compositingAncestor), compositingAncestor))
1209 layerConfigChanged = true;
1210
1211 if (updateOverflowControlsLayers(requiresHorizontalScrollbarLayer(), requiresVerticalScrollbarLayer(), requiresScrollCornerLayer()))
1212 layerConfigChanged = true;
1213
1214 if (layerConfigChanged)
1215 updateInternalHierarchy();
1216
1217 // RenderLayerCompositor::adjustOverflowScrollbarContainerLayers() may have reparented the overflowControlsContainer
1218 // in an earlier update, so always put it back here. We don't yet know if it will get reparented again.
1219 if (m_overflowControlsContainer && m_overflowControlsContainer->parent() != m_graphicsLayer.get()) {
1220 m_graphicsLayer->addChild(*m_overflowControlsContainer);
1221 // Ensure that we fix up the position of m_overflowControlsContainer.
1222 m_owningLayer.setNeedsCompositingGeometryUpdate();
1223 }
1224
1225 // FIXME: Overlow controls need to be above the flattening layer?
1226 if (RefPtr flatteningLayer = tileCacheFlatteningLayer()) {
1227 if (layerConfigChanged || flatteningLayer->parent() != m_graphicsLayer.get()) {
1228 // FIXME: m_graphicsLayer children are clobbered in RenderLayerCompositor::updateBackingAndHierarchy(); this probably doesn't work.
1229 m_graphicsLayer->addChild(*flatteningLayer);
1230 }
1231 }
1232
1233 if (updateMaskingLayer(renderer().hasMask(), renderer().hasClipPath()))
1234 layerConfigChanged = true;
1235
1236 if (m_owningLayer.hasReflection()) {
1237 if (m_owningLayer.reflectionLayer()->backing()) {
1238 RefPtr reflectionLayer = m_owningLayer.reflectionLayer()->backing()->graphicsLayer();
1239 m_graphicsLayer->setReplicatedByLayer(WTF::move(reflectionLayer));
1240 }
1241 } else
1242 m_graphicsLayer->setReplicatedByLayer(nullptr);
1243
1244 PaintedContentsInfo contentsInfo(*this);
1245
1246 // Requires layout.
1247 if (!m_owningLayer.isRenderViewLayer()) {
1248 bool didUpdateContentsRect = false;
1249 updateDirectlyCompositedBoxDecorations(contentsInfo, didUpdateContentsRect);
1250 } else
1251 updateRootLayerConfiguration();
1252
1253 // Requires layout.
1254 if (contentsInfo.isDirectlyCompositedImage())
1255 updateImageContents(contentsInfo);
1256
1257 bool unscaledBitmap = contentsInfo.isUnscaledBitmapOnly();
1258 if (unscaledBitmap == m_graphicsLayer->appliesDeviceScale()) {
1259 m_graphicsLayer->setAppliesDeviceScale(!unscaledBitmap);
1260 layerConfigChanged = true;
1261 }
1262
1263 bool shouldPaintUsingCompositeCopy = unscaledBitmap && is<RenderHTMLCanvas>(renderer()) && m_owningLayer.hasVisibleContent();
1264 if (shouldPaintUsingCompositeCopy != m_shouldPaintUsingCompositeCopy) {
1265 m_shouldPaintUsingCompositeCopy = shouldPaintUsingCompositeCopy;
1266 m_graphicsLayer->setShouldPaintUsingCompositeCopy(shouldPaintUsingCompositeCopy);
1267 layerConfigChanged = true;
1268 }
1269
1270 auto attachPluginLayer = [&](RenderEmbeddedObject& rendererEmbeddedObject) {
1271 RefPtr pluginViewBase = dynamicDowncast<PluginViewBase>(rendererEmbeddedObject.widget());
1272 if (!pluginViewBase)
1273 return;
1274
1275 switch (pluginViewBase->layerHostingStrategy()) {
1276 case PluginLayerHostingStrategy::None:
1277 break;
1278 case PluginLayerHostingStrategy::PlatformLayer:
1279 m_graphicsLayer->setContentsToPlatformLayer(pluginViewBase->platformLayer(), GraphicsLayer::ContentsLayerPurpose::Plugin);
1280 break;
1281 case PluginLayerHostingStrategy::GraphicsLayer:
1282 // layer is parented in RenderLayerCompositor::updateBackingAndHierarchy().
1283 break;
1284 }
1285 };
1286
1287 if (RenderLayerCompositor::isCompositedPlugin(renderer()))
1288 attachPluginLayer(downcast<RenderEmbeddedObject>(renderer()));
1289
1290#if ENABLE(VIDEO)(defined 1 && 1)
1291 else if (auto* renderVideo = dynamicDowncast<RenderVideo>(renderer()); renderVideo && renderVideo->shouldDisplayVideo()) {
1292 Ref videoElement = downcast<HTMLVideoElement>(*renderer().element());
1293 if (m_graphicsLayer->layerMode() == GraphicsLayer::LayerMode::LayerHostingContextId
1294#if ENABLE(GPU_PROCESS)(defined 1 && 1)
1295 && videoElement->document().settings().blockMediaLayerRehostingInWebContentProcess()
1296 && videoElement->document().page()
1297 && videoElement->document().page()->chrome().client().isUsingUISideCompositing()
1298#endif
1299 )
1300 m_graphicsLayer->setContentsToVideoElement(videoElement, GraphicsLayer::ContentsLayerPurpose::Media);
1301 else
1302 m_graphicsLayer->setContentsToPlatformLayer(videoElement->platformLayer(), GraphicsLayer::ContentsLayerPurpose::Media);
1303 updateContentsRects();
1304 }
1305#endif
1306 else if (RefPtr remoteFrame = is<RenderWidget>(renderer()) ? downcast<RenderWidget>(renderer()).remoteFrame() : nullptr; remoteFrame && remoteFrame->layerHostingContextIdentifier())
1307 m_graphicsLayer->setContentsToPlatformLayerHost(*remoteFrame->layerHostingContextIdentifier());
1308 else if (shouldSetContentsDisplayDelegate()) {
1309 RefPtr canvas = downcast<HTMLCanvasElement>(renderer().element());
1310 if (RefPtr context = canvas->renderingContext())
1311 context->setContentsToLayer(*m_graphicsLayer);
1312
1313 layerConfigChanged = true;
1314 }
1315#if ENABLE(MODEL_ELEMENT)(defined 1 && 1)
1316 else if (is<RenderModel>(renderer())) {
1317 RefPtr element = downcast<HTMLModelElement>(renderer().element());
1318
1319 element->configureGraphicsLayer(*m_graphicsLayer, rendererBackgroundColor());
1320 element->sizeMayHaveChanged();
1321
1322 layerConfigChanged = true;
1323 }
1324#endif // ENABLE(MODEL_ELEMENT)
1325
1326 // FIXME: Why do we do this twice?
1327 if (CheckedPtr widget = dynamicDowncast<RenderWidget>(renderer())) {
1328 if (compositor.attachWidgetContentLayersIfNecessary(*widget).layerHierarchyChanged) {
1329 m_owningLayer.setNeedsCompositingGeometryUpdate();
1330 layerConfigChanged = true;
1331 }
1332 }
1333
1334#if HAVE(CORE_ANIMATION_SEPARATED_LAYERS)(defined HAVE_CORE_ANIMATION_SEPARATED_LAYERS && HAVE_CORE_ANIMATION_SEPARATED_LAYERS
)
1335 bool clipsDescendants = RenderLayerCompositor::hasCompositedWidgetContents(renderer())
1336 || RenderLayerCompositor::isSeparated(renderer());
1337 updateSeparatedProperties();
1338#else
1339 bool clipsDescendants = RenderLayerCompositor::hasCompositedWidgetContents(renderer());
1340#endif
1341 if (clipsDescendants) {
1342 m_graphicsLayer->setContentsRectClipsDescendants(true);
1343 updateContentsRects();
1344 }
1345
1346 if (updateBackdropRoot())
1347 layerConfigChanged = true;
1348
1349 if (layerConfigChanged)
1350 updatePaintingPhases();
1351
1352 return layerConfigChanged;
1353}
1354
1355static bool subpixelOffsetFromRendererChanged(const LayoutSize& oldSubpixelOffsetFromRenderer, const LayoutSize& newSubpixelOffsetFromRenderer, float deviceScaleFactor)
1356{
1357 FloatSize previous = snapSizeToDevicePixel(oldSubpixelOffsetFromRenderer, LayoutPoint(), deviceScaleFactor);
1358 FloatSize current = snapSizeToDevicePixel(newSubpixelOffsetFromRenderer, LayoutPoint(), deviceScaleFactor);
1359 return previous != current;
1360}
1361
1362static FloatSize subpixelForLayerPainting(const LayoutPoint& point, float pixelSnappingFactor)
1363{
1364 LayoutUnit x = point.x();
1365 LayoutUnit y = point.y();
1366 x = x >= 0 ? floorToDevicePixel(x, pixelSnappingFactor) : ceilToDevicePixel(x, pixelSnappingFactor);
1367 y = y >= 0 ? floorToDevicePixel(y, pixelSnappingFactor) : ceilToDevicePixel(y, pixelSnappingFactor);
1368 return point - LayoutPoint(x, y);
1369}
1370
1371struct OffsetFromRenderer {
1372 // 1.2px - > { m_devicePixelOffset = 1px m_subpixelOffset = 0.2px }
1373 LayoutSize m_devicePixelOffset;
1374 LayoutSize m_subpixelOffset;
1375};
1376
1377static OffsetFromRenderer computeOffsetFromRenderer(const LayoutSize& offset, float deviceScaleFactor)
1378{
1379 OffsetFromRenderer offsetFromRenderer;
1380 offsetFromRenderer.m_subpixelOffset = LayoutSize(subpixelForLayerPainting(toLayoutPoint(offset), deviceScaleFactor));
1381 offsetFromRenderer.m_devicePixelOffset = offset - offsetFromRenderer.m_subpixelOffset;
1382 return offsetFromRenderer;
1383}
1384
1385struct SnappedRectInfo {
1386 LayoutRect m_snappedRect;
1387 LayoutSize m_snapDelta;
1388};
1389
1390static SnappedRectInfo snappedGraphicsLayer(const LayoutSize& offset, const LayoutSize& size, const RenderLayerModelObject& renderer)
1391{
1392 SnappedRectInfo snappedGraphicsLayer;
1393 LayoutRect graphicsLayerRect = LayoutRect(toLayoutPoint(offset), size);
1394 snappedGraphicsLayer.m_snappedRect = LayoutRect(snapRectToDevicePixelsIfNeeded(graphicsLayerRect, renderer));
1395 snappedGraphicsLayer.m_snapDelta = snappedGraphicsLayer.m_snappedRect.location() - toLayoutPoint(offset);
1396 return snappedGraphicsLayer;
1397}
1398
1399static LayoutSize computeOffsetFromAncestorGraphicsLayer(const RenderLayer* compositedAncestor, const LayoutPoint& location, float deviceScaleFactor)
1400{
1401 if (!compositedAncestor)
1402 return toLayoutSize(location);
1403
1404 // FIXME: This is a workaround until after webkit.org/b/162634 gets fixed. ancestorSubpixelOffsetFromRenderer
1405 // could be stale when a dynamic composited state change triggers a pre-order updateGeometry() traversal.
1406 LayoutSize ancestorSubpixelOffsetFromRenderer = compositedAncestor->backing()->subpixelOffsetFromRenderer();
1407 LayoutRect ancestorCompositedBounds = compositedAncestor->backing()->compositedBounds();
1408 LayoutSize floored = toLayoutSize(LayoutPoint(floorPointToDevicePixels(ancestorCompositedBounds.location() - ancestorSubpixelOffsetFromRenderer, deviceScaleFactor)));
1409 LayoutSize ancestorRendererOffsetFromAncestorGraphicsLayer = -(floored + ancestorSubpixelOffsetFromRenderer);
1410 return ancestorRendererOffsetFromAncestorGraphicsLayer + toLayoutSize(location);
1411}
1412
1413class ComputedOffsets {
1414public:
1415 ComputedOffsets(const RenderLayer& renderLayer, const RenderLayer* compositingAncestor, const LayoutRect& localRect, const LayoutRect& parentGraphicsLayerRect, const LayoutRect& primaryGraphicsLayerRect)
1416 : m_renderLayer(renderLayer)
1417 , m_compositingAncestor(compositingAncestor)
1418 , m_location(localRect.location())
1419 , m_parentGraphicsLayerOffset(toLayoutSize(parentGraphicsLayerRect.location()))
1420 , m_primaryGraphicsLayerOffset(toLayoutSize(primaryGraphicsLayerRect.location()))
1421 , m_deviceScaleFactor(renderLayer.renderer().document().deviceScaleFactor())
1422 {
1423 }
1424
1425 LayoutSize fromParentGraphicsLayer()
1426 {
1427 if (!m_fromParentGraphicsLayer)
1428 m_fromParentGraphicsLayer = fromAncestorGraphicsLayer() - m_parentGraphicsLayerOffset;
1429 return m_fromParentGraphicsLayer.value();
1430 }
1431
1432 LayoutSize fromPrimaryGraphicsLayer()
1433 {
1434 if (!m_fromPrimaryGraphicsLayer)
1435 m_fromPrimaryGraphicsLayer = fromAncestorGraphicsLayer() - m_parentGraphicsLayerOffset - m_primaryGraphicsLayerOffset;
1436 return m_fromPrimaryGraphicsLayer.value();
1437 }
1438
1439private:
1440 LayoutSize fromAncestorGraphicsLayer()
1441 {
1442 if (!m_fromAncestorGraphicsLayer) {
1443 LayoutPoint localPointInAncestorRenderLayerCoords = m_renderLayer.convertToLayerCoords(m_compositingAncestor, m_location, RenderLayer::AdjustForColumns);
1444 m_fromAncestorGraphicsLayer = computeOffsetFromAncestorGraphicsLayer(m_compositingAncestor, localPointInAncestorRenderLayerCoords, m_deviceScaleFactor);
1445 }
1446 return m_fromAncestorGraphicsLayer.value();
1447 }
1448
1449 std::optional<LayoutSize> m_fromAncestorGraphicsLayer;
1450 std::optional<LayoutSize> m_fromParentGraphicsLayer;
1451 std::optional<LayoutSize> m_fromPrimaryGraphicsLayer;
1452
1453 const RenderLayer& m_renderLayer;
1454 const RenderLayer* m_compositingAncestor;
1455 // Location is relative to the renderer.
1456 const LayoutPoint m_location;
1457 const LayoutSize m_parentGraphicsLayerOffset;
1458 const LayoutSize m_primaryGraphicsLayerOffset;
1459 float m_deviceScaleFactor;
1460};
1461
1462LayoutRect RenderLayerBacking::computePrimaryGraphicsLayerRect(const RenderLayer* compositedAncestor, const LayoutRect& parentGraphicsLayerRect) const
1463{
1464 ComputedOffsets compositedBoundsOffset(m_owningLayer, compositedAncestor, compositedBounds(), parentGraphicsLayerRect, { });
1465 return LayoutRect(encloseRectToDevicePixels(LayoutRect(toLayoutPoint(compositedBoundsOffset.fromParentGraphicsLayer()), compositedBounds().size()),
1466 deviceScaleFactor()));
1467}
1468
1469// FIXME: See if we need this now that updateGeometry() is always called in post-order traversal.
1470LayoutRect RenderLayerBacking::computeParentGraphicsLayerRect(const RenderLayer* compositedAncestor) const
1471{
1472 if (!compositedAncestor || !compositedAncestor->backing())
1473 return renderer().view().documentRect();
1474
1475 auto* ancestorBacking = compositedAncestor->backing();
1476 LayoutRect parentGraphicsLayerRect;
1477 if (m_owningLayer.isInsideFragmentedFlow()) {
1478 // FIXME: flows/columns need work.
1479 LayoutRect ancestorCompositedBounds = ancestorBacking->compositedBounds();
1480 ancestorCompositedBounds.setLocation(LayoutPoint());
1481 parentGraphicsLayerRect = ancestorCompositedBounds;
1482 }
1483
1484 CheckedPtr ancestorRenderBox = dynamicDowncast<RenderBox>(compositedAncestor->renderer());
1485 if (!ancestorRenderBox)
1486 return parentGraphicsLayerRect;
1487
1488 if (ancestorBacking->hasClippingLayer()) {
1489 // If the compositing ancestor has a layer to clip children, we parent in that, and therefore position relative to it.
1490 LayoutRect clippingBox = clippingLayerBox(*ancestorRenderBox);
1491 LayoutSize clippingBoxOffset = computeOffsetFromAncestorGraphicsLayer(compositedAncestor, clippingBox.location(), deviceScaleFactor());
1492 parentGraphicsLayerRect = snappedGraphicsLayer(clippingBoxOffset, clippingBox.size(), renderer()).m_snappedRect;
1493 }
1494
1495 if (compositedAncestor->hasCompositedScrollableOverflow()) {
1496 auto* scrollableArea = compositedAncestor->scrollableArea();
1497 ASSERT(scrollableArea)((void)0);
1498
1499 LayoutRect ancestorCompositedBounds = ancestorBacking->compositedBounds();
1500 LayoutRect scrollContainerBox = scrollContainerLayerBox(*ancestorRenderBox);
1501 ScrollOffset scrollOffset = scrollableArea->scrollOffset();
1502 parentGraphicsLayerRect = LayoutRect((scrollContainerBox.location() - toLayoutSize(ancestorCompositedBounds.location()) - toLayoutSize(scrollOffset)), scrollContainerBox.size());
1503 }
1504
1505 return parentGraphicsLayerRect;
1506}
1507
1508void RenderLayerBacking::updateGeometry(const RenderLayer* compositedAncestor)
1509{
1510 ASSERT(!m_owningLayer.normalFlowListDirty())((void)0);
1511 ASSERT(!m_owningLayer.zOrderListsDirty())((void)0);
1512 ASSERT(!m_owningLayer.descendantDependentFlagsAreDirty())((void)0);
1513 ASSERT(!renderer().view().needsLayout())((void)0);
1514
1515 const RenderStyle& style = renderer().style();
1516 const auto deviceScaleFactor = this->deviceScaleFactor();
1517
1518 auto styleable = Styleable::fromRenderer(renderer());
1519 bool isRunningAcceleratedTransformAnimation = styleable && styleable->isRunningAcceleratedTransformRelatedAnimation();
1520
1521 updateTransform(style);
1522 updateOpacity(style);
1523 updateFilters(style);
1524 updateBackdropFilters(style);
1525#if HAVE(CORE_MATERIAL)(defined 1 && 1)
1526 updateAppleVisualEffect(style);
1527#endif
1528 updateBackdropRoot();
1529 updateBlendMode(style);
1530 updateContentsScalingFilters(style);
1531
1532#if ENABLE(VIDEO)(defined 1 && 1)
1533 updateVideoGravity(style);
1534#endif
1535
1536 ASSERT(compositedAncestor == m_owningLayer.ancestorCompositingLayer())((void)0);
1537 LayoutRect parentGraphicsLayerRect = computeParentGraphicsLayerRect(compositedAncestor);
1538
1539 // If our content is being used in a view-transition, then all positioning is handled using a synthesized 'transform' property on the wrapping
1540 // ::view-transition-new element. Set the parent graphics layer rect to that of the pseudo, adjusted into coordinates of the parent layer.
1541 if (renderer().effectiveCapturedInViewTransition() && renderer().element()) {
1542 if (RefPtr activeViewTransition = renderer().document().activeViewTransition()) {
1543 if (CheckedPtr viewTransitionCapture = activeViewTransition->viewTransitionNewPseudoForCapturedElement(renderer())) {
1544 ComputedOffsets computedOffsets(m_owningLayer, compositedAncestor, viewTransitionCapture->captureOverflowRect(), { }, { });
1545 parentGraphicsLayerRect = LayoutRect(snapRectToDevicePixelsIfNeeded(LayoutRect(toLayoutPoint(computedOffsets.fromParentGraphicsLayer()), viewTransitionCapture->captureOverflowRect().size()), renderer()));
1546 }
1547 }
1548 }
1549
1550 if (m_ancestorClippingStack)
1551 updateClippingStackLayerGeometry(*m_ancestorClippingStack, compositedAncestor, parentGraphicsLayerRect);
1552
1553 LayoutRect primaryGraphicsLayerRect = computePrimaryGraphicsLayerRect(compositedAncestor, parentGraphicsLayerRect);
1554
1555 ComputedOffsets compositedBoundsOffset(m_owningLayer, compositedAncestor, compositedBounds(), parentGraphicsLayerRect, primaryGraphicsLayerRect);
1556 ComputedOffsets rendererOffset(m_owningLayer, compositedAncestor, { }, parentGraphicsLayerRect, primaryGraphicsLayerRect);
1557
1558 m_compositedBoundsOffsetFromGraphicsLayer = compositedBoundsOffset.fromPrimaryGraphicsLayer();
1559
1560 auto primaryLayerPosition = primaryGraphicsLayerRect.location();
1561
1562 // FIXME: reflections should force transform-style to be flat in the style: https://bugs.webkit.org/show_bug.cgi?id=106959
1563 bool preserves3D = style.usedTransformStyle3D() == TransformStyle3D::Preserve3D && !renderer().hasReflection();
1564
1565 if (m_viewportAnchorLayer) {
1566 if (m_viewportClippingLayer) {
1567 ASSERT(compositedAncestor == renderer().view().layer())((void)0);
1568 auto fixedPositionRect = renderer().view().frameView().rectForFixedPositionLayout();
1569 if (m_ancestorClippingStack) {
1570 for (auto& entry : m_ancestorClippingStack->stack()) {
1571 if (entry.clippingLayer)
1572 fixedPositionRect.moveBy(-LayoutPoint { entry.clippingLayer->position() });
1573 }
1574 }
1575
1576 // RenderView's layer has a non-zero offsetFromGraphicsLayer in RTL content; we have to account
1577 // for that to map rectForFixedPositionLayout from content to GraphicsLayer coordinates.
1578 CheckedPtr renderViewLayer = renderer().view().layer();
1579 ASSERT(renderViewLayer->isComposited())((void)0);
1580 fixedPositionRect.move(renderViewLayer->backing()->contentOffsetInCompositingLayer());
1581
1582 m_viewportClippingLayer->setPosition(fixedPositionRect.location());
1583 m_viewportClippingLayer->setSize(fixedPositionRect.size());
1584 primaryLayerPosition.moveBy(-fixedPositionRect.location());
1585 }
1586 m_viewportAnchorLayer->setPosition(primaryLayerPosition);
1587 primaryLayerPosition = { };
1588 }
1589
1590 setNeedsFixedContainerEdgesUpdateIfNeeded();
1591
1592 if (m_contentsContainmentLayer) {
1593 m_contentsContainmentLayer->setPreserves3D(preserves3D);
1594 m_contentsContainmentLayer->setPosition(primaryLayerPosition);
1595 primaryLayerPosition = { };
1596 // Use the same size as m_graphicsLayer so transforms behave correctly.
1597 m_contentsContainmentLayer->setSize(primaryGraphicsLayerRect.size());
1598 }
1599
1600 auto computeAnimationExtent = [&] () -> std::optional<FloatRect> {
1601 LayoutRect animatedBounds;
1602 if (isRunningAcceleratedTransformAnimation && m_owningLayer.getOverlapBoundsIncludingChildrenAccountingForTransformAnimations(animatedBounds, RenderLayer::IncludeCompositedDescendants))
1603 return FloatRect(animatedBounds);
1604 return { };
1605 };
1606 m_graphicsLayer->setAnimationExtent(computeAnimationExtent());
1607 m_graphicsLayer->setPreserves3D(preserves3D);
1608 m_graphicsLayer->setBackfaceVisibility(style.backfaceVisibility() == BackfaceVisibility::Visible);
1609
1610 m_graphicsLayer->setPosition(primaryLayerPosition);
1611 m_graphicsLayer->setSize(primaryGraphicsLayerRect.size());
1612 if (hasTiledBackingFlatteningLayer())
1613 m_childContainmentLayer->setSize(primaryGraphicsLayerRect.size());
1614
1615 // Compute renderer offset from primary graphics layer. Note that primaryGraphicsLayerRect is in parentGraphicsLayer's coordinate system which is not necessarily
1616 // the same as the ancestor graphics layer.
1617 OffsetFromRenderer primaryGraphicsLayerOffsetFromRenderer;
1618 LayoutSize oldSubpixelOffsetFromRenderer = m_subpixelOffsetFromRenderer;
1619 primaryGraphicsLayerOffsetFromRenderer = computeOffsetFromRenderer(-rendererOffset.fromPrimaryGraphicsLayer(), deviceScaleFactor);
1620 m_subpixelOffsetFromRenderer = primaryGraphicsLayerOffsetFromRenderer.m_subpixelOffset;
1621 m_hasSubpixelRounding = !m_subpixelOffsetFromRenderer.isZero() || compositedBounds().size() != primaryGraphicsLayerRect.size();
1622
1623 if (primaryGraphicsLayerOffsetFromRenderer.m_devicePixelOffset != m_graphicsLayer->offsetFromRenderer())
1624 m_graphicsLayer->setOffsetFromRenderer(primaryGraphicsLayerOffsetFromRenderer.m_devicePixelOffset);
1625
1626 // If we have a layer that clips children, position it.
1627 LayoutRect clippingBox;
1628 if (RefPtr clipLayer = clippingLayer()) {
1629 // clipLayer is the m_childContainmentLayer.
1630 clippingBox = clippingLayerBox(renderer());
1631 // Clipping layer is parented in the primary graphics layer.
1632 LayoutSize clipBoxOffsetFromGraphicsLayer = toLayoutSize(clippingBox.location()) + rendererOffset.fromPrimaryGraphicsLayer();
1633 SnappedRectInfo snappedClippingGraphicsLayer = snappedGraphicsLayer(clipBoxOffsetFromGraphicsLayer, clippingBox.size(), renderer());
1634 clipLayer->setPosition(snappedClippingGraphicsLayer.m_snappedRect.location());
1635 clipLayer->setSize(snappedClippingGraphicsLayer.m_snappedRect.size());
1636 clipLayer->setOffsetFromRenderer(toLayoutSize(clippingBox.location() - snappedClippingGraphicsLayer.m_snapDelta));
1637
1638 auto computeMasksToBoundsRect = [&] {
1639 if ((renderer().hasClipPath() || renderer().style().border().hasBorderRadius())) {
1640 auto borderShape = BorderShape::shapeForBorderRect(renderer().style(), m_owningLayer.rendererBorderBoxRect());
1641 auto contentsClippingRect = borderShape.deprecatedPixelSnappedInnerRoundedRect(deviceScaleFactor);
1642 contentsClippingRect.move(LayoutSize(-clipLayer->offsetFromRenderer()));
1643 return contentsClippingRect;
1644 }
1645
1646 return FloatRoundedRect { FloatRect { { }, snappedClippingGraphicsLayer.m_snappedRect.size() } };
1647 };
1648
1649 clipLayer->setContentsClippingRect(computeMasksToBoundsRect());
1650 }
1651
1652 if (m_maskLayer)
1653 updateMaskingLayerGeometry();
1654
1655 updateChildrenTransformAndAnchorPoint(primaryGraphicsLayerRect, rendererOffset.fromParentGraphicsLayer());
1656
1657 if (m_owningLayer.reflectionLayer() && m_owningLayer.reflectionLayer()->isComposited()) {
1658 auto* reflectionBacking = m_owningLayer.reflectionLayer()->backing();
1659 reflectionBacking->updateGeometry(&m_owningLayer);
1660
1661 // The reflection layer has the bounds of m_owningLayer.reflectionLayer(),
1662 // but the reflected layer is the bounds of this layer, so we need to position it appropriately.
1663 FloatRect layerBounds = this->compositedBounds();
1664 FloatRect reflectionLayerBounds = reflectionBacking->compositedBounds();
1665 reflectionBacking->graphicsLayer()->setReplicatedLayerPosition(FloatPoint(layerBounds.location() - reflectionLayerBounds.location()));
1666 }
1667
1668 if (m_scrollContainerLayer) {
1669 ASSERT(m_scrolledContentsLayer)((void)0);
1670 LayoutRect scrollContainerBox = scrollContainerLayerBox(downcast<RenderBox>(renderer()));
1671 LayoutRect parentLayerBounds = clippingLayer() ? scrollContainerBox : compositedBounds();
1672
1673 // FIXME: need to do some pixel snapping here.
1674 m_scrollContainerLayer->setPosition(FloatPoint(scrollContainerBox.location() - parentLayerBounds.location()));
1675 m_scrollContainerLayer->setSize(roundedIntSize(LayoutSize(scrollContainerBox.width(), scrollContainerBox.height())));
1676
1677 auto* scrollableArea = m_owningLayer.scrollableArea();
1678 ASSERT(scrollableArea)((void)0);
1679
1680 ScrollOffset scrollOffset = scrollableArea->scrollOffset();
1681 updateScrollOffset(scrollOffset);
1682
1683 FloatSize oldScrollingLayerOffset = m_scrollContainerLayer->offsetFromRenderer();
1684 m_scrollContainerLayer->setOffsetFromRenderer(toFloatSize(scrollContainerBox.location()));
1685
1686 bool paddingBoxOffsetChanged = oldScrollingLayerOffset != m_scrollContainerLayer->offsetFromRenderer();
1687
1688 IntSize scrollSize;
1689 if (scrollableArea)
1690 scrollSize = IntSize(scrollableArea->scrollWidth(), scrollableArea->scrollHeight());
1691 if (scrollSize != m_scrolledContentsLayer->size() || paddingBoxOffsetChanged)
1692 m_scrolledContentsLayer->setNeedsDisplay();
1693
1694 m_scrolledContentsLayer->setSize(scrollSize);
1695 m_scrolledContentsLayer->setScrollOffset(scrollOffset, GraphicsLayer::ShouldSetNeedsDisplay::DoNotSet);
1696 m_scrolledContentsLayer->setOffsetFromRenderer(toLayoutSize(scrollContainerBox.location()), GraphicsLayer::ShouldSetNeedsDisplay::DoNotSet);
1697
1698 adjustTiledBackingCoverage();
1699 }
1700
1701 if (m_overflowControlsContainer) {
1702 LayoutRect overflowControlsBox = overflowControlsHostLayerRect(downcast<RenderBox>(renderer()));
1703 LayoutSize boxOffsetFromGraphicsLayer = toLayoutSize(overflowControlsBox.location()) + rendererOffset.fromPrimaryGraphicsLayer();
1704 SnappedRectInfo snappedBoxInfo = snappedGraphicsLayer(boxOffsetFromGraphicsLayer, overflowControlsBox.size(), renderer());
1705
1706 m_overflowControlsContainer->setPosition(snappedBoxInfo.m_snappedRect.location());
1707 m_overflowControlsContainer->setSize(snappedBoxInfo.m_snappedRect.size());
1708 m_overflowControlsContainer->setMasksToBounds(true);
1709 }
1710
1711 if (m_foregroundLayer) {
1712 FloatSize foregroundSize;
1713 FloatSize foregroundOffset;
1714 auto needsDisplayOnOffsetChange = GraphicsLayer::ShouldSetNeedsDisplay::Set;
1715 if (m_scrolledContentsLayer) {
1716 foregroundSize = m_scrolledContentsLayer->size();
1717 foregroundOffset = m_scrolledContentsLayer->offsetFromRenderer() - toLayoutSize(m_scrolledContentsLayer->scrollOffset());
1718 needsDisplayOnOffsetChange = GraphicsLayer::ShouldSetNeedsDisplay::DoNotSet;
1719 } else if (hasClippingLayer()) {
1720 // If we have a clipping layer (which clips descendants), then the foreground layer is a child of it,
1721 // so that it gets correctly sorted with children. In that case, position relative to the clipping layer.
1722 foregroundSize = FloatSize(clippingBox.size());
1723 foregroundOffset = toFloatSize(clippingBox.location());
1724 } else {
1725 foregroundSize = primaryGraphicsLayerRect.size();
1726 foregroundOffset = m_graphicsLayer->offsetFromRenderer();
1727 }
1728
1729 m_foregroundLayer->setPosition({ });
1730 m_foregroundLayer->setSize(foregroundSize);
1731 m_foregroundLayer->setOffsetFromRenderer(foregroundOffset, needsDisplayOnOffsetChange);
1732 }
1733
1734 if (m_backgroundLayer) {
1735 FloatPoint backgroundPosition;
1736 FloatSize backgroundSize = primaryGraphicsLayerRect.size();
1737 if (backgroundLayerPaintsFixedRootBackground()) {
1738 const LocalFrameView& frameView = renderer().view().frameView();
Local variable 'frameView' is uncounted and unsafe
1739 backgroundPosition = frameView.scrollPositionForFixedPosition();
1740 backgroundSize = frameView.layoutSize();
1741 } else {
1742 auto boundingBox = renderer().objectBoundingBox();
1743 backgroundPosition = boundingBox.location();
1744 backgroundSize = boundingBox.size();
1745 }
1746 m_backgroundLayer->setPosition(backgroundPosition);
1747 m_backgroundLayer->setSize(backgroundSize);
1748 m_backgroundLayer->setOffsetFromRenderer(m_graphicsLayer->offsetFromRenderer());
1749 }
1750
1751 // If this layer was created just for clipping or to apply perspective, it doesn't need its own backing store.
1752 LayoutRect ancestorCompositedBounds = compositedAncestor ? compositedAncestor->backing()->compositedBounds() : LayoutRect();
1753 setRequiresOwnBackingStore(compositor().requiresOwnBackingStore(m_owningLayer, compositedAncestor,
1754 LayoutRect(toLayoutPoint(compositedBoundsOffset.fromParentGraphicsLayer()), compositedBounds().size()), ancestorCompositedBounds));
1755 updateBackdropFiltersGeometry();
1756 updateAfterWidgetResize();
1757
1758 positionOverflowControlsLayers();
1759
1760 if (subpixelOffsetFromRendererChanged(oldSubpixelOffsetFromRenderer, m_subpixelOffsetFromRenderer, deviceScaleFactor) && canIssueSetNeedsDisplay())
1761 setContentsNeedDisplay();
1762
1763#if ENABLE(MODEL_ELEMENT)(defined 1 && 1)
1764 if (is<RenderModel>(renderer()))
1765 downcast<HTMLModelElement>(renderer().element())->sizeMayHaveChanged();
1766#endif
1767}
1768
1769void RenderLayerBacking::adjustOverflowControlsPositionRelativeToAncestor(const RenderLayer& ancestorLayer)
1770{
1771 ASSERT(m_overflowControlsContainer)((void)0);
1772 ASSERT(ancestorLayer.isComposited())((void)0);
1773 auto ancestorBacking = ancestorLayer.backing();
1774 if (!ancestorBacking)
1775 return;
1776
1777 LayoutRect parentGraphicsLayerRect = computeParentGraphicsLayerRect(&ancestorLayer);
1778 LayoutRect primaryGraphicsLayerRect = computePrimaryGraphicsLayerRect(&ancestorLayer, parentGraphicsLayerRect);
1779
1780 auto overflowControlsRect = overflowControlsHostLayerRect(downcast<RenderBox>(renderer()));
1781
1782 if (overflowControlsHostLayerAncestorClippingStack())
1783 updateClippingStackLayerGeometry(*m_overflowControlsHostLayerAncestorClippingStack, &ancestorLayer, parentGraphicsLayerRect);
1784
1785 ComputedOffsets rendererOffset(m_owningLayer, &ancestorLayer, { }, parentGraphicsLayerRect, primaryGraphicsLayerRect);
1786
1787 LayoutSize boxOffsetFromGraphicsLayer = toLayoutSize(overflowControlsRect.location()) + rendererOffset.fromParentGraphicsLayer();
1788 SnappedRectInfo snappedBoxInfo = snappedGraphicsLayer(boxOffsetFromGraphicsLayer, overflowControlsRect.size(), renderer());
1789
1790 m_overflowControlsContainer->setPosition(snappedBoxInfo.m_snappedRect.location());
1791 m_overflowControlsContainer->setSize(snappedBoxInfo.m_snappedRect.size());
1792}
1793
1794void RenderLayerBacking::setLocationOfScrolledContents(ScrollOffset scrollOffset, ScrollingLayerPositionAction setOrSync)
1795{
1796 if (setOrSync == ScrollingLayerPositionAction::Sync)
1797 m_scrollContainerLayer->syncBoundsOrigin(scrollOffset);
1798 else
1799 m_scrollContainerLayer->setBoundsOrigin(scrollOffset);
1800}
1801
1802void RenderLayerBacking::updateScrollOffset(ScrollOffset scrollOffset)
1803{
1804 auto* scrollableArea = m_owningLayer.scrollableArea();
1805 ASSERT(scrollableArea)((void)0);
1806
1807 if (scrollableArea->currentScrollType() == ScrollType::User) {
1808 // If scrolling is happening externally, we don't want to touch the layer bounds origin here because that will cause jitter.
1809 setLocationOfScrolledContents(scrollOffset, ScrollingLayerPositionAction::Sync);
1810 scrollableArea->setRequiresScrollPositionReconciliation(true);
1811 } else {
1812 // Note that we implement the contents offset via the bounds origin on this layer, rather than a position on the sublayer.
1813 setLocationOfScrolledContents(scrollOffset, ScrollingLayerPositionAction::Set);
1814 scrollableArea->setRequiresScrollPositionReconciliation(false);
1815 }
1816
1817 ASSERT(m_scrolledContentsLayer->position().isZero())((void)0);
1818}
1819
1820void RenderLayerBacking::updateAfterDescendants()
1821{
1822 // FIXME: this potentially duplicates work we did in updateConfiguration().
1823 PaintedContentsInfo contentsInfo(*this);
1824
1825 if (!m_owningLayer.isRenderViewLayer()) {
1826 bool didUpdateContentsRect = false;
1827 updateDirectlyCompositedBoxDecorations(contentsInfo, didUpdateContentsRect);
1828 if (!didUpdateContentsRect && m_graphicsLayer->usesContentsLayer())
1829 resetContentsRect();
1830 }
1831
1832 updateDrawsContent(contentsInfo);
1833
1834 if (!m_isMainFrameRenderViewLayer && !m_isFrameLayerWithTiledBacking && !m_requiresBackgroundLayer) {
1835 // For non-root layers, background is always painted by the primary graphics layer.
1836 ASSERT(!m_backgroundLayer)((void)0);
1837 m_graphicsLayer->setContentsOpaque(!m_hasSubpixelRounding && m_owningLayer.backgroundIsKnownToBeOpaqueInRect(compositedBounds()));
1838 }
1839
1840 m_graphicsLayer->setContentsVisible(m_owningLayer.hasVisibleContent() || hasVisibleNonCompositedDescendants());
1841 if (m_scrollContainerLayer) {
1842 m_scrollContainerLayer->setContentsVisible(renderer().style().usedVisibility() == Visibility::Visible);
1843
1844 bool userInteractive = renderer().visibleToHitTesting();
1845 m_scrollContainerLayer->setUserInteractionEnabled(userInteractive);
1846 if (m_layerForHorizontalScrollbar)
1847 m_layerForHorizontalScrollbar->setUserInteractionEnabled(userInteractive);
1848 if (m_layerForVerticalScrollbar)
1849 m_layerForVerticalScrollbar->setUserInteractionEnabled(userInteractive);
1850 if (m_layerForScrollCorner)
1851 m_layerForScrollCorner->setUserInteractionEnabled(userInteractive);
1852 }
1853}
1854
1855// FIXME: Avoid repaints when clip path changes.
1856void RenderLayerBacking::updateMaskingLayerGeometry()
1857{
1858 m_maskLayer->setSize(m_graphicsLayer->size());
1859 m_maskLayer->setPosition(FloatPoint());
1860 m_maskLayer->setOffsetFromRenderer(m_graphicsLayer->offsetFromRenderer());
1861
1862 if (!m_maskLayer->drawsContent()) {
1863 if (renderer().hasClipPath()) {
1864 ASSERT(!WTF::holdsAlternative<Style::ReferencePath>(renderer().style().clipPath()))((void)0);
1865
1866 // FIXME: Use correct reference box for inlines: https://bugs.webkit.org/show_bug.cgi?id=129047, https://github.com/w3c/csswg-drafts/issues/6383
1867 LayoutRect boundingBox = m_owningLayer.boundingBox(&m_owningLayer);
1868 LayoutRect referenceBoxForClippedInline = LayoutRect(snapRectToDevicePixelsIfNeeded(boundingBox, renderer()));
1869 LayoutSize offset = LayoutSize(snapSizeToDevicePixel(-m_subpixelOffsetFromRenderer, LayoutPoint(), deviceScaleFactor()));
1870 auto [clipPath, windRule] = m_owningLayer.computeClipPath(offset, referenceBoxForClippedInline);
1871
1872 FloatSize pathOffset = m_maskLayer->offsetFromRenderer();
1873 if (!pathOffset.isZero())
1874 clipPath.translate(-pathOffset);
1875
1876 m_maskLayer->setShapeLayerPath(clipPath);
1877 m_maskLayer->setShapeLayerWindRule(windRule);
1878 }
1879 }
1880}
1881
1882void RenderLayerBacking::updateDirectlyCompositedBoxDecorations(PaintedContentsInfo& contentsInfo, bool& didUpdateContentsRect)
1883{
1884 if (!m_owningLayer.hasVisibleContent())
1885 return;
1886
1887 // The order of operations here matters, since the last valid type of contents needs
1888 // to also update the contentsRect.
1889 updateDirectlyCompositedBackgroundColor(contentsInfo, didUpdateContentsRect);
1890 updateDirectlyCompositedBackgroundImage(contentsInfo, didUpdateContentsRect);
1891}
1892
1893GraphicsLayer* RenderLayerBacking::layerForContents() const
1894{
1895 if (!RenderLayerCompositor::isCompositedPlugin(renderer()))
1896 return nullptr;
1897
1898 RefPtr pluginViewBase = dynamicDowncast<PluginViewBase>(downcast<RenderEmbeddedObject>(renderer()).widget());
1899 if (!pluginViewBase)
1900 return nullptr;
1901
1902 if (pluginViewBase->layerHostingStrategy() != PluginLayerHostingStrategy::GraphicsLayer)
1903 return nullptr;
1904
1905 return pluginViewBase->graphicsLayer();
1906}
1907
1908void RenderLayerBacking::updateInternalHierarchy()
1909{
1910 // m_foregroundLayer has to be inserted in the correct order with child layers,
1911 // so it's not inserted here.
1912 RefPtr<GraphicsLayer> lastClippingLayer;
1913 if (m_ancestorClippingStack) {
1914 connectClippingStackLayers(*m_ancestorClippingStack);
1915 lastClippingLayer = m_ancestorClippingStack->lastLayer();
1916 }
1917
1918 constexpr size_t maxOrderedLayers = 6;
1919 Vector<GraphicsLayer*, maxOrderedLayers> orderedLayers;
1920
1921 if (lastClippingLayer)
1922 orderedLayers.append(lastClippingLayer);
1923
1924 if (m_viewportClippingLayer)
1925 orderedLayers.append(m_viewportClippingLayer.get());
1926
1927 if (m_viewportAnchorLayer)
1928 orderedLayers.append(m_viewportAnchorLayer.get());
1929
1930 if (m_contentsContainmentLayer) {
1931 m_contentsContainmentLayer->removeAllChildren();
1932
1933 ASSERT(m_backgroundLayer)((void)0);
1934 m_contentsContainmentLayer->addChild(*m_backgroundLayer);
1935
1936 // The loop below will add a second child to the m_contentsContainmentLayer.
1937 orderedLayers.append(m_contentsContainmentLayer.get());
1938 }
1939
1940 orderedLayers.append(m_graphicsLayer.get());
1941
1942 // The transform flattening layer is outside the clipping stack, so we need
1943 // to make sure we add the first layer in the clipping stack as its child.
1944 if (m_transformFlatteningLayer) {
1945 if (lastClippingLayer)
1946 m_transformFlatteningLayer->addChild(*m_ancestorClippingStack->firstLayer());
1947 else
1948 m_transformFlatteningLayer->addChild(*orderedLayers[0]);
1949 }
1950
1951 if (m_childContainmentLayer)
1952 orderedLayers.append(m_childContainmentLayer.get());
1953
1954 if (m_scrollContainerLayer)
1955 orderedLayers.append(m_scrollContainerLayer.get());
1956
1957 RefPtr<GraphicsLayer> previousLayer;
1958 for (RefPtr layer : orderedLayers) {
1959 if (previousLayer)
1960 previousLayer->addChild(*layer);
1961
1962 previousLayer = layer;
1963 }
1964
1965 // The clip for child layers does not include space for overflow controls, so they exist as
1966 // siblings of the clipping layer if we have one. Normal children of this layer are set as
1967 // children of the clipping layer.
1968 if (m_overflowControlsContainer) {
1969 if (m_layerForHorizontalScrollbar)
1970 m_overflowControlsContainer->addChild(*m_layerForHorizontalScrollbar);
1971
1972 if (m_layerForVerticalScrollbar)
1973 m_overflowControlsContainer->addChild(*m_layerForVerticalScrollbar);
1974
1975 if (m_layerForScrollCorner)
1976 m_overflowControlsContainer->addChild(*m_layerForScrollCorner);
1977
1978 // m_overflowControlsContainer may get reparented later.
1979 m_graphicsLayer->addChild(*m_overflowControlsContainer);
1980 }
1981}
1982
1983void RenderLayerBacking::updateContentsRects()
1984{
1985 m_graphicsLayer->setContentsRect(snapRectToDevicePixelsIfNeeded(contentsBox(), renderer()));
1986
1987#if HAVE(CORE_ANIMATION_SEPARATED_LAYERS)(defined HAVE_CORE_ANIMATION_SEPARATED_LAYERS && HAVE_CORE_ANIMATION_SEPARATED_LAYERS
)
1988 if (RenderLayerCompositor::isSeparated(renderer())) {
1989 if (CheckedPtr renderBox = dynamicDowncast<RenderBox>(renderer())) {
1990 auto borderShape = BorderShape::shapeForBorderRect(renderBox->style(), renderBox->borderBoxRect());
1991 auto contentsClippingRect = borderShape.deprecatedPixelSnappedInnerRoundedRect(deviceScaleFactor());
1992 contentsClippingRect.move(contentOffsetInCompositingLayer());
1993 m_graphicsLayer->setContentsClippingRect(contentsClippingRect);
1994 return;
1995 }
1996 }
1997#endif
1998
1999 if (CheckedPtr renderReplaced = dynamicDowncast<RenderReplaced>(renderer())) {
2000 if (renderer().isRenderViewTransitionCapture() && !renderer().hasNonVisibleOverflow())
2001 m_graphicsLayer->setContentsClippingRect(FloatRoundedRect(m_graphicsLayer->contentsRect()));
2002 else {
2003 // FIXME: Support visible overflow for replaced content.
2004 auto borderShape = renderReplaced->borderShapeForContentClipping(renderReplaced->borderBoxRect());
2005 auto contentsClippingRect = borderShape.deprecatedPixelSnappedInnerRoundedRect(deviceScaleFactor());
2006 contentsClippingRect.move(contentOffsetInCompositingLayer());
2007 m_graphicsLayer->setContentsClippingRect(contentsClippingRect);
2008 }
2009 }
2010}
2011
2012void RenderLayerBacking::resetContentsRect()
2013{
2014 updateContentsRects();
2015 m_graphicsLayer->setContentsTileSize(IntSize());
2016 m_graphicsLayer->setContentsTilePhase(IntSize());
2017}
2018
2019void RenderLayerBacking::updateDrawsContent()
2020{
2021 PaintedContentsInfo contentsInfo(*this);
2022 updateDrawsContent(contentsInfo);
2023}
2024
2025void RenderLayerBacking::updateDrawsContent(PaintedContentsInfo& contentsInfo)
2026{
2027 if (m_scrollContainerLayer) {
2028 // We don't have to consider overflow controls, because we know that the scrollbars are drawn elsewhere.
2029 // m_graphicsLayer only needs backing store if the non-scrolling parts (background, outlines, borders, shadows etc) need to paint.
2030 // m_scrollContainerLayer never has backing store.
2031 // m_scrolledContentsLayer only needs backing store if the scrolled contents need to paint.
2032 bool hasNonScrollingPaintedContent = m_owningLayer.hasVisibleContent() && m_owningLayer.hasVisibleBoxDecorationsOrBackground();
2033 m_graphicsLayer->setDrawsContent(hasNonScrollingPaintedContent);
2034
2035 bool hasScrollingPaintedContent = hasBackingSharingLayers() || (m_owningLayer.hasVisibleContent() && (renderer().hasBackground() || contentsInfo.paintsContent()));
2036 m_scrolledContentsLayer->setDrawsContent(hasScrollingPaintedContent);
2037 return;
2038 }
2039
2040#if HAVE(SUPPORT_HDR_DISPLAY)(defined 1 && 1)
2041 if (renderer().document().drawsHDRContent())
2042 contentsInfo.setDetectsHDRContent();
2043#endif
2044
2045 bool hasPaintedContent = containsPaintedContent(contentsInfo);
2046
2047 // FIXME: we could refine this to only allocate backing for one of these layers if possible.
2048 m_graphicsLayer->setDrawsContent(hasPaintedContent);
2049 if (m_foregroundLayer)
2050 m_foregroundLayer->setDrawsContent(hasPaintedContent);
2051
2052 if (m_backgroundLayer)
2053 m_backgroundLayer->setDrawsContent(m_backgroundLayerPaintsFixedRootBackground ? hasPaintedContent : contentsInfo.paintsBoxDecorations());
2054
2055#if HAVE(SUPPORT_HDR_DISPLAY)(defined 1 && 1)
2056 m_graphicsLayer->setDrawsHDRContent(contentsInfo.paintsHDRContent() || contentsInfo.rendererHasHDRContent());
2057 if (contentsInfo.paintsHDRContent() || contentsInfo.rendererHasHDRContent()) {
2058 LOG_WITH_STREAM(HDR, stream << "RenderLayerBacking " << *this << " updateDrawContent headroom " << m_owningLayer.page().displayEDRHeadroom())((void)0);
2059 m_graphicsLayer->setNeedsDisplayIfEDRHeadroomExceeds(m_owningLayer.page().displayEDRHeadroom());
2060 m_graphicsLayer->setTonemappingEnabled(m_owningLayer.page().hdrLayersRequireTonemapping());
2061 } else
2062 m_graphicsLayer->setTonemappingEnabled(false);
2063#endif
2064}
2065
2066#if ENABLE(ASYNC_SCROLLING)(defined 1 && 1)
2067bool RenderLayerBacking::maintainsEventRegion() const
2068{
2069 if (!m_owningLayer.page().scrollingCoordinator())
2070 return false;
2071
2072 if (paintsIntoCompositedAncestor())
2073 return false;
2074
2075 if (renderer().view().needsEventRegionUpdateForNonCompositedFrame())
2076 return true;
2077
2078#if ENABLE(TOUCH_ACTION_REGIONS)(defined 0 && 0)
2079 if (renderer().document().mayHaveElementsWithNonAutoTouchAction())
2080 return true;
2081#endif
2082#if ENABLE(EDITABLE_REGION)(defined ENABLE_EDITABLE_REGION && ENABLE_EDITABLE_REGION
)
2083 LOG_WITH_STREAM(EventRegions, stream << "RenderLayerBacking: " << this << " maintainsEventRegion - mayHaveEditableElements: " << renderer().document().mayHaveEditableElements() << " shouldBuildEditableRegion: " << renderer().page().shouldBuildEditableRegion())((void)0);
2084 if (renderer().document().mayHaveEditableElements() && renderer().page().shouldBuildEditableRegion())
2085 return true;
2086#endif
2087#if ENABLE(WHEEL_EVENT_REGIONS)(defined 1 && 1)
2088 if (renderer().document().hasWheelEventHandlers())
2089 return true;
2090#endif
2091#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)(defined ENABLE_INTERACTION_REGIONS_IN_EVENT_REGION &&
ENABLE_INTERACTION_REGIONS_IN_EVENT_REGION)
2092 if (renderer().page().shouldBuildInteractionRegions())
2093 return true;
2094#endif
2095#if ENABLE(TOUCH_EVENT_REGIONS)(defined 0 && 0)
2096 if (renderer().document().hasTouchEventHandlers())
2097 return true;
2098 if (renderer().document().needsPointerEventHandlingForPopover())
2099 return true;
2100#endif
2101
2102 if (m_owningLayer.isRenderViewLayer())
2103 return false;
2104
2105 Ref settings = renderer().settings();
2106 if (!settings->asyncFrameScrollingEnabled() && !settings->asyncOverflowScrollingEnabled())
2107 return false;
2108
2109 if (!m_owningLayer.page().scrollingCoordinator()->hasSubscrollers(renderer().view().frame().rootFrame().frameID()))
2110 return false;
2111
2112 return true;
2113}
2114
2115void RenderLayerBacking::setNeedsEventRegionUpdate(bool needsUpdate)
2116{
2117 m_needsEventRegionUpdate = needsUpdate;
2118}
2119
2120void RenderLayerBacking::updateEventRegion()
2121{
2122 LOG_WITH_STREAM(EventRegions, stream << m_owningLayer << " " << this << " updateEventRegion (needs update: " << needsEventRegionUpdate() << ", maintainsEventRegion: " << maintainsEventRegion() << ")")((void)0);
2123
2124 if (!maintainsEventRegion())
2125 return;
2126
2127 if (!needsEventRegionUpdate())
2128 return;
2129
2130 TraceScope scope(ComputeEventRegionsStart, ComputeEventRegionsEnd);
2131
2132 auto visibleToHitTesting = renderer().visibleToHitTesting();
2133
2134 auto setEventRegionToLayerBounds = [&](GraphicsLayer* graphicsLayer) {
2135 if (!graphicsLayer)
2136 return;
2137
2138 EventRegion eventRegion;
2139 auto eventRegionContext = eventRegion.makeContext();
2140 if (visibleToHitTesting)
2141 eventRegionContext.unite(FloatRoundedRect(FloatRect({ }, graphicsLayer->size())), renderer(), renderer().style());
2142
2143#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)(defined ENABLE_INTERACTION_REGIONS_IN_EVENT_REGION &&
ENABLE_INTERACTION_REGIONS_IN_EVENT_REGION)
2144 eventRegionContext.copyInteractionRegionsToEventRegion(renderer().document().settings().interactionRegionMinimumCornerRadius());
2145#endif
2146 graphicsLayer->setEventRegion(WTF::move(eventRegion));
2147 };
2148
2149 auto updateEventRegionForLayer = [&](GraphicsLayer& graphicsLayer) {
2150 NullGraphicsContext nullContext;
2151 EventRegion eventRegion;
2152#if ENABLE(EDITABLE_REGION)(defined ENABLE_EDITABLE_REGION && ENABLE_EDITABLE_REGION
)
2153 if (renderer().page().shouldBuildEditableRegion())
2154 eventRegion.ensureEditableRegion();
2155#endif
2156 auto eventRegionContext = eventRegion.makeContext();
2157#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)(defined ENABLE_INTERACTION_REGIONS_IN_EVENT_REGION &&
ENABLE_INTERACTION_REGIONS_IN_EVENT_REGION)
2158 eventRegionContext.reserveCapacityForInteractionRegions(graphicsLayer.eventRegion().interactionRegions().size());
2159#endif
2160 auto layerOffset = graphicsLayer.scrollOffset() - graphicsLayer.offsetFromRenderer();
2161 auto layerBounds = FloatRoundedRect(FloatRect(-layerOffset, graphicsLayer.size()));
2162
2163 if (visibleToHitTesting) {
2164 if (&graphicsLayer == m_scrolledContentsLayer) {
2165 // Initialize scrolled contents layer with layer-sized event region as it can all used for scrolling.
2166 // This avoids generating unnecessarily complex event regions. We still need to to do the paint to capture touch-action regions.
2167 eventRegionContext.unite(layerBounds, renderer(), renderer().style());
2168 }
2169 }
2170
2171 if (m_owningLayer.isRenderViewLayer() && (&graphicsLayer == m_graphicsLayer || &graphicsLayer == m_foregroundLayer)) {
2172 // Event handlers on the root cover the entire layer.
2173 eventRegionContext.unite(layerBounds, renderer(), renderer().style());
2174 }
2175
2176 auto dirtyRect = enclosingIntRect(FloatRect(FloatPoint(graphicsLayer.offsetFromRenderer()), graphicsLayer.size()));
2177 paintIntoLayer(&graphicsLayer, nullContext, dirtyRect, { }, &eventRegionContext);
2178
2179#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)(defined ENABLE_INTERACTION_REGIONS_IN_EVENT_REGION &&
ENABLE_INTERACTION_REGIONS_IN_EVENT_REGION)
2180 eventRegionContext.copyInteractionRegionsToEventRegion(renderer().document().settings().interactionRegionMinimumCornerRadius());
2181#endif
2182 eventRegion.translate(toIntSize(roundedIntPoint(layerOffset)));
2183 graphicsLayer.setEventRegion(WTF::move(eventRegion));
2184 };
2185
2186 updateEventRegionForLayer(*m_graphicsLayer);
2187
2188 setEventRegionToLayerBounds(m_scrollContainerLayer.get());
2189 setEventRegionToLayerBounds(m_layerForHorizontalScrollbar.get());
2190 setEventRegionToLayerBounds(m_layerForVerticalScrollbar.get());
2191 setEventRegionToLayerBounds(m_layerForScrollCorner.get());
2192
2193 if (m_scrolledContentsLayer)
2194 updateEventRegionForLayer(*m_scrolledContentsLayer);
2195
2196 if (m_foregroundLayer)
2197 updateEventRegionForLayer(*m_foregroundLayer);
2198
2199 setNeedsEventRegionUpdate(false);
2200}
2201#endif
2202
2203#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)(defined ENABLE_INTERACTION_REGIONS_IN_EVENT_REGION &&
ENABLE_INTERACTION_REGIONS_IN_EVENT_REGION)
2204void RenderLayerBacking::clearInteractionRegions()
2205{
2206 auto clearInteractionRegionsForLayer = [&](GraphicsLayer& graphicsLayer) {
2207 if (graphicsLayer.eventRegion().interactionRegions().isEmpty())
2208 return;
2209
2210 EventRegion eventRegion = graphicsLayer.eventRegion();
2211 eventRegion.clearInteractionRegions();
2212 graphicsLayer.setEventRegion(WTF::move(eventRegion));
2213 };
2214
2215 clearInteractionRegionsForLayer(*m_graphicsLayer);
2216
2217 if (m_scrolledContentsLayer)
2218 clearInteractionRegionsForLayer(*m_scrolledContentsLayer);
2219
2220 if (m_foregroundLayer)
2221 clearInteractionRegionsForLayer(*m_foregroundLayer);
2222}
2223#endif
2224
2225#if HAVE(CORE_ANIMATION_SEPARATED_LAYERS)(defined HAVE_CORE_ANIMATION_SEPARATED_LAYERS && HAVE_CORE_ANIMATION_SEPARATED_LAYERS
)
2226void RenderLayerBacking::updateSeparatedProperties()
2227{
2228 bool isSeparated = RenderLayerCompositor::isSeparated(renderer());
2229 m_graphicsLayer->setIsSeparated(isSeparated);
2230
2231 const auto& renderImage = dynamicDowncast<RenderImage>(renderer());
2232 if (!renderImage)
2233 return;
2234
2235 bool isSeparatedImage = [&] {
2236 if (!isSeparated)
2237 return false;
2238 if (!renderImage->cachedImage() || renderImage->cachedImage()->errorOccurred())
2239 return false;
2240 auto* image = renderImage->cachedImage()->imageForRenderer(renderImage);
2241 if (!image)
2242 return false;
2243 if (image == &Image::nullImage())
2244 return false;
2245 return !image->isAnimated() && image->isBitmapImage() && image->nativeImage();
2246 }();
2247
2248 m_graphicsLayer->setIsSeparatedImage(isSeparatedImage);
2249}
2250#endif
2251
2252bool RenderLayerBacking::updateAncestorClippingStack(Vector<CompositedClipData>&& clippingData)
2253{
2254 if (!m_ancestorClippingStack && clippingData.isEmpty())
2255 return false;
2256
2257 RefPtr scrollingCoordinator = m_owningLayer.page().scrollingCoordinator();
2258
2259 if (m_ancestorClippingStack && clippingData.isEmpty()) {
2260 m_ancestorClippingStack->clear(scrollingCoordinator);
2261 m_ancestorClippingStack = nullptr;
2262
2263 if (m_overflowControlsHostLayerAncestorClippingStack) {
2264 m_overflowControlsHostLayerAncestorClippingStack->clear(scrollingCoordinator);
2265 m_overflowControlsHostLayerAncestorClippingStack = nullptr;
2266 }
2267 return true;
2268 }
2269
2270 if (!m_ancestorClippingStack) {
2271 m_ancestorClippingStack = makeUnique<LayerAncestorClippingStack>(WTF::move(clippingData));
2272 LOG_WITH_STREAM(Compositing, stream << "layer " << &m_owningLayer << " ancestorClippingStack " << *m_ancestorClippingStack)((void)0);
2273 return true;
2274 }
2275
2276 if (m_ancestorClippingStack->equalToClipData(clippingData)) {
2277 LOG_WITH_STREAM(Compositing, stream << "layer " << &m_owningLayer << " ancestorClippingStack " << *m_ancestorClippingStack)((void)0);
2278 return false;
2279 }
2280
2281 m_ancestorClippingStack->updateWithClipData(scrollingCoordinator, WTF::move(clippingData));
2282 LOG_WITH_STREAM(Compositing, stream << "layer " << &m_owningLayer << " ancestorClippingStack " << *m_ancestorClippingStack)((void)0);
2283 if (m_overflowControlsHostLayerAncestorClippingStack)
2284 m_overflowControlsHostLayerAncestorClippingStack->updateWithClipData(scrollingCoordinator, WTF::move(clippingData));
2285 return true;
2286}
2287
2288void RenderLayerBacking::ensureOverflowControlsHostLayerAncestorClippingStack(const RenderLayer* compositedAncestor)
2289{
2290 RefPtr scrollingCoordinator = m_owningLayer.page().scrollingCoordinator();
2291 auto clippingData = m_ancestorClippingStack->compositedClipData();
2292
2293 if (m_overflowControlsHostLayerAncestorClippingStack)
2294 m_overflowControlsHostLayerAncestorClippingStack->updateWithClipData(scrollingCoordinator, WTF::move(clippingData));
2295 else
2296 m_overflowControlsHostLayerAncestorClippingStack = makeUnique<LayerAncestorClippingStack>(WTF::move(clippingData));
2297
2298 ensureClippingStackLayers(*m_overflowControlsHostLayerAncestorClippingStack);
2299
2300 LayoutRect parentGraphicsLayerRect = computeParentGraphicsLayerRect(compositedAncestor);
2301 updateClippingStackLayerGeometry(*m_overflowControlsHostLayerAncestorClippingStack, compositedAncestor, parentGraphicsLayerRect);
2302
2303 connectClippingStackLayers(*m_overflowControlsHostLayerAncestorClippingStack);
2304}
2305
2306void RenderLayerBacking::ensureClippingStackLayers(LayerAncestorClippingStack& clippingStack)
2307{
2308 for (auto& entry : clippingStack.stack()) {
2309 if (!entry.clippingLayer) {
2310 entry.clippingLayer = createGraphicsLayer(entry.clipData.isOverflowScroll ? "clip for scroller"_s : "ancestor clipping"_s);
2311 entry.clippingLayer->setMasksToBounds(true);
2312 entry.clippingLayer->setPaintingPhase({ });
2313 }
2314
2315 if (entry.clipData.isOverflowScroll) {
2316 if (!entry.scrollingLayer)
2317 entry.scrollingLayer = createGraphicsLayer("scrolling proxy"_s);
2318 } else if (entry.scrollingLayer)
2319 GraphicsLayer::unparentAndClear(entry.scrollingLayer);
2320 }
2321}
2322
2323void RenderLayerBacking::removeClippingStackLayers(LayerAncestorClippingStack& clippingStack)
2324{
2325 for (auto& entry : clippingStack.stack()) {
2326 GraphicsLayer::unparentAndClear(entry.clippingLayer);
2327 GraphicsLayer::unparentAndClear(entry.scrollingLayer);
2328 }
2329}
2330
2331void RenderLayerBacking::connectClippingStackLayers(LayerAncestorClippingStack& clippingStack)
2332{
2333 auto connectEntryLayers = [](LayerAncestorClippingStack::ClippingStackEntry& entry) {
2334 if (entry.scrollingLayer)
2335 entry.clippingLayer->setChildren({ Ref { *entry.scrollingLayer } });
2336 };
2337
2338 auto& clippingEntryStack = clippingStack.stack();
2339 for (unsigned i = 0; i < clippingEntryStack.size() - 1; ++i) {
2340 auto& entry = clippingEntryStack.at(i);
2341 connectEntryLayers(entry);
2342
2343 RefPtr entryParentForSublayers = entry.parentForSublayers();
2344 RefPtr childLayer = clippingEntryStack.at(i + 1).childForSuperlayers();
2345 entryParentForSublayers->setChildren({ Ref { *childLayer } });
2346 }
2347
2348 connectEntryLayers(clippingEntryStack.last());
2349 clippingEntryStack.last().parentForSublayers()->removeAllChildren();
2350}
2351
2352void RenderLayerBacking::updateClippingStackLayerGeometry(LayerAncestorClippingStack& clippingStack, const RenderLayer* compositedAncestor, LayoutRect& parentGraphicsLayerRect)
2353{
2354 // All clipRects in the stack are computed relative to m_owningLayer, so convert them back to compositedAncestor.
2355 auto offsetFromCompositedAncestor = toLayoutSize(m_owningLayer.convertToLayerCoords(compositedAncestor, { }, RenderLayer::AdjustForColumns));
2356 LayoutRect lastClipLayerRect = parentGraphicsLayerRect;
2357
2358 auto deviceScaleFactor = this->deviceScaleFactor();
2359 for (auto& entry : clippingStack.stack()) {
2360 auto roundedClipRect = entry.clipData.clipRect;
2361 auto clipRect = roundedClipRect.rect();
2362 LayoutSize clippingOffset = computeOffsetFromAncestorGraphicsLayer(compositedAncestor, clipRect.location() + offsetFromCompositedAncestor, deviceScaleFactor);
2363 LayoutRect snappedClippingLayerRect = snappedGraphicsLayer(clippingOffset, clipRect.size(), renderer()).m_snappedRect;
2364
2365 auto clippingLayerPosition = toLayoutPoint(snappedClippingLayerRect.location() - lastClipLayerRect.location());
2366 entry.clippingLayer->setPosition(clippingLayerPosition);
2367 entry.clippingLayer->setSize(snappedClippingLayerRect.size());
2368
2369 clipRect.setLocation({ });
2370 roundedClipRect.setRect(clipRect);
2371 entry.clippingLayer->setContentsClippingRect(FloatRoundedRect(roundedClipRect));
2372 entry.clippingLayer->setContentsRectClipsDescendants(true);
2373
2374 lastClipLayerRect = snappedClippingLayerRect;
2375
2376 if (entry.clipData.isOverflowScroll) {
2377 ScrollOffset scrollOffset;
2378 if (auto* scrollableArea = entry.clipData.clippingLayer ? entry.clipData.clippingLayer->scrollableArea() : nullptr)
2379 scrollOffset = scrollableArea->scrollOffset();
2380
2381 // scrollingLayer size and position are always 0,0.
2382 entry.scrollingLayer->setBoundsOrigin(scrollOffset);
2383 lastClipLayerRect.moveBy(-scrollOffset);
2384 }
2385 }
2386
2387 parentGraphicsLayerRect = lastClipLayerRect;
2388}
2389
2390// Return true if the layer changed.
2391bool RenderLayerBacking::updateAncestorClipping(bool needsAncestorClip, const RenderLayer* compositingAncestor)
2392{
2393 bool layersChanged = false;
2394
2395 if (needsAncestorClip) {
2396 if (compositor().updateAncestorClippingStack(m_owningLayer, compositingAncestor)) {
2397 if (m_ancestorClippingStack)
2398 ensureClippingStackLayers(*m_ancestorClippingStack);
2399
2400 layersChanged = true;
2401 }
2402 } else if (m_ancestorClippingStack) {
2403 RefPtr scrollingCoordinator = m_owningLayer.page().scrollingCoordinator();
2404
2405 m_ancestorClippingStack->clear(scrollingCoordinator);
2406 m_ancestorClippingStack = nullptr;
2407
2408 if (m_overflowControlsHostLayerAncestorClippingStack) {
2409 m_overflowControlsHostLayerAncestorClippingStack->clear(scrollingCoordinator);
2410 m_overflowControlsHostLayerAncestorClippingStack = nullptr;
2411 }
2412
2413 layersChanged = true;
2414 }
2415
2416 return layersChanged;
2417}
2418
2419// Return true if the layer changed.
2420bool RenderLayerBacking::updateDescendantClippingLayer(bool needsDescendantClip)
2421{
2422 bool layersChanged = false;
2423
2424 if (needsDescendantClip) {
2425 if (!m_childContainmentLayer && !m_isFrameLayerWithTiledBacking) {
2426 m_childContainmentLayer = createGraphicsLayer("child clipping"_s);
2427 m_childContainmentLayer->setMasksToBounds(true);
2428 m_childContainmentLayer->setContentsRectClipsDescendants(true);
2429 layersChanged = true;
2430 }
2431 } else if (hasClippingLayer()) {
2432 willDestroyLayer(m_childContainmentLayer.get());
2433 GraphicsLayer::unparentAndClear(m_childContainmentLayer);
2434 layersChanged = true;
2435 }
2436
2437 return layersChanged;
2438}
2439
2440bool RenderLayerBacking::needsRepaintOnCompositedScroll() const
2441{
2442 if (!hasScrollingLayer())
2443 return false;
2444
2445 if (Style::hasImageWithAttachment(renderer().style().backgroundLayers(), FillAttachment::LocalBackground))
2446 return true;
2447
2448 if (RefPtr scrollingCoordinator = m_owningLayer.page().scrollingCoordinator())
2449 return scrollingCoordinator->hasSynchronousScrollingReasons(m_scrollingNodeID);
2450
2451 return false;
2452}
2453
2454void RenderLayerBacking::setBackgroundLayerPaintsFixedRootBackground(bool backgroundLayerPaintsFixedRootBackground)
2455{
2456 if (backgroundLayerPaintsFixedRootBackground == m_backgroundLayerPaintsFixedRootBackground)
2457 return;
2458
2459 m_backgroundLayerPaintsFixedRootBackground = backgroundLayerPaintsFixedRootBackground;
2460
2461 if (m_backgroundLayerPaintsFixedRootBackground) {
2462 ASSERT(m_isFrameLayerWithTiledBacking)((void)0);
2463 renderer().view().frameView().removeSlowRepaintObject(*renderer().view().rendererForRootBackground());
2464 }
2465}
2466
2467void RenderLayerBacking::setRequiresBackgroundLayer(bool requiresBackgroundLayer)
2468{
2469 if (requiresBackgroundLayer == m_requiresBackgroundLayer)
2470 return;
2471
2472 m_requiresBackgroundLayer = requiresBackgroundLayer;
2473 m_owningLayer.setNeedsCompositingConfigurationUpdate();
2474}
2475
2476bool RenderLayerBacking::requiresLayerForScrollbar(Scrollbar* scrollbar) const
2477{
2478 return scrollbar && (scrollbar->isOverlayScrollbar()
2479#if !PLATFORM(IOS_FAMILY)(defined WTF_PLATFORM_IOS_FAMILY && WTF_PLATFORM_IOS_FAMILY
)
// FIXME: This should be an #if ENABLE(): webkit.org/b/210460
2480 || renderer().settings().asyncOverflowScrollingEnabled()
2481#endif
2482 );
2483}
2484
2485bool RenderLayerBacking::requiresHorizontalScrollbarLayer() const
2486{
2487 if (auto* scrollableArea = m_owningLayer.scrollableArea())
2488 return requiresLayerForScrollbar(scrollableArea->horizontalScrollbar());
2489 return false;
2490}
2491
2492bool RenderLayerBacking::requiresVerticalScrollbarLayer() const
2493{
2494 if (auto* scrollableArea = m_owningLayer.scrollableArea())
2495 return requiresLayerForScrollbar(scrollableArea->verticalScrollbar());
2496 return false;
2497}
2498
2499bool RenderLayerBacking::requiresScrollCornerLayer() const
2500{
2501 if (!is<RenderBox>(m_owningLayer.renderer()))
2502 return false;
2503
2504 auto* scrollableArea = m_owningLayer.scrollableArea();
2505 if (!scrollableArea)
2506 return false;
2507
2508 auto cornerRect = scrollableArea->overflowControlsRects().scrollCornerOrResizerRect();
2509 if (cornerRect.isEmpty())
2510 return false;
2511
2512 RefPtr verticalScrollbar = scrollableArea->verticalScrollbar();
2513 RefPtr scrollbar = verticalScrollbar ? verticalScrollbar.get() : scrollableArea->horizontalScrollbar();
2514 return requiresLayerForScrollbar(scrollbar);
2515}
2516
2517void RenderLayerBacking::clearOverflowControlsLayers()
2518{
2519 auto destroyLayer = [&](RefPtr<GraphicsLayer>& layer) {
2520 if (!layer)
2521 return;
2522
2523 willDestroyLayer(layer.get());
2524 GraphicsLayer::unparentAndClear(layer);
2525 };
2526
2527 destroyLayer(m_overflowControlsContainer);
2528 destroyLayer(m_layerForHorizontalScrollbar);
2529 destroyLayer(m_layerForVerticalScrollbar);
2530 destroyLayer(m_layerForScrollCorner);
2531}
2532
2533bool RenderLayerBacking::updateOverflowControlsLayers(bool needsHorizontalScrollbarLayer, bool needsVerticalScrollbarLayer, bool needsScrollCornerLayer)
2534{
2535 auto createOrDestroyLayer = [&](RefPtr<GraphicsLayer>& layer, bool needLayer, bool drawsContent, ASCIILiteral layerName) {
2536 if (needLayer == !!layer)
2537 return false;
2538
2539 if (needLayer) {
2540 layer = createGraphicsLayer(layerName);
2541 if (drawsContent) {
2542 layer->setAllowsBackingStoreDetaching(false);
2543 layer->setAllowsTiling(false);
2544 } else {
2545 layer->setPaintingPhase({ });
2546 layer->setDrawsContent(false);
2547 }
2548 } else {
2549 willDestroyLayer(layer.get());
2550 GraphicsLayer::unparentAndClear(layer);
2551 }
2552 return true;
2553 };
2554
2555 bool layersChanged = createOrDestroyLayer(m_overflowControlsContainer, needsHorizontalScrollbarLayer || needsVerticalScrollbarLayer || needsScrollCornerLayer, false, "overflow controls container"_s);
2556
2557 bool horizontalScrollbarLayerChanged = createOrDestroyLayer(m_layerForHorizontalScrollbar, needsHorizontalScrollbarLayer, true, "horizontal scrollbar"_s);
2558 layersChanged |= horizontalScrollbarLayerChanged;
2559
2560 bool verticalScrollbarLayerChanged = createOrDestroyLayer(m_layerForVerticalScrollbar, needsVerticalScrollbarLayer, true, "vertical scrollbar"_s);
2561 layersChanged |= verticalScrollbarLayerChanged;
2562
2563 layersChanged |= createOrDestroyLayer(m_layerForScrollCorner, needsScrollCornerLayer, true, "scroll corner"_s);
2564
2565 if (RefPtr scrollingCoordinator = m_owningLayer.page().scrollingCoordinator()) {
2566 if (auto* scrollableArea = m_owningLayer.scrollableArea()) {
2567 if (horizontalScrollbarLayerChanged)
2568 scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(*scrollableArea, ScrollbarOrientation::Horizontal);
2569 if (verticalScrollbarLayerChanged)
2570 scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(*scrollableArea, ScrollbarOrientation::Vertical);
2571 }
2572 }
2573
2574 return layersChanged;
2575}
2576
2577void RenderLayerBacking::positionOverflowControlsLayers()
2578{
2579 auto* scrollableArea = m_owningLayer.scrollableArea();
2580 if (!scrollableArea || !scrollableArea->hasScrollbars())
2581 return;
2582 // FIXME: Should do device-pixel snapping.
2583 auto box = renderBox();
2584 auto borderBox = snappedIntRect(box->borderBoxRect());
2585
2586 // m_overflowControlsContainer is positioned using the paddingBoxRectIncludingScrollbar.
2587 auto paddingBox = snappedIntRect(box->paddingBoxRectIncludingScrollbar());
2588 auto paddingBoxInset = paddingBox.location() - borderBox.location();
2589
2590 auto positionScrollbarLayer = [](GraphicsLayer& layer, const IntRect& scrollbarRect, IntSize paddingBoxInset) {
2591 layer.setPosition(scrollbarRect.location() - paddingBoxInset);
2592 layer.setSize(scrollbarRect.size());
2593 if (layer.usesContentsLayer()) {
2594 IntRect barRect = IntRect(IntPoint(), scrollbarRect.size());
2595 layer.setContentsRect(barRect);
2596 layer.setContentsClippingRect(FloatRoundedRect(barRect));
2597 }
2598 };
2599
2600 // These rects are relative to the borderBoxRect.
2601 auto rects = scrollableArea->overflowControlsRects();
2602 if (RefPtr layer = layerForHorizontalScrollbar()) {
2603 positionScrollbarLayer(*layer, rects.horizontalScrollbar, paddingBoxInset);
2604 layer->setDrawsContent(scrollableArea->horizontalScrollbar() && !layer->usesContentsLayer());
2605 }
2606
2607 if (RefPtr layer = layerForVerticalScrollbar()) {
2608 positionScrollbarLayer(*layer, rects.verticalScrollbar, paddingBoxInset);
2609 layer->setDrawsContent(scrollableArea->verticalScrollbar() && !layer->usesContentsLayer());
2610 }
2611
2612 if (RefPtr layer = layerForScrollCorner()) {
2613 auto cornerRect = rects.scrollCornerOrResizerRect();
2614 layer->setPosition(cornerRect.location() - paddingBoxInset);
2615 layer->setSize(cornerRect.size());
2616 layer->setDrawsContent(!cornerRect.isEmpty());
2617 }
2618}
2619
2620static bool ancestorLayerWillCombineTransform(const RenderLayer* compositingAncestor)
2621{
2622 if (!compositingAncestor)
2623 return false;
2624
2625 auto& style = compositingAncestor->renderer().style();
2626 return style.usedTransformStyle3D() == TransformStyle3D::Preserve3D
2627 || !style.perspective().isNone();
2628}
2629
2630bool RenderLayerBacking::updateTransformFlatteningLayer(const RenderLayer* compositingAncestor)
2631{
2632 bool needsFlatteningLayer = false;
2633 // If our parent layer has preserve-3d or perspective, and it's not our DOM parent, then we need a flattening layer to block that from being applied in 3d.
2634 if (ancestorLayerWillCombineTransform(compositingAncestor) && !m_owningLayer.ancestorLayerIsDOMParent(compositingAncestor))
2635 needsFlatteningLayer = true;
2636
2637 bool layerChanged = false;
2638 if (needsFlatteningLayer) {
2639 if (!m_transformFlatteningLayer) {
2640 m_transformFlatteningLayer = createGraphicsLayer(makeString(m_owningLayer.name(), " (3d flattening)"_s));
2641 layerChanged = true;
2642 }
2643 } else if (m_transformFlatteningLayer) {
2644 willDestroyLayer(m_transformFlatteningLayer.get());
2645 GraphicsLayer::unparentAndClear(m_transformFlatteningLayer);
2646 layerChanged = true;
2647 }
2648
2649 return layerChanged;
2650}
2651
2652bool RenderLayerBacking::updateViewportConstrainedSublayers(ViewportConstrainedSublayers sublayers)
2653{
2654 bool layerChanged = false;
2655
2656 using enum ViewportConstrainedSublayers;
2657
2658 bool needsAnchorLayer = false;
2659 bool needsClippingLayer = false;
2660 switch (sublayers) {
2661 case None:
2662 break;
2663 case ClippingAndAnchor:
2664 needsClippingLayer = true;
2665 [[fallthrough]];
2666 case Anchor:
2667 needsAnchorLayer = true;
2668 break;
2669 }
2670
2671 if (needsAnchorLayer) {
2672 if (!m_viewportAnchorLayer) {
2673 auto layerName = makeString(m_owningLayer.name(), " (anchor)"_s);
2674 m_viewportAnchorLayer = createGraphicsLayer(layerName, GraphicsLayer::Type::Structural);
2675 layerChanged = true;
2676 }
2677 } else if (m_viewportAnchorLayer) {
2678 willDestroyLayer(m_viewportAnchorLayer.get());
2679 GraphicsLayer::unparentAndClear(m_viewportAnchorLayer);
2680 layerChanged = true;
2681 }
2682
2683 if (needsClippingLayer) {
2684 if (!m_viewportClippingLayer) {
2685 auto layerName = makeString(m_owningLayer.name(), " (clipping)"_s);
2686 m_viewportClippingLayer = createGraphicsLayer(layerName, GraphicsLayer::Type::Normal);
2687 m_viewportClippingLayer->setMasksToBounds(true);
2688 layerChanged = true;
2689 }
2690 } else if (m_viewportClippingLayer) {
2691 willDestroyLayer(m_viewportClippingLayer.get());
2692 GraphicsLayer::unparentAndClear(m_viewportClippingLayer);
2693 layerChanged = true;
2694 }
2695
2696 return layerChanged;
2697}
2698
2699bool RenderLayerBacking::updateForegroundLayer(bool needsForegroundLayer)
2700{
2701 bool layerChanged = false;
2702 if (needsForegroundLayer) {
2703 if (!m_foregroundLayer) {
2704 auto layerName = makeString(m_owningLayer.name(), " (foreground)"_s);
2705 m_foregroundLayer = createGraphicsLayer(layerName);
2706 m_foregroundLayer->setDrawsContent(true);
2707 layerChanged = true;
2708 }
2709 } else if (m_foregroundLayer) {
2710 willDestroyLayer(m_foregroundLayer.get());
2711 GraphicsLayer::unparentAndClear(m_foregroundLayer);
2712 layerChanged = true;
2713 }
2714
2715 return layerChanged;
2716}
2717
2718bool RenderLayerBacking::updateBackgroundLayer(bool needsBackgroundLayer)
2719{
2720 bool layerChanged = false;
2721 if (needsBackgroundLayer) {
2722 if (!m_backgroundLayer) {
2723 auto layerName = makeString(m_owningLayer.name(), " (background)"_s);
2724 m_backgroundLayer = createGraphicsLayer(layerName);
2725 m_backgroundLayer->setDrawsContent(true);
2726 m_backgroundLayer->setAnchorPoint(FloatPoint3D());
2727 layerChanged = true;
2728 }
2729
2730 if (!m_contentsContainmentLayer) {
2731 auto layerName = makeString(m_owningLayer.name(), " (contents containment)"_s);
2732 m_contentsContainmentLayer = createGraphicsLayer(layerName);
2733 m_contentsContainmentLayer->setAppliesPageScale(true);
2734 m_graphicsLayer->setAppliesPageScale(false);
2735 layerChanged = true;
2736 }
2737 } else {
2738 if (m_backgroundLayer) {
2739 willDestroyLayer(m_backgroundLayer.get());
2740 GraphicsLayer::unparentAndClear(m_backgroundLayer);
2741 layerChanged = true;
2742 }
2743 if (m_contentsContainmentLayer) {
2744 willDestroyLayer(m_contentsContainmentLayer.get());
2745 GraphicsLayer::unparentAndClear(m_contentsContainmentLayer);
2746 layerChanged = true;
2747 m_graphicsLayer->setAppliesPageScale(true);
2748 }
2749 }
2750
2751 return layerChanged;
2752}
2753
2754// Masking layer is used for masks or clip-path.
2755bool RenderLayerBacking::updateMaskingLayer(bool hasMask, bool hasClipPath)
2756{
2757 bool layerChanged = false;
2758 if (hasMask || hasClipPath) {
2759 OptionSet<GraphicsLayerPaintingPhase> maskPhases;
2760 if (hasMask)
2761 maskPhases = GraphicsLayerPaintingPhase::Mask;
2762
2763 if (hasClipPath) {
2764 // If we have a mask, we need to paint the combined clip-path and mask into the mask layer.
2765 if (hasMask || WTF::holdsAlternative<Style::ReferencePath>(renderer().style().clipPath()) || !GraphicsLayer::supportsLayerType(GraphicsLayer::Type::Shape))
2766 maskPhases.add(GraphicsLayerPaintingPhase::ClipPath);
2767 }
2768
2769 bool paintsContent = !maskPhases.isEmpty();
2770 GraphicsLayer::Type requiredLayerType = paintsContent ? GraphicsLayer::Type::Normal : GraphicsLayer::Type::Shape;
2771 if (m_maskLayer && m_maskLayer->type() != requiredLayerType) {
2772 m_graphicsLayer->setMaskLayer(nullptr);
2773 willDestroyLayer(m_maskLayer.get());
2774 GraphicsLayer::clear(m_maskLayer);
2775 }
2776
2777 if (!m_maskLayer) {
2778 m_maskLayer = createGraphicsLayer("mask"_s, requiredLayerType);
2779 layerChanged = true;
2780 m_graphicsLayer->setMaskLayer(m_maskLayer.copyRef());
2781 // We need a geometry update to size the new mask layer.
2782 m_owningLayer.setNeedsCompositingGeometryUpdate();
2783 }
2784 m_maskLayer->setDrawsContent(paintsContent);
2785 m_maskLayer->setPaintingPhase(maskPhases);
2786 } else if (m_maskLayer) {
2787 m_graphicsLayer->setMaskLayer(nullptr);
2788 willDestroyLayer(m_maskLayer.get());
2789 GraphicsLayer::clear(m_maskLayer);
2790 layerChanged = true;
2791 }
2792
2793 return layerChanged;
2794}
2795
2796bool RenderLayerBacking::updateScrollingLayers(bool needsScrollingLayers)
2797{
2798 if (needsScrollingLayers == !!m_scrollContainerLayer)
2799 return false;
2800
2801 if (!m_scrollContainerLayer) {
2802 // Outer layer which corresponds with the scroll view. This never paints content.
2803 m_scrollContainerLayer = createGraphicsLayer("scroll container"_s, GraphicsLayer::Type::ScrollContainer);
2804 m_scrollContainerLayer->setPaintingPhase({ });
2805 m_scrollContainerLayer->setDrawsContent(false);
2806 m_scrollContainerLayer->setMasksToBounds(true);
2807
2808 // Inner layer which renders the content that scrolls.
2809 m_scrolledContentsLayer = createGraphicsLayer("scrolled contents"_s, GraphicsLayer::Type::ScrolledContents);
2810 m_scrolledContentsLayer->setDrawsContent(true);
2811 m_scrolledContentsLayer->setAnchorPoint({ });
2812 m_scrollContainerLayer->addChild(*m_scrolledContentsLayer);
2813 } else {
2814 compositor().willRemoveScrollingLayerWithBacking(m_owningLayer, *this);
2815
2816 willDestroyLayer(m_scrollContainerLayer.get());
2817 willDestroyLayer(m_scrolledContentsLayer.get());
2818
2819 GraphicsLayer::unparentAndClear(m_scrollContainerLayer);
2820 GraphicsLayer::unparentAndClear(m_scrolledContentsLayer);
2821 }
2822
2823 if (m_scrollContainerLayer)
2824 compositor().didAddScrollingLayer(m_owningLayer);
2825
2826 return true;
2827}
2828
2829void RenderLayerBacking::detachFromScrollingCoordinator(OptionSet<ScrollCoordinationRole> roles)
2830{
2831 if (!m_scrollingNodeID && !m_ancestorClippingStack && !m_frameHostingNodeID && !m_pluginHostingNodeID && !m_viewportConstrainedNodeID && !m_positioningNodeID)
2832 return;
2833
2834 RefPtr scrollingCoordinator = m_owningLayer.page().scrollingCoordinator();
2835 if (!scrollingCoordinator)
2836 return;
2837
2838 if (roles.contains(ScrollCoordinationRole::Scrolling) && m_scrollingNodeID) {
2839 LOG_WITH_STREAM(Compositing, stream << "Detaching Scrolling node " << *m_scrollingNodeID)((void)0);
2840 scrollingCoordinator->unparentChildrenAndDestroyNode(*m_scrollingNodeID);
2841 m_scrollingNodeID = std::nullopt;
2842
2843#if ENABLE(SCROLLING_THREAD)(defined 1 && 1)
2844 if (m_scrollContainerLayer)
2845 m_scrollContainerLayer->setScrollingNodeID(std::nullopt);
2846 if (m_layerForHorizontalScrollbar)
2847 m_layerForHorizontalScrollbar->setScrollingNodeID(std::nullopt);
2848 if (m_layerForVerticalScrollbar)
2849 m_layerForVerticalScrollbar->setScrollingNodeID(std::nullopt);
2850 if (m_layerForScrollCorner)
2851 m_layerForScrollCorner->setScrollingNodeID(std::nullopt);
2852#endif
2853 }
2854
2855 if (roles.contains(ScrollCoordinationRole::ScrollingProxy) && m_ancestorClippingStack) {
2856 m_ancestorClippingStack->detachFromScrollingCoordinator(*scrollingCoordinator);
2857 LOG_WITH_STREAM(Compositing, stream << "Detaching nodes in ancestor clipping stack")((void)0);
2858 }
2859
2860 if (roles.contains(ScrollCoordinationRole::FrameHosting) && m_frameHostingNodeID) {
2861 LOG_WITH_STREAM(Compositing, stream << "Detaching FrameHosting node " << *m_frameHostingNodeID)((void)0);
2862 scrollingCoordinator->unparentChildrenAndDestroyNode(*m_frameHostingNodeID);
2863 m_frameHostingNodeID = std::nullopt;
2864 }
2865
2866 if (roles.contains(ScrollCoordinationRole::PluginHosting) && m_pluginHostingNodeID) {
2867 LOG_WITH_STREAM(Compositing, stream << "Detaching PluginHosting node " << *m_pluginHostingNodeID)((void)0);
2868 scrollingCoordinator->unparentChildrenAndDestroyNode(*m_pluginHostingNodeID);
2869 m_pluginHostingNodeID = std::nullopt;
2870 }
2871
2872 if (roles.contains(ScrollCoordinationRole::ViewportConstrained) && m_viewportConstrainedNodeID) {
2873 LOG_WITH_STREAM(Compositing, stream << "Detaching ViewportConstrained node " << *m_viewportConstrainedNodeID)((void)0);
2874 scrollingCoordinator->unparentChildrenAndDestroyNode(*m_viewportConstrainedNodeID);
2875 m_viewportConstrainedNodeID = std::nullopt;
2876 }
2877
2878 if (roles.contains(ScrollCoordinationRole::Positioning) && m_positioningNodeID) {
2879 LOG_WITH_STREAM(Compositing, stream << "Detaching Positioned node " << *m_positioningNodeID)((void)0);
2880 scrollingCoordinator->unparentChildrenAndDestroyNode(*m_positioningNodeID);
2881 m_positioningNodeID = std::nullopt;
2882#if ENABLE(SCROLLING_THREAD)(defined 1 && 1)
2883 m_graphicsLayer->setScrollingNodeID(std::nullopt);
2884#endif
2885 }
2886}
2887
2888void RenderLayerBacking::setScrollingNodeIDForRole(ScrollingNodeID nodeID, ScrollCoordinationRole role)
2889{
2890 switch (role) {
2891 case ScrollCoordinationRole::Scrolling:
2892 m_scrollingNodeID = nodeID;
2893#if ENABLE(SCROLLING_THREAD)(defined 1 && 1)
2894 if (m_scrollContainerLayer)
2895 m_scrollContainerLayer->setScrollingNodeID(m_scrollingNodeID);
2896
2897 if (m_layerForHorizontalScrollbar)
2898 m_layerForHorizontalScrollbar->setScrollingNodeID(m_scrollingNodeID);
2899 if (m_layerForVerticalScrollbar)
2900 m_layerForVerticalScrollbar->setScrollingNodeID(m_scrollingNodeID);
2901 if (m_layerForScrollCorner)
2902 m_layerForScrollCorner->setScrollingNodeID(m_scrollingNodeID);
2903#endif
2904 break;
2905 case ScrollCoordinationRole::ScrollingProxy:
2906 // These nodeIDs are stored in m_ancestorClippingStack.
2907 ASSERT_NOT_REACHED()((void)0);
2908 break;
2909 case ScrollCoordinationRole::FrameHosting:
2910 m_frameHostingNodeID = nodeID;
2911 break;
2912 case ScrollCoordinationRole::PluginHosting:
2913 m_pluginHostingNodeID = nodeID;
2914 break;
2915 case ScrollCoordinationRole::ViewportConstrained:
2916 m_viewportConstrainedNodeID = nodeID;
2917 break;
2918 case ScrollCoordinationRole::Positioning:
2919 m_positioningNodeID = nodeID;
2920#if ENABLE(SCROLLING_THREAD)(defined 1 && 1)
2921 m_graphicsLayer->setScrollingNodeID(m_positioningNodeID);
2922#endif
2923 break;
2924 }
2925}
2926
2927float RenderLayerBacking::compositingOpacity(float rendererOpacity) const
2928{
2929 float finalOpacity = rendererOpacity;
2930
2931 for (CheckedPtr curr = m_owningLayer.stackingContext(); curr; curr = curr->stackingContext()) {
2932 // If we found a compositing layer, we want to compute opacity
2933 // relative to it. So we can break here.
2934 if (curr->isComposited())
2935 break;
2936
2937 finalOpacity *= curr->renderer().opacity();
2938 }
2939
2940 return finalOpacity;
2941}
2942
2943// FIXME: Code is duplicated in RenderLayer. Also, we should probably not consider filters a box decoration here.
2944static inline bool hasVisibleBoxDecorations(const RenderStyle& style)
2945{
2946 return style.border().hasVisibleBorder()
2947 || style.border().hasBorderRadius()
2948 || style.hasOutline()
2949 || style.hasUsedAppearance()
2950 || !style.boxShadow().isNone()
2951 || !style.filter().isNone();
2952}
2953
2954static bool canDirectlyCompositeBackgroundBackgroundImage(const RenderElement& renderer)
2955{
2956 const RenderStyle& style = renderer.style();
2957
2958 if (!GraphicsLayer::supportsContentsTiling())
2959 return false;
2960
2961 auto& backgroundLayers = style.backgroundLayers();
2962 if (backgroundLayers.usedLength() > 1)
2963 return false;
2964
2965 if (!Style::imagesAreLoaded(backgroundLayers, renderer))
2966 return false;
2967
2968 auto& layer = backgroundLayers.usedFirst();
2969
2970 if (layer.attachment() != FillAttachment::ScrollBackground)
2971 return false;
2972
2973 // FIXME: Allow color+image compositing when it makes sense.
2974 // For now bailing out.
2975 if (style.visitedDependentBackgroundColorApplyingColorFilter().isVisible())
2976 return false;
2977
2978 // FIXME: support gradients with isGeneratedImage.
2979 RefPtr styleImage = layer.image().tryStyleImage();
2980 if (!styleImage->hasCachedImage())
2981 return false;
2982
2983 RefPtr image = styleImage->cachedImage()->image();
2984 if (!image->isBitmapImage())
2985 return false;
2986
2987 return true;
2988}
2989
2990static bool hasPaintedBoxDecorationsOrBackgroundImage(const RenderElement& renderer)
2991{
2992 const RenderStyle& style = renderer.style();
2993
2994 if (hasVisibleBoxDecorations(style))
2995 return true;
2996
2997 if (!Style::hasImageInAnyLayer(style.backgroundLayers()))
2998 return false;
2999
3000 return !canDirectlyCompositeBackgroundBackgroundImage(renderer);
3001}
3002
3003static inline bool hasPerspectiveOrPreserves3D(const RenderStyle& style)
3004{
3005 return !style.perspective().isNone() || style.usedTransformStyle3D() == TransformStyle3D::Preserve3D;
3006}
3007
3008Color RenderLayerBacking::rendererBackgroundColor() const
3009{
3010 RenderElement* backgroundRenderer = nullptr;
3011 if (renderer().isDocumentElementRenderer())
3012 backgroundRenderer = renderer().view().rendererForRootBackground();
3013
3014 if (!backgroundRenderer)
3015 backgroundRenderer = &renderer();
3016
3017 return backgroundRenderer->style().visitedDependentBackgroundColorApplyingColorFilter();
3018}
3019
3020void RenderLayerBacking::updateDirectlyCompositedBackgroundColor(PaintedContentsInfo& contentsInfo, bool& didUpdateContentsRect)
3021{
3022 if (m_backgroundLayer && !m_backgroundLayerPaintsFixedRootBackground && !contentsInfo.paintsBoxDecorations()) {
3023 m_graphicsLayer->setContentsToSolidColor(Color());
3024 m_backgroundLayer->setContentsToSolidColor(rendererBackgroundColor());
3025
3026 FloatRect contentsRect = backgroundBoxForSimpleContainerPainting();
3027 // NOTE: This is currently only used by RenderFullScreen, which we want to be
3028 // big enough to hide overflow areas of the root.
3029 contentsRect.inflate(contentsRect.size());
3030 m_backgroundLayer->setContentsRect(contentsRect);
3031 m_backgroundLayer->setContentsClippingRect(FloatRoundedRect(contentsRect));
3032 return;
3033 }
3034
3035 if (!contentsInfo.isSimpleContainer() || (is<RenderBox>(renderer()) && !BackgroundPainter::paintsOwnBackground(*renderBox()))) {
3036 m_graphicsLayer->setContentsToSolidColor(Color());
3037 return;
3038 }
3039
3040 Color backgroundColor = rendererBackgroundColor();
3041
3042 // An unset (invalid) color will remove the solid color.
3043 m_graphicsLayer->setContentsToSolidColor(backgroundColor);
3044 FloatRect contentsRect = backgroundBoxForSimpleContainerPainting();
3045 m_graphicsLayer->setContentsRect(contentsRect);
3046 m_graphicsLayer->setContentsClippingRect(FloatRoundedRect(contentsRect));
3047 didUpdateContentsRect = true;
3048}
3049
3050void RenderLayerBacking::updateDirectlyCompositedBackgroundImage(PaintedContentsInfo& contentsInfo, bool& didUpdateContentsRect)
3051{
3052 if (!GraphicsLayer::supportsContentsTiling())
3053 return;
3054
3055 if (contentsInfo.isDirectlyCompositedImage())
3056 return;
3057
3058 if (!contentsInfo.isSimpleContainer()) {
3059 m_graphicsLayer->setContentsToImage(nullptr);
3060 return;
3061 }
3062
3063 auto& backgroundLayers = renderer().style().backgroundLayers();
3064 if (!Style::hasImageInAnyLayer(backgroundLayers)) {
3065 m_graphicsLayer->setContentsToImage(nullptr);
3066 return;
3067 }
3068
3069 auto& backgroundLayer = backgroundLayers.usedFirst();
3070 auto backgroundBox = LayoutRect { backgroundBoxForSimpleContainerPainting() };
3071 // FIXME: Absolute paint location is required here.
3072 auto geometry = BackgroundPainter::calculateFillLayerImageGeometry(*renderBox(), renderBox(), backgroundLayer, renderer().style().usedZoomForLength(), { }, backgroundBox);
3073
3074 m_graphicsLayer->setContentsTileSize(geometry.tileSize);
3075 m_graphicsLayer->setContentsTilePhase(geometry.phase);
3076 m_graphicsLayer->setContentsRect(geometry.destinationRect);
3077 m_graphicsLayer->setContentsClippingRect(FloatRoundedRect(geometry.destinationRect));
3078 m_graphicsLayer->setContentsToImage(backgroundLayer.image().tryStyleImage()->cachedImage()->image());
3079
3080 didUpdateContentsRect = true;
3081}
3082
3083void RenderLayerBacking::updateRootLayerConfiguration()
3084{
3085 if (!m_isFrameLayerWithTiledBacking)
3086 return;
3087
3088 Color backgroundColor;
3089 bool viewIsTransparent = compositor().viewHasTransparentBackground(&backgroundColor);
3090
3091 if (m_backgroundLayerPaintsFixedRootBackground && m_backgroundLayer) {
3092 if (m_isMainFrameRenderViewLayer) {
3093 m_backgroundLayer->setBackgroundColor(backgroundColor);
3094 m_backgroundLayer->setContentsOpaque(!viewIsTransparent);
3095 }
3096
3097 m_graphicsLayer->setBackgroundColor(Color());
3098 m_graphicsLayer->setContentsOpaque(false);
3099 } else if (m_isMainFrameRenderViewLayer) {
3100 m_graphicsLayer->setBackgroundColor(backgroundColor);
3101 m_graphicsLayer->setContentsOpaque(!viewIsTransparent);
3102 }
3103}
3104
3105void RenderLayerBacking::updatePaintingPhases()
3106{
3107 // Phases for m_maskLayer are set elsewhere.
3108 OptionSet<GraphicsLayerPaintingPhase> primaryLayerPhases = { GraphicsLayerPaintingPhase::Background, GraphicsLayerPaintingPhase::Foreground };
3109
3110 if (m_foregroundLayer) {
3111 OptionSet<GraphicsLayerPaintingPhase> foregroundLayerPhases { GraphicsLayerPaintingPhase::Foreground };
3112
3113 if (m_scrolledContentsLayer)
3114 foregroundLayerPhases.add(GraphicsLayerPaintingPhase::OverflowContents);
3115
3116 m_foregroundLayer->setPaintingPhase(foregroundLayerPhases);
3117 primaryLayerPhases.remove(GraphicsLayerPaintingPhase::Foreground);
3118 }
3119
3120 if (m_backgroundLayer) {
3121 m_backgroundLayer->setPaintingPhase(GraphicsLayerPaintingPhase::Background);
3122 primaryLayerPhases.remove(GraphicsLayerPaintingPhase::Background);
3123 }
3124
3125 if (m_scrolledContentsLayer) {
3126 OptionSet<GraphicsLayerPaintingPhase> scrolledContentLayerPhases = { GraphicsLayerPaintingPhase::OverflowContents, GraphicsLayerPaintingPhase::CompositedScroll };
3127 if (!m_foregroundLayer)
3128 scrolledContentLayerPhases.add(GraphicsLayerPaintingPhase::Foreground);
3129 m_scrolledContentsLayer->setPaintingPhase(scrolledContentLayerPhases);
3130
3131 primaryLayerPhases.remove(GraphicsLayerPaintingPhase::Foreground);
3132 primaryLayerPhases.add(GraphicsLayerPaintingPhase::CompositedScroll);
3133 }
3134
3135 m_graphicsLayer->setPaintingPhase(primaryLayerPhases);
3136}
3137
3138static bool supportsDirectlyCompositedBoxDecorations(const RenderLayerModelObject& renderer)
3139{
3140 const RenderStyle& style = renderer.style();
3141 if (renderer.hasClip())
3142 return false;
3143
3144 if (hasPaintedBoxDecorationsOrBackgroundImage(renderer))
3145 return false;
3146
3147 // FIXME: We can't create a directly composited background if this
3148 // layer will have children that intersect with the background layer.
3149 // A better solution might be to introduce a flattening layer if
3150 // we do direct box decoration composition.
3151 // https://bugs.webkit.org/show_bug.cgi?id=119461
3152 if (hasPerspectiveOrPreserves3D(style))
3153 return false;
3154
3155 return true;
3156}
3157
3158bool RenderLayerBacking::paintsBoxDecorations() const
3159{
3160 if (!m_owningLayer.hasVisibleBoxDecorations())
3161 return false;
3162
3163 return !supportsDirectlyCompositedBoxDecorations(renderer());
3164}
3165
3166void RenderLayerBacking::determinePaintsContent(RenderLayer::PaintedContentRequest& request) const
3167{
3168 m_owningLayer.updateDescendantDependentFlags();
3169 bool shouldScanDescendants = m_owningLayer.hasVisibleContent();
3170
3171#if HAVE(SUPPORT_HDR_DISPLAY)(defined 1 && 1)
3172 if (!request.isHDRContentSatisfied())
3173 shouldScanDescendants = true;
3174#endif
3175
3176 if (shouldScanDescendants) {
3177 m_owningLayer.determineNonLayerDescendantsPaintedContent(request);
3178
3179 if (request.isSatisfied())
3180 return;
3181 }
3182
3183 determineNonCompositedLayerDescendantsPaintedContent(request);
3184
3185 if (request.isSatisfied())
3186 return;
3187
3188 if (is<RenderSVGModelObject>(m_owningLayer.renderer())) {
3189 // FIXME: [LBSE] Eventually cache if we're part of a RenderSVGHiddenContainer subtree to avoid tree walks.
3190 // FIXME: [LBSE] Eventually refine the logic to end up with a narrower set of conditions (webkit.org/b/243417).
3191 if (m_owningLayer.hasVisibleContent() && !lineageOfType<RenderSVGHiddenContainer>(m_owningLayer.renderer()).first())
3192 request.setHasPaintedContent();
3193
3194 if (request.isSatisfied())
3195 return;
3196 }
3197
3198 if (request.hasPaintedContent == RequestState::Unknown)
3199 request.hasPaintedContent = RequestState::False;
3200
3201#if HAVE(SUPPORT_HDR_DISPLAY)(defined 1 && 1)
3202 if (request.hasHDRContent == RequestState::Unknown)
3203 request.hasHDRContent = RequestState::False;
3204#endif
3205}
3206
3207// A "simple container layer" is a RenderLayer which has no visible content to render.
3208// It may have no children, or all its children may be themselves composited.
3209// This is a useful optimization, because it allows us to avoid allocating backing store.
3210bool RenderLayerBacking::isSimpleContainerCompositingLayer(PaintedContentsInfo& contentsInfo) const
3211{
3212 if (m_owningLayer.isRenderViewLayer())
3213 return false;
3214
3215 if (hasBackingSharingLayers())
3216 return false;
3217
3218 if (auto* replaced = dynamicDowncast<RenderReplaced>(renderer())) {
3219 if (replaced->paintsContent())
3220 return false;
3221 }
3222
3223 if (renderer().isRenderTextControl())
3224 return false;
3225
3226 if (contentsInfo.paintsBoxDecorations() || contentsInfo.paintsContent())
3227 return false;
3228
3229 if (renderer().style().backgroundLayers().usedFirst().clip() == FillBox::Text)
3230 return false;
3231
3232 if (renderer().isDocumentElementRenderer() && m_owningLayer.isolatesCompositedBlending())
3233 return false;
3234
3235 return true;
3236}
3237
3238// Returning true stops the traversal.
3239enum class LayerTraversal { Continue, Stop };
3240
3241static LayerTraversal traverseVisibleNonCompositedDescendantLayers(RenderLayer& parent, NOESCAPE[[clang::noescape]] const Function<LayerTraversal(const RenderLayer&)>& layerFunc)
3242{
3243 // FIXME: We shouldn't be called with a stale z-order lists. See bug 85512.
3244 parent.updateLayerListsIfNeeded();
3245
3246#if ASSERT_ENABLED0
3247 LayerListMutationDetector mutationChecker(parent);
3248#endif
3249
3250 for (CheckedPtr childLayer : parent.normalFlowLayers()) {
3251 if (compositedWithOwnBackingStore(*childLayer))
3252 continue;
3253
3254 if (layerFunc(*childLayer) == LayerTraversal::Stop)
3255 return LayerTraversal::Stop;
3256
3257 if (traverseVisibleNonCompositedDescendantLayers(*childLayer, layerFunc) == LayerTraversal::Stop)
3258 return LayerTraversal::Stop;
3259 }
3260
3261 if (parent.isStackingContext() && !parent.hasVisibleDescendant())
3262 return LayerTraversal::Continue;
3263
3264 // Use the m_hasCompositingDescendant bit to optimize?
3265 for (CheckedPtr childLayer : parent.negativeZOrderLayers()) {
3266 if (compositedWithOwnBackingStore(*childLayer))
3267 continue;
3268
3269 if (layerFunc(*childLayer) == LayerTraversal::Stop)
3270 return LayerTraversal::Stop;
3271
3272 if (traverseVisibleNonCompositedDescendantLayers(*childLayer, layerFunc) == LayerTraversal::Stop)
3273 return LayerTraversal::Stop;
3274 }
3275
3276 for (CheckedPtr childLayer : parent.positiveZOrderLayers()) {
3277 if (compositedWithOwnBackingStore(*childLayer))
3278 continue;
3279
3280 if (layerFunc(*childLayer) == LayerTraversal::Stop)
3281 return LayerTraversal::Stop;
3282
3283 if (traverseVisibleNonCompositedDescendantLayers(*childLayer, layerFunc) == LayerTraversal::Stop)
3284 return LayerTraversal::Stop;
3285 }
3286
3287 return LayerTraversal::Continue;
3288}
3289
3290static std::optional<bool> intersectsWithAncestor(const RenderLayer& child, const RenderLayer& ancestor, const LayoutRect& ancestorCompositedBounds)
3291{
3292 // If any layers between child and ancestor are transformed, then adjusting the offset is
3293 // insufficient to convert coordinates into ancestor's coordinate space.
3294 if (!child.canUseOffsetFromAncestor(ancestor))
3295 return std::nullopt;
3296
3297 auto overlap = child.boundingBox(&ancestor, child.offsetFromAncestor(&ancestor), RenderLayer::UseFragmentBoxesExcludingCompositing);
3298 return overlap.intersects(ancestorCompositedBounds);
3299}
3300
3301void RenderLayerBacking::determineNonCompositedLayerDescendantsPaintedContent(RenderLayer::PaintedContentRequest& request) const
3302{
3303 bool hasPaintingDescendant = false;
3304 traverseVisibleNonCompositedDescendantLayers(m_owningLayer, [&hasPaintingDescendant, &request, this](const RenderLayer& layer) {
3305 auto localRequest = RenderLayer::PaintedContentRequest { };
3306#if HAVE(SUPPORT_HDR_DISPLAY)(defined 1 && 1)
3307 localRequest.setHDRRequestState(request.hasHDRContent);
3308#endif
3309 if (layer.isVisuallyNonEmpty(&localRequest)) {
3310 bool mayIntersect = intersectsWithAncestor(layer, m_owningLayer, compositedBounds()).value_or(true);
3311 if (mayIntersect) {
3312 hasPaintingDescendant = true;
3313 request.setHasPaintedContent();
3314 }
3315 }
3316#if HAVE(SUPPORT_HDR_DISPLAY)(defined 1 && 1)
3317 if (localRequest.probablyHasPaintedContent() && localRequest.hasHDRContent == RequestState::True)
3318 request.hasHDRContent = RequestState::True;
3319#endif
3320 return (hasPaintingDescendant && request.isSatisfied()) ? LayerTraversal::Stop : LayerTraversal::Continue;
3321 });
3322}
3323
3324bool RenderLayerBacking::hasVisibleNonCompositedDescendants() const
3325{
3326 bool hasVisibleDescendant = false;
3327 traverseVisibleNonCompositedDescendantLayers(m_owningLayer, [&hasVisibleDescendant](const RenderLayer& layer) {
3328 hasVisibleDescendant |= layer.hasVisibleContent();
3329 return hasVisibleDescendant ? LayerTraversal::Stop : LayerTraversal::Continue;
3330 });
3331
3332 return hasVisibleDescendant;
3333}
3334
3335bool RenderLayerBacking::containsPaintedContent(PaintedContentsInfo& contentsInfo) const
3336{
3337 if (contentsInfo.isSimpleContainer() || paintsIntoWindow() || paintsIntoCompositedAncestor() || m_artificiallyInflatedBounds || m_owningLayer.isReflection())
3338 return false;
3339
3340 if (contentsInfo.isDirectlyCompositedImage())
3341 return false;
3342
3343 if (auto styleable = Styleable::fromRenderer(renderer())) {
3344 if (!styleable->mayHaveNonZeroOpacity())
3345 return false;
3346 }
3347
3348 // FIXME: we could optimize cases where the image, video or canvas is known to fill the border box entirely,
3349 // and set background color on the layer in that case, instead of allocating backing store and painting.
3350#if ENABLE(VIDEO)(defined 1 && 1)
3351 if (auto* renderVideo = dynamicDowncast<RenderVideo>(renderer()); renderVideo && renderVideo->shouldDisplayVideo())
3352 return m_owningLayer.hasVisibleBoxDecorationsOrBackground() || (!(renderVideo->supportsAcceleratedRendering()) && m_requiresOwnBackingStore);
3353#endif
3354
3355#if ENABLE(WEBGL)(defined 1 && 1) || ENABLE(OFFSCREEN_CANVAS)(defined 1 && 1)
3356 if (is<RenderHTMLCanvas>(renderer()) && canvasCompositingStrategy(renderer()) == CanvasAsLayerContents)
3357 return m_owningLayer.hasVisibleBoxDecorationsOrBackground();
3358#endif
3359
3360 return true;
3361}
3362
3363// An image can be directly compositing if it's the sole content of the layer, and has no box decorations
3364// that require painting. Direct compositing saves backing store.
3365bool RenderLayerBacking::isDirectlyCompositedImage() const
3366{
3367 if (m_owningLayer.hasVisibleBoxDecorationsOrBackground() || m_owningLayer.shouldPaintWithFilters() || renderer().hasClip())
3368 return false;
3369
3370 // Fixed layers that allow detaching won't have a backing store,
3371 // so using a directly composited image doesn't help (and has non-zero cost)
3372 if (m_owningLayer.behavesAsFixed() && m_graphicsLayer->allowsBackingStoreDetaching())
3373 return false;
3374
3375#if (PLATFORM(GTK)(defined WTF_PLATFORM_GTK && WTF_PLATFORM_GTK) || PLATFORM(WPE)(defined WTF_PLATFORM_WPE && WTF_PLATFORM_WPE))
3376 // GTK and WPE ports don't support rounded rect clipping at TextureMapper level, so they cannot
3377 // directly composite images that have border-radius propery. Draw them as non directly composited
3378 // content instead. See https://bugs.webkit.org/show_bug.cgi?id=174157.
3379 if (renderer().style().border().hasBorderRadius())
3380 return false;
3381#endif
3382
3383 if (auto* viewTransitionCapture = dynamicDowncast<RenderViewTransitionCapture>(renderer())) {
3384 auto image = viewTransitionCapture->image();
3385 if (!image)
3386 return false;
3387 return m_graphicsLayer->shouldDirectlyCompositeImageBuffer(image.get());
3388 }
3389
3390 CheckedPtr imageRenderer = dynamicDowncast<RenderImage>(renderer());
3391 if (!imageRenderer)
3392 return false;
3393
3394#if ENABLE(VIDEO)(defined 1 && 1)
3395 if (is<RenderMedia>(renderer()))
3396 return false;
3397#endif
3398
3399 if (auto* cachedImage = imageRenderer->cachedImage()) {
3400 if (!cachedImage->hasImage())
3401 return false;
3402
3403 RefPtr image = dynamicDowncast<BitmapImage>(cachedImage->imageForRenderer(imageRenderer.get()));
3404 if (!image)
3405 return false;
3406
3407 if (image->currentFrameOrientation() != ImageOrientation::Orientation::None)
3408 return false;
3409
3410 return m_graphicsLayer->shouldDirectlyCompositeImage(image);
3411 }
3412
3413 return false;
3414}
3415
3416bool RenderLayerBacking::isBitmapOnly() const
3417{
3418 return m_owningLayer.isBitmapOnly();
3419}
3420
3421#if ENABLE(RE_DYNAMIC_CONTENT_SCALING)(defined ENABLE_RE_DYNAMIC_CONTENT_SCALING && ENABLE_RE_DYNAMIC_CONTENT_SCALING
)
3422bool RenderLayerBacking::layerAllowsDynamicContentScaling(const GraphicsLayer*) const
3423{
3424 return m_owningLayer.allowsDynamicContentScaling();
3425}
3426#endif
3427
3428bool RenderLayerBacking::isUnscaledBitmapOnly() const
3429{
3430 if (!is<RenderImage>(renderer()) && !is<RenderHTMLCanvas>(renderer()))
3431 return false;
3432
3433 if (m_owningLayer.hasVisibleBoxDecorationsOrBackground())
3434 return false;
3435
3436 if (pageScaleFactor() < 1.0f)
3437 return false;
3438
3439 auto contents = contentsBox();
3440 if (contents.location() != LayoutPoint(0, 0))
3441 return false;
3442
3443 if (CheckedPtr imageRenderer = dynamicDowncast<RenderImage>(renderer())) {
3444 if (auto* cachedImage = imageRenderer->cachedImage()) {
3445 if (!cachedImage->hasImage())
3446 return false;
3447
3448 RefPtr image = dynamicDowncast<BitmapImage>(cachedImage->imageForRenderer(imageRenderer.get()));
3449 if (!image)
3450 return false;
3451
3452 if (image->currentFrameOrientation() != ImageOrientation::Orientation::None)
3453 return false;
3454
3455 return contents.size() == image->size();
3456 }
3457 return false;
3458 }
3459
3460 if (renderer().style().imageRendering() == ImageRendering::CrispEdges || renderer().style().imageRendering() == ImageRendering::Pixelated)
3461 return false;
3462
3463 auto& canvasRenderer = downcast<RenderHTMLCanvas>(renderer());
3464 if (snappedIntRect(contents).size() == canvasRenderer.canvasElement().size())
3465 return true;
3466 return false;
3467}
3468
3469#if HAVE(SUPPORT_HDR_DISPLAY)(defined 1 && 1)
3470bool RenderLayerBacking::rendererHasHDRContent() const
3471{
3472 return m_owningLayer.rendererHasHDRContent();
3473}
3474#endif
3475
3476void RenderLayerBacking::contentChanged(ContentChangeType changeType, const std::optional<FloatRect>& dirtyRect)
3477{
3478 PaintedContentsInfo contentsInfo(*this);
3479#if HAVE(CORE_ANIMATION_SEPARATED_LAYERS)(defined HAVE_CORE_ANIMATION_SEPARATED_LAYERS && HAVE_CORE_ANIMATION_SEPARATED_LAYERS
)
3480 if (changeType == ContentChangeType::Image && RenderLayerCompositor::isSeparated(renderer()))
3481 updateSeparatedProperties();
3482#endif
3483 if (changeType == ContentChangeType::Image || changeType == ContentChangeType::Canvas) {
3484 if (contentsInfo.isDirectlyCompositedImage()) {
3485 updateImageContents(contentsInfo);
3486 return;
3487 }
3488 if (contentsInfo.isUnscaledBitmapOnly() != m_graphicsLayer->appliesDeviceScale()) {
3489 compositor().scheduleCompositingLayerUpdate();
3490 return;
3491 }
3492 }
3493
3494 if (changeType == ContentChangeType::Video) {
3495 compositor().scheduleCompositingLayerUpdate();
3496 return;
3497 }
3498
3499#if ENABLE(MODEL_ELEMENT)(defined 1 && 1)
3500 if (changeType == ContentChangeType::Model) {
3501#if ENABLE(GPU_PROCESS_MODEL)(defined 0 && 0)
3502 if (m_graphicsLayer && m_graphicsLayer->drawsContent())
3503 m_graphicsLayer->setNeedsDisplay();
3504#endif
3505 compositor().scheduleCompositingLayerUpdate();
3506 return;
3507 }
3508#endif
3509
3510 if ((changeType == ContentChangeType::BackgroundImage) && canDirectlyCompositeBackgroundBackgroundImage(renderer()))
3511 m_owningLayer.setNeedsCompositingConfigurationUpdate();
3512
3513 if ((changeType == ContentChangeType::MaskImage) && m_maskLayer)
3514 m_owningLayer.setNeedsCompositingConfigurationUpdate();
3515
3516#if ENABLE(WEBGL)(defined 1 && 1) || ENABLE(OFFSCREEN_CANVAS)(defined 1 && 1)
3517 if ((changeType == ContentChangeType::Canvas || changeType == ContentChangeType::CanvasPixels) && renderer().isRenderHTMLCanvas() && canvasCompositingStrategy(renderer()) == CanvasAsLayerContents) {
3518 if (changeType == ContentChangeType::Canvas)
3519 compositor().scheduleCompositingLayerUpdate();
3520
3521 if (dirtyRect)
3522 m_graphicsLayer->setContentsNeedsDisplayInRect(*dirtyRect);
3523 else
3524 m_graphicsLayer->setContentsNeedsDisplay();
3525 return;
3526 }
3527#else
3528 UNUSED_PARAM(dirtyRect)(void)dirtyRect;
3529#endif
3530}
3531
3532void RenderLayerBacking::updateImageContents(PaintedContentsInfo& contentsInfo)
3533{
3534 if (auto* viewTransitionCapture = dynamicDowncast<RenderViewTransitionCapture>(renderer())) {
3535 if (auto image = viewTransitionCapture->image())
3536 m_graphicsLayer->setContentsToImageBuffer(image.get());
3537 } else {
3538 auto& imageRenderer = downcast<RenderImage>(renderer());
3539
3540 auto* cachedImage = imageRenderer.cachedImage();
3541 if (!cachedImage)
3542 return;
3543
3544 RefPtr image = cachedImage->imageForRenderer(&imageRenderer);
3545 if (!image)
3546 return;
3547
3548 // We have to wait until the image is fully loaded before setting it on the layer.
3549 if (!cachedImage->isLoaded())
3550 return;
3551
3552
3553 m_graphicsLayer->setContentsToImage(image);
3554
3555 // Image animation is "lazy", in that it automatically stops unless someone is drawing
3556 // the image. So we have to kick the animation each time; this has the downside that the
3557 // image will keep animating, even if its layer is not visible.
3558 image->startAnimation();
3559 }
3560
3561 updateContentsRects();
3562 updateDrawsContent(contentsInfo);
3563}
3564
3565// Return the offset from the top-left of this compositing layer at which the renderer's contents are painted.
3566LayoutSize RenderLayerBacking::contentOffsetInCompositingLayer() const
3567{
3568 return LayoutSize(-m_compositedBounds.x() + m_compositedBoundsOffsetFromGraphicsLayer.width(), -m_compositedBounds.y() + m_compositedBoundsOffsetFromGraphicsLayer.height());
3569}
3570
3571LayoutRect RenderLayerBacking::contentsBox() const
3572{
3573 CheckedPtr renderBox = dynamicDowncast<RenderBox>(renderer());
3574 if (!renderBox)
3575 return LayoutRect();
3576
3577 LayoutRect contentsRect;
3578#if ENABLE(VIDEO)(defined 1 && 1)
3579 if (auto* renderVideo = dynamicDowncast<RenderVideo>(*renderBox))
3580 contentsRect = renderVideo->videoBox();
3581 else
3582#endif
3583
3584 if (CheckedPtr renderViewTransitionCapture = dynamicDowncast<RenderViewTransitionCapture>(*renderBox))
3585 contentsRect = renderViewTransitionCapture->captureLocalOverflowRect();
3586 else if (CheckedPtr renderReplaced = dynamicDowncast<RenderReplaced>(*renderBox); renderReplaced && !is<RenderWidget>(*renderReplaced))
3587 contentsRect = renderReplaced->replacedContentRect();
3588 else
3589 contentsRect = renderBox->contentBoxRect();
3590
3591 contentsRect.move(contentOffsetInCompositingLayer());
3592 return contentsRect;
3593}
3594
3595static LayoutRect backgroundRectForBox(const RenderBox& box)
3596{
3597 switch (box.style().backgroundLayers().usedFirst().clip()) {
3598 case FillBox::BorderBox:
3599 return box.borderBoxRect();
3600 case FillBox::PaddingBox:
3601 return box.paddingBoxRect();
3602 case FillBox::ContentBox:
3603 return box.contentBoxRect();
3604 default:
3605 break;
3606 }
3607
3608 ASSERT_NOT_REACHED()((void)0);
3609 return { };
3610}
3611
3612FloatRect RenderLayerBacking::backgroundBoxForSimpleContainerPainting() const
3613{
3614 CheckedPtr box = dynamicDowncast<RenderBox>(renderer());
3615 if (!box)
3616 return FloatRect();
3617
3618 LayoutRect backgroundBox = backgroundRectForBox(*box);
3619 backgroundBox.move(contentOffsetInCompositingLayer());
3620 return snapRectToDevicePixels(backgroundBox, deviceScaleFactor());
3621}
3622
3623GraphicsLayer* RenderLayerBacking::parentForSublayers() const
3624{
3625 if (m_scrolledContentsLayer)
3626 return m_scrolledContentsLayer.get();
3627
3628 return m_childContainmentLayer ? m_childContainmentLayer.get() : m_graphicsLayer.get();
3629}
3630
3631GraphicsLayer* RenderLayerBacking::childForSuperlayers() const
3632{
3633 if (m_owningLayer.isRenderViewLayer()) {
3634 // If the document element is captured, then the RenderView's layer will get attached
3635 // into the view-transition tree, and we instead want to attach the root of the VT tree to our ancestor.
3636 if (protect(m_owningLayer.renderer().document())->activeViewTransitionCapturedDocumentElement()) {
3637 if (WeakPtr viewTransitionContainingBlock = m_owningLayer.renderer().view().viewTransitionContainingBlock(); viewTransitionContainingBlock && viewTransitionContainingBlock->hasLayer() && viewTransitionContainingBlock->layer()->backing())
3638 return viewTransitionContainingBlock->layer()->backing()->childForSuperlayers();
3639 }
3640 }
3641 return childForSuperlayersExcludingViewTransitions();
3642}
3643
3644GraphicsLayer* RenderLayerBacking::childForSuperlayersExcludingViewTransitions() const
3645{
3646 if (m_transformFlatteningLayer)
3647 return m_transformFlatteningLayer.get();
3648
3649 if (m_ancestorClippingStack)
3650 return m_ancestorClippingStack->firstLayer();
3651
3652 if (RefPtr viewportConstrainedLayer = viewportClippingOrAnchorLayer())
3653 return viewportConstrainedLayer.unsafeGet();
3654
3655 if (m_contentsContainmentLayer)
3656 return m_contentsContainmentLayer.get();
3657
3658 return m_graphicsLayer.get();
3659}
3660
3661LayoutSize RenderLayerBacking::offsetRelativeToRendererOriginForDescendantLayers() const
3662{
3663 if (m_scrolledContentsLayer)
3664 return toLayoutSize(scrollContainerLayerBox(downcast<RenderBox>(renderer())).location());
3665
3666 if (hasClippingLayer())
3667 return toLayoutSize(clippingLayerBox(renderer()).location());
3668
3669 return { };
3670}
3671
3672bool RenderLayerBacking::paintsIntoWindow() const
3673{
3674#if USE(COORDINATED_GRAPHICS)(defined USE_COORDINATED_GRAPHICS && USE_COORDINATED_GRAPHICS
)
3675 return false;
3676#endif
3677
3678 if (m_isFrameLayerWithTiledBacking)
3679 return false;
3680
3681 if (m_owningLayer.isRenderViewLayer()) {
3682#if PLATFORM(IOS_FAMILY)(defined WTF_PLATFORM_IOS_FAMILY && WTF_PLATFORM_IOS_FAMILY
)
|| USE(COORDINATED_GRAPHICS)(defined USE_COORDINATED_GRAPHICS && USE_COORDINATED_GRAPHICS
)
3683 if (compositor().inForcedCompositingMode())
3684 return false;
3685#endif
3686
3687 // Site-isolated root frames don't have a window to paint into.
3688 if (m_isRootFrameRenderViewLayer && !m_isMainFrameRenderViewLayer)
3689 return false;
3690
3691 return compositor().rootLayerAttachment() != RenderLayerCompositor::RootLayerAttachedViaEnclosingFrame;
3692 }
3693
3694 return false;
3695}
3696
3697void RenderLayerBacking::setRequiresOwnBackingStore(bool requiresOwnBacking)
3698{
3699 if (requiresOwnBacking == m_requiresOwnBackingStore)
3700 return;
3701
3702 m_requiresOwnBackingStore = requiresOwnBacking;
3703
3704 // This affects the answer to paintsIntoCompositedAncestor(), which in turn affects
3705 // cached clip rects, so we have to notify the layer.
3706 m_owningLayer.compositingStatusChanged(LayoutUpToDate::Yes);
3707
3708 compositor().repaintInCompositedAncestor(m_owningLayer, compositedBounds());
3709
3710#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)(defined ENABLE_INTERACTION_REGIONS_IN_EVENT_REGION &&
ENABLE_INTERACTION_REGIONS_IN_EVENT_REGION)
3711 if (!requiresOwnBacking)
3712 clearInteractionRegions();
3713#endif
3714}
3715
3716void RenderLayerBacking::setContentsNeedDisplay(GraphicsLayer::ShouldClipToLayer shouldClip)
3717{
3718 ASSERT(!paintsIntoCompositedAncestor())((void)0);
3719
3720 // Use the repaint as a trigger to re-evaluate direct compositing (which is never used on the root layer).
3721 if (!m_owningLayer.isRenderViewLayer())
3722 m_owningLayer.setNeedsCompositingConfigurationUpdate();
3723
3724 m_owningLayer.invalidateEventRegion(RenderLayer::EventRegionInvalidationReason::Paint);
3725
3726 auto& frameView = renderer().view().frameView();
3727 if (m_isMainFrameRenderViewLayer && frameView.isTrackingRepaints())
3728 frameView.addTrackedRepaintRect(owningLayer().absoluteBoundingBoxForPainting());
3729
3730 if (m_graphicsLayer && m_graphicsLayer->drawsContent()) {
3731 // By default, setNeedsDisplay will clip to the size of the GraphicsLayer, which does not include margin tiles.
3732 // So if the TiledBacking has a margin that needs to be invalidated, we need to send in a rect to setNeedsDisplayInRect
3733 // that is large enough to include the margin. TiledBacking::bounds() includes the margin.
3734 auto* tiledBacking = this->tiledBacking();
3735 FloatRect rectToRepaint = tiledBacking ? tiledBacking->bounds() : FloatRect(FloatPoint(0, 0), m_graphicsLayer->size());
3736 m_graphicsLayer->setNeedsDisplayInRect(rectToRepaint, shouldClip);
3737 }
3738
3739 if (m_foregroundLayer && m_foregroundLayer->drawsContent())
3740 m_foregroundLayer->setNeedsDisplay();
3741
3742 if (m_backgroundLayer && m_backgroundLayer->drawsContent())
3743 m_backgroundLayer->setNeedsDisplay();
3744
3745 if (m_maskLayer && m_maskLayer->drawsContent())
3746 m_maskLayer->setNeedsDisplay();
3747
3748 if (m_scrolledContentsLayer && m_scrolledContentsLayer->drawsContent())
3749 m_scrolledContentsLayer->setNeedsDisplay();
3750
3751 setNeedsFixedContainerEdgesUpdateIfNeeded();
3752}
3753
3754// r is in the coordinate space of the layer's render object
3755void RenderLayerBacking::setContentsNeedDisplayInRect(const LayoutRect& r, GraphicsLayer::ShouldClipToLayer shouldClip)
3756{
3757 ASSERT(!paintsIntoCompositedAncestor())((void)0);
3758
3759 // Use the repaint as a trigger to re-evaluate direct compositing (which is never used on the root layer).
3760 if (!m_owningLayer.isRenderViewLayer())
3761 m_owningLayer.setNeedsCompositingConfigurationUpdate();
3762
3763 m_owningLayer.invalidateEventRegion(RenderLayer::EventRegionInvalidationReason::Paint);
3764
3765 FloatRect pixelSnappedRectForPainting = snapRectToDevicePixelsIfNeeded(r, renderer());
3766 auto& frameView = renderer().view().frameView();
3767 if (m_isMainFrameRenderViewLayer && frameView.isTrackingRepaints())
3768 frameView.addTrackedRepaintRect(pixelSnappedRectForPainting);
3769
3770 if (m_graphicsLayer && m_graphicsLayer->drawsContent()) {
3771 FloatRect layerDirtyRect = pixelSnappedRectForPainting;
3772 layerDirtyRect.move(-m_graphicsLayer->offsetFromRenderer() - m_subpixelOffsetFromRenderer);
3773 m_graphicsLayer->setNeedsDisplayInRect(layerDirtyRect, shouldClip);
3774 }
3775
3776 if (m_foregroundLayer && m_foregroundLayer->drawsContent()) {
3777 FloatRect layerDirtyRect = pixelSnappedRectForPainting;
3778 layerDirtyRect.move(-m_foregroundLayer->offsetFromRenderer() - m_subpixelOffsetFromRenderer);
3779 m_foregroundLayer->setNeedsDisplayInRect(layerDirtyRect, shouldClip);
3780 }
3781
3782 // FIXME: need to split out repaints for the background.
3783 if (m_backgroundLayer && m_backgroundLayer->drawsContent()) {
3784 FloatRect layerDirtyRect = pixelSnappedRectForPainting;
3785 layerDirtyRect.move(-m_backgroundLayer->offsetFromRenderer() - m_subpixelOffsetFromRenderer);
3786 m_backgroundLayer->setNeedsDisplayInRect(layerDirtyRect, shouldClip);
3787 }
3788
3789 if (m_maskLayer && m_maskLayer->drawsContent()) {
3790 FloatRect layerDirtyRect = pixelSnappedRectForPainting;
3791 layerDirtyRect.move(-m_maskLayer->offsetFromRenderer() - m_subpixelOffsetFromRenderer);
3792 m_maskLayer->setNeedsDisplayInRect(layerDirtyRect, shouldClip);
3793 }
3794
3795 if (m_scrolledContentsLayer && m_scrolledContentsLayer->drawsContent()) {
3796 FloatRect layerDirtyRect = pixelSnappedRectForPainting;
3797 ScrollOffset scrollOffset;
3798 if (auto* scrollableArea = m_owningLayer.scrollableArea())
3799 scrollOffset = scrollableArea->scrollOffset();
3800 layerDirtyRect.move(-m_scrolledContentsLayer->offsetFromRenderer() + toLayoutSize(scrollOffset) - m_subpixelOffsetFromRenderer);
3801 m_scrolledContentsLayer->setNeedsDisplayInRect(layerDirtyRect, shouldClip);
3802 }
3803
3804 setNeedsFixedContainerEdgesUpdateIfNeeded();
3805}
3806
3807void RenderLayerBacking::paintIntoLayer(const GraphicsLayer* graphicsLayer, GraphicsContext& context,
3808 const IntRect& paintDirtyRect, // In the coords of rootLayer.
3809 OptionSet<PaintBehavior> paintBehavior, RegionContext* regionContext)
3810{
3811 if ((paintsIntoWindow() || paintsIntoCompositedAncestor()) && graphicsLayer->paintingPhase() != OptionSet<GraphicsLayerPaintingPhase>(GraphicsLayerPaintingPhase::ChildClippingMask)) {
3812#if !PLATFORM(IOS_FAMILY)(defined WTF_PLATFORM_IOS_FAMILY && WTF_PLATFORM_IOS_FAMILY
)
&& !OS(WINDOWS)(defined WTF_OS_WINDOWS && WTF_OS_WINDOWS)
3813 // FIXME: Looks like the CALayer tree is out of sync with the GraphicsLayer heirarchy
3814 // when pages are restored from the BackForwardCache.
3815 // <rdar://problem/8712587> ASSERT: When Going Back to Page with Plugins in BackForwardCache
3816 ASSERT_NOT_REACHED()((void)0);
3817#endif
3818 return;
3819 }
3820 auto paintFlags = paintFlagsForLayer(*graphicsLayer);
3821
3822 if (is<EventRegionContext>(regionContext))
3823 paintFlags.add(RenderLayer::PaintLayerFlag::CollectingEventRegion);
3824
3825 RenderObject::SetLayoutNeededForbiddenScope forbidSetNeedsLayout(renderer());
3826
3827 auto paintOneLayer = [&](RenderLayer& layer, OptionSet<RenderLayer::PaintLayerFlag> paintFlags) {
3828 LocalFrameView::PaintingState paintingState;
3829 if (!regionContext) {
3830 InspectorInstrumentation::willPaint(layer.renderer());
3831
3832 if (layer.isRenderViewLayer())
3833 renderer().view().frameView().willPaintContents(context, paintDirtyRect, paintingState, regionContext);
3834 }
3835
3836 RenderLayer::LayerPaintingInfo paintingInfo(&m_owningLayer, paintDirtyRect, paintBehavior, -m_subpixelOffsetFromRenderer);
3837 paintingInfo.regionContext = regionContext;
3838
3839 if (&layer == &m_owningLayer) {
3840 {
3841 bool shouldResetCompositeMode = false;
3842 if (m_shouldPaintUsingCompositeCopy && context.compositeMode() == CompositeMode { CompositeOperator::SourceOver, BlendMode::Normal }) {
3843 context.setCompositeMode({ CompositeOperator::Copy, BlendMode::Normal });
3844 shouldResetCompositeMode = true;
3845 }
3846 layer.paintLayerContents(context, paintingInfo, paintFlags);
3847 if (shouldResetCompositeMode)
3848 context.setCompositeMode({ CompositeOperator::SourceOver, BlendMode::Normal });
3849 }
3850 auto* scrollableArea = layer.scrollableArea();
3851 if (scrollableArea && scrollableArea->containsDirtyOverlayScrollbars() && !regionContext)
3852 layer.paintLayerContents(context, paintingInfo, paintFlags | RenderLayer::PaintLayerFlag::PaintingOverlayScrollbars);
3853 } else
3854 layer.paintLayerWithEffects(context, paintingInfo, paintFlags);
3855
3856 if (!regionContext) {
3857 if (layer.isRenderViewLayer())
3858 renderer().view().frameView().didPaintContents(context, paintDirtyRect, paintingState);
3859
3860 InspectorInstrumentation::didPaint(layer.renderer(), paintDirtyRect);
3861 }
3862
3863 ASSERT(!m_owningLayer.m_usedTransparency)((void)0);
3864 };
3865
3866 paintOneLayer(m_owningLayer, paintFlags);
3867
3868 // FIXME: Need to check m_foregroundLayer, masking etc. webkit.org/b/197565.
3869 RefPtr<GraphicsLayer> destinationForSharingLayers = m_scrolledContentsLayer ? m_scrolledContentsLayer.get() : m_graphicsLayer.get();
3870
3871 if (graphicsLayer == destinationForSharingLayers) {
3872 OptionSet<RenderLayer::PaintLayerFlag> sharingLayerPaintFlags = {
3873 RenderLayer::PaintLayerFlag::PaintingCompositingBackgroundPhase,
3874 RenderLayer::PaintLayerFlag::PaintingCompositingForegroundPhase
3875 };
3876
3877 if (graphicsLayer->paintingPhase().contains(GraphicsLayerPaintingPhase::OverflowContents))
3878 sharingLayerPaintFlags.add(RenderLayer::PaintLayerFlag::PaintingOverflowContents);
3879
3880 if (is<EventRegionContext>(regionContext))
3881 sharingLayerPaintFlags.add(RenderLayer::PaintLayerFlag::CollectingEventRegion);
3882
3883 for (CheckedRef layer : m_backingSharingLayers | dereferenceView)
3884 paintOneLayer(layer, sharingLayerPaintFlags);
3885 }
3886
3887 if (!regionContext)
3888 compositor().didPaintBacking(this);
3889}
3890
3891OptionSet<RenderLayer::PaintLayerFlag> RenderLayerBacking::paintFlagsForLayer(const GraphicsLayer& graphicsLayer) const
3892{
3893 OptionSet<RenderLayer::PaintLayerFlag> paintFlags;
3894
3895 auto paintingPhase = graphicsLayer.paintingPhase();
3896 if (paintingPhase.contains(GraphicsLayerPaintingPhase::Background))
3897 paintFlags.add(RenderLayer::PaintLayerFlag::PaintingCompositingBackgroundPhase);
3898 if (paintingPhase.contains(GraphicsLayerPaintingPhase::Foreground))
3899 paintFlags.add(RenderLayer::PaintLayerFlag::PaintingCompositingForegroundPhase);
3900 if (paintingPhase.contains(GraphicsLayerPaintingPhase::Mask))
3901 paintFlags.add(RenderLayer::PaintLayerFlag::PaintingCompositingMaskPhase);
3902 if (paintingPhase.contains(GraphicsLayerPaintingPhase::ClipPath))
3903 paintFlags.add(RenderLayer::PaintLayerFlag::PaintingCompositingClipPathPhase);
3904 if (paintingPhase.contains(GraphicsLayerPaintingPhase::ChildClippingMask))
3905 paintFlags.add(RenderLayer::PaintLayerFlag::PaintingChildClippingMaskPhase);
3906 if (paintingPhase.contains(GraphicsLayerPaintingPhase::OverflowContents))
3907 paintFlags.add({ RenderLayer::PaintLayerFlag::PaintingOverflowContents, RenderLayer::PaintLayerFlag::PaintingOverflowContentsRoot });
3908
3909 if (paintingPhase.contains(GraphicsLayerPaintingPhase::CompositedScroll)) {
3910 if (&graphicsLayer == m_graphicsLayer.get())
3911 paintFlags.add(RenderLayer::PaintLayerFlag::PaintingOverflowContainer);
3912 }
3913
3914 if (&graphicsLayer == m_backgroundLayer.get() && m_backgroundLayerPaintsFixedRootBackground)
3915 paintFlags.add({ RenderLayer::PaintLayerFlag::PaintingRootBackgroundOnly, RenderLayer::PaintLayerFlag::PaintingCompositingForegroundPhase }); // Need PaintLayerFlag::PaintingCompositingForegroundPhase to walk child layers.
3916 else if (compositor().fixedRootBackgroundLayer())
3917 paintFlags.add(RenderLayer::PaintLayerFlag::PaintingSkipRootBackground);
3918
3919 return paintFlags;
3920}
3921
3922#if ENABLE(TOUCH_ACTION_REGIONS)(defined 0 && 0) || ENABLE(WHEEL_EVENT_REGIONS)(defined 1 && 1) || ENABLE(TOUCH_EVENT_REGIONS)(defined 0 && 0)
3923struct PatternDescription {
3924 ASCIILiteral name;
3925 FloatSize phase;
3926 SRGBA<uint8_t> fillColor;
3927};
3928
3929static RefPtr<Pattern> patternForDescription(PatternDescription description, FloatSize contentOffset, GraphicsContext& destContext)
3930{
3931 const FloatSize tileSize { 32, 18 };
3932
3933 auto imageBuffer = destContext.createAlignedImageBuffer(tileSize);
3934 if (!imageBuffer)
3935 return nullptr;
3936
3937 {
3938 GraphicsContext& imageContext = imageBuffer->context();
3939
3940 FontCascadeDescription fontDescription;
3941 fontDescription.setOneFamily("Helvetica"_s);
3942 fontDescription.setSpecifiedSize(10);
3943 fontDescription.setComputedSize(10);
3944 fontDescription.setWeight(FontSelectionValue(500));
3945 FontCascade font(WTF::move(fontDescription));
3946 font.update(nullptr);
3947
3948 TextRun textRun = TextRun(StringView { description.name });
3949 imageContext.setFillColor(description.fillColor);
3950
3951 constexpr float textGap = 4;
3952 constexpr float yOffset = 12;
3953 imageContext.drawText(font, textRun, { textGap, yOffset }, 0);
3954 }
3955
3956 AffineTransform patternOffsetTransform;
3957 patternOffsetTransform.translate(contentOffset + description.phase);
3958 patternOffsetTransform.scale(1 / destContext.scaleFactor());
3959
3960 return Pattern::create({ imageBuffer.releaseNonNull() }, { true, true, patternOffsetTransform });
3961};
3962#endif
3963
3964#if ENABLE(TOUCH_ACTION_REGIONS)(defined 0 && 0)
3965static RefPtr<Pattern> patternForTouchAction(TouchAction touchAction, FloatSize contentOffset, GraphicsContext& destContext)
3966{
3967 auto toIndex = [](TouchAction touchAction) -> unsigned {
3968 switch (touchAction) {
3969 case TouchAction::None:
3970 return 1;
3971 case TouchAction::Manipulation:
3972 return 2;
3973 case TouchAction::PanX:
3974 return 3;
3975 case TouchAction::PanY:
3976 return 4;
3977 case TouchAction::PinchZoom:
3978 return 5;
3979 case TouchAction::Auto:
3980 break;
3981 }
3982 return 0;
3983 };
3984
3985 constexpr auto fillColor = Color::black.colorWithAlphaByte(128);
3986
3987 static const std::array patternDescriptions {
3988 PatternDescription { "auto"_s, { }, fillColor },
3989 PatternDescription { "none"_s, { }, fillColor },
3990 PatternDescription { "manip"_s, { }, fillColor },
3991 PatternDescription { "pan-x"_s, { }, fillColor },
3992 PatternDescription { "pan-y"_s, { 0, 9 }, fillColor },
3993 PatternDescription { "p-z"_s, { 16, 4.5 }, fillColor },
3994 };
3995
3996 auto actionIndex = toIndex(touchAction);
3997 if (!actionIndex || actionIndex >= patternDescriptions.size())
3998 return nullptr;
3999
4000 return patternForDescription(patternDescriptions[actionIndex], contentOffset, destContext);
4001}
4002#endif
4003
4004#if ENABLE(WHEEL_EVENT_REGIONS)(defined 1 && 1) || ENABLE(TOUCH_EVENT_REGIONS)(defined 0 && 0)
4005static RefPtr<Pattern> patternForEventListenerRegionType(EventListenerRegionType type, FloatSize contentOffset, GraphicsContext& destContext)
4006{
4007 auto patternAndPhase = [&]() -> PatternDescription {
4008 switch (type) {
4009 case EventListenerRegionType::Wheel:
4010 return { "wheel"_s, { }, Color::darkGreen.colorWithAlphaByte(128) };
4011 case EventListenerRegionType::NonPassiveWheel:
4012 return { "sync"_s, { 0, 9 }, SRGBA<uint8_t> { 200, 0, 0, 128 } };
4013 case EventListenerRegionType::MouseClick:
4014 break;
4015 case EventListenerRegionType::TouchStart:
4016 case EventListenerRegionType::TouchMove:
4017 case EventListenerRegionType::TouchEnd:
4018 case EventListenerRegionType::TouchForceChange:
4019 case EventListenerRegionType::TouchCancel:
4020 return { "touch"_s, { }, Color::gray.colorWithAlphaByte(128) };
4021 case EventListenerRegionType::NonPassiveTouchStart:
4022 case EventListenerRegionType::NonPassiveTouchEnd:
4023 case EventListenerRegionType::NonPassiveTouchMove:
4024 case EventListenerRegionType::NonPassiveTouchForceChange:
4025 return { "sync touch"_s, { 0, 9 }, SRGBA<uint8_t> { 200, 200, 0, 128 } };
4026 case EventListenerRegionType::PointerDown:
4027 case EventListenerRegionType::PointerEnter:
4028 case EventListenerRegionType::PointerLeave:
4029 case EventListenerRegionType::PointerMove:
4030 case EventListenerRegionType::PointerOut:
4031 case EventListenerRegionType::PointerOver:
4032 case EventListenerRegionType::PointerUp:
4033 return { "pointer"_s, { }, Color::gray.colorWithAlphaByte(128) };
4034 case EventListenerRegionType::NonPassivePointerDown:
4035 case EventListenerRegionType::NonPassivePointerEnter:
4036 case EventListenerRegionType::NonPassivePointerLeave:
4037 case EventListenerRegionType::NonPassivePointerMove:
4038 case EventListenerRegionType::NonPassivePointerOut:
4039 case EventListenerRegionType::NonPassivePointerOver:
4040 case EventListenerRegionType::NonPassivePointerUp:
4041 return { "sync pointer"_s, { 0, 9 }, SRGBA<uint8_t> { 200, 200, 0, 128 } };
4042 case EventListenerRegionType::GestureChange:
4043 case EventListenerRegionType::GestureEnd:
4044 case EventListenerRegionType::GestureStart:
4045 return { "gesture"_s, { }, Color::lightGray.colorWithAlphaByte(128) };
4046 case EventListenerRegionType::NonPassiveGestureChange:
4047 case EventListenerRegionType::NonPassiveGestureEnd:
4048 case EventListenerRegionType::NonPassiveGestureStart:
4049 return { "sync gesture"_s, { 0, 9 }, SRGBA<uint8_t> { 200, 200, 0, 128 } };
4050 default:
4051 return { ""_s, { }, Color::black };
4052 }
4053 ASSERT_NOT_REACHED()((void)0);
4054 return { ""_s, { }, Color::black };
4055 }();
4056
4057 return patternForDescription(patternAndPhase, contentOffset, destContext);
4058}
4059#endif
4060
4061void RenderLayerBacking::paintDebugOverlays(const GraphicsLayer* graphicsLayer, GraphicsContext& context)
4062{
4063 auto& eventRegion = graphicsLayer->eventRegion();
4064 if (eventRegion.isEmpty())
4065 return;
4066
4067 GraphicsContextStateSaver stateSaver(context);
4068
4069 // The region is offset by offsetFromRenderer() so undo that.
4070 auto contentOffset = roundedIntSize(graphicsLayer->offsetFromRenderer());
4071 context.translate(contentOffset);
4072
4073 auto visibleDebugOverlayRegions = OptionSet<DebugOverlayRegions>::fromRaw(renderer().settings().visibleDebugOverlayRegions());
4074 if (visibleDebugOverlayRegions.containsAny({ DebugOverlayRegions::TouchActionRegion, DebugOverlayRegions::WheelEventHandlerRegion })) {
4075 constexpr auto regionColor = Color::blue.colorWithAlphaByte(50);
4076 context.setFillColor(regionColor);
4077 for (auto rect : eventRegion.region().rects())
4078 context.fillRect(rect);
4079 }
4080
4081 if (visibleDebugOverlayRegions.contains(DebugOverlayRegions::TouchEventRegion)) {
4082 static constexpr auto regionColor = Color::red.colorWithAlphaByte(50);
4083 context.setFillColor(regionColor);
4084 for (auto rect : eventRegion.region().rects())
4085 context.fillRect(rect);
4086 }
4087
4088#if ENABLE(TOUCH_ACTION_REGIONS)(defined 0 && 0)
4089 if (visibleDebugOverlayRegions.contains(DebugOverlayRegions::TouchActionRegion)) {
4090 constexpr std::array touchActionList {
4091 TouchAction::None,
4092 TouchAction::Manipulation,
4093 TouchAction::PanX,
4094 TouchAction::PanY,
4095 TouchAction::PinchZoom,
4096 };
4097
4098 for (auto action : touchActionList) {
4099 auto* actionRegion = graphicsLayer->eventRegion().regionForTouchAction(action);
4100 if (!actionRegion)
4101 continue;
4102
4103 auto fillPattern = patternForTouchAction(action, contentOffsetInCompositingLayer(), context);
4104 if (!fillPattern)
4105 continue;
4106
4107 context.setFillPattern(fillPattern.releaseNonNull());
4108 for (auto rect : actionRegion->rects())
4109 context.fillRect(rect);
4110 }
4111 }
4112#endif
4113
4114#if ENABLE(WHEEL_EVENT_REGIONS)(defined 1 && 1)
4115 if (visibleDebugOverlayRegions.contains(DebugOverlayRegions::WheelEventHandlerRegion)) {
4116 for (auto type : { EventListenerRegionType::Wheel, EventListenerRegionType::NonPassiveWheel }) {
4117 auto fillPattern = patternForEventListenerRegionType(type, graphicsLayer->offsetFromRenderer(), context);
4118 context.setFillPattern(fillPattern.releaseNonNull());
4119
4120 auto& region = graphicsLayer->eventRegion().eventListenerRegionForType(type);
4121 for (auto rect : region.rects())
4122 context.fillRect(rect);
4123 }
4124 }
4125#endif
4126
4127#if ENABLE(TOUCH_EVENT_REGIONS)(defined 0 && 0)
4128 if (visibleDebugOverlayRegions.contains(DebugOverlayRegions::TouchEventRegion)) {
4129 const auto& touchEventRegion = graphicsLayer->eventRegion().touchEventListenerRegion();
4130
4131 if (!touchEventRegion.asynchronousDispatchRegion.isEmpty()) {
4132 if (RefPtr fillPattern = patternForEventListenerRegionType(EventListenerRegionType::TouchStart, graphicsLayer->offsetFromRenderer(), context)) {
4133 context.setFillPattern(fillPattern.releaseNonNull());
4134 for (auto rect : touchEventRegion.asynchronousDispatchRegion.rects())
4135 context.fillRect(rect);
4136 }
4137 }
4138
4139 for (const auto& [eventType, region] : touchEventRegion.eventSpecificSynchronousDispatchRegions) {
4140 if (region.isEmpty())
4141 continue;
4142
4143 EventListenerRegionType regionType;
4144 switch (eventType) {
4145 case EventTrackingRegionsEventType::Touchstart:
4146 regionType = EventListenerRegionType::NonPassiveTouchStart;
4147 break;
4148 case EventTrackingRegionsEventType::Touchend:
4149 regionType = EventListenerRegionType::NonPassiveTouchEnd;
4150 break;
4151 case EventTrackingRegionsEventType::Touchmove:
4152 regionType = EventListenerRegionType::NonPassiveTouchMove;
4153 break;
4154 case EventTrackingRegionsEventType::Touchforcechange:
4155 regionType = EventListenerRegionType::NonPassiveTouchForceChange;
4156 break;
4157 default:
4158 continue;
4159 }
4160
4161 if (RefPtr fillPattern = patternForEventListenerRegionType(regionType, graphicsLayer->offsetFromRenderer(), context)) {
4162 context.setFillPattern(fillPattern.releaseNonNull());
4163 for (auto rect : region.rects())
4164 context.fillRect(rect);
4165 }
4166 }
4167 }
4168#endif
4169
4170#if ENABLE(EDITABLE_REGION)(defined ENABLE_EDITABLE_REGION && ENABLE_EDITABLE_REGION
)
4171 if (visibleDebugOverlayRegions.contains(DebugOverlayRegions::EditableElementRegion)) {
4172 context.setFillColor(SRGBA<uint8_t> { 128, 0, 128, 50 });
4173 for (auto rect : eventRegion.rectsForEditableElements())
4174 context.fillRect(rect);
4175 }
4176#endif
4177
4178#if ENABLE(INTERACTION_REGIONS_IN_EVENT_REGION)(defined ENABLE_INTERACTION_REGIONS_IN_EVENT_REGION &&
ENABLE_INTERACTION_REGIONS_IN_EVENT_REGION)
4179 if (DebugPageOverlays::shouldPaintOverlayIntoLayerForRegionType(renderer().page(), DebugPageOverlays::RegionType::InteractionRegion)) {
4180 context.setStrokeThickness(1);
4181
4182 for (const auto& region : eventRegion.interactionRegions()) {
4183 if (region.type == InteractionRegion::Type::Occlusion)
4184 context.setStrokeColor(Color::red);
4185 else
4186 context.setStrokeColor(Color::green);
4187
4188 auto rect = region.rectInLayerCoordinates;
4189 Path path;
4190 path.addRoundedRect(rect, { region.cornerRadius, region.cornerRadius });
4191 context.strokePath(path);
4192 }
4193 }
4194#endif
4195}
4196
4197// Up-call from compositing layer drawing callback.
4198void RenderLayerBacking::paintContents(const GraphicsLayer& graphicsLayer, GraphicsContext& context, const FloatRect& clip, OptionSet<GraphicsLayerPaintBehavior> layerPaintBehavior)
4199{
4200#ifndef NDEBUG1
4201 renderer().page().setIsPainting(true);
4202#endif
4203
4204#if PLATFORM(MAC)(defined 1 && 1)
4205 LocalDefaultSystemAppearance localAppearance(renderer().useDarkAppearance());
4206#endif
4207
4208#if HAVE(SUPPORT_HDR_DISPLAY)(defined 1 && 1)
4209 if (layerPaintBehavior.contains(GraphicsLayerPaintBehavior::TonemapHDRToDisplayHeadroom))
4210 context.setMaxEDRHeadroom(m_owningLayer.page().displayEDRHeadroom());
4211 else
4212 context.setMaxEDRHeadroom(std::nullopt);
4213#endif
4214
4215 // The dirtyRect is in the coords of the painting root.
4216 FloatRect adjustedClipRect = clip;
4217 adjustedClipRect.move(m_subpixelOffsetFromRenderer);
4218 IntRect dirtyRect = enclosingIntRect(adjustedClipRect);
4219
4220 if (!layerPaintBehavior.contains(GraphicsLayerPaintBehavior::ForceSynchronousImageDecode)) {
4221 if (!graphicsLayer.repaintCount())
4222 layerPaintBehavior.add(GraphicsLayerPaintBehavior::DefaultAsynchronousImageDecode);
4223 }
4224
4225 if (&graphicsLayer == m_graphicsLayer.get()
4226 || &graphicsLayer == m_foregroundLayer.get()
4227 || &graphicsLayer == m_backgroundLayer.get()
4228 || &graphicsLayer == m_maskLayer.get()
4229 || &graphicsLayer == m_scrolledContentsLayer.get()) {
4230
4231 if (!graphicsLayer.paintingPhase().contains(GraphicsLayerPaintingPhase::OverflowContents))
4232 dirtyRect.intersect(enclosingIntRect(compositedBoundsIncludingMargin()));
4233
4234 // We have to use the same root as for hit testing, because both methods can compute and cache clipRects.
4235 OptionSet<PaintBehavior> behavior = PaintBehavior::Normal;
4236 if (layerPaintBehavior.contains(GraphicsLayerPaintBehavior::ForceSynchronousImageDecode))
4237 behavior.add(PaintBehavior::ForceSynchronousImageDecode);
4238 else if (layerPaintBehavior.contains(GraphicsLayerPaintBehavior::DefaultAsynchronousImageDecode))
4239 behavior.add(PaintBehavior::DefaultAsynchronousImageDecode);
4240
4241#if HAVE(SUPPORT_HDR_DISPLAY)(defined 1 && 1)
4242 if (graphicsLayer.drawsHDRContent())
4243 behavior.add(PaintBehavior::DrawsHDRContent);
4244#endif
4245
4246 paintIntoLayer(&graphicsLayer, context, dirtyRect, behavior);
4247
4248 auto visibleDebugOverlayRegions = OptionSet<DebugOverlayRegions>::fromRaw(renderer().settings().visibleDebugOverlayRegions());
4249
4250 if (visibleDebugOverlayRegions.containsAny({ DebugOverlayRegions::TouchActionRegion, DebugOverlayRegions::TouchEventRegion, DebugOverlayRegions::EditableElementRegion, DebugOverlayRegions::WheelEventHandlerRegion, DebugOverlayRegions::InteractionRegion }))
4251 paintDebugOverlays(&graphicsLayer, context);
4252
4253 } else if (&graphicsLayer == layerForHorizontalScrollbar()) {
4254 if (m_owningLayer.hasVisibleContent()) {
4255 auto* scrollableArea = m_owningLayer.scrollableArea();
4256 ASSERT(scrollableArea)((void)0);
4257
4258 paintScrollbar(scrollableArea->horizontalScrollbar(), context, dirtyRect);
4259 }
4260 } else if (&graphicsLayer == layerForVerticalScrollbar()) {
4261 if (m_owningLayer.hasVisibleContent()) {
4262 auto* scrollableArea = m_owningLayer.scrollableArea();
4263 ASSERT(scrollableArea)((void)0);
4264
4265 paintScrollbar(scrollableArea->verticalScrollbar(), context, dirtyRect);
4266 }
4267 } else if (&graphicsLayer == layerForScrollCorner()) {
4268 auto* scrollableArea = m_owningLayer.scrollableArea();
4269 ASSERT(scrollableArea)((void)0);
4270
4271 auto controlsRects = scrollableArea->overflowControlsRects();
4272 auto cornerRect = controlsRects.scrollCornerOrResizerRect();
4273 GraphicsContextStateSaver stateSaver(context);
4274 context.translate(-cornerRect.location());
4275 LayoutRect transformedClip = LayoutRect(clip);
4276 transformedClip.moveBy(cornerRect.location());
4277
4278 scrollableArea->paintScrollCorner(context, IntPoint(), controlsRects.scrollCorner, snappedIntRect(transformedClip));
4279 scrollableArea->paintResizer(context, IntPoint(), controlsRects.resizer, transformedClip);
4280 }
4281#ifndef NDEBUG1
4282 renderer().page().setIsPainting(false);
4283#endif
4284#if HAVE(SUPPORT_HDR_DISPLAY)(defined 1 && 1)
4285 context.setMaxEDRHeadroom(std::nullopt);
4286#endif
4287}
4288
4289float RenderLayerBacking::pageScaleFactor() const
4290{
4291 return compositor().pageScaleFactor();
4292}
4293
4294float RenderLayerBacking::zoomedOutPageScaleFactor() const
4295{
4296 return compositor().zoomedOutPageScaleFactor();
4297}
4298
4299FloatSize RenderLayerBacking::enclosingFrameViewVisibleSize() const
4300{
4301 return compositor().enclosingFrameViewVisibleSize();
4302}
4303
4304float RenderLayerBacking::deviceScaleFactor() const
4305{
4306 return compositor().deviceScaleFactor();
4307}
4308
4309float RenderLayerBacking::contentsScaleMultiplierForNewTiles(const GraphicsLayer* layer) const
4310{
4311 return compositor().contentsScaleMultiplierForNewTiles(layer);
4312}
4313
4314bool RenderLayerBacking::paintsOpaquelyAtNonIntegralScales(const GraphicsLayer*) const
4315{
4316 return m_isMainFrameRenderViewLayer;
4317}
4318
4319void RenderLayerBacking::didChangePlatformLayerForLayer(const GraphicsLayer* layer)
4320{
4321 compositor().didChangePlatformLayerForLayer(m_owningLayer, layer);
4322}
4323
4324bool RenderLayerBacking::getCurrentTransform(const GraphicsLayer* graphicsLayer, TransformationMatrix& transform) const
4325{
4326 RefPtr transformedLayer = m_contentsContainmentLayer.get() ? m_contentsContainmentLayer.get() : m_graphicsLayer.get();
4327 if (graphicsLayer != transformedLayer)
4328 return false;
4329
4330 if (m_owningLayer.isTransformed()) {
4331 transform = m_owningLayer.currentTransform(Style::TransformResolver::individualTransformOperations);
4332 return true;
4333 }
4334 return false;
4335}
4336
4337bool RenderLayerBacking::isFlushingLayers() const
4338{
4339 return static_cast<GraphicsLayerClient&>(compositor()).isFlushingLayers();
4340}
4341
4342bool RenderLayerBacking::isTrackingRepaints() const
4343{
4344 return static_cast<GraphicsLayerClient&>(compositor()).isTrackingRepaints();
4345}
4346
4347bool RenderLayerBacking::shouldSkipLayerInDump(const GraphicsLayer* layer, OptionSet<LayerTreeAsTextOptions> options) const
4348{
4349 if (options & LayerTreeAsTextOptions::Debug)
4350 return false;
4351
4352 // Skip the root tile cache's flattening layer.
4353 return m_isMainFrameRenderViewLayer && layer && layer == m_childContainmentLayer.get();
4354}
4355
4356bool RenderLayerBacking::shouldDumpPropertyForLayer(const GraphicsLayer* layer, ASCIILiteral propertyName, OptionSet<LayerTreeAsTextOptions> options) const
4357{
4358 // For backwards compatibility with WebKit1 and other platforms,
4359 // skip some properties on the root tile cache.
4360 if (m_isMainFrameRenderViewLayer && layer == m_graphicsLayer.get() && !(options & LayerTreeAsTextOptions::IncludeRootLayerProperties)) {
4361 if (propertyName == "drawsContent"_s)
4362 return false;
4363
4364 // Background color could be of interest to tests or other dumpers if it's non-white.
4365 if (propertyName == "backgroundColor"_s && Color::isWhiteColor(layer->backgroundColor()))
4366 return false;
4367
4368 // The root tile cache's repaints will show up at the top with FrameView's,
4369 // so don't dump them twice.
4370 if (propertyName == "repaintRects"_s)
4371 return false;
4372 }
4373
4374 if (m_owningLayer.isRenderViewLayer() && (layer == m_graphicsLayer.get() || layer == m_contentsContainmentLayer.get())) {
4375 if (propertyName == "anchorPoint"_s)
4376 return layer->anchorPoint() != FloatPoint3D { };
4377
4378 return true;
4379 }
4380
4381 if (propertyName == "anchorPoint"_s)
4382 return layer->anchorPoint() != FloatPoint3D(0.5f, 0.5f, 0);
4383
4384 return true;
4385}
4386
4387bool RenderLayerBacking::shouldAggressivelyRetainTiles(const GraphicsLayer*) const
4388{
4389 // Only the main frame TileController has enough information about in-window state to
4390 // correctly implement aggressive tile retention.
4391 if (!m_isMainFrameRenderViewLayer)
4392 return false;
4393
4394 return renderer().settings().aggressiveTileRetentionEnabled();
4395}
4396
4397bool RenderLayerBacking::shouldTemporarilyRetainTileCohorts(const GraphicsLayer*) const
4398{
4399 return renderer().settings().temporaryTileCohortRetentionEnabled();
4400}
4401
4402bool RenderLayerBacking::useGiantTiles() const
4403{
4404 return renderer().settings().useGiantTiles();
4405}
4406
4407bool RenderLayerBacking::cssUnprefixedBackdropFilterEnabled() const
4408{
4409 return renderer().settings().cssUnprefixedBackdropFilterEnabled();
4410}
4411
4412void RenderLayerBacking::logFilledVisibleFreshTile(unsigned blankPixelCount)
4413{
4414 if (auto* loggingClient = renderer().page().performanceLoggingClient())
4415 loggingClient->logScrollingEvent(PerformanceLoggingClient::ScrollingEvent::FilledTile, MonotonicTime::now(), blankPixelCount);
4416}
4417
4418#ifndef NDEBUG1
4419void RenderLayerBacking::verifyNotPainting()
4420{
4421 ASSERT(!renderer().page().isPainting())((void)0);
4422}
4423#endif
4424
4425bool RenderLayerBacking::startAnimation(double timeOffset, const GraphicsLayerAnimation& animation, const BlendingKeyframes& keyframes)
4426{
4427 if (renderer().capturedInViewTransition())
4428 return false;
4429
4430 bool shouldApplyAnimationsToTargetRenderer = renderer().isRenderBox() || renderer().isSVGLayerAwareRenderer();
4431
4432 bool hasOpacity = keyframes.containsProperty(CSSPropertyOpacity);
4433 bool hasRotate = shouldApplyAnimationsToTargetRenderer && keyframes.containsProperty(CSSPropertyRotate);
4434 bool hasScale = shouldApplyAnimationsToTargetRenderer && keyframes.containsProperty(CSSPropertyScale);
4435 bool hasTranslate = shouldApplyAnimationsToTargetRenderer && keyframes.containsProperty(CSSPropertyTranslate);
4436 bool hasTransform = shouldApplyAnimationsToTargetRenderer && keyframes.containsProperty(CSSPropertyTransform);
4437 bool hasFilter = keyframes.containsProperty(CSSPropertyFilter);
4438
4439 bool hasBackdropFilter = false;
4440 hasBackdropFilter = keyframes.containsProperty(CSSPropertyWebkitBackdropFilter) || keyframes.containsProperty(CSSPropertyBackdropFilter);
4441
4442 if (!hasOpacity && !hasRotate && !hasScale && !hasTranslate && !hasTransform && !hasFilter && !hasBackdropFilter)
4443 return false;
4444
4445 auto referenceBoxRect = renderer().transformReferenceBoxRect(renderer().style());
4446 if (!renderer().isSVGLayerAwareRenderer())
4447 referenceBoxRect = snappedIntRect(LayoutRect(referenceBoxRect));
4448
4449 GraphicsLayerKeyframeValueList rotateVector(AnimatedProperty::Rotate);
4450 GraphicsLayerKeyframeValueList scaleVector(AnimatedProperty::Scale);
4451 GraphicsLayerKeyframeValueList translateVector(AnimatedProperty::Translate);
4452 GraphicsLayerKeyframeValueList transformVector(AnimatedProperty::Transform);
4453 GraphicsLayerKeyframeValueList opacityVector(AnimatedProperty::Opacity);
4454 GraphicsLayerKeyframeValueList filterVector(AnimatedProperty::Filter);
4455 GraphicsLayerKeyframeValueList backdropFilterVector(AnimatedProperty::WebkitBackdropFilter);
4456
4457 for (auto& currentKeyframe : keyframes) {
4458 const RenderStyle* keyframeStyle = currentKeyframe.style();
4459 double offset = currentKeyframe.offset();
4460
4461 if (!keyframeStyle)
4462 continue;
4463
4464 RefPtr tf = currentKeyframe.timingFunction();
4465
4466 if (currentKeyframe.animatesProperty(CSSPropertyRotate))
4467 rotateVector.insert(makeUnique<GraphicsLayerTransformAnimationValue>(offset, Style::toPlatform(keyframeStyle->rotate(), referenceBoxRect.size()).get(), tf));
4468
4469 if (currentKeyframe.animatesProperty(CSSPropertyScale))
4470 scaleVector.insert(makeUnique<GraphicsLayerTransformAnimationValue>(offset, Style::toPlatform(keyframeStyle->scale(), referenceBoxRect.size()).get(), tf));
4471
4472 if (currentKeyframe.animatesProperty(CSSPropertyTranslate))
4473 translateVector.insert(makeUnique<GraphicsLayerTransformAnimationValue>(offset, Style::toPlatform(keyframeStyle->translate(), referenceBoxRect.size()).get(), tf));
4474
4475 if (currentKeyframe.animatesProperty(CSSPropertyTransform))
4476 transformVector.insert(makeUnique<GraphicsLayerTransformAnimationValue>(offset, Style::toPlatform(keyframeStyle->transform(), referenceBoxRect.size()), tf));
4477
4478 if (currentKeyframe.animatesProperty(CSSPropertyOpacity))
4479 opacityVector.insert(makeUnique<GraphicsLayerFloatAnimationValue>(offset, keyframeStyle->opacity().value.value, tf));
4480
4481 if (currentKeyframe.animatesProperty(CSSPropertyFilter))
4482 filterVector.insert(makeUnique<GraphicsLayerFilterAnimationValue>(offset, Style::toPlatform(keyframeStyle->filter(), renderer().style()), tf));
4483
4484 if (currentKeyframe.animatesProperty(CSSPropertyWebkitBackdropFilter) || currentKeyframe.animatesProperty(CSSPropertyBackdropFilter))
4485 backdropFilterVector.insert(makeUnique<GraphicsLayerFilterAnimationValue>(offset, Style::toPlatform(keyframeStyle->backdropFilter(), renderer().style()), tf));
4486 }
4487
4488 bool didAnimate = false;
4489
4490 if (hasRotate && m_graphicsLayer->addAnimation(rotateVector, &animation, keyframes.acceleratedAnimationName(), timeOffset))
4491 didAnimate = true;
4492
4493 if (hasScale && m_graphicsLayer->addAnimation(scaleVector, &animation, keyframes.acceleratedAnimationName(), timeOffset))
4494 didAnimate = true;
4495
4496 if (hasTranslate && m_graphicsLayer->addAnimation(translateVector, &animation, keyframes.acceleratedAnimationName(), timeOffset))
4497 didAnimate = true;
4498
4499 if (hasTransform && m_graphicsLayer->addAnimation(transformVector, &animation, keyframes.acceleratedAnimationName(), timeOffset))
4500 didAnimate = true;
4501
4502 if (hasOpacity && m_graphicsLayer->addAnimation(opacityVector, &animation, keyframes.acceleratedAnimationName(), timeOffset))
4503 didAnimate = true;
4504
4505 if (hasFilter && m_graphicsLayer->addAnimation(filterVector, &animation, keyframes.acceleratedAnimationName(), timeOffset))
4506 didAnimate = true;
4507
4508 if (hasBackdropFilter && m_graphicsLayer->addAnimation(backdropFilterVector, &animation, keyframes.acceleratedAnimationName(), timeOffset))
4509 didAnimate = true;
4510
4511 if (didAnimate) {
4512 m_owningLayer.setNeedsPostLayoutCompositingUpdate();
4513 m_owningLayer.setNeedsCompositingGeometryUpdate();
4514 }
4515
4516 return didAnimate;
4517}
4518
4519#if ENABLE(THREADED_ANIMATIONS)(defined 1 && 1)
4520const AcceleratedEffectStack* RenderLayerBacking::acceleratedEffectStack() const
4521{
4522 return m_graphicsLayer->acceleratedEffectStack();
4523}
4524
4525void RenderLayerBacking::updateAcceleratedEffectsAndBaseValues(HashSet<Ref<AcceleratedTimeline>>& timelines)
4526{
4527 auto& renderer = this->renderer();
4528 OptionSet<AcceleratedEffectProperty> disallowedAcceleratedProperties;
4529
4530 auto rendererAllowsTransform = renderer.isRenderBox() || renderer.isSVGLayerAwareRenderer();
4531 if (!rendererAllowsTransform)
4532 disallowedAcceleratedProperties.add(transformRelatedAcceleratedProperties);
4533
4534 auto target = Styleable::fromRenderer(renderer);
4535 ASSERT(target)((void)0);
4536
4537 bool hasEffectAffectingFilter = false;
4538 bool hasEffectAffectingBackdropFilter = false;
4539 auto borderBoxRect = snappedIntRect(m_owningLayer.rendererBorderBoxRect());
4540
4541 auto baseValues = [&]() -> AcceleratedEffectValues {
4542 if (auto* style = target->lastStyleChangeEventStyle())
4543 return { *style, borderBoxRect, &renderer };
4544 return { };
4545 }();
4546
4547 // We keep property sets to track all properties we've encountered as well as
4548 // those we know will interpolate (ie. the animation is in the "running" state).
4549 // We will use these to determine if there are non-interpolating animations
4550 // that we can disregard.
4551 OptionSet<AcceleratedEffectProperty> allAcceleratedProperties;
4552 OptionSet<AcceleratedEffectProperty> interpolatingProperties;
4553
4554 // We keep another property set to track proeprties for which we have found an
4555 // interpolating effect that fully replaces any previous effect or base value.
4556 // The purpose of this property set is to not add any effect, running or otherwise,
4557 // that is fully replaced by effects higher up the effect stack, ensuring a minimal
4558 // amount of accelerated effects.
4559 OptionSet<AcceleratedEffectProperty> replacedAcceleratedProperties;
4560
4561 AcceleratedEffects acceleratedEffects;
4562 HashSet<Ref<AcceleratedTimeline>> effectTimelines;
4563 if (auto* effectStack = target->keyframeEffectStack()) {
4564 WeakListHashSet<AcceleratedEffect> weakAcceleratedEffects;
4565 if (effectStack->allowsAcceleration()) {
4566 auto animatesWidth = effectStack->containsProperty(CSSPropertyWidth);
4567 auto animatesHeight = effectStack->containsProperty(CSSPropertyHeight);
4568 for (const auto& effect : effectStack->sortedEffects() | std::views::reverse) {
4569 if (!effect || !effect->canHaveAcceleratedRepresentation() || !effect->canBeAccelerated())
4570 continue;
4571 if (animatesWidth || animatesHeight) {
4572 auto& blendingKeyframes = effect->blendingKeyframes();
4573 if ((animatesWidth && blendingKeyframes.hasWidthDependentTransform()) || (animatesHeight && blendingKeyframes.hasHeightDependentTransform()))
4574 disallowedAcceleratedProperties.add(transformRelatedAcceleratedProperties);
4575 }
4576 Ref acceleratedEffect = effect->acceleratedRepresentation(borderBoxRect, baseValues, disallowedAcceleratedProperties);
4577 // FIXME: it feels like we should be able to assert here, or perhaps we could just fold this into the logic
4578 // to determine whether we have an interpolating effect.
4579 auto& acceleratedProperties = acceleratedEffect->animatedProperties();
4580 if (acceleratedProperties.isEmpty())
4581 continue;
4582 // This effect is fully replaced by effects higher up the stack.
4583 if (replacedAcceleratedProperties.containsAll(acceleratedProperties))
4584 continue;
4585 // Keep track of properties replaced by this effect.
4586 replacedAcceleratedProperties.add(acceleratedEffect->replacedProperties());
4587 // Keep track of this effect's properties in the list of all known properties.
4588 allAcceleratedProperties.add(acceleratedProperties);
4589 if (effect->isRunningAccelerated())
4590 interpolatingProperties.add(acceleratedProperties);
4591 if (!hasEffectAffectingFilter && acceleratedProperties.contains(AcceleratedEffectProperty::Filter))
4592 hasEffectAffectingFilter = true;
4593 if (!hasEffectAffectingBackdropFilter && acceleratedProperties.contains(AcceleratedEffectProperty::BackdropFilter))
4594 hasEffectAffectingBackdropFilter = true;
4595 effectTimelines.add(Ref { *acceleratedEffect->timeline() });
4596 weakAcceleratedEffects.add(acceleratedEffect.ptr());
4597 acceleratedEffects.append(WTF::move(acceleratedEffect));
4598 }
4599 }
4600 effectStack->setAcceleratedEffects(WTF::move(weakAcceleratedEffects));
4601 }
4602
4603 // Effects were added in reverse, so we need to reverse the accelerated effects.
4604 acceleratedEffects.reverse();
4605
4606 // Now let's prune any effect that only animates a non-interpolating property.
4607 auto nonInterpolatingProperties = allAcceleratedProperties ^ interpolatingProperties;
4608 if (!nonInterpolatingProperties.isEmpty()) {
4609 // Make a copy of our current list of effects and clear the the original list as well
4610 // as the set of timelines. We'll re-populate both without effects that are only animating
4611 // non-interpolating properties.
4612 auto effectsIncludingNonInterpolating = acceleratedEffects;
4613 acceleratedEffects.clear();
4614 effectTimelines.clear();
4615 for (auto& acceleratedEffect : effectsIncludingNonInterpolating) {
4616 if (nonInterpolatingProperties.containsAll(acceleratedEffect->animatedProperties()))
4617 continue;
4618 acceleratedEffects.append(acceleratedEffect);
4619 effectTimelines.add(Ref { *acceleratedEffect->timeline() });
4620 }
4621 }
4622
4623 // If all of the effects in the stack are either idle, paused or filling, then the
4624 // effect stack will not produce an interpolated value and we don't need to run
4625 // any of these effects. Otherwise, add the timelines we've encountered for the
4626 // effects to the general timelines list.
4627 if (interpolatingProperties.isEmpty()) {
4628 acceleratedEffects.clear();
4629 baseValues = { };
4630 } else
4631 timelines.addAll(effectTimelines);
4632
4633 // If a filter property was disallowed, it's because it cannot be represented remotely,
4634 // so we must ensure we reset it in the base values so that we don't attempt to encode
4635 // an unsupported filter operation.
4636 if (!hasEffectAffectingFilter || disallowedAcceleratedProperties.contains(AcceleratedEffectProperty::Filter)) {
4637 for (auto& effect : acceleratedEffects)
4638 effect->clearProperty(AcceleratedEffectProperty::Filter);
4639 baseValues.filter = { };
4640 }
4641 if (!hasEffectAffectingBackdropFilter || disallowedAcceleratedProperties.contains(AcceleratedEffectProperty::BackdropFilter)) {
4642 for (auto& effect : acceleratedEffects)
4643 effect->clearProperty(AcceleratedEffectProperty::BackdropFilter);
4644 baseValues.backdropFilter = { };
4645 }
4646
4647 m_graphicsLayer->setAcceleratedEffectsAndBaseValues(WTF::move(acceleratedEffects), WTF::move(baseValues));
4648
4649 m_owningLayer.setNeedsPostLayoutCompositingUpdate();
4650 m_owningLayer.setNeedsCompositingGeometryUpdate();
4651}
4652#endif
4653
4654void RenderLayerBacking::animationPaused(double timeOffset, const String& animationName)
4655{
4656 m_graphicsLayer->pauseAnimation(animationName, timeOffset);
4657}
4658
4659void RenderLayerBacking::animationFinished(const String& animationName)
4660{
4661 m_graphicsLayer->removeAnimation(animationName, std::nullopt);
4662 m_owningLayer.setNeedsPostLayoutCompositingUpdate();
4663 m_owningLayer.setNeedsCompositingGeometryUpdate();
4664}
4665
4666void RenderLayerBacking::transformRelatedPropertyDidChange()
4667{
4668 m_graphicsLayer->transformRelatedPropertyDidChange();
4669}
4670
4671void RenderLayerBacking::notifyAnimationStarted(const GraphicsLayer*, const String&, MonotonicTime)
4672{
4673}
4674
4675void RenderLayerBacking::notifyFlushRequired(const GraphicsLayer* layer)
4676{
4677 if (renderer().renderTreeBeingDestroyed())
4678 return;
4679
4680 compositor().notifyFlushRequired(layer);
4681}
4682
4683void RenderLayerBacking::notifySubsequentFlushRequired(const GraphicsLayer* layer)
4684{
4685 compositor().notifySubsequentFlushRequired(layer);
4686}
4687
4688// This is used for the 'freeze' API, for testing only.
4689void RenderLayerBacking::suspendAnimations(MonotonicTime time)
4690{
4691 m_graphicsLayer->suspendAnimations(time);
4692}
4693
4694void RenderLayerBacking::resumeAnimations()
4695{
4696 m_graphicsLayer->resumeAnimations();
4697}
4698
4699LayoutRect RenderLayerBacking::compositedBounds() const
4700{
4701 return m_compositedBounds;
4702}
4703
4704bool RenderLayerBacking::setCompositedBounds(const LayoutRect& bounds)
4705{
4706 if (bounds == m_compositedBounds)
4707 return false;
4708
4709 m_compositedBounds = bounds;
4710 return true;
4711}
4712
4713LayoutRect RenderLayerBacking::compositedBoundsIncludingMargin() const
4714{
4715 auto* tiledBacking = this->tiledBacking();
4716 if (!tiledBacking || !tiledBacking->hasMargins())
4717 return compositedBounds();
4718
4719 LayoutRect boundsIncludingMargin = compositedBounds();
4720 LayoutUnit leftMarginWidth = tiledBacking->leftMarginWidth();
4721 LayoutUnit topMarginHeight = tiledBacking->topMarginHeight();
4722
4723 boundsIncludingMargin.moveBy(LayoutPoint(-leftMarginWidth, -topMarginHeight));
4724 boundsIncludingMargin.expand(leftMarginWidth + tiledBacking->rightMarginWidth(), topMarginHeight + tiledBacking->bottomMarginHeight());
4725
4726 return boundsIncludingMargin;
4727}
4728
4729CSSPropertyID RenderLayerBacking::graphicsLayerToCSSProperty(AnimatedProperty property)
4730{
4731 CSSPropertyID cssProperty = CSSPropertyInvalid;
4732 switch (property) {
4733 case AnimatedProperty::Translate:
4734 cssProperty = CSSPropertyTranslate;
4735 break;
4736 case AnimatedProperty::Scale:
4737 cssProperty = CSSPropertyScale;
4738 break;
4739 case AnimatedProperty::Rotate:
4740 cssProperty = CSSPropertyRotate;
4741 break;
4742 case AnimatedProperty::Transform:
4743 cssProperty = CSSPropertyTransform;
4744 break;
4745 case AnimatedProperty::Opacity:
4746 cssProperty = CSSPropertyOpacity;
4747 break;
4748 case AnimatedProperty::BackgroundColor:
4749 cssProperty = CSSPropertyBackgroundColor;
4750 break;
4751 case AnimatedProperty::Filter:
4752 cssProperty = CSSPropertyFilter;
4753 break;
4754 case AnimatedProperty::WebkitBackdropFilter:
4755 cssProperty = CSSPropertyWebkitBackdropFilter;
4756 break;
4757 case AnimatedProperty::Invalid:
4758 ASSERT_NOT_REACHED()((void)0);
4759 }
4760 return cssProperty;
4761}
4762
4763AnimatedProperty RenderLayerBacking::cssToGraphicsLayerProperty(CSSPropertyID cssProperty)
4764{
4765 switch (cssProperty) {
4766 case CSSPropertyTranslate:
4767 return AnimatedProperty::Translate;
4768 case CSSPropertyScale:
4769 return AnimatedProperty::Scale;
4770 case CSSPropertyRotate:
4771 return AnimatedProperty::Rotate;
4772 case CSSPropertyTransform:
4773 return AnimatedProperty::Transform;
4774 case CSSPropertyOpacity:
4775 return AnimatedProperty::Opacity;
4776 case CSSPropertyBackgroundColor:
4777 return AnimatedProperty::BackgroundColor;
4778 case CSSPropertyFilter:
4779 return AnimatedProperty::Filter;
4780 case CSSPropertyBackdropFilter:
4781 case CSSPropertyWebkitBackdropFilter:
4782 return AnimatedProperty::WebkitBackdropFilter;
4783 default:
4784 // It's fine if we see other css properties here; they are just not accelerated.
4785 break;
4786 }
4787 return AnimatedProperty::Invalid;
4788}
4789
4790CompositingLayerType RenderLayerBacking::compositingLayerType() const
4791{
4792 if (m_graphicsLayer->usesContentsLayer())
4793 return MediaCompositingLayer;
4794
4795 if (m_graphicsLayer->drawsContent())
4796 return m_graphicsLayer->tiledBacking() ? TiledCompositingLayer : NormalCompositingLayer;
4797
4798 return ContainerCompositingLayer;
4799}
4800
4801double RenderLayerBacking::backingStoreMemoryEstimate() const
4802{
4803 double backingMemory;
4804
4805 // Layers in m_ancestorClippingStack, m_contentsContainmentLayer and m_childContainmentLayer are just used for masking or containment, so have no backing.
4806 backingMemory = m_graphicsLayer->backingStoreMemoryEstimate();
4807 if (m_foregroundLayer)
4808 backingMemory += m_foregroundLayer->backingStoreMemoryEstimate();
4809 if (m_backgroundLayer)
4810 backingMemory += m_backgroundLayer->backingStoreMemoryEstimate();
4811 if (m_maskLayer)
4812 backingMemory += m_maskLayer->backingStoreMemoryEstimate();
4813
4814 if (m_scrolledContentsLayer)
4815 backingMemory += m_scrolledContentsLayer->backingStoreMemoryEstimate();
4816
4817 if (m_layerForHorizontalScrollbar)
4818 backingMemory += m_layerForHorizontalScrollbar->backingStoreMemoryEstimate();
4819
4820 if (m_layerForVerticalScrollbar)
4821 backingMemory += m_layerForVerticalScrollbar->backingStoreMemoryEstimate();
4822
4823 if (m_layerForScrollCorner)
4824 backingMemory += m_layerForScrollCorner->backingStoreMemoryEstimate();
4825
4826 return backingMemory;
4827}
4828
4829TextStream& operator<<(TextStream& ts, const RenderLayerBacking& backing)
4830{
4831 ts << "RenderLayerBacking "_s << &backing << " bounds "_s << backing.compositedBounds();
4832
4833 if (backing.isFrameLayerWithTiledBacking())
4834 ts << " frame layer tiled backing"_s;
4835 if (backing.paintsIntoWindow())
4836 ts << " paintsIntoWindow"_s;
4837 if (backing.paintsIntoCompositedAncestor())
4838 ts << " paintsIntoCompositedAncestor"_s;
4839
4840 ts << " primary layer ID "_s << (backing.graphicsLayer()->primaryLayerID() ? backing.graphicsLayer()->primaryLayerID()->object().toUInt64() : 0);
4841 if (auto nodeID = backing.scrollingNodeIDForRole(ScrollCoordinationRole::ViewportConstrained))
4842 ts << " viewport constrained scrolling node "_s << nodeID;
4843 if (auto nodeID = backing.scrollingNodeIDForRole(ScrollCoordinationRole::Scrolling))
4844 ts << " scrolling node "_s << nodeID;
4845
4846 if (backing.ancestorClippingStack())
4847 ts << " ancestor clip stack "_s << *backing.ancestorClippingStack();
4848
4849 if (auto nodeID = backing.scrollingNodeIDForRole(ScrollCoordinationRole::FrameHosting))
4850 ts << " frame hosting node "_s << nodeID;
4851 if (auto nodeID = backing.scrollingNodeIDForRole(ScrollCoordinationRole::PluginHosting))
4852 ts << " plugin hosting node "_s << nodeID;
4853 if (auto nodeID = backing.scrollingNodeIDForRole(ScrollCoordinationRole::Positioning))
4854 ts << " positioning node "_s << nodeID;
4855 return ts;
4856}
4857
4858TransformationMatrix RenderLayerBacking::transformMatrixForProperty(AnimatedProperty property) const
4859{
4860 TransformationMatrix matrix;
4861
4862 auto applyTransformOperation = [&](const auto& operation) {
4863 operation.apply(matrix, snappedIntRect(m_owningLayer.rendererBorderBoxRect()).size());
4864 };
4865
4866 if (property == AnimatedProperty::Translate)
4867 applyTransformOperation(renderer().style().translate());
4868 else if (property == AnimatedProperty::Scale)
4869 applyTransformOperation(renderer().style().scale());
4870 else if (property == AnimatedProperty::Rotate)
4871 applyTransformOperation(renderer().style().rotate());
4872 else if (property == AnimatedProperty::Transform)
4873 applyTransformOperation(renderer().style().transform());
4874 else
4875 ASSERT_NOT_REACHED()((void)0);
4876
4877 return matrix;
4878}
4879
4880void RenderLayerBacking::purgeFrontBufferForTesting()
4881{
4882 if (RefPtr graphicsLayer = m_graphicsLayer)
4883 graphicsLayer->purgeFrontBufferForTesting();
4884}
4885
4886void RenderLayerBacking::purgeBackBufferForTesting()
4887{
4888 if (RefPtr graphicsLayer = m_graphicsLayer)
4889 graphicsLayer->purgeBackBufferForTesting();
4890}
4891
4892void RenderLayerBacking::markFrontBufferVolatileForTesting()
4893{
4894 if (RefPtr graphicsLayer = m_graphicsLayer)
4895 graphicsLayer->markFrontBufferVolatileForTesting();
4896}
4897
4898void RenderLayerBacking::dumpProperties(const GraphicsLayer* layer, TextStream& ts, OptionSet<LayerTreeAsTextOptions> options) const
4899{
4900 if (!is<RenderWidget>(renderer()))
4901 return;
4902
4903 // If this is the leaf layer for a RemoteFrame, then collect layers from the frame's process.
4904 if (RefPtr remoteFrame = downcast<RenderWidget>(renderer()).remoteFrame(); remoteFrame && layer->children().isEmpty()) {
4905 ts << indent << "(children 1\n"_s;
4906 ts << remoteFrame->client().layerTreeAsText(ts.indent() + 1, options);
4907 ts << indent << ")\n"_s;
4908 }
4909}
4910
4911void RenderLayerBacking::setNeedsFixedContainerEdgesUpdateIfNeeded()
4912{
4913 if (!m_owningLayer.isViewportConstrained())
4914 return;
4915
4916 renderer().page().chrome().client().setNeedsFixedContainerEdgesUpdate();
4917}
4918
4919OptionSet<ContentsFormat> RenderLayerBacking::screenContentsFormats() const
4920{
4921#if PLATFORM(MAC)(defined 1 && 1) || PLATFORM(IOS_FAMILY)(defined WTF_PLATFORM_IOS_FAMILY && WTF_PLATFORM_IOS_FAMILY
)
4922 return WebCore::screenContentsFormats(&renderer().view().frameView());
4923#else
4924 return { };
4925#endif
4926}
4927
4928
4929} // namespace WebCore