Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : /*
7 : * rendering object for replaced elements that contain a document, such
8 : * as <frame>, <iframe>, and some <object>s
9 : */
10 :
11 : #include "nsSubDocumentFrame.h"
12 :
13 : #include "gfxPrefs.h"
14 :
15 : #include "mozilla/layout/RenderFrameParent.h"
16 :
17 : #include "nsCOMPtr.h"
18 : #include "nsGenericHTMLElement.h"
19 : #include "nsGenericHTMLFrameElement.h"
20 : #include "nsAttrValueInlines.h"
21 : #include "nsIDocShell.h"
22 : #include "nsIContentViewer.h"
23 : #include "nsPresContext.h"
24 : #include "nsIPresShell.h"
25 : #include "nsIDocument.h"
26 : #include "nsView.h"
27 : #include "nsViewManager.h"
28 : #include "nsGkAtoms.h"
29 : #include "nsStyleConsts.h"
30 : #include "nsFrameSetFrame.h"
31 : #include "nsIDOMHTMLFrameElement.h"
32 : #include "nsIScrollable.h"
33 : #include "nsNameSpaceManager.h"
34 : #include "nsDisplayList.h"
35 : #include "nsIScrollableFrame.h"
36 : #include "nsIObjectLoadingContent.h"
37 : #include "nsLayoutUtils.h"
38 : #include "FrameLayerBuilder.h"
39 : #include "nsPluginFrame.h"
40 : #include "nsContentUtils.h"
41 : #include "nsIPermissionManager.h"
42 : #include "nsServiceManagerUtils.h"
43 : #include "nsIDOMMutationEvent.h"
44 : #include "mozilla/Preferences.h"
45 :
46 : using namespace mozilla;
47 : using mozilla::layout::RenderFrameParent;
48 :
49 : static bool sShowPreviousPage = true;
50 :
51 : static nsIDocument*
52 1 : GetDocumentFromView(nsView* aView)
53 : {
54 1 : NS_PRECONDITION(aView, "");
55 :
56 1 : nsViewManager* vm = aView->GetViewManager();
57 1 : nsIPresShell* ps = vm ? vm->GetPresShell() : nullptr;
58 1 : return ps ? ps->GetDocument() : nullptr;
59 : }
60 :
61 3 : nsSubDocumentFrame::nsSubDocumentFrame(nsStyleContext* aContext)
62 : : nsAtomicContainerFrame(aContext, kClassID)
63 : , mOuterView(nullptr)
64 : , mInnerView(nullptr)
65 : , mIsInline(false)
66 : , mPostedReflowCallback(false)
67 : , mDidCreateDoc(false)
68 3 : , mCallingShow(false)
69 : {
70 3 : }
71 :
72 : #ifdef ACCESSIBILITY
73 : a11y::AccType
74 0 : nsSubDocumentFrame::AccessibleType()
75 : {
76 0 : return a11y::eOuterDocType;
77 : }
78 : #endif
79 :
80 26 : NS_QUERYFRAME_HEAD(nsSubDocumentFrame)
81 4 : NS_QUERYFRAME_ENTRY(nsSubDocumentFrame)
82 22 : NS_QUERYFRAME_TAIL_INHERITING(nsAtomicContainerFrame)
83 :
84 9 : class AsyncFrameInit : public Runnable
85 : {
86 : public:
87 3 : explicit AsyncFrameInit(nsIFrame* aFrame)
88 3 : : mozilla::Runnable("AsyncFrameInit")
89 3 : , mFrame(aFrame)
90 : {
91 3 : }
92 3 : NS_IMETHOD Run() override
93 : {
94 6 : AUTO_PROFILER_LABEL("AsyncFrameInit::Run", OTHER);
95 3 : if (mFrame.IsAlive()) {
96 3 : static_cast<nsSubDocumentFrame*>(mFrame.GetFrame())->ShowViewer();
97 : }
98 6 : return NS_OK;
99 : }
100 : private:
101 : WeakFrame mFrame;
102 : };
103 :
104 : static void
105 : InsertViewsInReverseOrder(nsView* aSibling, nsView* aParent);
106 :
107 : static void
108 : EndSwapDocShellsForViews(nsView* aView);
109 :
110 : void
111 3 : nsSubDocumentFrame::Init(nsIContent* aContent,
112 : nsContainerFrame* aParent,
113 : nsIFrame* aPrevInFlow)
114 : {
115 : // determine if we are a <frame> or <iframe>
116 6 : nsCOMPtr<nsIDOMHTMLFrameElement> frameElem = do_QueryInterface(aContent);
117 3 : mIsInline = frameElem ? false : true;
118 :
119 : static bool addedShowPreviousPage = false;
120 3 : if (!addedShowPreviousPage) {
121 : // If layout.show_previous_page is true then during loading of a new page we
122 : // will draw the previous page if the new page has painting suppressed.
123 1 : Preferences::AddBoolVarCache(&sShowPreviousPage, "layout.show_previous_page", true);
124 1 : addedShowPreviousPage = true;
125 : }
126 :
127 3 : nsAtomicContainerFrame::Init(aContent, aParent, aPrevInFlow);
128 :
129 : // CreateView() creates this frame's view, stored in mOuterView. It needs to
130 : // be created first since it's the parent of the inner view, stored in
131 : // mInnerView.
132 3 : CreateView();
133 3 : EnsureInnerView();
134 :
135 : // Set the primary frame now so that nsDocumentViewer::FindContainerView
136 : // called from within EndSwapDocShellsForViews below can find it if needed.
137 3 : aContent->SetPrimaryFrame(this);
138 :
139 : // If we have a detached subdoc's root view on our frame loader, re-insert
140 : // it into the view tree. This happens when we've been reframed, and
141 : // ensures the presentation persists across reframes. If the frame element
142 : // has changed documents however, we blow away the presentation.
143 6 : RefPtr<nsFrameLoader> frameloader = FrameLoader();
144 3 : if (frameloader) {
145 6 : nsCOMPtr<nsIDocument> oldContainerDoc;
146 : nsIFrame* detachedFrame =
147 3 : frameloader->GetDetachedSubdocFrame(getter_AddRefs(oldContainerDoc));
148 3 : frameloader->SetDetachedSubdocFrame(nullptr, nullptr);
149 3 : MOZ_ASSERT(oldContainerDoc || !detachedFrame);
150 3 : if (oldContainerDoc) {
151 : nsView* detachedView =
152 0 : detachedFrame ? detachedFrame->GetView() : nullptr;
153 0 : if (detachedView && oldContainerDoc == aContent->OwnerDoc()) {
154 : // Restore stashed presentation.
155 0 : ::InsertViewsInReverseOrder(detachedView, mInnerView);
156 0 : ::EndSwapDocShellsForViews(mInnerView->GetFirstChild());
157 : } else {
158 : // Presentation is for a different document, don't restore it.
159 0 : frameloader->Hide();
160 : }
161 : }
162 : }
163 :
164 3 : nsContentUtils::AddScriptRunner(new AsyncFrameInit(this));
165 3 : }
166 :
167 : void
168 3 : nsSubDocumentFrame::ShowViewer()
169 : {
170 3 : if (mCallingShow) {
171 0 : return;
172 : }
173 :
174 3 : if (!PresContext()->IsDynamic()) {
175 : // We let the printing code take care of loading the document; just
176 : // create the inner view for it to use.
177 0 : (void) EnsureInnerView();
178 : } else {
179 6 : RefPtr<nsFrameLoader> frameloader = FrameLoader();
180 3 : if (frameloader) {
181 3 : CSSIntSize margin = GetMarginAttributes();
182 6 : AutoWeakFrame weakThis(this);
183 3 : mCallingShow = true;
184 : const nsAttrValue* attrValue =
185 3 : GetContent()->AsElement()->GetParsedAttr(nsGkAtoms::scrolling);
186 : int32_t scrolling =
187 3 : nsGenericHTMLFrameElement::MapScrollingAttribute(attrValue);
188 : bool didCreateDoc =
189 3 : frameloader->Show(margin.width, margin.height,
190 3 : scrolling, scrolling, this);
191 3 : if (!weakThis.IsAlive()) {
192 0 : return;
193 : }
194 3 : mCallingShow = false;
195 3 : mDidCreateDoc = didCreateDoc;
196 : }
197 : }
198 : }
199 :
200 : nsIFrame*
201 2 : nsSubDocumentFrame::GetSubdocumentRootFrame()
202 : {
203 2 : if (!mInnerView)
204 0 : return nullptr;
205 2 : nsView* subdocView = mInnerView->GetFirstChild();
206 2 : return subdocView ? subdocView->GetFrame() : nullptr;
207 : }
208 :
209 : nsIPresShell*
210 0 : nsSubDocumentFrame::GetSubdocumentPresShellForPainting(uint32_t aFlags)
211 : {
212 0 : if (!mInnerView)
213 0 : return nullptr;
214 :
215 0 : nsView* subdocView = mInnerView->GetFirstChild();
216 0 : if (!subdocView)
217 0 : return nullptr;
218 :
219 0 : nsIPresShell* presShell = nullptr;
220 :
221 0 : nsIFrame* subdocRootFrame = subdocView->GetFrame();
222 0 : if (subdocRootFrame) {
223 0 : presShell = subdocRootFrame->PresContext()->PresShell();
224 : }
225 :
226 : // If painting is suppressed in the presshell, we try to look for a better
227 : // presshell to use.
228 0 : if (!presShell || (presShell->IsPaintingSuppressed() &&
229 0 : !(aFlags & IGNORE_PAINT_SUPPRESSION))) {
230 : // During page transition mInnerView will sometimes have two children, the
231 : // first being the new page that may not have any frame, and the second
232 : // being the old page that will probably have a frame.
233 0 : nsView* nextView = subdocView->GetNextSibling();
234 0 : nsIFrame* frame = nullptr;
235 0 : if (nextView) {
236 0 : frame = nextView->GetFrame();
237 : }
238 0 : if (frame) {
239 0 : nsIPresShell* ps = frame->PresContext()->PresShell();
240 0 : if (!presShell || (ps && !ps->IsPaintingSuppressed() && sShowPreviousPage)) {
241 0 : subdocView = nextView;
242 0 : subdocRootFrame = frame;
243 0 : presShell = ps;
244 : }
245 : }
246 0 : if (!presShell) {
247 : // If we don't have a frame we use this roundabout way to get the pres shell.
248 0 : if (!mFrameLoader)
249 0 : return nullptr;
250 0 : nsCOMPtr<nsIDocShell> docShell;
251 0 : mFrameLoader->GetDocShell(getter_AddRefs(docShell));
252 0 : if (!docShell)
253 0 : return nullptr;
254 0 : presShell = docShell->GetPresShell();
255 : }
256 : }
257 :
258 0 : return presShell;
259 : }
260 :
261 :
262 :
263 :
264 : ScreenIntSize
265 6 : nsSubDocumentFrame::GetSubdocumentSize()
266 : {
267 6 : if (GetStateBits() & NS_FRAME_FIRST_REFLOW) {
268 6 : RefPtr<nsFrameLoader> frameloader = FrameLoader();
269 3 : if (frameloader) {
270 6 : nsCOMPtr<nsIDocument> oldContainerDoc;
271 : nsIFrame* detachedFrame =
272 3 : frameloader->GetDetachedSubdocFrame(getter_AddRefs(oldContainerDoc));
273 3 : nsView* view = detachedFrame ? detachedFrame->GetView() : nullptr;
274 3 : if (view) {
275 0 : nsSize size = view->GetBounds().Size();
276 0 : nsPresContext* presContext = detachedFrame->PresContext();
277 0 : return ScreenIntSize(presContext->AppUnitsToDevPixels(size.width),
278 0 : presContext->AppUnitsToDevPixels(size.height));
279 : }
280 : }
281 : // Pick some default size for now. Using 10x10 because that's what the
282 : // code used to do.
283 3 : return ScreenIntSize(10, 10);
284 : } else {
285 3 : nsSize docSizeAppUnits;
286 3 : nsPresContext* presContext = PresContext();
287 : nsCOMPtr<nsIDOMHTMLFrameElement> frameElem =
288 6 : do_QueryInterface(GetContent());
289 3 : if (frameElem) {
290 0 : docSizeAppUnits = GetSize();
291 : } else {
292 3 : docSizeAppUnits = GetContentRect().Size();
293 : }
294 : // Adjust subdocument size, according to 'object-fit' and the
295 : // subdocument's intrinsic size and ratio.
296 3 : nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
297 3 : if (subDocRoot) {
298 : nsRect destRect =
299 0 : nsLayoutUtils::ComputeObjectDestRect(nsRect(nsPoint(), docSizeAppUnits),
300 0 : subDocRoot->GetIntrinsicSize(),
301 0 : subDocRoot->GetIntrinsicRatio(),
302 0 : StylePosition());
303 0 : docSizeAppUnits = destRect.Size();
304 : }
305 :
306 6 : return ScreenIntSize(presContext->AppUnitsToDevPixels(docSizeAppUnits.width),
307 3 : presContext->AppUnitsToDevPixels(docSizeAppUnits.height));
308 : }
309 : }
310 :
311 : static void
312 33 : WrapBackgroundColorInOwnLayer(nsDisplayListBuilder* aBuilder,
313 : nsIFrame* aFrame,
314 : nsDisplayList* aList)
315 : {
316 66 : nsDisplayList tempItems;
317 : nsDisplayItem* item;
318 51 : while ((item = aList->RemoveBottom()) != nullptr) {
319 9 : if (item->GetType() == nsDisplayItem::TYPE_BACKGROUND_COLOR) {
320 18 : nsDisplayList tmpList;
321 9 : tmpList.AppendToTop(item);
322 9 : item = new (aBuilder) nsDisplayOwnLayer(aBuilder, aFrame, &tmpList, aBuilder->CurrentActiveScrolledRoot());
323 : }
324 9 : tempItems.AppendToTop(item);
325 : }
326 33 : aList->AppendToTop(&tempItems);
327 33 : }
328 :
329 : void
330 33 : nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
331 : const nsRect& aDirtyRect,
332 : const nsDisplayListSet& aLists)
333 : {
334 33 : if (!IsVisibleForPainting(aBuilder))
335 33 : return;
336 :
337 33 : nsFrameLoader* frameLoader = FrameLoader();
338 33 : RenderFrameParent* rfp = nullptr;
339 33 : if (frameLoader) {
340 33 : rfp = frameLoader->GetCurrentRenderFrame();
341 : }
342 :
343 : // If we are pointer-events:none then we don't need to HitTest background
344 : bool pointerEventsNone =
345 33 : StyleUserInterface()->mPointerEvents == NS_STYLE_POINTER_EVENTS_NONE;
346 33 : if (!aBuilder->IsForEventDelivery() || !pointerEventsNone) {
347 66 : nsDisplayListCollection decorations;
348 33 : DisplayBorderBackgroundOutline(aBuilder, decorations);
349 33 : if (rfp) {
350 : // Wrap background colors of <iframe>s with remote subdocuments in their
351 : // own layer so we generate a ColorLayer. This is helpful for optimizing
352 : // compositing; we can skip compositing the ColorLayer when the
353 : // remote content is opaque.
354 33 : WrapBackgroundColorInOwnLayer(aBuilder, this, decorations.BorderBackground());
355 : }
356 33 : decorations.MoveTo(aLists);
357 : }
358 :
359 33 : if (aBuilder->IsForEventDelivery() && pointerEventsNone) {
360 0 : return;
361 : }
362 :
363 : // If we're passing pointer events to children then we have to descend into
364 : // subdocuments no matter what, to determine which parts are transparent for
365 : // hit-testing or event regions.
366 33 : bool needToDescend = aBuilder->GetDescendIntoSubdocuments();
367 33 : if (!mInnerView || !needToDescend) {
368 0 : return;
369 : }
370 :
371 33 : if (rfp) {
372 33 : rfp->BuildDisplayList(aBuilder, this, aDirtyRect, aLists);
373 33 : return;
374 : }
375 :
376 : nsCOMPtr<nsIPresShell> presShell =
377 : GetSubdocumentPresShellForPainting(
378 0 : aBuilder->IsIgnoringPaintSuppression() ? IGNORE_PAINT_SUPPRESSION : 0);
379 :
380 0 : if (!presShell) {
381 0 : return;
382 : }
383 :
384 0 : nsIFrame* subdocRootFrame = presShell->GetRootFrame();
385 :
386 0 : nsPresContext* presContext = presShell->GetPresContext();
387 :
388 0 : int32_t parentAPD = PresContext()->AppUnitsPerDevPixel();
389 0 : int32_t subdocAPD = presContext->AppUnitsPerDevPixel();
390 :
391 0 : nsRect dirty;
392 0 : bool haveDisplayPort = false;
393 0 : bool ignoreViewportScrolling = false;
394 0 : nsIFrame* savedIgnoreScrollFrame = nullptr;
395 0 : if (subdocRootFrame) {
396 : // get the dirty rect relative to the root frame of the subdoc
397 0 : dirty = aDirtyRect + GetOffsetToCrossDoc(subdocRootFrame);
398 : // and convert into the appunits of the subdoc
399 0 : dirty = dirty.ScaleToOtherAppUnitsRoundOut(parentAPD, subdocAPD);
400 :
401 0 : if (nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame()) {
402 0 : nsIScrollableFrame* rootScrollableFrame = presShell->GetRootScrollFrameAsScrollable();
403 0 : MOZ_ASSERT(rootScrollableFrame);
404 : // Use a copy, so the dirty rect doesn't get modified to the display port.
405 0 : nsRect copy = dirty;
406 : haveDisplayPort = rootScrollableFrame->DecideScrollableLayer(aBuilder,
407 0 : ©, /* aAllowCreateDisplayPort = */ true);
408 :
409 0 : if (!gfxPrefs::LayoutUseContainersForRootFrames() ||
410 0 : !aBuilder->IsPaintingToWindow()) {
411 0 : haveDisplayPort = false;
412 : }
413 :
414 0 : ignoreViewportScrolling = presShell->IgnoringViewportScrolling();
415 0 : if (ignoreViewportScrolling) {
416 0 : savedIgnoreScrollFrame = aBuilder->GetIgnoreScrollFrame();
417 0 : aBuilder->SetIgnoreScrollFrame(rootScrollFrame);
418 : }
419 : }
420 :
421 0 : aBuilder->EnterPresShell(subdocRootFrame, pointerEventsNone);
422 : } else {
423 0 : dirty = aDirtyRect;
424 : }
425 :
426 0 : DisplayListClipState::AutoSaveRestore clipState(aBuilder);
427 0 : if (ShouldClipSubdocument()) {
428 0 : clipState.ClipContainingBlockDescendantsToContentBox(aBuilder, this);
429 : }
430 :
431 0 : nsIScrollableFrame *sf = presShell->GetRootScrollFrameAsScrollable();
432 0 : bool constructResolutionItem = subdocRootFrame &&
433 0 : (presShell->GetResolution() != 1.0);
434 0 : bool constructZoomItem = subdocRootFrame && parentAPD != subdocAPD;
435 0 : bool needsOwnLayer = false;
436 0 : if (constructResolutionItem ||
437 0 : constructZoomItem ||
438 0 : haveDisplayPort ||
439 0 : presContext->IsRootContentDocument() ||
440 0 : (sf && sf->IsScrollingActive(aBuilder)))
441 : {
442 0 : needsOwnLayer = true;
443 : }
444 0 : if (!needsOwnLayer && aBuilder->IsBuildingLayerEventRegions() &&
445 0 : nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(presShell))
446 : {
447 0 : needsOwnLayer = true;
448 : }
449 :
450 0 : nsDisplayList childItems;
451 :
452 : {
453 0 : DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder);
454 0 : if (needsOwnLayer) {
455 : // Clear current clip. There's no point in propagating it down, since
456 : // the layer we will construct will be clipped by the current clip.
457 : // In fact for nsDisplayZoom propagating it down would be incorrect since
458 : // nsDisplayZoom changes the meaning of appunits.
459 0 : nestedClipState.Clear();
460 : }
461 :
462 0 : if (subdocRootFrame) {
463 0 : nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
464 : nsDisplayListBuilder::AutoCurrentScrollParentIdSetter idSetter(
465 : aBuilder,
466 0 : ignoreViewportScrolling && rootScrollFrame && rootScrollFrame->GetContent()
467 0 : ? nsLayoutUtils::FindOrCreateIDFor(rootScrollFrame->GetContent())
468 0 : : aBuilder->GetCurrentScrollParentId());
469 :
470 0 : aBuilder->SetAncestorHasApzAwareEventHandler(false);
471 : subdocRootFrame->
472 0 : BuildDisplayListForStackingContext(aBuilder, dirty, &childItems);
473 : }
474 :
475 0 : if (!aBuilder->IsForEventDelivery()) {
476 : // If we are going to use a displayzoom below then any items we put under
477 : // it need to have underlying frames from the subdocument. So we need to
478 : // calculate the bounds based on which frame will be the underlying frame
479 : // for the canvas background color item.
480 0 : nsRect bounds = GetContentRectRelativeToSelf() +
481 0 : aBuilder->ToReferenceFrame(this);
482 0 : if (subdocRootFrame) {
483 0 : bounds = bounds.ScaleToOtherAppUnitsRoundOut(parentAPD, subdocAPD);
484 : }
485 :
486 : // If we are in print preview/page layout we want to paint the grey
487 : // background behind the page, not the canvas color. The canvas color gets
488 : // painted on the page itself.
489 0 : if (nsLayoutUtils::NeedsPrintPreviewBackground(presContext)) {
490 0 : presShell->AddPrintPreviewBackgroundItem(
491 : *aBuilder, childItems, subdocRootFrame ? subdocRootFrame : this,
492 0 : bounds);
493 : } else {
494 : // Invoke AutoBuildingDisplayList to ensure that the correct dirty rect
495 : // is used to compute the visible rect if AddCanvasBackgroundColorItem
496 : // creates a display item.
497 0 : nsIFrame* frame = subdocRootFrame ? subdocRootFrame : this;
498 : nsDisplayListBuilder::AutoBuildingDisplayList
499 0 : building(aBuilder, frame, dirty, true);
500 : // Add the canvas background color to the bottom of the list. This
501 : // happens after we've built the list so that AddCanvasBackgroundColorItem
502 : // can monkey with the contents if necessary.
503 0 : uint32_t flags = nsIPresShell::FORCE_DRAW | nsIPresShell::ADD_FOR_SUBDOC;
504 0 : presShell->AddCanvasBackgroundColorItem(
505 0 : *aBuilder, childItems, frame, bounds, NS_RGBA(0,0,0,0), flags);
506 : }
507 : }
508 : }
509 :
510 0 : if (subdocRootFrame) {
511 0 : aBuilder->LeavePresShell(subdocRootFrame, &childItems);
512 :
513 0 : if (ignoreViewportScrolling) {
514 0 : aBuilder->SetIgnoreScrollFrame(savedIgnoreScrollFrame);
515 : }
516 : }
517 :
518 : // Generate a resolution and/or zoom item if needed. If one or both of those is
519 : // created, we don't need to create a separate nsDisplaySubDocument.
520 :
521 0 : uint32_t flags = nsDisplayOwnLayer::GENERATE_SUBDOC_INVALIDATIONS;
522 : // If ignoreViewportScrolling is true then the top most layer we create here
523 : // is going to become the scrollable layer for the root scroll frame, so we
524 : // want to add nsDisplayOwnLayer::GENERATE_SCROLLABLE_LAYER to whatever layer
525 : // becomes the topmost. We do this below.
526 0 : if (constructZoomItem) {
527 0 : uint32_t zoomFlags = flags;
528 0 : if (ignoreViewportScrolling && !constructResolutionItem) {
529 0 : zoomFlags |= nsDisplayOwnLayer::GENERATE_SCROLLABLE_LAYER;
530 : }
531 : nsDisplayZoom* zoomItem =
532 : new (aBuilder) nsDisplayZoom(aBuilder, subdocRootFrame, &childItems,
533 0 : subdocAPD, parentAPD, zoomFlags);
534 0 : childItems.AppendToTop(zoomItem);
535 0 : needsOwnLayer = false;
536 : }
537 : // Wrap the zoom item in the resolution item if we have both because we want the
538 : // resolution scale applied on top of the app units per dev pixel conversion.
539 0 : if (ignoreViewportScrolling) {
540 0 : flags |= nsDisplayOwnLayer::GENERATE_SCROLLABLE_LAYER;
541 : }
542 0 : if (constructResolutionItem) {
543 : nsDisplayResolution* resolutionItem =
544 : new (aBuilder) nsDisplayResolution(aBuilder, subdocRootFrame, &childItems,
545 0 : flags);
546 0 : childItems.AppendToTop(resolutionItem);
547 0 : needsOwnLayer = false;
548 : }
549 0 : if (needsOwnLayer) {
550 : // We always want top level content documents to be in their own layer.
551 : nsDisplaySubDocument* layerItem = new (aBuilder) nsDisplaySubDocument(
552 : aBuilder, subdocRootFrame ? subdocRootFrame : this,
553 0 : &childItems, flags);
554 0 : childItems.AppendToTop(layerItem);
555 : }
556 :
557 : // If we're using containers for root frames, then the earlier call
558 : // to AddCanvasBackgroundColorItem won't have been able to add an
559 : // unscrolled color item for overscroll. Try again now that we're
560 : // outside the scrolled ContainerLayer.
561 0 : if (!aBuilder->IsForEventDelivery() &&
562 0 : gfxPrefs::LayoutUseContainersForRootFrames() &&
563 0 : !nsLayoutUtils::NeedsPrintPreviewBackground(presContext)) {
564 0 : nsRect bounds = GetContentRectRelativeToSelf() +
565 0 : aBuilder->ToReferenceFrame(this);
566 :
567 : // Invoke AutoBuildingDisplayList to ensure that the correct dirty rect
568 : // is used to compute the visible rect if AddCanvasBackgroundColorItem
569 : // creates a display item.
570 : nsDisplayListBuilder::AutoBuildingDisplayList
571 0 : building(aBuilder, this, dirty, true);
572 : // Add the canvas background color to the bottom of the list. This
573 : // happens after we've built the list so that AddCanvasBackgroundColorItem
574 : // can monkey with the contents if necessary.
575 0 : uint32_t flags = nsIPresShell::FORCE_DRAW | nsIPresShell::APPEND_UNSCROLLED_ONLY;
576 0 : presShell->AddCanvasBackgroundColorItem(
577 0 : *aBuilder, childItems, this, bounds, NS_RGBA(0,0,0,0), flags);
578 : }
579 :
580 0 : if (aBuilder->IsForFrameVisibility()) {
581 : // We don't add the childItems to the return list as we're dealing with them here.
582 0 : presShell->RebuildApproximateFrameVisibilityDisplayList(childItems);
583 0 : childItems.DeleteAll();
584 : } else {
585 0 : aLists.Content()->AppendToTop(&childItems);
586 : }
587 : }
588 :
589 : nscoord
590 3 : nsSubDocumentFrame::GetIntrinsicISize()
591 : {
592 3 : if (!IsInline()) {
593 0 : return 0; // HTML <frame> has no useful intrinsic isize
594 : }
595 :
596 3 : if (mContent->IsXULElement()) {
597 3 : return 0; // XUL <iframe> and <browser> have no useful intrinsic isize
598 : }
599 :
600 0 : NS_ASSERTION(ObtainIntrinsicSizeFrame() == nullptr,
601 : "Intrinsic isize should come from the embedded document.");
602 :
603 : // We must be an HTML <iframe>. Default to size of 300px x 150px, for IE
604 : // compat (and per CSS2.1 draft).
605 0 : WritingMode wm = GetWritingMode();
606 0 : return nsPresContext::CSSPixelsToAppUnits(wm.IsVertical() ? 150 : 300);
607 : }
608 :
609 : nscoord
610 1 : nsSubDocumentFrame::GetIntrinsicBSize()
611 : {
612 : // <frame> processing does not use this routine, only <iframe>
613 1 : NS_ASSERTION(IsInline(), "Shouldn't have been called");
614 :
615 1 : if (mContent->IsXULElement()) {
616 1 : return 0;
617 : }
618 :
619 0 : NS_ASSERTION(ObtainIntrinsicSizeFrame() == nullptr,
620 : "Intrinsic bsize should come from the embedded document.");
621 :
622 : // Use size of 300px x 150px, for compatibility with IE, and per CSS2.1 draft.
623 0 : WritingMode wm = GetWritingMode();
624 0 : return nsPresContext::CSSPixelsToAppUnits(wm.IsVertical() ? 300 : 150);
625 : }
626 :
627 : #ifdef DEBUG_FRAME_DUMP
628 : void
629 0 : nsSubDocumentFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
630 : {
631 0 : nsCString str;
632 0 : ListGeneric(str, aPrefix, aFlags);
633 0 : fprintf_stderr(out, "%s\n", str.get());
634 :
635 0 : if (aFlags & TRAVERSE_SUBDOCUMENT_FRAMES) {
636 0 : nsSubDocumentFrame* f = const_cast<nsSubDocumentFrame*>(this);
637 0 : nsIFrame* subdocRootFrame = f->GetSubdocumentRootFrame();
638 0 : if (subdocRootFrame) {
639 0 : nsCString pfx(aPrefix);
640 0 : pfx += " ";
641 0 : subdocRootFrame->List(out, pfx.get(), aFlags);
642 : }
643 : }
644 0 : }
645 :
646 0 : nsresult nsSubDocumentFrame::GetFrameName(nsAString& aResult) const
647 : {
648 0 : return MakeFrameName(NS_LITERAL_STRING("FrameOuter"), aResult);
649 : }
650 : #endif
651 :
652 : /* virtual */ nscoord
653 1 : nsSubDocumentFrame::GetMinISize(gfxContext *aRenderingContext)
654 : {
655 : nscoord result;
656 2 : DISPLAY_MIN_WIDTH(this, result);
657 :
658 1 : nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
659 1 : if (subDocRoot) {
660 0 : result = subDocRoot->GetMinISize(aRenderingContext);
661 : } else {
662 1 : result = GetIntrinsicISize();
663 : }
664 :
665 2 : return result;
666 : }
667 :
668 : /* virtual */ nscoord
669 1 : nsSubDocumentFrame::GetPrefISize(gfxContext *aRenderingContext)
670 : {
671 : nscoord result;
672 2 : DISPLAY_PREF_WIDTH(this, result);
673 :
674 1 : nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
675 1 : if (subDocRoot) {
676 0 : result = subDocRoot->GetPrefISize(aRenderingContext);
677 : } else {
678 1 : result = GetIntrinsicISize();
679 : }
680 :
681 2 : return result;
682 : }
683 :
684 : /* virtual */ IntrinsicSize
685 0 : nsSubDocumentFrame::GetIntrinsicSize()
686 : {
687 0 : nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
688 0 : if (subDocRoot) {
689 0 : return subDocRoot->GetIntrinsicSize();
690 : }
691 0 : return nsAtomicContainerFrame::GetIntrinsicSize();
692 : }
693 :
694 : /* virtual */ nsSize
695 1 : nsSubDocumentFrame::GetIntrinsicRatio()
696 : {
697 1 : nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
698 1 : if (subDocRoot) {
699 0 : return subDocRoot->GetIntrinsicRatio();
700 : }
701 1 : return nsAtomicContainerFrame::GetIntrinsicRatio();
702 : }
703 :
704 : /* virtual */
705 : LogicalSize
706 1 : nsSubDocumentFrame::ComputeAutoSize(gfxContext* aRenderingContext,
707 : WritingMode aWM,
708 : const LogicalSize& aCBSize,
709 : nscoord aAvailableISize,
710 : const LogicalSize& aMargin,
711 : const LogicalSize& aBorder,
712 : const LogicalSize& aPadding,
713 : ComputeSizeFlags aFlags)
714 : {
715 1 : if (!IsInline()) {
716 : return nsFrame::ComputeAutoSize(aRenderingContext, aWM, aCBSize,
717 : aAvailableISize, aMargin, aBorder,
718 0 : aPadding, aFlags);
719 : }
720 :
721 1 : const WritingMode wm = GetWritingMode();
722 1 : LogicalSize result(wm, GetIntrinsicISize(), GetIntrinsicBSize());
723 1 : return result.ConvertTo(aWM, wm);
724 : }
725 :
726 :
727 : /* virtual */
728 : LogicalSize
729 1 : nsSubDocumentFrame::ComputeSize(gfxContext* aRenderingContext,
730 : WritingMode aWM,
731 : const LogicalSize& aCBSize,
732 : nscoord aAvailableISize,
733 : const LogicalSize& aMargin,
734 : const LogicalSize& aBorder,
735 : const LogicalSize& aPadding,
736 : ComputeSizeFlags aFlags)
737 : {
738 1 : nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
739 1 : if (subDocRoot) {
740 : return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM,
741 0 : subDocRoot->GetIntrinsicSize(),
742 0 : subDocRoot->GetIntrinsicRatio(),
743 : aCBSize, aMargin, aBorder,
744 0 : aPadding, aFlags);
745 : }
746 : return nsAtomicContainerFrame::ComputeSize(aRenderingContext, aWM,
747 : aCBSize, aAvailableISize,
748 : aMargin, aBorder, aPadding,
749 1 : aFlags);
750 : }
751 :
752 : void
753 4 : nsSubDocumentFrame::Reflow(nsPresContext* aPresContext,
754 : ReflowOutput& aDesiredSize,
755 : const ReflowInput& aReflowInput,
756 : nsReflowStatus& aStatus)
757 : {
758 4 : MarkInReflow();
759 4 : DO_GLOBAL_REFLOW_COUNT("nsSubDocumentFrame");
760 8 : DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
761 4 : NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
762 : ("enter nsSubDocumentFrame::Reflow: maxSize=%d,%d",
763 : aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight()));
764 :
765 4 : NS_ASSERTION(aReflowInput.ComputedWidth() != NS_UNCONSTRAINEDSIZE,
766 : "Shouldn't have unconstrained stuff here "
767 : "thanks to the rules of reflow");
768 4 : NS_ASSERTION(NS_INTRINSICSIZE != aReflowInput.ComputedHeight(),
769 : "Shouldn't have unconstrained stuff here "
770 : "thanks to ComputeAutoSize");
771 :
772 4 : aStatus.Reset();
773 :
774 4 : NS_ASSERTION(mContent->GetPrimaryFrame() == this,
775 : "Shouldn't happen");
776 :
777 : // XUL <iframe> or <browser>, or HTML <iframe>, <object> or <embed>
778 4 : aDesiredSize.SetSize(aReflowInput.GetWritingMode(),
779 4 : aReflowInput.ComputedSizeWithBorderPadding());
780 :
781 : // "offset" is the offset of our content area from our frame's
782 : // top-left corner.
783 4 : nsPoint offset = nsPoint(aReflowInput.ComputedPhysicalBorderPadding().left,
784 8 : aReflowInput.ComputedPhysicalBorderPadding().top);
785 :
786 4 : if (mInnerView) {
787 4 : const nsMargin& bp = aReflowInput.ComputedPhysicalBorderPadding();
788 4 : nsSize innerSize(aDesiredSize.Width() - bp.LeftRight(),
789 8 : aDesiredSize.Height() - bp.TopBottom());
790 :
791 : // Size & position the view according to 'object-fit' & 'object-position'.
792 4 : nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
793 8 : IntrinsicSize intrinsSize;
794 4 : nsSize intrinsRatio;
795 4 : if (subDocRoot) {
796 0 : intrinsSize = subDocRoot->GetIntrinsicSize();
797 0 : intrinsRatio = subDocRoot->GetIntrinsicRatio();
798 : }
799 : nsRect destRect =
800 8 : nsLayoutUtils::ComputeObjectDestRect(nsRect(offset, innerSize),
801 : intrinsSize, intrinsRatio,
802 12 : StylePosition());
803 :
804 4 : nsViewManager* vm = mInnerView->GetViewManager();
805 4 : vm->MoveViewTo(mInnerView, destRect.x, destRect.y);
806 4 : vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), destRect.Size()), true);
807 : }
808 :
809 4 : aDesiredSize.SetOverflowAreasToDesiredBounds();
810 4 : if (!ShouldClipSubdocument()) {
811 0 : nsIFrame* subdocRootFrame = GetSubdocumentRootFrame();
812 0 : if (subdocRootFrame) {
813 0 : aDesiredSize.mOverflowAreas.UnionWith(subdocRootFrame->GetOverflowAreas() + offset);
814 : }
815 : }
816 :
817 4 : FinishAndStoreOverflow(&aDesiredSize);
818 :
819 4 : if (!aPresContext->IsPaginated() && !mPostedReflowCallback) {
820 3 : PresContext()->PresShell()->PostReflowCallback(this);
821 3 : mPostedReflowCallback = true;
822 : }
823 :
824 4 : NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
825 : ("exit nsSubDocumentFrame::Reflow: size=%d,%d status=%s",
826 : aDesiredSize.Width(), aDesiredSize.Height(), ToString(aStatus).c_str()));
827 :
828 4 : NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
829 4 : }
830 :
831 : bool
832 3 : nsSubDocumentFrame::ReflowFinished()
833 : {
834 3 : if (mFrameLoader) {
835 6 : AutoWeakFrame weakFrame(this);
836 :
837 3 : mFrameLoader->UpdatePositionAndSize(this);
838 :
839 3 : if (weakFrame.IsAlive()) {
840 : // Make sure that we can post a reflow callback in the future.
841 3 : mPostedReflowCallback = false;
842 : }
843 : } else {
844 0 : mPostedReflowCallback = false;
845 : }
846 3 : return false;
847 : }
848 :
849 : void
850 0 : nsSubDocumentFrame::ReflowCallbackCanceled()
851 : {
852 0 : mPostedReflowCallback = false;
853 0 : }
854 :
855 : nsresult
856 1 : nsSubDocumentFrame::AttributeChanged(int32_t aNameSpaceID,
857 : nsIAtom* aAttribute,
858 : int32_t aModType)
859 : {
860 1 : if (aNameSpaceID != kNameSpaceID_None) {
861 0 : return NS_OK;
862 : }
863 :
864 : // If the noResize attribute changes, dis/allow frame to be resized
865 1 : if (aAttribute == nsGkAtoms::noresize) {
866 : // Note that we're not doing content type checks, but that's ok -- if
867 : // they'd fail we will just end up with a null framesetFrame.
868 0 : if (mContent->GetParent()->IsHTMLElement(nsGkAtoms::frameset)) {
869 0 : nsIFrame* parentFrame = GetParent();
870 :
871 0 : if (parentFrame) {
872 : // There is no interface for nsHTMLFramesetFrame so QI'ing to
873 : // concrete class, yay!
874 0 : nsHTMLFramesetFrame* framesetFrame = do_QueryFrame(parentFrame);
875 0 : if (framesetFrame) {
876 0 : framesetFrame->RecalculateBorderResize();
877 : }
878 : }
879 : }
880 : }
881 1 : else if (aAttribute == nsGkAtoms::showresizer) {
882 0 : nsIFrame* rootFrame = GetSubdocumentRootFrame();
883 0 : if (rootFrame) {
884 0 : rootFrame->PresContext()->PresShell()->
885 0 : FrameNeedsReflow(rootFrame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
886 : }
887 : }
888 2 : else if (aAttribute == nsGkAtoms::marginwidth ||
889 1 : aAttribute == nsGkAtoms::marginheight) {
890 :
891 : // Retrieve the attributes
892 0 : CSSIntSize margins = GetMarginAttributes();
893 :
894 : // Notify the frameloader
895 0 : RefPtr<nsFrameLoader> frameloader = FrameLoader();
896 0 : if (frameloader)
897 0 : frameloader->MarginsChanged(margins.width, margins.height);
898 : }
899 :
900 1 : return NS_OK;
901 : }
902 :
903 : nsIFrame*
904 3 : NS_NewSubDocumentFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
905 : {
906 3 : return new (aPresShell) nsSubDocumentFrame(aContext);
907 : }
908 :
909 3 : NS_IMPL_FRAMEARENA_HELPERS(nsSubDocumentFrame)
910 :
911 0 : class nsHideViewer : public Runnable {
912 : public:
913 0 : nsHideViewer(nsIContent* aFrameElement,
914 : nsFrameLoader* aFrameLoader,
915 : nsIPresShell* aPresShell,
916 : bool aHideViewerIfFrameless)
917 0 : : mozilla::Runnable("nsHideViewer")
918 : , mFrameElement(aFrameElement)
919 : , mFrameLoader(aFrameLoader)
920 : , mPresShell(aPresShell)
921 0 : , mHideViewerIfFrameless(aHideViewerIfFrameless)
922 : {
923 0 : NS_ASSERTION(mFrameElement, "Must have a frame element");
924 0 : NS_ASSERTION(mFrameLoader, "Must have a frame loader");
925 0 : NS_ASSERTION(mPresShell, "Must have a presshell");
926 0 : }
927 :
928 0 : NS_IMETHOD Run() override
929 : {
930 : // Flush frames, to ensure any pending display:none changes are made.
931 : // Note it can be unsafe to flush if we've destroyed the presentation
932 : // for some other reason, like if we're shutting down.
933 0 : if (!mPresShell->IsDestroying()) {
934 0 : mPresShell->FlushPendingNotifications(FlushType::Frames);
935 : }
936 :
937 : // Either the frame has been constructed by now, or it never will be,
938 : // either way we want to clear the stashed views.
939 0 : mFrameLoader->SetDetachedSubdocFrame(nullptr, nullptr);
940 :
941 0 : nsSubDocumentFrame* frame = do_QueryFrame(mFrameElement->GetPrimaryFrame());
942 0 : if ((!frame && mHideViewerIfFrameless) ||
943 0 : mPresShell->IsDestroying()) {
944 : // Either the frame element has no nsIFrame or the presshell is being
945 : // destroyed. Hide the nsFrameLoader, which destroys the presentation.
946 0 : mFrameLoader->Hide();
947 : }
948 0 : return NS_OK;
949 : }
950 : private:
951 : nsCOMPtr<nsIContent> mFrameElement;
952 : RefPtr<nsFrameLoader> mFrameLoader;
953 : nsCOMPtr<nsIPresShell> mPresShell;
954 : bool mHideViewerIfFrameless;
955 : };
956 :
957 : static nsView*
958 : BeginSwapDocShellsForViews(nsView* aSibling);
959 :
960 : void
961 2 : nsSubDocumentFrame::DestroyFrom(nsIFrame* aDestructRoot)
962 : {
963 2 : if (mPostedReflowCallback) {
964 0 : PresContext()->PresShell()->CancelReflowCallback(this);
965 0 : mPostedReflowCallback = false;
966 : }
967 :
968 : // Detach the subdocument's views and stash them in the frame loader.
969 : // We can then reattach them if we're being reframed (for example if
970 : // the frame has been made position:fixed).
971 4 : RefPtr<nsFrameLoader> frameloader = FrameLoader();
972 2 : if (frameloader) {
973 2 : nsView* detachedViews = ::BeginSwapDocShellsForViews(mInnerView->GetFirstChild());
974 :
975 2 : if (detachedViews && detachedViews->GetFrame()) {
976 0 : MOZ_ASSERT(mContent->OwnerDoc());
977 0 : frameloader->SetDetachedSubdocFrame(
978 0 : detachedViews->GetFrame(), mContent->OwnerDoc());
979 :
980 : // We call nsFrameLoader::HideViewer() in a script runner so that we can
981 : // safely determine whether the frame is being reframed or destroyed.
982 : nsContentUtils::AddScriptRunner(
983 : new nsHideViewer(mContent,
984 : frameloader,
985 0 : PresContext()->PresShell(),
986 0 : (mDidCreateDoc || mCallingShow)));
987 : } else {
988 2 : frameloader->SetDetachedSubdocFrame(nullptr, nullptr);
989 2 : if (mDidCreateDoc || mCallingShow) {
990 2 : frameloader->Hide();
991 : }
992 : }
993 : }
994 :
995 2 : nsAtomicContainerFrame::DestroyFrom(aDestructRoot);
996 2 : }
997 :
998 : CSSIntSize
999 3 : nsSubDocumentFrame::GetMarginAttributes()
1000 : {
1001 3 : CSSIntSize result(-1, -1);
1002 3 : nsGenericHTMLElement *content = nsGenericHTMLElement::FromContent(mContent);
1003 3 : if (content) {
1004 0 : const nsAttrValue* attr = content->GetParsedAttr(nsGkAtoms::marginwidth);
1005 0 : if (attr && attr->Type() == nsAttrValue::eInteger)
1006 0 : result.width = attr->GetIntegerValue();
1007 0 : attr = content->GetParsedAttr(nsGkAtoms::marginheight);
1008 0 : if (attr && attr->Type() == nsAttrValue::eInteger)
1009 0 : result.height = attr->GetIntegerValue();
1010 : }
1011 3 : return result;
1012 : }
1013 :
1014 : nsFrameLoader*
1015 50 : nsSubDocumentFrame::FrameLoader()
1016 : {
1017 50 : nsIContent* content = GetContent();
1018 50 : if (!content)
1019 0 : return nullptr;
1020 :
1021 50 : if (!mFrameLoader) {
1022 6 : nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(content);
1023 3 : if (loaderOwner) {
1024 3 : mFrameLoader = loaderOwner->GetFrameLoader();
1025 : }
1026 : }
1027 50 : return mFrameLoader;
1028 : }
1029 :
1030 : // XXX this should be called ObtainDocShell or something like that,
1031 : // to indicate that it could have side effects
1032 : nsresult
1033 2 : nsSubDocumentFrame::GetDocShell(nsIDocShell **aDocShell)
1034 : {
1035 2 : *aDocShell = nullptr;
1036 :
1037 2 : NS_ENSURE_STATE(FrameLoader());
1038 2 : return mFrameLoader->GetDocShell(aDocShell);
1039 : }
1040 :
1041 : static void
1042 0 : DestroyDisplayItemDataForFrames(nsIFrame* aFrame)
1043 : {
1044 0 : FrameLayerBuilder::DestroyDisplayItemDataFor(aFrame);
1045 :
1046 0 : nsIFrame::ChildListIterator lists(aFrame);
1047 0 : for (; !lists.IsDone(); lists.Next()) {
1048 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
1049 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
1050 0 : DestroyDisplayItemDataForFrames(childFrames.get());
1051 : }
1052 : }
1053 0 : }
1054 :
1055 : static bool
1056 1 : BeginSwapDocShellsForDocument(nsIDocument* aDocument, void*)
1057 : {
1058 1 : NS_PRECONDITION(aDocument, "");
1059 :
1060 1 : nsIPresShell* shell = aDocument->GetShell();
1061 1 : if (shell) {
1062 : // Disable painting while the views are detached, see bug 946929.
1063 1 : shell->SetNeverPainting(true);
1064 :
1065 1 : nsIFrame* rootFrame = shell->GetRootFrame();
1066 1 : if (rootFrame) {
1067 0 : ::DestroyDisplayItemDataForFrames(rootFrame);
1068 : }
1069 : }
1070 : aDocument->EnumerateActivityObservers(
1071 1 : nsPluginFrame::BeginSwapDocShells, nullptr);
1072 1 : aDocument->EnumerateSubDocuments(BeginSwapDocShellsForDocument, nullptr);
1073 1 : return true;
1074 : }
1075 :
1076 : static nsView*
1077 2 : BeginSwapDocShellsForViews(nsView* aSibling)
1078 : {
1079 : // Collect the removed sibling views in reverse order in 'removedViews'.
1080 2 : nsView* removedViews = nullptr;
1081 4 : while (aSibling) {
1082 1 : nsIDocument* doc = ::GetDocumentFromView(aSibling);
1083 1 : if (doc) {
1084 1 : ::BeginSwapDocShellsForDocument(doc, nullptr);
1085 : }
1086 1 : nsView* next = aSibling->GetNextSibling();
1087 1 : aSibling->GetViewManager()->RemoveChild(aSibling);
1088 1 : aSibling->SetNextSibling(removedViews);
1089 1 : removedViews = aSibling;
1090 1 : aSibling = next;
1091 : }
1092 2 : return removedViews;
1093 : }
1094 :
1095 : static void
1096 0 : InsertViewsInReverseOrder(nsView* aSibling, nsView* aParent)
1097 : {
1098 0 : NS_PRECONDITION(aParent, "");
1099 0 : NS_PRECONDITION(!aParent->GetFirstChild(), "inserting into non-empty list");
1100 :
1101 0 : nsViewManager* vm = aParent->GetViewManager();
1102 0 : while (aSibling) {
1103 0 : nsView* next = aSibling->GetNextSibling();
1104 0 : aSibling->SetNextSibling(nullptr);
1105 : // true means 'after' in document order which is 'before' in view order,
1106 : // so this call prepends the child, thus reversing the siblings as we go.
1107 0 : vm->InsertChild(aParent, aSibling, nullptr, true);
1108 0 : aSibling = next;
1109 : }
1110 0 : }
1111 :
1112 : nsresult
1113 0 : nsSubDocumentFrame::BeginSwapDocShells(nsIFrame* aOther)
1114 : {
1115 0 : if (!aOther || !aOther->IsSubDocumentFrame()) {
1116 0 : return NS_ERROR_NOT_IMPLEMENTED;
1117 : }
1118 :
1119 0 : nsSubDocumentFrame* other = static_cast<nsSubDocumentFrame*>(aOther);
1120 0 : if (!mFrameLoader || !mDidCreateDoc || mCallingShow ||
1121 0 : !other->mFrameLoader || !other->mDidCreateDoc) {
1122 0 : return NS_ERROR_NOT_IMPLEMENTED;
1123 : }
1124 :
1125 0 : if (mInnerView && other->mInnerView) {
1126 0 : nsView* ourSubdocViews = mInnerView->GetFirstChild();
1127 0 : nsView* ourRemovedViews = ::BeginSwapDocShellsForViews(ourSubdocViews);
1128 0 : nsView* otherSubdocViews = other->mInnerView->GetFirstChild();
1129 0 : nsView* otherRemovedViews = ::BeginSwapDocShellsForViews(otherSubdocViews);
1130 :
1131 0 : ::InsertViewsInReverseOrder(ourRemovedViews, other->mInnerView);
1132 0 : ::InsertViewsInReverseOrder(otherRemovedViews, mInnerView);
1133 : }
1134 0 : mFrameLoader.swap(other->mFrameLoader);
1135 0 : return NS_OK;
1136 : }
1137 :
1138 : static bool
1139 0 : EndSwapDocShellsForDocument(nsIDocument* aDocument, void*)
1140 : {
1141 0 : NS_PRECONDITION(aDocument, "");
1142 :
1143 : // Our docshell and view trees have been updated for the new hierarchy.
1144 : // Now also update all nsDeviceContext::mWidget to that of the
1145 : // container view in the new hierarchy.
1146 0 : nsCOMPtr<nsIDocShell> ds = aDocument->GetDocShell();
1147 0 : if (ds) {
1148 0 : nsCOMPtr<nsIContentViewer> cv;
1149 0 : ds->GetContentViewer(getter_AddRefs(cv));
1150 0 : while (cv) {
1151 0 : RefPtr<nsPresContext> pc;
1152 0 : cv->GetPresContext(getter_AddRefs(pc));
1153 0 : if (pc && pc->GetPresShell()) {
1154 0 : pc->GetPresShell()->SetNeverPainting(ds->IsInvisible());
1155 : }
1156 0 : nsDeviceContext* dc = pc ? pc->DeviceContext() : nullptr;
1157 0 : if (dc) {
1158 0 : nsView* v = cv->FindContainerView();
1159 0 : dc->Init(v ? v->GetNearestWidget(nullptr) : nullptr);
1160 : }
1161 0 : nsCOMPtr<nsIContentViewer> prev;
1162 0 : cv->GetPreviousViewer(getter_AddRefs(prev));
1163 0 : cv = prev;
1164 : }
1165 : }
1166 :
1167 : aDocument->EnumerateActivityObservers(
1168 0 : nsPluginFrame::EndSwapDocShells, nullptr);
1169 0 : aDocument->EnumerateSubDocuments(EndSwapDocShellsForDocument, nullptr);
1170 0 : return true;
1171 : }
1172 :
1173 : static void
1174 0 : EndSwapDocShellsForViews(nsView* aSibling)
1175 : {
1176 0 : for ( ; aSibling; aSibling = aSibling->GetNextSibling()) {
1177 0 : nsIDocument* doc = ::GetDocumentFromView(aSibling);
1178 0 : if (doc) {
1179 0 : ::EndSwapDocShellsForDocument(doc, nullptr);
1180 : }
1181 0 : nsIFrame *frame = aSibling->GetFrame();
1182 0 : if (frame) {
1183 0 : nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(frame);
1184 0 : if (parent->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
1185 0 : nsIFrame::AddInPopupStateBitToDescendants(frame);
1186 : } else {
1187 0 : nsIFrame::RemoveInPopupStateBitFromDescendants(frame);
1188 : }
1189 0 : if (frame->HasInvalidFrameInSubtree()) {
1190 0 : while (parent && !parent->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT | NS_FRAME_IS_NONDISPLAY)) {
1191 0 : parent->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT);
1192 0 : parent = nsLayoutUtils::GetCrossDocParentFrame(parent);
1193 : }
1194 : }
1195 : }
1196 : }
1197 0 : }
1198 :
1199 : void
1200 0 : nsSubDocumentFrame::EndSwapDocShells(nsIFrame* aOther)
1201 : {
1202 0 : nsSubDocumentFrame* other = static_cast<nsSubDocumentFrame*>(aOther);
1203 0 : AutoWeakFrame weakThis(this);
1204 0 : AutoWeakFrame weakOther(aOther);
1205 :
1206 0 : if (mInnerView) {
1207 0 : ::EndSwapDocShellsForViews(mInnerView->GetFirstChild());
1208 : }
1209 0 : if (other->mInnerView) {
1210 0 : ::EndSwapDocShellsForViews(other->mInnerView->GetFirstChild());
1211 : }
1212 :
1213 : // Now make sure we reflow both frames, in case their contents
1214 : // determine their size.
1215 : // And repaint them, for good measure, in case there's nothing
1216 : // interesting that happens during reflow.
1217 0 : if (weakThis.IsAlive()) {
1218 0 : PresContext()->PresShell()->
1219 0 : FrameNeedsReflow(this, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
1220 0 : InvalidateFrameSubtree();
1221 : }
1222 0 : if (weakOther.IsAlive()) {
1223 0 : other->PresContext()->PresShell()->
1224 0 : FrameNeedsReflow(other, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
1225 0 : other->InvalidateFrameSubtree();
1226 : }
1227 0 : }
1228 :
1229 : nsView*
1230 37 : nsSubDocumentFrame::EnsureInnerView()
1231 : {
1232 37 : if (mInnerView) {
1233 34 : return mInnerView;
1234 : }
1235 :
1236 : // create, init, set the parent of the view
1237 3 : nsView* outerView = GetView();
1238 3 : NS_ASSERTION(outerView, "Must have an outer view already");
1239 6 : nsRect viewBounds(0, 0, 0, 0); // size will be fixed during reflow
1240 :
1241 3 : nsViewManager* viewMan = outerView->GetViewManager();
1242 3 : nsView* innerView = viewMan->CreateView(viewBounds, outerView);
1243 3 : if (!innerView) {
1244 0 : NS_ERROR("Could not create inner view");
1245 0 : return nullptr;
1246 : }
1247 3 : mInnerView = innerView;
1248 3 : viewMan->InsertChild(outerView, innerView, nullptr, true);
1249 :
1250 3 : return mInnerView;
1251 : }
1252 :
1253 : nsIFrame*
1254 11 : nsSubDocumentFrame::ObtainIntrinsicSizeFrame()
1255 : {
1256 22 : nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(GetContent());
1257 11 : if (olc) {
1258 : // We are an HTML <object>, <embed> or <applet> (a replaced element).
1259 :
1260 : // Try to get an nsIFrame for our sub-document's document element
1261 0 : nsIFrame* subDocRoot = nullptr;
1262 :
1263 0 : nsCOMPtr<nsIDocShell> docShell;
1264 0 : GetDocShell(getter_AddRefs(docShell));
1265 0 : if (docShell) {
1266 0 : nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell();
1267 0 : if (presShell) {
1268 0 : nsIScrollableFrame* scrollable = presShell->GetRootScrollFrameAsScrollable();
1269 0 : if (scrollable) {
1270 0 : nsIFrame* scrolled = scrollable->GetScrolledFrame();
1271 0 : if (scrolled) {
1272 0 : subDocRoot = scrolled->PrincipalChildList().FirstChild();
1273 : }
1274 : }
1275 : }
1276 : }
1277 :
1278 0 : if (subDocRoot && subDocRoot->GetContent() &&
1279 0 : subDocRoot->GetContent()->NodeInfo()->Equals(nsGkAtoms::svg, kNameSpaceID_SVG)) {
1280 0 : return subDocRoot; // SVG documents have an intrinsic size
1281 : }
1282 : }
1283 11 : return nullptr;
1284 : }
|