Bug Summary

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