Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsSubDocumentFrame.cpp
Warning:line 253, column 9
Value stored to 'subdocRootFrame' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_layout_generic4.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -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 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/layout/generic -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/layout/generic -resource-dir /usr/lib/llvm-18/lib/clang/18 -include /var/lib/jenkins/workspace/firefox-scan-build/config/gcc_hidden.h -include /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /var/lib/jenkins/workspace/firefox-scan-build/layout/generic -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/layout/generic -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /var/lib/jenkins/workspace/firefox-scan-build/ipc/chromium/src -I /var/lib/jenkins/workspace/firefox-scan-build/layout/base -I /var/lib/jenkins/workspace/firefox-scan-build/layout/forms -I /var/lib/jenkins/workspace/firefox-scan-build/layout/painting -I /var/lib/jenkins/workspace/firefox-scan-build/layout/style -I /var/lib/jenkins/workspace/firefox-scan-build/layout/tables -I /var/lib/jenkins/workspace/firefox-scan-build/layout/xul -I /var/lib/jenkins/workspace/firefox-scan-build/docshell/base -I /var/lib/jenkins/workspace/firefox-scan-build/dom/base -I /var/lib/jenkins/workspace/firefox-scan-build/dom/html -I /var/lib/jenkins/workspace/firefox-scan-build/dom/xul -I /var/lib/jenkins/workspace/firefox-scan-build/gfx/cairo/cairo/src -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/cloudproviders -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/gtk-3.0/unix-print -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-deprecated-this-capture -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -fdeprecated-macro -ferror-limit 19 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-07-21-021012-413605-1 -x c++ Unified_cpp_layout_generic4.cpp
1/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7/*
8 * rendering object for replaced elements that contain a document, such
9 * as <frame>, <iframe>, and some <object>s
10 */
11
12#include "nsSubDocumentFrame.h"
13
14#include "mozilla/ComputedStyleInlines.h"
15#include "mozilla/Preferences.h"
16#include "mozilla/PresShell.h"
17#include "mozilla/ScrollContainerFrame.h"
18#include "mozilla/StaticPrefs_layout.h"
19#include "mozilla/Unused.h"
20#include "mozilla/dom/Document.h"
21#include "mozilla/dom/HTMLFrameElement.h"
22#include "mozilla/dom/ImageDocument.h"
23#include "mozilla/dom/BrowserParent.h"
24
25#include "nsCOMPtr.h"
26#include "nsGenericHTMLElement.h"
27#include "nsGenericHTMLFrameElement.h"
28#include "nsAttrValueInlines.h"
29#include "nsIDocShell.h"
30#include "nsIDocumentViewer.h"
31#include "nsIContentInlines.h"
32#include "nsPresContext.h"
33#include "nsView.h"
34#include "nsViewManager.h"
35#include "nsGkAtoms.h"
36#include "nsStyleConsts.h"
37#include "nsStyleStruct.h"
38#include "nsStyleStructInlines.h"
39#include "nsFrameSetFrame.h"
40#include "nsNameSpaceManager.h"
41#include "nsDisplayList.h"
42#include "nsIObjectLoadingContent.h"
43#include "nsLayoutUtils.h"
44#include "nsContentUtils.h"
45#include "nsServiceManagerUtils.h"
46#include "nsQueryObject.h"
47#include "RetainedDisplayListBuilder.h"
48#include "nsObjectLoadingContent.h"
49
50#include "mozilla/layers/WebRenderUserData.h"
51#include "mozilla/layers/WebRenderScrollData.h"
52#include "mozilla/layers/RenderRootStateManager.h"
53#include "mozilla/layers/StackingContextHelper.h" // for StackingContextHelper
54#include "mozilla/ProfilerLabels.h"
55
56using namespace mozilla;
57using namespace mozilla::dom;
58using namespace mozilla::gfx;
59using namespace mozilla::layers;
60
61static Document* GetDocumentFromView(nsView* aView) {
62 MOZ_ASSERT(aView, "null view")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aView)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aView))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aView" " (" "null view" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsSubDocumentFrame.cpp"
, 62); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aView" ") (" "null view"
")"); do { *((volatile int*)__null) = 62; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
63
64 nsViewManager* vm = aView->GetViewManager();
65 PresShell* presShell = vm ? vm->GetPresShell() : nullptr;
66 return presShell ? presShell->GetDocument() : nullptr;
67}
68
69static void PropagateIsUnderHiddenEmbedderElement(nsFrameLoader* aFrameLoader,
70 bool aValue) {
71 if (!aFrameLoader) {
72 return;
73 }
74
75 if (BrowsingContext* bc = aFrameLoader->GetExtantBrowsingContext()) {
76 if (bc->IsUnderHiddenEmbedderElement() != aValue) {
77 Unused << bc->SetIsUnderHiddenEmbedderElement(aValue);
78 }
79 }
80}
81
82nsSubDocumentFrame::nsSubDocumentFrame(ComputedStyle* aStyle,
83 nsPresContext* aPresContext)
84 : nsAtomicContainerFrame(aStyle, aPresContext, kClassID),
85 mOuterView(nullptr),
86 mInnerView(nullptr),
87 mIsInline(false),
88 mPostedReflowCallback(false),
89 mDidCreateDoc(false),
90 mCallingShow(false),
91 mIsInObjectOrEmbed(false) {}
92
93#ifdef ACCESSIBILITY1
94a11y::AccType nsSubDocumentFrame::AccessibleType() {
95 return a11y::eOuterDocType;
96}
97#endif
98
99NS_QUERYFRAME_HEAD(nsSubDocumentFrame)void* nsSubDocumentFrame ::QueryFrame(FrameIID id) const { switch
(id) {
100 NS_QUERYFRAME_ENTRY(nsSubDocumentFrame)case nsSubDocumentFrame ::kFrameIID: { static_assert( std::is_same_v
<nsSubDocumentFrame, nsSubDocumentFrame ::Has_NS_DECL_QUERYFRAME_TARGET
>, "nsSubDocumentFrame" " must declare itself as a queryframe target"
); return const_cast<nsSubDocumentFrame*>(static_cast<
const nsSubDocumentFrame*>(this)); }
101NS_QUERYFRAME_TAIL_INHERITING(nsAtomicContainerFrame)default: break; } return nsAtomicContainerFrame ::QueryFrame(
id); }
102
103class AsyncFrameInit : public Runnable {
104 public:
105 explicit AsyncFrameInit(nsIFrame* aFrame)
106 : mozilla::Runnable("AsyncFrameInit"), mFrame(aFrame) {}
107 NS_IMETHODvirtual nsresult Run() override {
108 AUTO_PROFILER_LABEL("AsyncFrameInit::Run", OTHER)mozilla::AutoProfilerLabel raiiObject108( "AsyncFrameInit::Run"
, nullptr, JS::ProfilingCategoryPair::OTHER)
;
109 if (mFrame.IsAlive()) {
110 static_cast<nsSubDocumentFrame*>(mFrame.GetFrame())->ShowViewer();
111 }
112 return NS_OK;
113 }
114
115 private:
116 WeakFrame mFrame;
117};
118
119void nsSubDocumentFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
120 nsIFrame* aPrevInFlow) {
121 MOZ_ASSERT(aContent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aContent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aContent", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsSubDocumentFrame.cpp"
, 121); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent" ")"
); do { *((volatile int*)__null) = 121; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
122 // determine if we are a <frame> or <iframe>
123 mIsInline = !aContent->IsHTMLElement(nsGkAtoms::frame);
124
125 nsAtomicContainerFrame::Init(aContent, aParent, aPrevInFlow);
126
127 // CreateView() creates this frame's view, stored in mOuterView. It needs to
128 // be created first since it's the parent of the inner view, stored in
129 // mInnerView.
130 CreateView();
131 EnsureInnerView();
132
133 // Set the primary frame now so that nsDocumentViewer::FindContainerView
134 // called from within EndSwapDocShellsForViews below can find it if needed.
135 aContent->SetPrimaryFrame(this);
136
137 // If we have a detached subdoc's root view on our frame loader, re-insert it
138 // into the view tree. This happens when we've been reframed, and ensures the
139 // presentation persists across reframes.
140 if (RefPtr<nsFrameLoader> frameloader = FrameLoader()) {
141 bool hadFrame = false;
142 nsIFrame* detachedFrame = frameloader->GetDetachedSubdocFrame(&hadFrame);
143 frameloader->SetDetachedSubdocFrame(nullptr);
144 nsView* detachedView = detachedFrame ? detachedFrame->GetView() : nullptr;
145 if (detachedView) {
146 // Restore stashed presentation.
147 InsertViewsInReverseOrder(detachedView, mInnerView);
148 EndSwapDocShellsForViews(mInnerView->GetFirstChild());
149 } else if (hadFrame) {
150 // Presentation is for a different document, don't restore it.
151 frameloader->Hide();
152 }
153 }
154
155 // NOTE: The frame loader might not yet be initialized yet. If it's not, the
156 // call in ShowViewer() should pick things up.
157 UpdateEmbeddedBrowsingContextDependentData();
158 nsContentUtils::AddScriptRunner(new AsyncFrameInit(this));
159}
160
161void nsSubDocumentFrame::UpdateEmbeddedBrowsingContextDependentData() {
162 if (!mFrameLoader) {
163 return;
164 }
165 BrowsingContext* bc = mFrameLoader->GetExtantBrowsingContext();
166 if (!bc) {
167 return;
168 }
169 mIsInObjectOrEmbed = bc->IsEmbedderTypeObjectOrEmbed();
170 MaybeUpdateRemoteStyle();
171 MaybeUpdateEmbedderColorScheme();
172 PropagateIsUnderHiddenEmbedderElement(
173 PresShell()->IsUnderHiddenEmbedderElement() ||
174 !StyleVisibility()->IsVisible());
175}
176
177void nsSubDocumentFrame::PropagateIsUnderHiddenEmbedderElement(bool aValue) {
178 ::PropagateIsUnderHiddenEmbedderElement(mFrameLoader, aValue);
179}
180
181void nsSubDocumentFrame::ShowViewer() {
182 if (mCallingShow) {
183 return;
184 }
185
186 RefPtr<nsFrameLoader> frameloader = FrameLoader();
187 if (!frameloader || frameloader->IsDead()) {
188 return;
189 }
190
191 if (!frameloader->IsRemoteFrame() && !PresContext()->IsDynamic()) {
192 // We let the printing code take care of loading the document and
193 // initializing the shell; just create the inner view for it to use.
194 (void)EnsureInnerView();
195 } else {
196 AutoWeakFrame weakThis(this);
197 mCallingShow = true;
198 bool didCreateDoc = frameloader->Show(this);
199 if (!weakThis.IsAlive()) {
200 return;
201 }
202 mCallingShow = false;
203 mDidCreateDoc = didCreateDoc;
204 if (!HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
205 frameloader->UpdatePositionAndSize(this);
206 }
207 if (!weakThis.IsAlive()) {
208 return;
209 }
210 UpdateEmbeddedBrowsingContextDependentData();
211 InvalidateFrame();
212 }
213}
214
215nsIFrame* nsSubDocumentFrame::GetSubdocumentRootFrame() {
216 if (!mInnerView) return nullptr;
217 nsView* subdocView = mInnerView->GetFirstChild();
218 return subdocView ? subdocView->GetFrame() : nullptr;
219}
220
221mozilla::PresShell* nsSubDocumentFrame::GetSubdocumentPresShellForPainting(
222 uint32_t aFlags) {
223 if (!mInnerView) return nullptr;
224
225 nsView* subdocView = mInnerView->GetFirstChild();
226 if (!subdocView) return nullptr;
227
228 mozilla::PresShell* presShell = nullptr;
229
230 nsIFrame* subdocRootFrame = subdocView->GetFrame();
231 if (subdocRootFrame) {
232 presShell = subdocRootFrame->PresShell();
233 }
234
235 // If painting is suppressed in the presshell, we try to look for a better
236 // presshell to use.
237 if (!presShell || (presShell->IsPaintingSuppressed() &&
238 !(aFlags & IGNORE_PAINT_SUPPRESSION))) {
239 // During page transition mInnerView will sometimes have two children, the
240 // first being the new page that may not have any frame, and the second
241 // being the old page that will probably have a frame.
242 nsView* nextView = subdocView->GetNextSibling();
243 nsIFrame* frame = nullptr;
244 if (nextView) {
245 frame = nextView->GetFrame();
246 }
247 if (frame) {
248 mozilla::PresShell* presShellForNextView = frame->PresShell();
249 if (!presShell || (presShellForNextView &&
250 !presShellForNextView->IsPaintingSuppressed() &&
251 StaticPrefs::layout_show_previous_page())) {
252 subdocView = nextView;
253 subdocRootFrame = frame;
Value stored to 'subdocRootFrame' is never read
254 presShell = presShellForNextView;
255 }
256 }
257 if (!presShell) {
258 // If we don't have a frame we use this roundabout way to get the pres
259 // shell.
260 if (!mFrameLoader) return nullptr;
261 nsIDocShell* docShell = mFrameLoader->GetDocShell(IgnoreErrors());
262 if (!docShell) return nullptr;
263 presShell = docShell->GetPresShell();
264 }
265 }
266
267 return presShell;
268}
269
270nsRect nsSubDocumentFrame::GetDestRect() {
271 nsRect rect = GetContent()->IsHTMLElement(nsGkAtoms::frame)
272 ? GetRectRelativeToSelf()
273 : GetContentRectRelativeToSelf();
274 return GetDestRect(rect);
275}
276
277nsRect nsSubDocumentFrame::GetDestRect(const nsRect& aConstraintRect) {
278 // Adjust subdocument size, according to 'object-fit' and the subdocument's
279 // intrinsic size and ratio.
280 return nsLayoutUtils::ComputeObjectDestRect(
281 aConstraintRect, ComputeIntrinsicSize(/* aIgnoreContainment = */ true),
282 GetIntrinsicRatio(), StylePosition());
283}
284
285ScreenIntSize nsSubDocumentFrame::GetSubdocumentSize() {
286 if (HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
287 if (RefPtr<nsFrameLoader> frameloader = FrameLoader()) {
288 nsIFrame* detachedFrame = frameloader->GetDetachedSubdocFrame();
289 if (nsView* view = detachedFrame ? detachedFrame->GetView() : nullptr) {
290 nsSize size = view->GetBounds().Size();
291 nsPresContext* presContext = detachedFrame->PresContext();
292 return ScreenIntSize(presContext->AppUnitsToDevPixels(size.width),
293 presContext->AppUnitsToDevPixels(size.height));
294 }
295 }
296 // Pick some default size for now. Using 10x10 because that's what the
297 // code used to do.
298 return ScreenIntSize(10, 10);
299 }
300
301 nsSize docSizeAppUnits = GetDestRect().Size();
302 nsPresContext* pc = PresContext();
303 return ScreenIntSize(pc->AppUnitsToDevPixels(docSizeAppUnits.width),
304 pc->AppUnitsToDevPixels(docSizeAppUnits.height));
305}
306
307static void WrapBackgroundColorInOwnLayer(nsDisplayListBuilder* aBuilder,
308 nsIFrame* aFrame,
309 nsDisplayList* aList) {
310 for (nsDisplayItem* item : aList->TakeItems()) {
311 if (item->GetType() == DisplayItemType::TYPE_BACKGROUND_COLOR) {
312 nsDisplayList tmpList(aBuilder);
313 tmpList.AppendToTop(item);
314 item = MakeDisplayItemWithIndex<nsDisplayOwnLayer>(
315 aBuilder, aFrame, /* aIndex = */ nsDisplayOwnLayer::OwnLayerForSubdoc,
316 &tmpList, aBuilder->CurrentActiveScrolledRoot(),
317 nsDisplayOwnLayerFlags::None, ScrollbarData{}, true, false);
318 }
319 aList->AppendToTop(item);
320 }
321}
322
323void nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
324 const nsDisplayListSet& aLists) {
325 if (!IsVisibleForPainting()) {
326 return;
327 }
328
329 const bool pointerEventsNone =
330 Style()->PointerEvents() == StylePointerEvents::None;
331 if (aBuilder->IsForEventDelivery() && pointerEventsNone) {
332 // If we are pointer-events:none then we don't need to HitTest background or
333 // anything else.
334 return;
335 }
336
337 nsFrameLoader* frameLoader = FrameLoader();
338 const bool isRemoteFrame = frameLoader && frameLoader->IsRemoteFrame();
339
340 nsDisplayListCollection decorations(aBuilder);
341 DisplayBorderBackgroundOutline(aBuilder, decorations);
342 if (isRemoteFrame) {
343 // Wrap background colors of <iframe>s with remote subdocuments in their
344 // own layer so we generate a ColorLayer. This is helpful for optimizing
345 // compositing; we can skip compositing the ColorLayer when the
346 // remote content is opaque.
347 WrapBackgroundColorInOwnLayer(aBuilder, this,
348 decorations.BorderBackground());
349 }
350 decorations.MoveTo(aLists);
351
352 if (HidesContent()) {
353 return;
354 }
355
356 // If we're passing pointer events to children then we have to descend into
357 // subdocuments no matter what, to determine which parts are transparent for
358 // hit-testing or event regions.
359 bool needToDescend = aBuilder->GetDescendIntoSubdocuments();
360 if (!mInnerView || !needToDescend) {
361 return;
362 }
363
364 if (isRemoteFrame) {
365 // We're the subdoc for <browser remote="true"> and it has
366 // painted content. Display its shadow layer tree.
367 DisplayListClipState::AutoSaveRestore clipState(aBuilder);
368 clipState.ClipContainingBlockDescendantsToContentBox(aBuilder, this);
369
370 aLists.Content()->AppendNewToTop<nsDisplayRemote>(aBuilder, this);
371 return;
372 }
373
374 RefPtr<mozilla::PresShell> presShell = GetSubdocumentPresShellForPainting(
375 aBuilder->IsIgnoringPaintSuppression() ? IGNORE_PAINT_SUPPRESSION : 0);
376
377 if (!presShell) {
378 return;
379 }
380
381 if (aBuilder->IsInFilter()) {
382 Document* outerDoc = PresShell()->GetDocument();
383 Document* innerDoc = presShell->GetDocument();
384 if (outerDoc && innerDoc) {
385 if (!outerDoc->NodePrincipal()->Equals(innerDoc->NodePrincipal())) {
386 outerDoc->SetUseCounter(eUseCounter_custom_FilteredCrossOriginIFrame);
387 }
388 }
389 }
390
391 nsIFrame* subdocRootFrame = presShell->GetRootFrame();
392
393 nsPresContext* presContext = presShell->GetPresContext();
394
395 int32_t parentAPD = PresContext()->AppUnitsPerDevPixel();
396 int32_t subdocAPD = presContext->AppUnitsPerDevPixel();
397
398 nsRect visible;
399 nsRect dirty;
400 bool ignoreViewportScrolling = false;
401 if (subdocRootFrame) {
402 // get the dirty rect relative to the root frame of the subdoc
403 visible = aBuilder->GetVisibleRect() + GetOffsetToCrossDoc(subdocRootFrame);
404 dirty = aBuilder->GetDirtyRect() + GetOffsetToCrossDoc(subdocRootFrame);
405 // and convert into the appunits of the subdoc
406 visible = visible.ScaleToOtherAppUnitsRoundOut(parentAPD, subdocAPD);
407 dirty = dirty.ScaleToOtherAppUnitsRoundOut(parentAPD, subdocAPD);
408
409 if (ScrollContainerFrame* sf = presShell->GetRootScrollContainerFrame()) {
410 // Use a copy, so the rects don't get modified.
411 nsRect copyOfDirty = dirty;
412 nsRect copyOfVisible = visible;
413 // TODO(botond): Can we just axe this DecideScrollableLayer call?
414 sf->DecideScrollableLayer(aBuilder, &copyOfVisible, &copyOfDirty,
415 /* aSetBase = */ true);
416
417 ignoreViewportScrolling = presShell->IgnoringViewportScrolling();
418 }
419
420 aBuilder->EnterPresShell(subdocRootFrame, pointerEventsNone);
421 aBuilder->IncrementPresShellPaintCount(presShell);
422 } else {
423 visible = aBuilder->GetVisibleRect();
424 dirty = aBuilder->GetDirtyRect();
425 }
426
427 DisplayListClipState::AutoSaveRestore clipState(aBuilder);
428 clipState.ClipContainingBlockDescendantsToContentBox(aBuilder, this);
429
430 ScrollContainerFrame* sf = presShell->GetRootScrollContainerFrame();
431 bool constructZoomItem = subdocRootFrame && parentAPD != subdocAPD;
432 bool needsOwnLayer = constructZoomItem ||
433 presContext->IsRootContentDocumentCrossProcess() ||
434 (sf && sf->IsScrollingActive());
435
436 nsDisplayList childItems(aBuilder);
437
438 {
439 DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder);
440 if (needsOwnLayer) {
441 // Clear current clip. There's no point in propagating it down, since
442 // the layer we will construct will be clipped by the current clip.
443 // In fact for nsDisplayZoom propagating it down would be incorrect since
444 // nsDisplayZoom changes the meaning of appunits.
445 nestedClipState.Clear();
446 }
447
448 // Invoke AutoBuildingDisplayList to ensure that the correct dirty rect
449 // is used to compute the visible rect if AddCanvasBackgroundColorItem
450 // creates a display item.
451 nsIFrame* frame = subdocRootFrame ? subdocRootFrame : this;
452 nsDisplayListBuilder::AutoBuildingDisplayList building(aBuilder, frame,
453 visible, dirty);
454
455 if (subdocRootFrame) {
456 bool hasDocumentLevelListenersForApzAwareEvents =
457 gfxPlatform::AsyncPanZoomEnabled() &&
458 nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(presShell);
459
460 aBuilder->SetAncestorHasApzAwareEventHandler(
461 hasDocumentLevelListenersForApzAwareEvents);
462 subdocRootFrame->BuildDisplayListForStackingContext(aBuilder,
463 &childItems);
464 if (!aBuilder->IsForEventDelivery()) {
465 // If we are going to use a displayzoom below then any items we put
466 // under it need to have underlying frames from the subdocument. So we
467 // need to calculate the bounds based on which frame will be the
468 // underlying frame for the canvas background color item.
469 nsRect bounds =
470 GetContentRectRelativeToSelf() + aBuilder->ToReferenceFrame(this);
471 bounds = bounds.ScaleToOtherAppUnitsRoundOut(parentAPD, subdocAPD);
472
473 // Add the canvas background color to the bottom of the list. This
474 // happens after we've built the list so that
475 // AddCanvasBackgroundColorItem can monkey with the contents if
476 // necessary.
477 presShell->AddCanvasBackgroundColorItem(aBuilder, &childItems, frame,
478 bounds, NS_RGBA(0, 0, 0, 0)((nscolor)(((0) << 24) | ((0) << 16) | ((0) <<
8) | (0)))
);
479 }
480 }
481 }
482
483 if (subdocRootFrame) {
484 aBuilder->LeavePresShell(subdocRootFrame, &childItems);
485 }
486
487 // Generate a resolution and/or zoom item if needed. If one or both of those
488 // is created, we don't need to create a separate nsDisplaySubDocument.
489
490 nsDisplayOwnLayerFlags flags =
491 nsDisplayOwnLayerFlags::GenerateSubdocInvalidations;
492 // If ignoreViewportScrolling is true then the top most layer we create here
493 // is going to become the scrollable layer for the root scroll frame, so we
494 // want to add nsDisplayOwnLayer::GENERATE_SCROLLABLE_LAYER to whatever layer
495 // becomes the topmost. We do this below.
496 if (constructZoomItem) {
497 nsDisplayOwnLayerFlags zoomFlags = flags;
498 if (ignoreViewportScrolling) {
499 zoomFlags |= nsDisplayOwnLayerFlags::GenerateScrollableLayer;
500 }
501 childItems.AppendNewToTop<nsDisplayZoom>(aBuilder, subdocRootFrame, this,
502 &childItems, subdocAPD, parentAPD,
503 zoomFlags);
504
505 needsOwnLayer = false;
506 }
507 // Wrap the zoom item in the resolution item if we have both because we want
508 // the resolution scale applied on top of the app units per dev pixel
509 // conversion.
510 if (ignoreViewportScrolling) {
511 flags |= nsDisplayOwnLayerFlags::GenerateScrollableLayer;
512 }
513
514 // We always want top level content documents to be in their own layer.
515 nsDisplaySubDocument* layerItem = MakeDisplayItem<nsDisplaySubDocument>(
516 aBuilder, subdocRootFrame ? subdocRootFrame : this, this, &childItems,
517 flags);
518 if (layerItem) {
519 childItems.AppendToTop(layerItem);
520 layerItem->SetShouldFlattenAway(!needsOwnLayer);
521 }
522
523 if (aBuilder->IsForFrameVisibility()) {
524 // We don't add the childItems to the return list as we're dealing with them
525 // here.
526 presShell->RebuildApproximateFrameVisibilityDisplayList(childItems);
527 childItems.DeleteAll(aBuilder);
528 } else {
529 aLists.Content()->AppendToTop(&childItems);
530 }
531}
532
533#ifdef DEBUG_FRAME_DUMP1
534void nsSubDocumentFrame::List(FILE* out, const char* aPrefix,
535 ListFlags aFlags) const {
536 nsCString str;
537 ListGeneric(str, aPrefix, aFlags);
538 fprintf_stderr(out, "%s\n", str.get());
539
540 if (aFlags.contains(ListFlag::TraverseSubdocumentFrames)) {
541 nsSubDocumentFrame* f = const_cast<nsSubDocumentFrame*>(this);
542 nsIFrame* subdocRootFrame = f->GetSubdocumentRootFrame();
543 if (subdocRootFrame) {
544 nsCString pfx(aPrefix);
545 pfx += " ";
546 subdocRootFrame->List(out, pfx.get(), aFlags);
547 }
548 }
549}
550
551nsresult nsSubDocumentFrame::GetFrameName(nsAString& aResult) const {
552 return MakeFrameName(u"FrameOuter"_ns, aResult);
553}
554#endif
555
556/* virtual */
557nscoord nsSubDocumentFrame::GetMinISize(gfxContext* aRenderingContext) {
558 return GetIntrinsicISize();
559}
560
561/* virtual */
562nscoord nsSubDocumentFrame::GetPrefISize(gfxContext* aRenderingContext) {
563 // If the subdocument is an SVG document, then in theory we want to return
564 // the same thing that SVGOuterSVGFrame::GetPrefISize does. That method
565 // has some special handling of percentage values to avoid unhelpful zero
566 // sizing in the presence of orthogonal writing modes. We don't bother
567 // with that for SVG documents in <embed> and <object>, since that special
568 // handling doesn't look up across document boundaries anyway.
569 return GetIntrinsicISize();
570}
571
572/* virtual */
573IntrinsicSize nsSubDocumentFrame::GetIntrinsicSize() {
574 return ComputeIntrinsicSize();
575}
576
577IntrinsicSize nsSubDocumentFrame::ComputeIntrinsicSize(
578 bool aIgnoreContainment) const {
579 const auto containAxes =
580 aIgnoreContainment ? ContainSizeAxes(false, false) : GetContainSizeAxes();
581 if (containAxes.IsBoth()) {
582 // Intrinsic size of 'contain:size' replaced elements is determined by
583 // contain-intrinsic-size.
584 return FinishIntrinsicSize(containAxes, IntrinsicSize(0, 0));
585 }
586
587 if (nsCOMPtr<nsIObjectLoadingContent> iolc = do_QueryInterface(mContent)) {
588 const auto* olc = static_cast<nsObjectLoadingContent*>(iolc.get());
589 if (auto size = olc->GetSubdocumentIntrinsicSize()) {
590 // Use the intrinsic size from the child SVG document, if available.
591 return FinishIntrinsicSize(containAxes, *size);
592 }
593 }
594
595 if (!IsInline()) {
596 return {}; // <frame> elements have no useful intrinsic size.
597 }
598
599 if (mContent->IsXULElement()) {
600 return {}; // XUL <iframe> and <browser> have no useful intrinsic size
601 }
602
603 // We must be an HTML <iframe>. Return fallback size.
604 return FinishIntrinsicSize(containAxes,
605 IntrinsicSize(kFallbackIntrinsicSize));
606}
607
608/* virtual */
609AspectRatio nsSubDocumentFrame::GetIntrinsicRatio() const {
610 // FIXME(emilio): This should probably respect contain: size and return no
611 // ratio in the case subDocRoot is non-null. Otherwise we do it by virtue of
612 // using a zero-size below and reusing GetIntrinsicSize().
613 if (nsCOMPtr<nsIObjectLoadingContent> iolc = do_QueryInterface(mContent)) {
614 auto olc = static_cast<nsObjectLoadingContent*>(iolc.get());
615
616 auto ratio = olc->GetSubdocumentIntrinsicRatio();
617 if (ratio && *ratio) {
618 // Use the intrinsic aspect ratio from the child SVG document, if
619 // available.
620 return *ratio;
621 }
622 }
623
624 // NOTE(emilio): Even though we have an intrinsic size, we may not have an
625 // intrinsic ratio. For example `<iframe style="width: 100px">` should not
626 // shrink in the vertical axis to preserve the 300x150 ratio.
627 return nsAtomicContainerFrame::GetIntrinsicRatio();
628}
629
630/* virtual */
631LogicalSize nsSubDocumentFrame::ComputeAutoSize(
632 gfxContext* aRenderingContext, WritingMode aWM, const LogicalSize& aCBSize,
633 nscoord aAvailableISize, const LogicalSize& aMargin,
634 const LogicalSize& aBorderPadding, const StyleSizeOverrides& aSizeOverrides,
635 ComputeSizeFlags aFlags) {
636 if (!IsInline()) {
637 return nsIFrame::ComputeAutoSize(aRenderingContext, aWM, aCBSize,
638 aAvailableISize, aMargin, aBorderPadding,
639 aSizeOverrides, aFlags);
640 }
641
642 const WritingMode wm = GetWritingMode();
643 LogicalSize result(wm, GetIntrinsicISize(), GetIntrinsicBSize());
644 return result.ConvertTo(aWM, wm);
645}
646
647/* virtual */
648nsIFrame::SizeComputationResult nsSubDocumentFrame::ComputeSize(
649 gfxContext* aRenderingContext, WritingMode aWM, const LogicalSize& aCBSize,
650 nscoord aAvailableISize, const LogicalSize& aMargin,
651 const LogicalSize& aBorderPadding, const StyleSizeOverrides& aSizeOverrides,
652 ComputeSizeFlags aFlags) {
653 return {ComputeSizeWithIntrinsicDimensions(
654 aRenderingContext, aWM, GetIntrinsicSize(), GetAspectRatio(),
655 aCBSize, aMargin, aBorderPadding, aSizeOverrides, aFlags),
656 AspectRatioUsage::None};
657}
658
659void nsSubDocumentFrame::Reflow(nsPresContext* aPresContext,
660 ReflowOutput& aDesiredSize,
661 const ReflowInput& aReflowInput,
662 nsReflowStatus& aStatus) {
663 MarkInReflow();
664 DO_GLOBAL_REFLOW_COUNT("nsSubDocumentFrame")aPresContext->CountReflows(("nsSubDocumentFrame"), (nsIFrame
*)this);
;
665 MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus.IsEmpty()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aStatus.IsEmpty()"
" (" "Caller should pass a fresh reflow status!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsSubDocumentFrame.cpp"
, 665); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus.IsEmpty()"
") (" "Caller should pass a fresh reflow status!" ")"); do {
*((volatile int*)__null) = 665; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
666 NS_FRAME_TRACE(do { if ((int(((mozilla::LogModule*)(nsIFrame::sFrameLogModule
))->Level()) & (0x1))) { TraceMsg ("enter nsSubDocumentFrame::Reflow: maxSize=%d,%d"
, aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight
()); } } while (0)
667 NS_FRAME_TRACE_CALLS,do { if ((int(((mozilla::LogModule*)(nsIFrame::sFrameLogModule
))->Level()) & (0x1))) { TraceMsg ("enter nsSubDocumentFrame::Reflow: maxSize=%d,%d"
, aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight
()); } } while (0)
668 ("enter nsSubDocumentFrame::Reflow: maxSize=%d,%d",do { if ((int(((mozilla::LogModule*)(nsIFrame::sFrameLogModule
))->Level()) & (0x1))) { TraceMsg ("enter nsSubDocumentFrame::Reflow: maxSize=%d,%d"
, aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight
()); } } while (0)
669 aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight()))do { if ((int(((mozilla::LogModule*)(nsIFrame::sFrameLogModule
))->Level()) & (0x1))) { TraceMsg ("enter nsSubDocumentFrame::Reflow: maxSize=%d,%d"
, aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight
()); } } while (0)
;
670
671 NS_ASSERTION(aReflowInput.ComputedISize() != NS_UNCONSTRAINEDSIZE,do { if (!(aReflowInput.ComputedISize() != NS_UNCONSTRAINEDSIZE
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Shouldn't have unconstrained inline-size here "
"thanks to the rules of reflow", "aReflowInput.ComputedISize() != NS_UNCONSTRAINEDSIZE"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsSubDocumentFrame.cpp"
, 673); MOZ_PretendNoReturn(); } } while (0)
672 "Shouldn't have unconstrained inline-size here "do { if (!(aReflowInput.ComputedISize() != NS_UNCONSTRAINEDSIZE
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Shouldn't have unconstrained inline-size here "
"thanks to the rules of reflow", "aReflowInput.ComputedISize() != NS_UNCONSTRAINEDSIZE"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsSubDocumentFrame.cpp"
, 673); MOZ_PretendNoReturn(); } } while (0)
673 "thanks to the rules of reflow")do { if (!(aReflowInput.ComputedISize() != NS_UNCONSTRAINEDSIZE
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Shouldn't have unconstrained inline-size here "
"thanks to the rules of reflow", "aReflowInput.ComputedISize() != NS_UNCONSTRAINEDSIZE"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsSubDocumentFrame.cpp"
, 673); MOZ_PretendNoReturn(); } } while (0)
;
674 NS_ASSERTION(aReflowInput.ComputedBSize() != NS_UNCONSTRAINEDSIZE,do { if (!(aReflowInput.ComputedBSize() != NS_UNCONSTRAINEDSIZE
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Shouldn't have unconstrained block-size here "
"thanks to ComputeAutoSize", "aReflowInput.ComputedBSize() != NS_UNCONSTRAINEDSIZE"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsSubDocumentFrame.cpp"
, 676); MOZ_PretendNoReturn(); } } while (0)
675 "Shouldn't have unconstrained block-size here "do { if (!(aReflowInput.ComputedBSize() != NS_UNCONSTRAINEDSIZE
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Shouldn't have unconstrained block-size here "
"thanks to ComputeAutoSize", "aReflowInput.ComputedBSize() != NS_UNCONSTRAINEDSIZE"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsSubDocumentFrame.cpp"
, 676); MOZ_PretendNoReturn(); } } while (0)
676 "thanks to ComputeAutoSize")do { if (!(aReflowInput.ComputedBSize() != NS_UNCONSTRAINEDSIZE
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Shouldn't have unconstrained block-size here "
"thanks to ComputeAutoSize", "aReflowInput.ComputedBSize() != NS_UNCONSTRAINEDSIZE"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsSubDocumentFrame.cpp"
, 676); MOZ_PretendNoReturn(); } } while (0)
;
677
678 NS_ASSERTION(mContent->GetPrimaryFrame() == this, "Shouldn't happen")do { if (!(mContent->GetPrimaryFrame() == this)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Shouldn't happen", "mContent->GetPrimaryFrame() == this"
, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsSubDocumentFrame.cpp"
, 678); MOZ_PretendNoReturn(); } } while (0)
;
679
680 // XUL <iframe> or <browser>, or HTML <iframe>, <object> or <embed>
681 const auto wm = aReflowInput.GetWritingMode();
682 aDesiredSize.SetSize(wm, aReflowInput.ComputedSizeWithBorderPadding(wm));
683
684 // "offset" is the offset of our content area from our frame's
685 // top-left corner.
686 nsPoint offset = nsPoint(aReflowInput.ComputedPhysicalBorderPadding().left,
687 aReflowInput.ComputedPhysicalBorderPadding().top);
688
689 if (mInnerView) {
690 const nsMargin& bp = aReflowInput.ComputedPhysicalBorderPadding();
691 nsSize innerSize(aDesiredSize.Width() - bp.LeftRight(),
692 aDesiredSize.Height() - bp.TopBottom());
693
694 // Size & position the view according to 'object-fit' & 'object-position'.
695 nsRect destRect = GetDestRect(nsRect(offset, innerSize));
696 nsViewManager* vm = mInnerView->GetViewManager();
697 vm->MoveViewTo(mInnerView, destRect.x, destRect.y);
698 vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), destRect.Size()));
699 }
700
701 aDesiredSize.SetOverflowAreasToDesiredBounds();
702
703 FinishAndStoreOverflow(&aDesiredSize);
704
705 if (!aPresContext->IsRootPaginatedDocument() && !mPostedReflowCallback) {
706 PresShell()->PostReflowCallback(this);
707 mPostedReflowCallback = true;
708 }
709
710 NS_FRAME_TRACE(do { if ((int(((mozilla::LogModule*)(nsIFrame::sFrameLogModule
))->Level()) & (0x1))) { TraceMsg ("exit nsSubDocumentFrame::Reflow: size=%d,%d status=%s"
, aDesiredSize.Width(), aDesiredSize.Height(), ToString(aStatus
).c_str()); } } while (0)
711 NS_FRAME_TRACE_CALLS,do { if ((int(((mozilla::LogModule*)(nsIFrame::sFrameLogModule
))->Level()) & (0x1))) { TraceMsg ("exit nsSubDocumentFrame::Reflow: size=%d,%d status=%s"
, aDesiredSize.Width(), aDesiredSize.Height(), ToString(aStatus
).c_str()); } } while (0)
712 ("exit nsSubDocumentFrame::Reflow: size=%d,%d status=%s",do { if ((int(((mozilla::LogModule*)(nsIFrame::sFrameLogModule
))->Level()) & (0x1))) { TraceMsg ("exit nsSubDocumentFrame::Reflow: size=%d,%d status=%s"
, aDesiredSize.Width(), aDesiredSize.Height(), ToString(aStatus
).c_str()); } } while (0)
713 aDesiredSize.Width(), aDesiredSize.Height(), ToString(aStatus).c_str()))do { if ((int(((mozilla::LogModule*)(nsIFrame::sFrameLogModule
))->Level()) & (0x1))) { TraceMsg ("exit nsSubDocumentFrame::Reflow: size=%d,%d status=%s"
, aDesiredSize.Width(), aDesiredSize.Height(), ToString(aStatus
).c_str()); } } while (0)
;
714}
715
716bool nsSubDocumentFrame::ReflowFinished() {
717 RefPtr<nsFrameLoader> frameloader = FrameLoader();
718 if (frameloader) {
719 AutoWeakFrame weakFrame(this);
720
721 frameloader->UpdatePositionAndSize(this);
722
723 if (weakFrame.IsAlive()) {
724 // Make sure that we can post a reflow callback in the future.
725 mPostedReflowCallback = false;
726 }
727 } else {
728 mPostedReflowCallback = false;
729 }
730 return false;
731}
732
733void nsSubDocumentFrame::ReflowCallbackCanceled() {
734 mPostedReflowCallback = false;
735}
736
737nsresult nsSubDocumentFrame::AttributeChanged(int32_t aNameSpaceID,
738 nsAtom* aAttribute,
739 int32_t aModType) {
740 if (aNameSpaceID != kNameSpaceID_None) {
741 return NS_OK;
742 }
743
744 // If the noResize attribute changes, dis/allow frame to be resized
745 if (aAttribute == nsGkAtoms::noresize) {
746 // Note that we're not doing content type checks, but that's ok -- if
747 // they'd fail we will just end up with a null framesetFrame.
748 if (mContent->GetParent()->IsHTMLElement(nsGkAtoms::frameset)) {
749 nsIFrame* parentFrame = GetParent();
750
751 if (parentFrame) {
752 // There is no interface for nsHTMLFramesetFrame so QI'ing to
753 // concrete class, yay!
754 nsHTMLFramesetFrame* framesetFrame = do_QueryFrame(parentFrame);
755 if (framesetFrame) {
756 framesetFrame->RecalculateBorderResize();
757 }
758 }
759 }
760 } else if (aAttribute == nsGkAtoms::marginwidth ||
761 aAttribute == nsGkAtoms::marginheight) {
762 // Notify the frameloader
763 if (RefPtr<nsFrameLoader> frameloader = FrameLoader()) {
764 frameloader->MarginsChanged();
765 }
766 }
767
768 return NS_OK;
769}
770
771void nsSubDocumentFrame::MaybeUpdateEmbedderColorScheme() {
772 nsFrameLoader* fl = mFrameLoader.get();
773 if (!fl) {
774 return;
775 }
776
777 BrowsingContext* bc = fl->GetExtantBrowsingContext();
778 if (!bc) {
779 return;
780 }
781
782 auto ToOverride = [](ColorScheme aScheme) -> PrefersColorSchemeOverride {
783 return aScheme == ColorScheme::Dark ? PrefersColorSchemeOverride::Dark
784 : PrefersColorSchemeOverride::Light;
785 };
786
787 EmbedderColorSchemes schemes{
788 ToOverride(LookAndFeel::ColorSchemeForFrame(this, ColorSchemeMode::Used)),
789 ToOverride(
790 LookAndFeel::ColorSchemeForFrame(this, ColorSchemeMode::Preferred))};
791 if (bc->GetEmbedderColorSchemes() == schemes) {
792 return;
793 }
794
795 Unused << bc->SetEmbedderColorSchemes(schemes);
796}
797
798void nsSubDocumentFrame::MaybeUpdateRemoteStyle(
799 ComputedStyle* aOldComputedStyle) {
800 if (!mIsInObjectOrEmbed) {
801 return;
802 }
803
804 if (aOldComputedStyle &&
805 aOldComputedStyle->StyleVisibility()->mImageRendering ==
806 Style()->StyleVisibility()->mImageRendering) {
807 return;
808 }
809
810 if (!mFrameLoader) {
811 return;
812 }
813
814 if (mFrameLoader->IsRemoteFrame()) {
815 mFrameLoader->UpdateRemoteStyle(
816 Style()->StyleVisibility()->mImageRendering);
817 return;
818 }
819
820 BrowsingContext* context = mFrameLoader->GetExtantBrowsingContext();
821 if (!context) {
822 return;
823 }
824
825 Document* document = context->GetDocument();
826 if (!document) {
827 return;
828 }
829
830 if (document->IsImageDocument()) {
831 document->AsImageDocument()->UpdateRemoteStyle(
832 Style()->StyleVisibility()->mImageRendering);
833 }
834}
835
836void nsSubDocumentFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) {
837 nsAtomicContainerFrame::DidSetComputedStyle(aOldComputedStyle);
838
839 MaybeUpdateEmbedderColorScheme();
840
841 MaybeUpdateRemoteStyle(aOldComputedStyle);
842
843 // If this presshell has invisible ancestors, we don't need to propagate the
844 // visibility style change to the subdocument since the subdocument should
845 // have already set the IsUnderHiddenEmbedderElement flag in
846 // nsSubDocumentFrame::Init.
847 if (PresShell()->IsUnderHiddenEmbedderElement()) {
848 return;
849 }
850
851 const bool isVisible = StyleVisibility()->IsVisible();
852 if (!aOldComputedStyle ||
853 isVisible != aOldComputedStyle->StyleVisibility()->IsVisible()) {
854 PropagateIsUnderHiddenEmbedderElement(!isVisible);
855 }
856}
857
858nsIFrame* NS_NewSubDocumentFrame(PresShell* aPresShell, ComputedStyle* aStyle) {
859 return new (aPresShell)
860 nsSubDocumentFrame(aStyle, aPresShell->GetPresContext());
861}
862
863NS_IMPL_FRAMEARENA_HELPERS(nsSubDocumentFrame)void* nsSubDocumentFrame ::operator new(size_t sz, mozilla::PresShell
* aShell) { return aShell->AllocateFrame(nsQueryFrame::nsSubDocumentFrame_id
, sz); }
864
865class nsHideViewer final : public Runnable {
866 public:
867 nsHideViewer(nsIContent* aFrameElement, nsFrameLoader* aFrameLoader,
868 PresShell* aPresShell, bool aHideViewerIfFrameless)
869 : mozilla::Runnable("nsHideViewer"),
870 mFrameElement(aFrameElement),
871 mFrameLoader(aFrameLoader),
872 mPresShell(aPresShell),
873 mHideViewerIfFrameless(aHideViewerIfFrameless) {
874 NS_ASSERTION(mFrameElement, "Must have a frame element")do { if (!(mFrameElement)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Must have a frame element", "mFrameElement", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsSubDocumentFrame.cpp"
, 874); MOZ_PretendNoReturn(); } } while (0)
;
875 NS_ASSERTION(mFrameLoader, "Must have a frame loader")do { if (!(mFrameLoader)) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"Must have a frame loader", "mFrameLoader", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsSubDocumentFrame.cpp"
, 875); MOZ_PretendNoReturn(); } } while (0)
;
876 NS_ASSERTION(mPresShell, "Must have a presshell")do { if (!(mPresShell)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Must have a presshell"
, "mPresShell", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsSubDocumentFrame.cpp"
, 876); MOZ_PretendNoReturn(); } } while (0)
;
877 }
878
879 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODvirtual nsresult Run() override {
880 // Flush frames, to ensure any pending display:none changes are made.
881 // Note it can be unsafe to flush if we've destroyed the presentation
882 // for some other reason, like if we're shutting down.
883 //
884 // But avoid the flush if we know for sure we're away, like when we're out
885 // of the document already.
886 //
887 // FIXME(emilio): This could still be a perf footgun when removing lots of
888 // siblings where each of them cause the reframe of an ancestor which happen
889 // to contain a subdocument.
890 //
891 // We should find some way to avoid that!
892 if (!mPresShell->IsDestroying() && mFrameElement->IsInComposedDoc()) {
893 mPresShell->FlushPendingNotifications(FlushType::Frames);
894 }
895
896 // Either the frame has been constructed by now, or it never will be,
897 // either way we want to clear the stashed views.
898 mFrameLoader->SetDetachedSubdocFrame(nullptr);
899
900 nsSubDocumentFrame* frame = do_QueryFrame(mFrameElement->GetPrimaryFrame());
901 if (!frame || frame->FrameLoader() != mFrameLoader) {
902 PropagateIsUnderHiddenEmbedderElement(mFrameLoader, true);
903 if (mHideViewerIfFrameless) {
904 // The frame element has no nsIFrame for the same frame loader.
905 // Hide the nsFrameLoader, which destroys the presentation.
906 mFrameLoader->Hide();
907 }
908 }
909 return NS_OK;
910 }
911
912 private:
913 const nsCOMPtr<nsIContent> mFrameElement;
914 const RefPtr<nsFrameLoader> mFrameLoader;
915 const RefPtr<PresShell> mPresShell;
916 const bool mHideViewerIfFrameless;
917};
918
919static nsView* BeginSwapDocShellsForViews(nsView* aSibling);
920
921void nsSubDocumentFrame::Destroy(DestroyContext& aContext) {
922 if (mPostedReflowCallback) {
923 PresShell()->CancelReflowCallback(this);
924 mPostedReflowCallback = false;
925 }
926
927 // Detach the subdocument's views and stash them in the frame loader.
928 // We can then reattach them if we're being reframed (for example if
929 // the frame has been made position:fixed).
930 if (RefPtr<nsFrameLoader> frameloader = FrameLoader()) {
931 ClearDisplayItems();
932
933 nsView* detachedViews =
934 ::BeginSwapDocShellsForViews(mInnerView->GetFirstChild());
935
936 frameloader->SetDetachedSubdocFrame(
937 detachedViews ? detachedViews->GetFrame() : nullptr);
938
939 // We call nsFrameLoader::HideViewer() in a script runner so that we can
940 // safely determine whether the frame is being reframed or destroyed.
941 nsContentUtils::AddScriptRunner(new nsHideViewer(
942 mContent, frameloader, PresShell(), (mDidCreateDoc || mCallingShow)));
943 }
944
945 nsAtomicContainerFrame::Destroy(aContext);
946}
947
948nsFrameLoader* nsSubDocumentFrame::FrameLoader() const {
949 if (mFrameLoader) {
950 return mFrameLoader;
951 }
952
953 if (RefPtr<nsFrameLoaderOwner> loaderOwner = do_QueryObject(GetContent())) {
954 mFrameLoader = loaderOwner->GetFrameLoader();
955 }
956
957 return mFrameLoader;
958}
959
960auto nsSubDocumentFrame::GetRemotePaintData() const -> RemoteFramePaintData {
961 if (mRetainedRemoteFrame) {
962 return *mRetainedRemoteFrame;
963 }
964
965 RemoteFramePaintData data;
966 nsFrameLoader* fl = FrameLoader();
967 if (!fl) {
968 return data;
969 }
970
971 auto* rb = fl->GetRemoteBrowser();
972 if (!rb) {
973 return data;
974 }
975 data.mLayersId = rb->GetLayersId();
976 data.mTabId = rb->GetTabId();
977 return data;
978}
979
980void nsSubDocumentFrame::ResetFrameLoader(RetainPaintData aRetain) {
981 if (aRetain == RetainPaintData::Yes && mFrameLoader) {
982 mRetainedRemoteFrame = Some(GetRemotePaintData());
983 } else {
984 mRetainedRemoteFrame.reset();
985 }
986 mFrameLoader = nullptr;
987 ClearDisplayItems();
988 nsContentUtils::AddScriptRunner(new AsyncFrameInit(this));
989}
990
991void nsSubDocumentFrame::ClearRetainedPaintData() {
992 mRetainedRemoteFrame.reset();
993 ClearDisplayItems();
994 InvalidateFrameSubtree();
995}
996
997// XXX this should be called ObtainDocShell or something like that,
998// to indicate that it could have side effects
999nsIDocShell* nsSubDocumentFrame::GetDocShell() const {
1000 // How can FrameLoader() return null???
1001 if (NS_WARN_IF(!FrameLoader())NS_warn_if_impl(!FrameLoader(), "!FrameLoader()", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsSubDocumentFrame.cpp"
, 1001)
) {
1002 return nullptr;
1003 }
1004 return mFrameLoader->GetDocShell(IgnoreErrors());
1005}
1006
1007static void DestroyDisplayItemDataForFrames(nsIFrame* aFrame) {
1008 // Destroying a WebRenderUserDataTable can cause destruction of other objects
1009 // which can remove frame properties in their destructor. If we delete a frame
1010 // property it runs the destructor of the stored object in the middle of
1011 // updating the frame property table, so if the destruction of that object
1012 // causes another update to the frame property table it would leave the frame
1013 // property table in an inconsistent state. So we remove it from the table and
1014 // then destroy it. (bug 1530657)
1015 WebRenderUserDataTable* userDataTable =
1016 aFrame->TakeProperty(WebRenderUserDataProperty::Key());
1017 if (userDataTable) {
1018 for (const auto& data : userDataTable->Values()) {
1019 data->RemoveFromTable();
1020 }
1021 delete userDataTable;
1022 }
1023
1024 for (const auto& childList : aFrame->ChildLists()) {
1025 for (nsIFrame* child : childList.mList) {
1026 DestroyDisplayItemDataForFrames(child);
1027 }
1028 }
1029}
1030
1031static CallState BeginSwapDocShellsForDocument(Document& aDocument) {
1032 if (PresShell* presShell = aDocument.GetPresShell()) {
1033 // Disable painting while the views are detached, see bug 946929.
1034 presShell->SetNeverPainting(true);
1035
1036 if (nsIFrame* rootFrame = presShell->GetRootFrame()) {
1037 ::DestroyDisplayItemDataForFrames(rootFrame);
1038 }
1039 }
1040 aDocument.EnumerateSubDocuments(BeginSwapDocShellsForDocument);
1041 return CallState::Continue;
1042}
1043
1044static nsView* BeginSwapDocShellsForViews(nsView* aSibling) {
1045 // Collect the removed sibling views in reverse order in 'removedViews'.
1046 nsView* removedViews = nullptr;
1047 while (aSibling) {
1048 if (Document* doc = ::GetDocumentFromView(aSibling)) {
1049 ::BeginSwapDocShellsForDocument(*doc);
1050 }
1051 nsView* next = aSibling->GetNextSibling();
1052 aSibling->GetViewManager()->RemoveChild(aSibling);
1053 aSibling->SetNextSibling(removedViews);
1054 removedViews = aSibling;
1055 aSibling = next;
1056 }
1057 return removedViews;
1058}
1059
1060/* static */
1061void nsSubDocumentFrame::InsertViewsInReverseOrder(nsView* aSibling,
1062 nsView* aParent) {
1063 MOZ_ASSERT(aParent, "null view")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aParent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aParent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aParent" " (" "null view"
")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsSubDocumentFrame.cpp"
, 1063); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aParent" ") ("
"null view" ")"); do { *((volatile int*)__null) = 1063; __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
1064 MOZ_ASSERT(!aParent->GetFirstChild(), "inserting into non-empty list")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aParent->GetFirstChild())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aParent->GetFirstChild()
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!aParent->GetFirstChild()" " (" "inserting into non-empty list"
")", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsSubDocumentFrame.cpp"
, 1064); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aParent->GetFirstChild()"
") (" "inserting into non-empty list" ")"); do { *((volatile
int*)__null) = 1064; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1065
1066 nsViewManager* vm = aParent->GetViewManager();
1067 while (aSibling) {
1068 nsView* next = aSibling->GetNextSibling();
1069 aSibling->SetNextSibling(nullptr);
1070 // true means 'after' in document order which is 'before' in view order,
1071 // so this call prepends the child, thus reversing the siblings as we go.
1072 vm->InsertChild(aParent, aSibling, nullptr, true);
1073 aSibling = next;
1074 }
1075}
1076
1077nsresult nsSubDocumentFrame::BeginSwapDocShells(nsIFrame* aOther) {
1078 if (!aOther || !aOther->IsSubDocumentFrame()) {
1079 return NS_ERROR_NOT_IMPLEMENTED;
1080 }
1081
1082 nsSubDocumentFrame* other = static_cast<nsSubDocumentFrame*>(aOther);
1083 if (!mFrameLoader || !mDidCreateDoc || mCallingShow || !other->mFrameLoader ||
1084 !other->mDidCreateDoc) {
1085 return NS_ERROR_NOT_IMPLEMENTED;
1086 }
1087
1088 ClearDisplayItems();
1089 other->ClearDisplayItems();
1090
1091 if (mInnerView && other->mInnerView) {
1092 nsView* ourSubdocViews = mInnerView->GetFirstChild();
1093 nsView* ourRemovedViews = ::BeginSwapDocShellsForViews(ourSubdocViews);
1094 nsView* otherSubdocViews = other->mInnerView->GetFirstChild();
1095 nsView* otherRemovedViews = ::BeginSwapDocShellsForViews(otherSubdocViews);
1096
1097 InsertViewsInReverseOrder(ourRemovedViews, other->mInnerView);
1098 InsertViewsInReverseOrder(otherRemovedViews, mInnerView);
1099 }
1100 mFrameLoader.swap(other->mFrameLoader);
1101 return NS_OK;
1102}
1103
1104static CallState EndSwapDocShellsForDocument(Document& aDocument) {
1105 // Our docshell and view trees have been updated for the new hierarchy.
1106 // Now also update all nsDeviceContext::mWidget to that of the
1107 // container view in the new hierarchy.
1108 if (nsCOMPtr<nsIDocShell> ds = aDocument.GetDocShell()) {
1109 nsCOMPtr<nsIDocumentViewer> viewer;
1110 ds->GetDocViewer(getter_AddRefs(viewer));
1111 while (viewer) {
1112 RefPtr<nsPresContext> pc = viewer->GetPresContext();
1113 if (pc && pc->GetPresShell()) {
1114 pc->GetPresShell()->SetNeverPainting(ds->IsInvisible());
1115 }
1116 nsDeviceContext* dc = pc ? pc->DeviceContext() : nullptr;
1117 if (dc) {
1118 nsView* v = viewer->FindContainerView();
1119 dc->Init(v ? v->GetNearestWidget(nullptr) : nullptr);
1120 }
1121 viewer = viewer->GetPreviousViewer();
1122 }
1123 }
1124
1125 aDocument.EnumerateSubDocuments(EndSwapDocShellsForDocument);
1126 return CallState::Continue;
1127}
1128
1129/* static */
1130void nsSubDocumentFrame::EndSwapDocShellsForViews(nsView* aSibling) {
1131 for (; aSibling; aSibling = aSibling->GetNextSibling()) {
1132 if (Document* doc = ::GetDocumentFromView(aSibling)) {
1133 ::EndSwapDocShellsForDocument(*doc);
1134 }
1135 nsIFrame* frame = aSibling->GetFrame();
1136 if (frame) {
1137 nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrameInProcess(frame);
1138 if (parent->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
1139 nsIFrame::AddInPopupStateBitToDescendants(frame);
1140 } else {
1141 nsIFrame::RemoveInPopupStateBitFromDescendants(frame);
1142 }
1143 if (frame->HasInvalidFrameInSubtree()) {
1144 while (parent &&
1145 !parent->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT |
1146 NS_FRAME_IS_NONDISPLAY)) {
1147 parent->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT);
1148 parent = nsLayoutUtils::GetCrossDocParentFrameInProcess(parent);
1149 }
1150 }
1151 }
1152 }
1153}
1154
1155void nsSubDocumentFrame::EndSwapDocShells(nsIFrame* aOther) {
1156 nsSubDocumentFrame* other = static_cast<nsSubDocumentFrame*>(aOther);
1157 AutoWeakFrame weakThis(this);
1158 AutoWeakFrame weakOther(aOther);
1159
1160 if (mInnerView) {
1161 EndSwapDocShellsForViews(mInnerView->GetFirstChild());
1162 }
1163 if (other->mInnerView) {
1164 EndSwapDocShellsForViews(other->mInnerView->GetFirstChild());
1165 }
1166
1167 // Now make sure we reflow both frames, in case their contents
1168 // determine their size.
1169 // And repaint them, for good measure, in case there's nothing
1170 // interesting that happens during reflow.
1171 if (weakThis.IsAlive()) {
1172 PresShell()->FrameNeedsReflow(this, IntrinsicDirty::FrameAndAncestors,
1173 NS_FRAME_IS_DIRTY);
1174 InvalidateFrameSubtree();
1175 PropagateIsUnderHiddenEmbedderElement(
1176 PresShell()->IsUnderHiddenEmbedderElement() ||
1177 !StyleVisibility()->IsVisible());
1178 }
1179 if (weakOther.IsAlive()) {
1180 other->PresShell()->FrameNeedsReflow(
1181 other, IntrinsicDirty::FrameAndAncestors, NS_FRAME_IS_DIRTY);
1182 other->InvalidateFrameSubtree();
1183 other->PropagateIsUnderHiddenEmbedderElement(
1184 other->PresShell()->IsUnderHiddenEmbedderElement() ||
1185 !other->StyleVisibility()->IsVisible());
1186 }
1187}
1188
1189void nsSubDocumentFrame::ClearDisplayItems() {
1190 if (auto* builder = nsLayoutUtils::GetRetainedDisplayListBuilder(this)) {
1191 DL_LOGD("nsSubDocumentFrame::ClearDisplayItems() %p", this)do { const ::mozilla::LogModule* moz_real_module = GetLoggerByProcess
(); if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "nsSubDocumentFrame::ClearDisplayItems() %p"
, this); } } while (0)
;
1192 builder->ClearRetainedData();
1193 }
1194}
1195
1196nsView* nsSubDocumentFrame::EnsureInnerView() {
1197 if (mInnerView) {
1198 return mInnerView;
1199 }
1200
1201 // create, init, set the parent of the view
1202 nsView* outerView = GetView();
1203 NS_ASSERTION(outerView, "Must have an outer view already")do { if (!(outerView)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Must have an outer view already"
, "outerView", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsSubDocumentFrame.cpp"
, 1203); MOZ_PretendNoReturn(); } } while (0)
;
1204 nsRect viewBounds(0, 0, 0, 0); // size will be fixed during reflow
1205
1206 nsViewManager* viewMan = outerView->GetViewManager();
1207 nsView* innerView = viewMan->CreateView(viewBounds, outerView);
1208 if (!innerView) {
1209 NS_ERROR("Could not create inner view")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Could not create inner view"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsSubDocumentFrame.cpp"
, 1209); MOZ_PretendNoReturn(); } while (0)
;
1210 return nullptr;
1211 }
1212 mInnerView = innerView;
1213 viewMan->InsertChild(outerView, innerView, nullptr, true);
1214
1215 return mInnerView;
1216}
1217
1218nsPoint nsSubDocumentFrame::GetExtraOffset() const {
1219 MOZ_ASSERT(mInnerView)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mInnerView)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mInnerView))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("mInnerView", "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsSubDocumentFrame.cpp"
, 1219); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mInnerView"
")"); do { *((volatile int*)__null) = 1219; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1220 return mInnerView->GetPosition();
1221}
1222
1223void nsSubDocumentFrame::SubdocumentIntrinsicSizeOrRatioChanged() {
1224 const nsStylePosition* pos = StylePosition();
1225 bool dependsOnIntrinsics =
1226 !pos->mWidth.ConvertsToLength() || !pos->mHeight.ConvertsToLength();
1227
1228 if (dependsOnIntrinsics || pos->mObjectFit != StyleObjectFit::Fill) {
1229 auto dirtyHint = dependsOnIntrinsics
1230 ? IntrinsicDirty::FrameAncestorsAndDescendants
1231 : IntrinsicDirty::None;
1232 PresShell()->FrameNeedsReflow(this, dirtyHint, NS_FRAME_IS_DIRTY);
1233 InvalidateFrame();
1234 }
1235}
1236
1237// Return true iff |aManager| is a "temporary layer manager". They're
1238// used for small software rendering tasks, like drawWindow. That's
1239// currently implemented by a BasicLayerManager without a backing
1240// widget, and hence in non-retained mode.
1241nsDisplayRemote::nsDisplayRemote(nsDisplayListBuilder* aBuilder,
1242 nsSubDocumentFrame* aFrame)
1243 : nsPaintedDisplayItem(aBuilder, aFrame),
1244 mEventRegionsOverride(EventRegionsOverride::NoOverride) {
1245 const bool frameIsPointerEventsNone =
1246 aFrame->Style()->PointerEvents() == StylePointerEvents::None;
1247 if (aBuilder->IsInsidePointerEventsNoneDoc() || frameIsPointerEventsNone) {
1248 mEventRegionsOverride |= EventRegionsOverride::ForceEmptyHitRegion;
1249 }
1250 if (nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(
1251 aFrame->PresShell())) {
1252 mEventRegionsOverride |= EventRegionsOverride::ForceDispatchToContent;
1253 }
1254
1255 mPaintData = aFrame->GetRemotePaintData();
1256}
1257
1258namespace mozilla {
1259
1260void nsDisplayRemote::Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) {
1261 nsPresContext* pc = mFrame->PresContext();
1262 nsFrameLoader* fl = GetFrameLoader();
1263 if (pc->GetPrintSettings() && fl->IsRemoteFrame()) {
1264 // See the comment below in CreateWebRenderCommands() as for why doing this.
1265 fl->UpdatePositionAndSize(static_cast<nsSubDocumentFrame*>(mFrame));
1266 }
1267
1268 DrawTarget* target = aCtx->GetDrawTarget();
1269 if (!target->IsRecording() || mPaintData.mTabId == 0) {
1270 NS_WARNING("Remote iframe not rendered")NS_DebugBreak(NS_DEBUG_WARNING, "Remote iframe not rendered",
nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/layout/generic/nsSubDocumentFrame.cpp"
, 1270)
;
1271 return;
1272 }
1273
1274 // Rendering the inner document will apply a scale to account for its app
1275 // units per dev pixel ratio. We want to apply the inverse scaling using our
1276 // app units per dev pixel ratio, so that no actual scaling will be applied if
1277 // they match. For in-process rendering, nsSubDocumentFrame creates an
1278 // nsDisplayZoom item if the app units per dev pixel ratio changes.
1279 //
1280 // Similarly, rendering the inner document will scale up by the cross process
1281 // paint scale again, so we also need to account for that.
1282 const int32_t appUnitsPerDevPixel = pc->AppUnitsPerDevPixel();
1283
1284 gfxContextMatrixAutoSaveRestore saveMatrix(aCtx);
1285 gfxFloat targetAuPerDev =
1286 gfxFloat(AppUnitsPerCSSPixel()) / aCtx->GetCrossProcessPaintScale();
1287
1288 gfxFloat scale = targetAuPerDev / appUnitsPerDevPixel;
1289 aCtx->Multiply(gfxMatrix::Scaling(scale, scale));
1290
1291 Rect destRect =
1292 NSRectToSnappedRect(GetContentRect(), targetAuPerDev, *target);
1293 target->DrawDependentSurface(mPaintData.mTabId, destRect);
1294}
1295
1296bool nsDisplayRemote::CreateWebRenderCommands(
1297 mozilla::wr::DisplayListBuilder& aBuilder,
1298 mozilla::wr::IpcResourceUpdateQueue& aResources,
1299 const StackingContextHelper& aSc,
1300 mozilla::layers::RenderRootStateManager* aManager,
1301 nsDisplayListBuilder* aDisplayListBuilder) {
1302 if (!mPaintData.mLayersId.IsValid()) {
1303 return true;
1304 }
1305
1306 nsPresContext* pc = mFrame->PresContext();
1307 nsFrameLoader* fl = GetFrameLoader();
1308
1309 auto* subDocFrame = static_cast<nsSubDocumentFrame*>(mFrame);
1310 nsRect destRect = subDocFrame->GetDestRect();
1311 if (RefPtr<RemoteBrowser> remoteBrowser = fl->GetRemoteBrowser()) {
1312 if (pc->GetPrintSettings()) {
1313 // HACK(emilio): Usually we update sizing/positioning from
1314 // ReflowFinished(). Print documents have no incremental reflow at all
1315 // though, so we can't rely on it firing after a frame becomes remote.
1316 // Thus, if we're painting a remote frame, update its sizing and position
1317 // now.
1318 //
1319 // UpdatePositionAndSize() can cause havoc for non-remote frames but
1320 // luckily we don't care about those, so this is fine.
1321 fl->UpdatePositionAndSize(subDocFrame);
1322 }
1323
1324 // Adjust mItemVisibleRect, which is relative to the reference frame, to be
1325 // relative to this frame.
1326 const nsRect buildingRect = GetBuildingRect() - ToReferenceFrame();
1327 Maybe<nsRect> visibleRect =
1328 buildingRect.EdgeInclusiveIntersection(destRect);
1329 if (visibleRect) {
1330 *visibleRect -= destRect.TopLeft();
1331 }
1332
1333 // Generate an effects update notifying the browser it is visible
1334 MatrixScales scale = aSc.GetInheritedScale();
1335
1336 ParentLayerToScreenScale2D transformToAncestorScale =
1337 ParentLayerToParentLayerScale(
1338 pc->GetPresShell() ? pc->GetPresShell()->GetCumulativeResolution()
1339 : 1.f) *
1340 nsLayoutUtils::GetTransformToAncestorScaleCrossProcessForFrameMetrics(
1341 mFrame);
1342
1343 aDisplayListBuilder->AddEffectUpdate(
1344 remoteBrowser, EffectsInfo::VisibleWithinRect(
1345 visibleRect, scale, transformToAncestorScale));
1346
1347 // Create a WebRenderRemoteData to notify the RemoteBrowser when it is no
1348 // longer visible
1349 RefPtr<WebRenderRemoteData> userData =
1350 aManager->CommandBuilder()
1351 .CreateOrRecycleWebRenderUserData<WebRenderRemoteData>(this,
1352 nullptr);
1353 userData->SetRemoteBrowser(remoteBrowser);
1354 }
1355
1356 nscoord auPerDevPixel = pc->AppUnitsPerDevPixel();
1357 nsPoint layerOffset =
1358 aDisplayListBuilder->ToReferenceFrame(mFrame) + destRect.TopLeft();
1359 mOffset = LayoutDevicePoint::FromAppUnits(layerOffset, auPerDevPixel);
1360
1361 destRect.MoveTo(0, 0);
1362 auto rect = LayoutDeviceRect::FromAppUnits(destRect, auPerDevPixel);
1363 rect += mOffset;
1364
1365 aBuilder.PushIFrame(rect, !BackfaceIsHidden(),
1366 mozilla::wr::AsPipelineId(mPaintData.mLayersId),
1367 /*ignoreMissingPipelines*/ true);
1368
1369 return true;
1370}
1371
1372bool nsDisplayRemote::UpdateScrollData(
1373 mozilla::layers::WebRenderScrollData* aData,
1374 mozilla::layers::WebRenderLayerScrollData* aLayerData) {
1375 if (!mPaintData.mLayersId.IsValid()) {
1376 return true;
1377 }
1378
1379 if (aLayerData) {
1380 aLayerData->SetReferentId(mPaintData.mLayersId);
1381
1382 auto size = static_cast<nsSubDocumentFrame*>(mFrame)->GetSubdocumentSize();
1383 Matrix4x4 m = Matrix4x4::Translation(mOffset.x, mOffset.y, 0.0);
1384 aLayerData->SetTransform(m);
1385 aLayerData->SetEventRegionsOverride(mEventRegionsOverride);
1386 aLayerData->SetRemoteDocumentSize(LayerIntSize(size.width, size.height));
1387 }
1388 return true;
1389}
1390
1391nsFrameLoader* nsDisplayRemote::GetFrameLoader() const {
1392 return static_cast<nsSubDocumentFrame*>(mFrame)->FrameLoader();
1393}
1394
1395} // namespace mozilla