nsSubDocumentFrame.cpp (46228B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* 8 * rendering object for replaced elements that contain a document, such 9 * as <frame>, <iframe>, and some <object>s 10 */ 11 12 #include "nsSubDocumentFrame.h" 13 14 #include "RetainedDisplayListBuilder.h" 15 #include "mozilla/ComputedStyleInlines.h" 16 #include "mozilla/Preferences.h" 17 #include "mozilla/PresShell.h" 18 #include "mozilla/ProfilerLabels.h" 19 #include "mozilla/ScrollContainerFrame.h" 20 #include "mozilla/StaticPrefs_layout.h" 21 #include "mozilla/dom/BrowserParent.h" 22 #include "mozilla/dom/Document.h" 23 #include "mozilla/dom/HTMLFrameElement.h" 24 #include "mozilla/dom/ImageDocument.h" 25 #include "mozilla/dom/RemoteBrowser.h" 26 #include "mozilla/layers/RenderRootStateManager.h" 27 #include "mozilla/layers/StackingContextHelper.h" // for StackingContextHelper 28 #include "mozilla/layers/WebRenderScrollData.h" 29 #include "mozilla/layers/WebRenderUserData.h" 30 #include "nsAttrValueInlines.h" 31 #include "nsCOMPtr.h" 32 #include "nsContentUtils.h" 33 #include "nsDeviceContext.h" 34 #include "nsDisplayList.h" 35 #include "nsFrameSetFrame.h" 36 #include "nsGenericHTMLElement.h" 37 #include "nsGenericHTMLFrameElement.h" 38 #include "nsGkAtoms.h" 39 #include "nsIContentInlines.h" 40 #include "nsIDocShell.h" 41 #include "nsIDocumentViewer.h" 42 #include "nsIObjectLoadingContent.h" 43 #include "nsIWeakReferenceUtils.h" 44 #include "nsLayoutUtils.h" 45 #include "nsNameSpaceManager.h" 46 #include "nsObjectLoadingContent.h" 47 #include "nsPresContext.h" 48 #include "nsQueryObject.h" 49 #include "nsServiceManagerUtils.h" 50 #include "nsStyleConsts.h" 51 #include "nsStyleStruct.h" 52 #include "nsStyleStructInlines.h" 53 54 using namespace mozilla; 55 using namespace mozilla::dom; 56 using namespace mozilla::gfx; 57 using namespace mozilla::layers; 58 59 static void PropagateIsUnderHiddenEmbedderElement(nsFrameLoader* aFrameLoader, 60 bool aValue) { 61 if (!aFrameLoader) { 62 return; 63 } 64 65 if (BrowsingContext* bc = aFrameLoader->GetExtantBrowsingContext()) { 66 if (bc->IsUnderHiddenEmbedderElement() != aValue) { 67 (void)bc->SetIsUnderHiddenEmbedderElement(aValue); 68 } 69 } 70 } 71 72 nsSubDocumentFrame::nsSubDocumentFrame(ComputedStyle* aStyle, 73 nsPresContext* aPresContext) 74 : nsAtomicContainerFrame(aStyle, aPresContext, kClassID), 75 mIsInline(false), 76 mPostedReflowCallback(false), 77 mDidCreateDoc(false), 78 mCallingShow(false), 79 mIsInObjectOrEmbed(false) {} 80 81 #ifdef ACCESSIBILITY 82 a11y::AccType nsSubDocumentFrame::AccessibleType() { 83 return a11y::eOuterDocType; 84 } 85 #endif 86 87 NS_QUERYFRAME_HEAD(nsSubDocumentFrame) 88 NS_QUERYFRAME_ENTRY(nsSubDocumentFrame) 89 NS_QUERYFRAME_TAIL_INHERITING(nsAtomicContainerFrame) 90 91 class AsyncFrameInit : public Runnable { 92 public: 93 explicit AsyncFrameInit(nsIFrame* aFrame) 94 : mozilla::Runnable("AsyncFrameInit"), mFrame(aFrame) {} 95 NS_IMETHOD Run() override { 96 AUTO_PROFILER_LABEL("AsyncFrameInit::Run", OTHER); 97 if (mFrame.IsAlive()) { 98 static_cast<nsSubDocumentFrame*>(mFrame.GetFrame())->ShowViewer(); 99 } 100 return NS_OK; 101 } 102 103 private: 104 WeakFrame mFrame; 105 }; 106 107 void nsSubDocumentFrame::EnsureEmbeddingPresShell(class PresShell* aPs) { 108 MOZ_ASSERT(aPs); 109 nsWeakPtr weakRef = do_GetWeakReference(aPs); 110 if (!mInProcessPresShells.Contains(weakRef)) { 111 aPs->SetInProcessEmbedderFrame(this); 112 mInProcessPresShells.AppendElement(std::move(weakRef)); 113 } 114 } 115 116 void nsSubDocumentFrame::AddEmbeddingPresShell(class PresShell* aPs) { 117 MOZ_ASSERT(aPs); 118 nsWeakPtr weakRef = do_GetWeakReference(aPs); 119 MOZ_ASSERT(!mInProcessPresShells.Contains(weakRef)); 120 aPs->SetInProcessEmbedderFrame(this); 121 mInProcessPresShells.AppendElement(std::move(weakRef)); 122 } 123 124 void nsSubDocumentFrame::RemoveEmbeddingPresShell(class PresShell* aPs) { 125 MOZ_ASSERT(aPs); 126 nsWeakPtr weakRef = do_GetWeakReference(aPs); 127 MOZ_ASSERT(mInProcessPresShells.Contains(weakRef)); 128 aPs->SetInProcessEmbedderFrame(nullptr); 129 if (mLastPaintedPresShell == weakRef) { 130 mLastPaintedPresShell = nullptr; 131 } 132 mInProcessPresShells.RemoveElement(weakRef); 133 } 134 135 void nsSubDocumentFrame::Init(nsIContent* aContent, nsContainerFrame* aParent, 136 nsIFrame* aPrevInFlow) { 137 MOZ_ASSERT(aContent); 138 // determine if we are a <frame> or <iframe> 139 mIsInline = !aContent->IsHTMLElement(nsGkAtoms::frame); 140 141 nsAtomicContainerFrame::Init(aContent, aParent, aPrevInFlow); 142 143 aContent->SetPrimaryFrame(this); 144 145 // If we have a detached subdoc's root view on our frame loader, re-insert it 146 // into the view tree. This happens when we've been reframed, and ensures the 147 // presentation persists across reframes. 148 if (RefPtr<nsFrameLoader> frameloader = FrameLoader()) { 149 mInProcessPresShells = frameloader->TakeDetachedSubdocs(); 150 const bool anyLiveShell = FixUpInProcessPresShellsAfterAttach(); 151 if (!mInProcessPresShells.IsEmpty() && !anyLiveShell) { 152 mInProcessPresShells.Clear(); 153 // Presentation is for a different document, don't restore it. 154 frameloader->Hide(); 155 } 156 } 157 158 // NOTE: The frame loader might not yet be initialized yet. If it's not, the 159 // call in ShowViewer() should pick things up. 160 UpdateEmbeddedBrowsingContextDependentData(); 161 nsContentUtils::AddScriptRunner(new AsyncFrameInit(this)); 162 } 163 164 void nsSubDocumentFrame::UpdateEmbeddedBrowsingContextDependentData() { 165 if (!mFrameLoader) { 166 return; 167 } 168 BrowsingContext* bc = mFrameLoader->GetExtantBrowsingContext(); 169 if (!bc) { 170 return; 171 } 172 mIsInObjectOrEmbed = bc->IsEmbedderTypeObjectOrEmbed(); 173 MaybeUpdateRemoteStyle(); 174 MaybeUpdateEmbedderColorScheme(); 175 MaybeUpdateEmbedderZoom(); 176 PropagateIsUnderHiddenEmbedderElement( 177 PresShell()->IsUnderHiddenEmbedderElement() || 178 !StyleVisibility()->IsVisible()); 179 } 180 181 void nsSubDocumentFrame::PropagateIsUnderHiddenEmbedderElement(bool aValue) { 182 ::PropagateIsUnderHiddenEmbedderElement(mFrameLoader, aValue); 183 } 184 185 void nsSubDocumentFrame::ShowViewer() { 186 if (mCallingShow) { 187 return; 188 } 189 190 RefPtr<nsFrameLoader> frameloader = FrameLoader(); 191 if (!frameloader || frameloader->IsDead()) { 192 return; 193 } 194 195 if (!frameloader->IsRemoteFrame() && !PresContext()->IsDynamic()) { 196 // We let the printing code take care of loading the document and 197 // initializing the shell. 198 } else { 199 AutoWeakFrame weakThis(this); 200 mCallingShow = true; 201 bool didCreateDoc = frameloader->Show(this); 202 if (!weakThis.IsAlive()) { 203 return; 204 } 205 mCallingShow = false; 206 mDidCreateDoc = didCreateDoc; 207 if (!HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) { 208 frameloader->UpdatePositionAndSize(this); 209 } 210 if (!weakThis.IsAlive()) { 211 return; 212 } 213 UpdateEmbeddedBrowsingContextDependentData(); 214 InvalidateFrame(); 215 } 216 } 217 218 Document* nsSubDocumentFrame::GetExtantSubdocument() { 219 nsIDocShell* ds = GetExtantDocShell(); 220 return ds ? ds->GetExtantDocument() : nullptr; 221 } 222 223 mozilla::PresShell* nsSubDocumentFrame::GetSubdocumentPresShell() { 224 Document* doc = GetExtantSubdocument(); 225 return doc ? doc->GetPresShell() : nullptr; 226 } 227 228 nsIFrame* nsSubDocumentFrame::GetSubdocumentRootFrame() { 229 mozilla::PresShell* ps = GetSubdocumentPresShell(); 230 return ps ? ps->GetRootFrame() : nullptr; 231 } 232 233 mozilla::PresShell* nsSubDocumentFrame::GetSubdocumentPresShellForPainting( 234 uint32_t aFlags) { 235 mozilla::PresShell* presShell = GetSubdocumentPresShell(); 236 if (presShell && (!presShell->IsPaintingSuppressed() || 237 (aFlags & IGNORE_PAINT_SUPPRESSION))) { 238 return presShell; 239 } 240 // If painting is suppressed in the presshell or there's no presShell, we try 241 // to look for a better presshell to use. 242 if (StaticPrefs::layout_show_previous_page()) { 243 RefPtr<mozilla::PresShell> old = do_QueryReferent(mLastPaintedPresShell); 244 if (old && old->GetInProcessEmbedderFrame() == this) { 245 return old; 246 } 247 } 248 return presShell; 249 } 250 251 nsRect nsSubDocumentFrame::GetDestRect() const { 252 const nsRect rect = GetContent()->IsHTMLElement(nsGkAtoms::frame) 253 ? GetRectRelativeToSelf() 254 : GetContentRectRelativeToSelf(); 255 return GetDestRect(rect); 256 } 257 258 nsRect nsSubDocumentFrame::GetDestRect(const nsRect& aConstraintRect) const { 259 // Adjust subdocument size, according to 'object-fit' and the subdocument's 260 // intrinsic size and ratio. 261 return nsLayoutUtils::ComputeObjectDestRect( 262 aConstraintRect, ComputeIntrinsicSize(/* aIgnoreContainment = */ true), 263 GetIntrinsicRatio(), StylePosition()); 264 } 265 266 LayoutDeviceIntSize nsSubDocumentFrame::GetInitialSubdocumentSize() const { 267 if (RefPtr<nsFrameLoader> frameloader = FrameLoader()) { 268 for (const auto& detachedShell : frameloader->GetDetachedSubdocs()) { 269 if (RefPtr<mozilla::PresShell> ps = do_QueryReferent(detachedShell)) { 270 if (nsPresContext* pc = ps->GetPresContext()) { 271 return LayoutDeviceIntSize( 272 pc->AppUnitsToDevPixels(pc->GetVisibleArea().width), 273 pc->AppUnitsToDevPixels(pc->GetVisibleArea().height)); 274 } 275 } 276 } 277 } 278 // Pick some default size for now. Using 10x10 because that's what the 279 // code used to do. 280 return LayoutDeviceIntSize(10, 10); 281 } 282 283 LayoutDeviceIntSize nsSubDocumentFrame::GetSubdocumentSize() const { 284 if (HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) { 285 return GetInitialSubdocumentSize(); 286 } 287 288 nsSize docSizeAppUnits = GetDestRect().Size(); 289 nsPresContext* pc = PresContext(); 290 return LayoutDeviceIntSize(pc->AppUnitsToDevPixels(docSizeAppUnits.width), 291 pc->AppUnitsToDevPixels(docSizeAppUnits.height)); 292 } 293 294 static void WrapBackgroundColorInOwnLayer(nsDisplayListBuilder* aBuilder, 295 nsIFrame* aFrame, 296 nsDisplayList* aList) { 297 for (nsDisplayItem* item : aList->TakeItems()) { 298 if (item->GetType() == DisplayItemType::TYPE_BACKGROUND_COLOR) { 299 nsDisplayList tmpList(aBuilder); 300 tmpList.AppendToTop(item); 301 item = MakeDisplayItemWithIndex<nsDisplayOwnLayer>( 302 aBuilder, aFrame, /* aIndex = */ nsDisplayOwnLayer::OwnLayerForSubdoc, 303 &tmpList, aBuilder->CurrentActiveScrolledRoot(), 304 nsDisplayItem::ContainerASRType::Constant, 305 nsDisplayOwnLayerFlags::None, ScrollbarData{}, true, false); 306 } 307 aList->AppendToTop(item); 308 } 309 } 310 311 void nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, 312 const nsDisplayListSet& aLists) { 313 if (!IsVisibleForPainting()) { 314 return; 315 } 316 317 const bool forEvents = aBuilder->IsForEventDelivery(); 318 if (forEvents && Style()->PointerEvents() == StylePointerEvents::None) { 319 // If we are pointer-events:none then we don't need to HitTest background or 320 // anything else. 321 return; 322 } 323 324 nsFrameLoader* frameLoader = FrameLoader(); 325 const bool isRemoteFrame = frameLoader && frameLoader->IsRemoteFrame(); 326 327 nsDisplayListCollection decorations(aBuilder); 328 DisplayBorderBackgroundOutline(aBuilder, decorations); 329 if (isRemoteFrame) { 330 // Wrap background colors of <iframe>s with remote subdocuments in their 331 // own layer so we generate a ColorLayer. This is helpful for optimizing 332 // compositing; we can skip compositing the ColorLayer when the 333 // remote content is opaque. 334 WrapBackgroundColorInOwnLayer(aBuilder, this, 335 decorations.BorderBackground()); 336 } 337 decorations.MoveTo(aLists); 338 339 if (forEvents && !ContentReactsToPointerEvents()) { 340 return; 341 } 342 343 if (HidesContent()) { 344 return; 345 } 346 347 // If we're passing pointer events to children then we have to descend into 348 // subdocuments no matter what, to determine which parts are transparent for 349 // hit-testing or event regions. 350 if (!aBuilder->GetDescendIntoSubdocuments()) { 351 return; 352 } 353 354 if (isRemoteFrame) { 355 // We're the subdoc for <browser remote="true"> and it has 356 // painted content. Display its shadow layer tree. 357 DisplayListClipState::AutoSaveRestore clipState(aBuilder); 358 clipState.ClipContainingBlockDescendantsToContentBox(aBuilder, this); 359 360 aLists.Content()->AppendNewToTop<nsDisplayRemote>(aBuilder, this); 361 return; 362 } 363 364 RefPtr<mozilla::PresShell> presShell = GetSubdocumentPresShellForPainting( 365 aBuilder->IsIgnoringPaintSuppression() ? IGNORE_PAINT_SUPPRESSION : 0); 366 367 if (!presShell) { 368 return; 369 } 370 371 if (aBuilder->IsForPainting() && !aBuilder->IsIgnoringPaintSuppression()) { 372 mLastPaintedPresShell = do_GetWeakReference(presShell); 373 } 374 375 if (aBuilder->IsInFilter()) { 376 Document* outerDoc = PresShell()->GetDocument(); 377 Document* innerDoc = presShell->GetDocument(); 378 if (outerDoc && innerDoc) { 379 if (!outerDoc->NodePrincipal()->Equals(innerDoc->NodePrincipal())) { 380 outerDoc->SetUseCounter(eUseCounter_custom_FilteredCrossOriginIFrame); 381 } 382 } 383 } 384 385 nsIFrame* subdocRootFrame = presShell->GetRootFrame(); 386 387 nsPresContext* presContext = presShell->GetPresContext(); 388 389 int32_t parentAPD = PresContext()->AppUnitsPerDevPixel(); 390 int32_t subdocAPD = presContext->AppUnitsPerDevPixel(); 391 392 nsRect visible; 393 nsRect dirty; 394 bool ignoreViewportScrolling = false; 395 if (subdocRootFrame) { 396 // get the dirty rect relative to the root frame of the subdoc 397 visible = aBuilder->GetVisibleRect() + GetOffsetToCrossDoc(subdocRootFrame); 398 dirty = aBuilder->GetDirtyRect() + GetOffsetToCrossDoc(subdocRootFrame); 399 // and convert into the appunits of the subdoc 400 visible = visible.ScaleToOtherAppUnitsRoundOut(parentAPD, subdocAPD); 401 dirty = dirty.ScaleToOtherAppUnitsRoundOut(parentAPD, subdocAPD); 402 403 if (ScrollContainerFrame* sf = presShell->GetRootScrollContainerFrame()) { 404 // Use a copy, so the rects don't get modified. 405 nsRect copyOfDirty = dirty; 406 nsRect copyOfVisible = visible; 407 // TODO(botond): Can we just axe this DecideScrollableLayer call? 408 sf->DecideScrollableLayer(aBuilder, ©OfVisible, ©OfDirty, 409 /* aSetBase = */ true); 410 411 ignoreViewportScrolling = presShell->IgnoringViewportScrolling(); 412 } 413 414 aBuilder->EnterPresShell(subdocRootFrame, !ContentReactsToPointerEvents()); 415 aBuilder->IncrementPresShellPaintCount(presShell); 416 } else { 417 visible = aBuilder->GetVisibleRect(); 418 dirty = aBuilder->GetDirtyRect(); 419 } 420 421 DisplayListClipState::AutoSaveRestore clipState(aBuilder); 422 clipState.ClipContainingBlockDescendantsToContentBox(aBuilder, this); 423 424 ScrollContainerFrame* sf = presShell->GetRootScrollContainerFrame(); 425 bool constructZoomItem = subdocRootFrame && parentAPD != subdocAPD; 426 bool needsOwnLayer = constructZoomItem || 427 presContext->IsRootContentDocumentCrossProcess() || 428 (sf && sf->IsScrollingActive()); 429 430 nsDisplayList childItems(aBuilder); 431 432 if (subdocRootFrame) { 433 DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder); 434 if (needsOwnLayer) { 435 // Clear current clip. There's no point in propagating it down, since 436 // the layer we will construct will be clipped by the current clip. 437 // In fact for nsDisplayZoom propagating it down would be incorrect since 438 // nsDisplayZoom changes the meaning of appunits. 439 nestedClipState.Clear(); 440 } 441 442 nsDisplayListBuilder::AutoBuildingDisplayList building( 443 aBuilder, subdocRootFrame, visible, dirty); 444 if (aBuilder->BuildCompositorHitTestInfo()) { 445 bool hasDocumentLevelListenersForApzAwareEvents = 446 gfxPlatform::AsyncPanZoomEnabled() && 447 nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(presShell); 448 449 aBuilder->SetAncestorHasApzAwareEventHandler( 450 hasDocumentLevelListenersForApzAwareEvents); 451 } 452 subdocRootFrame->BuildDisplayListForStackingContext(aBuilder, &childItems); 453 if (!aBuilder->IsForEventDelivery()) { 454 // If we are going to use a displayzoom below then any items we put 455 // under it need to have underlying frames from the subdocument. So we 456 // need to calculate the bounds based on which frame will be the 457 // underlying frame for the canvas background color item. 458 nsRect bounds = 459 GetContentRectRelativeToSelf() + aBuilder->ToReferenceFrame(this); 460 bounds = bounds.ScaleToOtherAppUnitsRoundOut(parentAPD, subdocAPD); 461 462 // Add the canvas background color to the bottom of the list. This 463 // happens after we've built the list so that 464 // AddCanvasBackgroundColorItem can monkey with the contents if 465 // necessary. 466 presShell->AddCanvasBackgroundColorItem( 467 aBuilder, &childItems, subdocRootFrame, bounds, NS_RGBA(0, 0, 0, 0)); 468 } 469 } 470 471 if (subdocRootFrame) { 472 aBuilder->LeavePresShell(subdocRootFrame, &childItems); 473 } 474 475 // Generate a resolution and/or zoom item if needed. If one or both of those 476 // is created, we don't need to create a separate nsDisplaySubDocument. 477 478 nsDisplayOwnLayerFlags flags = 479 nsDisplayOwnLayerFlags::GenerateSubdocInvalidations; 480 // If ignoreViewportScrolling is true then the top most layer we create here 481 // is going to become the scrollable layer for the root scroll frame, so we 482 // want to add nsDisplayOwnLayer::GENERATE_SCROLLABLE_LAYER to whatever layer 483 // becomes the topmost. We do this below. 484 if (constructZoomItem) { 485 nsDisplayOwnLayerFlags zoomFlags = flags; 486 if (ignoreViewportScrolling) { 487 zoomFlags |= nsDisplayOwnLayerFlags::GenerateScrollableLayer; 488 } 489 childItems.AppendNewToTop<nsDisplayZoom>(aBuilder, subdocRootFrame, this, 490 &childItems, subdocAPD, parentAPD, 491 zoomFlags); 492 493 needsOwnLayer = false; 494 } 495 // Wrap the zoom item in the resolution item if we have both because we want 496 // the resolution scale applied on top of the app units per dev pixel 497 // conversion. 498 if (ignoreViewportScrolling) { 499 flags |= nsDisplayOwnLayerFlags::GenerateScrollableLayer; 500 } 501 502 // We always want top level content documents to be in their own layer. 503 nsDisplaySubDocument* layerItem = MakeDisplayItem<nsDisplaySubDocument>( 504 aBuilder, subdocRootFrame ? subdocRootFrame : this, this, &childItems, 505 flags); 506 if (layerItem) { 507 childItems.AppendToTop(layerItem); 508 layerItem->SetShouldFlattenAway(!needsOwnLayer); 509 } 510 511 if (aBuilder->IsForFrameVisibility()) { 512 // We don't add the childItems to the return list as we're dealing with them 513 // here. 514 presShell->RebuildApproximateFrameVisibilityDisplayList(childItems); 515 childItems.DeleteAll(aBuilder); 516 } else { 517 aLists.Content()->AppendToTop(&childItems); 518 } 519 } 520 521 #ifdef DEBUG_FRAME_DUMP 522 void nsSubDocumentFrame::List(FILE* out, const char* aPrefix, 523 ListFlags aFlags) const { 524 nsCString str; 525 ListGeneric(str, aPrefix, aFlags); 526 fprintf_stderr(out, "%s\n", str.get()); 527 528 if (aFlags.contains(ListFlag::TraverseSubdocumentFrames)) { 529 nsSubDocumentFrame* f = const_cast<nsSubDocumentFrame*>(this); 530 nsIFrame* subdocRootFrame = f->GetSubdocumentRootFrame(); 531 if (subdocRootFrame) { 532 nsCString pfx(aPrefix); 533 pfx += " "; 534 subdocRootFrame->List(out, pfx.get(), aFlags); 535 } 536 } 537 } 538 539 nsresult nsSubDocumentFrame::GetFrameName(nsAString& aResult) const { 540 return MakeFrameName(u"FrameOuter"_ns, aResult); 541 } 542 #endif 543 544 nscoord nsSubDocumentFrame::IntrinsicISize(const IntrinsicSizeInput& aInput, 545 IntrinsicISizeType aType) { 546 // Note: when computing max-content inline size (i.e. when aType is 547 // IntrinsicISizeType::PrefISize), if the subdocument is an SVG document, then 548 // in theory we want to return the same value that SVGOuterSVGFrame does. That 549 // method has some special handling of percentage values to avoid unhelpful 550 // zero sizing in the presence of orthogonal writing modes. We don't bother 551 // with that for SVG documents in <embed> and <object>, since that special 552 // handling doesn't look up across document boundaries anyway. 553 return GetIntrinsicSize().ISize(GetWritingMode()).valueOr(0); 554 } 555 556 /* virtual */ 557 IntrinsicSize nsSubDocumentFrame::GetIntrinsicSize() { 558 return ComputeIntrinsicSize(); 559 } 560 561 IntrinsicSize nsSubDocumentFrame::ComputeIntrinsicSize( 562 bool aIgnoreContainment) const { 563 const auto containAxes = 564 aIgnoreContainment ? ContainSizeAxes(false, false) : GetContainSizeAxes(); 565 if (containAxes.IsBoth()) { 566 // Intrinsic size of 'contain:size' replaced elements is determined by 567 // contain-intrinsic-size. 568 return FinishIntrinsicSize(containAxes, IntrinsicSize(0, 0)); 569 } 570 571 if (nsCOMPtr<nsIObjectLoadingContent> iolc = do_QueryInterface(mContent)) { 572 const auto* olc = static_cast<nsObjectLoadingContent*>(iolc.get()); 573 if (auto size = olc->GetSubdocumentIntrinsicSize()) { 574 // Use the intrinsic size from the child SVG document, if available. 575 return FinishIntrinsicSize(containAxes, *size); 576 } 577 } 578 579 if (!IsInline()) { 580 return {}; // <frame> elements have no useful intrinsic size. 581 } 582 583 if (mContent->IsXULElement()) { 584 return {}; // XUL <iframe> and <browser> have no useful intrinsic size 585 } 586 587 // We must be an HTML <iframe>. Return fallback size. 588 return FinishIntrinsicSize(containAxes, 589 IntrinsicSize(kFallbackIntrinsicSize)); 590 } 591 592 /* virtual */ 593 AspectRatio nsSubDocumentFrame::GetIntrinsicRatio() const { 594 // FIXME(emilio): This should probably respect contain: size and return no 595 // ratio in the case subDocRoot is non-null. Otherwise we do it by virtue of 596 // using a zero-size below and reusing GetIntrinsicSize(). 597 if (nsCOMPtr<nsIObjectLoadingContent> iolc = do_QueryInterface(mContent)) { 598 auto olc = static_cast<nsObjectLoadingContent*>(iolc.get()); 599 600 auto ratio = olc->GetSubdocumentIntrinsicRatio(); 601 if (ratio && *ratio) { 602 // Use the intrinsic aspect ratio from the child SVG document, if 603 // available. 604 return *ratio; 605 } 606 } 607 608 // NOTE(emilio): Even though we have an intrinsic size, we may not have an 609 // intrinsic ratio. For example `<iframe style="width: 100px">` should not 610 // shrink in the vertical axis to preserve the 300x150 ratio. 611 return nsAtomicContainerFrame::GetIntrinsicRatio(); 612 } 613 614 /* virtual */ 615 nsIFrame::SizeComputationResult nsSubDocumentFrame::ComputeSize( 616 const SizeComputationInput& aSizingInput, WritingMode aWM, 617 const LogicalSize& aCBSize, nscoord aAvailableISize, 618 const LogicalSize& aMargin, const LogicalSize& aBorderPadding, 619 const StyleSizeOverrides& aSizeOverrides, ComputeSizeFlags aFlags) { 620 return {ComputeSizeWithIntrinsicDimensions( 621 aSizingInput.mRenderingContext, aWM, GetIntrinsicSize(), 622 GetAspectRatio(), aCBSize, aMargin, aBorderPadding, 623 aSizeOverrides, aFlags), 624 AspectRatioUsage::None}; 625 } 626 627 void nsSubDocumentFrame::Reflow(nsPresContext* aPresContext, 628 ReflowOutput& aDesiredSize, 629 const ReflowInput& aReflowInput, 630 nsReflowStatus& aStatus) { 631 MarkInReflow(); 632 DO_GLOBAL_REFLOW_COUNT("nsSubDocumentFrame"); 633 MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!"); 634 NS_FRAME_TRACE( 635 NS_FRAME_TRACE_CALLS, 636 ("enter nsSubDocumentFrame::Reflow: maxSize=%d,%d", 637 aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight())); 638 639 NS_ASSERTION(aReflowInput.ComputedISize() != NS_UNCONSTRAINEDSIZE, 640 "Shouldn't have unconstrained inline-size here " 641 "thanks to the rules of reflow"); 642 NS_ASSERTION(aReflowInput.ComputedBSize() != NS_UNCONSTRAINEDSIZE, 643 "Shouldn't have unconstrained block-size here " 644 "thanks to ComputeAutoSize"); 645 646 NS_ASSERTION(mContent->GetPrimaryFrame() == this, "Shouldn't happen"); 647 648 // XUL <iframe> or <browser>, or HTML <iframe>, <object> or <embed> 649 const auto wm = aReflowInput.GetWritingMode(); 650 aDesiredSize.SetSize(wm, aReflowInput.ComputedSizeWithBorderPadding(wm)); 651 652 // "offset" is the offset of our content area from our frame's 653 // top-left corner. 654 nsPoint offset = nsPoint(aReflowInput.ComputedPhysicalBorderPadding().left, 655 aReflowInput.ComputedPhysicalBorderPadding().top); 656 657 if (nsCOMPtr<nsIDocShell> ds = GetExtantDocShell()) { 658 const nsMargin& bp = aReflowInput.ComputedPhysicalBorderPadding(); 659 nsSize innerSize(aDesiredSize.Width() - bp.LeftRight(), 660 aDesiredSize.Height() - bp.TopBottom()); 661 662 // Size & position the view according to 'object-fit' & 'object-position'. 663 const nsRect destRect = GetDestRect(nsRect(offset, innerSize)); 664 auto rect = LayoutDeviceIntRect::FromAppUnitsToInside( 665 destRect, PresContext()->AppUnitsPerDevPixel()); 666 mExtraOffset = destRect.TopLeft(); 667 nsDocShell::Cast(ds)->SetPositionAndSize(0, 0, rect.width, rect.height, 668 nsIBaseWindow::eDelayResize); 669 } 670 671 aDesiredSize.SetOverflowAreasToDesiredBounds(); 672 673 FinishAndStoreOverflow(&aDesiredSize); 674 675 if (!aPresContext->IsRootPaginatedDocument() && !mPostedReflowCallback) { 676 PresShell()->PostReflowCallback(this); 677 mPostedReflowCallback = true; 678 } 679 680 NS_FRAME_TRACE( 681 NS_FRAME_TRACE_CALLS, 682 ("exit nsSubDocumentFrame::Reflow: size=%d,%d status=%s", 683 aDesiredSize.Width(), aDesiredSize.Height(), ToString(aStatus).c_str())); 684 } 685 686 bool nsSubDocumentFrame::ReflowFinished() { 687 mPostedReflowCallback = false; 688 nsFrameLoader* fl = FrameLoader(); 689 if (!fl) { 690 return false; 691 } 692 if (fl->IsRemoteFrame() && fl->HasRemoteBrowserBeenSized()) { 693 // For remote frames we don't need to update the size and position instantly 694 // (but we should try to do so if we haven't shown it yet). 695 return false; 696 } 697 RefPtr{fl}->UpdatePositionAndSize(this); 698 return false; 699 } 700 701 void nsSubDocumentFrame::ReflowCallbackCanceled() { 702 mPostedReflowCallback = false; 703 } 704 705 nsresult nsSubDocumentFrame::AttributeChanged(int32_t aNameSpaceID, 706 nsAtom* aAttribute, AttrModType) { 707 if (aNameSpaceID != kNameSpaceID_None) { 708 return NS_OK; 709 } 710 711 // If the noResize attribute changes, dis/allow frame to be resized 712 if (aAttribute == nsGkAtoms::noresize) { 713 // Note that we're not doing content type checks, but that's ok -- if 714 // they'd fail we will just end up with a null framesetFrame. 715 if (mContent->GetParent()->IsHTMLElement(nsGkAtoms::frameset)) { 716 nsIFrame* parentFrame = GetParent(); 717 718 if (parentFrame) { 719 // There is no interface for nsHTMLFramesetFrame so QI'ing to 720 // concrete class, yay! 721 nsHTMLFramesetFrame* framesetFrame = do_QueryFrame(parentFrame); 722 if (framesetFrame) { 723 framesetFrame->RecalculateBorderResize(); 724 } 725 } 726 } 727 } else if (aAttribute == nsGkAtoms::marginwidth || 728 aAttribute == nsGkAtoms::marginheight) { 729 // Notify the frameloader 730 if (RefPtr<nsFrameLoader> frameloader = FrameLoader()) { 731 frameloader->MarginsChanged(); 732 } 733 } 734 735 return NS_OK; 736 } 737 738 void nsSubDocumentFrame::MaybeUpdateEmbedderColorScheme() { 739 nsFrameLoader* fl = mFrameLoader.get(); 740 if (!fl) { 741 return; 742 } 743 744 BrowsingContext* bc = fl->GetExtantBrowsingContext(); 745 if (!bc) { 746 return; 747 } 748 749 auto ToOverride = [](ColorScheme aScheme) -> PrefersColorSchemeOverride { 750 return aScheme == ColorScheme::Dark ? PrefersColorSchemeOverride::Dark 751 : PrefersColorSchemeOverride::Light; 752 }; 753 754 EmbedderColorSchemes schemes{ 755 ToOverride(LookAndFeel::ColorSchemeForFrame(this, ColorSchemeMode::Used)), 756 ToOverride( 757 LookAndFeel::ColorSchemeForFrame(this, ColorSchemeMode::Preferred))}; 758 if (bc->GetEmbedderColorSchemes() == schemes) { 759 return; 760 } 761 762 (void)bc->SetEmbedderColorSchemes(schemes); 763 } 764 765 void nsSubDocumentFrame::MaybeUpdateEmbedderZoom() { 766 nsFrameLoader* fl = mFrameLoader.get(); 767 if (!fl) { 768 return; 769 } 770 771 BrowsingContext* bc = fl->GetExtantBrowsingContext(); 772 if (!bc) { 773 return; 774 } 775 776 BrowsingContext* parent = bc->GetParent(); 777 if (!parent) { 778 // Don't propagate zoom from the top browsing context, i.e. the browser 779 // frontend. (If we did propagate at that level, we wouldn't be able to 780 // reliably handle per-tab zoom levels, because the top level context's 781 // propagated zoom level would replace the per-tab zoom levels.) 782 return; 783 } 784 785 // The zoom that we propagate to our child document is parent's full-page-zoom 786 // level, *combined with* the EffectiveZoom (i.e. the css 'zoom') of this 787 // embedding frame. 788 auto newZoom = Style()->EffectiveZoom().Zoom(parent->GetFullZoom()); 789 if (bc->GetFullZoom() == newZoom) { 790 return; 791 } 792 (void)bc->SetFullZoom(newZoom); 793 } 794 795 void nsSubDocumentFrame::MaybeUpdateRemoteStyle( 796 ComputedStyle* aOldComputedStyle) { 797 if (!mIsInObjectOrEmbed) { 798 return; 799 } 800 801 if (aOldComputedStyle && 802 aOldComputedStyle->StyleVisibility()->mImageRendering == 803 Style()->StyleVisibility()->mImageRendering) { 804 return; 805 } 806 807 if (!mFrameLoader) { 808 return; 809 } 810 811 if (mFrameLoader->IsRemoteFrame()) { 812 mFrameLoader->UpdateRemoteStyle( 813 Style()->StyleVisibility()->mImageRendering); 814 return; 815 } 816 817 BrowsingContext* context = mFrameLoader->GetExtantBrowsingContext(); 818 if (!context) { 819 return; 820 } 821 822 Document* document = context->GetDocument(); 823 if (!document) { 824 return; 825 } 826 827 if (document->IsImageDocument()) { 828 document->AsImageDocument()->UpdateRemoteStyle( 829 Style()->StyleVisibility()->mImageRendering); 830 } 831 } 832 833 void nsSubDocumentFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) { 834 nsAtomicContainerFrame::DidSetComputedStyle(aOldComputedStyle); 835 836 if (aOldComputedStyle) { 837 // If there's no old style, the call in Init() or ShowViewer() should have 838 // us covered. 839 MaybeUpdateEmbedderColorScheme(); 840 MaybeUpdateRemoteStyle(aOldComputedStyle); 841 if (aOldComputedStyle->EffectiveZoom() != Style()->EffectiveZoom()) { 842 MaybeUpdateEmbedderZoom(); 843 } 844 } 845 846 // If this presshell has invisible ancestors, we don't need to propagate the 847 // visibility style change to the subdocument since the subdocument should 848 // have already set the IsUnderHiddenEmbedderElement flag in 849 // nsSubDocumentFrame::Init. 850 if (PresShell()->IsUnderHiddenEmbedderElement()) { 851 return; 852 } 853 854 const bool isVisible = StyleVisibility()->IsVisible(); 855 if (!aOldComputedStyle || 856 isVisible != aOldComputedStyle->StyleVisibility()->IsVisible()) { 857 PropagateIsUnderHiddenEmbedderElement(!isVisible); 858 } 859 } 860 861 nsIFrame* NS_NewSubDocumentFrame(PresShell* aPresShell, ComputedStyle* aStyle) { 862 return new (aPresShell) 863 nsSubDocumentFrame(aStyle, aPresShell->GetPresContext()); 864 } 865 866 NS_IMPL_FRAMEARENA_HELPERS(nsSubDocumentFrame) 867 868 class nsHideViewer final : public Runnable { 869 public: 870 nsHideViewer(nsIContent* aFrameElement, nsFrameLoader* aFrameLoader, 871 PresShell* aPresShell, bool aHideViewerIfFrameless) 872 : mozilla::Runnable("nsHideViewer"), 873 mFrameElement(aFrameElement), 874 mFrameLoader(aFrameLoader), 875 mPresShell(aPresShell), 876 mHideViewerIfFrameless(aHideViewerIfFrameless) { 877 NS_ASSERTION(mFrameElement, "Must have a frame element"); 878 NS_ASSERTION(mFrameLoader, "Must have a frame loader"); 879 NS_ASSERTION(mPresShell, "Must have a presshell"); 880 } 881 882 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() override { 883 // Flush frames, to ensure any pending display:none changes are made. 884 // Note it can be unsafe to flush if we've destroyed the presentation 885 // for some other reason, like if we're shutting down. 886 // 887 // But avoid the flush if we know for sure we're away, like when we're out 888 // of the document already. 889 // 890 // FIXME(emilio): This could still be a perf footgun when removing lots of 891 // siblings where each of them cause the reframe of an ancestor which happen 892 // to contain a subdocument. 893 // 894 // We should find some way to avoid that! 895 if (!mPresShell->IsDestroying() && mFrameElement->IsInComposedDoc()) { 896 mPresShell->FlushPendingNotifications(FlushType::Frames); 897 } 898 899 // Either the frame has been constructed by now, or it never will be, 900 // either way we want to clear the stashed views. 901 mFrameLoader->SetDetachedSubdocs({}); 902 903 nsSubDocumentFrame* frame = do_QueryFrame(mFrameElement->GetPrimaryFrame()); 904 if (!frame || frame->FrameLoader() != mFrameLoader) { 905 PropagateIsUnderHiddenEmbedderElement(mFrameLoader, true); 906 if (mHideViewerIfFrameless) { 907 // The frame element has no nsIFrame for the same frame loader. 908 // Hide the nsFrameLoader, which destroys the presentation. 909 mFrameLoader->Hide(); 910 } 911 } 912 return NS_OK; 913 } 914 915 private: 916 const nsCOMPtr<nsIContent> mFrameElement; 917 const RefPtr<nsFrameLoader> mFrameLoader; 918 const RefPtr<PresShell> mPresShell; 919 const bool mHideViewerIfFrameless; 920 }; 921 922 void nsSubDocumentFrame::Destroy(DestroyContext& aContext) { 923 if (mPostedReflowCallback) { 924 PresShell()->CancelReflowCallback(this); 925 mPostedReflowCallback = false; 926 } 927 928 // Detach the subdocument's views and stash them in the frame loader. 929 // We can then reattach them if we're being reframed (for example if 930 // the frame has been made position:fixed). 931 if (RefPtr<nsFrameLoader> frameloader = FrameLoader()) { 932 ClearDisplayItems(); 933 934 PrepareInProcessPresShellsForDetach(); 935 frameloader->SetDetachedSubdocs(std::move(mInProcessPresShells)); 936 937 // We call nsFrameLoader::HideViewer() in a script runner so that we can 938 // safely determine whether the frame is being reframed or destroyed. 939 nsContentUtils::AddScriptRunner(new nsHideViewer( 940 mContent, frameloader, PresShell(), (mDidCreateDoc || mCallingShow))); 941 } 942 943 nsAtomicContainerFrame::Destroy(aContext); 944 } 945 946 nsFrameLoader* nsSubDocumentFrame::FrameLoader() const { 947 if (mFrameLoader) { 948 return mFrameLoader; 949 } 950 951 if (RefPtr<nsFrameLoaderOwner> loaderOwner = do_QueryObject(GetContent())) { 952 mFrameLoader = loaderOwner->GetFrameLoader(); 953 } 954 955 return mFrameLoader; 956 } 957 958 auto nsSubDocumentFrame::GetRemotePaintData() const -> RemoteFramePaintData { 959 if (mRetainedRemoteFrame) { 960 return *mRetainedRemoteFrame; 961 } 962 963 RemoteFramePaintData data; 964 nsFrameLoader* fl = FrameLoader(); 965 if (!fl) { 966 return data; 967 } 968 969 auto* rb = fl->GetRemoteBrowser(); 970 if (!rb) { 971 return data; 972 } 973 data.mLayersId = rb->GetLayersId(); 974 data.mTabId = rb->GetTabId(); 975 return data; 976 } 977 978 void nsSubDocumentFrame::ResetFrameLoader(RetainPaintData aRetain) { 979 if (aRetain == RetainPaintData::Yes && mFrameLoader) { 980 mRetainedRemoteFrame = Some(GetRemotePaintData()); 981 } else { 982 mRetainedRemoteFrame.reset(); 983 } 984 mFrameLoader = nullptr; 985 ClearDisplayItems(); 986 nsContentUtils::AddScriptRunner(new AsyncFrameInit(this)); 987 } 988 989 void nsSubDocumentFrame::ClearRetainedPaintData() { 990 mRetainedRemoteFrame.reset(); 991 ClearDisplayItems(); 992 InvalidateFrameSubtree(); 993 } 994 995 // XXX this should be called ObtainDocShell or something like that, 996 // to indicate that it could have side effects 997 nsIDocShell* nsSubDocumentFrame::GetDocShell() const { 998 // How can FrameLoader() return null??? 999 if (NS_WARN_IF(!FrameLoader())) { 1000 return nullptr; 1001 } 1002 return mFrameLoader->GetDocShell(IgnoreErrors()); 1003 } 1004 1005 nsIDocShell* nsSubDocumentFrame::GetExtantDocShell() const { 1006 return mFrameLoader ? mFrameLoader->GetExistingDocShell() : nullptr; 1007 } 1008 1009 static void DestroyDisplayItemDataForFrames(nsIFrame* aFrame) { 1010 // Destroying a WebRenderUserDataTable can cause destruction of other objects 1011 // which can remove frame properties in their destructor. If we delete a frame 1012 // property it runs the destructor of the stored object in the middle of 1013 // updating the frame property table, so if the destruction of that object 1014 // causes another update to the frame property table it would leave the frame 1015 // property table in an inconsistent state. So we remove it from the table and 1016 // then destroy it. (bug 1530657) 1017 WebRenderUserDataTable* userDataTable = 1018 aFrame->TakeProperty(WebRenderUserDataProperty::Key()); 1019 if (userDataTable) { 1020 for (const auto& data : userDataTable->Values()) { 1021 data->RemoveFromTable(); 1022 } 1023 delete userDataTable; 1024 } 1025 1026 for (const auto& childList : aFrame->ChildLists()) { 1027 for (nsIFrame* child : childList.mList) { 1028 DestroyDisplayItemDataForFrames(child); 1029 } 1030 } 1031 } 1032 1033 nsresult nsSubDocumentFrame::BeginSwapDocShells(nsIFrame* aOther) { 1034 if (!aOther || !aOther->IsSubDocumentFrame()) { 1035 return NS_ERROR_NOT_IMPLEMENTED; 1036 } 1037 1038 nsSubDocumentFrame* other = static_cast<nsSubDocumentFrame*>(aOther); 1039 if (!mFrameLoader || !mDidCreateDoc || mCallingShow || !other->mFrameLoader || 1040 !other->mDidCreateDoc) { 1041 return NS_ERROR_NOT_IMPLEMENTED; 1042 } 1043 1044 ClearDisplayItems(); 1045 other->ClearDisplayItems(); 1046 1047 PrepareInProcessPresShellsForDetach(); 1048 other->PrepareInProcessPresShellsForDetach(); 1049 1050 mFrameLoader.swap(other->mFrameLoader); 1051 return NS_OK; 1052 } 1053 1054 static CallState EndSwapDocShellsForDocument(Document& aDocument) { 1055 // Our docshell trees have been updated for the new hierarchy. Now also update 1056 // all nsDeviceContext::mWidget to that of the container view in the new 1057 // hierarchy. 1058 if (nsCOMPtr<nsIDocShell> ds = aDocument.GetDocShell()) { 1059 nsCOMPtr<nsIDocumentViewer> viewer; 1060 ds->GetDocViewer(getter_AddRefs(viewer)); 1061 while (viewer) { 1062 RefPtr<nsPresContext> pc = viewer->GetPresContext(); 1063 if (pc && pc->GetPresShell()) { 1064 pc->GetPresShell()->SetNeverPainting(ds->IsInvisible()); 1065 } 1066 nsDeviceContext* dc = pc ? pc->DeviceContext() : nullptr; 1067 if (dc) { 1068 nsSubDocumentFrame* f = viewer->FindContainerFrame(); 1069 nsIWidget* widget = f ? f->GetNearestWidget() : nullptr; 1070 if (widget) { 1071 widget = widget->GetTopLevelWidget(); 1072 } 1073 dc->Init(widget); 1074 } 1075 viewer = viewer->GetPreviousViewer(); 1076 } 1077 } 1078 1079 aDocument.EnumerateSubDocuments(EndSwapDocShellsForDocument); 1080 return CallState::Continue; 1081 } 1082 1083 static CallState BeginSwapDocShellsForDocument(Document& aDocument) { 1084 if (PresShell* presShell = aDocument.GetPresShell()) { 1085 // Disable painting while the presentation shell is detached. 1086 presShell->SetNeverPainting(true); 1087 1088 if (nsIFrame* rootFrame = presShell->GetRootFrame()) { 1089 ::DestroyDisplayItemDataForFrames(rootFrame); 1090 } 1091 } 1092 aDocument.EnumerateSubDocuments(BeginSwapDocShellsForDocument); 1093 return CallState::Continue; 1094 } 1095 1096 void nsSubDocumentFrame::PrepareInProcessPresShellsForDetach() { 1097 for (const auto& shell : mInProcessPresShells) { 1098 if (RefPtr<class PresShell> ps = do_QueryReferent(shell)) { 1099 BeginSwapDocShellsForDocument(*ps->GetDocument()); 1100 } 1101 } 1102 } 1103 1104 bool nsSubDocumentFrame::FixUpInProcessPresShellsAfterAttach() { 1105 bool anyLiveShell = false; 1106 for (auto& shell : mInProcessPresShells) { 1107 if (RefPtr<mozilla::PresShell> ps = do_QueryReferent(shell)) { 1108 if (ps && !ps->IsDestroying()) { 1109 anyLiveShell = true; 1110 ps->SetInProcessEmbedderFrame(this); 1111 EndSwapDocShellsForDocument(*ps->GetDocument()); 1112 } 1113 } 1114 } 1115 return anyLiveShell; 1116 } 1117 1118 void nsSubDocumentFrame::EndSwapDocShells(nsIFrame* aOther) { 1119 auto* other = static_cast<nsSubDocumentFrame*>(aOther); 1120 1121 mInProcessPresShells.SwapElements(other->mInProcessPresShells); 1122 FixUpInProcessPresShellsAfterAttach(); 1123 other->FixUpInProcessPresShellsAfterAttach(); 1124 1125 // Now make sure we reflow both frames, in case their contents 1126 // determine their size. 1127 // And repaint them, for good measure, in case there's nothing 1128 // interesting that happens during reflow. 1129 PresShell()->FrameNeedsReflow(this, IntrinsicDirty::FrameAndAncestors, 1130 NS_FRAME_IS_DIRTY); 1131 InvalidateFrameSubtree(); 1132 PropagateIsUnderHiddenEmbedderElement( 1133 PresShell()->IsUnderHiddenEmbedderElement() || 1134 !StyleVisibility()->IsVisible()); 1135 1136 other->PresShell()->FrameNeedsReflow(other, IntrinsicDirty::FrameAndAncestors, 1137 NS_FRAME_IS_DIRTY); 1138 other->InvalidateFrameSubtree(); 1139 other->PropagateIsUnderHiddenEmbedderElement( 1140 other->PresShell()->IsUnderHiddenEmbedderElement() || 1141 !other->StyleVisibility()->IsVisible()); 1142 } 1143 1144 void nsSubDocumentFrame::ClearDisplayItems() { 1145 if (auto* builder = nsLayoutUtils::GetRetainedDisplayListBuilder(this)) { 1146 DL_LOGD("nsSubDocumentFrame::ClearDisplayItems() %p", this); 1147 builder->ClearRetainedData(); 1148 } 1149 } 1150 1151 void nsSubDocumentFrame::SubdocumentIntrinsicSizeOrRatioChanged() { 1152 const nsStylePosition* pos = StylePosition(); 1153 const auto anchorResolutionParams = AnchorPosResolutionParams::From(this); 1154 bool dependsOnIntrinsics = 1155 !pos->GetWidth(anchorResolutionParams)->ConvertsToLength() || 1156 !pos->GetHeight(anchorResolutionParams)->ConvertsToLength(); 1157 1158 if (dependsOnIntrinsics || pos->mObjectFit != StyleObjectFit::Fill) { 1159 auto dirtyHint = dependsOnIntrinsics 1160 ? IntrinsicDirty::FrameAncestorsAndDescendants 1161 : IntrinsicDirty::None; 1162 PresShell()->FrameNeedsReflow(this, dirtyHint, NS_FRAME_IS_DIRTY); 1163 InvalidateFrame(); 1164 } 1165 } 1166 1167 bool nsSubDocumentFrame::ContentReactsToPointerEvents() const { 1168 if (Style()->PointerEvents() == StylePointerEvents::None) { 1169 return false; 1170 } 1171 if (mIsInObjectOrEmbed) { 1172 if (nsCOMPtr<nsIObjectLoadingContent> iolc = do_QueryInterface(mContent)) { 1173 const auto* olc = static_cast<nsObjectLoadingContent*>(iolc.get()); 1174 if (olc->IsSyntheticImageDocument()) { 1175 return false; 1176 } 1177 } 1178 } 1179 return true; 1180 } 1181 1182 nsDisplayRemote::nsDisplayRemote(nsDisplayListBuilder* aBuilder, 1183 nsSubDocumentFrame* aFrame) 1184 : nsPaintedDisplayItem(aBuilder, aFrame), 1185 mEventRegionsOverride(EventRegionsOverride::NoOverride) { 1186 if (aBuilder->BuildCompositorHitTestInfo()) { 1187 if (aBuilder->IsInsidePointerEventsNoneDoc() || 1188 !aFrame->ContentReactsToPointerEvents()) { 1189 mEventRegionsOverride |= EventRegionsOverride::ForceEmptyHitRegion; 1190 } 1191 if (nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents( 1192 aFrame->PresShell())) { 1193 mEventRegionsOverride |= EventRegionsOverride::ForceDispatchToContent; 1194 } 1195 } 1196 1197 mPaintData = aFrame->GetRemotePaintData(); 1198 } 1199 1200 namespace mozilla { 1201 1202 void nsDisplayRemote::Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) { 1203 DrawTarget* target = aCtx->GetDrawTarget(); 1204 if (!target->IsRecording() || mPaintData.mTabId == 0) { 1205 NS_WARNING("Remote iframe not rendered"); 1206 return; 1207 } 1208 1209 // Rendering the inner document will apply a scale to account for its app 1210 // units per dev pixel ratio. We want to apply the inverse scaling using our 1211 // app units per dev pixel ratio, so that no actual scaling will be applied if 1212 // they match. For in-process rendering, nsSubDocumentFrame creates an 1213 // nsDisplayZoom item if the app units per dev pixel ratio changes. 1214 // 1215 // Similarly, rendering the inner document will scale up by the cross process 1216 // paint scale again, so we also need to account for that. 1217 const int32_t appUnitsPerDevPixel = 1218 mFrame->PresContext()->AppUnitsPerDevPixel(); 1219 1220 gfxContextMatrixAutoSaveRestore saveMatrix(aCtx); 1221 gfxFloat targetAuPerDev = 1222 gfxFloat(AppUnitsPerCSSPixel()) / aCtx->GetCrossProcessPaintScale(); 1223 1224 gfxFloat scale = targetAuPerDev / appUnitsPerDevPixel; 1225 aCtx->Multiply(gfxMatrix::Scaling(scale, scale)); 1226 1227 Rect destRect = 1228 NSRectToSnappedRect(GetContentRect(), targetAuPerDev, *target); 1229 target->DrawDependentSurface(mPaintData.mTabId, destRect); 1230 } 1231 1232 bool nsDisplayRemote::CreateWebRenderCommands( 1233 mozilla::wr::DisplayListBuilder& aBuilder, 1234 mozilla::wr::IpcResourceUpdateQueue& aResources, 1235 const StackingContextHelper& aSc, 1236 mozilla::layers::RenderRootStateManager* aManager, 1237 nsDisplayListBuilder* aDisplayListBuilder) { 1238 if (!mPaintData.mLayersId.IsValid()) { 1239 return true; 1240 } 1241 1242 auto* subDocFrame = static_cast<nsSubDocumentFrame*>(mFrame); 1243 nsRect destRect = subDocFrame->GetDestRect(); 1244 if (aDisplayListBuilder->IsForPainting()) { 1245 subDocFrame->SetRasterScale(aSc.GetInheritedScale()); 1246 const nsRect buildingRect = GetBuildingRect() - ToReferenceFrame(); 1247 Maybe<nsRect> visibleRect = 1248 buildingRect.EdgeInclusiveIntersection(destRect); 1249 if (visibleRect) { 1250 *visibleRect -= destRect.TopLeft(); 1251 } 1252 subDocFrame->SetVisibleRect(visibleRect); 1253 } 1254 nscoord auPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel(); 1255 nsPoint layerOffset = 1256 aDisplayListBuilder->ToReferenceFrame(mFrame) + destRect.TopLeft(); 1257 mOffset = LayoutDevicePoint::FromAppUnits(layerOffset, auPerDevPixel); 1258 1259 destRect.MoveTo(0, 0); 1260 auto rect = LayoutDeviceRect::FromAppUnits(destRect, auPerDevPixel); 1261 rect += mOffset; 1262 1263 aBuilder.PushIFrame(rect, !BackfaceIsHidden(), 1264 mozilla::wr::AsPipelineId(mPaintData.mLayersId), 1265 /*ignoreMissingPipelines*/ true); 1266 1267 return true; 1268 } 1269 1270 bool nsDisplayRemote::UpdateScrollData( 1271 mozilla::layers::WebRenderScrollData* aData, 1272 mozilla::layers::WebRenderLayerScrollData* aLayerData) { 1273 if (!mPaintData.mLayersId.IsValid()) { 1274 return true; 1275 } 1276 1277 if (aLayerData) { 1278 aLayerData->SetReferentId(mPaintData.mLayersId); 1279 1280 auto size = static_cast<nsSubDocumentFrame*>(mFrame)->GetSubdocumentSize(); 1281 Matrix4x4 m = Matrix4x4::Translation(mOffset.x, mOffset.y, 0.0); 1282 aLayerData->SetTransform(m); 1283 aLayerData->SetEventRegionsOverride(mEventRegionsOverride); 1284 aLayerData->SetRemoteDocumentSize(LayerIntSize(size.width, size.height)); 1285 } 1286 return true; 1287 } 1288 1289 nsFrameLoader* nsDisplayRemote::GetFrameLoader() const { 1290 return static_cast<nsSubDocumentFrame*>(mFrame)->FrameLoader(); 1291 } 1292 1293 } // namespace mozilla