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/. */
7 * rendering object for replaced elements that contain a document, such
8 * as <frame>, <iframe>, and some <object>s
11 #include "nsSubDocumentFrame.h"
13 #include "mozilla/layout/RenderFrameParent.h"
16 #include "nsGenericHTMLElement.h"
17 #include "nsGenericHTMLFrameElement.h"
18 #include "nsAttrValueInlines.h"
19 #include "nsIDocShell.h"
20 #include "nsIContentViewer.h"
21 #include "nsPresContext.h"
22 #include "nsIPresShell.h"
23 #include "nsIDocument.h"
25 #include "nsViewManager.h"
26 #include "nsGkAtoms.h"
27 #include "nsStyleConsts.h"
28 #include "nsFrameSetFrame.h"
29 #include "nsIDOMHTMLFrameElement.h"
30 #include "nsIScrollable.h"
31 #include "nsNameSpaceManager.h"
32 #include "nsDisplayList.h"
33 #include "nsIScrollableFrame.h"
34 #include "nsIObjectLoadingContent.h"
35 #include "nsLayoutUtils.h"
36 #include "FrameLayerBuilder.h"
37 #include "nsObjectFrame.h"
38 #include "nsContentUtils.h"
39 #include "nsIPermissionManager.h"
40 #include "nsServiceManagerUtils.h"
42 using namespace mozilla
;
43 using mozilla::layout::RenderFrameParent
;
46 GetDocumentFromView(nsView
* aView
)
48 NS_PRECONDITION(aView
, "");
50 nsIFrame
* f
= aView
->GetFrame();
51 nsIPresShell
* ps
= f
? f
->PresContext()->PresShell() : nullptr;
52 return ps
? ps
->GetDocument() : nullptr;
55 nsSubDocumentFrame::nsSubDocumentFrame(nsStyleContext
* aContext
)
56 : nsLeafFrame(aContext
)
58 , mPostedReflowCallback(false)
59 , mDidCreateDoc(false)
66 nsSubDocumentFrame::AccessibleType()
68 return a11y::eOuterDocType
;
72 NS_QUERYFRAME_HEAD(nsSubDocumentFrame
)
73 NS_QUERYFRAME_ENTRY(nsSubDocumentFrame
)
74 NS_QUERYFRAME_TAIL_INHERITING(nsLeafFrame
)
76 class AsyncFrameInit
: public nsRunnable
79 explicit AsyncFrameInit(nsIFrame
* aFrame
) : mFrame(aFrame
) {}
82 if (mFrame
.IsAlive()) {
83 static_cast<nsSubDocumentFrame
*>(mFrame
.GetFrame())->ShowViewer();
92 InsertViewsInReverseOrder(nsView
* aSibling
, nsView
* aParent
);
95 EndSwapDocShellsForViews(nsView
* aView
);
98 nsSubDocumentFrame::Init(nsIContent
* aContent
,
99 nsContainerFrame
* aParent
,
100 nsIFrame
* aPrevInFlow
)
102 // determine if we are a <frame> or <iframe>
104 nsCOMPtr
<nsIDOMHTMLFrameElement
> frameElem
= do_QueryInterface(aContent
);
105 mIsInline
= frameElem
? false : true;
108 nsLeafFrame::Init(aContent
, aParent
, aPrevInFlow
);
110 // We are going to create an inner view. If we need a view for the
111 // OuterFrame but we wait for the normal view creation path in
112 // nsCSSFrameConstructor, then we will lose because the inner view's
113 // parent will already have been set to some outer view (e.g., the
114 // canvas) when it really needs to have this frame's view as its
115 // parent. So, create this frame's view right away, whether we
116 // really need it or not, and the inner view will get it as the
119 nsContainerFrame::CreateViewForFrame(this, true);
123 // Set the primary frame now so that nsDocumentViewer::FindContainerView
124 // called from within EndSwapDocShellsForViews below can find it if needed.
125 aContent
->SetPrimaryFrame(this);
127 // If we have a detached subdoc's root view on our frame loader, re-insert
128 // it into the view tree. This happens when we've been reframed, and
129 // ensures the presentation persists across reframes. If the frame element
130 // has changed documents however, we blow away the presentation.
131 nsRefPtr
<nsFrameLoader
> frameloader
= FrameLoader();
133 nsCOMPtr
<nsIDocument
> oldContainerDoc
;
134 nsView
* detachedViews
=
135 frameloader
->GetDetachedSubdocView(getter_AddRefs(oldContainerDoc
));
137 if (oldContainerDoc
== aContent
->OwnerDoc()) {
138 // Restore stashed presentation.
139 ::InsertViewsInReverseOrder(detachedViews
, mInnerView
);
140 ::EndSwapDocShellsForViews(mInnerView
->GetFirstChild());
142 // Presentation is for a different document, don't restore it.
146 frameloader
->SetDetachedSubdocView(nullptr, nullptr);
149 nsContentUtils::AddScriptRunner(new AsyncFrameInit(this));
153 nsSubDocumentFrame::ShowViewer()
159 if (!PresContext()->IsDynamic()) {
160 // We let the printing code take care of loading the document; just
161 // create the inner view for it to use.
162 (void) EnsureInnerView();
164 nsRefPtr
<nsFrameLoader
> frameloader
= FrameLoader();
166 nsIntSize margin
= GetMarginAttributes();
167 nsWeakFrame
weakThis(this);
169 const nsAttrValue
* attrValue
=
170 GetContent()->AsElement()->GetParsedAttr(nsGkAtoms::scrolling
);
172 nsGenericHTMLFrameElement::MapScrollingAttribute(attrValue
);
174 frameloader
->Show(margin
.width
, margin
.height
,
175 scrolling
, scrolling
, this);
176 if (!weakThis
.IsAlive()) {
179 mCallingShow
= false;
180 mDidCreateDoc
= didCreateDoc
;
186 nsSubDocumentFrame::GetSubdocumentRootFrame()
190 nsView
* subdocView
= mInnerView
->GetFirstChild();
191 return subdocView
? subdocView
->GetFrame() : nullptr;
195 nsSubDocumentFrame::GetSubdocumentPresShellForPainting(uint32_t aFlags
)
200 nsView
* subdocView
= mInnerView
->GetFirstChild();
204 nsIPresShell
* presShell
= nullptr;
206 nsIFrame
* subdocRootFrame
= subdocView
->GetFrame();
207 if (subdocRootFrame
) {
208 presShell
= subdocRootFrame
->PresContext()->PresShell();
211 // If painting is suppressed in the presshell, we try to look for a better
213 if (!presShell
|| (presShell
->IsPaintingSuppressed() &&
214 !(aFlags
& IGNORE_PAINT_SUPPRESSION
))) {
215 // During page transition mInnerView will sometimes have two children, the
216 // first being the new page that may not have any frame, and the second
217 // being the old page that will probably have a frame.
218 nsView
* nextView
= subdocView
->GetNextSibling();
219 nsIFrame
* frame
= nullptr;
221 frame
= nextView
->GetFrame();
224 nsIPresShell
* ps
= frame
->PresContext()->PresShell();
225 if (!presShell
|| (ps
&& !ps
->IsPaintingSuppressed())) {
226 subdocView
= nextView
;
227 subdocRootFrame
= frame
;
232 // If we don't have a frame we use this roundabout way to get the pres shell.
235 nsCOMPtr
<nsIDocShell
> docShell
;
236 mFrameLoader
->GetDocShell(getter_AddRefs(docShell
));
239 presShell
= docShell
->GetPresShell();
250 nsSubDocumentFrame::GetSubdocumentSize()
252 if (GetStateBits() & NS_FRAME_FIRST_REFLOW
) {
253 nsRefPtr
<nsFrameLoader
> frameloader
= FrameLoader();
255 nsCOMPtr
<nsIDocument
> oldContainerDoc
;
256 nsView
* detachedViews
=
257 frameloader
->GetDetachedSubdocView(getter_AddRefs(oldContainerDoc
));
259 nsSize size
= detachedViews
->GetBounds().Size();
260 nsPresContext
* presContext
= detachedViews
->GetFrame()->PresContext();
261 return nsIntSize(presContext
->AppUnitsToDevPixels(size
.width
),
262 presContext
->AppUnitsToDevPixels(size
.height
));
265 // Pick some default size for now. Using 10x10 because that's what the
267 return nsIntSize(10, 10);
269 nsSize docSizeAppUnits
;
270 nsPresContext
* presContext
= PresContext();
271 nsCOMPtr
<nsIDOMHTMLFrameElement
> frameElem
=
272 do_QueryInterface(GetContent());
274 docSizeAppUnits
= GetSize();
276 docSizeAppUnits
= GetContentRect().Size();
278 return nsIntSize(presContext
->AppUnitsToDevPixels(docSizeAppUnits
.width
),
279 presContext
->AppUnitsToDevPixels(docSizeAppUnits
.height
));
284 nsSubDocumentFrame::PassPointerEventsToChildren()
286 // Limit use of mozpasspointerevents to documents with embedded:apps/chrome
287 // permission, because this could be used by the parent document to discover
288 // which parts of the subdocument are transparent to events (if subdocument
289 // uses pointer-events:none on its root element, which is admittedly
291 if (mContent
->HasAttr(kNameSpaceID_None
, nsGkAtoms::mozpasspointerevents
)) {
292 if (PresContext()->IsChrome()) {
296 nsCOMPtr
<nsIPermissionManager
> permMgr
=
297 services::GetPermissionManager();
299 uint32_t permission
= nsIPermissionManager::DENY_ACTION
;
300 permMgr
->TestPermissionFromPrincipal(GetContent()->NodePrincipal(),
301 "embed-apps", &permission
);
303 return permission
== nsIPermissionManager::ALLOW_ACTION
;
311 WrapBackgroundColorInOwnLayer(nsDisplayListBuilder
* aBuilder
,
313 nsDisplayList
* aList
)
315 nsDisplayList tempItems
;
317 while ((item
= aList
->RemoveBottom()) != nullptr) {
318 if (item
->GetType() == nsDisplayItem::TYPE_BACKGROUND_COLOR
) {
319 nsDisplayList tmpList
;
320 tmpList
.AppendToTop(item
);
321 item
= new (aBuilder
) nsDisplayOwnLayer(aBuilder
, aFrame
, &tmpList
);
323 tempItems
.AppendToTop(item
);
325 aList
->AppendToTop(&tempItems
);
329 nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
330 const nsRect
& aDirtyRect
,
331 const nsDisplayListSet
& aLists
)
333 if (!IsVisibleForPainting(aBuilder
))
336 nsFrameLoader
* frameLoader
= FrameLoader();
337 RenderFrameParent
* rfp
= nullptr;
339 rfp
= frameLoader
->GetCurrentRemoteFrame();
342 // If we are pointer-events:none then we don't need to HitTest background
343 bool pointerEventsNone
= StyleVisibility()->mPointerEvents
== NS_STYLE_POINTER_EVENTS_NONE
;
344 if (!aBuilder
->IsForEventDelivery() || !pointerEventsNone
) {
345 nsDisplayListCollection decorations
;
346 DisplayBorderBackgroundOutline(aBuilder
, decorations
);
348 // Wrap background colors of <iframe>s with remote subdocuments in their
349 // own layer so we generate a ColorLayer. This is helpful for optimizing
350 // compositing; we can skip compositing the ColorLayer when the
351 // remote content is opaque.
352 WrapBackgroundColorInOwnLayer(aBuilder
, this, decorations
.BorderBackground());
354 decorations
.MoveTo(aLists
);
357 bool passPointerEventsToChildren
= false;
358 if (aBuilder
->IsForEventDelivery()) {
359 passPointerEventsToChildren
= PassPointerEventsToChildren();
360 // If mozpasspointerevents is set, then we should allow subdocument content
361 // to handle events even if we're pointer-events:none.
362 if (pointerEventsNone
&& !passPointerEventsToChildren
) {
367 // If we're passing pointer events to children then we have to descend into
368 // subdocuments no matter what, to determine which parts are transparent for
371 (!aBuilder
->GetDescendIntoSubdocuments() && !passPointerEventsToChildren
)) {
376 rfp
->BuildDisplayList(aBuilder
, this, aDirtyRect
, aLists
);
380 nsCOMPtr
<nsIPresShell
> presShell
=
381 GetSubdocumentPresShellForPainting(
382 aBuilder
->IsIgnoringPaintSuppression() ? IGNORE_PAINT_SUPPRESSION
: 0);
388 nsIFrame
* subdocRootFrame
= presShell
->GetRootFrame();
390 nsPresContext
* presContext
= presShell
->GetPresContext();
392 int32_t parentAPD
= PresContext()->AppUnitsPerDevPixel();
393 int32_t subdocAPD
= presContext
->AppUnitsPerDevPixel();
396 bool haveDisplayPort
= false;
397 bool ignoreViewportScrolling
= false;
398 nsIFrame
* savedIgnoreScrollFrame
= nullptr;
399 if (subdocRootFrame
) {
400 // get the dirty rect relative to the root frame of the subdoc
401 dirty
= aDirtyRect
+ GetOffsetToCrossDoc(subdocRootFrame
);
402 // and convert into the appunits of the subdoc
403 dirty
= dirty
.ConvertAppUnitsRoundOut(parentAPD
, subdocAPD
);
405 if (nsIFrame
* rootScrollFrame
= presShell
->GetRootScrollFrame()) {
406 // for root content documents we want the base to be the composition bounds
407 nsRect displayportBase
= presContext
->IsRootContentDocument() ?
408 nsRect(nsPoint(0,0), nsLayoutUtils::CalculateCompositionSizeForFrame(rootScrollFrame
)) :
409 dirty
.Intersect(nsRect(nsPoint(0,0), subdocRootFrame
->GetSize()));
411 if (aBuilder
->IsPaintingToWindow() &&
412 nsLayoutUtils::GetOrMaybeCreateDisplayPort(
413 *aBuilder
, rootScrollFrame
, displayportBase
, &displayPort
)) {
414 haveDisplayPort
= true;
418 ignoreViewportScrolling
= presShell
->IgnoringViewportScrolling();
419 if (ignoreViewportScrolling
) {
420 savedIgnoreScrollFrame
= aBuilder
->GetIgnoreScrollFrame();
421 aBuilder
->SetIgnoreScrollFrame(rootScrollFrame
);
423 if (aBuilder
->IsForImageVisibility()) {
424 // The ExpandRectToNearlyVisible that the root scroll frame would do gets short
425 // circuited due to us ignoring the root scroll frame, so we do it here.
426 nsIScrollableFrame
* rootScrollableFrame
= do_QueryFrame(rootScrollFrame
);
427 dirty
= rootScrollableFrame
->ExpandRectToNearlyVisible(dirty
);
432 aBuilder
->EnterPresShell(subdocRootFrame
, dirty
);
437 DisplayListClipState::AutoSaveRestore
clipState(aBuilder
);
438 if (ShouldClipSubdocument()) {
439 clipState
.ClipContainingBlockDescendantsToContentBox(aBuilder
, this);
442 nsIScrollableFrame
*sf
= presShell
->GetRootScrollFrameAsScrollable();
443 bool constructResolutionItem
= subdocRootFrame
&&
444 (presShell
->GetXResolution() != 1.0 || presShell
->GetYResolution() != 1.0);
445 bool constructZoomItem
= subdocRootFrame
&& parentAPD
!= subdocAPD
;
446 bool needsOwnLayer
= constructResolutionItem
|| constructZoomItem
||
448 presContext
->IsRootContentDocument() || (sf
&& sf
->IsScrollingActive());
450 nsDisplayList childItems
;
453 DisplayListClipState::AutoSaveRestore
nestedClipState(aBuilder
);
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 nestedClipState
.Clear();
462 if (subdocRootFrame
) {
463 nsIFrame
* rootScrollFrame
= presShell
->GetRootScrollFrame();
464 nsDisplayListBuilder::AutoCurrentScrollParentIdSetter
idSetter(
466 ignoreViewportScrolling
&& rootScrollFrame
&& rootScrollFrame
->GetContent()
467 ? nsLayoutUtils::FindOrCreateIDFor(rootScrollFrame
->GetContent())
468 : aBuilder
->GetCurrentScrollParentId());
470 aBuilder
->SetAncestorHasTouchEventHandler(false);
472 BuildDisplayListForStackingContext(aBuilder
, dirty
, &childItems
);
475 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 nsRect bounds
= GetContentRectRelativeToSelf() +
481 aBuilder
->ToReferenceFrame(this);
482 if (subdocRootFrame
) {
483 bounds
= bounds
.ConvertAppUnitsRoundOut(parentAPD
, subdocAPD
);
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 if (nsLayoutUtils::NeedsPrintPreviewBackground(presContext
)) {
490 presShell
->AddPrintPreviewBackgroundItem(
491 *aBuilder
, childItems
, subdocRootFrame
? subdocRootFrame
: this,
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 nsIFrame
* frame
= subdocRootFrame
? subdocRootFrame
: this;
498 nsDisplayListBuilder::AutoBuildingDisplayList
499 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 uint32_t flags
= nsIPresShell::FORCE_DRAW
;
504 presShell
->AddCanvasBackgroundColorItem(
505 *aBuilder
, childItems
, frame
, bounds
, NS_RGBA(0,0,0,0), flags
);
510 if (subdocRootFrame
) {
511 aBuilder
->LeavePresShell(subdocRootFrame
, dirty
);
513 if (ignoreViewportScrolling
) {
514 aBuilder
->SetIgnoreScrollFrame(savedIgnoreScrollFrame
);
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.
521 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 if (constructZoomItem
) {
527 uint32_t zoomFlags
= flags
;
528 if (ignoreViewportScrolling
&& !constructResolutionItem
) {
529 zoomFlags
|= nsDisplayOwnLayer::GENERATE_SCROLLABLE_LAYER
;
531 nsDisplayZoom
* zoomItem
=
532 new (aBuilder
) nsDisplayZoom(aBuilder
, subdocRootFrame
, &childItems
,
533 subdocAPD
, parentAPD
, zoomFlags
);
534 childItems
.AppendToTop(zoomItem
);
535 needsOwnLayer
= false;
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 if (ignoreViewportScrolling
) {
540 flags
|= nsDisplayOwnLayer::GENERATE_SCROLLABLE_LAYER
;
542 if (constructResolutionItem
) {
543 nsDisplayResolution
* resolutionItem
=
544 new (aBuilder
) nsDisplayResolution(aBuilder
, subdocRootFrame
, &childItems
,
546 childItems
.AppendToTop(resolutionItem
);
547 needsOwnLayer
= false;
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,
554 childItems
.AppendToTop(layerItem
);
557 if (aBuilder
->IsForImageVisibility()) {
558 // We don't add the childItems to the return list as we're dealing with them here.
559 presShell
->RebuildImageVisibilityDisplayList(childItems
);
560 childItems
.DeleteAll();
562 aLists
.Content()->AppendToTop(&childItems
);
567 nsSubDocumentFrame::GetIntrinsicISize()
570 return 0; // HTML <frame> has no useful intrinsic width
573 if (mContent
->IsXUL()) {
574 return 0; // XUL <iframe> and <browser> have no useful intrinsic width
577 NS_ASSERTION(ObtainIntrinsicSizeFrame() == nullptr,
578 "Intrinsic width should come from the embedded document.");
580 // We must be an HTML <iframe>. Default to a width of 300, for IE
581 // compat (and per CSS2.1 draft).
582 return nsPresContext::CSSPixelsToAppUnits(300);
586 nsSubDocumentFrame::GetIntrinsicBSize()
588 // <frame> processing does not use this routine, only <iframe>
589 NS_ASSERTION(IsInline(), "Shouldn't have been called");
591 if (mContent
->IsXUL()) {
595 NS_ASSERTION(ObtainIntrinsicSizeFrame() == nullptr,
596 "Intrinsic height should come from the embedded document.");
598 // Use 150px, for compatibility with IE, and per CSS2.1 draft.
599 return nsPresContext::CSSPixelsToAppUnits(150);
602 #ifdef DEBUG_FRAME_DUMP
604 nsSubDocumentFrame::List(FILE* out
, const char* aPrefix
, uint32_t aFlags
) const
607 ListGeneric(str
, aPrefix
, aFlags
);
608 fprintf_stderr(out
, "%s\n", str
.get());
610 if (aFlags
& TRAVERSE_SUBDOCUMENT_FRAMES
) {
611 nsSubDocumentFrame
* f
= const_cast<nsSubDocumentFrame
*>(this);
612 nsIFrame
* subdocRootFrame
= f
->GetSubdocumentRootFrame();
613 if (subdocRootFrame
) {
614 nsCString
pfx(aPrefix
);
616 subdocRootFrame
->List(out
, pfx
.get(), aFlags
);
621 nsresult
nsSubDocumentFrame::GetFrameName(nsAString
& aResult
) const
623 return MakeFrameName(NS_LITERAL_STRING("FrameOuter"), aResult
);
628 nsSubDocumentFrame::GetType() const
630 return nsGkAtoms::subDocumentFrame
;
633 /* virtual */ nscoord
634 nsSubDocumentFrame::GetMinISize(nsRenderingContext
*aRenderingContext
)
637 DISPLAY_MIN_WIDTH(this, result
);
639 nsIFrame
* subDocRoot
= ObtainIntrinsicSizeFrame();
641 result
= subDocRoot
->GetMinISize(aRenderingContext
);
643 result
= GetIntrinsicISize();
649 /* virtual */ nscoord
650 nsSubDocumentFrame::GetPrefISize(nsRenderingContext
*aRenderingContext
)
653 DISPLAY_PREF_WIDTH(this, result
);
655 nsIFrame
* subDocRoot
= ObtainIntrinsicSizeFrame();
657 result
= subDocRoot
->GetPrefISize(aRenderingContext
);
659 result
= GetIntrinsicISize();
665 /* virtual */ IntrinsicSize
666 nsSubDocumentFrame::GetIntrinsicSize()
668 nsIFrame
* subDocRoot
= ObtainIntrinsicSizeFrame();
670 return subDocRoot
->GetIntrinsicSize();
672 return nsLeafFrame::GetIntrinsicSize();
676 nsSubDocumentFrame::GetIntrinsicRatio()
678 nsIFrame
* subDocRoot
= ObtainIntrinsicSizeFrame();
680 return subDocRoot
->GetIntrinsicRatio();
682 return nsLeafFrame::GetIntrinsicRatio();
687 nsSubDocumentFrame::ComputeAutoSize(nsRenderingContext
*aRenderingContext
,
689 const LogicalSize
& aCBSize
,
690 nscoord aAvailableISize
,
691 const LogicalSize
& aMargin
,
692 const LogicalSize
& aBorder
,
693 const LogicalSize
& aPadding
,
697 return nsFrame::ComputeAutoSize(aRenderingContext
, aWM
, aCBSize
,
698 aAvailableISize
, aMargin
, aBorder
,
699 aPadding
, aShrinkWrap
);
702 return nsLeafFrame::ComputeAutoSize(aRenderingContext
, aWM
, aCBSize
,
703 aAvailableISize
, aMargin
, aBorder
,
704 aPadding
, aShrinkWrap
);
710 nsSubDocumentFrame::ComputeSize(nsRenderingContext
*aRenderingContext
,
712 const LogicalSize
& aCBSize
,
713 nscoord aAvailableISize
,
714 const LogicalSize
& aMargin
,
715 const LogicalSize
& aBorder
,
716 const LogicalSize
& aPadding
,
719 nsIFrame
* subDocRoot
= ObtainIntrinsicSizeFrame();
721 return nsLayoutUtils::ComputeSizeWithIntrinsicDimensions(aWM
,
722 aRenderingContext
, this,
723 subDocRoot
->GetIntrinsicSize(),
724 subDocRoot
->GetIntrinsicRatio(),
730 return nsLeafFrame::ComputeSize(aRenderingContext
, aWM
,
731 aCBSize
, aAvailableISize
,
732 aMargin
, aBorder
, aPadding
, aFlags
);
736 nsSubDocumentFrame::Reflow(nsPresContext
* aPresContext
,
737 nsHTMLReflowMetrics
& aDesiredSize
,
738 const nsHTMLReflowState
& aReflowState
,
739 nsReflowStatus
& aStatus
)
741 DO_GLOBAL_REFLOW_COUNT("nsSubDocumentFrame");
742 DISPLAY_REFLOW(aPresContext
, this, aReflowState
, aDesiredSize
, aStatus
);
743 // printf("OuterFrame::Reflow %X (%d,%d) \n", this, aReflowState.AvailableWidth(), aReflowState.AvailableHeight());
744 NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS
,
745 ("enter nsSubDocumentFrame::Reflow: maxSize=%d,%d",
746 aReflowState
.AvailableWidth(), aReflowState
.AvailableHeight()));
748 aStatus
= NS_FRAME_COMPLETE
;
750 NS_ASSERTION(mContent
->GetPrimaryFrame() == this,
753 // XUL <iframe> or <browser>, or HTML <iframe>, <object> or <embed>
754 nsLeafFrame::DoReflow(aPresContext
, aDesiredSize
, aReflowState
, aStatus
);
756 // "offset" is the offset of our content area from our frame's
758 nsPoint offset
= nsPoint(aReflowState
.ComputedPhysicalBorderPadding().left
,
759 aReflowState
.ComputedPhysicalBorderPadding().top
);
761 nsSize
innerSize(aDesiredSize
.Width(), aDesiredSize
.Height());
762 innerSize
.width
-= aReflowState
.ComputedPhysicalBorderPadding().LeftRight();
763 innerSize
.height
-= aReflowState
.ComputedPhysicalBorderPadding().TopBottom();
766 nsViewManager
* vm
= mInnerView
->GetViewManager();
767 vm
->MoveViewTo(mInnerView
, offset
.x
, offset
.y
);
768 vm
->ResizeView(mInnerView
, nsRect(nsPoint(0, 0), innerSize
), true);
771 aDesiredSize
.SetOverflowAreasToDesiredBounds();
772 if (!ShouldClipSubdocument()) {
773 nsIFrame
* subdocRootFrame
= GetSubdocumentRootFrame();
774 if (subdocRootFrame
) {
775 aDesiredSize
.mOverflowAreas
.UnionWith(subdocRootFrame
->GetOverflowAreas() + offset
);
779 FinishAndStoreOverflow(&aDesiredSize
);
781 if (!aPresContext
->IsPaginated() && !mPostedReflowCallback
) {
782 PresContext()->PresShell()->PostReflowCallback(this);
783 mPostedReflowCallback
= true;
786 // printf("OuterFrame::Reflow DONE %X (%d,%d)\n", this,
787 // aDesiredSize.Width(), aDesiredSize.Height());
789 NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS
,
790 ("exit nsSubDocumentFrame::Reflow: size=%d,%d status=%x",
791 aDesiredSize
.Width(), aDesiredSize
.Height(), aStatus
));
793 NS_FRAME_SET_TRUNCATION(aStatus
, aReflowState
, aDesiredSize
);
797 nsSubDocumentFrame::ReflowFinished()
800 nsWeakFrame
weakFrame(this);
802 mFrameLoader
->UpdatePositionAndSize(this);
804 if (weakFrame
.IsAlive()) {
805 // Make sure that we can post a reflow callback in the future.
806 mPostedReflowCallback
= false;
809 mPostedReflowCallback
= false;
815 nsSubDocumentFrame::ReflowCallbackCanceled()
817 mPostedReflowCallback
= false;
821 nsSubDocumentFrame::AttributeChanged(int32_t aNameSpaceID
,
825 if (aNameSpaceID
!= kNameSpaceID_None
) {
829 // If the noResize attribute changes, dis/allow frame to be resized
830 if (aAttribute
== nsGkAtoms::noresize
) {
831 // Note that we're not doing content type checks, but that's ok -- if
832 // they'd fail we will just end up with a null framesetFrame.
833 if (mContent
->GetParent()->Tag() == nsGkAtoms::frameset
) {
834 nsIFrame
* parentFrame
= GetParent();
837 // There is no interface for nsHTMLFramesetFrame so QI'ing to
838 // concrete class, yay!
839 nsHTMLFramesetFrame
* framesetFrame
= do_QueryFrame(parentFrame
);
841 framesetFrame
->RecalculateBorderResize();
846 else if (aAttribute
== nsGkAtoms::showresizer
) {
847 nsIFrame
* rootFrame
= GetSubdocumentRootFrame();
849 rootFrame
->PresContext()->PresShell()->
850 FrameNeedsReflow(rootFrame
, nsIPresShell::eResize
, NS_FRAME_IS_DIRTY
);
853 else if (aAttribute
== nsGkAtoms::marginwidth
||
854 aAttribute
== nsGkAtoms::marginheight
) {
856 // Retrieve the attributes
857 nsIntSize margins
= GetMarginAttributes();
859 // Notify the frameloader
860 nsRefPtr
<nsFrameLoader
> frameloader
= FrameLoader();
862 frameloader
->MarginsChanged(margins
.width
, margins
.height
);
869 NS_NewSubDocumentFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
871 return new (aPresShell
) nsSubDocumentFrame(aContext
);
874 NS_IMPL_FRAMEARENA_HELPERS(nsSubDocumentFrame
)
876 class nsHideViewer
: public nsRunnable
{
878 nsHideViewer(nsIContent
* aFrameElement
,
879 nsFrameLoader
* aFrameLoader
,
880 nsIPresShell
* aPresShell
,
881 bool aHideViewerIfFrameless
)
882 : mFrameElement(aFrameElement
),
883 mFrameLoader(aFrameLoader
),
884 mPresShell(aPresShell
),
885 mHideViewerIfFrameless(aHideViewerIfFrameless
)
887 NS_ASSERTION(mFrameElement
, "Must have a frame element");
888 NS_ASSERTION(mFrameLoader
, "Must have a frame loader");
889 NS_ASSERTION(mPresShell
, "Must have a presshell");
894 // Flush frames, to ensure any pending display:none changes are made.
895 // Note it can be unsafe to flush if we've destroyed the presentation
896 // for some other reason, like if we're shutting down.
897 if (!mPresShell
->IsDestroying()) {
898 mPresShell
->FlushPendingNotifications(Flush_Frames
);
900 nsIFrame
* frame
= mFrameElement
->GetPrimaryFrame();
901 if ((!frame
&& mHideViewerIfFrameless
) ||
902 mPresShell
->IsDestroying()) {
903 // Either the frame element has no nsIFrame or the presshell is being
904 // destroyed. Hide the nsFrameLoader, which destroys the presentation,
905 // and clear our references to the stashed presentation.
906 mFrameLoader
->SetDetachedSubdocView(nullptr, nullptr);
907 mFrameLoader
->Hide();
912 nsCOMPtr
<nsIContent
> mFrameElement
;
913 nsRefPtr
<nsFrameLoader
> mFrameLoader
;
914 nsCOMPtr
<nsIPresShell
> mPresShell
;
915 bool mHideViewerIfFrameless
;
919 BeginSwapDocShellsForViews(nsView
* aSibling
);
922 nsSubDocumentFrame::DestroyFrom(nsIFrame
* aDestructRoot
)
924 if (mPostedReflowCallback
) {
925 PresContext()->PresShell()->CancelReflowCallback(this);
926 mPostedReflowCallback
= false;
929 // Detach the subdocument's views and stash them in the frame loader.
930 // We can then reattach them if we're being reframed (for example if
931 // the frame has been made position:fixed).
932 nsFrameLoader
* frameloader
= FrameLoader();
934 nsView
* detachedViews
= ::BeginSwapDocShellsForViews(mInnerView
->GetFirstChild());
935 frameloader
->SetDetachedSubdocView(detachedViews
, mContent
->OwnerDoc());
937 // We call nsFrameLoader::HideViewer() in a script runner so that we can
938 // safely determine whether the frame is being reframed or destroyed.
939 nsContentUtils::AddScriptRunner(
940 new nsHideViewer(mContent
,
942 PresContext()->PresShell(),
943 (mDidCreateDoc
|| mCallingShow
)));
946 nsLeafFrame::DestroyFrom(aDestructRoot
);
950 nsSubDocumentFrame::GetMarginAttributes()
952 nsIntSize
result(-1, -1);
953 nsGenericHTMLElement
*content
= nsGenericHTMLElement::FromContent(mContent
);
955 const nsAttrValue
* attr
= content
->GetParsedAttr(nsGkAtoms::marginwidth
);
956 if (attr
&& attr
->Type() == nsAttrValue::eInteger
)
957 result
.width
= attr
->GetIntegerValue();
958 attr
= content
->GetParsedAttr(nsGkAtoms::marginheight
);
959 if (attr
&& attr
->Type() == nsAttrValue::eInteger
)
960 result
.height
= attr
->GetIntegerValue();
966 nsSubDocumentFrame::FrameLoader()
968 nsIContent
* content
= GetContent();
973 nsCOMPtr
<nsIFrameLoaderOwner
> loaderOwner
= do_QueryInterface(content
);
975 nsCOMPtr
<nsIFrameLoader
> loader
;
976 loaderOwner
->GetFrameLoader(getter_AddRefs(loader
));
977 mFrameLoader
= static_cast<nsFrameLoader
*>(loader
.get());
983 // XXX this should be called ObtainDocShell or something like that,
984 // to indicate that it could have side effects
986 nsSubDocumentFrame::GetDocShell(nsIDocShell
**aDocShell
)
988 *aDocShell
= nullptr;
990 NS_ENSURE_STATE(FrameLoader());
991 return mFrameLoader
->GetDocShell(aDocShell
);
995 DestroyDisplayItemDataForFrames(nsIFrame
* aFrame
)
997 FrameLayerBuilder::DestroyDisplayItemDataFor(aFrame
);
999 nsIFrame::ChildListIterator
lists(aFrame
);
1000 for (; !lists
.IsDone(); lists
.Next()) {
1001 nsFrameList::Enumerator
childFrames(lists
.CurrentList());
1002 for (; !childFrames
.AtEnd(); childFrames
.Next()) {
1003 DestroyDisplayItemDataForFrames(childFrames
.get());
1009 BeginSwapDocShellsForDocument(nsIDocument
* aDocument
, void*)
1011 NS_PRECONDITION(aDocument
, "");
1013 nsIPresShell
* shell
= aDocument
->GetShell();
1015 // Disable painting while the views are detached, see bug 946929.
1016 shell
->SetNeverPainting(true);
1018 nsIFrame
* rootFrame
= shell
->GetRootFrame();
1020 ::DestroyDisplayItemDataForFrames(rootFrame
);
1023 aDocument
->EnumerateActivityObservers(
1024 nsObjectFrame::BeginSwapDocShells
, nullptr);
1025 aDocument
->EnumerateSubDocuments(BeginSwapDocShellsForDocument
, nullptr);
1030 BeginSwapDocShellsForViews(nsView
* aSibling
)
1032 // Collect the removed sibling views in reverse order in 'removedViews'.
1033 nsView
* removedViews
= nullptr;
1035 nsIDocument
* doc
= ::GetDocumentFromView(aSibling
);
1037 ::BeginSwapDocShellsForDocument(doc
, nullptr);
1039 nsView
* next
= aSibling
->GetNextSibling();
1040 aSibling
->GetViewManager()->RemoveChild(aSibling
);
1041 aSibling
->SetNextSibling(removedViews
);
1042 removedViews
= aSibling
;
1045 return removedViews
;
1049 InsertViewsInReverseOrder(nsView
* aSibling
, nsView
* aParent
)
1051 NS_PRECONDITION(aParent
, "");
1052 NS_PRECONDITION(!aParent
->GetFirstChild(), "inserting into non-empty list");
1054 nsViewManager
* vm
= aParent
->GetViewManager();
1056 nsView
* next
= aSibling
->GetNextSibling();
1057 aSibling
->SetNextSibling(nullptr);
1058 // true means 'after' in document order which is 'before' in view order,
1059 // so this call prepends the child, thus reversing the siblings as we go.
1060 vm
->InsertChild(aParent
, aSibling
, nullptr, true);
1066 nsSubDocumentFrame::BeginSwapDocShells(nsIFrame
* aOther
)
1068 if (!aOther
|| aOther
->GetType() != nsGkAtoms::subDocumentFrame
) {
1069 return NS_ERROR_NOT_IMPLEMENTED
;
1072 nsSubDocumentFrame
* other
= static_cast<nsSubDocumentFrame
*>(aOther
);
1073 if (!mFrameLoader
|| !mDidCreateDoc
|| mCallingShow
||
1074 !other
->mFrameLoader
|| !other
->mDidCreateDoc
) {
1075 return NS_ERROR_NOT_IMPLEMENTED
;
1078 if (mInnerView
&& other
->mInnerView
) {
1079 nsView
* ourSubdocViews
= mInnerView
->GetFirstChild();
1080 nsView
* ourRemovedViews
= ::BeginSwapDocShellsForViews(ourSubdocViews
);
1081 nsView
* otherSubdocViews
= other
->mInnerView
->GetFirstChild();
1082 nsView
* otherRemovedViews
= ::BeginSwapDocShellsForViews(otherSubdocViews
);
1084 ::InsertViewsInReverseOrder(ourRemovedViews
, other
->mInnerView
);
1085 ::InsertViewsInReverseOrder(otherRemovedViews
, mInnerView
);
1087 mFrameLoader
.swap(other
->mFrameLoader
);
1092 EndSwapDocShellsForDocument(nsIDocument
* aDocument
, void*)
1094 NS_PRECONDITION(aDocument
, "");
1096 // Our docshell and view trees have been updated for the new hierarchy.
1097 // Now also update all nsDeviceContext::mWidget to that of the
1098 // container view in the new hierarchy.
1099 nsCOMPtr
<nsIDocShell
> ds
= aDocument
->GetDocShell();
1101 nsCOMPtr
<nsIContentViewer
> cv
;
1102 ds
->GetContentViewer(getter_AddRefs(cv
));
1104 nsRefPtr
<nsPresContext
> pc
;
1105 cv
->GetPresContext(getter_AddRefs(pc
));
1106 if (pc
&& pc
->GetPresShell()) {
1107 pc
->GetPresShell()->SetNeverPainting(ds
->IsInvisible());
1109 nsDeviceContext
* dc
= pc
? pc
->DeviceContext() : nullptr;
1111 nsView
* v
= cv
->FindContainerView();
1112 dc
->Init(v
? v
->GetNearestWidget(nullptr) : nullptr);
1114 nsCOMPtr
<nsIContentViewer
> prev
;
1115 cv
->GetPreviousViewer(getter_AddRefs(prev
));
1120 aDocument
->EnumerateActivityObservers(
1121 nsObjectFrame::EndSwapDocShells
, nullptr);
1122 aDocument
->EnumerateSubDocuments(EndSwapDocShellsForDocument
, nullptr);
1127 EndSwapDocShellsForViews(nsView
* aSibling
)
1129 for ( ; aSibling
; aSibling
= aSibling
->GetNextSibling()) {
1130 nsIDocument
* doc
= ::GetDocumentFromView(aSibling
);
1132 ::EndSwapDocShellsForDocument(doc
, nullptr);
1134 nsIFrame
*frame
= aSibling
->GetFrame();
1136 nsIFrame
* parent
= nsLayoutUtils::GetCrossDocParentFrame(frame
);
1137 if (parent
->HasAnyStateBits(NS_FRAME_IN_POPUP
)) {
1138 nsIFrame::AddInPopupStateBitToDescendants(frame
);
1140 nsIFrame::RemoveInPopupStateBitFromDescendants(frame
);
1142 if (frame
->HasInvalidFrameInSubtree()) {
1143 while (parent
&& !parent
->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT
)) {
1144 parent
->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT
);
1145 parent
= nsLayoutUtils::GetCrossDocParentFrame(parent
);
1153 nsSubDocumentFrame::EndSwapDocShells(nsIFrame
* aOther
)
1155 nsSubDocumentFrame
* other
= static_cast<nsSubDocumentFrame
*>(aOther
);
1156 nsWeakFrame
weakThis(this);
1157 nsWeakFrame
weakOther(aOther
);
1160 ::EndSwapDocShellsForViews(mInnerView
->GetFirstChild());
1162 if (other
->mInnerView
) {
1163 ::EndSwapDocShellsForViews(other
->mInnerView
->GetFirstChild());
1166 // Now make sure we reflow both frames, in case their contents
1167 // determine their size.
1168 // And repaint them, for good measure, in case there's nothing
1169 // interesting that happens during reflow.
1170 if (weakThis
.IsAlive()) {
1171 PresContext()->PresShell()->
1172 FrameNeedsReflow(this, nsIPresShell::eTreeChange
, NS_FRAME_IS_DIRTY
);
1173 InvalidateFrameSubtree();
1175 if (weakOther
.IsAlive()) {
1176 other
->PresContext()->PresShell()->
1177 FrameNeedsReflow(other
, nsIPresShell::eTreeChange
, NS_FRAME_IS_DIRTY
);
1178 other
->InvalidateFrameSubtree();
1183 nsSubDocumentFrame::EnsureInnerView()
1189 // create, init, set the parent of the view
1190 nsView
* outerView
= GetView();
1191 NS_ASSERTION(outerView
, "Must have an outer view already");
1192 nsRect
viewBounds(0, 0, 0, 0); // size will be fixed during reflow
1194 nsViewManager
* viewMan
= outerView
->GetViewManager();
1195 nsView
* innerView
= viewMan
->CreateView(viewBounds
, outerView
);
1197 NS_ERROR("Could not create inner view");
1200 mInnerView
= innerView
;
1201 viewMan
->InsertChild(outerView
, innerView
, nullptr, true);
1207 nsSubDocumentFrame::ObtainIntrinsicSizeFrame()
1209 nsCOMPtr
<nsIObjectLoadingContent
> olc
= do_QueryInterface(GetContent());
1211 // We are an HTML <object>, <embed> or <applet> (a replaced element).
1213 // Try to get an nsIFrame for our sub-document's document element
1214 nsIFrame
* subDocRoot
= nullptr;
1216 nsCOMPtr
<nsIDocShell
> docShell
;
1217 GetDocShell(getter_AddRefs(docShell
));
1219 nsCOMPtr
<nsIPresShell
> presShell
= docShell
->GetPresShell();
1221 nsIScrollableFrame
* scrollable
= presShell
->GetRootScrollFrameAsScrollable();
1223 nsIFrame
* scrolled
= scrollable
->GetScrolledFrame();
1225 subDocRoot
= scrolled
->GetFirstPrincipalChild();
1231 if (subDocRoot
&& subDocRoot
->GetContent() &&
1232 subDocRoot
->GetContent()->NodeInfo()->Equals(nsGkAtoms::svg
, kNameSpaceID_SVG
)) {
1233 return subDocRoot
; // SVG documents have an intrinsic size