summaryrefslogtreecommitdiffstats
path: root/layout/generic/nsSubDocumentFrame.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'layout/generic/nsSubDocumentFrame.cpp')
-rw-r--r--layout/generic/nsSubDocumentFrame.cpp1263
1 files changed, 1263 insertions, 0 deletions
diff --git a/layout/generic/nsSubDocumentFrame.cpp b/layout/generic/nsSubDocumentFrame.cpp
new file mode 100644
index 000000000..47026b73c
--- /dev/null
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -0,0 +1,1263 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * rendering object for replaced elements that contain a document, such
+ * as <frame>, <iframe>, and some <object>s
+ */
+
+#include "nsSubDocumentFrame.h"
+
+#include "gfxPrefs.h"
+
+#include "mozilla/layout/RenderFrameParent.h"
+
+#include "nsCOMPtr.h"
+#include "nsGenericHTMLElement.h"
+#include "nsGenericHTMLFrameElement.h"
+#include "nsAttrValueInlines.h"
+#include "nsIDocShell.h"
+#include "nsIContentViewer.h"
+#include "nsPresContext.h"
+#include "nsIPresShell.h"
+#include "nsIDocument.h"
+#include "nsView.h"
+#include "nsViewManager.h"
+#include "nsGkAtoms.h"
+#include "nsStyleConsts.h"
+#include "nsFrameSetFrame.h"
+#include "nsIDOMHTMLFrameElement.h"
+#include "nsIScrollable.h"
+#include "nsNameSpaceManager.h"
+#include "nsDisplayList.h"
+#include "nsIScrollableFrame.h"
+#include "nsIObjectLoadingContent.h"
+#include "nsLayoutUtils.h"
+#include "FrameLayerBuilder.h"
+#include "nsPluginFrame.h"
+#include "nsContentUtils.h"
+#include "nsIPermissionManager.h"
+#include "nsServiceManagerUtils.h"
+#include "nsIDOMMutationEvent.h"
+#include "mozilla/Preferences.h"
+
+using namespace mozilla;
+using mozilla::layout::RenderFrameParent;
+
+static bool sShowPreviousPage = true;
+
+static nsIDocument*
+GetDocumentFromView(nsView* aView)
+{
+ NS_PRECONDITION(aView, "");
+
+ nsViewManager* vm = aView->GetViewManager();
+ nsIPresShell* ps = vm ? vm->GetPresShell() : nullptr;
+ return ps ? ps->GetDocument() : nullptr;
+}
+
+nsSubDocumentFrame::nsSubDocumentFrame(nsStyleContext* aContext)
+ : nsAtomicContainerFrame(aContext)
+ , mIsInline(false)
+ , mPostedReflowCallback(false)
+ , mDidCreateDoc(false)
+ , mCallingShow(false)
+{
+}
+
+#ifdef ACCESSIBILITY
+a11y::AccType
+nsSubDocumentFrame::AccessibleType()
+{
+ return a11y::eOuterDocType;
+}
+#endif
+
+NS_QUERYFRAME_HEAD(nsSubDocumentFrame)
+ NS_QUERYFRAME_ENTRY(nsSubDocumentFrame)
+NS_QUERYFRAME_TAIL_INHERITING(nsAtomicContainerFrame)
+
+class AsyncFrameInit : public Runnable
+{
+public:
+ explicit AsyncFrameInit(nsIFrame* aFrame) : mFrame(aFrame) {}
+ NS_IMETHOD Run() override
+ {
+ PROFILER_LABEL("mozilla", "AsyncFrameInit::Run", js::ProfileEntry::Category::OTHER);
+ if (mFrame.IsAlive()) {
+ static_cast<nsSubDocumentFrame*>(mFrame.GetFrame())->ShowViewer();
+ }
+ return NS_OK;
+ }
+private:
+ nsWeakFrame mFrame;
+};
+
+static void
+InsertViewsInReverseOrder(nsView* aSibling, nsView* aParent);
+
+static void
+EndSwapDocShellsForViews(nsView* aView);
+
+void
+nsSubDocumentFrame::Init(nsIContent* aContent,
+ nsContainerFrame* aParent,
+ nsIFrame* aPrevInFlow)
+{
+ // determine if we are a <frame> or <iframe>
+ nsCOMPtr<nsIDOMHTMLFrameElement> frameElem = do_QueryInterface(aContent);
+ mIsInline = frameElem ? false : true;
+
+ static bool addedShowPreviousPage = false;
+ if (!addedShowPreviousPage) {
+ Preferences::AddBoolVarCache(&sShowPreviousPage, "layout.show_previous_page", true);
+ addedShowPreviousPage = true;
+ }
+
+ nsAtomicContainerFrame::Init(aContent, aParent, aPrevInFlow);
+
+ // We are going to create an inner view. If we need a view for the
+ // OuterFrame but we wait for the normal view creation path in
+ // nsCSSFrameConstructor, then we will lose because the inner view's
+ // parent will already have been set to some outer view (e.g., the
+ // canvas) when it really needs to have this frame's view as its
+ // parent. So, create this frame's view right away, whether we
+ // really need it or not, and the inner view will get it as the
+ // parent.
+ if (!HasView()) {
+ nsContainerFrame::CreateViewForFrame(this, true);
+ }
+ EnsureInnerView();
+
+ // Set the primary frame now so that nsDocumentViewer::FindContainerView
+ // called from within EndSwapDocShellsForViews below can find it if needed.
+ aContent->SetPrimaryFrame(this);
+
+ // If we have a detached subdoc's root view on our frame loader, re-insert
+ // it into the view tree. This happens when we've been reframed, and
+ // ensures the presentation persists across reframes. If the frame element
+ // has changed documents however, we blow away the presentation.
+ RefPtr<nsFrameLoader> frameloader = FrameLoader();
+ if (frameloader) {
+ nsCOMPtr<nsIDocument> oldContainerDoc;
+ nsIFrame* detachedFrame =
+ frameloader->GetDetachedSubdocFrame(getter_AddRefs(oldContainerDoc));
+ frameloader->SetDetachedSubdocFrame(nullptr, nullptr);
+ MOZ_ASSERT(oldContainerDoc || !detachedFrame);
+ if (oldContainerDoc) {
+ nsView* detachedView =
+ detachedFrame ? detachedFrame->GetView() : nullptr;
+ if (detachedView && oldContainerDoc == aContent->OwnerDoc()) {
+ // Restore stashed presentation.
+ ::InsertViewsInReverseOrder(detachedView, mInnerView);
+ ::EndSwapDocShellsForViews(mInnerView->GetFirstChild());
+ } else {
+ // Presentation is for a different document, don't restore it.
+ frameloader->Hide();
+ }
+ }
+ }
+
+ nsContentUtils::AddScriptRunner(new AsyncFrameInit(this));
+}
+
+void
+nsSubDocumentFrame::ShowViewer()
+{
+ if (mCallingShow) {
+ return;
+ }
+
+ if (!PresContext()->IsDynamic()) {
+ // We let the printing code take care of loading the document; just
+ // create the inner view for it to use.
+ (void) EnsureInnerView();
+ } else {
+ RefPtr<nsFrameLoader> frameloader = FrameLoader();
+ if (frameloader) {
+ CSSIntSize margin = GetMarginAttributes();
+ nsWeakFrame weakThis(this);
+ mCallingShow = true;
+ const nsAttrValue* attrValue =
+ GetContent()->AsElement()->GetParsedAttr(nsGkAtoms::scrolling);
+ int32_t scrolling =
+ nsGenericHTMLFrameElement::MapScrollingAttribute(attrValue);
+ bool didCreateDoc =
+ frameloader->Show(margin.width, margin.height,
+ scrolling, scrolling, this);
+ if (!weakThis.IsAlive()) {
+ return;
+ }
+ mCallingShow = false;
+ mDidCreateDoc = didCreateDoc;
+ }
+ }
+}
+
+nsIFrame*
+nsSubDocumentFrame::GetSubdocumentRootFrame()
+{
+ if (!mInnerView)
+ return nullptr;
+ nsView* subdocView = mInnerView->GetFirstChild();
+ return subdocView ? subdocView->GetFrame() : nullptr;
+}
+
+nsIPresShell*
+nsSubDocumentFrame::GetSubdocumentPresShellForPainting(uint32_t aFlags)
+{
+ if (!mInnerView)
+ return nullptr;
+
+ nsView* subdocView = mInnerView->GetFirstChild();
+ if (!subdocView)
+ return nullptr;
+
+ nsIPresShell* presShell = nullptr;
+
+ nsIFrame* subdocRootFrame = subdocView->GetFrame();
+ if (subdocRootFrame) {
+ presShell = subdocRootFrame->PresContext()->PresShell();
+ }
+
+ // If painting is suppressed in the presshell, we try to look for a better
+ // presshell to use.
+ if (!presShell || (presShell->IsPaintingSuppressed() &&
+ !(aFlags & IGNORE_PAINT_SUPPRESSION))) {
+ // During page transition mInnerView will sometimes have two children, the
+ // first being the new page that may not have any frame, and the second
+ // being the old page that will probably have a frame.
+ nsView* nextView = subdocView->GetNextSibling();
+ nsIFrame* frame = nullptr;
+ if (nextView) {
+ frame = nextView->GetFrame();
+ }
+ if (frame) {
+ nsIPresShell* ps = frame->PresContext()->PresShell();
+ if (!presShell || (ps && !ps->IsPaintingSuppressed() && sShowPreviousPage)) {
+ subdocView = nextView;
+ subdocRootFrame = frame;
+ presShell = ps;
+ }
+ }
+ if (!presShell) {
+ // If we don't have a frame we use this roundabout way to get the pres shell.
+ if (!mFrameLoader)
+ return nullptr;
+ nsCOMPtr<nsIDocShell> docShell;
+ mFrameLoader->GetDocShell(getter_AddRefs(docShell));
+ if (!docShell)
+ return nullptr;
+ presShell = docShell->GetPresShell();
+ }
+ }
+
+ return presShell;
+}
+
+
+
+
+ScreenIntSize
+nsSubDocumentFrame::GetSubdocumentSize()
+{
+ if (GetStateBits() & NS_FRAME_FIRST_REFLOW) {
+ RefPtr<nsFrameLoader> frameloader = FrameLoader();
+ if (frameloader) {
+ nsCOMPtr<nsIDocument> oldContainerDoc;
+ nsIFrame* detachedFrame =
+ frameloader->GetDetachedSubdocFrame(getter_AddRefs(oldContainerDoc));
+ nsView* view = detachedFrame ? detachedFrame->GetView() : nullptr;
+ if (view) {
+ nsSize size = view->GetBounds().Size();
+ nsPresContext* presContext = detachedFrame->PresContext();
+ return ScreenIntSize(presContext->AppUnitsToDevPixels(size.width),
+ presContext->AppUnitsToDevPixels(size.height));
+ }
+ }
+ // Pick some default size for now. Using 10x10 because that's what the
+ // code used to do.
+ return ScreenIntSize(10, 10);
+ } else {
+ nsSize docSizeAppUnits;
+ nsPresContext* presContext = PresContext();
+ nsCOMPtr<nsIDOMHTMLFrameElement> frameElem =
+ do_QueryInterface(GetContent());
+ if (frameElem) {
+ docSizeAppUnits = GetSize();
+ } else {
+ docSizeAppUnits = GetContentRect().Size();
+ }
+ // Adjust subdocument size, according to 'object-fit' and the
+ // subdocument's intrinsic size and ratio.
+ nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
+ if (subDocRoot) {
+ nsRect destRect =
+ nsLayoutUtils::ComputeObjectDestRect(nsRect(nsPoint(), docSizeAppUnits),
+ subDocRoot->GetIntrinsicSize(),
+ subDocRoot->GetIntrinsicRatio(),
+ StylePosition());
+ docSizeAppUnits = destRect.Size();
+ }
+
+ return ScreenIntSize(presContext->AppUnitsToDevPixels(docSizeAppUnits.width),
+ presContext->AppUnitsToDevPixels(docSizeAppUnits.height));
+ }
+}
+
+static void
+WrapBackgroundColorInOwnLayer(nsDisplayListBuilder* aBuilder,
+ nsIFrame* aFrame,
+ nsDisplayList* aList)
+{
+ nsDisplayList tempItems;
+ nsDisplayItem* item;
+ while ((item = aList->RemoveBottom()) != nullptr) {
+ if (item->GetType() == nsDisplayItem::TYPE_BACKGROUND_COLOR) {
+ nsDisplayList tmpList;
+ tmpList.AppendToTop(item);
+ item = new (aBuilder) nsDisplayOwnLayer(aBuilder, aFrame, &tmpList);
+ }
+ tempItems.AppendToTop(item);
+ }
+ aList->AppendToTop(&tempItems);
+}
+
+void
+nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
+ const nsRect& aDirtyRect,
+ const nsDisplayListSet& aLists)
+{
+ if (!IsVisibleForPainting(aBuilder))
+ return;
+
+ nsFrameLoader* frameLoader = FrameLoader();
+ RenderFrameParent* rfp = nullptr;
+ if (frameLoader) {
+ rfp = frameLoader->GetCurrentRenderFrame();
+ }
+
+ // If we are pointer-events:none then we don't need to HitTest background
+ bool pointerEventsNone =
+ StyleUserInterface()->mPointerEvents == NS_STYLE_POINTER_EVENTS_NONE;
+ if (!aBuilder->IsForEventDelivery() || !pointerEventsNone) {
+ nsDisplayListCollection decorations;
+ DisplayBorderBackgroundOutline(aBuilder, decorations);
+ if (rfp) {
+ // Wrap background colors of <iframe>s with remote subdocuments in their
+ // own layer so we generate a ColorLayer. This is helpful for optimizing
+ // compositing; we can skip compositing the ColorLayer when the
+ // remote content is opaque.
+ WrapBackgroundColorInOwnLayer(aBuilder, this, decorations.BorderBackground());
+ }
+ decorations.MoveTo(aLists);
+ }
+
+ if (aBuilder->IsForEventDelivery() && pointerEventsNone) {
+ return;
+ }
+
+ // If we're passing pointer events to children then we have to descend into
+ // subdocuments no matter what, to determine which parts are transparent for
+ // hit-testing or event regions.
+ bool needToDescend = aBuilder->GetDescendIntoSubdocuments();
+ if (!mInnerView || !needToDescend) {
+ return;
+ }
+
+ if (rfp) {
+ rfp->BuildDisplayList(aBuilder, this, aDirtyRect, aLists);
+ return;
+ }
+
+ nsCOMPtr<nsIPresShell> presShell =
+ GetSubdocumentPresShellForPainting(
+ aBuilder->IsIgnoringPaintSuppression() ? IGNORE_PAINT_SUPPRESSION : 0);
+
+ if (!presShell) {
+ return;
+ }
+
+ nsIFrame* subdocRootFrame = presShell->GetRootFrame();
+
+ nsPresContext* presContext = presShell->GetPresContext();
+
+ int32_t parentAPD = PresContext()->AppUnitsPerDevPixel();
+ int32_t subdocAPD = presContext->AppUnitsPerDevPixel();
+
+ nsRect dirty;
+ bool haveDisplayPort = false;
+ bool ignoreViewportScrolling = false;
+ nsIFrame* savedIgnoreScrollFrame = nullptr;
+ if (subdocRootFrame) {
+ // get the dirty rect relative to the root frame of the subdoc
+ dirty = aDirtyRect + GetOffsetToCrossDoc(subdocRootFrame);
+ // and convert into the appunits of the subdoc
+ dirty = dirty.ScaleToOtherAppUnitsRoundOut(parentAPD, subdocAPD);
+
+ if (nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame()) {
+ nsIScrollableFrame* rootScrollableFrame = presShell->GetRootScrollFrameAsScrollable();
+ MOZ_ASSERT(rootScrollableFrame);
+ // Use a copy, so the dirty rect doesn't get modified to the display port.
+ nsRect copy = dirty;
+ haveDisplayPort = rootScrollableFrame->DecideScrollableLayer(aBuilder,
+ &copy, /* aAllowCreateDisplayPort = */ true);
+ if (!gfxPrefs::LayoutUseContainersForRootFrames()) {
+ haveDisplayPort = false;
+ }
+
+ ignoreViewportScrolling = presShell->IgnoringViewportScrolling();
+ if (ignoreViewportScrolling) {
+ savedIgnoreScrollFrame = aBuilder->GetIgnoreScrollFrame();
+ aBuilder->SetIgnoreScrollFrame(rootScrollFrame);
+ }
+ }
+
+ aBuilder->EnterPresShell(subdocRootFrame, pointerEventsNone);
+ } else {
+ dirty = aDirtyRect;
+ }
+
+ DisplayListClipState::AutoSaveRestore clipState(aBuilder);
+ if (ShouldClipSubdocument()) {
+ clipState.ClipContainingBlockDescendantsToContentBox(aBuilder, this);
+ }
+
+ nsIScrollableFrame *sf = presShell->GetRootScrollFrameAsScrollable();
+ bool constructResolutionItem = subdocRootFrame &&
+ (presShell->GetResolution() != 1.0);
+ bool constructZoomItem = subdocRootFrame && parentAPD != subdocAPD;
+ bool needsOwnLayer = false;
+ if (constructResolutionItem ||
+ constructZoomItem ||
+ haveDisplayPort ||
+ presContext->IsRootContentDocument() ||
+ (sf && sf->IsScrollingActive(aBuilder)))
+ {
+ needsOwnLayer = true;
+ }
+ if (!needsOwnLayer && aBuilder->IsBuildingLayerEventRegions() &&
+ nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(presShell))
+ {
+ needsOwnLayer = true;
+ }
+
+ nsDisplayList childItems;
+
+ {
+ DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder);
+ if (needsOwnLayer) {
+ // Clear current clip. There's no point in propagating it down, since
+ // the layer we will construct will be clipped by the current clip.
+ // In fact for nsDisplayZoom propagating it down would be incorrect since
+ // nsDisplayZoom changes the meaning of appunits.
+ nestedClipState.EnterStackingContextContents(true);
+ }
+
+ if (subdocRootFrame) {
+ nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
+ nsDisplayListBuilder::AutoCurrentScrollParentIdSetter idSetter(
+ aBuilder,
+ ignoreViewportScrolling && rootScrollFrame && rootScrollFrame->GetContent()
+ ? nsLayoutUtils::FindOrCreateIDFor(rootScrollFrame->GetContent())
+ : aBuilder->GetCurrentScrollParentId());
+
+ aBuilder->SetAncestorHasApzAwareEventHandler(false);
+ subdocRootFrame->
+ BuildDisplayListForStackingContext(aBuilder, dirty, &childItems);
+ }
+
+ if (!aBuilder->IsForEventDelivery()) {
+ // If we are going to use a displayzoom below then any items we put under
+ // it need to have underlying frames from the subdocument. So we need to
+ // calculate the bounds based on which frame will be the underlying frame
+ // for the canvas background color item.
+ nsRect bounds = GetContentRectRelativeToSelf() +
+ aBuilder->ToReferenceFrame(this);
+ if (subdocRootFrame) {
+ bounds = bounds.ScaleToOtherAppUnitsRoundOut(parentAPD, subdocAPD);
+ }
+
+ // If we are in print preview/page layout we want to paint the grey
+ // background behind the page, not the canvas color. The canvas color gets
+ // painted on the page itself.
+ if (nsLayoutUtils::NeedsPrintPreviewBackground(presContext)) {
+ presShell->AddPrintPreviewBackgroundItem(
+ *aBuilder, childItems, subdocRootFrame ? subdocRootFrame : this,
+ bounds);
+ } else {
+ // Invoke AutoBuildingDisplayList to ensure that the correct dirty rect
+ // is used to compute the visible rect if AddCanvasBackgroundColorItem
+ // creates a display item.
+ nsIFrame* frame = subdocRootFrame ? subdocRootFrame : this;
+ nsDisplayListBuilder::AutoBuildingDisplayList
+ building(aBuilder, frame, dirty, true);
+ // Add the canvas background color to the bottom of the list. This
+ // happens after we've built the list so that AddCanvasBackgroundColorItem
+ // can monkey with the contents if necessary.
+ uint32_t flags = nsIPresShell::FORCE_DRAW;
+ presShell->AddCanvasBackgroundColorItem(
+ *aBuilder, childItems, frame, bounds, NS_RGBA(0,0,0,0), flags);
+ }
+ }
+ }
+
+ if (subdocRootFrame) {
+ aBuilder->LeavePresShell(subdocRootFrame, &childItems);
+
+ if (ignoreViewportScrolling) {
+ aBuilder->SetIgnoreScrollFrame(savedIgnoreScrollFrame);
+ }
+ }
+
+ // Generate a resolution and/or zoom item if needed. If one or both of those is
+ // created, we don't need to create a separate nsDisplaySubDocument.
+
+ uint32_t flags = nsDisplayOwnLayer::GENERATE_SUBDOC_INVALIDATIONS;
+ // If ignoreViewportScrolling is true then the top most layer we create here
+ // is going to become the scrollable layer for the root scroll frame, so we
+ // want to add nsDisplayOwnLayer::GENERATE_SCROLLABLE_LAYER to whatever layer
+ // becomes the topmost. We do this below.
+ if (constructZoomItem) {
+ uint32_t zoomFlags = flags;
+ if (ignoreViewportScrolling && !constructResolutionItem) {
+ zoomFlags |= nsDisplayOwnLayer::GENERATE_SCROLLABLE_LAYER;
+ }
+ nsDisplayZoom* zoomItem =
+ new (aBuilder) nsDisplayZoom(aBuilder, subdocRootFrame, &childItems,
+ subdocAPD, parentAPD, zoomFlags);
+ childItems.AppendToTop(zoomItem);
+ needsOwnLayer = false;
+ }
+ // Wrap the zoom item in the resolution item if we have both because we want the
+ // resolution scale applied on top of the app units per dev pixel conversion.
+ if (ignoreViewportScrolling) {
+ flags |= nsDisplayOwnLayer::GENERATE_SCROLLABLE_LAYER;
+ }
+ if (constructResolutionItem) {
+ nsDisplayResolution* resolutionItem =
+ new (aBuilder) nsDisplayResolution(aBuilder, subdocRootFrame, &childItems,
+ flags);
+ childItems.AppendToTop(resolutionItem);
+ needsOwnLayer = false;
+ }
+ if (needsOwnLayer) {
+ // We always want top level content documents to be in their own layer.
+ nsDisplaySubDocument* layerItem = new (aBuilder) nsDisplaySubDocument(
+ aBuilder, subdocRootFrame ? subdocRootFrame : this,
+ &childItems, flags);
+ childItems.AppendToTop(layerItem);
+ }
+
+ if (aBuilder->IsForFrameVisibility()) {
+ // We don't add the childItems to the return list as we're dealing with them here.
+ presShell->RebuildApproximateFrameVisibilityDisplayList(childItems);
+ childItems.DeleteAll();
+ } else {
+ aLists.Content()->AppendToTop(&childItems);
+ }
+}
+
+nscoord
+nsSubDocumentFrame::GetIntrinsicISize()
+{
+ if (!IsInline()) {
+ return 0; // HTML <frame> has no useful intrinsic isize
+ }
+
+ if (mContent->IsXULElement()) {
+ return 0; // XUL <iframe> and <browser> have no useful intrinsic isize
+ }
+
+ NS_ASSERTION(ObtainIntrinsicSizeFrame() == nullptr,
+ "Intrinsic isize should come from the embedded document.");
+
+ // We must be an HTML <iframe>. Default to size of 300px x 150px, for IE
+ // compat (and per CSS2.1 draft).
+ WritingMode wm = GetWritingMode();
+ return nsPresContext::CSSPixelsToAppUnits(wm.IsVertical() ? 150 : 300);
+}
+
+nscoord
+nsSubDocumentFrame::GetIntrinsicBSize()
+{
+ // <frame> processing does not use this routine, only <iframe>
+ NS_ASSERTION(IsInline(), "Shouldn't have been called");
+
+ if (mContent->IsXULElement()) {
+ return 0;
+ }
+
+ NS_ASSERTION(ObtainIntrinsicSizeFrame() == nullptr,
+ "Intrinsic bsize should come from the embedded document.");
+
+ // Use size of 300px x 150px, for compatibility with IE, and per CSS2.1 draft.
+ WritingMode wm = GetWritingMode();
+ return nsPresContext::CSSPixelsToAppUnits(wm.IsVertical() ? 300 : 150);
+}
+
+#ifdef DEBUG_FRAME_DUMP
+void
+nsSubDocumentFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
+{
+ nsCString str;
+ ListGeneric(str, aPrefix, aFlags);
+ fprintf_stderr(out, "%s\n", str.get());
+
+ if (aFlags & TRAVERSE_SUBDOCUMENT_FRAMES) {
+ nsSubDocumentFrame* f = const_cast<nsSubDocumentFrame*>(this);
+ nsIFrame* subdocRootFrame = f->GetSubdocumentRootFrame();
+ if (subdocRootFrame) {
+ nsCString pfx(aPrefix);
+ pfx += " ";
+ subdocRootFrame->List(out, pfx.get(), aFlags);
+ }
+ }
+}
+
+nsresult nsSubDocumentFrame::GetFrameName(nsAString& aResult) const
+{
+ return MakeFrameName(NS_LITERAL_STRING("FrameOuter"), aResult);
+}
+#endif
+
+nsIAtom*
+nsSubDocumentFrame::GetType() const
+{
+ return nsGkAtoms::subDocumentFrame;
+}
+
+/* virtual */ nscoord
+nsSubDocumentFrame::GetMinISize(nsRenderingContext *aRenderingContext)
+{
+ nscoord result;
+ DISPLAY_MIN_WIDTH(this, result);
+
+ nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
+ if (subDocRoot) {
+ result = subDocRoot->GetMinISize(aRenderingContext);
+ } else {
+ result = GetIntrinsicISize();
+ }
+
+ return result;
+}
+
+/* virtual */ nscoord
+nsSubDocumentFrame::GetPrefISize(nsRenderingContext *aRenderingContext)
+{
+ nscoord result;
+ DISPLAY_PREF_WIDTH(this, result);
+
+ nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
+ if (subDocRoot) {
+ result = subDocRoot->GetPrefISize(aRenderingContext);
+ } else {
+ result = GetIntrinsicISize();
+ }
+
+ return result;
+}
+
+/* virtual */ IntrinsicSize
+nsSubDocumentFrame::GetIntrinsicSize()
+{
+ nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
+ if (subDocRoot) {
+ return subDocRoot->GetIntrinsicSize();
+ }
+ return nsAtomicContainerFrame::GetIntrinsicSize();
+}
+
+/* virtual */ nsSize
+nsSubDocumentFrame::GetIntrinsicRatio()
+{
+ nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
+ if (subDocRoot) {
+ return subDocRoot->GetIntrinsicRatio();
+ }
+ return nsAtomicContainerFrame::GetIntrinsicRatio();
+}
+
+/* virtual */
+LogicalSize
+nsSubDocumentFrame::ComputeAutoSize(nsRenderingContext* aRenderingContext,
+ WritingMode aWM,
+ const LogicalSize& aCBSize,
+ nscoord aAvailableISize,
+ const LogicalSize& aMargin,
+ const LogicalSize& aBorder,
+ const LogicalSize& aPadding,
+ ComputeSizeFlags aFlags)
+{
+ if (!IsInline()) {
+ return nsFrame::ComputeAutoSize(aRenderingContext, aWM, aCBSize,
+ aAvailableISize, aMargin, aBorder,
+ aPadding, aFlags);
+ }
+
+ const WritingMode wm = GetWritingMode();
+ LogicalSize result(wm, GetIntrinsicISize(), GetIntrinsicBSize());
+ return result.ConvertTo(aWM, wm);
+}
+
+
+/* virtual */
+LogicalSize
+nsSubDocumentFrame::ComputeSize(nsRenderingContext* aRenderingContext,
+ WritingMode aWM,
+ const LogicalSize& aCBSize,
+ nscoord aAvailableISize,
+ const LogicalSize& aMargin,
+ const LogicalSize& aBorder,
+ const LogicalSize& aPadding,
+ ComputeSizeFlags aFlags)
+{
+ nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
+ if (subDocRoot) {
+ return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM,
+ subDocRoot->GetIntrinsicSize(),
+ subDocRoot->GetIntrinsicRatio(),
+ aCBSize, aMargin, aBorder,
+ aPadding, aFlags);
+ }
+ return nsAtomicContainerFrame::ComputeSize(aRenderingContext, aWM,
+ aCBSize, aAvailableISize,
+ aMargin, aBorder, aPadding,
+ aFlags);
+}
+
+void
+nsSubDocumentFrame::Reflow(nsPresContext* aPresContext,
+ ReflowOutput& aDesiredSize,
+ const ReflowInput& aReflowInput,
+ nsReflowStatus& aStatus)
+{
+ MarkInReflow();
+ DO_GLOBAL_REFLOW_COUNT("nsSubDocumentFrame");
+ DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
+ NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
+ ("enter nsSubDocumentFrame::Reflow: maxSize=%d,%d",
+ aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight()));
+
+ NS_ASSERTION(aReflowInput.ComputedWidth() != NS_UNCONSTRAINEDSIZE,
+ "Shouldn't have unconstrained stuff here "
+ "thanks to the rules of reflow");
+ NS_ASSERTION(NS_INTRINSICSIZE != aReflowInput.ComputedHeight(),
+ "Shouldn't have unconstrained stuff here "
+ "thanks to ComputeAutoSize");
+
+ aStatus = NS_FRAME_COMPLETE;
+
+ NS_ASSERTION(mContent->GetPrimaryFrame() == this,
+ "Shouldn't happen");
+
+ // XUL <iframe> or <browser>, or HTML <iframe>, <object> or <embed>
+ aDesiredSize.SetSize(aReflowInput.GetWritingMode(),
+ aReflowInput.ComputedSizeWithBorderPadding());
+
+ // "offset" is the offset of our content area from our frame's
+ // top-left corner.
+ nsPoint offset = nsPoint(aReflowInput.ComputedPhysicalBorderPadding().left,
+ aReflowInput.ComputedPhysicalBorderPadding().top);
+
+ if (mInnerView) {
+ const nsMargin& bp = aReflowInput.ComputedPhysicalBorderPadding();
+ nsSize innerSize(aDesiredSize.Width() - bp.LeftRight(),
+ aDesiredSize.Height() - bp.TopBottom());
+
+ // Size & position the view according to 'object-fit' & 'object-position'.
+ nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
+ IntrinsicSize intrinsSize;
+ nsSize intrinsRatio;
+ if (subDocRoot) {
+ intrinsSize = subDocRoot->GetIntrinsicSize();
+ intrinsRatio = subDocRoot->GetIntrinsicRatio();
+ }
+ nsRect destRect =
+ nsLayoutUtils::ComputeObjectDestRect(nsRect(offset, innerSize),
+ intrinsSize, intrinsRatio,
+ StylePosition());
+
+ nsViewManager* vm = mInnerView->GetViewManager();
+ vm->MoveViewTo(mInnerView, destRect.x, destRect.y);
+ vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), destRect.Size()), true);
+ }
+
+ aDesiredSize.SetOverflowAreasToDesiredBounds();
+ if (!ShouldClipSubdocument()) {
+ nsIFrame* subdocRootFrame = GetSubdocumentRootFrame();
+ if (subdocRootFrame) {
+ aDesiredSize.mOverflowAreas.UnionWith(subdocRootFrame->GetOverflowAreas() + offset);
+ }
+ }
+
+ FinishAndStoreOverflow(&aDesiredSize);
+
+ if (!aPresContext->IsPaginated() && !mPostedReflowCallback) {
+ PresContext()->PresShell()->PostReflowCallback(this);
+ mPostedReflowCallback = true;
+ }
+
+ NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
+ ("exit nsSubDocumentFrame::Reflow: size=%d,%d status=%x",
+ aDesiredSize.Width(), aDesiredSize.Height(), aStatus));
+
+ NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
+}
+
+bool
+nsSubDocumentFrame::ReflowFinished()
+{
+ if (mFrameLoader) {
+ nsWeakFrame weakFrame(this);
+
+ mFrameLoader->UpdatePositionAndSize(this);
+
+ if (weakFrame.IsAlive()) {
+ // Make sure that we can post a reflow callback in the future.
+ mPostedReflowCallback = false;
+ }
+ } else {
+ mPostedReflowCallback = false;
+ }
+ return false;
+}
+
+void
+nsSubDocumentFrame::ReflowCallbackCanceled()
+{
+ mPostedReflowCallback = false;
+}
+
+nsresult
+nsSubDocumentFrame::AttributeChanged(int32_t aNameSpaceID,
+ nsIAtom* aAttribute,
+ int32_t aModType)
+{
+ if (aNameSpaceID != kNameSpaceID_None) {
+ return NS_OK;
+ }
+
+ // If the noResize attribute changes, dis/allow frame to be resized
+ if (aAttribute == nsGkAtoms::noresize) {
+ // Note that we're not doing content type checks, but that's ok -- if
+ // they'd fail we will just end up with a null framesetFrame.
+ if (mContent->GetParent()->IsHTMLElement(nsGkAtoms::frameset)) {
+ nsIFrame* parentFrame = GetParent();
+
+ if (parentFrame) {
+ // There is no interface for nsHTMLFramesetFrame so QI'ing to
+ // concrete class, yay!
+ nsHTMLFramesetFrame* framesetFrame = do_QueryFrame(parentFrame);
+ if (framesetFrame) {
+ framesetFrame->RecalculateBorderResize();
+ }
+ }
+ }
+ }
+ else if (aAttribute == nsGkAtoms::showresizer) {
+ nsIFrame* rootFrame = GetSubdocumentRootFrame();
+ if (rootFrame) {
+ rootFrame->PresContext()->PresShell()->
+ FrameNeedsReflow(rootFrame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
+ }
+ }
+ else if (aAttribute == nsGkAtoms::marginwidth ||
+ aAttribute == nsGkAtoms::marginheight) {
+
+ // Retrieve the attributes
+ CSSIntSize margins = GetMarginAttributes();
+
+ // Notify the frameloader
+ RefPtr<nsFrameLoader> frameloader = FrameLoader();
+ if (frameloader)
+ frameloader->MarginsChanged(margins.width, margins.height);
+ }
+
+ return NS_OK;
+}
+
+nsIFrame*
+NS_NewSubDocumentFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
+{
+ return new (aPresShell) nsSubDocumentFrame(aContext);
+}
+
+NS_IMPL_FRAMEARENA_HELPERS(nsSubDocumentFrame)
+
+class nsHideViewer : public Runnable {
+public:
+ nsHideViewer(nsIContent* aFrameElement,
+ nsFrameLoader* aFrameLoader,
+ nsIPresShell* aPresShell,
+ bool aHideViewerIfFrameless)
+ : mFrameElement(aFrameElement),
+ mFrameLoader(aFrameLoader),
+ mPresShell(aPresShell),
+ mHideViewerIfFrameless(aHideViewerIfFrameless)
+ {
+ NS_ASSERTION(mFrameElement, "Must have a frame element");
+ NS_ASSERTION(mFrameLoader, "Must have a frame loader");
+ NS_ASSERTION(mPresShell, "Must have a presshell");
+ }
+
+ NS_IMETHOD Run() override
+ {
+ // Flush frames, to ensure any pending display:none changes are made.
+ // Note it can be unsafe to flush if we've destroyed the presentation
+ // for some other reason, like if we're shutting down.
+ if (!mPresShell->IsDestroying()) {
+ mPresShell->FlushPendingNotifications(Flush_Frames);
+ }
+
+ // Either the frame has been constructed by now, or it never will be,
+ // either way we want to clear the stashed views.
+ mFrameLoader->SetDetachedSubdocFrame(nullptr, nullptr);
+
+ nsSubDocumentFrame* frame = do_QueryFrame(mFrameElement->GetPrimaryFrame());
+ if ((!frame && mHideViewerIfFrameless) ||
+ mPresShell->IsDestroying()) {
+ // Either the frame element has no nsIFrame or the presshell is being
+ // destroyed. Hide the nsFrameLoader, which destroys the presentation.
+ mFrameLoader->Hide();
+ }
+ return NS_OK;
+ }
+private:
+ nsCOMPtr<nsIContent> mFrameElement;
+ RefPtr<nsFrameLoader> mFrameLoader;
+ nsCOMPtr<nsIPresShell> mPresShell;
+ bool mHideViewerIfFrameless;
+};
+
+static nsView*
+BeginSwapDocShellsForViews(nsView* aSibling);
+
+void
+nsSubDocumentFrame::DestroyFrom(nsIFrame* aDestructRoot)
+{
+ if (mPostedReflowCallback) {
+ PresContext()->PresShell()->CancelReflowCallback(this);
+ mPostedReflowCallback = false;
+ }
+
+ // Detach the subdocument's views and stash them in the frame loader.
+ // We can then reattach them if we're being reframed (for example if
+ // the frame has been made position:fixed).
+ RefPtr<nsFrameLoader> frameloader = FrameLoader();
+ if (frameloader) {
+ nsView* detachedViews = ::BeginSwapDocShellsForViews(mInnerView->GetFirstChild());
+
+ if (detachedViews && detachedViews->GetFrame()) {
+ MOZ_ASSERT(mContent->OwnerDoc());
+ frameloader->SetDetachedSubdocFrame(
+ detachedViews->GetFrame(), mContent->OwnerDoc());
+
+ // We call nsFrameLoader::HideViewer() in a script runner so that we can
+ // safely determine whether the frame is being reframed or destroyed.
+ nsContentUtils::AddScriptRunner(
+ new nsHideViewer(mContent,
+ frameloader,
+ PresContext()->PresShell(),
+ (mDidCreateDoc || mCallingShow)));
+ } else {
+ frameloader->SetDetachedSubdocFrame(nullptr, nullptr);
+ if (mDidCreateDoc || mCallingShow) {
+ frameloader->Hide();
+ }
+ }
+ }
+
+ nsAtomicContainerFrame::DestroyFrom(aDestructRoot);
+}
+
+CSSIntSize
+nsSubDocumentFrame::GetMarginAttributes()
+{
+ CSSIntSize result(-1, -1);
+ nsGenericHTMLElement *content = nsGenericHTMLElement::FromContent(mContent);
+ if (content) {
+ const nsAttrValue* attr = content->GetParsedAttr(nsGkAtoms::marginwidth);
+ if (attr && attr->Type() == nsAttrValue::eInteger)
+ result.width = attr->GetIntegerValue();
+ attr = content->GetParsedAttr(nsGkAtoms::marginheight);
+ if (attr && attr->Type() == nsAttrValue::eInteger)
+ result.height = attr->GetIntegerValue();
+ }
+ return result;
+}
+
+nsFrameLoader*
+nsSubDocumentFrame::FrameLoader()
+{
+ nsIContent* content = GetContent();
+ if (!content)
+ return nullptr;
+
+ if (!mFrameLoader) {
+ nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(content);
+ if (loaderOwner) {
+ mFrameLoader = loaderOwner->GetFrameLoader();
+ }
+ }
+ return mFrameLoader;
+}
+
+// XXX this should be called ObtainDocShell or something like that,
+// to indicate that it could have side effects
+nsresult
+nsSubDocumentFrame::GetDocShell(nsIDocShell **aDocShell)
+{
+ *aDocShell = nullptr;
+
+ NS_ENSURE_STATE(FrameLoader());
+ return mFrameLoader->GetDocShell(aDocShell);
+}
+
+static void
+DestroyDisplayItemDataForFrames(nsIFrame* aFrame)
+{
+ FrameLayerBuilder::DestroyDisplayItemDataFor(aFrame);
+
+ nsIFrame::ChildListIterator lists(aFrame);
+ for (; !lists.IsDone(); lists.Next()) {
+ nsFrameList::Enumerator childFrames(lists.CurrentList());
+ for (; !childFrames.AtEnd(); childFrames.Next()) {
+ DestroyDisplayItemDataForFrames(childFrames.get());
+ }
+ }
+}
+
+static bool
+BeginSwapDocShellsForDocument(nsIDocument* aDocument, void*)
+{
+ NS_PRECONDITION(aDocument, "");
+
+ nsIPresShell* shell = aDocument->GetShell();
+ if (shell) {
+ // Disable painting while the views are detached, see bug 946929.
+ shell->SetNeverPainting(true);
+
+ nsIFrame* rootFrame = shell->GetRootFrame();
+ if (rootFrame) {
+ ::DestroyDisplayItemDataForFrames(rootFrame);
+ }
+ }
+ aDocument->EnumerateActivityObservers(
+ nsPluginFrame::BeginSwapDocShells, nullptr);
+ aDocument->EnumerateSubDocuments(BeginSwapDocShellsForDocument, nullptr);
+ return true;
+}
+
+static nsView*
+BeginSwapDocShellsForViews(nsView* aSibling)
+{
+ // Collect the removed sibling views in reverse order in 'removedViews'.
+ nsView* removedViews = nullptr;
+ while (aSibling) {
+ nsIDocument* doc = ::GetDocumentFromView(aSibling);
+ if (doc) {
+ ::BeginSwapDocShellsForDocument(doc, nullptr);
+ }
+ nsView* next = aSibling->GetNextSibling();
+ aSibling->GetViewManager()->RemoveChild(aSibling);
+ aSibling->SetNextSibling(removedViews);
+ removedViews = aSibling;
+ aSibling = next;
+ }
+ return removedViews;
+}
+
+static void
+InsertViewsInReverseOrder(nsView* aSibling, nsView* aParent)
+{
+ NS_PRECONDITION(aParent, "");
+ NS_PRECONDITION(!aParent->GetFirstChild(), "inserting into non-empty list");
+
+ nsViewManager* vm = aParent->GetViewManager();
+ while (aSibling) {
+ nsView* next = aSibling->GetNextSibling();
+ aSibling->SetNextSibling(nullptr);
+ // true means 'after' in document order which is 'before' in view order,
+ // so this call prepends the child, thus reversing the siblings as we go.
+ vm->InsertChild(aParent, aSibling, nullptr, true);
+ aSibling = next;
+ }
+}
+
+nsresult
+nsSubDocumentFrame::BeginSwapDocShells(nsIFrame* aOther)
+{
+ if (!aOther || aOther->GetType() != nsGkAtoms::subDocumentFrame) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+ }
+
+ nsSubDocumentFrame* other = static_cast<nsSubDocumentFrame*>(aOther);
+ if (!mFrameLoader || !mDidCreateDoc || mCallingShow ||
+ !other->mFrameLoader || !other->mDidCreateDoc) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+ }
+
+ if (mInnerView && other->mInnerView) {
+ nsView* ourSubdocViews = mInnerView->GetFirstChild();
+ nsView* ourRemovedViews = ::BeginSwapDocShellsForViews(ourSubdocViews);
+ nsView* otherSubdocViews = other->mInnerView->GetFirstChild();
+ nsView* otherRemovedViews = ::BeginSwapDocShellsForViews(otherSubdocViews);
+
+ ::InsertViewsInReverseOrder(ourRemovedViews, other->mInnerView);
+ ::InsertViewsInReverseOrder(otherRemovedViews, mInnerView);
+ }
+ mFrameLoader.swap(other->mFrameLoader);
+ return NS_OK;
+}
+
+static bool
+EndSwapDocShellsForDocument(nsIDocument* aDocument, void*)
+{
+ NS_PRECONDITION(aDocument, "");
+
+ // Our docshell and view trees have been updated for the new hierarchy.
+ // Now also update all nsDeviceContext::mWidget to that of the
+ // container view in the new hierarchy.
+ nsCOMPtr<nsIDocShell> ds = aDocument->GetDocShell();
+ if (ds) {
+ nsCOMPtr<nsIContentViewer> cv;
+ ds->GetContentViewer(getter_AddRefs(cv));
+ while (cv) {
+ RefPtr<nsPresContext> pc;
+ cv->GetPresContext(getter_AddRefs(pc));
+ if (pc && pc->GetPresShell()) {
+ pc->GetPresShell()->SetNeverPainting(ds->IsInvisible());
+ }
+ nsDeviceContext* dc = pc ? pc->DeviceContext() : nullptr;
+ if (dc) {
+ nsView* v = cv->FindContainerView();
+ dc->Init(v ? v->GetNearestWidget(nullptr) : nullptr);
+ }
+ nsCOMPtr<nsIContentViewer> prev;
+ cv->GetPreviousViewer(getter_AddRefs(prev));
+ cv = prev;
+ }
+ }
+
+ aDocument->EnumerateActivityObservers(
+ nsPluginFrame::EndSwapDocShells, nullptr);
+ aDocument->EnumerateSubDocuments(EndSwapDocShellsForDocument, nullptr);
+ return true;
+}
+
+static void
+EndSwapDocShellsForViews(nsView* aSibling)
+{
+ for ( ; aSibling; aSibling = aSibling->GetNextSibling()) {
+ nsIDocument* doc = ::GetDocumentFromView(aSibling);
+ if (doc) {
+ ::EndSwapDocShellsForDocument(doc, nullptr);
+ }
+ nsIFrame *frame = aSibling->GetFrame();
+ if (frame) {
+ nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(frame);
+ if (parent->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
+ nsIFrame::AddInPopupStateBitToDescendants(frame);
+ } else {
+ nsIFrame::RemoveInPopupStateBitFromDescendants(frame);
+ }
+ if (frame->HasInvalidFrameInSubtree()) {
+ while (parent && !parent->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT | NS_FRAME_IS_NONDISPLAY)) {
+ parent->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT);
+ parent = nsLayoutUtils::GetCrossDocParentFrame(parent);
+ }
+ }
+ }
+ }
+}
+
+void
+nsSubDocumentFrame::EndSwapDocShells(nsIFrame* aOther)
+{
+ nsSubDocumentFrame* other = static_cast<nsSubDocumentFrame*>(aOther);
+ nsWeakFrame weakThis(this);
+ nsWeakFrame weakOther(aOther);
+
+ if (mInnerView) {
+ ::EndSwapDocShellsForViews(mInnerView->GetFirstChild());
+ }
+ if (other->mInnerView) {
+ ::EndSwapDocShellsForViews(other->mInnerView->GetFirstChild());
+ }
+
+ // Now make sure we reflow both frames, in case their contents
+ // determine their size.
+ // And repaint them, for good measure, in case there's nothing
+ // interesting that happens during reflow.
+ if (weakThis.IsAlive()) {
+ PresContext()->PresShell()->
+ FrameNeedsReflow(this, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
+ InvalidateFrameSubtree();
+ }
+ if (weakOther.IsAlive()) {
+ other->PresContext()->PresShell()->
+ FrameNeedsReflow(other, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
+ other->InvalidateFrameSubtree();
+ }
+}
+
+nsView*
+nsSubDocumentFrame::EnsureInnerView()
+{
+ if (mInnerView) {
+ return mInnerView;
+ }
+
+ // create, init, set the parent of the view
+ nsView* outerView = GetView();
+ NS_ASSERTION(outerView, "Must have an outer view already");
+ nsRect viewBounds(0, 0, 0, 0); // size will be fixed during reflow
+
+ nsViewManager* viewMan = outerView->GetViewManager();
+ nsView* innerView = viewMan->CreateView(viewBounds, outerView);
+ if (!innerView) {
+ NS_ERROR("Could not create inner view");
+ return nullptr;
+ }
+ mInnerView = innerView;
+ viewMan->InsertChild(outerView, innerView, nullptr, true);
+
+ return mInnerView;
+}
+
+nsIFrame*
+nsSubDocumentFrame::ObtainIntrinsicSizeFrame()
+{
+ nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(GetContent());
+ if (olc) {
+ // We are an HTML <object>, <embed> or <applet> (a replaced element).
+
+ // Try to get an nsIFrame for our sub-document's document element
+ nsIFrame* subDocRoot = nullptr;
+
+ nsCOMPtr<nsIDocShell> docShell;
+ GetDocShell(getter_AddRefs(docShell));
+ if (docShell) {
+ nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell();
+ if (presShell) {
+ nsIScrollableFrame* scrollable = presShell->GetRootScrollFrameAsScrollable();
+ if (scrollable) {
+ nsIFrame* scrolled = scrollable->GetScrolledFrame();
+ if (scrolled) {
+ subDocRoot = scrolled->PrincipalChildList().FirstChild();
+ }
+ }
+ }
+ }
+
+ if (subDocRoot && subDocRoot->GetContent() &&
+ subDocRoot->GetContent()->NodeInfo()->Equals(nsGkAtoms::svg, kNameSpaceID_SVG)) {
+ return subDocRoot; // SVG documents have an intrinsic size
+ }
+ }
+ return nullptr;
+}