layout/generic/nsSubDocumentFrame.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/generic/nsSubDocumentFrame.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1196 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/*
    1.10 + * rendering object for replaced elements that contain a document, such
    1.11 + * as <frame>, <iframe>, and some <object>s
    1.12 + */
    1.13 +
    1.14 +#include "nsSubDocumentFrame.h"
    1.15 +
    1.16 +#include "mozilla/layout/RenderFrameParent.h"
    1.17 +
    1.18 +#include "nsCOMPtr.h"
    1.19 +#include "nsGenericHTMLElement.h"
    1.20 +#include "nsGenericHTMLFrameElement.h"
    1.21 +#include "nsAttrValueInlines.h"
    1.22 +#include "nsIDocShell.h"
    1.23 +#include "nsIContentViewer.h"
    1.24 +#include "nsPresContext.h"
    1.25 +#include "nsIPresShell.h"
    1.26 +#include "nsIDocument.h"
    1.27 +#include "nsView.h"
    1.28 +#include "nsViewManager.h"
    1.29 +#include "nsGkAtoms.h"
    1.30 +#include "nsStyleConsts.h"
    1.31 +#include "nsFrameSetFrame.h"
    1.32 +#include "nsIDOMHTMLFrameElement.h"
    1.33 +#include "nsIScrollable.h"
    1.34 +#include "nsNameSpaceManager.h"
    1.35 +#include "nsDisplayList.h"
    1.36 +#include "nsIScrollableFrame.h"
    1.37 +#include "nsIObjectLoadingContent.h"
    1.38 +#include "nsLayoutUtils.h"
    1.39 +#include "FrameLayerBuilder.h"
    1.40 +#include "nsObjectFrame.h"
    1.41 +#include "nsContentUtils.h"
    1.42 +#include "nsIPermissionManager.h"
    1.43 +#include "nsServiceManagerUtils.h"
    1.44 +
    1.45 +using namespace mozilla;
    1.46 +using mozilla::layout::RenderFrameParent;
    1.47 +
    1.48 +static nsIDocument*
    1.49 +GetDocumentFromView(nsView* aView)
    1.50 +{
    1.51 +  NS_PRECONDITION(aView, "");
    1.52 +
    1.53 +  nsIFrame* f = aView->GetFrame();
    1.54 +  nsIPresShell* ps =  f ? f->PresContext()->PresShell() : nullptr;
    1.55 +  return ps ? ps->GetDocument() : nullptr;
    1.56 +}
    1.57 +
    1.58 +nsSubDocumentFrame::nsSubDocumentFrame(nsStyleContext* aContext)
    1.59 +  : nsLeafFrame(aContext)
    1.60 +  , mIsInline(false)
    1.61 +  , mPostedReflowCallback(false)
    1.62 +  , mDidCreateDoc(false)
    1.63 +  , mCallingShow(false)
    1.64 +{
    1.65 +}
    1.66 +
    1.67 +#ifdef ACCESSIBILITY
    1.68 +a11y::AccType
    1.69 +nsSubDocumentFrame::AccessibleType()
    1.70 +{
    1.71 +  return a11y::eOuterDocType;
    1.72 +}
    1.73 +#endif
    1.74 +
    1.75 +NS_QUERYFRAME_HEAD(nsSubDocumentFrame)
    1.76 +  NS_QUERYFRAME_ENTRY(nsSubDocumentFrame)
    1.77 +NS_QUERYFRAME_TAIL_INHERITING(nsLeafFrame)
    1.78 +
    1.79 +class AsyncFrameInit : public nsRunnable
    1.80 +{
    1.81 +public:
    1.82 +  AsyncFrameInit(nsIFrame* aFrame) : mFrame(aFrame) {}
    1.83 +  NS_IMETHOD Run()
    1.84 +  {
    1.85 +    if (mFrame.IsAlive()) {
    1.86 +      static_cast<nsSubDocumentFrame*>(mFrame.GetFrame())->ShowViewer();
    1.87 +    }
    1.88 +    return NS_OK;
    1.89 +  }
    1.90 +private:
    1.91 +  nsWeakFrame mFrame;
    1.92 +};
    1.93 +
    1.94 +static void
    1.95 +InsertViewsInReverseOrder(nsView* aSibling, nsView* aParent);
    1.96 +
    1.97 +static void
    1.98 +EndSwapDocShellsForViews(nsView* aView);
    1.99 +
   1.100 +void
   1.101 +nsSubDocumentFrame::Init(nsIContent*     aContent,
   1.102 +                         nsIFrame*       aParent,
   1.103 +                         nsIFrame*       aPrevInFlow)
   1.104 +{
   1.105 +  // determine if we are a <frame> or <iframe>
   1.106 +  if (aContent) {
   1.107 +    nsCOMPtr<nsIDOMHTMLFrameElement> frameElem = do_QueryInterface(aContent);
   1.108 +    mIsInline = frameElem ? false : true;
   1.109 +  }
   1.110 +
   1.111 +  nsLeafFrame::Init(aContent, aParent, aPrevInFlow);
   1.112 +
   1.113 +  // We are going to create an inner view.  If we need a view for the
   1.114 +  // OuterFrame but we wait for the normal view creation path in
   1.115 +  // nsCSSFrameConstructor, then we will lose because the inner view's
   1.116 +  // parent will already have been set to some outer view (e.g., the
   1.117 +  // canvas) when it really needs to have this frame's view as its
   1.118 +  // parent. So, create this frame's view right away, whether we
   1.119 +  // really need it or not, and the inner view will get it as the
   1.120 +  // parent.
   1.121 +  if (!HasView()) {
   1.122 +    nsContainerFrame::CreateViewForFrame(this, true);
   1.123 +  }
   1.124 +  EnsureInnerView();
   1.125 +
   1.126 +  // Set the primary frame now so that nsDocumentViewer::FindContainerView
   1.127 +  // called from within EndSwapDocShellsForViews below can find it if needed.
   1.128 +  aContent->SetPrimaryFrame(this);
   1.129 +
   1.130 +  // If we have a detached subdoc's root view on our frame loader, re-insert
   1.131 +  // it into the view tree. This happens when we've been reframed, and
   1.132 +  // ensures the presentation persists across reframes. If the frame element
   1.133 +  // has changed documents however, we blow away the presentation.
   1.134 +  nsRefPtr<nsFrameLoader> frameloader = FrameLoader();
   1.135 +  if (frameloader) {
   1.136 +    nsCOMPtr<nsIDocument> oldContainerDoc;
   1.137 +    nsView* detachedViews =
   1.138 +      frameloader->GetDetachedSubdocView(getter_AddRefs(oldContainerDoc));
   1.139 +    if (detachedViews) {
   1.140 +      if (oldContainerDoc == aContent->OwnerDoc()) {
   1.141 +        // Restore stashed presentation.
   1.142 +        ::InsertViewsInReverseOrder(detachedViews, mInnerView);
   1.143 +        ::EndSwapDocShellsForViews(mInnerView->GetFirstChild());
   1.144 +      } else {
   1.145 +        // Presentation is for a different document, don't restore it.
   1.146 +        frameloader->Hide();
   1.147 +      }
   1.148 +    }
   1.149 +    frameloader->SetDetachedSubdocView(nullptr, nullptr);
   1.150 +  }
   1.151 +
   1.152 +  nsContentUtils::AddScriptRunner(new AsyncFrameInit(this));
   1.153 +}
   1.154 +
   1.155 +void
   1.156 +nsSubDocumentFrame::ShowViewer()
   1.157 +{
   1.158 +  if (mCallingShow) {
   1.159 +    return;
   1.160 +  }
   1.161 +
   1.162 +  if (!PresContext()->IsDynamic()) {
   1.163 +    // We let the printing code take care of loading the document; just
   1.164 +    // create the inner view for it to use.
   1.165 +    (void) EnsureInnerView();
   1.166 +  } else {
   1.167 +    nsRefPtr<nsFrameLoader> frameloader = FrameLoader();
   1.168 +    if (frameloader) {
   1.169 +      nsIntSize margin = GetMarginAttributes();
   1.170 +      nsWeakFrame weakThis(this);
   1.171 +      mCallingShow = true;
   1.172 +      const nsAttrValue* attrValue =
   1.173 +        GetContent()->AsElement()->GetParsedAttr(nsGkAtoms::scrolling);
   1.174 +      int32_t scrolling =
   1.175 +        nsGenericHTMLFrameElement::MapScrollingAttribute(attrValue);
   1.176 +      bool didCreateDoc =
   1.177 +        frameloader->Show(margin.width, margin.height,
   1.178 +                          scrolling, scrolling, this);
   1.179 +      if (!weakThis.IsAlive()) {
   1.180 +        return;
   1.181 +      }
   1.182 +      mCallingShow = false;
   1.183 +      mDidCreateDoc = didCreateDoc;
   1.184 +    }
   1.185 +  }
   1.186 +}
   1.187 +
   1.188 +nsIFrame*
   1.189 +nsSubDocumentFrame::GetSubdocumentRootFrame()
   1.190 +{
   1.191 +  if (!mInnerView)
   1.192 +    return nullptr;
   1.193 +  nsView* subdocView = mInnerView->GetFirstChild();
   1.194 +  return subdocView ? subdocView->GetFrame() : nullptr;
   1.195 +}
   1.196 +
   1.197 +nsIntSize
   1.198 +nsSubDocumentFrame::GetSubdocumentSize()
   1.199 +{
   1.200 +  if (GetStateBits() & NS_FRAME_FIRST_REFLOW) {
   1.201 +    nsRefPtr<nsFrameLoader> frameloader = FrameLoader();
   1.202 +    if (frameloader) {
   1.203 +      nsCOMPtr<nsIDocument> oldContainerDoc;
   1.204 +      nsView* detachedViews =
   1.205 +        frameloader->GetDetachedSubdocView(getter_AddRefs(oldContainerDoc));
   1.206 +      if (detachedViews) {
   1.207 +        nsSize size = detachedViews->GetBounds().Size();
   1.208 +        nsPresContext* presContext = detachedViews->GetFrame()->PresContext();
   1.209 +        return nsIntSize(presContext->AppUnitsToDevPixels(size.width),
   1.210 +                         presContext->AppUnitsToDevPixels(size.height));
   1.211 +      }
   1.212 +    }
   1.213 +    // Pick some default size for now.  Using 10x10 because that's what the
   1.214 +    // code used to do.
   1.215 +    return nsIntSize(10, 10);
   1.216 +  } else {
   1.217 +    nsSize docSizeAppUnits;
   1.218 +    nsPresContext* presContext = PresContext();
   1.219 +    nsCOMPtr<nsIDOMHTMLFrameElement> frameElem =
   1.220 +      do_QueryInterface(GetContent());
   1.221 +    if (frameElem) {
   1.222 +      docSizeAppUnits = GetSize();
   1.223 +    } else {
   1.224 +      docSizeAppUnits = GetContentRect().Size();
   1.225 +    }
   1.226 +    return nsIntSize(presContext->AppUnitsToDevPixels(docSizeAppUnits.width),
   1.227 +                     presContext->AppUnitsToDevPixels(docSizeAppUnits.height));
   1.228 +  }
   1.229 +}
   1.230 +
   1.231 +bool
   1.232 +nsSubDocumentFrame::PassPointerEventsToChildren()
   1.233 +{
   1.234 +  // Limit use of mozpasspointerevents to documents with embedded:apps/chrome
   1.235 +  // permission, because this could be used by the parent document to discover
   1.236 +  // which parts of the subdocument are transparent to events (if subdocument
   1.237 +  // uses pointer-events:none on its root element, which is admittedly
   1.238 +  // unlikely)
   1.239 +  if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::mozpasspointerevents)) {
   1.240 +      if (PresContext()->IsChrome()) {
   1.241 +        return true;
   1.242 +      }
   1.243 +
   1.244 +      nsCOMPtr<nsIPermissionManager> permMgr =
   1.245 +        do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
   1.246 +      if (permMgr) {
   1.247 +        uint32_t permission = nsIPermissionManager::DENY_ACTION;
   1.248 +        permMgr->TestPermissionFromPrincipal(GetContent()->NodePrincipal(),
   1.249 +                                             "embed-apps", &permission);
   1.250 +
   1.251 +        return permission == nsIPermissionManager::ALLOW_ACTION;
   1.252 +      }
   1.253 +  }
   1.254 +
   1.255 +  return false;
   1.256 +}
   1.257 +
   1.258 +static void
   1.259 +WrapBackgroundColorInOwnLayer(nsDisplayListBuilder* aBuilder,
   1.260 +                              nsIFrame* aFrame,
   1.261 +                              nsDisplayList* aList)
   1.262 +{
   1.263 +  nsDisplayList tempItems;
   1.264 +  nsDisplayItem* item;
   1.265 +  while ((item = aList->RemoveBottom()) != nullptr) {
   1.266 +    if (item->GetType() == nsDisplayItem::TYPE_BACKGROUND_COLOR) {
   1.267 +      nsDisplayList tmpList;
   1.268 +      tmpList.AppendToTop(item);
   1.269 +      item = new (aBuilder) nsDisplayOwnLayer(aBuilder, aFrame, &tmpList);
   1.270 +    }
   1.271 +    tempItems.AppendToTop(item);
   1.272 +  }
   1.273 +  aList->AppendToTop(&tempItems);
   1.274 +}
   1.275 +
   1.276 +void
   1.277 +nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
   1.278 +                                     const nsRect&           aDirtyRect,
   1.279 +                                     const nsDisplayListSet& aLists)
   1.280 +{
   1.281 +  if (!IsVisibleForPainting(aBuilder))
   1.282 +    return;
   1.283 +
   1.284 +  nsFrameLoader* frameLoader = FrameLoader();
   1.285 +  RenderFrameParent* rfp = nullptr;
   1.286 +  if (frameLoader) {
   1.287 +    rfp = frameLoader->GetCurrentRemoteFrame();
   1.288 +  }
   1.289 +
   1.290 +  // If we are pointer-events:none then we don't need to HitTest background
   1.291 +  bool pointerEventsNone = StyleVisibility()->mPointerEvents == NS_STYLE_POINTER_EVENTS_NONE;
   1.292 +  if (!aBuilder->IsForEventDelivery() || !pointerEventsNone) {
   1.293 +    nsDisplayListCollection decorations;
   1.294 +    DisplayBorderBackgroundOutline(aBuilder, decorations);
   1.295 +    if (rfp) {
   1.296 +      // Wrap background colors of <iframe>s with remote subdocuments in their
   1.297 +      // own layer so we generate a ColorLayer. This is helpful for optimizing
   1.298 +      // compositing; we can skip compositing the ColorLayer when the
   1.299 +      // remote content is opaque.
   1.300 +      WrapBackgroundColorInOwnLayer(aBuilder, this, decorations.BorderBackground());
   1.301 +    }
   1.302 +    decorations.MoveTo(aLists);
   1.303 +  }
   1.304 +
   1.305 +  bool passPointerEventsToChildren = false;
   1.306 +  if (aBuilder->IsForEventDelivery()) {
   1.307 +    passPointerEventsToChildren = PassPointerEventsToChildren();
   1.308 +    // If mozpasspointerevents is set, then we should allow subdocument content
   1.309 +    // to handle events even if we're pointer-events:none.
   1.310 +    if (pointerEventsNone && !passPointerEventsToChildren) {
   1.311 +      return;
   1.312 +    }
   1.313 +  }
   1.314 +
   1.315 +  // If we're passing pointer events to children then we have to descend into
   1.316 +  // subdocuments no matter what, to determine which parts are transparent for
   1.317 +  // elementFromPoint.
   1.318 +  if (!mInnerView ||
   1.319 +      (!aBuilder->GetDescendIntoSubdocuments() && !passPointerEventsToChildren)) {
   1.320 +    return;
   1.321 +  }
   1.322 +
   1.323 +  if (rfp) {
   1.324 +    rfp->BuildDisplayList(aBuilder, this, aDirtyRect, aLists);
   1.325 +    return;
   1.326 +  }
   1.327 +
   1.328 +  nsView* subdocView = mInnerView->GetFirstChild();
   1.329 +  if (!subdocView)
   1.330 +    return;
   1.331 +
   1.332 +  nsCOMPtr<nsIPresShell> presShell = nullptr;
   1.333 +
   1.334 +  nsIFrame* subdocRootFrame = subdocView->GetFrame();
   1.335 +  if (subdocRootFrame) {
   1.336 +    presShell = subdocRootFrame->PresContext()->PresShell();
   1.337 +  }
   1.338 +  // If painting is suppressed in the presshell, we try to look for a better
   1.339 +  // presshell to use.
   1.340 +  if (!presShell || (presShell->IsPaintingSuppressed() &&
   1.341 +                     !aBuilder->IsIgnoringPaintSuppression())) {
   1.342 +    // During page transition mInnerView will sometimes have two children, the
   1.343 +    // first being the new page that may not have any frame, and the second
   1.344 +    // being the old page that will probably have a frame.
   1.345 +    nsView* nextView = subdocView->GetNextSibling();
   1.346 +    nsIFrame* frame = nullptr;
   1.347 +    if (nextView) {
   1.348 +      frame = nextView->GetFrame();
   1.349 +    }
   1.350 +    if (frame) {
   1.351 +      nsIPresShell* ps = frame->PresContext()->PresShell();
   1.352 +      if (!presShell || (ps && !ps->IsPaintingSuppressed())) {
   1.353 +        subdocView = nextView;
   1.354 +        subdocRootFrame = frame;
   1.355 +        presShell = ps;
   1.356 +      }
   1.357 +    }
   1.358 +    if (!presShell) {
   1.359 +      // If we don't have a frame we use this roundabout way to get the pres shell.
   1.360 +      if (!mFrameLoader)
   1.361 +        return;
   1.362 +      nsCOMPtr<nsIDocShell> docShell;
   1.363 +      mFrameLoader->GetDocShell(getter_AddRefs(docShell));
   1.364 +      if (!docShell)
   1.365 +        return;
   1.366 +      presShell = docShell->GetPresShell();
   1.367 +      if (!presShell)
   1.368 +        return;
   1.369 +    }
   1.370 +  }
   1.371 +
   1.372 +  nsPresContext* presContext = presShell->GetPresContext();
   1.373 +
   1.374 +  int32_t parentAPD = PresContext()->AppUnitsPerDevPixel();
   1.375 +  int32_t subdocAPD = presContext->AppUnitsPerDevPixel();
   1.376 +
   1.377 +  nsRect dirty;
   1.378 +  bool haveDisplayPort = false;
   1.379 +  bool ignoreViewportScrolling = false;
   1.380 +  nsIFrame* savedIgnoreScrollFrame = nullptr;
   1.381 +  if (subdocRootFrame) {
   1.382 +    // get the dirty rect relative to the root frame of the subdoc
   1.383 +    dirty = aDirtyRect + GetOffsetToCrossDoc(subdocRootFrame);
   1.384 +    // and convert into the appunits of the subdoc
   1.385 +    dirty = dirty.ConvertAppUnitsRoundOut(parentAPD, subdocAPD);
   1.386 +
   1.387 +    if (nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame()) {
   1.388 +      // for root content documents we want the base to be the composition bounds
   1.389 +      nsRect displayportBase = presContext->IsRootContentDocument() ?
   1.390 +          nsRect(nsPoint(0,0), nsLayoutUtils::CalculateCompositionSizeForFrame(rootScrollFrame)) :
   1.391 +          dirty.Intersect(nsRect(nsPoint(0,0), subdocRootFrame->GetSize()));
   1.392 +      nsRect displayPort;
   1.393 +      if (nsLayoutUtils::GetOrMaybeCreateDisplayPort(
   1.394 +            *aBuilder, rootScrollFrame, displayportBase, &displayPort)) {
   1.395 +        haveDisplayPort = true;
   1.396 +        dirty = displayPort;
   1.397 +      }
   1.398 +
   1.399 +      ignoreViewportScrolling = presShell->IgnoringViewportScrolling();
   1.400 +      if (ignoreViewportScrolling) {
   1.401 +        savedIgnoreScrollFrame = aBuilder->GetIgnoreScrollFrame();
   1.402 +        aBuilder->SetIgnoreScrollFrame(rootScrollFrame);
   1.403 +      }
   1.404 +    }
   1.405 +
   1.406 +    aBuilder->EnterPresShell(subdocRootFrame, dirty);
   1.407 +  }
   1.408 +
   1.409 +  DisplayListClipState::AutoSaveRestore clipState(aBuilder);
   1.410 +  if (ShouldClipSubdocument()) {
   1.411 +    clipState.ClipContainingBlockDescendantsToContentBox(aBuilder, this);
   1.412 +  }
   1.413 +
   1.414 +  nsIScrollableFrame *sf = presShell->GetRootScrollFrameAsScrollable();
   1.415 +  bool constructResolutionItem = subdocRootFrame &&
   1.416 +    (presShell->GetXResolution() != 1.0 || presShell->GetYResolution() != 1.0);
   1.417 +  bool constructZoomItem = subdocRootFrame && parentAPD != subdocAPD;
   1.418 +  bool needsOwnLayer = constructResolutionItem || constructZoomItem ||
   1.419 +    haveDisplayPort ||
   1.420 +    presContext->IsRootContentDocument() || (sf && sf->IsScrollingActive());
   1.421 +
   1.422 +  // Don't let in fixed pos propagate down to child documents. This makes
   1.423 +  // it a little less effective but doesn't regress an important case of a
   1.424 +  // child document being in a fixed pos element where we would do no occlusion
   1.425 +  // at all if we let it propagate down.
   1.426 +  nsDisplayListBuilder::AutoInFixedPosSetter
   1.427 +    buildingInFixedPos(aBuilder, false);
   1.428 +
   1.429 +  nsDisplayList childItems;
   1.430 +
   1.431 +  {
   1.432 +    DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder);
   1.433 +    if (needsOwnLayer) {
   1.434 +      // Clear current clip. There's no point in propagating it down, since
   1.435 +      // the layer we will construct will be clipped by the current clip.
   1.436 +      // In fact for nsDisplayZoom propagating it down would be incorrect since
   1.437 +      // nsDisplayZoom changes the meaning of appunits.
   1.438 +      nestedClipState.Clear();
   1.439 +    }
   1.440 +
   1.441 +    if (subdocRootFrame) {
   1.442 +      nsDisplayListBuilder::AutoCurrentScrollParentIdSetter idSetter(
   1.443 +          aBuilder,
   1.444 +          ignoreViewportScrolling && subdocRootFrame->GetContent()
   1.445 +              ? nsLayoutUtils::FindOrCreateIDFor(subdocRootFrame->GetContent())
   1.446 +              : aBuilder->GetCurrentScrollParentId());
   1.447 +
   1.448 +      aBuilder->SetAncestorHasTouchEventHandler(false);
   1.449 +      subdocRootFrame->
   1.450 +        BuildDisplayListForStackingContext(aBuilder, dirty, &childItems);
   1.451 +    }
   1.452 +
   1.453 +    if (!aBuilder->IsForEventDelivery()) {
   1.454 +      // If we are going to use a displayzoom below then any items we put under
   1.455 +      // it need to have underlying frames from the subdocument. So we need to
   1.456 +      // calculate the bounds based on which frame will be the underlying frame
   1.457 +      // for the canvas background color item.
   1.458 +      nsRect bounds = GetContentRectRelativeToSelf() +
   1.459 +        aBuilder->ToReferenceFrame(this);
   1.460 +      if (subdocRootFrame) {
   1.461 +        bounds = bounds.ConvertAppUnitsRoundOut(parentAPD, subdocAPD);
   1.462 +      }
   1.463 +
   1.464 +      // If we are in print preview/page layout we want to paint the grey
   1.465 +      // background behind the page, not the canvas color. The canvas color gets
   1.466 +      // painted on the page itself.
   1.467 +      if (nsLayoutUtils::NeedsPrintPreviewBackground(presContext)) {
   1.468 +        presShell->AddPrintPreviewBackgroundItem(
   1.469 +          *aBuilder, childItems, subdocRootFrame ? subdocRootFrame : this,
   1.470 +          bounds);
   1.471 +      } else {
   1.472 +        // Add the canvas background color to the bottom of the list. This
   1.473 +        // happens after we've built the list so that AddCanvasBackgroundColorItem
   1.474 +        // can monkey with the contents if necessary.
   1.475 +        uint32_t flags = nsIPresShell::FORCE_DRAW;
   1.476 +        presShell->AddCanvasBackgroundColorItem(
   1.477 +          *aBuilder, childItems, subdocRootFrame ? subdocRootFrame : this,
   1.478 +          bounds, NS_RGBA(0,0,0,0), flags);
   1.479 +      }
   1.480 +    }
   1.481 +  }
   1.482 +
   1.483 +  // Generate a resolution and/or zoom item if needed. If one or both of those is
   1.484 +  // created, we don't need to create a separate nsDisplaySubDocument.
   1.485 +
   1.486 +  uint32_t flags = nsDisplayOwnLayer::GENERATE_SUBDOC_INVALIDATIONS;
   1.487 +  // If ignoreViewportScrolling is true then the top most layer we create here
   1.488 +  // is going to become the scrollable layer for the root scroll frame, so we
   1.489 +  // want to add nsDisplayOwnLayer::GENERATE_SCROLLABLE_LAYER to whatever layer
   1.490 +  // becomes the topmost. We do this below.
   1.491 +  if (constructZoomItem) {
   1.492 +    uint32_t zoomFlags = flags;
   1.493 +    if (ignoreViewportScrolling && !constructResolutionItem) {
   1.494 +      zoomFlags |= nsDisplayOwnLayer::GENERATE_SCROLLABLE_LAYER;
   1.495 +    }
   1.496 +    nsDisplayZoom* zoomItem =
   1.497 +      new (aBuilder) nsDisplayZoom(aBuilder, subdocRootFrame, &childItems,
   1.498 +                                   subdocAPD, parentAPD, zoomFlags);
   1.499 +    childItems.AppendToTop(zoomItem);
   1.500 +    needsOwnLayer = false;
   1.501 +  }
   1.502 +  // Wrap the zoom item in the resolution item if we have both because we want the
   1.503 +  // resolution scale applied on top of the app units per dev pixel conversion.
   1.504 +  if (ignoreViewportScrolling) {
   1.505 +    flags |= nsDisplayOwnLayer::GENERATE_SCROLLABLE_LAYER;
   1.506 +  }
   1.507 +  if (constructResolutionItem) {
   1.508 +    nsDisplayResolution* resolutionItem =
   1.509 +      new (aBuilder) nsDisplayResolution(aBuilder, subdocRootFrame, &childItems,
   1.510 +                                         flags);
   1.511 +    childItems.AppendToTop(resolutionItem);
   1.512 +    needsOwnLayer = false;
   1.513 +  }
   1.514 +  if (needsOwnLayer) {
   1.515 +    // We always want top level content documents to be in their own layer.
   1.516 +    nsDisplaySubDocument* layerItem = new (aBuilder) nsDisplaySubDocument(
   1.517 +      aBuilder, subdocRootFrame ? subdocRootFrame : this,
   1.518 +      &childItems, flags);
   1.519 +    childItems.AppendToTop(layerItem);
   1.520 +  }
   1.521 +
   1.522 +  if (subdocRootFrame) {
   1.523 +    aBuilder->LeavePresShell(subdocRootFrame, dirty);
   1.524 +
   1.525 +    if (ignoreViewportScrolling) {
   1.526 +      aBuilder->SetIgnoreScrollFrame(savedIgnoreScrollFrame);
   1.527 +    }
   1.528 +  }
   1.529 +
   1.530 +  if (aBuilder->IsForImageVisibility()) {
   1.531 +    // We don't add the childItems to the return list as we're dealing with them here.
   1.532 +    presShell->RebuildImageVisibility(childItems);
   1.533 +    childItems.DeleteAll();
   1.534 +  } else {
   1.535 +    aLists.Content()->AppendToTop(&childItems);
   1.536 +  }
   1.537 +}
   1.538 +
   1.539 +nscoord
   1.540 +nsSubDocumentFrame::GetIntrinsicWidth()
   1.541 +{
   1.542 +  if (!IsInline()) {
   1.543 +    return 0;  // HTML <frame> has no useful intrinsic width
   1.544 +  }
   1.545 +
   1.546 +  if (mContent->IsXUL()) {
   1.547 +    return 0;  // XUL <iframe> and <browser> have no useful intrinsic width
   1.548 +  }
   1.549 +
   1.550 +  NS_ASSERTION(ObtainIntrinsicSizeFrame() == nullptr,
   1.551 +               "Intrinsic width should come from the embedded document.");
   1.552 +
   1.553 +  // We must be an HTML <iframe>.  Default to a width of 300, for IE
   1.554 +  // compat (and per CSS2.1 draft).
   1.555 +  return nsPresContext::CSSPixelsToAppUnits(300);
   1.556 +}
   1.557 +
   1.558 +nscoord
   1.559 +nsSubDocumentFrame::GetIntrinsicHeight()
   1.560 +{
   1.561 +  // <frame> processing does not use this routine, only <iframe>
   1.562 +  NS_ASSERTION(IsInline(), "Shouldn't have been called");
   1.563 +
   1.564 +  if (mContent->IsXUL()) {
   1.565 +    return 0;
   1.566 +  }
   1.567 +
   1.568 +  NS_ASSERTION(ObtainIntrinsicSizeFrame() == nullptr,
   1.569 +               "Intrinsic height should come from the embedded document.");
   1.570 +
   1.571 +  // Use 150px, for compatibility with IE, and per CSS2.1 draft.
   1.572 +  return nsPresContext::CSSPixelsToAppUnits(150);
   1.573 +}
   1.574 +
   1.575 +#ifdef DEBUG_FRAME_DUMP
   1.576 +void
   1.577 +nsSubDocumentFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
   1.578 +{
   1.579 +  nsCString str;
   1.580 +  ListGeneric(str, aPrefix, aFlags);
   1.581 +  fprintf_stderr(out, "%s\n", str.get());
   1.582 +
   1.583 +  if (aFlags & TRAVERSE_SUBDOCUMENT_FRAMES) {
   1.584 +    nsSubDocumentFrame* f = const_cast<nsSubDocumentFrame*>(this);
   1.585 +    nsIFrame* subdocRootFrame = f->GetSubdocumentRootFrame();
   1.586 +    if (subdocRootFrame) {
   1.587 +      nsCString pfx(aPrefix);
   1.588 +      pfx += "  ";
   1.589 +      subdocRootFrame->List(out, pfx.get(), aFlags);
   1.590 +    }
   1.591 +  }
   1.592 +}
   1.593 +
   1.594 +nsresult nsSubDocumentFrame::GetFrameName(nsAString& aResult) const
   1.595 +{
   1.596 +  return MakeFrameName(NS_LITERAL_STRING("FrameOuter"), aResult);
   1.597 +}
   1.598 +#endif
   1.599 +
   1.600 +nsIAtom*
   1.601 +nsSubDocumentFrame::GetType() const
   1.602 +{
   1.603 +  return nsGkAtoms::subDocumentFrame;
   1.604 +}
   1.605 +
   1.606 +/* virtual */ nscoord
   1.607 +nsSubDocumentFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
   1.608 +{
   1.609 +  nscoord result;
   1.610 +  DISPLAY_MIN_WIDTH(this, result);
   1.611 +
   1.612 +  nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
   1.613 +  if (subDocRoot) {
   1.614 +    result = subDocRoot->GetMinWidth(aRenderingContext);
   1.615 +  } else {
   1.616 +    result = GetIntrinsicWidth();
   1.617 +  }
   1.618 +
   1.619 +  return result;
   1.620 +}
   1.621 +
   1.622 +/* virtual */ nscoord
   1.623 +nsSubDocumentFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
   1.624 +{
   1.625 +  nscoord result;
   1.626 +  DISPLAY_PREF_WIDTH(this, result);
   1.627 +
   1.628 +  nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
   1.629 +  if (subDocRoot) {
   1.630 +    result = subDocRoot->GetPrefWidth(aRenderingContext);
   1.631 +  } else {
   1.632 +    result = GetIntrinsicWidth();
   1.633 +  }
   1.634 +
   1.635 +  return result;
   1.636 +}
   1.637 +
   1.638 +/* virtual */ IntrinsicSize
   1.639 +nsSubDocumentFrame::GetIntrinsicSize()
   1.640 +{
   1.641 +  nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
   1.642 +  if (subDocRoot) {
   1.643 +    return subDocRoot->GetIntrinsicSize();
   1.644 +  }
   1.645 +  return nsLeafFrame::GetIntrinsicSize();
   1.646 +}
   1.647 +
   1.648 +/* virtual */ nsSize
   1.649 +nsSubDocumentFrame::GetIntrinsicRatio()
   1.650 +{
   1.651 +  nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
   1.652 +  if (subDocRoot) {
   1.653 +    return subDocRoot->GetIntrinsicRatio();
   1.654 +  }
   1.655 +  return nsLeafFrame::GetIntrinsicRatio();
   1.656 +}
   1.657 +
   1.658 +/* virtual */ nsSize
   1.659 +nsSubDocumentFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext,
   1.660 +                                    nsSize aCBSize, nscoord aAvailableWidth,
   1.661 +                                    nsSize aMargin, nsSize aBorder,
   1.662 +                                    nsSize aPadding, bool aShrinkWrap)
   1.663 +{
   1.664 +  if (!IsInline()) {
   1.665 +    return nsFrame::ComputeAutoSize(aRenderingContext, aCBSize,
   1.666 +                                    aAvailableWidth, aMargin, aBorder,
   1.667 +                                    aPadding, aShrinkWrap);
   1.668 +  }
   1.669 +
   1.670 +  return nsLeafFrame::ComputeAutoSize(aRenderingContext, aCBSize,
   1.671 +                                      aAvailableWidth, aMargin, aBorder,
   1.672 +                                      aPadding, aShrinkWrap);  
   1.673 +}
   1.674 +
   1.675 +
   1.676 +/* virtual */ nsSize
   1.677 +nsSubDocumentFrame::ComputeSize(nsRenderingContext *aRenderingContext,
   1.678 +                                nsSize aCBSize, nscoord aAvailableWidth,
   1.679 +                                nsSize aMargin, nsSize aBorder, nsSize aPadding,
   1.680 +                                uint32_t aFlags)
   1.681 +{
   1.682 +  nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
   1.683 +  if (subDocRoot) {
   1.684 +    return nsLayoutUtils::ComputeSizeWithIntrinsicDimensions(
   1.685 +                            aRenderingContext, this,
   1.686 +                            subDocRoot->GetIntrinsicSize(),
   1.687 +                            subDocRoot->GetIntrinsicRatio(),
   1.688 +                            aCBSize, aMargin, aBorder, aPadding);
   1.689 +  }
   1.690 +  return nsLeafFrame::ComputeSize(aRenderingContext, aCBSize, aAvailableWidth,
   1.691 +                                  aMargin, aBorder, aPadding, aFlags);
   1.692 +}
   1.693 +
   1.694 +nsresult
   1.695 +nsSubDocumentFrame::Reflow(nsPresContext*           aPresContext,
   1.696 +                           nsHTMLReflowMetrics&     aDesiredSize,
   1.697 +                           const nsHTMLReflowState& aReflowState,
   1.698 +                           nsReflowStatus&          aStatus)
   1.699 +{
   1.700 +  DO_GLOBAL_REFLOW_COUNT("nsSubDocumentFrame");
   1.701 +  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
   1.702 +  // printf("OuterFrame::Reflow %X (%d,%d) \n", this, aReflowState.AvailableWidth(), aReflowState.AvailableHeight());
   1.703 +  NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
   1.704 +     ("enter nsSubDocumentFrame::Reflow: maxSize=%d,%d",
   1.705 +      aReflowState.AvailableWidth(), aReflowState.AvailableHeight()));
   1.706 +
   1.707 +  aStatus = NS_FRAME_COMPLETE;
   1.708 +
   1.709 +  NS_ASSERTION(mContent->GetPrimaryFrame() == this,
   1.710 +               "Shouldn't happen");
   1.711 +
   1.712 +  // XUL <iframe> or <browser>, or HTML <iframe>, <object> or <embed>
   1.713 +  nsresult rv = nsLeafFrame::DoReflow(aPresContext, aDesiredSize, aReflowState,
   1.714 +                                      aStatus);
   1.715 +  NS_ENSURE_SUCCESS(rv, rv);
   1.716 +
   1.717 +  // "offset" is the offset of our content area from our frame's
   1.718 +  // top-left corner.
   1.719 +  nsPoint offset = nsPoint(aReflowState.ComputedPhysicalBorderPadding().left,
   1.720 +                           aReflowState.ComputedPhysicalBorderPadding().top);
   1.721 +
   1.722 +  nsSize innerSize(aDesiredSize.Width(), aDesiredSize.Height());
   1.723 +  innerSize.width  -= aReflowState.ComputedPhysicalBorderPadding().LeftRight();
   1.724 +  innerSize.height -= aReflowState.ComputedPhysicalBorderPadding().TopBottom();
   1.725 +
   1.726 +  if (mInnerView) {
   1.727 +    nsViewManager* vm = mInnerView->GetViewManager();
   1.728 +    vm->MoveViewTo(mInnerView, offset.x, offset.y);
   1.729 +    vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), innerSize), true);
   1.730 +  }
   1.731 +
   1.732 +  aDesiredSize.SetOverflowAreasToDesiredBounds();
   1.733 +  if (!ShouldClipSubdocument()) {
   1.734 +    nsIFrame* subdocRootFrame = GetSubdocumentRootFrame();
   1.735 +    if (subdocRootFrame) {
   1.736 +      aDesiredSize.mOverflowAreas.UnionWith(subdocRootFrame->GetOverflowAreas() + offset);
   1.737 +    }
   1.738 +  }
   1.739 +
   1.740 +  FinishAndStoreOverflow(&aDesiredSize);
   1.741 +
   1.742 +  if (!aPresContext->IsPaginated() && !mPostedReflowCallback) {
   1.743 +    PresContext()->PresShell()->PostReflowCallback(this);
   1.744 +    mPostedReflowCallback = true;
   1.745 +  }
   1.746 +
   1.747 +  // printf("OuterFrame::Reflow DONE %X (%d,%d)\n", this,
   1.748 +  //        aDesiredSize.Width(), aDesiredSize.Height());
   1.749 +
   1.750 +  NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
   1.751 +     ("exit nsSubDocumentFrame::Reflow: size=%d,%d status=%x",
   1.752 +      aDesiredSize.Width(), aDesiredSize.Height(), aStatus));
   1.753 +
   1.754 +  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
   1.755 +  return NS_OK;
   1.756 +}
   1.757 +
   1.758 +bool
   1.759 +nsSubDocumentFrame::ReflowFinished()
   1.760 +{
   1.761 +  if (mFrameLoader) {
   1.762 +    nsWeakFrame weakFrame(this);
   1.763 +
   1.764 +    mFrameLoader->UpdatePositionAndSize(this);
   1.765 +
   1.766 +    if (weakFrame.IsAlive()) {
   1.767 +      // Make sure that we can post a reflow callback in the future.
   1.768 +      mPostedReflowCallback = false;
   1.769 +    }
   1.770 +  } else {
   1.771 +    mPostedReflowCallback = false;
   1.772 +  }
   1.773 +  return false;
   1.774 +}
   1.775 +
   1.776 +void
   1.777 +nsSubDocumentFrame::ReflowCallbackCanceled()
   1.778 +{
   1.779 +  mPostedReflowCallback = false;
   1.780 +}
   1.781 +
   1.782 +nsresult
   1.783 +nsSubDocumentFrame::AttributeChanged(int32_t aNameSpaceID,
   1.784 +                                     nsIAtom* aAttribute,
   1.785 +                                     int32_t aModType)
   1.786 +{
   1.787 +  if (aNameSpaceID != kNameSpaceID_None) {
   1.788 +    return NS_OK;
   1.789 +  }
   1.790 +  
   1.791 +  // If the noResize attribute changes, dis/allow frame to be resized
   1.792 +  if (aAttribute == nsGkAtoms::noresize) {
   1.793 +    // Note that we're not doing content type checks, but that's ok -- if
   1.794 +    // they'd fail we will just end up with a null framesetFrame.
   1.795 +    if (mContent->GetParent()->Tag() == nsGkAtoms::frameset) {
   1.796 +      nsIFrame* parentFrame = GetParent();
   1.797 +
   1.798 +      if (parentFrame) {
   1.799 +        // There is no interface for nsHTMLFramesetFrame so QI'ing to
   1.800 +        // concrete class, yay!
   1.801 +        nsHTMLFramesetFrame* framesetFrame = do_QueryFrame(parentFrame);
   1.802 +        if (framesetFrame) {
   1.803 +          framesetFrame->RecalculateBorderResize();
   1.804 +        }
   1.805 +      }
   1.806 +    }
   1.807 +  }
   1.808 +  else if (aAttribute == nsGkAtoms::showresizer) {
   1.809 +    nsIFrame* rootFrame = GetSubdocumentRootFrame();
   1.810 +    if (rootFrame) {
   1.811 +      rootFrame->PresContext()->PresShell()->
   1.812 +        FrameNeedsReflow(rootFrame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
   1.813 +    }
   1.814 +  }
   1.815 +  else if (aAttribute == nsGkAtoms::marginwidth ||
   1.816 +           aAttribute == nsGkAtoms::marginheight) {
   1.817 +
   1.818 +    // Retrieve the attributes
   1.819 +    nsIntSize margins = GetMarginAttributes();
   1.820 +
   1.821 +    // Notify the frameloader
   1.822 +    nsRefPtr<nsFrameLoader> frameloader = FrameLoader();
   1.823 +    if (frameloader)
   1.824 +      frameloader->MarginsChanged(margins.width, margins.height);
   1.825 +  }
   1.826 +
   1.827 +  return NS_OK;
   1.828 +}
   1.829 +
   1.830 +nsIFrame*
   1.831 +NS_NewSubDocumentFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
   1.832 +{
   1.833 +  return new (aPresShell) nsSubDocumentFrame(aContext);
   1.834 +}
   1.835 +
   1.836 +NS_IMPL_FRAMEARENA_HELPERS(nsSubDocumentFrame)
   1.837 +
   1.838 +class nsHideViewer : public nsRunnable {
   1.839 +public:
   1.840 +  nsHideViewer(nsIContent* aFrameElement,
   1.841 +               nsFrameLoader* aFrameLoader,
   1.842 +               nsIPresShell* aPresShell,
   1.843 +               bool aHideViewerIfFrameless)
   1.844 +    : mFrameElement(aFrameElement),
   1.845 +      mFrameLoader(aFrameLoader),
   1.846 +      mPresShell(aPresShell),
   1.847 +      mHideViewerIfFrameless(aHideViewerIfFrameless)
   1.848 +  {
   1.849 +    NS_ASSERTION(mFrameElement, "Must have a frame element");
   1.850 +    NS_ASSERTION(mFrameLoader, "Must have a frame loader");
   1.851 +    NS_ASSERTION(mPresShell, "Must have a presshell");
   1.852 +  }
   1.853 +
   1.854 +  NS_IMETHOD Run()
   1.855 +  {
   1.856 +    // Flush frames, to ensure any pending display:none changes are made.
   1.857 +    // Note it can be unsafe to flush if we've destroyed the presentation
   1.858 +    // for some other reason, like if we're shutting down.
   1.859 +    if (!mPresShell->IsDestroying()) {
   1.860 +      mPresShell->FlushPendingNotifications(Flush_Frames);
   1.861 +    }
   1.862 +    nsIFrame* frame = mFrameElement->GetPrimaryFrame();
   1.863 +    if ((!frame && mHideViewerIfFrameless) ||
   1.864 +        mPresShell->IsDestroying()) {
   1.865 +      // Either the frame element has no nsIFrame or the presshell is being
   1.866 +      // destroyed. Hide the nsFrameLoader, which destroys the presentation,
   1.867 +      // and clear our references to the stashed presentation.
   1.868 +      mFrameLoader->SetDetachedSubdocView(nullptr, nullptr);
   1.869 +      mFrameLoader->Hide();
   1.870 +    }
   1.871 +    return NS_OK;
   1.872 +  }
   1.873 +private:
   1.874 +  nsCOMPtr<nsIContent> mFrameElement;
   1.875 +  nsRefPtr<nsFrameLoader> mFrameLoader;
   1.876 +  nsCOMPtr<nsIPresShell> mPresShell;
   1.877 +  bool mHideViewerIfFrameless;
   1.878 +};
   1.879 +
   1.880 +static nsView*
   1.881 +BeginSwapDocShellsForViews(nsView* aSibling);
   1.882 +
   1.883 +void
   1.884 +nsSubDocumentFrame::DestroyFrom(nsIFrame* aDestructRoot)
   1.885 +{
   1.886 +  if (mPostedReflowCallback) {
   1.887 +    PresContext()->PresShell()->CancelReflowCallback(this);
   1.888 +    mPostedReflowCallback = false;
   1.889 +  }
   1.890 +
   1.891 +  // Detach the subdocument's views and stash them in the frame loader.
   1.892 +  // We can then reattach them if we're being reframed (for example if
   1.893 +  // the frame has been made position:fixed).
   1.894 +  nsFrameLoader* frameloader = FrameLoader();
   1.895 +  if (frameloader) {
   1.896 +    nsView* detachedViews = ::BeginSwapDocShellsForViews(mInnerView->GetFirstChild());
   1.897 +    frameloader->SetDetachedSubdocView(detachedViews, mContent->OwnerDoc());
   1.898 +
   1.899 +    // We call nsFrameLoader::HideViewer() in a script runner so that we can
   1.900 +    // safely determine whether the frame is being reframed or destroyed.
   1.901 +    nsContentUtils::AddScriptRunner(
   1.902 +      new nsHideViewer(mContent,
   1.903 +                       mFrameLoader,
   1.904 +                       PresContext()->PresShell(),
   1.905 +                       (mDidCreateDoc || mCallingShow)));
   1.906 +  }
   1.907 +
   1.908 +  nsLeafFrame::DestroyFrom(aDestructRoot);
   1.909 +}
   1.910 +
   1.911 +nsIntSize
   1.912 +nsSubDocumentFrame::GetMarginAttributes()
   1.913 +{
   1.914 +  nsIntSize result(-1, -1);
   1.915 +  nsGenericHTMLElement *content = nsGenericHTMLElement::FromContent(mContent);
   1.916 +  if (content) {
   1.917 +    const nsAttrValue* attr = content->GetParsedAttr(nsGkAtoms::marginwidth);
   1.918 +    if (attr && attr->Type() == nsAttrValue::eInteger)
   1.919 +      result.width = attr->GetIntegerValue();
   1.920 +    attr = content->GetParsedAttr(nsGkAtoms::marginheight);
   1.921 +    if (attr && attr->Type() == nsAttrValue::eInteger)
   1.922 +      result.height = attr->GetIntegerValue();
   1.923 +  }
   1.924 +  return result;
   1.925 +}
   1.926 +
   1.927 +nsFrameLoader*
   1.928 +nsSubDocumentFrame::FrameLoader()
   1.929 +{
   1.930 +  nsIContent* content = GetContent();
   1.931 +  if (!content)
   1.932 +    return nullptr;
   1.933 +
   1.934 +  if (!mFrameLoader) {
   1.935 +    nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(content);
   1.936 +    if (loaderOwner) {
   1.937 +      nsCOMPtr<nsIFrameLoader> loader;
   1.938 +      loaderOwner->GetFrameLoader(getter_AddRefs(loader));
   1.939 +      mFrameLoader = static_cast<nsFrameLoader*>(loader.get());
   1.940 +    }
   1.941 +  }
   1.942 +  return mFrameLoader;
   1.943 +}
   1.944 +
   1.945 +// XXX this should be called ObtainDocShell or something like that,
   1.946 +// to indicate that it could have side effects
   1.947 +nsresult
   1.948 +nsSubDocumentFrame::GetDocShell(nsIDocShell **aDocShell)
   1.949 +{
   1.950 +  *aDocShell = nullptr;
   1.951 +
   1.952 +  NS_ENSURE_STATE(FrameLoader());
   1.953 +  return mFrameLoader->GetDocShell(aDocShell);
   1.954 +}
   1.955 +
   1.956 +static void
   1.957 +DestroyDisplayItemDataForFrames(nsIFrame* aFrame)
   1.958 +{
   1.959 +  FrameLayerBuilder::DestroyDisplayItemDataFor(aFrame);
   1.960 +
   1.961 +  nsIFrame::ChildListIterator lists(aFrame);
   1.962 +  for (; !lists.IsDone(); lists.Next()) {
   1.963 +    nsFrameList::Enumerator childFrames(lists.CurrentList());
   1.964 +    for (; !childFrames.AtEnd(); childFrames.Next()) {
   1.965 +      DestroyDisplayItemDataForFrames(childFrames.get());
   1.966 +    }
   1.967 +  }
   1.968 +}
   1.969 +
   1.970 +static bool
   1.971 +BeginSwapDocShellsForDocument(nsIDocument* aDocument, void*)
   1.972 +{
   1.973 +  NS_PRECONDITION(aDocument, "");
   1.974 +
   1.975 +  nsIPresShell* shell = aDocument->GetShell();
   1.976 +  if (shell) {
   1.977 +    // Disable painting while the views are detached, see bug 946929.
   1.978 +    shell->SetNeverPainting(true);
   1.979 +
   1.980 +    nsIFrame* rootFrame = shell->GetRootFrame();
   1.981 +    if (rootFrame) {
   1.982 +      ::DestroyDisplayItemDataForFrames(rootFrame);
   1.983 +    }
   1.984 +  }
   1.985 +  aDocument->EnumerateFreezableElements(
   1.986 +    nsObjectFrame::BeginSwapDocShells, nullptr);
   1.987 +  aDocument->EnumerateSubDocuments(BeginSwapDocShellsForDocument, nullptr);
   1.988 +  return true;
   1.989 +}
   1.990 +
   1.991 +static nsView*
   1.992 +BeginSwapDocShellsForViews(nsView* aSibling)
   1.993 +{
   1.994 +  // Collect the removed sibling views in reverse order in 'removedViews'.
   1.995 +  nsView* removedViews = nullptr;
   1.996 +  while (aSibling) {
   1.997 +    nsIDocument* doc = ::GetDocumentFromView(aSibling);
   1.998 +    if (doc) {
   1.999 +      ::BeginSwapDocShellsForDocument(doc, nullptr);
  1.1000 +    }
  1.1001 +    nsView* next = aSibling->GetNextSibling();
  1.1002 +    aSibling->GetViewManager()->RemoveChild(aSibling);
  1.1003 +    aSibling->SetNextSibling(removedViews);
  1.1004 +    removedViews = aSibling;
  1.1005 +    aSibling = next;
  1.1006 +  }
  1.1007 +  return removedViews;
  1.1008 +}
  1.1009 +
  1.1010 +static void
  1.1011 +InsertViewsInReverseOrder(nsView* aSibling, nsView* aParent)
  1.1012 +{
  1.1013 +  NS_PRECONDITION(aParent, "");
  1.1014 +  NS_PRECONDITION(!aParent->GetFirstChild(), "inserting into non-empty list");
  1.1015 +
  1.1016 +  nsViewManager* vm = aParent->GetViewManager();
  1.1017 +  while (aSibling) {
  1.1018 +    nsView* next = aSibling->GetNextSibling();
  1.1019 +    aSibling->SetNextSibling(nullptr);
  1.1020 +    // true means 'after' in document order which is 'before' in view order,
  1.1021 +    // so this call prepends the child, thus reversing the siblings as we go.
  1.1022 +    vm->InsertChild(aParent, aSibling, nullptr, true);
  1.1023 +    aSibling = next;
  1.1024 +  }
  1.1025 +}
  1.1026 +
  1.1027 +nsresult
  1.1028 +nsSubDocumentFrame::BeginSwapDocShells(nsIFrame* aOther)
  1.1029 +{
  1.1030 +  if (!aOther || aOther->GetType() != nsGkAtoms::subDocumentFrame) {
  1.1031 +    return NS_ERROR_NOT_IMPLEMENTED;
  1.1032 +  }
  1.1033 +
  1.1034 +  nsSubDocumentFrame* other = static_cast<nsSubDocumentFrame*>(aOther);
  1.1035 +  if (!mFrameLoader || !mDidCreateDoc || mCallingShow ||
  1.1036 +      !other->mFrameLoader || !other->mDidCreateDoc) {
  1.1037 +    return NS_ERROR_NOT_IMPLEMENTED;
  1.1038 +  }
  1.1039 +
  1.1040 +  if (mInnerView && other->mInnerView) {
  1.1041 +    nsView* ourSubdocViews = mInnerView->GetFirstChild();
  1.1042 +    nsView* ourRemovedViews = ::BeginSwapDocShellsForViews(ourSubdocViews);
  1.1043 +    nsView* otherSubdocViews = other->mInnerView->GetFirstChild();
  1.1044 +    nsView* otherRemovedViews = ::BeginSwapDocShellsForViews(otherSubdocViews);
  1.1045 +
  1.1046 +    ::InsertViewsInReverseOrder(ourRemovedViews, other->mInnerView);
  1.1047 +    ::InsertViewsInReverseOrder(otherRemovedViews, mInnerView);
  1.1048 +  }
  1.1049 +  mFrameLoader.swap(other->mFrameLoader);
  1.1050 +  return NS_OK;
  1.1051 +}
  1.1052 +
  1.1053 +static bool
  1.1054 +EndSwapDocShellsForDocument(nsIDocument* aDocument, void*)
  1.1055 +{
  1.1056 +  NS_PRECONDITION(aDocument, "");
  1.1057 +
  1.1058 +  // Our docshell and view trees have been updated for the new hierarchy.
  1.1059 +  // Now also update all nsDeviceContext::mWidget to that of the
  1.1060 +  // container view in the new hierarchy.
  1.1061 +  nsCOMPtr<nsIDocShell> ds = aDocument->GetDocShell();
  1.1062 +  if (ds) {
  1.1063 +    nsCOMPtr<nsIContentViewer> cv;
  1.1064 +    ds->GetContentViewer(getter_AddRefs(cv));
  1.1065 +    while (cv) {
  1.1066 +      nsRefPtr<nsPresContext> pc;
  1.1067 +      cv->GetPresContext(getter_AddRefs(pc));
  1.1068 +      if (pc && pc->GetPresShell()) {
  1.1069 +        pc->GetPresShell()->SetNeverPainting(ds->IsInvisible());
  1.1070 +      }
  1.1071 +      nsDeviceContext* dc = pc ? pc->DeviceContext() : nullptr;
  1.1072 +      if (dc) {
  1.1073 +        nsView* v = cv->FindContainerView();
  1.1074 +        dc->Init(v ? v->GetNearestWidget(nullptr) : nullptr);
  1.1075 +      }
  1.1076 +      nsCOMPtr<nsIContentViewer> prev;
  1.1077 +      cv->GetPreviousViewer(getter_AddRefs(prev));
  1.1078 +      cv = prev;
  1.1079 +    }
  1.1080 +  }
  1.1081 +
  1.1082 +  aDocument->EnumerateFreezableElements(
  1.1083 +    nsObjectFrame::EndSwapDocShells, nullptr);
  1.1084 +  aDocument->EnumerateSubDocuments(EndSwapDocShellsForDocument, nullptr);
  1.1085 +  return true;
  1.1086 +}
  1.1087 +
  1.1088 +static void
  1.1089 +EndSwapDocShellsForViews(nsView* aSibling)
  1.1090 +{
  1.1091 +  for ( ; aSibling; aSibling = aSibling->GetNextSibling()) {
  1.1092 +    nsIDocument* doc = ::GetDocumentFromView(aSibling);
  1.1093 +    if (doc) {
  1.1094 +      ::EndSwapDocShellsForDocument(doc, nullptr);
  1.1095 +    }
  1.1096 +    nsIFrame *frame = aSibling->GetFrame();
  1.1097 +    if (frame) {
  1.1098 +      nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(frame);
  1.1099 +      if (parent->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
  1.1100 +        nsIFrame::AddInPopupStateBitToDescendants(frame);
  1.1101 +      } else {
  1.1102 +        nsIFrame::RemoveInPopupStateBitFromDescendants(frame);
  1.1103 +      }
  1.1104 +      if (frame->HasInvalidFrameInSubtree()) {
  1.1105 +        while (parent && !parent->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) {
  1.1106 +          parent->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT);
  1.1107 +          parent = nsLayoutUtils::GetCrossDocParentFrame(parent);
  1.1108 +        }
  1.1109 +      }
  1.1110 +    }
  1.1111 +  }
  1.1112 +}
  1.1113 +
  1.1114 +void
  1.1115 +nsSubDocumentFrame::EndSwapDocShells(nsIFrame* aOther)
  1.1116 +{
  1.1117 +  nsSubDocumentFrame* other = static_cast<nsSubDocumentFrame*>(aOther);
  1.1118 +  nsWeakFrame weakThis(this);
  1.1119 +  nsWeakFrame weakOther(aOther);
  1.1120 +
  1.1121 +  if (mInnerView) {
  1.1122 +    ::EndSwapDocShellsForViews(mInnerView->GetFirstChild());
  1.1123 +  }
  1.1124 +  if (other->mInnerView) {
  1.1125 +    ::EndSwapDocShellsForViews(other->mInnerView->GetFirstChild());
  1.1126 +  }
  1.1127 +
  1.1128 +  // Now make sure we reflow both frames, in case their contents
  1.1129 +  // determine their size.
  1.1130 +  // And repaint them, for good measure, in case there's nothing
  1.1131 +  // interesting that happens during reflow.
  1.1132 +  if (weakThis.IsAlive()) {
  1.1133 +    PresContext()->PresShell()->
  1.1134 +      FrameNeedsReflow(this, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
  1.1135 +    InvalidateFrameSubtree();
  1.1136 +  }
  1.1137 +  if (weakOther.IsAlive()) {
  1.1138 +    other->PresContext()->PresShell()->
  1.1139 +      FrameNeedsReflow(other, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
  1.1140 +    other->InvalidateFrameSubtree();
  1.1141 +  }
  1.1142 +}
  1.1143 +
  1.1144 +nsView*
  1.1145 +nsSubDocumentFrame::EnsureInnerView()
  1.1146 +{
  1.1147 +  if (mInnerView) {
  1.1148 +    return mInnerView;
  1.1149 +  }
  1.1150 +
  1.1151 +  // create, init, set the parent of the view
  1.1152 +  nsView* outerView = GetView();
  1.1153 +  NS_ASSERTION(outerView, "Must have an outer view already");
  1.1154 +  nsRect viewBounds(0, 0, 0, 0); // size will be fixed during reflow
  1.1155 +
  1.1156 +  nsViewManager* viewMan = outerView->GetViewManager();
  1.1157 +  nsView* innerView = viewMan->CreateView(viewBounds, outerView);
  1.1158 +  if (!innerView) {
  1.1159 +    NS_ERROR("Could not create inner view");
  1.1160 +    return nullptr;
  1.1161 +  }
  1.1162 +  mInnerView = innerView;
  1.1163 +  viewMan->InsertChild(outerView, innerView, nullptr, true);
  1.1164 +
  1.1165 +  return mInnerView;
  1.1166 +}
  1.1167 +
  1.1168 +nsIFrame*
  1.1169 +nsSubDocumentFrame::ObtainIntrinsicSizeFrame()
  1.1170 +{
  1.1171 +  nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(GetContent());
  1.1172 +  if (olc) {
  1.1173 +    // We are an HTML <object>, <embed> or <applet> (a replaced element).
  1.1174 +
  1.1175 +    // Try to get an nsIFrame for our sub-document's document element
  1.1176 +    nsIFrame* subDocRoot = nullptr;
  1.1177 +
  1.1178 +    nsCOMPtr<nsIDocShell> docShell;
  1.1179 +    GetDocShell(getter_AddRefs(docShell));
  1.1180 +    if (docShell) {
  1.1181 +      nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell();
  1.1182 +      if (presShell) {
  1.1183 +        nsIScrollableFrame* scrollable = presShell->GetRootScrollFrameAsScrollable();
  1.1184 +        if (scrollable) {
  1.1185 +          nsIFrame* scrolled = scrollable->GetScrolledFrame();
  1.1186 +          if (scrolled) {
  1.1187 +            subDocRoot = scrolled->GetFirstPrincipalChild();
  1.1188 +          }
  1.1189 +        }
  1.1190 +      }
  1.1191 +    }
  1.1192 +
  1.1193 +    if (subDocRoot && subDocRoot->GetContent() &&
  1.1194 +        subDocRoot->GetContent()->NodeInfo()->Equals(nsGkAtoms::svg, kNameSpaceID_SVG)) {
  1.1195 +      return subDocRoot; // SVG documents have an intrinsic size
  1.1196 +    }
  1.1197 +  }
  1.1198 +  return nullptr;
  1.1199 +}

mercurial