Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/generic/nsSubDocumentFrame.cpp
Line
Count
Source (jump to first uncovered line)
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 "gfxPrefs.h"
15
16
#include "mozilla/layout/RenderFrameParent.h"
17
18
#include "nsCOMPtr.h"
19
#include "nsGenericHTMLElement.h"
20
#include "nsGenericHTMLFrameElement.h"
21
#include "nsAttrValueInlines.h"
22
#include "nsIDocShell.h"
23
#include "nsIContentViewer.h"
24
#include "nsIContentInlines.h"
25
#include "nsPresContext.h"
26
#include "nsIPresShell.h"
27
#include "nsIDocument.h"
28
#include "nsView.h"
29
#include "nsViewManager.h"
30
#include "nsGkAtoms.h"
31
#include "nsStyleConsts.h"
32
#include "nsFrameSetFrame.h"
33
#include "nsIScrollable.h"
34
#include "nsNameSpaceManager.h"
35
#include "nsDisplayList.h"
36
#include "nsIScrollableFrame.h"
37
#include "nsIObjectLoadingContent.h"
38
#include "nsLayoutUtils.h"
39
#include "FrameLayerBuilder.h"
40
#include "nsPluginFrame.h"
41
#include "nsContentUtils.h"
42
#include "nsIPermissionManager.h"
43
#include "nsServiceManagerUtils.h"
44
#include "mozilla/Preferences.h"
45
#include "mozilla/dom/HTMLFrameElement.h"
46
#include "RetainedDisplayListBuilder.h"
47
48
using namespace mozilla;
49
using mozilla::layout::RenderFrameParent;
50
51
static bool sShowPreviousPage = true;
52
53
static nsIDocument*
54
GetDocumentFromView(nsView* aView)
55
0
{
56
0
  MOZ_ASSERT(aView, "null view");
57
0
58
0
  nsViewManager* vm = aView->GetViewManager();
59
0
  nsIPresShell* ps =  vm ? vm->GetPresShell() : nullptr;
60
0
  return ps ? ps->GetDocument() : nullptr;
61
0
}
62
63
nsSubDocumentFrame::nsSubDocumentFrame(ComputedStyle* aStyle)
64
  : nsAtomicContainerFrame(aStyle, kClassID)
65
  , mOuterView(nullptr)
66
  , mInnerView(nullptr)
67
  , mIsInline(false)
68
  , mPostedReflowCallback(false)
69
  , mDidCreateDoc(false)
70
  , mCallingShow(false)
71
0
{
72
0
}
73
74
#ifdef ACCESSIBILITY
75
a11y::AccType
76
nsSubDocumentFrame::AccessibleType()
77
0
{
78
0
  return a11y::eOuterDocType;
79
0
}
80
#endif
81
82
0
NS_QUERYFRAME_HEAD(nsSubDocumentFrame)
83
0
  NS_QUERYFRAME_ENTRY(nsSubDocumentFrame)
84
0
NS_QUERYFRAME_TAIL_INHERITING(nsAtomicContainerFrame)
85
86
class AsyncFrameInit : public Runnable
87
{
88
public:
89
  explicit AsyncFrameInit(nsIFrame* aFrame)
90
    : mozilla::Runnable("AsyncFrameInit")
91
    , mFrame(aFrame)
92
0
  {
93
0
  }
94
  NS_IMETHOD Run() override
95
0
  {
96
0
    AUTO_PROFILER_LABEL("AsyncFrameInit::Run", OTHER);
97
0
    if (mFrame.IsAlive()) {
98
0
      static_cast<nsSubDocumentFrame*>(mFrame.GetFrame())->ShowViewer();
99
0
    }
100
0
    return NS_OK;
101
0
  }
102
private:
103
  WeakFrame mFrame;
104
};
105
106
static void
107
InsertViewsInReverseOrder(nsView* aSibling, nsView* aParent);
108
109
static void
110
EndSwapDocShellsForViews(nsView* aView);
111
112
void
113
nsSubDocumentFrame::Init(nsIContent*       aContent,
114
                         nsContainerFrame* aParent,
115
                         nsIFrame*         aPrevInFlow)
116
0
{
117
0
  MOZ_ASSERT(aContent);
118
0
  // determine if we are a <frame> or <iframe>
119
0
  mIsInline = !aContent->IsHTMLElement(nsGkAtoms::frame);
120
0
121
0
  static bool addedShowPreviousPage = false;
122
0
  if (!addedShowPreviousPage) {
123
0
    // If layout.show_previous_page is true then during loading of a new page we
124
0
    // will draw the previous page if the new page has painting suppressed.
125
0
    Preferences::AddBoolVarCache(&sShowPreviousPage, "layout.show_previous_page", true);
126
0
    addedShowPreviousPage = true;
127
0
  }
128
0
129
0
  nsAtomicContainerFrame::Init(aContent, aParent, aPrevInFlow);
130
0
131
0
  // CreateView() creates this frame's view, stored in mOuterView.  It needs to
132
0
  // be created first since it's the parent of the inner view, stored in
133
0
  // mInnerView.
134
0
  CreateView();
135
0
  EnsureInnerView();
136
0
137
0
  // Set the primary frame now so that nsDocumentViewer::FindContainerView
138
0
  // called from within EndSwapDocShellsForViews below can find it if needed.
139
0
  aContent->SetPrimaryFrame(this);
140
0
141
0
  // If we have a detached subdoc's root view on our frame loader, re-insert
142
0
  // it into the view tree. This happens when we've been reframed, and
143
0
  // ensures the presentation persists across reframes. If the frame element
144
0
  // has changed documents however, we blow away the presentation.
145
0
  RefPtr<nsFrameLoader> frameloader = FrameLoader();
146
0
  if (frameloader) {
147
0
    nsCOMPtr<nsIDocument> oldContainerDoc;
148
0
    nsIFrame* detachedFrame =
149
0
      frameloader->GetDetachedSubdocFrame(getter_AddRefs(oldContainerDoc));
150
0
    frameloader->SetDetachedSubdocFrame(nullptr, nullptr);
151
0
    MOZ_ASSERT(oldContainerDoc || !detachedFrame);
152
0
    if (oldContainerDoc) {
153
0
      nsView* detachedView =
154
0
        detachedFrame ? detachedFrame->GetView() : nullptr;
155
0
      if (detachedView && oldContainerDoc == aContent->OwnerDoc()) {
156
0
        // Restore stashed presentation.
157
0
        ::InsertViewsInReverseOrder(detachedView, mInnerView);
158
0
        ::EndSwapDocShellsForViews(mInnerView->GetFirstChild());
159
0
      } else {
160
0
        // Presentation is for a different document, don't restore it.
161
0
        frameloader->Hide();
162
0
      }
163
0
    }
164
0
  }
165
0
166
0
  nsContentUtils::AddScriptRunner(new AsyncFrameInit(this));
167
0
}
168
169
void
170
nsSubDocumentFrame::ShowViewer()
171
0
{
172
0
  if (mCallingShow) {
173
0
    return;
174
0
  }
175
0
176
0
  if (!PresContext()->IsDynamic()) {
177
0
    // We let the printing code take care of loading the document; just
178
0
    // create the inner view for it to use.
179
0
    (void) EnsureInnerView();
180
0
  } else {
181
0
    RefPtr<nsFrameLoader> frameloader = FrameLoader();
182
0
    if (frameloader) {
183
0
      CSSIntSize margin = GetMarginAttributes();
184
0
      AutoWeakFrame weakThis(this);
185
0
      mCallingShow = true;
186
0
      const nsAttrValue* attrValue =
187
0
        GetContent()->AsElement()->GetParsedAttr(nsGkAtoms::scrolling);
188
0
      int32_t scrolling =
189
0
        nsGenericHTMLFrameElement::MapScrollingAttribute(attrValue);
190
0
      bool didCreateDoc =
191
0
        frameloader->Show(margin.width, margin.height,
192
0
                          scrolling, scrolling, this);
193
0
      if (!weakThis.IsAlive()) {
194
0
        return;
195
0
      }
196
0
      mCallingShow = false;
197
0
      mDidCreateDoc = didCreateDoc;
198
0
    }
199
0
  }
200
0
}
201
202
nsIFrame*
203
nsSubDocumentFrame::GetSubdocumentRootFrame()
204
0
{
205
0
  if (!mInnerView)
206
0
    return nullptr;
207
0
  nsView* subdocView = mInnerView->GetFirstChild();
208
0
  return subdocView ? subdocView->GetFrame() : nullptr;
209
0
}
210
211
nsIPresShell*
212
nsSubDocumentFrame::GetSubdocumentPresShellForPainting(uint32_t aFlags)
213
0
{
214
0
  if (!mInnerView)
215
0
    return nullptr;
216
0
217
0
  nsView* subdocView = mInnerView->GetFirstChild();
218
0
  if (!subdocView)
219
0
    return nullptr;
220
0
221
0
  nsIPresShell* presShell = nullptr;
222
0
223
0
  nsIFrame* subdocRootFrame = subdocView->GetFrame();
224
0
  if (subdocRootFrame) {
225
0
    presShell = subdocRootFrame->PresShell();
226
0
  }
227
0
228
0
  // If painting is suppressed in the presshell, we try to look for a better
229
0
  // presshell to use.
230
0
  if (!presShell || (presShell->IsPaintingSuppressed() &&
231
0
                     !(aFlags & IGNORE_PAINT_SUPPRESSION))) {
232
0
    // During page transition mInnerView will sometimes have two children, the
233
0
    // first being the new page that may not have any frame, and the second
234
0
    // being the old page that will probably have a frame.
235
0
    nsView* nextView = subdocView->GetNextSibling();
236
0
    nsIFrame* frame = nullptr;
237
0
    if (nextView) {
238
0
      frame = nextView->GetFrame();
239
0
    }
240
0
    if (frame) {
241
0
      nsIPresShell* ps = frame->PresShell();
242
0
      if (!presShell || (ps && !ps->IsPaintingSuppressed() && sShowPreviousPage)) {
243
0
        subdocView = nextView;
244
0
        subdocRootFrame = frame;
245
0
        presShell = ps;
246
0
      }
247
0
    }
248
0
    if (!presShell) {
249
0
      // If we don't have a frame we use this roundabout way to get the pres shell.
250
0
      if (!mFrameLoader)
251
0
        return nullptr;
252
0
      nsIDocShell* docShell = mFrameLoader->GetDocShell(IgnoreErrors());
253
0
      if (!docShell)
254
0
        return nullptr;
255
0
      presShell = docShell->GetPresShell();
256
0
    }
257
0
  }
258
0
259
0
  return presShell;
260
0
}
261
262
263
264
265
ScreenIntSize
266
nsSubDocumentFrame::GetSubdocumentSize()
267
0
{
268
0
  if (GetStateBits() & NS_FRAME_FIRST_REFLOW) {
269
0
    RefPtr<nsFrameLoader> frameloader = FrameLoader();
270
0
    if (frameloader) {
271
0
      nsCOMPtr<nsIDocument> oldContainerDoc;
272
0
      nsIFrame* detachedFrame =
273
0
        frameloader->GetDetachedSubdocFrame(getter_AddRefs(oldContainerDoc));
274
0
      nsView* view = detachedFrame ? detachedFrame->GetView() : nullptr;
275
0
      if (view) {
276
0
        nsSize size = view->GetBounds().Size();
277
0
        nsPresContext* presContext = detachedFrame->PresContext();
278
0
        return ScreenIntSize(presContext->AppUnitsToDevPixels(size.width),
279
0
                             presContext->AppUnitsToDevPixels(size.height));
280
0
      }
281
0
    }
282
0
    // Pick some default size for now.  Using 10x10 because that's what the
283
0
    // code used to do.
284
0
    return ScreenIntSize(10, 10);
285
0
  } else {
286
0
    nsSize docSizeAppUnits;
287
0
    nsPresContext* presContext = PresContext();
288
0
    if (GetContent()->IsHTMLElement(nsGkAtoms::frame)) {
289
0
      docSizeAppUnits = GetSize();
290
0
    } else {
291
0
      docSizeAppUnits = GetContentRect().Size();
292
0
    }
293
0
    // Adjust subdocument size, according to 'object-fit' and the
294
0
    // subdocument's intrinsic size and ratio.
295
0
    nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
296
0
    if (subDocRoot) {
297
0
      nsRect destRect =
298
0
        nsLayoutUtils::ComputeObjectDestRect(nsRect(nsPoint(), docSizeAppUnits),
299
0
                                             subDocRoot->GetIntrinsicSize(),
300
0
                                             subDocRoot->GetIntrinsicRatio(),
301
0
                                             StylePosition());
302
0
      docSizeAppUnits = destRect.Size();
303
0
    }
304
0
305
0
    return ScreenIntSize(presContext->AppUnitsToDevPixels(docSizeAppUnits.width),
306
0
                         presContext->AppUnitsToDevPixels(docSizeAppUnits.height));
307
0
  }
308
0
}
309
310
static void
311
WrapBackgroundColorInOwnLayer(nsDisplayListBuilder* aBuilder,
312
                              nsIFrame* aFrame,
313
                              nsDisplayList* aList)
314
0
{
315
0
  nsDisplayList tempItems;
316
0
  nsDisplayItem* item;
317
0
  while ((item = aList->RemoveBottom()) != nullptr) {
318
0
    if (item->GetType() == DisplayItemType::TYPE_BACKGROUND_COLOR) {
319
0
      nsDisplayList tmpList;
320
0
      tmpList.AppendToTop(item);
321
0
      item = MakeDisplayItem<nsDisplayOwnLayer>(aBuilder, aFrame, &tmpList, aBuilder->CurrentActiveScrolledRoot());
322
0
    }
323
0
    tempItems.AppendToTop(item);
324
0
  }
325
0
  aList->AppendToTop(&tempItems);
326
0
}
327
328
void
329
nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
330
                                     const nsDisplayListSet& aLists)
331
0
{
332
0
  if (!IsVisibleForPainting(aBuilder))
333
0
    return;
334
0
335
0
  nsFrameLoader* frameLoader = FrameLoader();
336
0
  RenderFrameParent* rfp = nullptr;
337
0
  if (frameLoader) {
338
0
    rfp = frameLoader->GetCurrentRenderFrame();
339
0
  }
340
0
341
0
  // If we are pointer-events:none then we don't need to HitTest background
342
0
  bool pointerEventsNone =
343
0
    StyleUI()->mPointerEvents == NS_STYLE_POINTER_EVENTS_NONE;
344
0
  if (!aBuilder->IsForEventDelivery() || !pointerEventsNone) {
345
0
    nsDisplayListCollection decorations(aBuilder);
346
0
    DisplayBorderBackgroundOutline(aBuilder, decorations);
347
0
    if (rfp) {
348
0
      // Wrap background colors of <iframe>s with remote subdocuments in their
349
0
      // own layer so we generate a ColorLayer. This is helpful for optimizing
350
0
      // compositing; we can skip compositing the ColorLayer when the
351
0
      // remote content is opaque.
352
0
      WrapBackgroundColorInOwnLayer(aBuilder, this, decorations.BorderBackground());
353
0
    }
354
0
    decorations.MoveTo(aLists);
355
0
  }
356
0
357
0
  if (aBuilder->IsForEventDelivery() && pointerEventsNone) {
358
0
    return;
359
0
  }
360
0
361
0
  // If we're passing pointer events to children then we have to descend into
362
0
  // subdocuments no matter what, to determine which parts are transparent for
363
0
  // hit-testing or event regions.
364
0
  bool needToDescend = aBuilder->GetDescendIntoSubdocuments();
365
0
  if (!mInnerView || !needToDescend) {
366
0
    return;
367
0
  }
368
0
369
0
  if (rfp) {
370
0
    rfp->BuildDisplayList(aBuilder, this, aLists);
371
0
    return;
372
0
  }
373
0
374
0
  nsCOMPtr<nsIPresShell> presShell =
375
0
    GetSubdocumentPresShellForPainting(
376
0
      aBuilder->IsIgnoringPaintSuppression() ? IGNORE_PAINT_SUPPRESSION : 0);
377
0
378
0
  if (!presShell) {
379
0
    return;
380
0
  }
381
0
382
0
  if (aBuilder->IsInFilter()) {
383
0
    nsIDocument* outerDoc = PresShell()->GetDocument();
384
0
    nsIDocument* innerDoc = presShell->GetDocument();
385
0
    if (outerDoc && innerDoc) {
386
0
      if (!outerDoc->NodePrincipal()->Equals(innerDoc->NodePrincipal())) {
387
0
        outerDoc->SetDocumentAndPageUseCounter(eUseCounter_custom_FilteredCrossOriginIFrame);
388
0
      }
389
0
    }
390
0
  }
391
0
392
0
  nsIFrame* subdocRootFrame = presShell->GetRootFrame();
393
0
394
0
  nsPresContext* presContext = presShell->GetPresContext();
395
0
396
0
  int32_t parentAPD = PresContext()->AppUnitsPerDevPixel();
397
0
  int32_t subdocAPD = presContext->AppUnitsPerDevPixel();
398
0
399
0
  nsRect visible;
400
0
  nsRect dirty;
401
0
  bool haveDisplayPort = false;
402
0
  bool ignoreViewportScrolling = false;
403
0
  nsIFrame* savedIgnoreScrollFrame = nullptr;
404
0
  if (subdocRootFrame) {
405
0
    // get the dirty rect relative to the root frame of the subdoc
406
0
    visible = aBuilder->GetVisibleRect() + GetOffsetToCrossDoc(subdocRootFrame);
407
0
    dirty = aBuilder->GetDirtyRect() + GetOffsetToCrossDoc(subdocRootFrame);
408
0
    // and convert into the appunits of the subdoc
409
0
    visible = visible.ScaleToOtherAppUnitsRoundOut(parentAPD, subdocAPD);
410
0
    dirty = dirty.ScaleToOtherAppUnitsRoundOut(parentAPD, subdocAPD);
411
0
412
0
    if (nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame()) {
413
0
      nsIScrollableFrame* rootScrollableFrame = presShell->GetRootScrollFrameAsScrollable();
414
0
      MOZ_ASSERT(rootScrollableFrame);
415
0
      // Use a copy, so the rects don't get modified.
416
0
      nsRect copyOfDirty = dirty;
417
0
      nsRect copyOfVisible = visible;
418
0
      haveDisplayPort = rootScrollableFrame->DecideScrollableLayer(aBuilder,
419
0
                          &copyOfVisible, &copyOfDirty,
420
0
                          /* aSetBase = */ true);
421
0
422
0
      if (!gfxPrefs::LayoutUseContainersForRootFrames() ||
423
0
          !aBuilder->IsPaintingToWindow()) {
424
0
        haveDisplayPort = false;
425
0
      }
426
0
427
0
      ignoreViewportScrolling = presShell->IgnoringViewportScrolling();
428
0
      if (ignoreViewportScrolling) {
429
0
        savedIgnoreScrollFrame = aBuilder->GetIgnoreScrollFrame();
430
0
        aBuilder->SetIgnoreScrollFrame(rootScrollFrame);
431
0
      }
432
0
    }
433
0
434
0
    aBuilder->EnterPresShell(subdocRootFrame, pointerEventsNone);
435
0
    aBuilder->IncrementPresShellPaintCount(presShell);
436
0
  } else {
437
0
    visible = aBuilder->GetVisibleRect();
438
0
    dirty = aBuilder->GetDirtyRect();
439
0
  }
440
0
441
0
  DisplayListClipState::AutoSaveRestore clipState(aBuilder);
442
0
  if (ShouldClipSubdocument()) {
443
0
    clipState.ClipContainingBlockDescendantsToContentBox(aBuilder, this);
444
0
  }
445
0
446
0
  nsIScrollableFrame *sf = presShell->GetRootScrollFrameAsScrollable();
447
0
  bool constructResolutionItem = subdocRootFrame &&
448
0
    (presShell->GetResolution() != 1.0);
449
0
  bool constructZoomItem = subdocRootFrame && parentAPD != subdocAPD;
450
0
  bool needsOwnLayer = false;
451
0
  if (constructResolutionItem ||
452
0
      constructZoomItem ||
453
0
      haveDisplayPort ||
454
0
      presContext->IsRootContentDocument() ||
455
0
      (sf && sf->IsScrollingActive(aBuilder)))
456
0
  {
457
0
    needsOwnLayer = true;
458
0
  }
459
0
460
0
  if (aBuilder->IsRetainingDisplayList()) {
461
0
    // Caret frame changed, rebuild the entire subdoc.
462
0
    // We could just invalidate the old and new frame
463
0
    // areas and save some work here. RetainedDisplayListBuilder
464
0
    // does this, so we could teach it to find and check all
465
0
    // subdocs in advance.
466
0
    if (mPreviousCaret != aBuilder->GetCaretFrame()) {
467
0
      dirty = visible;
468
0
      aBuilder->RebuildAllItemsInCurrentSubtree();
469
0
      // Mark the old caret frame as invalid so that we remove the
470
0
      // old nsDisplayCaret. We don't mark the current frame as invalid
471
0
      // since we want the nsDisplaySubdocument to retain it's place
472
0
      // in the retained display list.
473
0
      if (mPreviousCaret) {
474
0
        aBuilder->MarkFrameModifiedDuringBuilding(mPreviousCaret);
475
0
      }
476
0
      if (aBuilder->GetCaretFrame()) {
477
0
        aBuilder->MarkFrameModifiedDuringBuilding(aBuilder->GetCaretFrame());
478
0
      }
479
0
    }
480
0
    mPreviousCaret = aBuilder->GetCaretFrame();
481
0
  }
482
0
483
0
  nsDisplayList childItems;
484
0
485
0
  {
486
0
    DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder);
487
0
    if (needsOwnLayer) {
488
0
      // Clear current clip. There's no point in propagating it down, since
489
0
      // the layer we will construct will be clipped by the current clip.
490
0
      // In fact for nsDisplayZoom propagating it down would be incorrect since
491
0
      // nsDisplayZoom changes the meaning of appunits.
492
0
      nestedClipState.Clear();
493
0
    }
494
0
495
0
    // Invoke AutoBuildingDisplayList to ensure that the correct dirty rect
496
0
    // is used to compute the visible rect if AddCanvasBackgroundColorItem
497
0
    // creates a display item.
498
0
    nsIFrame* frame = subdocRootFrame ? subdocRootFrame : this;
499
0
    nsDisplayListBuilder::AutoBuildingDisplayList
500
0
      building(aBuilder, frame, visible, dirty, true);
501
0
502
0
    if (subdocRootFrame) {
503
0
      nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
504
0
      nsDisplayListBuilder::AutoCurrentScrollParentIdSetter idSetter(
505
0
          aBuilder,
506
0
          ignoreViewportScrolling && rootScrollFrame && rootScrollFrame->GetContent()
507
0
              ? nsLayoutUtils::FindOrCreateIDFor(rootScrollFrame->GetContent())
508
0
              : aBuilder->GetCurrentScrollParentId());
509
0
510
0
      bool hasDocumentLevelListenersForApzAwareEvents =
511
0
          gfxPlatform::AsyncPanZoomEnabled() &&
512
0
          nsLayoutUtils::HasDocumentLevelListenersForApzAwareEvents(presShell);
513
0
514
0
      aBuilder->SetAncestorHasApzAwareEventHandler(hasDocumentLevelListenersForApzAwareEvents);
515
0
      subdocRootFrame->
516
0
        BuildDisplayListForStackingContext(aBuilder, &childItems);
517
0
    }
518
0
519
0
    if (!aBuilder->IsForEventDelivery()) {
520
0
      // If we are going to use a displayzoom below then any items we put under
521
0
      // it need to have underlying frames from the subdocument. So we need to
522
0
      // calculate the bounds based on which frame will be the underlying frame
523
0
      // for the canvas background color item.
524
0
      nsRect bounds = GetContentRectRelativeToSelf() +
525
0
        aBuilder->ToReferenceFrame(this);
526
0
      if (subdocRootFrame) {
527
0
        bounds = bounds.ScaleToOtherAppUnitsRoundOut(parentAPD, subdocAPD);
528
0
      }
529
0
530
0
      // If we are in print preview/page layout we want to paint the grey
531
0
      // background behind the page, not the canvas color. The canvas color gets
532
0
      // painted on the page itself.
533
0
      if (nsLayoutUtils::NeedsPrintPreviewBackground(presContext)) {
534
0
        presShell->AddPrintPreviewBackgroundItem(
535
0
          *aBuilder, childItems, frame, bounds);
536
0
      } else {
537
0
        // Add the canvas background color to the bottom of the list. This
538
0
        // happens after we've built the list so that AddCanvasBackgroundColorItem
539
0
        // can monkey with the contents if necessary.
540
0
        uint32_t flags = nsIPresShell::FORCE_DRAW | nsIPresShell::ADD_FOR_SUBDOC;
541
0
        presShell->AddCanvasBackgroundColorItem(
542
0
          *aBuilder, childItems, frame, bounds, NS_RGBA(0,0,0,0), flags);
543
0
      }
544
0
    }
545
0
  }
546
0
547
0
  if (subdocRootFrame) {
548
0
    aBuilder->LeavePresShell(subdocRootFrame, &childItems);
549
0
550
0
    if (ignoreViewportScrolling) {
551
0
      aBuilder->SetIgnoreScrollFrame(savedIgnoreScrollFrame);
552
0
    }
553
0
  }
554
0
555
0
  // Generate a resolution and/or zoom item if needed. If one or both of those is
556
0
  // created, we don't need to create a separate nsDisplaySubDocument.
557
0
558
0
  nsDisplayOwnLayerFlags flags = nsDisplayOwnLayerFlags::eGenerateSubdocInvalidations;
559
0
  // If ignoreViewportScrolling is true then the top most layer we create here
560
0
  // is going to become the scrollable layer for the root scroll frame, so we
561
0
  // want to add nsDisplayOwnLayer::GENERATE_SCROLLABLE_LAYER to whatever layer
562
0
  // becomes the topmost. We do this below.
563
0
  if (constructZoomItem) {
564
0
    nsDisplayOwnLayerFlags zoomFlags = flags;
565
0
    if (ignoreViewportScrolling && !constructResolutionItem) {
566
0
      zoomFlags |= nsDisplayOwnLayerFlags::eGenerateScrollableLayer;
567
0
    }
568
0
    nsDisplayZoom* zoomItem = MakeDisplayItem<nsDisplayZoom>(
569
0
      aBuilder, subdocRootFrame, this, &childItems, subdocAPD, parentAPD, zoomFlags);
570
0
571
0
    childItems.AppendToTop(zoomItem);
572
0
    needsOwnLayer = false;
573
0
  }
574
0
  // Wrap the zoom item in the resolution item if we have both because we want the
575
0
  // resolution scale applied on top of the app units per dev pixel conversion.
576
0
  if (ignoreViewportScrolling) {
577
0
    flags |= nsDisplayOwnLayerFlags::eGenerateScrollableLayer;
578
0
  }
579
0
  if (constructResolutionItem) {
580
0
    nsDisplayResolution* resolutionItem = MakeDisplayItem<nsDisplayResolution>(
581
0
      aBuilder, subdocRootFrame, this, &childItems, flags);
582
0
583
0
    childItems.AppendToTop(resolutionItem);
584
0
    needsOwnLayer = false;
585
0
  }
586
0
587
0
  // We always want top level content documents to be in their own layer.
588
0
  nsDisplaySubDocument* layerItem = MakeDisplayItem<nsDisplaySubDocument>(
589
0
    aBuilder, subdocRootFrame ? subdocRootFrame : this, this,
590
0
    &childItems, flags);
591
0
  childItems.AppendToTop(layerItem);
592
0
  layerItem->SetShouldFlattenAway(!needsOwnLayer);
593
0
594
0
  // If we're using containers for root frames, then the earlier call
595
0
  // to AddCanvasBackgroundColorItem won't have been able to add an
596
0
  // unscrolled color item for overscroll. Try again now that we're
597
0
  // outside the scrolled ContainerLayer.
598
0
  if (!aBuilder->IsForEventDelivery() &&
599
0
      gfxPrefs::LayoutUseContainersForRootFrames() &&
600
0
      !nsLayoutUtils::NeedsPrintPreviewBackground(presContext)) {
601
0
     nsRect bounds = GetContentRectRelativeToSelf() +
602
0
       aBuilder->ToReferenceFrame(this);
603
0
604
0
    // Invoke AutoBuildingDisplayList to ensure that the correct dirty rect
605
0
    // is used to compute the visible rect if AddCanvasBackgroundColorItem
606
0
    // creates a display item.
607
0
    nsDisplayListBuilder::AutoBuildingDisplayList
608
0
      building(aBuilder, this, visible, dirty, true);
609
0
    // Add the canvas background color to the bottom of the list. This
610
0
    // happens after we've built the list so that AddCanvasBackgroundColorItem
611
0
    // can monkey with the contents if necessary.
612
0
    uint32_t flags = nsIPresShell::FORCE_DRAW | nsIPresShell::APPEND_UNSCROLLED_ONLY;
613
0
    presShell->AddCanvasBackgroundColorItem(
614
0
      *aBuilder, childItems, this, bounds, NS_RGBA(0,0,0,0), flags);
615
0
   }
616
0
617
0
  if (aBuilder->IsForFrameVisibility()) {
618
0
    // We don't add the childItems to the return list as we're dealing with them here.
619
0
    presShell->RebuildApproximateFrameVisibilityDisplayList(childItems);
620
0
    childItems.DeleteAll(aBuilder);
621
0
  } else {
622
0
    aLists.Content()->AppendToTop(&childItems);
623
0
  }
624
0
}
625
626
nscoord
627
nsSubDocumentFrame::GetIntrinsicISize()
628
0
{
629
0
  if (!IsInline()) {
630
0
    return 0;  // HTML <frame> has no useful intrinsic isize
631
0
  }
632
0
633
0
  if (mContent->IsXULElement()) {
634
0
    return 0;  // XUL <iframe> and <browser> have no useful intrinsic isize
635
0
  }
636
0
637
0
  NS_ASSERTION(ObtainIntrinsicSizeFrame() == nullptr,
638
0
               "Intrinsic isize should come from the embedded document.");
639
0
640
0
  // We must be an HTML <iframe>.  Default to size of 300px x 150px, for IE
641
0
  // compat (and per CSS2.1 draft).
642
0
  WritingMode wm = GetWritingMode();
643
0
  return nsPresContext::CSSPixelsToAppUnits(wm.IsVertical() ? 150 : 300);
644
0
}
645
646
nscoord
647
nsSubDocumentFrame::GetIntrinsicBSize()
648
0
{
649
0
  // <frame> processing does not use this routine, only <iframe>
650
0
  NS_ASSERTION(IsInline(), "Shouldn't have been called");
651
0
652
0
  if (mContent->IsXULElement()) {
653
0
    return 0;
654
0
  }
655
0
656
0
  NS_ASSERTION(ObtainIntrinsicSizeFrame() == nullptr,
657
0
               "Intrinsic bsize should come from the embedded document.");
658
0
659
0
  // Use size of 300px x 150px, for compatibility with IE, and per CSS2.1 draft.
660
0
  WritingMode wm = GetWritingMode();
661
0
  return nsPresContext::CSSPixelsToAppUnits(wm.IsVertical() ? 300 : 150);
662
0
}
663
664
#ifdef DEBUG_FRAME_DUMP
665
void
666
nsSubDocumentFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
667
{
668
  nsCString str;
669
  ListGeneric(str, aPrefix, aFlags);
670
  fprintf_stderr(out, "%s\n", str.get());
671
672
  if (aFlags & TRAVERSE_SUBDOCUMENT_FRAMES) {
673
    nsSubDocumentFrame* f = const_cast<nsSubDocumentFrame*>(this);
674
    nsIFrame* subdocRootFrame = f->GetSubdocumentRootFrame();
675
    if (subdocRootFrame) {
676
      nsCString pfx(aPrefix);
677
      pfx += "  ";
678
      subdocRootFrame->List(out, pfx.get(), aFlags);
679
    }
680
  }
681
}
682
683
nsresult nsSubDocumentFrame::GetFrameName(nsAString& aResult) const
684
{
685
  return MakeFrameName(NS_LITERAL_STRING("FrameOuter"), aResult);
686
}
687
#endif
688
689
/* virtual */ nscoord
690
nsSubDocumentFrame::GetMinISize(gfxContext *aRenderingContext)
691
0
{
692
0
  nscoord result;
693
0
  DISPLAY_MIN_INLINE_SIZE(this, result);
694
0
695
0
  nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
696
0
  if (subDocRoot) {
697
0
    result = subDocRoot->GetMinISize(aRenderingContext);
698
0
  } else {
699
0
    result = GetIntrinsicISize();
700
0
  }
701
0
702
0
  return result;
703
0
}
704
705
/* virtual */ nscoord
706
nsSubDocumentFrame::GetPrefISize(gfxContext *aRenderingContext)
707
0
{
708
0
  nscoord result;
709
0
  DISPLAY_PREF_INLINE_SIZE(this, result);
710
0
711
0
  nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
712
0
  if (subDocRoot) {
713
0
    result = subDocRoot->GetPrefISize(aRenderingContext);
714
0
  } else {
715
0
    result = GetIntrinsicISize();
716
0
  }
717
0
718
0
  return result;
719
0
}
720
721
/* virtual */ IntrinsicSize
722
nsSubDocumentFrame::GetIntrinsicSize()
723
0
{
724
0
  nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
725
0
  if (subDocRoot) {
726
0
    return subDocRoot->GetIntrinsicSize();
727
0
  }
728
0
  return nsAtomicContainerFrame::GetIntrinsicSize();
729
0
}
730
731
/* virtual */ nsSize
732
nsSubDocumentFrame::GetIntrinsicRatio()
733
0
{
734
0
  nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
735
0
  if (subDocRoot) {
736
0
    return subDocRoot->GetIntrinsicRatio();
737
0
  }
738
0
  return nsAtomicContainerFrame::GetIntrinsicRatio();
739
0
}
740
741
/* virtual */
742
LogicalSize
743
nsSubDocumentFrame::ComputeAutoSize(gfxContext*         aRenderingContext,
744
                                    WritingMode         aWM,
745
                                    const LogicalSize&  aCBSize,
746
                                    nscoord             aAvailableISize,
747
                                    const LogicalSize&  aMargin,
748
                                    const LogicalSize&  aBorder,
749
                                    const LogicalSize&  aPadding,
750
                                    ComputeSizeFlags    aFlags)
751
0
{
752
0
  if (!IsInline()) {
753
0
    return nsFrame::ComputeAutoSize(aRenderingContext, aWM, aCBSize,
754
0
                                    aAvailableISize, aMargin, aBorder,
755
0
                                    aPadding, aFlags);
756
0
  }
757
0
758
0
  const WritingMode wm = GetWritingMode();
759
0
  LogicalSize result(wm, GetIntrinsicISize(), GetIntrinsicBSize());
760
0
  return result.ConvertTo(aWM, wm);
761
0
}
762
763
764
/* virtual */
765
LogicalSize
766
nsSubDocumentFrame::ComputeSize(gfxContext*         aRenderingContext,
767
                                WritingMode         aWM,
768
                                const LogicalSize&  aCBSize,
769
                                nscoord             aAvailableISize,
770
                                const LogicalSize&  aMargin,
771
                                const LogicalSize&  aBorder,
772
                                const LogicalSize&  aPadding,
773
                                ComputeSizeFlags    aFlags)
774
0
{
775
0
  nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
776
0
  if (subDocRoot) {
777
0
    return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM,
778
0
                                              subDocRoot->GetIntrinsicSize(),
779
0
                                              subDocRoot->GetIntrinsicRatio(),
780
0
                                              aCBSize, aMargin, aBorder,
781
0
                                              aPadding, aFlags);
782
0
  }
783
0
  return nsAtomicContainerFrame::ComputeSize(aRenderingContext, aWM,
784
0
                                             aCBSize, aAvailableISize,
785
0
                                             aMargin, aBorder, aPadding,
786
0
                                             aFlags);
787
0
}
788
789
void
790
nsSubDocumentFrame::Reflow(nsPresContext*           aPresContext,
791
                           ReflowOutput&     aDesiredSize,
792
                           const ReflowInput& aReflowInput,
793
                           nsReflowStatus&          aStatus)
794
0
{
795
0
  MarkInReflow();
796
0
  DO_GLOBAL_REFLOW_COUNT("nsSubDocumentFrame");
797
0
  DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
798
0
  MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
799
0
  NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
800
0
     ("enter nsSubDocumentFrame::Reflow: maxSize=%d,%d",
801
0
      aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight()));
802
0
803
0
  NS_ASSERTION(aReflowInput.ComputedWidth() != NS_UNCONSTRAINEDSIZE,
804
0
               "Shouldn't have unconstrained stuff here "
805
0
               "thanks to the rules of reflow");
806
0
  NS_ASSERTION(NS_INTRINSICSIZE != aReflowInput.ComputedHeight(),
807
0
               "Shouldn't have unconstrained stuff here "
808
0
               "thanks to ComputeAutoSize");
809
0
810
0
  NS_ASSERTION(mContent->GetPrimaryFrame() == this,
811
0
               "Shouldn't happen");
812
0
813
0
  // XUL <iframe> or <browser>, or HTML <iframe>, <object> or <embed>
814
0
  aDesiredSize.SetSize(aReflowInput.GetWritingMode(),
815
0
                       aReflowInput.ComputedSizeWithBorderPadding());
816
0
817
0
  // "offset" is the offset of our content area from our frame's
818
0
  // top-left corner.
819
0
  nsPoint offset = nsPoint(aReflowInput.ComputedPhysicalBorderPadding().left,
820
0
                           aReflowInput.ComputedPhysicalBorderPadding().top);
821
0
822
0
  if (mInnerView) {
823
0
    const nsMargin& bp = aReflowInput.ComputedPhysicalBorderPadding();
824
0
    nsSize innerSize(aDesiredSize.Width() - bp.LeftRight(),
825
0
                     aDesiredSize.Height() - bp.TopBottom());
826
0
827
0
    // Size & position the view according to 'object-fit' & 'object-position'.
828
0
    nsIFrame* subDocRoot = ObtainIntrinsicSizeFrame();
829
0
    IntrinsicSize intrinsSize;
830
0
    nsSize intrinsRatio;
831
0
    if (subDocRoot) {
832
0
      intrinsSize = subDocRoot->GetIntrinsicSize();
833
0
      intrinsRatio = subDocRoot->GetIntrinsicRatio();
834
0
    }
835
0
    nsRect destRect =
836
0
      nsLayoutUtils::ComputeObjectDestRect(nsRect(offset, innerSize),
837
0
                                           intrinsSize, intrinsRatio,
838
0
                                           StylePosition());
839
0
840
0
    nsViewManager* vm = mInnerView->GetViewManager();
841
0
    vm->MoveViewTo(mInnerView, destRect.x, destRect.y);
842
0
    vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), destRect.Size()), true);
843
0
  }
844
0
845
0
  aDesiredSize.SetOverflowAreasToDesiredBounds();
846
0
  if (!ShouldClipSubdocument()) {
847
0
    nsIFrame* subdocRootFrame = GetSubdocumentRootFrame();
848
0
    if (subdocRootFrame) {
849
0
      aDesiredSize.mOverflowAreas.UnionWith(subdocRootFrame->GetOverflowAreas() + offset);
850
0
    }
851
0
  }
852
0
853
0
  FinishAndStoreOverflow(&aDesiredSize);
854
0
855
0
  if (!aPresContext->IsPaginated() && !mPostedReflowCallback) {
856
0
    PresShell()->PostReflowCallback(this);
857
0
    mPostedReflowCallback = true;
858
0
  }
859
0
860
0
  NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
861
0
     ("exit nsSubDocumentFrame::Reflow: size=%d,%d status=%s",
862
0
      aDesiredSize.Width(), aDesiredSize.Height(), ToString(aStatus).c_str()));
863
0
864
0
  NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
865
0
}
866
867
bool
868
nsSubDocumentFrame::ReflowFinished()
869
0
{
870
0
  if (mFrameLoader) {
871
0
    AutoWeakFrame weakFrame(this);
872
0
873
0
    mFrameLoader->UpdatePositionAndSize(this);
874
0
875
0
    if (weakFrame.IsAlive()) {
876
0
      // Make sure that we can post a reflow callback in the future.
877
0
      mPostedReflowCallback = false;
878
0
    }
879
0
  } else {
880
0
    mPostedReflowCallback = false;
881
0
  }
882
0
  return false;
883
0
}
884
885
void
886
nsSubDocumentFrame::ReflowCallbackCanceled()
887
0
{
888
0
  mPostedReflowCallback = false;
889
0
}
890
891
nsresult
892
nsSubDocumentFrame::AttributeChanged(int32_t aNameSpaceID,
893
                                     nsAtom* aAttribute,
894
                                     int32_t aModType)
895
0
{
896
0
  if (aNameSpaceID != kNameSpaceID_None) {
897
0
    return NS_OK;
898
0
  }
899
0
900
0
  // If the noResize attribute changes, dis/allow frame to be resized
901
0
  if (aAttribute == nsGkAtoms::noresize) {
902
0
    // Note that we're not doing content type checks, but that's ok -- if
903
0
    // they'd fail we will just end up with a null framesetFrame.
904
0
    if (mContent->GetParent()->IsHTMLElement(nsGkAtoms::frameset)) {
905
0
      nsIFrame* parentFrame = GetParent();
906
0
907
0
      if (parentFrame) {
908
0
        // There is no interface for nsHTMLFramesetFrame so QI'ing to
909
0
        // concrete class, yay!
910
0
        nsHTMLFramesetFrame* framesetFrame = do_QueryFrame(parentFrame);
911
0
        if (framesetFrame) {
912
0
          framesetFrame->RecalculateBorderResize();
913
0
        }
914
0
      }
915
0
    }
916
0
  }
917
0
  else if (aAttribute == nsGkAtoms::showresizer) {
918
0
    nsIFrame* rootFrame = GetSubdocumentRootFrame();
919
0
    if (rootFrame) {
920
0
      rootFrame->PresShell()->
921
0
        FrameNeedsReflow(rootFrame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
922
0
    }
923
0
  }
924
0
  else if (aAttribute == nsGkAtoms::marginwidth ||
925
0
           aAttribute == nsGkAtoms::marginheight) {
926
0
927
0
    // Retrieve the attributes
928
0
    CSSIntSize margins = GetMarginAttributes();
929
0
930
0
    // Notify the frameloader
931
0
    RefPtr<nsFrameLoader> frameloader = FrameLoader();
932
0
    if (frameloader)
933
0
      frameloader->MarginsChanged(margins.width, margins.height);
934
0
  }
935
0
936
0
  return NS_OK;
937
0
}
938
939
nsIFrame*
940
NS_NewSubDocumentFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle)
941
0
{
942
0
  return new (aPresShell) nsSubDocumentFrame(aStyle);
943
0
}
944
945
NS_IMPL_FRAMEARENA_HELPERS(nsSubDocumentFrame)
946
947
class nsHideViewer : public Runnable {
948
public:
949
  nsHideViewer(nsIContent* aFrameElement,
950
               nsFrameLoader* aFrameLoader,
951
               nsIPresShell* aPresShell,
952
               bool aHideViewerIfFrameless)
953
    : mozilla::Runnable("nsHideViewer")
954
    , mFrameElement(aFrameElement)
955
    , mFrameLoader(aFrameLoader)
956
    , mPresShell(aPresShell)
957
    , mHideViewerIfFrameless(aHideViewerIfFrameless)
958
0
  {
959
0
    NS_ASSERTION(mFrameElement, "Must have a frame element");
960
0
    NS_ASSERTION(mFrameLoader, "Must have a frame loader");
961
0
    NS_ASSERTION(mPresShell, "Must have a presshell");
962
0
  }
963
964
  NS_IMETHOD Run() override
965
0
  {
966
0
    // Flush frames, to ensure any pending display:none changes are made.
967
0
    // Note it can be unsafe to flush if we've destroyed the presentation
968
0
    // for some other reason, like if we're shutting down.
969
0
    //
970
0
    // But avoid the flush if we know for sure we're away, like when we're out
971
0
    // of the document already.
972
0
    //
973
0
    // FIXME(emilio): This could still be a perf footgun when removing lots of
974
0
    // siblings where each of them cause the reframe of an ancestor which happen
975
0
    // to contain a subdocument.
976
0
    //
977
0
    // We should find some way to avoid that!
978
0
    if (!mPresShell->IsDestroying() && mFrameElement->IsInComposedDoc()) {
979
0
      mPresShell->FlushPendingNotifications(FlushType::Frames);
980
0
    }
981
0
982
0
    // Either the frame has been constructed by now, or it never will be,
983
0
    // either way we want to clear the stashed views.
984
0
    mFrameLoader->SetDetachedSubdocFrame(nullptr, nullptr);
985
0
986
0
    nsSubDocumentFrame* frame = do_QueryFrame(mFrameElement->GetPrimaryFrame());
987
0
    if ((!frame && mHideViewerIfFrameless) ||
988
0
        mPresShell->IsDestroying()) {
989
0
      // Either the frame element has no nsIFrame or the presshell is being
990
0
      // destroyed. Hide the nsFrameLoader, which destroys the presentation.
991
0
      mFrameLoader->Hide();
992
0
    }
993
0
    return NS_OK;
994
0
  }
995
private:
996
  nsCOMPtr<nsIContent> mFrameElement;
997
  RefPtr<nsFrameLoader> mFrameLoader;
998
  nsCOMPtr<nsIPresShell> mPresShell;
999
  bool mHideViewerIfFrameless;
1000
};
1001
1002
static nsView*
1003
BeginSwapDocShellsForViews(nsView* aSibling);
1004
1005
void
1006
nsSubDocumentFrame::DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData& aPostDestroyData)
1007
0
{
1008
0
  if (mPostedReflowCallback) {
1009
0
    PresShell()->CancelReflowCallback(this);
1010
0
    mPostedReflowCallback = false;
1011
0
  }
1012
0
1013
0
  // Detach the subdocument's views and stash them in the frame loader.
1014
0
  // We can then reattach them if we're being reframed (for example if
1015
0
  // the frame has been made position:fixed).
1016
0
  RefPtr<nsFrameLoader> frameloader = FrameLoader();
1017
0
  if (frameloader) {
1018
0
    nsView* detachedViews = ::BeginSwapDocShellsForViews(mInnerView->GetFirstChild());
1019
0
1020
0
    if (detachedViews && detachedViews->GetFrame()) {
1021
0
      MOZ_ASSERT(mContent->OwnerDoc());
1022
0
      frameloader->SetDetachedSubdocFrame(
1023
0
        detachedViews->GetFrame(), mContent->OwnerDoc());
1024
0
1025
0
      // We call nsFrameLoader::HideViewer() in a script runner so that we can
1026
0
      // safely determine whether the frame is being reframed or destroyed.
1027
0
      nsContentUtils::AddScriptRunner(
1028
0
        new nsHideViewer(mContent,
1029
0
                         frameloader,
1030
0
                         PresShell(),
1031
0
                         (mDidCreateDoc || mCallingShow)));
1032
0
    } else {
1033
0
      frameloader->SetDetachedSubdocFrame(nullptr, nullptr);
1034
0
      if (mDidCreateDoc || mCallingShow) {
1035
0
        frameloader->Hide();
1036
0
      }
1037
0
    }
1038
0
  }
1039
0
1040
0
  nsAtomicContainerFrame::DestroyFrom(aDestructRoot, aPostDestroyData);
1041
0
}
1042
1043
CSSIntSize
1044
nsSubDocumentFrame::GetMarginAttributes()
1045
0
{
1046
0
  CSSIntSize result(-1, -1);
1047
0
  nsGenericHTMLElement *content = nsGenericHTMLElement::FromNode(mContent);
1048
0
  if (content) {
1049
0
    const nsAttrValue* attr = content->GetParsedAttr(nsGkAtoms::marginwidth);
1050
0
    if (attr && attr->Type() == nsAttrValue::eInteger)
1051
0
      result.width = attr->GetIntegerValue();
1052
0
    attr = content->GetParsedAttr(nsGkAtoms::marginheight);
1053
0
    if (attr && attr->Type() == nsAttrValue::eInteger)
1054
0
      result.height = attr->GetIntegerValue();
1055
0
  }
1056
0
  return result;
1057
0
}
1058
1059
nsFrameLoader*
1060
nsSubDocumentFrame::FrameLoader() const
1061
0
{
1062
0
  nsIContent* content = GetContent();
1063
0
  if (!content)
1064
0
    return nullptr;
1065
0
1066
0
  if (!mFrameLoader) {
1067
0
    nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(content);
1068
0
    if (loaderOwner) {
1069
0
      mFrameLoader = loaderOwner->GetFrameLoader();
1070
0
    }
1071
0
  }
1072
0
  return mFrameLoader;
1073
0
}
1074
1075
mozilla::layout::RenderFrameParent*
1076
nsSubDocumentFrame::GetRenderFrameParent() const
1077
0
{
1078
0
  return FrameLoader() ? FrameLoader()->GetCurrentRenderFrame() : nullptr;
1079
0
}
1080
1081
// XXX this should be called ObtainDocShell or something like that,
1082
// to indicate that it could have side effects
1083
nsIDocShell*
1084
nsSubDocumentFrame::GetDocShell()
1085
0
{
1086
0
  // How can FrameLoader() return null???
1087
0
  if (NS_WARN_IF(!FrameLoader())) {
1088
0
    return nullptr;
1089
0
  }
1090
0
  return mFrameLoader->GetDocShell(IgnoreErrors());
1091
0
}
1092
1093
static void
1094
DestroyDisplayItemDataForFrames(nsIFrame* aFrame)
1095
0
{
1096
0
  FrameLayerBuilder::DestroyDisplayItemDataFor(aFrame);
1097
0
1098
0
  nsIFrame::ChildListIterator lists(aFrame);
1099
0
  for (; !lists.IsDone(); lists.Next()) {
1100
0
    nsFrameList::Enumerator childFrames(lists.CurrentList());
1101
0
    for (; !childFrames.AtEnd(); childFrames.Next()) {
1102
0
      DestroyDisplayItemDataForFrames(childFrames.get());
1103
0
    }
1104
0
  }
1105
0
}
1106
1107
static bool
1108
BeginSwapDocShellsForDocument(nsIDocument* aDocument, void*)
1109
0
{
1110
0
  MOZ_ASSERT(aDocument, "null document");
1111
0
1112
0
  nsIPresShell* shell = aDocument->GetShell();
1113
0
  if (shell) {
1114
0
    // Disable painting while the views are detached, see bug 946929.
1115
0
    shell->SetNeverPainting(true);
1116
0
1117
0
    nsIFrame* rootFrame = shell->GetRootFrame();
1118
0
    if (rootFrame) {
1119
0
      ::DestroyDisplayItemDataForFrames(rootFrame);
1120
0
    }
1121
0
  }
1122
0
  aDocument->EnumerateActivityObservers(
1123
0
    nsPluginFrame::BeginSwapDocShells, nullptr);
1124
0
  aDocument->EnumerateSubDocuments(BeginSwapDocShellsForDocument, nullptr);
1125
0
  return true;
1126
0
}
1127
1128
static nsView*
1129
BeginSwapDocShellsForViews(nsView* aSibling)
1130
0
{
1131
0
  // Collect the removed sibling views in reverse order in 'removedViews'.
1132
0
  nsView* removedViews = nullptr;
1133
0
  while (aSibling) {
1134
0
    nsIDocument* doc = ::GetDocumentFromView(aSibling);
1135
0
    if (doc) {
1136
0
      ::BeginSwapDocShellsForDocument(doc, nullptr);
1137
0
    }
1138
0
    nsView* next = aSibling->GetNextSibling();
1139
0
    aSibling->GetViewManager()->RemoveChild(aSibling);
1140
0
    aSibling->SetNextSibling(removedViews);
1141
0
    removedViews = aSibling;
1142
0
    aSibling = next;
1143
0
  }
1144
0
  return removedViews;
1145
0
}
1146
1147
static void
1148
InsertViewsInReverseOrder(nsView* aSibling, nsView* aParent)
1149
0
{
1150
0
  MOZ_ASSERT(aParent, "null view");
1151
0
  MOZ_ASSERT(!aParent->GetFirstChild(), "inserting into non-empty list");
1152
0
1153
0
  nsViewManager* vm = aParent->GetViewManager();
1154
0
  while (aSibling) {
1155
0
    nsView* next = aSibling->GetNextSibling();
1156
0
    aSibling->SetNextSibling(nullptr);
1157
0
    // true means 'after' in document order which is 'before' in view order,
1158
0
    // so this call prepends the child, thus reversing the siblings as we go.
1159
0
    vm->InsertChild(aParent, aSibling, nullptr, true);
1160
0
    aSibling = next;
1161
0
  }
1162
0
}
1163
1164
nsresult
1165
nsSubDocumentFrame::BeginSwapDocShells(nsIFrame* aOther)
1166
0
{
1167
0
  if (!aOther || !aOther->IsSubDocumentFrame()) {
1168
0
    return NS_ERROR_NOT_IMPLEMENTED;
1169
0
  }
1170
0
1171
0
  nsSubDocumentFrame* other = static_cast<nsSubDocumentFrame*>(aOther);
1172
0
  if (!mFrameLoader || !mDidCreateDoc || mCallingShow ||
1173
0
      !other->mFrameLoader || !other->mDidCreateDoc) {
1174
0
    return NS_ERROR_NOT_IMPLEMENTED;
1175
0
  }
1176
0
1177
0
  ClearDisplayItems();
1178
0
  other->ClearDisplayItems();
1179
0
1180
0
  if (mInnerView && other->mInnerView) {
1181
0
    nsView* ourSubdocViews = mInnerView->GetFirstChild();
1182
0
    nsView* ourRemovedViews = ::BeginSwapDocShellsForViews(ourSubdocViews);
1183
0
    nsView* otherSubdocViews = other->mInnerView->GetFirstChild();
1184
0
    nsView* otherRemovedViews = ::BeginSwapDocShellsForViews(otherSubdocViews);
1185
0
1186
0
    ::InsertViewsInReverseOrder(ourRemovedViews, other->mInnerView);
1187
0
    ::InsertViewsInReverseOrder(otherRemovedViews, mInnerView);
1188
0
  }
1189
0
  mFrameLoader.swap(other->mFrameLoader);
1190
0
  return NS_OK;
1191
0
}
1192
1193
static bool
1194
EndSwapDocShellsForDocument(nsIDocument* aDocument, void*)
1195
0
{
1196
0
  MOZ_ASSERT(aDocument, "null document");
1197
0
1198
0
  // Our docshell and view trees have been updated for the new hierarchy.
1199
0
  // Now also update all nsDeviceContext::mWidget to that of the
1200
0
  // container view in the new hierarchy.
1201
0
  nsCOMPtr<nsIDocShell> ds = aDocument->GetDocShell();
1202
0
  if (ds) {
1203
0
    nsCOMPtr<nsIContentViewer> cv;
1204
0
    ds->GetContentViewer(getter_AddRefs(cv));
1205
0
    while (cv) {
1206
0
      RefPtr<nsPresContext> pc;
1207
0
      cv->GetPresContext(getter_AddRefs(pc));
1208
0
      if (pc && pc->GetPresShell()) {
1209
0
        pc->GetPresShell()->SetNeverPainting(ds->IsInvisible());
1210
0
      }
1211
0
      nsDeviceContext* dc = pc ? pc->DeviceContext() : nullptr;
1212
0
      if (dc) {
1213
0
        nsView* v = cv->FindContainerView();
1214
0
        dc->Init(v ? v->GetNearestWidget(nullptr) : nullptr);
1215
0
      }
1216
0
      nsCOMPtr<nsIContentViewer> prev;
1217
0
      cv->GetPreviousViewer(getter_AddRefs(prev));
1218
0
      cv = prev;
1219
0
    }
1220
0
  }
1221
0
1222
0
  aDocument->EnumerateActivityObservers(
1223
0
    nsPluginFrame::EndSwapDocShells, nullptr);
1224
0
  aDocument->EnumerateSubDocuments(EndSwapDocShellsForDocument, nullptr);
1225
0
  return true;
1226
0
}
1227
1228
static void
1229
EndSwapDocShellsForViews(nsView* aSibling)
1230
0
{
1231
0
  for ( ; aSibling; aSibling = aSibling->GetNextSibling()) {
1232
0
    nsIDocument* doc = ::GetDocumentFromView(aSibling);
1233
0
    if (doc) {
1234
0
      ::EndSwapDocShellsForDocument(doc, nullptr);
1235
0
    }
1236
0
    nsIFrame *frame = aSibling->GetFrame();
1237
0
    if (frame) {
1238
0
      nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(frame);
1239
0
      if (parent->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
1240
0
        nsIFrame::AddInPopupStateBitToDescendants(frame);
1241
0
      } else {
1242
0
        nsIFrame::RemoveInPopupStateBitFromDescendants(frame);
1243
0
      }
1244
0
      if (frame->HasInvalidFrameInSubtree()) {
1245
0
        while (parent && !parent->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT | NS_FRAME_IS_NONDISPLAY)) {
1246
0
          parent->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT);
1247
0
          parent = nsLayoutUtils::GetCrossDocParentFrame(parent);
1248
0
        }
1249
0
      }
1250
0
    }
1251
0
  }
1252
0
}
1253
1254
void
1255
nsSubDocumentFrame::EndSwapDocShells(nsIFrame* aOther)
1256
0
{
1257
0
  nsSubDocumentFrame* other = static_cast<nsSubDocumentFrame*>(aOther);
1258
0
  AutoWeakFrame weakThis(this);
1259
0
  AutoWeakFrame weakOther(aOther);
1260
0
1261
0
  if (mInnerView) {
1262
0
    ::EndSwapDocShellsForViews(mInnerView->GetFirstChild());
1263
0
  }
1264
0
  if (other->mInnerView) {
1265
0
    ::EndSwapDocShellsForViews(other->mInnerView->GetFirstChild());
1266
0
  }
1267
0
1268
0
  // Now make sure we reflow both frames, in case their contents
1269
0
  // determine their size.
1270
0
  // And repaint them, for good measure, in case there's nothing
1271
0
  // interesting that happens during reflow.
1272
0
  if (weakThis.IsAlive()) {
1273
0
    PresShell()->
1274
0
      FrameNeedsReflow(this, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
1275
0
    InvalidateFrameSubtree();
1276
0
  }
1277
0
  if (weakOther.IsAlive()) {
1278
0
    other->PresShell()->
1279
0
      FrameNeedsReflow(other, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
1280
0
    other->InvalidateFrameSubtree();
1281
0
  }
1282
0
}
1283
1284
void
1285
nsSubDocumentFrame::ClearDisplayItems()
1286
0
{
1287
0
  DisplayItemArray* items = GetProperty(DisplayItems());
1288
0
  if (!items) {
1289
0
    return;
1290
0
  }
1291
0
1292
0
  nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(this);
1293
0
  MOZ_ASSERT(displayRoot);
1294
0
1295
0
  RetainedDisplayListBuilder* retainedBuilder =
1296
0
    displayRoot->GetProperty(RetainedDisplayListBuilder::Cached());
1297
0
  MOZ_ASSERT(retainedBuilder);
1298
0
1299
0
  for (nsDisplayItem* i : *items) {
1300
0
    if (i->GetType() == DisplayItemType::TYPE_SUBDOCUMENT) {
1301
0
      i->GetChildren()->DeleteAll(retainedBuilder->Builder());
1302
0
      static_cast<nsDisplaySubDocument*>(i)->Disown();
1303
0
      break;
1304
0
    }
1305
0
  }
1306
0
}
1307
1308
nsView*
1309
nsSubDocumentFrame::EnsureInnerView()
1310
0
{
1311
0
  if (mInnerView) {
1312
0
    return mInnerView;
1313
0
  }
1314
0
1315
0
  // create, init, set the parent of the view
1316
0
  nsView* outerView = GetView();
1317
0
  NS_ASSERTION(outerView, "Must have an outer view already");
1318
0
  nsRect viewBounds(0, 0, 0, 0); // size will be fixed during reflow
1319
0
1320
0
  nsViewManager* viewMan = outerView->GetViewManager();
1321
0
  nsView* innerView = viewMan->CreateView(viewBounds, outerView);
1322
0
  if (!innerView) {
1323
0
    NS_ERROR("Could not create inner view");
1324
0
    return nullptr;
1325
0
  }
1326
0
  mInnerView = innerView;
1327
0
  viewMan->InsertChild(outerView, innerView, nullptr, true);
1328
0
1329
0
  return mInnerView;
1330
0
}
1331
1332
nsIFrame*
1333
nsSubDocumentFrame::ObtainIntrinsicSizeFrame()
1334
0
{
1335
0
  nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(GetContent());
1336
0
  if (olc) {
1337
0
    // We are an HTML <object> or <embed> (a replaced element).
1338
0
1339
0
    // Try to get an nsIFrame for our sub-document's document element
1340
0
    nsIFrame* subDocRoot = nullptr;
1341
0
1342
0
    nsIDocShell* docShell = GetDocShell();
1343
0
    if (docShell) {
1344
0
      nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell();
1345
0
      if (presShell) {
1346
0
        nsIScrollableFrame* scrollable = presShell->GetRootScrollFrameAsScrollable();
1347
0
        if (scrollable) {
1348
0
          nsIFrame* scrolled = scrollable->GetScrolledFrame();
1349
0
          if (scrolled) {
1350
0
            subDocRoot = scrolled->PrincipalChildList().FirstChild();
1351
0
          }
1352
0
        }
1353
0
      }
1354
0
    }
1355
0
1356
0
    if (subDocRoot && subDocRoot->GetContent() &&
1357
0
        subDocRoot->GetContent()->NodeInfo()->Equals(nsGkAtoms::svg, kNameSpaceID_SVG)) {
1358
0
      return subDocRoot; // SVG documents have an intrinsic size
1359
0
    }
1360
0
  }
1361
0
  return nullptr;
1362
0
}