layout/generic/nsSubDocumentFrame.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial