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