|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set ts=2 sw=2 et tw=78: */ |
|
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 * Class for managing loading of a subframe (creation of the docshell, |
|
9 * handling of loads in it, recursion-checking). |
|
10 */ |
|
11 |
|
12 #include "base/basictypes.h" |
|
13 |
|
14 #include "prenv.h" |
|
15 |
|
16 #include "mozIApplication.h" |
|
17 #include "nsIDOMHTMLIFrameElement.h" |
|
18 #include "nsIDOMHTMLFrameElement.h" |
|
19 #include "nsIDOMMozBrowserFrame.h" |
|
20 #include "nsIDOMWindow.h" |
|
21 #include "nsIPresShell.h" |
|
22 #include "nsIContentInlines.h" |
|
23 #include "nsIContentViewer.h" |
|
24 #include "nsIDocument.h" |
|
25 #include "nsIDOMDocument.h" |
|
26 #include "nsIDOMFile.h" |
|
27 #include "nsPIDOMWindow.h" |
|
28 #include "nsIWebNavigation.h" |
|
29 #include "nsIWebProgress.h" |
|
30 #include "nsIDocShell.h" |
|
31 #include "nsIDocShellTreeOwner.h" |
|
32 #include "nsIDocShellLoadInfo.h" |
|
33 #include "nsIDOMApplicationRegistry.h" |
|
34 #include "nsIBaseWindow.h" |
|
35 #include "nsContentUtils.h" |
|
36 #include "nsCxPusher.h" |
|
37 #include "nsIXPConnect.h" |
|
38 #include "nsUnicharUtils.h" |
|
39 #include "nsIScriptGlobalObject.h" |
|
40 #include "nsIScriptSecurityManager.h" |
|
41 #include "nsIScrollable.h" |
|
42 #include "nsFrameLoader.h" |
|
43 #include "nsIDOMEventTarget.h" |
|
44 #include "nsIFrame.h" |
|
45 #include "nsIScrollableFrame.h" |
|
46 #include "nsSubDocumentFrame.h" |
|
47 #include "nsError.h" |
|
48 #include "nsISHistory.h" |
|
49 #include "nsISHistoryInternal.h" |
|
50 #include "nsIDOMHTMLDocument.h" |
|
51 #include "nsIXULWindow.h" |
|
52 #include "nsIEditor.h" |
|
53 #include "nsIMozBrowserFrame.h" |
|
54 #include "nsIPermissionManager.h" |
|
55 #include "nsISHistory.h" |
|
56 #include "nsNullPrincipal.h" |
|
57 |
|
58 #include "nsLayoutUtils.h" |
|
59 #include "nsView.h" |
|
60 |
|
61 #include "nsIURI.h" |
|
62 #include "nsIURL.h" |
|
63 #include "nsNetUtil.h" |
|
64 |
|
65 #include "nsGkAtoms.h" |
|
66 #include "nsNameSpaceManager.h" |
|
67 |
|
68 #include "nsThreadUtils.h" |
|
69 |
|
70 #include "nsIDOMChromeWindow.h" |
|
71 #include "nsInProcessTabChildGlobal.h" |
|
72 |
|
73 #include "Layers.h" |
|
74 |
|
75 #include "AppProcessChecker.h" |
|
76 #include "ContentParent.h" |
|
77 #include "TabParent.h" |
|
78 #include "mozilla/AsyncEventDispatcher.h" |
|
79 #include "mozilla/GuardObjects.h" |
|
80 #include "mozilla/Preferences.h" |
|
81 #include "mozilla/unused.h" |
|
82 #include "mozilla/dom/Element.h" |
|
83 #include "mozilla/layout/RenderFrameParent.h" |
|
84 #include "nsIAppsService.h" |
|
85 #include "GeckoProfiler.h" |
|
86 |
|
87 #include "jsapi.h" |
|
88 #include "mozilla/dom/HTMLIFrameElement.h" |
|
89 #include "nsSandboxFlags.h" |
|
90 #include "JavaScriptParent.h" |
|
91 |
|
92 #include "mozilla/dom/StructuredCloneUtils.h" |
|
93 |
|
94 #ifdef MOZ_XUL |
|
95 #include "nsXULPopupManager.h" |
|
96 #endif |
|
97 |
|
98 using namespace mozilla; |
|
99 using namespace mozilla::hal; |
|
100 using namespace mozilla::dom; |
|
101 using namespace mozilla::dom::ipc; |
|
102 using namespace mozilla::layers; |
|
103 using namespace mozilla::layout; |
|
104 typedef FrameMetrics::ViewID ViewID; |
|
105 |
|
106 class nsAsyncDocShellDestroyer : public nsRunnable |
|
107 { |
|
108 public: |
|
109 nsAsyncDocShellDestroyer(nsIDocShell* aDocShell) |
|
110 : mDocShell(aDocShell) |
|
111 { |
|
112 } |
|
113 |
|
114 NS_IMETHOD Run() |
|
115 { |
|
116 nsCOMPtr<nsIBaseWindow> base_win(do_QueryInterface(mDocShell)); |
|
117 if (base_win) { |
|
118 base_win->Destroy(); |
|
119 } |
|
120 return NS_OK; |
|
121 } |
|
122 nsRefPtr<nsIDocShell> mDocShell; |
|
123 }; |
|
124 |
|
125 NS_IMPL_ISUPPORTS(nsContentView, nsIContentView) |
|
126 |
|
127 nsresult |
|
128 nsContentView::Update(const ViewConfig& aConfig) |
|
129 { |
|
130 if (aConfig == mConfig) { |
|
131 return NS_OK; |
|
132 } |
|
133 mConfig = aConfig; |
|
134 |
|
135 // View changed. Try to locate our subdoc frame and invalidate |
|
136 // it if found. |
|
137 if (!mFrameLoader) { |
|
138 if (IsRoot()) { |
|
139 // Oops, don't have a frame right now. That's OK; the view |
|
140 // config persists and will apply to the next frame we get, if we |
|
141 // ever get one. |
|
142 return NS_OK; |
|
143 } else { |
|
144 // This view is no longer valid. |
|
145 return NS_ERROR_NOT_AVAILABLE; |
|
146 } |
|
147 } |
|
148 |
|
149 if (RenderFrameParent* rfp = mFrameLoader->GetCurrentRemoteFrame()) { |
|
150 rfp->ContentViewScaleChanged(this); |
|
151 } |
|
152 |
|
153 return NS_OK; |
|
154 } |
|
155 |
|
156 NS_IMETHODIMP |
|
157 nsContentView::ScrollTo(float aXpx, float aYpx) |
|
158 { |
|
159 ViewConfig config(mConfig); |
|
160 config.mScrollOffset = nsPoint(nsPresContext::CSSPixelsToAppUnits(aXpx), |
|
161 nsPresContext::CSSPixelsToAppUnits(aYpx)); |
|
162 return Update(config); |
|
163 } |
|
164 |
|
165 NS_IMETHODIMP |
|
166 nsContentView::ScrollBy(float aDXpx, float aDYpx) |
|
167 { |
|
168 ViewConfig config(mConfig); |
|
169 config.mScrollOffset.MoveBy(nsPresContext::CSSPixelsToAppUnits(aDXpx), |
|
170 nsPresContext::CSSPixelsToAppUnits(aDYpx)); |
|
171 return Update(config); |
|
172 } |
|
173 |
|
174 NS_IMETHODIMP |
|
175 nsContentView::SetScale(float aXScale, float aYScale) |
|
176 { |
|
177 ViewConfig config(mConfig); |
|
178 config.mXScale = aXScale; |
|
179 config.mYScale = aYScale; |
|
180 return Update(config); |
|
181 } |
|
182 |
|
183 NS_IMETHODIMP |
|
184 nsContentView::GetScrollX(float* aViewScrollX) |
|
185 { |
|
186 *aViewScrollX = nsPresContext::AppUnitsToFloatCSSPixels( |
|
187 mConfig.mScrollOffset.x); |
|
188 return NS_OK; |
|
189 } |
|
190 |
|
191 NS_IMETHODIMP |
|
192 nsContentView::GetScrollY(float* aViewScrollY) |
|
193 { |
|
194 *aViewScrollY = nsPresContext::AppUnitsToFloatCSSPixels( |
|
195 mConfig.mScrollOffset.y); |
|
196 return NS_OK; |
|
197 } |
|
198 |
|
199 NS_IMETHODIMP |
|
200 nsContentView::GetViewportWidth(float* aWidth) |
|
201 { |
|
202 *aWidth = nsPresContext::AppUnitsToFloatCSSPixels(mViewportSize.width); |
|
203 return NS_OK; |
|
204 } |
|
205 |
|
206 NS_IMETHODIMP |
|
207 nsContentView::GetViewportHeight(float* aHeight) |
|
208 { |
|
209 *aHeight = nsPresContext::AppUnitsToFloatCSSPixels(mViewportSize.height); |
|
210 return NS_OK; |
|
211 } |
|
212 |
|
213 NS_IMETHODIMP |
|
214 nsContentView::GetContentWidth(float* aWidth) |
|
215 { |
|
216 *aWidth = nsPresContext::AppUnitsToFloatCSSPixels(mContentSize.width); |
|
217 return NS_OK; |
|
218 } |
|
219 |
|
220 NS_IMETHODIMP |
|
221 nsContentView::GetContentHeight(float* aHeight) |
|
222 { |
|
223 *aHeight = nsPresContext::AppUnitsToFloatCSSPixels(mContentSize.height); |
|
224 return NS_OK; |
|
225 } |
|
226 |
|
227 NS_IMETHODIMP |
|
228 nsContentView::GetId(nsContentViewId* aId) |
|
229 { |
|
230 NS_ASSERTION(sizeof(nsContentViewId) == sizeof(ViewID), |
|
231 "ID size for XPCOM ID and internal ID type are not the same!"); |
|
232 *aId = mScrollId; |
|
233 return NS_OK; |
|
234 } |
|
235 |
|
236 // Bug 136580: Limit to the number of nested content frames that can have the |
|
237 // same URL. This is to stop content that is recursively loading |
|
238 // itself. Note that "#foo" on the end of URL doesn't affect |
|
239 // whether it's considered identical, but "?foo" or ";foo" are |
|
240 // considered and compared. |
|
241 // Bug 228829: Limit this to 1, like IE does. |
|
242 #define MAX_SAME_URL_CONTENT_FRAMES 1 |
|
243 |
|
244 // Bug 8065: Limit content frame depth to some reasonable level. This |
|
245 // does not count chrome frames when determining depth, nor does it |
|
246 // prevent chrome recursion. Number is fairly arbitrary, but meant to |
|
247 // keep number of shells to a reasonable number on accidental recursion with a |
|
248 // small (but not 1) branching factor. With large branching factors the number |
|
249 // of shells can rapidly become huge and run us out of memory. To solve that, |
|
250 // we'd need to re-institute a fixed version of bug 98158. |
|
251 #define MAX_DEPTH_CONTENT_FRAMES 10 |
|
252 |
|
253 NS_IMPL_CYCLE_COLLECTION(nsFrameLoader, mDocShell, mMessageManager, mChildMessageManager) |
|
254 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFrameLoader) |
|
255 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFrameLoader) |
|
256 |
|
257 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFrameLoader) |
|
258 NS_INTERFACE_MAP_ENTRY(nsIFrameLoader) |
|
259 NS_INTERFACE_MAP_ENTRY(nsIContentViewManager) |
|
260 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIFrameLoader) |
|
261 NS_INTERFACE_MAP_END |
|
262 |
|
263 nsFrameLoader::nsFrameLoader(Element* aOwner, bool aNetworkCreated) |
|
264 : mOwnerContent(aOwner) |
|
265 , mAppIdSentToPermissionManager(nsIScriptSecurityManager::NO_APP_ID) |
|
266 , mDetachedSubdocViews(nullptr) |
|
267 , mDepthTooGreat(false) |
|
268 , mIsTopLevelContent(false) |
|
269 , mDestroyCalled(false) |
|
270 , mNeedsAsyncDestroy(false) |
|
271 , mInSwap(false) |
|
272 , mInShow(false) |
|
273 , mHideCalled(false) |
|
274 , mNetworkCreated(aNetworkCreated) |
|
275 , mRemoteBrowserShown(false) |
|
276 , mRemoteFrame(false) |
|
277 , mClipSubdocument(true) |
|
278 , mClampScrollPosition(true) |
|
279 , mRemoteBrowserInitialized(false) |
|
280 , mObservingOwnerContent(false) |
|
281 , mVisible(true) |
|
282 , mCurrentRemoteFrame(nullptr) |
|
283 , mRemoteBrowser(nullptr) |
|
284 , mChildID(0) |
|
285 , mRenderMode(RENDER_MODE_DEFAULT) |
|
286 , mEventMode(EVENT_MODE_NORMAL_DISPATCH) |
|
287 , mPendingFrameSent(false) |
|
288 { |
|
289 ResetPermissionManagerStatus(); |
|
290 } |
|
291 |
|
292 nsFrameLoader::~nsFrameLoader() |
|
293 { |
|
294 mNeedsAsyncDestroy = true; |
|
295 if (mMessageManager) { |
|
296 mMessageManager->Disconnect(); |
|
297 } |
|
298 nsFrameLoader::Destroy(); |
|
299 } |
|
300 |
|
301 nsFrameLoader* |
|
302 nsFrameLoader::Create(Element* aOwner, bool aNetworkCreated) |
|
303 { |
|
304 NS_ENSURE_TRUE(aOwner, nullptr); |
|
305 nsIDocument* doc = aOwner->OwnerDoc(); |
|
306 NS_ENSURE_TRUE(!doc->IsResourceDoc() && |
|
307 ((!doc->IsLoadedAsData() && aOwner->GetCurrentDoc()) || |
|
308 doc->IsStaticDocument()), |
|
309 nullptr); |
|
310 |
|
311 return new nsFrameLoader(aOwner, aNetworkCreated); |
|
312 } |
|
313 |
|
314 NS_IMETHODIMP |
|
315 nsFrameLoader::LoadFrame() |
|
316 { |
|
317 NS_ENSURE_TRUE(mOwnerContent, NS_ERROR_NOT_INITIALIZED); |
|
318 |
|
319 nsAutoString src; |
|
320 |
|
321 bool isSrcdoc = mOwnerContent->IsHTML(nsGkAtoms::iframe) && |
|
322 mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::srcdoc); |
|
323 if (isSrcdoc) { |
|
324 src.AssignLiteral("about:srcdoc"); |
|
325 } |
|
326 else { |
|
327 GetURL(src); |
|
328 |
|
329 src.Trim(" \t\n\r"); |
|
330 |
|
331 if (src.IsEmpty()) { |
|
332 // If the frame is a XUL element and has the attribute 'nodefaultsrc=true' |
|
333 // then we will not use 'about:blank' as fallback but return early without |
|
334 // starting a load if no 'src' attribute is given (or it's empty). |
|
335 if (mOwnerContent->IsXUL() && |
|
336 mOwnerContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::nodefaultsrc, |
|
337 nsGkAtoms::_true, eCaseMatters)) { |
|
338 return NS_OK; |
|
339 } |
|
340 src.AssignLiteral("about:blank"); |
|
341 } |
|
342 } |
|
343 |
|
344 nsIDocument* doc = mOwnerContent->OwnerDoc(); |
|
345 if (doc->IsStaticDocument()) { |
|
346 return NS_OK; |
|
347 } |
|
348 |
|
349 nsCOMPtr<nsIURI> base_uri = mOwnerContent->GetBaseURI(); |
|
350 const nsAFlatCString &doc_charset = doc->GetDocumentCharacterSet(); |
|
351 const char *charset = doc_charset.IsEmpty() ? nullptr : doc_charset.get(); |
|
352 |
|
353 nsCOMPtr<nsIURI> uri; |
|
354 nsresult rv = NS_NewURI(getter_AddRefs(uri), src, charset, base_uri); |
|
355 |
|
356 // If the URI was malformed, try to recover by loading about:blank. |
|
357 if (rv == NS_ERROR_MALFORMED_URI) { |
|
358 rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_STRING("about:blank"), |
|
359 charset, base_uri); |
|
360 } |
|
361 |
|
362 if (NS_SUCCEEDED(rv)) { |
|
363 rv = LoadURI(uri); |
|
364 } |
|
365 |
|
366 if (NS_FAILED(rv)) { |
|
367 FireErrorEvent(); |
|
368 |
|
369 return rv; |
|
370 } |
|
371 |
|
372 return NS_OK; |
|
373 } |
|
374 |
|
375 void |
|
376 nsFrameLoader::FireErrorEvent() |
|
377 { |
|
378 if (!mOwnerContent) { |
|
379 return; |
|
380 } |
|
381 nsRefPtr<AsyncEventDispatcher > loadBlockingAsyncDispatcher = |
|
382 new LoadBlockingAsyncEventDispatcher(mOwnerContent, |
|
383 NS_LITERAL_STRING("error"), |
|
384 false, false); |
|
385 loadBlockingAsyncDispatcher->PostDOMEvent(); |
|
386 } |
|
387 |
|
388 NS_IMETHODIMP |
|
389 nsFrameLoader::LoadURI(nsIURI* aURI) |
|
390 { |
|
391 if (!aURI) |
|
392 return NS_ERROR_INVALID_POINTER; |
|
393 NS_ENSURE_STATE(!mDestroyCalled && mOwnerContent); |
|
394 |
|
395 nsCOMPtr<nsIDocument> doc = mOwnerContent->OwnerDoc(); |
|
396 |
|
397 nsresult rv = CheckURILoad(aURI); |
|
398 NS_ENSURE_SUCCESS(rv, rv); |
|
399 |
|
400 mURIToLoad = aURI; |
|
401 rv = doc->InitializeFrameLoader(this); |
|
402 if (NS_FAILED(rv)) { |
|
403 mURIToLoad = nullptr; |
|
404 } |
|
405 return rv; |
|
406 } |
|
407 |
|
408 nsresult |
|
409 nsFrameLoader::ReallyStartLoading() |
|
410 { |
|
411 nsresult rv = ReallyStartLoadingInternal(); |
|
412 if (NS_FAILED(rv)) { |
|
413 FireErrorEvent(); |
|
414 } |
|
415 |
|
416 return rv; |
|
417 } |
|
418 |
|
419 class DelayedStartLoadingRunnable : public nsRunnable |
|
420 { |
|
421 public: |
|
422 DelayedStartLoadingRunnable(nsFrameLoader* aFrameLoader) |
|
423 : mFrameLoader(aFrameLoader) |
|
424 { |
|
425 } |
|
426 |
|
427 NS_IMETHOD Run() |
|
428 { |
|
429 // Retry the request. |
|
430 mFrameLoader->ReallyStartLoading(); |
|
431 |
|
432 // We delayed nsFrameLoader::ReallyStartLoading() after the child process is |
|
433 // ready and might not be able to notify the remote browser in |
|
434 // UpdatePositionAndSize() when reflow finished. Retrigger reflow. |
|
435 nsIFrame* frame = mFrameLoader->GetPrimaryFrameOfOwningContent(); |
|
436 if (!frame) { |
|
437 return NS_OK; |
|
438 } |
|
439 frame->InvalidateFrame(); |
|
440 frame->PresContext()->PresShell()-> |
|
441 FrameNeedsReflow(frame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY); |
|
442 |
|
443 return NS_OK; |
|
444 } |
|
445 |
|
446 private: |
|
447 nsRefPtr<nsFrameLoader> mFrameLoader; |
|
448 }; |
|
449 |
|
450 nsresult |
|
451 nsFrameLoader::ReallyStartLoadingInternal() |
|
452 { |
|
453 NS_ENSURE_STATE(mURIToLoad && mOwnerContent && mOwnerContent->IsInDoc()); |
|
454 |
|
455 PROFILER_LABEL("nsFrameLoader", "ReallyStartLoading"); |
|
456 |
|
457 nsresult rv = MaybeCreateDocShell(); |
|
458 if (NS_FAILED(rv)) { |
|
459 return rv; |
|
460 } |
|
461 |
|
462 if (mRemoteFrame) { |
|
463 if (!mRemoteBrowser) { |
|
464 if (!mPendingFrameSent) { |
|
465 nsCOMPtr<nsIObserverService> os = services::GetObserverService(); |
|
466 if (os && !mRemoteBrowserInitialized) { |
|
467 os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this), |
|
468 "remote-browser-pending", nullptr); |
|
469 mPendingFrameSent = true; |
|
470 } |
|
471 } |
|
472 if (Preferences::GetBool("dom.ipc.processPrelaunch.enabled", false) && |
|
473 !ContentParent::PreallocatedProcessReady()) { |
|
474 |
|
475 ContentParent::RunAfterPreallocatedProcessReady( |
|
476 new DelayedStartLoadingRunnable(this)); |
|
477 return NS_ERROR_FAILURE; |
|
478 } |
|
479 |
|
480 TryRemoteBrowser(); |
|
481 |
|
482 if (!mRemoteBrowser) { |
|
483 NS_WARNING("Couldn't create child process for iframe."); |
|
484 return NS_ERROR_FAILURE; |
|
485 } |
|
486 } |
|
487 |
|
488 if (mRemoteBrowserShown || ShowRemoteFrame(nsIntSize(0, 0))) { |
|
489 // FIXME get error codes from child |
|
490 mRemoteBrowser->LoadURL(mURIToLoad); |
|
491 } else { |
|
492 NS_WARNING("[nsFrameLoader] ReallyStartLoadingInternal tried but couldn't show remote browser.\n"); |
|
493 } |
|
494 |
|
495 return NS_OK; |
|
496 } |
|
497 |
|
498 NS_ASSERTION(mDocShell, |
|
499 "MaybeCreateDocShell succeeded with a null mDocShell"); |
|
500 |
|
501 // Just to be safe, recheck uri. |
|
502 rv = CheckURILoad(mURIToLoad); |
|
503 NS_ENSURE_SUCCESS(rv, rv); |
|
504 |
|
505 nsCOMPtr<nsIDocShellLoadInfo> loadInfo; |
|
506 mDocShell->CreateLoadInfo(getter_AddRefs(loadInfo)); |
|
507 NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE); |
|
508 |
|
509 // If this frame is sandboxed with respect to origin we will set it up with |
|
510 // a null principal later in nsDocShell::DoURILoad. |
|
511 // We do it there to correctly sandbox content that was loaded into |
|
512 // the frame via other methods than the src attribute. |
|
513 // We'll use our principal, not that of the document loaded inside us. This |
|
514 // is very important; needed to prevent XSS attacks on documents loaded in |
|
515 // subframes! |
|
516 loadInfo->SetOwner(mOwnerContent->NodePrincipal()); |
|
517 |
|
518 nsCOMPtr<nsIURI> referrer; |
|
519 |
|
520 nsAutoString srcdoc; |
|
521 bool isSrcdoc = mOwnerContent->IsHTML(nsGkAtoms::iframe) && |
|
522 mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::srcdoc, |
|
523 srcdoc); |
|
524 |
|
525 if (isSrcdoc) { |
|
526 nsAutoString referrerStr; |
|
527 mOwnerContent->OwnerDoc()->GetReferrer(referrerStr); |
|
528 rv = NS_NewURI(getter_AddRefs(referrer), referrerStr); |
|
529 |
|
530 loadInfo->SetSrcdocData(srcdoc); |
|
531 nsCOMPtr<nsIURI> baseURI = mOwnerContent->GetBaseURI(); |
|
532 loadInfo->SetBaseURI(baseURI); |
|
533 } |
|
534 else { |
|
535 rv = mOwnerContent->NodePrincipal()->GetURI(getter_AddRefs(referrer)); |
|
536 NS_ENSURE_SUCCESS(rv, rv); |
|
537 } |
|
538 |
|
539 // Use referrer as long as it is not an nsNullPrincipalURI. |
|
540 // We could add a method such as GetReferrerURI to principals to make this |
|
541 // cleaner, but given that we need to start using Source Browsing Context for |
|
542 // referrer (see Bug 960639) this may be wasted effort at this stage. |
|
543 if (referrer) { |
|
544 bool isNullPrincipalScheme; |
|
545 rv = referrer->SchemeIs(NS_NULLPRINCIPAL_SCHEME, &isNullPrincipalScheme); |
|
546 if (NS_SUCCEEDED(rv) && !isNullPrincipalScheme) { |
|
547 loadInfo->SetReferrer(referrer); |
|
548 } |
|
549 } |
|
550 |
|
551 // Default flags: |
|
552 int32_t flags = nsIWebNavigation::LOAD_FLAGS_NONE; |
|
553 |
|
554 // Flags for browser frame: |
|
555 if (OwnerIsBrowserFrame()) { |
|
556 flags = nsIWebNavigation::LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP | |
|
557 nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_OWNER; |
|
558 } |
|
559 |
|
560 // Kick off the load... |
|
561 bool tmpState = mNeedsAsyncDestroy; |
|
562 mNeedsAsyncDestroy = true; |
|
563 nsCOMPtr<nsIURI> uriToLoad = mURIToLoad; |
|
564 rv = mDocShell->LoadURI(uriToLoad, loadInfo, flags, false); |
|
565 mNeedsAsyncDestroy = tmpState; |
|
566 mURIToLoad = nullptr; |
|
567 NS_ENSURE_SUCCESS(rv, rv); |
|
568 |
|
569 return NS_OK; |
|
570 } |
|
571 |
|
572 nsresult |
|
573 nsFrameLoader::CheckURILoad(nsIURI* aURI) |
|
574 { |
|
575 // Check for security. The fun part is trying to figure out what principals |
|
576 // to use. The way I figure it, if we're doing a LoadFrame() accidentally |
|
577 // (eg someone created a frame/iframe node, we're being parsed, XUL iframes |
|
578 // are being reframed, etc.) then we definitely want to use the node |
|
579 // principal of mOwnerContent for security checks. If, on the other hand, |
|
580 // someone's setting the src on our owner content, or created it via script, |
|
581 // or whatever, then they can clearly access it... and we should still use |
|
582 // the principal of mOwnerContent. I don't think that leads to privilege |
|
583 // escalation, and it's reasonably guaranteed to not lead to XSS issues |
|
584 // (since caller can already access mOwnerContent in this case). So just use |
|
585 // the principal of mOwnerContent no matter what. If script wants to run |
|
586 // things with its own permissions, which differ from those of mOwnerContent |
|
587 // (which means the script is privileged in some way) it should set |
|
588 // window.location instead. |
|
589 nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager(); |
|
590 |
|
591 // Get our principal |
|
592 nsIPrincipal* principal = mOwnerContent->NodePrincipal(); |
|
593 |
|
594 // Check if we are allowed to load absURL |
|
595 nsresult rv = |
|
596 secMan->CheckLoadURIWithPrincipal(principal, aURI, |
|
597 nsIScriptSecurityManager::STANDARD); |
|
598 if (NS_FAILED(rv)) { |
|
599 return rv; // We're not |
|
600 } |
|
601 |
|
602 // Bail out if this is an infinite recursion scenario |
|
603 rv = MaybeCreateDocShell(); |
|
604 if (NS_FAILED(rv)) { |
|
605 return rv; |
|
606 } |
|
607 if (mRemoteFrame) { |
|
608 return NS_OK; |
|
609 } |
|
610 return CheckForRecursiveLoad(aURI); |
|
611 } |
|
612 |
|
613 NS_IMETHODIMP |
|
614 nsFrameLoader::GetDocShell(nsIDocShell **aDocShell) |
|
615 { |
|
616 *aDocShell = nullptr; |
|
617 nsresult rv = NS_OK; |
|
618 |
|
619 // If we have an owner, make sure we have a docshell and return |
|
620 // that. If not, we're most likely in the middle of being torn down, |
|
621 // then we just return null. |
|
622 if (mOwnerContent) { |
|
623 nsresult rv = MaybeCreateDocShell(); |
|
624 if (NS_FAILED(rv)) |
|
625 return rv; |
|
626 if (mRemoteFrame) { |
|
627 NS_WARNING("No docshells for remote frames!"); |
|
628 return rv; |
|
629 } |
|
630 NS_ASSERTION(mDocShell, |
|
631 "MaybeCreateDocShell succeeded, but null mDocShell"); |
|
632 } |
|
633 |
|
634 *aDocShell = mDocShell; |
|
635 NS_IF_ADDREF(*aDocShell); |
|
636 |
|
637 return rv; |
|
638 } |
|
639 |
|
640 void |
|
641 nsFrameLoader::Finalize() |
|
642 { |
|
643 nsCOMPtr<nsIBaseWindow> base_win(do_QueryInterface(mDocShell)); |
|
644 if (base_win) { |
|
645 base_win->Destroy(); |
|
646 } |
|
647 mDocShell = nullptr; |
|
648 } |
|
649 |
|
650 static void |
|
651 FirePageHideEvent(nsIDocShellTreeItem* aItem, |
|
652 EventTarget* aChromeEventHandler) |
|
653 { |
|
654 nsCOMPtr<nsIDocument> internalDoc = do_GetInterface(aItem); |
|
655 NS_ASSERTION(internalDoc, "What happened here?"); |
|
656 internalDoc->OnPageHide(true, aChromeEventHandler); |
|
657 |
|
658 int32_t childCount = 0; |
|
659 aItem->GetChildCount(&childCount); |
|
660 nsAutoTArray<nsCOMPtr<nsIDocShellTreeItem>, 8> kids; |
|
661 kids.AppendElements(childCount); |
|
662 for (int32_t i = 0; i < childCount; ++i) { |
|
663 aItem->GetChildAt(i, getter_AddRefs(kids[i])); |
|
664 } |
|
665 |
|
666 for (uint32_t i = 0; i < kids.Length(); ++i) { |
|
667 if (kids[i]) { |
|
668 FirePageHideEvent(kids[i], aChromeEventHandler); |
|
669 } |
|
670 } |
|
671 } |
|
672 |
|
673 // The pageshow event is fired for a given document only if IsShowing() returns |
|
674 // the same thing as aFireIfShowing. This gives us a way to fire pageshow only |
|
675 // on documents that are still loading or only on documents that are already |
|
676 // loaded. |
|
677 static void |
|
678 FirePageShowEvent(nsIDocShellTreeItem* aItem, |
|
679 EventTarget* aChromeEventHandler, |
|
680 bool aFireIfShowing) |
|
681 { |
|
682 int32_t childCount = 0; |
|
683 aItem->GetChildCount(&childCount); |
|
684 nsAutoTArray<nsCOMPtr<nsIDocShellTreeItem>, 8> kids; |
|
685 kids.AppendElements(childCount); |
|
686 for (int32_t i = 0; i < childCount; ++i) { |
|
687 aItem->GetChildAt(i, getter_AddRefs(kids[i])); |
|
688 } |
|
689 |
|
690 for (uint32_t i = 0; i < kids.Length(); ++i) { |
|
691 if (kids[i]) { |
|
692 FirePageShowEvent(kids[i], aChromeEventHandler, aFireIfShowing); |
|
693 } |
|
694 } |
|
695 |
|
696 nsCOMPtr<nsIDocument> internalDoc = do_GetInterface(aItem); |
|
697 NS_ASSERTION(internalDoc, "What happened here?"); |
|
698 if (internalDoc->IsShowing() == aFireIfShowing) { |
|
699 internalDoc->OnPageShow(true, aChromeEventHandler); |
|
700 } |
|
701 } |
|
702 |
|
703 static void |
|
704 SetTreeOwnerAndChromeEventHandlerOnDocshellTree(nsIDocShellTreeItem* aItem, |
|
705 nsIDocShellTreeOwner* aOwner, |
|
706 EventTarget* aHandler) |
|
707 { |
|
708 NS_PRECONDITION(aItem, "Must have item"); |
|
709 |
|
710 aItem->SetTreeOwner(aOwner); |
|
711 |
|
712 int32_t childCount = 0; |
|
713 aItem->GetChildCount(&childCount); |
|
714 for (int32_t i = 0; i < childCount; ++i) { |
|
715 nsCOMPtr<nsIDocShellTreeItem> item; |
|
716 aItem->GetChildAt(i, getter_AddRefs(item)); |
|
717 if (aHandler) { |
|
718 nsCOMPtr<nsIDocShell> shell(do_QueryInterface(item)); |
|
719 shell->SetChromeEventHandler(aHandler); |
|
720 } |
|
721 SetTreeOwnerAndChromeEventHandlerOnDocshellTree(item, aOwner, aHandler); |
|
722 } |
|
723 } |
|
724 |
|
725 /** |
|
726 * Set the type of the treeitem and hook it up to the treeowner. |
|
727 * @param aItem the treeitem we're working with |
|
728 * @param aTreeOwner the relevant treeowner; might be null |
|
729 * @param aParentType the nsIDocShellTreeItem::GetType of our parent docshell |
|
730 * @param aParentNode if non-null, the docshell we should be added as a child to |
|
731 * |
|
732 * @return whether aItem is top-level content |
|
733 */ |
|
734 bool |
|
735 nsFrameLoader::AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem, |
|
736 nsIDocShellTreeOwner* aOwner, |
|
737 int32_t aParentType, |
|
738 nsIDocShell* aParentNode) |
|
739 { |
|
740 NS_PRECONDITION(aItem, "Must have docshell treeitem"); |
|
741 NS_PRECONDITION(mOwnerContent, "Must have owning content"); |
|
742 |
|
743 nsAutoString value; |
|
744 bool isContent = false; |
|
745 mOwnerContent->GetAttr(kNameSpaceID_None, TypeAttrName(), value); |
|
746 |
|
747 // we accept "content" and "content-xxx" values. |
|
748 // at time of writing, we expect "xxx" to be "primary" or "targetable", but |
|
749 // someday it might be an integer expressing priority or something else. |
|
750 |
|
751 isContent = value.LowerCaseEqualsLiteral("content") || |
|
752 StringBeginsWith(value, NS_LITERAL_STRING("content-"), |
|
753 nsCaseInsensitiveStringComparator()); |
|
754 |
|
755 // Force mozbrowser frames to always be typeContent, even if the |
|
756 // mozbrowser interfaces are disabled. |
|
757 nsCOMPtr<nsIDOMMozBrowserFrame> mozbrowser = |
|
758 do_QueryInterface(mOwnerContent); |
|
759 if (mozbrowser) { |
|
760 bool isMozbrowser = false; |
|
761 mozbrowser->GetMozbrowser(&isMozbrowser); |
|
762 isContent |= isMozbrowser; |
|
763 } |
|
764 |
|
765 if (isContent) { |
|
766 // The web shell's type is content. |
|
767 |
|
768 aItem->SetItemType(nsIDocShellTreeItem::typeContent); |
|
769 } else { |
|
770 // Inherit our type from our parent docshell. If it is |
|
771 // chrome, we'll be chrome. If it is content, we'll be |
|
772 // content. |
|
773 |
|
774 aItem->SetItemType(aParentType); |
|
775 } |
|
776 |
|
777 // Now that we have our type set, add ourselves to the parent, as needed. |
|
778 if (aParentNode) { |
|
779 aParentNode->AddChild(aItem); |
|
780 } |
|
781 |
|
782 bool retval = false; |
|
783 if (aParentType == nsIDocShellTreeItem::typeChrome && isContent) { |
|
784 retval = true; |
|
785 |
|
786 bool is_primary = value.LowerCaseEqualsLiteral("content-primary"); |
|
787 |
|
788 if (aOwner) { |
|
789 bool is_targetable = is_primary || |
|
790 value.LowerCaseEqualsLiteral("content-targetable"); |
|
791 mOwnerContent->AddMutationObserver(this); |
|
792 mObservingOwnerContent = true; |
|
793 aOwner->ContentShellAdded(aItem, is_primary, is_targetable, value); |
|
794 } |
|
795 } |
|
796 |
|
797 return retval; |
|
798 } |
|
799 |
|
800 static bool |
|
801 AllDescendantsOfType(nsIDocShellTreeItem* aParentItem, int32_t aType) |
|
802 { |
|
803 int32_t childCount = 0; |
|
804 aParentItem->GetChildCount(&childCount); |
|
805 |
|
806 for (int32_t i = 0; i < childCount; ++i) { |
|
807 nsCOMPtr<nsIDocShellTreeItem> kid; |
|
808 aParentItem->GetChildAt(i, getter_AddRefs(kid)); |
|
809 |
|
810 if (kid->ItemType() != aType || !AllDescendantsOfType(kid, aType)) { |
|
811 return false; |
|
812 } |
|
813 } |
|
814 |
|
815 return true; |
|
816 } |
|
817 |
|
818 /** |
|
819 * A class that automatically sets mInShow to false when it goes |
|
820 * out of scope. |
|
821 */ |
|
822 class MOZ_STACK_CLASS AutoResetInShow { |
|
823 private: |
|
824 nsFrameLoader* mFrameLoader; |
|
825 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER |
|
826 public: |
|
827 AutoResetInShow(nsFrameLoader* aFrameLoader MOZ_GUARD_OBJECT_NOTIFIER_PARAM) |
|
828 : mFrameLoader(aFrameLoader) |
|
829 { |
|
830 MOZ_GUARD_OBJECT_NOTIFIER_INIT; |
|
831 } |
|
832 ~AutoResetInShow() { mFrameLoader->mInShow = false; } |
|
833 }; |
|
834 |
|
835 |
|
836 bool |
|
837 nsFrameLoader::Show(int32_t marginWidth, int32_t marginHeight, |
|
838 int32_t scrollbarPrefX, int32_t scrollbarPrefY, |
|
839 nsSubDocumentFrame* frame) |
|
840 { |
|
841 if (mInShow) { |
|
842 return false; |
|
843 } |
|
844 // Reset mInShow if we exit early. |
|
845 AutoResetInShow resetInShow(this); |
|
846 mInShow = true; |
|
847 |
|
848 nsresult rv = MaybeCreateDocShell(); |
|
849 if (NS_FAILED(rv)) { |
|
850 return false; |
|
851 } |
|
852 |
|
853 if (!mRemoteFrame) { |
|
854 if (!mDocShell) |
|
855 return false; |
|
856 |
|
857 mDocShell->SetMarginWidth(marginWidth); |
|
858 mDocShell->SetMarginHeight(marginHeight); |
|
859 |
|
860 nsCOMPtr<nsIScrollable> sc = do_QueryInterface(mDocShell); |
|
861 if (sc) { |
|
862 sc->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_X, |
|
863 scrollbarPrefX); |
|
864 sc->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_Y, |
|
865 scrollbarPrefY); |
|
866 } |
|
867 |
|
868 nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell(); |
|
869 if (presShell) { |
|
870 // Ensure root scroll frame is reflowed in case scroll preferences or |
|
871 // margins have changed |
|
872 nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame(); |
|
873 if (rootScrollFrame) { |
|
874 presShell->FrameNeedsReflow(rootScrollFrame, nsIPresShell::eResize, |
|
875 NS_FRAME_IS_DIRTY); |
|
876 } |
|
877 return true; |
|
878 } |
|
879 } |
|
880 |
|
881 nsIntSize size = frame->GetSubdocumentSize(); |
|
882 if (mRemoteFrame) { |
|
883 return ShowRemoteFrame(size, frame); |
|
884 } |
|
885 |
|
886 nsView* view = frame->EnsureInnerView(); |
|
887 if (!view) |
|
888 return false; |
|
889 |
|
890 nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(mDocShell); |
|
891 NS_ASSERTION(baseWindow, "Found a nsIDocShell that isn't a nsIBaseWindow."); |
|
892 baseWindow->InitWindow(nullptr, view->GetWidget(), 0, 0, |
|
893 size.width, size.height); |
|
894 // This is kinda whacky, this "Create()" call doesn't really |
|
895 // create anything, one starts to wonder why this was named |
|
896 // "Create"... |
|
897 baseWindow->Create(); |
|
898 baseWindow->SetVisibility(true); |
|
899 NS_ENSURE_TRUE(mDocShell, false); |
|
900 |
|
901 // Trigger editor re-initialization if midas is turned on in the |
|
902 // sub-document. This shouldn't be necessary, but given the way our |
|
903 // editor works, it is. See |
|
904 // https://bugzilla.mozilla.org/show_bug.cgi?id=284245 |
|
905 nsCOMPtr<nsIPresShell> presShell = mDocShell->GetPresShell(); |
|
906 if (presShell) { |
|
907 nsCOMPtr<nsIDOMHTMLDocument> doc = |
|
908 do_QueryInterface(presShell->GetDocument()); |
|
909 |
|
910 if (doc) { |
|
911 nsAutoString designMode; |
|
912 doc->GetDesignMode(designMode); |
|
913 |
|
914 if (designMode.EqualsLiteral("on")) { |
|
915 // Hold on to the editor object to let the document reattach to the |
|
916 // same editor object, instead of creating a new one. |
|
917 nsCOMPtr<nsIEditor> editor; |
|
918 nsresult rv = mDocShell->GetEditor(getter_AddRefs(editor)); |
|
919 NS_ENSURE_SUCCESS(rv, false); |
|
920 |
|
921 doc->SetDesignMode(NS_LITERAL_STRING("off")); |
|
922 doc->SetDesignMode(NS_LITERAL_STRING("on")); |
|
923 } else { |
|
924 // Re-initialize the presentation for contenteditable documents |
|
925 bool editable = false, |
|
926 hasEditingSession = false; |
|
927 mDocShell->GetEditable(&editable); |
|
928 mDocShell->GetHasEditingSession(&hasEditingSession); |
|
929 nsCOMPtr<nsIEditor> editor; |
|
930 mDocShell->GetEditor(getter_AddRefs(editor)); |
|
931 if (editable && hasEditingSession && editor) { |
|
932 editor->PostCreate(); |
|
933 } |
|
934 } |
|
935 } |
|
936 } |
|
937 |
|
938 mInShow = false; |
|
939 if (mHideCalled) { |
|
940 mHideCalled = false; |
|
941 Hide(); |
|
942 return false; |
|
943 } |
|
944 return true; |
|
945 } |
|
946 |
|
947 void |
|
948 nsFrameLoader::MarginsChanged(uint32_t aMarginWidth, |
|
949 uint32_t aMarginHeight) |
|
950 { |
|
951 // We assume that the margins are always zero for remote frames. |
|
952 if (mRemoteFrame) |
|
953 return; |
|
954 |
|
955 // If there's no docshell, we're probably not up and running yet. |
|
956 // nsFrameLoader::Show() will take care of setting the right |
|
957 // margins. |
|
958 if (!mDocShell) |
|
959 return; |
|
960 |
|
961 // Set the margins |
|
962 mDocShell->SetMarginWidth(aMarginWidth); |
|
963 mDocShell->SetMarginHeight(aMarginHeight); |
|
964 |
|
965 // Trigger a restyle if there's a prescontext |
|
966 nsRefPtr<nsPresContext> presContext; |
|
967 mDocShell->GetPresContext(getter_AddRefs(presContext)); |
|
968 if (presContext) |
|
969 presContext->RebuildAllStyleData(nsChangeHint(0)); |
|
970 } |
|
971 |
|
972 bool |
|
973 nsFrameLoader::ShowRemoteFrame(const nsIntSize& size, |
|
974 nsSubDocumentFrame *aFrame) |
|
975 { |
|
976 NS_ASSERTION(mRemoteFrame, "ShowRemote only makes sense on remote frames."); |
|
977 |
|
978 if (!mRemoteBrowser) { |
|
979 TryRemoteBrowser(); |
|
980 |
|
981 if (!mRemoteBrowser) { |
|
982 NS_ERROR("Couldn't create child process."); |
|
983 return false; |
|
984 } |
|
985 } |
|
986 |
|
987 // FIXME/bug 589337: Show()/Hide() is pretty expensive for |
|
988 // cross-process layers; need to figure out what behavior we really |
|
989 // want here. For now, hack. |
|
990 if (!mRemoteBrowserShown) { |
|
991 if (!mOwnerContent || |
|
992 !mOwnerContent->GetCurrentDoc()) { |
|
993 return false; |
|
994 } |
|
995 |
|
996 nsRefPtr<layers::LayerManager> layerManager = |
|
997 nsContentUtils::LayerManagerForDocument(mOwnerContent->GetCurrentDoc()); |
|
998 if (!layerManager) { |
|
999 // This is just not going to work. |
|
1000 return false; |
|
1001 } |
|
1002 |
|
1003 mRemoteBrowser->Show(size); |
|
1004 mRemoteBrowserShown = true; |
|
1005 |
|
1006 EnsureMessageManager(); |
|
1007 |
|
1008 nsCOMPtr<nsIObserverService> os = services::GetObserverService(); |
|
1009 if (os && !mRemoteBrowserInitialized) { |
|
1010 if (!mPendingFrameSent) { |
|
1011 os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this), |
|
1012 "remote-browser-pending", nullptr); |
|
1013 mPendingFrameSent = true; |
|
1014 } |
|
1015 os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this), |
|
1016 "remote-browser-shown", nullptr); |
|
1017 mRemoteBrowserInitialized = true; |
|
1018 } |
|
1019 } else { |
|
1020 nsRect dimensions; |
|
1021 NS_ENSURE_SUCCESS(GetWindowDimensions(dimensions), false); |
|
1022 |
|
1023 // Don't show remote iframe if we are waiting for the completion of reflow. |
|
1024 if (!aFrame || !(aFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) { |
|
1025 mRemoteBrowser->UpdateDimensions(dimensions, size); |
|
1026 } |
|
1027 } |
|
1028 |
|
1029 return true; |
|
1030 } |
|
1031 |
|
1032 void |
|
1033 nsFrameLoader::Hide() |
|
1034 { |
|
1035 if (mHideCalled) { |
|
1036 return; |
|
1037 } |
|
1038 if (mInShow) { |
|
1039 mHideCalled = true; |
|
1040 return; |
|
1041 } |
|
1042 |
|
1043 if (!mDocShell) |
|
1044 return; |
|
1045 |
|
1046 nsCOMPtr<nsIContentViewer> contentViewer; |
|
1047 mDocShell->GetContentViewer(getter_AddRefs(contentViewer)); |
|
1048 if (contentViewer) |
|
1049 contentViewer->SetSticky(false); |
|
1050 |
|
1051 nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(mDocShell); |
|
1052 NS_ASSERTION(baseWin, |
|
1053 "Found an nsIDocShell which doesn't implement nsIBaseWindow."); |
|
1054 baseWin->SetVisibility(false); |
|
1055 baseWin->SetParentWidget(nullptr); |
|
1056 } |
|
1057 |
|
1058 nsresult |
|
1059 nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther, |
|
1060 nsRefPtr<nsFrameLoader>& aFirstToSwap, |
|
1061 nsRefPtr<nsFrameLoader>& aSecondToSwap) |
|
1062 { |
|
1063 NS_PRECONDITION((aFirstToSwap == this && aSecondToSwap == aOther) || |
|
1064 (aFirstToSwap == aOther && aSecondToSwap == this), |
|
1065 "Swapping some sort of random loaders?"); |
|
1066 NS_ENSURE_STATE(!mInShow && !aOther->mInShow); |
|
1067 |
|
1068 Element* ourContent = mOwnerContent; |
|
1069 Element* otherContent = aOther->mOwnerContent; |
|
1070 |
|
1071 if (!ourContent || !otherContent) { |
|
1072 // Can't handle this |
|
1073 return NS_ERROR_NOT_IMPLEMENTED; |
|
1074 } |
|
1075 |
|
1076 // Make sure there are no same-origin issues |
|
1077 bool equal; |
|
1078 nsresult rv = |
|
1079 ourContent->NodePrincipal()->Equals(otherContent->NodePrincipal(), &equal); |
|
1080 if (NS_FAILED(rv) || !equal) { |
|
1081 // Security problems loom. Just bail on it all |
|
1082 return NS_ERROR_DOM_SECURITY_ERR; |
|
1083 } |
|
1084 |
|
1085 nsCOMPtr<nsIDocShell> ourDocshell = GetExistingDocShell(); |
|
1086 nsCOMPtr<nsIDocShell> otherDocshell = aOther->GetExistingDocShell(); |
|
1087 if (!ourDocshell || !otherDocshell) { |
|
1088 // How odd |
|
1089 return NS_ERROR_NOT_IMPLEMENTED; |
|
1090 } |
|
1091 |
|
1092 // To avoid having to mess with session history, avoid swapping |
|
1093 // frameloaders that don't correspond to root same-type docshells, |
|
1094 // unless both roots have session history disabled. |
|
1095 nsCOMPtr<nsIDocShellTreeItem> ourRootTreeItem, otherRootTreeItem; |
|
1096 ourDocshell->GetSameTypeRootTreeItem(getter_AddRefs(ourRootTreeItem)); |
|
1097 otherDocshell->GetSameTypeRootTreeItem(getter_AddRefs(otherRootTreeItem)); |
|
1098 nsCOMPtr<nsIWebNavigation> ourRootWebnav = |
|
1099 do_QueryInterface(ourRootTreeItem); |
|
1100 nsCOMPtr<nsIWebNavigation> otherRootWebnav = |
|
1101 do_QueryInterface(otherRootTreeItem); |
|
1102 |
|
1103 if (!ourRootWebnav || !otherRootWebnav) { |
|
1104 return NS_ERROR_NOT_IMPLEMENTED; |
|
1105 } |
|
1106 |
|
1107 nsCOMPtr<nsISHistory> ourHistory; |
|
1108 nsCOMPtr<nsISHistory> otherHistory; |
|
1109 ourRootWebnav->GetSessionHistory(getter_AddRefs(ourHistory)); |
|
1110 otherRootWebnav->GetSessionHistory(getter_AddRefs(otherHistory)); |
|
1111 |
|
1112 if ((ourRootTreeItem != ourDocshell || otherRootTreeItem != otherDocshell) && |
|
1113 (ourHistory || otherHistory)) { |
|
1114 return NS_ERROR_NOT_IMPLEMENTED; |
|
1115 } |
|
1116 |
|
1117 // Also make sure that the two docshells are the same type. Otherwise |
|
1118 // swapping is certainly not safe. If this needs to be changed then |
|
1119 // the code below needs to be audited as it assumes identical types. |
|
1120 int32_t ourType = ourDocshell->ItemType(); |
|
1121 int32_t otherType = otherDocshell->ItemType(); |
|
1122 if (ourType != otherType) { |
|
1123 return NS_ERROR_NOT_IMPLEMENTED; |
|
1124 } |
|
1125 |
|
1126 // One more twist here. Setting up the right treeowners in a heterogeneous |
|
1127 // tree is a bit of a pain. So make sure that if ourType is not |
|
1128 // nsIDocShellTreeItem::typeContent then all of our descendants are the same |
|
1129 // type as us. |
|
1130 if (ourType != nsIDocShellTreeItem::typeContent && |
|
1131 (!AllDescendantsOfType(ourDocshell, ourType) || |
|
1132 !AllDescendantsOfType(otherDocshell, otherType))) { |
|
1133 return NS_ERROR_NOT_IMPLEMENTED; |
|
1134 } |
|
1135 |
|
1136 // Save off the tree owners, frame elements, chrome event handlers, and |
|
1137 // docshell and document parents before doing anything else. |
|
1138 nsCOMPtr<nsIDocShellTreeOwner> ourOwner, otherOwner; |
|
1139 ourDocshell->GetTreeOwner(getter_AddRefs(ourOwner)); |
|
1140 otherDocshell->GetTreeOwner(getter_AddRefs(otherOwner)); |
|
1141 // Note: it's OK to have null treeowners. |
|
1142 |
|
1143 nsCOMPtr<nsIDocShellTreeItem> ourParentItem, otherParentItem; |
|
1144 ourDocshell->GetParent(getter_AddRefs(ourParentItem)); |
|
1145 otherDocshell->GetParent(getter_AddRefs(otherParentItem)); |
|
1146 if (!ourParentItem || !otherParentItem) { |
|
1147 return NS_ERROR_NOT_IMPLEMENTED; |
|
1148 } |
|
1149 |
|
1150 // Make sure our parents are the same type too |
|
1151 int32_t ourParentType = ourParentItem->ItemType(); |
|
1152 int32_t otherParentType = otherParentItem->ItemType(); |
|
1153 if (ourParentType != otherParentType) { |
|
1154 return NS_ERROR_NOT_IMPLEMENTED; |
|
1155 } |
|
1156 |
|
1157 nsCOMPtr<nsPIDOMWindow> ourWindow = do_GetInterface(ourDocshell); |
|
1158 nsCOMPtr<nsPIDOMWindow> otherWindow = do_GetInterface(otherDocshell); |
|
1159 |
|
1160 nsCOMPtr<Element> ourFrameElement = |
|
1161 ourWindow->GetFrameElementInternal(); |
|
1162 nsCOMPtr<Element> otherFrameElement = |
|
1163 otherWindow->GetFrameElementInternal(); |
|
1164 |
|
1165 nsCOMPtr<EventTarget> ourChromeEventHandler = |
|
1166 do_QueryInterface(ourWindow->GetChromeEventHandler()); |
|
1167 nsCOMPtr<EventTarget> otherChromeEventHandler = |
|
1168 do_QueryInterface(otherWindow->GetChromeEventHandler()); |
|
1169 |
|
1170 NS_ASSERTION(SameCOMIdentity(ourFrameElement, ourContent) && |
|
1171 SameCOMIdentity(otherFrameElement, otherContent) && |
|
1172 SameCOMIdentity(ourChromeEventHandler, ourContent) && |
|
1173 SameCOMIdentity(otherChromeEventHandler, otherContent), |
|
1174 "How did that happen, exactly?"); |
|
1175 |
|
1176 nsCOMPtr<nsIDocument> ourChildDocument = ourWindow->GetExtantDoc(); |
|
1177 nsCOMPtr<nsIDocument> otherChildDocument = otherWindow ->GetExtantDoc(); |
|
1178 if (!ourChildDocument || !otherChildDocument) { |
|
1179 // This shouldn't be happening |
|
1180 return NS_ERROR_NOT_IMPLEMENTED; |
|
1181 } |
|
1182 |
|
1183 nsCOMPtr<nsIDocument> ourParentDocument = |
|
1184 ourChildDocument->GetParentDocument(); |
|
1185 nsCOMPtr<nsIDocument> otherParentDocument = |
|
1186 otherChildDocument->GetParentDocument(); |
|
1187 |
|
1188 // Make sure to swap docshells between the two frames. |
|
1189 nsIDocument* ourDoc = ourContent->GetCurrentDoc(); |
|
1190 nsIDocument* otherDoc = otherContent->GetCurrentDoc(); |
|
1191 if (!ourDoc || !otherDoc) { |
|
1192 // Again, how odd, given that we had docshells |
|
1193 return NS_ERROR_NOT_IMPLEMENTED; |
|
1194 } |
|
1195 |
|
1196 NS_ASSERTION(ourDoc == ourParentDocument, "Unexpected parent document"); |
|
1197 NS_ASSERTION(otherDoc == otherParentDocument, "Unexpected parent document"); |
|
1198 |
|
1199 nsIPresShell* ourShell = ourDoc->GetShell(); |
|
1200 nsIPresShell* otherShell = otherDoc->GetShell(); |
|
1201 if (!ourShell || !otherShell) { |
|
1202 return NS_ERROR_NOT_IMPLEMENTED; |
|
1203 } |
|
1204 |
|
1205 if (ourDocshell->GetIsBrowserElement() != |
|
1206 otherDocshell->GetIsBrowserElement() || |
|
1207 ourDocshell->GetIsApp() != otherDocshell->GetIsApp()) { |
|
1208 return NS_ERROR_NOT_IMPLEMENTED; |
|
1209 } |
|
1210 |
|
1211 if (mInSwap || aOther->mInSwap) { |
|
1212 return NS_ERROR_NOT_IMPLEMENTED; |
|
1213 } |
|
1214 mInSwap = aOther->mInSwap = true; |
|
1215 |
|
1216 // Fire pageshow events on still-loading pages, and then fire pagehide |
|
1217 // events. Note that we do NOT fire these in the normal way, but just fire |
|
1218 // them on the chrome event handlers. |
|
1219 FirePageShowEvent(ourDocshell, ourChromeEventHandler, false); |
|
1220 FirePageShowEvent(otherDocshell, otherChromeEventHandler, false); |
|
1221 FirePageHideEvent(ourDocshell, ourChromeEventHandler); |
|
1222 FirePageHideEvent(otherDocshell, otherChromeEventHandler); |
|
1223 |
|
1224 nsIFrame* ourFrame = ourContent->GetPrimaryFrame(); |
|
1225 nsIFrame* otherFrame = otherContent->GetPrimaryFrame(); |
|
1226 if (!ourFrame || !otherFrame) { |
|
1227 mInSwap = aOther->mInSwap = false; |
|
1228 FirePageShowEvent(ourDocshell, ourChromeEventHandler, true); |
|
1229 FirePageShowEvent(otherDocshell, otherChromeEventHandler, true); |
|
1230 return NS_ERROR_NOT_IMPLEMENTED; |
|
1231 } |
|
1232 |
|
1233 nsSubDocumentFrame* ourFrameFrame = do_QueryFrame(ourFrame); |
|
1234 if (!ourFrameFrame) { |
|
1235 mInSwap = aOther->mInSwap = false; |
|
1236 FirePageShowEvent(ourDocshell, ourChromeEventHandler, true); |
|
1237 FirePageShowEvent(otherDocshell, otherChromeEventHandler, true); |
|
1238 return NS_ERROR_NOT_IMPLEMENTED; |
|
1239 } |
|
1240 |
|
1241 // OK. First begin to swap the docshells in the two nsIFrames |
|
1242 rv = ourFrameFrame->BeginSwapDocShells(otherFrame); |
|
1243 if (NS_FAILED(rv)) { |
|
1244 mInSwap = aOther->mInSwap = false; |
|
1245 FirePageShowEvent(ourDocshell, ourChromeEventHandler, true); |
|
1246 FirePageShowEvent(otherDocshell, otherChromeEventHandler, true); |
|
1247 return rv; |
|
1248 } |
|
1249 |
|
1250 // Now move the docshells to the right docshell trees. Note that this |
|
1251 // resets their treeowners to null. |
|
1252 ourParentItem->RemoveChild(ourDocshell); |
|
1253 otherParentItem->RemoveChild(otherDocshell); |
|
1254 if (ourType == nsIDocShellTreeItem::typeContent) { |
|
1255 ourOwner->ContentShellRemoved(ourDocshell); |
|
1256 otherOwner->ContentShellRemoved(otherDocshell); |
|
1257 } |
|
1258 |
|
1259 ourParentItem->AddChild(otherDocshell); |
|
1260 otherParentItem->AddChild(ourDocshell); |
|
1261 |
|
1262 // Restore the correct chrome event handlers. |
|
1263 ourDocshell->SetChromeEventHandler(otherChromeEventHandler); |
|
1264 otherDocshell->SetChromeEventHandler(ourChromeEventHandler); |
|
1265 // Restore the correct treeowners |
|
1266 // (and also chrome event handlers for content frames only). |
|
1267 SetTreeOwnerAndChromeEventHandlerOnDocshellTree(ourDocshell, otherOwner, |
|
1268 ourType == nsIDocShellTreeItem::typeContent ? otherChromeEventHandler : nullptr); |
|
1269 SetTreeOwnerAndChromeEventHandlerOnDocshellTree(otherDocshell, ourOwner, |
|
1270 ourType == nsIDocShellTreeItem::typeContent ? ourChromeEventHandler : nullptr); |
|
1271 |
|
1272 // Switch the owner content before we start calling AddTreeItemToTreeOwner. |
|
1273 // Note that we rely on this to deal with setting mObservingOwnerContent to |
|
1274 // false and calling RemoveMutationObserver as needed. |
|
1275 SetOwnerContent(otherContent); |
|
1276 aOther->SetOwnerContent(ourContent); |
|
1277 |
|
1278 AddTreeItemToTreeOwner(ourDocshell, otherOwner, otherParentType, nullptr); |
|
1279 aOther->AddTreeItemToTreeOwner(otherDocshell, ourOwner, ourParentType, |
|
1280 nullptr); |
|
1281 |
|
1282 // SetSubDocumentFor nulls out parent documents on the old child doc if a |
|
1283 // new non-null document is passed in, so just go ahead and remove both |
|
1284 // kids before reinserting in the parent subdoc maps, to avoid |
|
1285 // complications. |
|
1286 ourParentDocument->SetSubDocumentFor(ourContent, nullptr); |
|
1287 otherParentDocument->SetSubDocumentFor(otherContent, nullptr); |
|
1288 ourParentDocument->SetSubDocumentFor(ourContent, otherChildDocument); |
|
1289 otherParentDocument->SetSubDocumentFor(otherContent, ourChildDocument); |
|
1290 |
|
1291 ourWindow->SetFrameElementInternal(otherFrameElement); |
|
1292 otherWindow->SetFrameElementInternal(ourFrameElement); |
|
1293 |
|
1294 nsRefPtr<nsFrameMessageManager> ourMessageManager = mMessageManager; |
|
1295 nsRefPtr<nsFrameMessageManager> otherMessageManager = aOther->mMessageManager; |
|
1296 // Swap pointers in child message managers. |
|
1297 if (mChildMessageManager) { |
|
1298 nsInProcessTabChildGlobal* tabChild = |
|
1299 static_cast<nsInProcessTabChildGlobal*>(mChildMessageManager.get()); |
|
1300 tabChild->SetOwner(otherContent); |
|
1301 tabChild->SetChromeMessageManager(otherMessageManager); |
|
1302 } |
|
1303 if (aOther->mChildMessageManager) { |
|
1304 nsInProcessTabChildGlobal* otherTabChild = |
|
1305 static_cast<nsInProcessTabChildGlobal*>(aOther->mChildMessageManager.get()); |
|
1306 otherTabChild->SetOwner(ourContent); |
|
1307 otherTabChild->SetChromeMessageManager(ourMessageManager); |
|
1308 } |
|
1309 // Swap and setup things in parent message managers. |
|
1310 if (mMessageManager) { |
|
1311 mMessageManager->SetCallback(aOther); |
|
1312 } |
|
1313 if (aOther->mMessageManager) { |
|
1314 aOther->mMessageManager->SetCallback(this); |
|
1315 } |
|
1316 mMessageManager.swap(aOther->mMessageManager); |
|
1317 |
|
1318 aFirstToSwap.swap(aSecondToSwap); |
|
1319 |
|
1320 // Drop any cached content viewers in the two session histories. |
|
1321 nsCOMPtr<nsISHistoryInternal> ourInternalHistory = |
|
1322 do_QueryInterface(ourHistory); |
|
1323 nsCOMPtr<nsISHistoryInternal> otherInternalHistory = |
|
1324 do_QueryInterface(otherHistory); |
|
1325 if (ourInternalHistory) { |
|
1326 ourInternalHistory->EvictAllContentViewers(); |
|
1327 } |
|
1328 if (otherInternalHistory) { |
|
1329 otherInternalHistory->EvictAllContentViewers(); |
|
1330 } |
|
1331 |
|
1332 NS_ASSERTION(ourFrame == ourContent->GetPrimaryFrame() && |
|
1333 otherFrame == otherContent->GetPrimaryFrame(), |
|
1334 "changed primary frame"); |
|
1335 |
|
1336 ourFrameFrame->EndSwapDocShells(otherFrame); |
|
1337 |
|
1338 // If the content being swapped came from windows on two screens with |
|
1339 // incompatible backing resolution (e.g. dragging a tab between windows on |
|
1340 // hi-dpi and low-dpi screens), it will have style data that is based on |
|
1341 // the wrong appUnitsPerDevPixel value. So we tell the PresShells that their |
|
1342 // backing scale factor may have changed. (Bug 822266) |
|
1343 ourShell->BackingScaleFactorChanged(); |
|
1344 otherShell->BackingScaleFactorChanged(); |
|
1345 |
|
1346 ourParentDocument->FlushPendingNotifications(Flush_Layout); |
|
1347 otherParentDocument->FlushPendingNotifications(Flush_Layout); |
|
1348 |
|
1349 FirePageShowEvent(ourDocshell, otherChromeEventHandler, true); |
|
1350 FirePageShowEvent(otherDocshell, ourChromeEventHandler, true); |
|
1351 |
|
1352 mInSwap = aOther->mInSwap = false; |
|
1353 return NS_OK; |
|
1354 } |
|
1355 |
|
1356 void |
|
1357 nsFrameLoader::DestroyChild() |
|
1358 { |
|
1359 if (mRemoteBrowser) { |
|
1360 mRemoteBrowser->SetOwnerElement(nullptr); |
|
1361 mRemoteBrowser->Destroy(); |
|
1362 mRemoteBrowser = nullptr; |
|
1363 } |
|
1364 } |
|
1365 |
|
1366 NS_IMETHODIMP |
|
1367 nsFrameLoader::Destroy() |
|
1368 { |
|
1369 if (mDestroyCalled) { |
|
1370 return NS_OK; |
|
1371 } |
|
1372 mDestroyCalled = true; |
|
1373 |
|
1374 if (mMessageManager) { |
|
1375 mMessageManager->Disconnect(); |
|
1376 } |
|
1377 if (mChildMessageManager) { |
|
1378 static_cast<nsInProcessTabChildGlobal*>(mChildMessageManager.get())->Disconnect(); |
|
1379 } |
|
1380 |
|
1381 nsCOMPtr<nsIDocument> doc; |
|
1382 bool dynamicSubframeRemoval = false; |
|
1383 if (mOwnerContent) { |
|
1384 doc = mOwnerContent->OwnerDoc(); |
|
1385 dynamicSubframeRemoval = !mIsTopLevelContent && !doc->InUnlinkOrDeletion(); |
|
1386 doc->SetSubDocumentFor(mOwnerContent, nullptr); |
|
1387 |
|
1388 SetOwnerContent(nullptr); |
|
1389 } |
|
1390 DestroyChild(); |
|
1391 |
|
1392 // Seems like this is a dynamic frame removal. |
|
1393 if (dynamicSubframeRemoval) { |
|
1394 if (mDocShell) { |
|
1395 mDocShell->RemoveFromSessionHistory(); |
|
1396 } |
|
1397 } |
|
1398 |
|
1399 // Let the tree owner know we're gone. |
|
1400 if (mIsTopLevelContent) { |
|
1401 if (mDocShell) { |
|
1402 nsCOMPtr<nsIDocShellTreeItem> parentItem; |
|
1403 mDocShell->GetParent(getter_AddRefs(parentItem)); |
|
1404 nsCOMPtr<nsIDocShellTreeOwner> owner = do_GetInterface(parentItem); |
|
1405 if (owner) { |
|
1406 owner->ContentShellRemoved(mDocShell); |
|
1407 } |
|
1408 } |
|
1409 } |
|
1410 |
|
1411 // Let our window know that we are gone |
|
1412 nsCOMPtr<nsPIDOMWindow> win_private(do_GetInterface(mDocShell)); |
|
1413 if (win_private) { |
|
1414 win_private->SetFrameElementInternal(nullptr); |
|
1415 } |
|
1416 |
|
1417 if ((mNeedsAsyncDestroy || !doc || |
|
1418 NS_FAILED(doc->FinalizeFrameLoader(this))) && mDocShell) { |
|
1419 nsCOMPtr<nsIRunnable> event = new nsAsyncDocShellDestroyer(mDocShell); |
|
1420 NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY); |
|
1421 NS_DispatchToCurrentThread(event); |
|
1422 |
|
1423 // Let go of our docshell now that the async destroyer holds on to |
|
1424 // the docshell. |
|
1425 |
|
1426 mDocShell = nullptr; |
|
1427 } |
|
1428 |
|
1429 // NOTE: 'this' may very well be gone by now. |
|
1430 |
|
1431 return NS_OK; |
|
1432 } |
|
1433 |
|
1434 NS_IMETHODIMP |
|
1435 nsFrameLoader::GetDepthTooGreat(bool* aDepthTooGreat) |
|
1436 { |
|
1437 *aDepthTooGreat = mDepthTooGreat; |
|
1438 return NS_OK; |
|
1439 } |
|
1440 |
|
1441 void |
|
1442 nsFrameLoader::SetOwnerContent(Element* aContent) |
|
1443 { |
|
1444 if (mObservingOwnerContent) { |
|
1445 mObservingOwnerContent = false; |
|
1446 mOwnerContent->RemoveMutationObserver(this); |
|
1447 } |
|
1448 mOwnerContent = aContent; |
|
1449 if (RenderFrameParent* rfp = GetCurrentRemoteFrame()) { |
|
1450 rfp->OwnerContentChanged(aContent); |
|
1451 } |
|
1452 |
|
1453 ResetPermissionManagerStatus(); |
|
1454 } |
|
1455 |
|
1456 bool |
|
1457 nsFrameLoader::OwnerIsBrowserOrAppFrame() |
|
1458 { |
|
1459 nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent); |
|
1460 return browserFrame ? browserFrame->GetReallyIsBrowserOrApp() : false; |
|
1461 } |
|
1462 |
|
1463 // The xpcom getter version |
|
1464 NS_IMETHODIMP |
|
1465 nsFrameLoader::GetOwnerIsBrowserOrAppFrame(bool* aResult) |
|
1466 { |
|
1467 *aResult = OwnerIsBrowserOrAppFrame(); |
|
1468 return NS_OK; |
|
1469 } |
|
1470 |
|
1471 bool |
|
1472 nsFrameLoader::OwnerIsAppFrame() |
|
1473 { |
|
1474 nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent); |
|
1475 return browserFrame ? browserFrame->GetReallyIsApp() : false; |
|
1476 } |
|
1477 |
|
1478 bool |
|
1479 nsFrameLoader::OwnerIsBrowserFrame() |
|
1480 { |
|
1481 return OwnerIsBrowserOrAppFrame() && !OwnerIsAppFrame(); |
|
1482 } |
|
1483 |
|
1484 void |
|
1485 nsFrameLoader::GetOwnerAppManifestURL(nsAString& aOut) |
|
1486 { |
|
1487 aOut.Truncate(); |
|
1488 nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent); |
|
1489 if (browserFrame) { |
|
1490 browserFrame->GetAppManifestURL(aOut); |
|
1491 } |
|
1492 } |
|
1493 |
|
1494 already_AddRefed<mozIApplication> |
|
1495 nsFrameLoader::GetOwnApp() |
|
1496 { |
|
1497 nsAutoString manifest; |
|
1498 GetOwnerAppManifestURL(manifest); |
|
1499 if (manifest.IsEmpty()) { |
|
1500 return nullptr; |
|
1501 } |
|
1502 |
|
1503 nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID); |
|
1504 NS_ENSURE_TRUE(appsService, nullptr); |
|
1505 |
|
1506 nsCOMPtr<mozIApplication> app; |
|
1507 appsService->GetAppByManifestURL(manifest, getter_AddRefs(app)); |
|
1508 |
|
1509 return app.forget(); |
|
1510 } |
|
1511 |
|
1512 already_AddRefed<mozIApplication> |
|
1513 nsFrameLoader::GetContainingApp() |
|
1514 { |
|
1515 // See if our owner content's principal has an associated app. |
|
1516 uint32_t appId = mOwnerContent->NodePrincipal()->GetAppId(); |
|
1517 MOZ_ASSERT(appId != nsIScriptSecurityManager::UNKNOWN_APP_ID); |
|
1518 |
|
1519 if (appId == nsIScriptSecurityManager::NO_APP_ID || |
|
1520 appId == nsIScriptSecurityManager::UNKNOWN_APP_ID) { |
|
1521 return nullptr; |
|
1522 } |
|
1523 |
|
1524 nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID); |
|
1525 NS_ENSURE_TRUE(appsService, nullptr); |
|
1526 |
|
1527 nsCOMPtr<mozIApplication> app; |
|
1528 appsService->GetAppByLocalId(appId, getter_AddRefs(app)); |
|
1529 |
|
1530 return app.forget(); |
|
1531 } |
|
1532 |
|
1533 bool |
|
1534 nsFrameLoader::ShouldUseRemoteProcess() |
|
1535 { |
|
1536 if (PR_GetEnv("MOZ_DISABLE_OOP_TABS") || |
|
1537 Preferences::GetBool("dom.ipc.tabs.disabled", false)) { |
|
1538 return false; |
|
1539 } |
|
1540 |
|
1541 // If we're inside a content process, don't use a remote process for this |
|
1542 // frame; it won't work properly until bug 761935 is fixed. |
|
1543 if (XRE_GetProcessType() == GeckoProcessType_Content) { |
|
1544 return false; |
|
1545 } |
|
1546 |
|
1547 // If we're an <iframe mozbrowser> and we don't have a "remote" attribute, |
|
1548 // fall back to the default. |
|
1549 if (OwnerIsBrowserOrAppFrame() && |
|
1550 !mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::Remote)) { |
|
1551 |
|
1552 return Preferences::GetBool("dom.ipc.browser_frames.oop_by_default", false); |
|
1553 } |
|
1554 |
|
1555 // Otherwise, we're remote if we have "remote=true" and we're either a |
|
1556 // browser frame or a XUL element. |
|
1557 return (OwnerIsBrowserOrAppFrame() || |
|
1558 mOwnerContent->GetNameSpaceID() == kNameSpaceID_XUL) && |
|
1559 mOwnerContent->AttrValueIs(kNameSpaceID_None, |
|
1560 nsGkAtoms::Remote, |
|
1561 nsGkAtoms::_true, |
|
1562 eCaseMatters); |
|
1563 } |
|
1564 |
|
1565 nsresult |
|
1566 nsFrameLoader::MaybeCreateDocShell() |
|
1567 { |
|
1568 if (mDocShell) { |
|
1569 return NS_OK; |
|
1570 } |
|
1571 if (mRemoteFrame) { |
|
1572 return NS_OK; |
|
1573 } |
|
1574 NS_ENSURE_STATE(!mDestroyCalled); |
|
1575 |
|
1576 if (ShouldUseRemoteProcess()) { |
|
1577 mRemoteFrame = true; |
|
1578 return NS_OK; |
|
1579 } |
|
1580 |
|
1581 // Get our parent docshell off the document of mOwnerContent |
|
1582 // XXXbz this is such a total hack.... We really need to have a |
|
1583 // better setup for doing this. |
|
1584 nsIDocument* doc = mOwnerContent->OwnerDoc(); |
|
1585 if (!(doc->IsStaticDocument() || mOwnerContent->IsInDoc())) { |
|
1586 return NS_ERROR_UNEXPECTED; |
|
1587 } |
|
1588 |
|
1589 if (doc->IsResourceDoc() || !doc->IsActive()) { |
|
1590 // Don't allow subframe loads in resource documents, nor |
|
1591 // in non-active documents. |
|
1592 return NS_ERROR_NOT_AVAILABLE; |
|
1593 } |
|
1594 |
|
1595 nsCOMPtr<nsIDocShell> docShell = doc->GetDocShell(); |
|
1596 nsCOMPtr<nsIWebNavigation> parentAsWebNav = do_QueryInterface(docShell); |
|
1597 NS_ENSURE_STATE(parentAsWebNav); |
|
1598 |
|
1599 // Create the docshell... |
|
1600 mDocShell = do_CreateInstance("@mozilla.org/docshell;1"); |
|
1601 NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE); |
|
1602 |
|
1603 // Apply sandbox flags even if our owner is not an iframe, as this copies |
|
1604 // flags from our owning content's owning document. |
|
1605 uint32_t sandboxFlags = 0; |
|
1606 HTMLIFrameElement* iframe = HTMLIFrameElement::FromContent(mOwnerContent); |
|
1607 if (iframe) { |
|
1608 sandboxFlags = iframe->GetSandboxFlags(); |
|
1609 } |
|
1610 ApplySandboxFlags(sandboxFlags); |
|
1611 |
|
1612 if (!mNetworkCreated) { |
|
1613 if (mDocShell) { |
|
1614 mDocShell->SetCreatedDynamically(true); |
|
1615 } |
|
1616 } |
|
1617 |
|
1618 // Get the frame name and tell the docshell about it. |
|
1619 NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE); |
|
1620 nsAutoString frameName; |
|
1621 |
|
1622 int32_t namespaceID = mOwnerContent->GetNameSpaceID(); |
|
1623 if (namespaceID == kNameSpaceID_XHTML && !mOwnerContent->IsInHTMLDocument()) { |
|
1624 mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, frameName); |
|
1625 } else { |
|
1626 mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, frameName); |
|
1627 // XXX if no NAME then use ID, after a transition period this will be |
|
1628 // changed so that XUL only uses ID too (bug 254284). |
|
1629 if (frameName.IsEmpty() && namespaceID == kNameSpaceID_XUL) { |
|
1630 mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, frameName); |
|
1631 } |
|
1632 } |
|
1633 |
|
1634 if (!frameName.IsEmpty()) { |
|
1635 mDocShell->SetName(frameName); |
|
1636 } |
|
1637 |
|
1638 // Inform our docShell that it has a new child. |
|
1639 // Note: This logic duplicates a lot of logic in |
|
1640 // nsSubDocumentFrame::AttributeChanged. We should fix that. |
|
1641 |
|
1642 int32_t parentType = docShell->ItemType(); |
|
1643 |
|
1644 // XXXbz why is this in content code, exactly? We should handle |
|
1645 // this some other way..... Not sure how yet. |
|
1646 nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner; |
|
1647 docShell->GetTreeOwner(getter_AddRefs(parentTreeOwner)); |
|
1648 NS_ENSURE_STATE(parentTreeOwner); |
|
1649 mIsTopLevelContent = |
|
1650 AddTreeItemToTreeOwner(mDocShell, parentTreeOwner, parentType, docShell); |
|
1651 |
|
1652 // Make sure all shells have links back to the content element |
|
1653 // in the nearest enclosing chrome shell. |
|
1654 nsCOMPtr<nsIDOMEventTarget> chromeEventHandler; |
|
1655 |
|
1656 if (parentType == nsIDocShellTreeItem::typeChrome) { |
|
1657 // Our parent shell is a chrome shell. It is therefore our nearest |
|
1658 // enclosing chrome shell. |
|
1659 |
|
1660 chromeEventHandler = do_QueryInterface(mOwnerContent); |
|
1661 NS_ASSERTION(chromeEventHandler, |
|
1662 "This mContent should implement this."); |
|
1663 } else { |
|
1664 // Our parent shell is a content shell. Get the chrome event |
|
1665 // handler from it and use that for our shell as well. |
|
1666 |
|
1667 docShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler)); |
|
1668 } |
|
1669 |
|
1670 mDocShell->SetChromeEventHandler(chromeEventHandler); |
|
1671 |
|
1672 // This is nasty, this code (the do_GetInterface(mDocShell) below) |
|
1673 // *must* come *after* the above call to |
|
1674 // mDocShell->SetChromeEventHandler() for the global window to get |
|
1675 // the right chrome event handler. |
|
1676 |
|
1677 // Tell the window about the frame that hosts it. |
|
1678 nsCOMPtr<Element> frame_element = mOwnerContent; |
|
1679 NS_ASSERTION(frame_element, "frame loader owner element not a DOM element!"); |
|
1680 |
|
1681 nsCOMPtr<nsPIDOMWindow> win_private(do_GetInterface(mDocShell)); |
|
1682 nsCOMPtr<nsIBaseWindow> base_win(do_QueryInterface(mDocShell)); |
|
1683 if (win_private) { |
|
1684 win_private->SetFrameElementInternal(frame_element); |
|
1685 } |
|
1686 |
|
1687 // This is kinda whacky, this call doesn't really create anything, |
|
1688 // but it must be called to make sure things are properly |
|
1689 // initialized. |
|
1690 if (NS_FAILED(base_win->Create()) || !win_private) { |
|
1691 // Do not call Destroy() here. See bug 472312. |
|
1692 NS_WARNING("Something wrong when creating the docshell for a frameloader!"); |
|
1693 return NS_ERROR_FAILURE; |
|
1694 } |
|
1695 |
|
1696 if (mIsTopLevelContent && |
|
1697 mOwnerContent->IsXUL(nsGkAtoms::browser) && |
|
1698 !mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::disablehistory)) { |
|
1699 nsresult rv; |
|
1700 nsCOMPtr<nsISHistory> sessionHistory = |
|
1701 do_CreateInstance(NS_SHISTORY_CONTRACTID, &rv); |
|
1702 NS_ENSURE_SUCCESS(rv, rv); |
|
1703 |
|
1704 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(mDocShell)); |
|
1705 webNav->SetSessionHistory(sessionHistory); |
|
1706 } |
|
1707 |
|
1708 EnsureMessageManager(); |
|
1709 |
|
1710 if (OwnerIsAppFrame()) { |
|
1711 // You can't be both an app and a browser frame. |
|
1712 MOZ_ASSERT(!OwnerIsBrowserFrame()); |
|
1713 |
|
1714 nsCOMPtr<mozIApplication> ownApp = GetOwnApp(); |
|
1715 MOZ_ASSERT(ownApp); |
|
1716 uint32_t ownAppId = nsIScriptSecurityManager::NO_APP_ID; |
|
1717 if (ownApp) { |
|
1718 NS_ENSURE_SUCCESS(ownApp->GetLocalId(&ownAppId), NS_ERROR_FAILURE); |
|
1719 } |
|
1720 |
|
1721 mDocShell->SetIsApp(ownAppId); |
|
1722 } |
|
1723 |
|
1724 if (OwnerIsBrowserFrame()) { |
|
1725 // You can't be both a browser and an app frame. |
|
1726 MOZ_ASSERT(!OwnerIsAppFrame()); |
|
1727 |
|
1728 nsCOMPtr<mozIApplication> containingApp = GetContainingApp(); |
|
1729 uint32_t containingAppId = nsIScriptSecurityManager::NO_APP_ID; |
|
1730 if (containingApp) { |
|
1731 NS_ENSURE_SUCCESS(containingApp->GetLocalId(&containingAppId), |
|
1732 NS_ERROR_FAILURE); |
|
1733 } |
|
1734 mDocShell->SetIsBrowserInsideApp(containingAppId); |
|
1735 } |
|
1736 |
|
1737 nsCOMPtr<nsIObserverService> os = services::GetObserverService(); |
|
1738 if (os) { |
|
1739 os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this), |
|
1740 "inprocess-browser-shown", nullptr); |
|
1741 } |
|
1742 |
|
1743 if (OwnerIsBrowserOrAppFrame() && mMessageManager) { |
|
1744 mMessageManager->LoadFrameScript( |
|
1745 NS_LITERAL_STRING("chrome://global/content/BrowserElementChild.js"), |
|
1746 /* allowDelayedLoad = */ true, |
|
1747 /* aRunInGlobalScope */ true); |
|
1748 } |
|
1749 |
|
1750 return NS_OK; |
|
1751 } |
|
1752 |
|
1753 void |
|
1754 nsFrameLoader::GetURL(nsString& aURI) |
|
1755 { |
|
1756 aURI.Truncate(); |
|
1757 |
|
1758 if (mOwnerContent->Tag() == nsGkAtoms::object) { |
|
1759 mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::data, aURI); |
|
1760 } else { |
|
1761 mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::src, aURI); |
|
1762 } |
|
1763 } |
|
1764 |
|
1765 nsresult |
|
1766 nsFrameLoader::CheckForRecursiveLoad(nsIURI* aURI) |
|
1767 { |
|
1768 nsresult rv; |
|
1769 |
|
1770 mDepthTooGreat = false; |
|
1771 rv = MaybeCreateDocShell(); |
|
1772 if (NS_FAILED(rv)) { |
|
1773 return rv; |
|
1774 } |
|
1775 NS_ASSERTION(!mRemoteFrame, |
|
1776 "Shouldn't call CheckForRecursiveLoad on remote frames."); |
|
1777 if (!mDocShell) { |
|
1778 return NS_ERROR_FAILURE; |
|
1779 } |
|
1780 |
|
1781 // Check that we're still in the docshell tree. |
|
1782 nsCOMPtr<nsIDocShellTreeOwner> treeOwner; |
|
1783 mDocShell->GetTreeOwner(getter_AddRefs(treeOwner)); |
|
1784 NS_WARN_IF_FALSE(treeOwner, |
|
1785 "Trying to load a new url to a docshell without owner!"); |
|
1786 NS_ENSURE_STATE(treeOwner); |
|
1787 |
|
1788 if (mDocShell->ItemType() != nsIDocShellTreeItem::typeContent) { |
|
1789 // No need to do recursion-protection here XXXbz why not?? Do we really |
|
1790 // trust people not to screw up with non-content docshells? |
|
1791 return NS_OK; |
|
1792 } |
|
1793 |
|
1794 // Bug 8065: Don't exceed some maximum depth in content frames |
|
1795 // (MAX_DEPTH_CONTENT_FRAMES) |
|
1796 nsCOMPtr<nsIDocShellTreeItem> parentAsItem; |
|
1797 mDocShell->GetSameTypeParent(getter_AddRefs(parentAsItem)); |
|
1798 int32_t depth = 0; |
|
1799 while (parentAsItem) { |
|
1800 ++depth; |
|
1801 |
|
1802 if (depth >= MAX_DEPTH_CONTENT_FRAMES) { |
|
1803 mDepthTooGreat = true; |
|
1804 NS_WARNING("Too many nested content frames so giving up"); |
|
1805 |
|
1806 return NS_ERROR_UNEXPECTED; // Too deep, give up! (silently?) |
|
1807 } |
|
1808 |
|
1809 nsCOMPtr<nsIDocShellTreeItem> temp; |
|
1810 temp.swap(parentAsItem); |
|
1811 temp->GetSameTypeParent(getter_AddRefs(parentAsItem)); |
|
1812 } |
|
1813 |
|
1814 // Bug 136580: Check for recursive frame loading excluding about:srcdoc URIs. |
|
1815 // srcdoc URIs require their contents to be specified inline, so it isn't |
|
1816 // possible for undesirable recursion to occur without the aid of a |
|
1817 // non-srcdoc URI, which this method will block normally. |
|
1818 // Besides, URI is not enough to guarantee uniqueness of srcdoc documents. |
|
1819 nsAutoCString buffer; |
|
1820 rv = aURI->GetScheme(buffer); |
|
1821 if (NS_SUCCEEDED(rv) && buffer.EqualsLiteral("about")) { |
|
1822 rv = aURI->GetPath(buffer); |
|
1823 if (NS_SUCCEEDED(rv) && buffer.EqualsLiteral("srcdoc")) { |
|
1824 // Duplicates allowed up to depth limits |
|
1825 return NS_OK; |
|
1826 } |
|
1827 } |
|
1828 int32_t matchCount = 0; |
|
1829 mDocShell->GetSameTypeParent(getter_AddRefs(parentAsItem)); |
|
1830 while (parentAsItem) { |
|
1831 // Check the parent URI with the URI we're loading |
|
1832 nsCOMPtr<nsIWebNavigation> parentAsNav(do_QueryInterface(parentAsItem)); |
|
1833 if (parentAsNav) { |
|
1834 // Does the URI match the one we're about to load? |
|
1835 nsCOMPtr<nsIURI> parentURI; |
|
1836 parentAsNav->GetCurrentURI(getter_AddRefs(parentURI)); |
|
1837 if (parentURI) { |
|
1838 // Bug 98158/193011: We need to ignore data after the # |
|
1839 bool equal; |
|
1840 rv = aURI->EqualsExceptRef(parentURI, &equal); |
|
1841 NS_ENSURE_SUCCESS(rv, rv); |
|
1842 |
|
1843 if (equal) { |
|
1844 matchCount++; |
|
1845 if (matchCount >= MAX_SAME_URL_CONTENT_FRAMES) { |
|
1846 NS_WARNING("Too many nested content frames have the same url (recursion?) so giving up"); |
|
1847 return NS_ERROR_UNEXPECTED; |
|
1848 } |
|
1849 } |
|
1850 } |
|
1851 } |
|
1852 nsCOMPtr<nsIDocShellTreeItem> temp; |
|
1853 temp.swap(parentAsItem); |
|
1854 temp->GetSameTypeParent(getter_AddRefs(parentAsItem)); |
|
1855 } |
|
1856 |
|
1857 return NS_OK; |
|
1858 } |
|
1859 |
|
1860 nsresult |
|
1861 nsFrameLoader::GetWindowDimensions(nsRect& aRect) |
|
1862 { |
|
1863 // Need to get outer window position here |
|
1864 nsIDocument* doc = mOwnerContent->GetDocument(); |
|
1865 if (!doc) { |
|
1866 return NS_ERROR_FAILURE; |
|
1867 } |
|
1868 |
|
1869 if (doc->IsResourceDoc()) { |
|
1870 return NS_ERROR_FAILURE; |
|
1871 } |
|
1872 |
|
1873 nsCOMPtr<nsIWebNavigation> parentAsWebNav = |
|
1874 do_GetInterface(doc->GetWindow()); |
|
1875 |
|
1876 if (!parentAsWebNav) { |
|
1877 return NS_ERROR_FAILURE; |
|
1878 } |
|
1879 |
|
1880 nsCOMPtr<nsIDocShellTreeItem> parentAsItem(do_QueryInterface(parentAsWebNav)); |
|
1881 |
|
1882 nsCOMPtr<nsIDocShellTreeOwner> parentOwner; |
|
1883 if (NS_FAILED(parentAsItem->GetTreeOwner(getter_AddRefs(parentOwner))) || |
|
1884 !parentOwner) { |
|
1885 return NS_ERROR_FAILURE; |
|
1886 } |
|
1887 |
|
1888 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_GetInterface(parentOwner)); |
|
1889 treeOwnerAsWin->GetPosition(&aRect.x, &aRect.y); |
|
1890 treeOwnerAsWin->GetSize(&aRect.width, &aRect.height); |
|
1891 return NS_OK; |
|
1892 } |
|
1893 |
|
1894 NS_IMETHODIMP |
|
1895 nsFrameLoader::UpdatePositionAndSize(nsSubDocumentFrame *aIFrame) |
|
1896 { |
|
1897 if (mRemoteFrame) { |
|
1898 if (mRemoteBrowser) { |
|
1899 nsIntSize size = aIFrame->GetSubdocumentSize(); |
|
1900 nsRect dimensions; |
|
1901 NS_ENSURE_SUCCESS(GetWindowDimensions(dimensions), NS_ERROR_FAILURE); |
|
1902 mRemoteBrowser->UpdateDimensions(dimensions, size); |
|
1903 } |
|
1904 return NS_OK; |
|
1905 } |
|
1906 return UpdateBaseWindowPositionAndSize(aIFrame); |
|
1907 } |
|
1908 |
|
1909 nsresult |
|
1910 nsFrameLoader::UpdateBaseWindowPositionAndSize(nsSubDocumentFrame *aIFrame) |
|
1911 { |
|
1912 nsCOMPtr<nsIDocShell> docShell; |
|
1913 GetDocShell(getter_AddRefs(docShell)); |
|
1914 nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(docShell)); |
|
1915 |
|
1916 // resize the sub document |
|
1917 if (baseWindow) { |
|
1918 int32_t x = 0; |
|
1919 int32_t y = 0; |
|
1920 |
|
1921 nsWeakFrame weakFrame(aIFrame); |
|
1922 |
|
1923 baseWindow->GetPositionAndSize(&x, &y, nullptr, nullptr); |
|
1924 |
|
1925 if (!weakFrame.IsAlive()) { |
|
1926 // GetPositionAndSize() killed us |
|
1927 return NS_OK; |
|
1928 } |
|
1929 |
|
1930 nsIntSize size = aIFrame->GetSubdocumentSize(); |
|
1931 |
|
1932 baseWindow->SetPositionAndSize(x, y, size.width, size.height, false); |
|
1933 } |
|
1934 |
|
1935 return NS_OK; |
|
1936 } |
|
1937 |
|
1938 NS_IMETHODIMP |
|
1939 nsFrameLoader::GetRenderMode(uint32_t* aRenderMode) |
|
1940 { |
|
1941 *aRenderMode = mRenderMode; |
|
1942 return NS_OK; |
|
1943 } |
|
1944 |
|
1945 NS_IMETHODIMP |
|
1946 nsFrameLoader::SetRenderMode(uint32_t aRenderMode) |
|
1947 { |
|
1948 if (aRenderMode == mRenderMode) { |
|
1949 return NS_OK; |
|
1950 } |
|
1951 |
|
1952 mRenderMode = aRenderMode; |
|
1953 return NS_OK; |
|
1954 } |
|
1955 |
|
1956 NS_IMETHODIMP |
|
1957 nsFrameLoader::GetEventMode(uint32_t* aEventMode) |
|
1958 { |
|
1959 *aEventMode = mEventMode; |
|
1960 return NS_OK; |
|
1961 } |
|
1962 |
|
1963 NS_IMETHODIMP |
|
1964 nsFrameLoader::SetEventMode(uint32_t aEventMode) |
|
1965 { |
|
1966 mEventMode = aEventMode; |
|
1967 return NS_OK; |
|
1968 } |
|
1969 |
|
1970 NS_IMETHODIMP |
|
1971 nsFrameLoader::GetClipSubdocument(bool* aResult) |
|
1972 { |
|
1973 *aResult = mClipSubdocument; |
|
1974 return NS_OK; |
|
1975 } |
|
1976 |
|
1977 NS_IMETHODIMP |
|
1978 nsFrameLoader::SetClipSubdocument(bool aClip) |
|
1979 { |
|
1980 mClipSubdocument = aClip; |
|
1981 nsIFrame* frame = GetPrimaryFrameOfOwningContent(); |
|
1982 if (frame) { |
|
1983 frame->InvalidateFrame(); |
|
1984 frame->PresContext()->PresShell()-> |
|
1985 FrameNeedsReflow(frame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY); |
|
1986 nsSubDocumentFrame* subdocFrame = do_QueryFrame(frame); |
|
1987 if (subdocFrame) { |
|
1988 nsIFrame* subdocRootFrame = subdocFrame->GetSubdocumentRootFrame(); |
|
1989 if (subdocRootFrame) { |
|
1990 nsIFrame* subdocRootScrollFrame = subdocRootFrame->PresContext()->PresShell()-> |
|
1991 GetRootScrollFrame(); |
|
1992 if (subdocRootScrollFrame) { |
|
1993 frame->PresContext()->PresShell()-> |
|
1994 FrameNeedsReflow(frame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY); |
|
1995 } |
|
1996 } |
|
1997 } |
|
1998 } |
|
1999 return NS_OK; |
|
2000 } |
|
2001 |
|
2002 NS_IMETHODIMP |
|
2003 nsFrameLoader::GetClampScrollPosition(bool* aResult) |
|
2004 { |
|
2005 *aResult = mClampScrollPosition; |
|
2006 return NS_OK; |
|
2007 } |
|
2008 |
|
2009 NS_IMETHODIMP |
|
2010 nsFrameLoader::SetClampScrollPosition(bool aClamp) |
|
2011 { |
|
2012 mClampScrollPosition = aClamp; |
|
2013 |
|
2014 // When turning clamping on, make sure the current position is clamped. |
|
2015 if (aClamp) { |
|
2016 nsIFrame* frame = GetPrimaryFrameOfOwningContent(); |
|
2017 nsSubDocumentFrame* subdocFrame = do_QueryFrame(frame); |
|
2018 if (subdocFrame) { |
|
2019 nsIFrame* subdocRootFrame = subdocFrame->GetSubdocumentRootFrame(); |
|
2020 if (subdocRootFrame) { |
|
2021 nsIScrollableFrame* subdocRootScrollFrame = subdocRootFrame->PresContext()->PresShell()-> |
|
2022 GetRootScrollFrameAsScrollable(); |
|
2023 if (subdocRootScrollFrame) { |
|
2024 subdocRootScrollFrame->ScrollTo(subdocRootScrollFrame->GetScrollPosition(), nsIScrollableFrame::INSTANT); |
|
2025 } |
|
2026 } |
|
2027 } |
|
2028 } |
|
2029 return NS_OK; |
|
2030 } |
|
2031 |
|
2032 bool |
|
2033 nsFrameLoader::TryRemoteBrowser() |
|
2034 { |
|
2035 NS_ASSERTION(!mRemoteBrowser, "TryRemoteBrowser called with a remote browser already?"); |
|
2036 |
|
2037 nsIDocument* doc = mOwnerContent->GetDocument(); |
|
2038 if (!doc) { |
|
2039 return false; |
|
2040 } |
|
2041 |
|
2042 if (doc->IsResourceDoc()) { |
|
2043 // Don't allow subframe loads in external reference documents |
|
2044 return false; |
|
2045 } |
|
2046 |
|
2047 nsCOMPtr<nsIWebNavigation> parentAsWebNav = |
|
2048 do_GetInterface(doc->GetWindow()); |
|
2049 |
|
2050 if (!parentAsWebNav) { |
|
2051 return false; |
|
2052 } |
|
2053 |
|
2054 nsCOMPtr<nsIDocShellTreeItem> parentAsItem(do_QueryInterface(parentAsWebNav)); |
|
2055 |
|
2056 // <iframe mozbrowser> gets to skip these checks. |
|
2057 if (!OwnerIsBrowserOrAppFrame()) { |
|
2058 if (parentAsItem->ItemType() != nsIDocShellTreeItem::typeChrome) { |
|
2059 return false; |
|
2060 } |
|
2061 |
|
2062 if (!mOwnerContent->IsXUL()) { |
|
2063 return false; |
|
2064 } |
|
2065 |
|
2066 nsAutoString value; |
|
2067 mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, value); |
|
2068 |
|
2069 if (!value.LowerCaseEqualsLiteral("content") && |
|
2070 !StringBeginsWith(value, NS_LITERAL_STRING("content-"), |
|
2071 nsCaseInsensitiveStringComparator())) { |
|
2072 return false; |
|
2073 } |
|
2074 } |
|
2075 |
|
2076 uint32_t chromeFlags = 0; |
|
2077 nsCOMPtr<nsIDocShellTreeOwner> parentOwner; |
|
2078 if (NS_FAILED(parentAsItem->GetTreeOwner(getter_AddRefs(parentOwner))) || |
|
2079 !parentOwner) { |
|
2080 return false; |
|
2081 } |
|
2082 nsCOMPtr<nsIXULWindow> window(do_GetInterface(parentOwner)); |
|
2083 if (!window) { |
|
2084 return false; |
|
2085 } |
|
2086 if (NS_FAILED(window->GetChromeFlags(&chromeFlags))) { |
|
2087 return false; |
|
2088 } |
|
2089 |
|
2090 PROFILER_LABEL("nsFrameLoader", "CreateRemoteBrowser"); |
|
2091 |
|
2092 MutableTabContext context; |
|
2093 nsCOMPtr<mozIApplication> ownApp = GetOwnApp(); |
|
2094 nsCOMPtr<mozIApplication> containingApp = GetContainingApp(); |
|
2095 ScrollingBehavior scrollingBehavior = DEFAULT_SCROLLING; |
|
2096 |
|
2097 if (Preferences::GetBool("dom.browser_frames.useAsyncPanZoom", false) || |
|
2098 mOwnerContent->AttrValueIs(kNameSpaceID_None, |
|
2099 nsGkAtoms::mozasyncpanzoom, |
|
2100 nsGkAtoms::_true, |
|
2101 eCaseMatters)) { |
|
2102 scrollingBehavior = ASYNC_PAN_ZOOM; |
|
2103 } |
|
2104 |
|
2105 bool rv = true; |
|
2106 if (ownApp) { |
|
2107 rv = context.SetTabContextForAppFrame(ownApp, containingApp, scrollingBehavior); |
|
2108 } else if (OwnerIsBrowserFrame()) { |
|
2109 // The |else| above is unnecessary; OwnerIsBrowserFrame() implies !ownApp. |
|
2110 rv = context.SetTabContextForBrowserFrame(containingApp, scrollingBehavior); |
|
2111 } else { |
|
2112 rv = context.SetTabContextForNormalFrame(scrollingBehavior); |
|
2113 } |
|
2114 NS_ENSURE_TRUE(rv, false); |
|
2115 |
|
2116 nsCOMPtr<Element> ownerElement = mOwnerContent; |
|
2117 mRemoteBrowser = ContentParent::CreateBrowserOrApp(context, ownerElement); |
|
2118 if (mRemoteBrowser) { |
|
2119 mChildID = mRemoteBrowser->Manager()->ChildID(); |
|
2120 nsCOMPtr<nsIDocShellTreeItem> rootItem; |
|
2121 parentAsItem->GetRootTreeItem(getter_AddRefs(rootItem)); |
|
2122 nsCOMPtr<nsIDOMWindow> rootWin = do_GetInterface(rootItem); |
|
2123 nsCOMPtr<nsIDOMChromeWindow> rootChromeWin = do_QueryInterface(rootWin); |
|
2124 NS_ABORT_IF_FALSE(rootChromeWin, "How did we not get a chrome window here?"); |
|
2125 |
|
2126 nsCOMPtr<nsIBrowserDOMWindow> browserDOMWin; |
|
2127 rootChromeWin->GetBrowserDOMWindow(getter_AddRefs(browserDOMWin)); |
|
2128 mRemoteBrowser->SetBrowserDOMWindow(browserDOMWin); |
|
2129 |
|
2130 mContentParent = mRemoteBrowser->Manager(); |
|
2131 |
|
2132 if (mOwnerContent->AttrValueIs(kNameSpaceID_None, |
|
2133 nsGkAtoms::mozpasspointerevents, |
|
2134 nsGkAtoms::_true, |
|
2135 eCaseMatters)) { |
|
2136 unused << mRemoteBrowser->SendSetUpdateHitRegion(true); |
|
2137 } |
|
2138 } |
|
2139 return true; |
|
2140 } |
|
2141 |
|
2142 mozilla::dom::PBrowserParent* |
|
2143 nsFrameLoader::GetRemoteBrowser() |
|
2144 { |
|
2145 return mRemoteBrowser; |
|
2146 } |
|
2147 |
|
2148 NS_IMETHODIMP |
|
2149 nsFrameLoader::ActivateRemoteFrame() { |
|
2150 if (mRemoteBrowser) { |
|
2151 mRemoteBrowser->Activate(); |
|
2152 return NS_OK; |
|
2153 } |
|
2154 return NS_ERROR_UNEXPECTED; |
|
2155 } |
|
2156 |
|
2157 NS_IMETHODIMP |
|
2158 nsFrameLoader::DeactivateRemoteFrame() { |
|
2159 if (mRemoteBrowser) { |
|
2160 mRemoteBrowser->Deactivate(); |
|
2161 return NS_OK; |
|
2162 } |
|
2163 return NS_ERROR_UNEXPECTED; |
|
2164 } |
|
2165 |
|
2166 NS_IMETHODIMP |
|
2167 nsFrameLoader::SendCrossProcessMouseEvent(const nsAString& aType, |
|
2168 float aX, |
|
2169 float aY, |
|
2170 int32_t aButton, |
|
2171 int32_t aClickCount, |
|
2172 int32_t aModifiers, |
|
2173 bool aIgnoreRootScrollFrame) |
|
2174 { |
|
2175 if (mRemoteBrowser) { |
|
2176 mRemoteBrowser->SendMouseEvent(aType, aX, aY, aButton, |
|
2177 aClickCount, aModifiers, |
|
2178 aIgnoreRootScrollFrame); |
|
2179 return NS_OK; |
|
2180 } |
|
2181 return NS_ERROR_FAILURE; |
|
2182 } |
|
2183 |
|
2184 NS_IMETHODIMP |
|
2185 nsFrameLoader::ActivateFrameEvent(const nsAString& aType, |
|
2186 bool aCapture) |
|
2187 { |
|
2188 if (mRemoteBrowser) { |
|
2189 return mRemoteBrowser->SendActivateFrameEvent(nsString(aType), aCapture) ? |
|
2190 NS_OK : NS_ERROR_NOT_AVAILABLE; |
|
2191 } |
|
2192 return NS_ERROR_FAILURE; |
|
2193 } |
|
2194 |
|
2195 NS_IMETHODIMP |
|
2196 nsFrameLoader::SendCrossProcessKeyEvent(const nsAString& aType, |
|
2197 int32_t aKeyCode, |
|
2198 int32_t aCharCode, |
|
2199 int32_t aModifiers, |
|
2200 bool aPreventDefault) |
|
2201 { |
|
2202 if (mRemoteBrowser) { |
|
2203 mRemoteBrowser->SendKeyEvent(aType, aKeyCode, aCharCode, aModifiers, |
|
2204 aPreventDefault); |
|
2205 return NS_OK; |
|
2206 } |
|
2207 return NS_ERROR_FAILURE; |
|
2208 } |
|
2209 |
|
2210 nsresult |
|
2211 nsFrameLoader::CreateStaticClone(nsIFrameLoader* aDest) |
|
2212 { |
|
2213 nsFrameLoader* dest = static_cast<nsFrameLoader*>(aDest); |
|
2214 dest->MaybeCreateDocShell(); |
|
2215 NS_ENSURE_STATE(dest->mDocShell); |
|
2216 |
|
2217 nsCOMPtr<nsIDocument> dummy = do_GetInterface(dest->mDocShell); |
|
2218 nsCOMPtr<nsIContentViewer> viewer; |
|
2219 dest->mDocShell->GetContentViewer(getter_AddRefs(viewer)); |
|
2220 NS_ENSURE_STATE(viewer); |
|
2221 |
|
2222 nsCOMPtr<nsIDocShell> origDocShell; |
|
2223 GetDocShell(getter_AddRefs(origDocShell)); |
|
2224 nsCOMPtr<nsIDocument> doc = do_GetInterface(origDocShell); |
|
2225 NS_ENSURE_STATE(doc); |
|
2226 nsCOMPtr<nsIDocument> clonedDoc = doc->CreateStaticClone(dest->mDocShell); |
|
2227 nsCOMPtr<nsIDOMDocument> clonedDOMDoc = do_QueryInterface(clonedDoc); |
|
2228 |
|
2229 viewer->SetDOMDocument(clonedDOMDoc); |
|
2230 return NS_OK; |
|
2231 } |
|
2232 |
|
2233 bool |
|
2234 nsFrameLoader::DoLoadFrameScript(const nsAString& aURL, bool aRunInGlobalScope) |
|
2235 { |
|
2236 mozilla::dom::PBrowserParent* tabParent = GetRemoteBrowser(); |
|
2237 if (tabParent) { |
|
2238 return tabParent->SendLoadRemoteScript(nsString(aURL), aRunInGlobalScope); |
|
2239 } |
|
2240 nsRefPtr<nsInProcessTabChildGlobal> tabChild = |
|
2241 static_cast<nsInProcessTabChildGlobal*>(GetTabChildGlobalAsEventTarget()); |
|
2242 if (tabChild) { |
|
2243 tabChild->LoadFrameScript(aURL, aRunInGlobalScope); |
|
2244 } |
|
2245 return true; |
|
2246 } |
|
2247 |
|
2248 class nsAsyncMessageToChild : public nsSameProcessAsyncMessageBase, |
|
2249 public nsRunnable |
|
2250 { |
|
2251 public: |
|
2252 nsAsyncMessageToChild(JSContext* aCx, |
|
2253 nsFrameLoader* aFrameLoader, |
|
2254 const nsAString& aMessage, |
|
2255 const StructuredCloneData& aData, |
|
2256 JS::Handle<JSObject *> aCpows, |
|
2257 nsIPrincipal* aPrincipal) |
|
2258 : nsSameProcessAsyncMessageBase(aCx, aMessage, aData, aCpows, aPrincipal) |
|
2259 , mFrameLoader(aFrameLoader) |
|
2260 { |
|
2261 } |
|
2262 |
|
2263 NS_IMETHOD Run() |
|
2264 { |
|
2265 nsInProcessTabChildGlobal* tabChild = |
|
2266 static_cast<nsInProcessTabChildGlobal*>(mFrameLoader->mChildMessageManager.get()); |
|
2267 if (tabChild && tabChild->GetInnerManager()) { |
|
2268 nsCOMPtr<nsIXPConnectJSObjectHolder> kungFuDeathGrip(tabChild->GetGlobal()); |
|
2269 ReceiveMessage(static_cast<EventTarget*>(tabChild), |
|
2270 tabChild->GetInnerManager()); |
|
2271 } |
|
2272 return NS_OK; |
|
2273 } |
|
2274 nsRefPtr<nsFrameLoader> mFrameLoader; |
|
2275 }; |
|
2276 |
|
2277 bool |
|
2278 nsFrameLoader::DoSendAsyncMessage(JSContext* aCx, |
|
2279 const nsAString& aMessage, |
|
2280 const StructuredCloneData& aData, |
|
2281 JS::Handle<JSObject *> aCpows, |
|
2282 nsIPrincipal* aPrincipal) |
|
2283 { |
|
2284 TabParent* tabParent = mRemoteBrowser; |
|
2285 if (tabParent) { |
|
2286 ClonedMessageData data; |
|
2287 ContentParent* cp = tabParent->Manager(); |
|
2288 if (!BuildClonedMessageDataForParent(cp, aData, data)) { |
|
2289 return false; |
|
2290 } |
|
2291 InfallibleTArray<mozilla::jsipc::CpowEntry> cpows; |
|
2292 if (aCpows && !cp->GetCPOWManager()->Wrap(aCx, aCpows, &cpows)) { |
|
2293 return false; |
|
2294 } |
|
2295 return tabParent->SendAsyncMessage(nsString(aMessage), data, cpows, |
|
2296 aPrincipal); |
|
2297 } |
|
2298 |
|
2299 if (mChildMessageManager) { |
|
2300 nsRefPtr<nsIRunnable> ev = new nsAsyncMessageToChild(aCx, this, aMessage, |
|
2301 aData, aCpows, |
|
2302 aPrincipal); |
|
2303 NS_DispatchToCurrentThread(ev); |
|
2304 return true; |
|
2305 } |
|
2306 |
|
2307 // We don't have any targets to send our asynchronous message to. |
|
2308 return false; |
|
2309 } |
|
2310 |
|
2311 bool |
|
2312 nsFrameLoader::CheckPermission(const nsAString& aPermission) |
|
2313 { |
|
2314 return AssertAppProcessPermission(GetRemoteBrowser(), |
|
2315 NS_ConvertUTF16toUTF8(aPermission).get()); |
|
2316 } |
|
2317 |
|
2318 bool |
|
2319 nsFrameLoader::CheckManifestURL(const nsAString& aManifestURL) |
|
2320 { |
|
2321 return AssertAppProcessManifestURL(GetRemoteBrowser(), |
|
2322 NS_ConvertUTF16toUTF8(aManifestURL).get()); |
|
2323 } |
|
2324 |
|
2325 bool |
|
2326 nsFrameLoader::CheckAppHasPermission(const nsAString& aPermission) |
|
2327 { |
|
2328 return AssertAppHasPermission(GetRemoteBrowser(), |
|
2329 NS_ConvertUTF16toUTF8(aPermission).get()); |
|
2330 } |
|
2331 |
|
2332 NS_IMETHODIMP |
|
2333 nsFrameLoader::GetMessageManager(nsIMessageSender** aManager) |
|
2334 { |
|
2335 EnsureMessageManager(); |
|
2336 if (mMessageManager) { |
|
2337 CallQueryInterface(mMessageManager, aManager); |
|
2338 } |
|
2339 return NS_OK; |
|
2340 } |
|
2341 |
|
2342 NS_IMETHODIMP |
|
2343 nsFrameLoader::GetContentViewsIn(float aXPx, float aYPx, |
|
2344 float aTopSize, float aRightSize, |
|
2345 float aBottomSize, float aLeftSize, |
|
2346 uint32_t* aLength, |
|
2347 nsIContentView*** aResult) |
|
2348 { |
|
2349 nscoord x = nsPresContext::CSSPixelsToAppUnits(aXPx - aLeftSize); |
|
2350 nscoord y = nsPresContext::CSSPixelsToAppUnits(aYPx - aTopSize); |
|
2351 nscoord w = nsPresContext::CSSPixelsToAppUnits(aLeftSize + aRightSize) + 1; |
|
2352 nscoord h = nsPresContext::CSSPixelsToAppUnits(aTopSize + aBottomSize) + 1; |
|
2353 nsRect target(x, y, w, h); |
|
2354 |
|
2355 nsIFrame* frame = GetPrimaryFrameOfOwningContent(); |
|
2356 |
|
2357 nsTArray<ViewID> ids; |
|
2358 nsLayoutUtils::GetRemoteContentIds(frame, target, ids, true); |
|
2359 if (ids.Length() == 0 || !GetCurrentRemoteFrame()) { |
|
2360 *aResult = nullptr; |
|
2361 *aLength = 0; |
|
2362 return NS_OK; |
|
2363 } |
|
2364 |
|
2365 nsIContentView** result = reinterpret_cast<nsIContentView**>( |
|
2366 NS_Alloc(ids.Length() * sizeof(nsIContentView*))); |
|
2367 |
|
2368 for (uint32_t i = 0; i < ids.Length(); i++) { |
|
2369 nsIContentView* view = GetCurrentRemoteFrame()->GetContentView(ids[i]); |
|
2370 NS_ABORT_IF_FALSE(view, "Retrieved ID from RenderFrameParent, it should be valid!"); |
|
2371 nsRefPtr<nsIContentView>(view).forget(&result[i]); |
|
2372 } |
|
2373 |
|
2374 *aResult = result; |
|
2375 *aLength = ids.Length(); |
|
2376 |
|
2377 return NS_OK; |
|
2378 } |
|
2379 |
|
2380 NS_IMETHODIMP |
|
2381 nsFrameLoader::GetRootContentView(nsIContentView** aContentView) |
|
2382 { |
|
2383 RenderFrameParent* rfp = GetCurrentRemoteFrame(); |
|
2384 if (!rfp) { |
|
2385 *aContentView = nullptr; |
|
2386 return NS_OK; |
|
2387 } |
|
2388 |
|
2389 nsContentView* view = rfp->GetRootContentView(); |
|
2390 NS_ABORT_IF_FALSE(view, "Should always be able to create root scrollable!"); |
|
2391 nsRefPtr<nsIContentView>(view).forget(aContentView); |
|
2392 |
|
2393 return NS_OK; |
|
2394 } |
|
2395 |
|
2396 nsresult |
|
2397 nsFrameLoader::EnsureMessageManager() |
|
2398 { |
|
2399 NS_ENSURE_STATE(mOwnerContent); |
|
2400 |
|
2401 nsresult rv = MaybeCreateDocShell(); |
|
2402 if (NS_FAILED(rv)) { |
|
2403 return rv; |
|
2404 } |
|
2405 |
|
2406 if (!mIsTopLevelContent && !OwnerIsBrowserOrAppFrame() && !mRemoteFrame) { |
|
2407 return NS_OK; |
|
2408 } |
|
2409 |
|
2410 if (mMessageManager) { |
|
2411 if (ShouldUseRemoteProcess() && mRemoteBrowserShown) { |
|
2412 mMessageManager->InitWithCallback(this); |
|
2413 } |
|
2414 return NS_OK; |
|
2415 } |
|
2416 |
|
2417 nsIScriptContext* sctx = mOwnerContent->GetContextForEventHandlers(&rv); |
|
2418 NS_ENSURE_SUCCESS(rv, rv); |
|
2419 NS_ENSURE_STATE(sctx); |
|
2420 AutoPushJSContext cx(sctx->GetNativeContext()); |
|
2421 NS_ENSURE_STATE(cx); |
|
2422 |
|
2423 nsCOMPtr<nsIDOMChromeWindow> chromeWindow = |
|
2424 do_QueryInterface(GetOwnerDoc()->GetWindow()); |
|
2425 nsCOMPtr<nsIMessageBroadcaster> parentManager; |
|
2426 if (chromeWindow) { |
|
2427 chromeWindow->GetMessageManager(getter_AddRefs(parentManager)); |
|
2428 } |
|
2429 |
|
2430 if (ShouldUseRemoteProcess()) { |
|
2431 mMessageManager = new nsFrameMessageManager(mRemoteBrowserShown ? this : nullptr, |
|
2432 static_cast<nsFrameMessageManager*>(parentManager.get()), |
|
2433 MM_CHROME); |
|
2434 } else { |
|
2435 mMessageManager = new nsFrameMessageManager(nullptr, |
|
2436 static_cast<nsFrameMessageManager*>(parentManager.get()), |
|
2437 MM_CHROME); |
|
2438 |
|
2439 mChildMessageManager = |
|
2440 new nsInProcessTabChildGlobal(mDocShell, mOwnerContent, mMessageManager); |
|
2441 // Force pending frame scripts to be loaded. |
|
2442 mMessageManager->InitWithCallback(this); |
|
2443 } |
|
2444 return NS_OK; |
|
2445 } |
|
2446 |
|
2447 EventTarget* |
|
2448 nsFrameLoader::GetTabChildGlobalAsEventTarget() |
|
2449 { |
|
2450 return static_cast<nsInProcessTabChildGlobal*>(mChildMessageManager.get()); |
|
2451 } |
|
2452 |
|
2453 NS_IMETHODIMP |
|
2454 nsFrameLoader::GetOwnerElement(nsIDOMElement **aElement) |
|
2455 { |
|
2456 nsCOMPtr<nsIDOMElement> ownerElement = do_QueryInterface(mOwnerContent); |
|
2457 ownerElement.forget(aElement); |
|
2458 return NS_OK; |
|
2459 } |
|
2460 |
|
2461 NS_IMETHODIMP |
|
2462 nsFrameLoader::GetChildID(uint64_t* aChildID) |
|
2463 { |
|
2464 *aChildID = mChildID; |
|
2465 return NS_OK; |
|
2466 } |
|
2467 |
|
2468 void |
|
2469 nsFrameLoader::SetRemoteBrowser(nsITabParent* aTabParent) |
|
2470 { |
|
2471 MOZ_ASSERT(!mRemoteBrowser); |
|
2472 MOZ_ASSERT(!mCurrentRemoteFrame); |
|
2473 mRemoteFrame = true; |
|
2474 mRemoteBrowser = static_cast<TabParent*>(aTabParent); |
|
2475 mChildID = mRemoteBrowser ? mRemoteBrowser->Manager()->ChildID() : 0; |
|
2476 ShowRemoteFrame(nsIntSize(0, 0)); |
|
2477 } |
|
2478 |
|
2479 void |
|
2480 nsFrameLoader::SetDetachedSubdocView(nsView* aDetachedViews, |
|
2481 nsIDocument* aContainerDoc) |
|
2482 { |
|
2483 mDetachedSubdocViews = aDetachedViews; |
|
2484 mContainerDocWhileDetached = aContainerDoc; |
|
2485 } |
|
2486 |
|
2487 nsView* |
|
2488 nsFrameLoader::GetDetachedSubdocView(nsIDocument** aContainerDoc) const |
|
2489 { |
|
2490 NS_IF_ADDREF(*aContainerDoc = mContainerDocWhileDetached); |
|
2491 return mDetachedSubdocViews; |
|
2492 } |
|
2493 |
|
2494 void |
|
2495 nsFrameLoader::ApplySandboxFlags(uint32_t sandboxFlags) |
|
2496 { |
|
2497 if (mDocShell) { |
|
2498 uint32_t parentSandboxFlags = mOwnerContent->OwnerDoc()->GetSandboxFlags(); |
|
2499 |
|
2500 // The child can only add restrictions, never remove them. |
|
2501 sandboxFlags |= parentSandboxFlags; |
|
2502 mDocShell->SetSandboxFlags(sandboxFlags); |
|
2503 } |
|
2504 } |
|
2505 |
|
2506 /* virtual */ void |
|
2507 nsFrameLoader::AttributeChanged(nsIDocument* aDocument, |
|
2508 mozilla::dom::Element* aElement, |
|
2509 int32_t aNameSpaceID, |
|
2510 nsIAtom* aAttribute, |
|
2511 int32_t aModType) |
|
2512 { |
|
2513 MOZ_ASSERT(mObservingOwnerContent); |
|
2514 // TODO: Implement ContentShellAdded for remote browsers (bug 658304) |
|
2515 MOZ_ASSERT(!mRemoteBrowser); |
|
2516 |
|
2517 if (aNameSpaceID != kNameSpaceID_None || aAttribute != TypeAttrName()) { |
|
2518 return; |
|
2519 } |
|
2520 |
|
2521 if (aElement != mOwnerContent) { |
|
2522 return; |
|
2523 } |
|
2524 |
|
2525 // Note: This logic duplicates a lot of logic in |
|
2526 // MaybeCreateDocshell. We should fix that. |
|
2527 |
|
2528 // Notify our enclosing chrome that our type has changed. We only do this |
|
2529 // if our parent is chrome, since in all other cases we're random content |
|
2530 // subframes and the treeowner shouldn't worry about us. |
|
2531 if (!mDocShell) { |
|
2532 return; |
|
2533 } |
|
2534 |
|
2535 nsCOMPtr<nsIDocShellTreeItem> parentItem; |
|
2536 mDocShell->GetParent(getter_AddRefs(parentItem)); |
|
2537 if (!parentItem) { |
|
2538 return; |
|
2539 } |
|
2540 |
|
2541 if (parentItem->ItemType() != nsIDocShellTreeItem::typeChrome) { |
|
2542 return; |
|
2543 } |
|
2544 |
|
2545 nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner; |
|
2546 parentItem->GetTreeOwner(getter_AddRefs(parentTreeOwner)); |
|
2547 if (!parentTreeOwner) { |
|
2548 return; |
|
2549 } |
|
2550 |
|
2551 nsAutoString value; |
|
2552 aElement->GetAttr(kNameSpaceID_None, TypeAttrName(), value); |
|
2553 |
|
2554 bool is_primary = value.LowerCaseEqualsLiteral("content-primary"); |
|
2555 |
|
2556 #ifdef MOZ_XUL |
|
2557 // when a content panel is no longer primary, hide any open popups it may have |
|
2558 if (!is_primary) { |
|
2559 nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); |
|
2560 if (pm) |
|
2561 pm->HidePopupsInDocShell(mDocShell); |
|
2562 } |
|
2563 #endif |
|
2564 |
|
2565 parentTreeOwner->ContentShellRemoved(mDocShell); |
|
2566 if (value.LowerCaseEqualsLiteral("content") || |
|
2567 StringBeginsWith(value, NS_LITERAL_STRING("content-"), |
|
2568 nsCaseInsensitiveStringComparator())) { |
|
2569 bool is_targetable = is_primary || |
|
2570 value.LowerCaseEqualsLiteral("content-targetable"); |
|
2571 |
|
2572 parentTreeOwner->ContentShellAdded(mDocShell, is_primary, |
|
2573 is_targetable, value); |
|
2574 } |
|
2575 } |
|
2576 |
|
2577 void |
|
2578 nsFrameLoader::ResetPermissionManagerStatus() |
|
2579 { |
|
2580 // The resetting of the permissions status can run only |
|
2581 // in the main process. |
|
2582 if (XRE_GetProcessType() == GeckoProcessType_Content) { |
|
2583 return; |
|
2584 } |
|
2585 |
|
2586 // Finding the new app Id: |
|
2587 // . first we check if the owner is an app frame |
|
2588 // . second, we check if the owner is a browser frame |
|
2589 // in both cases we populate the appId variable. |
|
2590 uint32_t appId = nsIScriptSecurityManager::NO_APP_ID; |
|
2591 if (OwnerIsAppFrame()) { |
|
2592 // You can't be both an app and a browser frame. |
|
2593 MOZ_ASSERT(!OwnerIsBrowserFrame()); |
|
2594 |
|
2595 nsCOMPtr<mozIApplication> ownApp = GetOwnApp(); |
|
2596 MOZ_ASSERT(ownApp); |
|
2597 uint32_t ownAppId = nsIScriptSecurityManager::NO_APP_ID; |
|
2598 if (ownApp && NS_SUCCEEDED(ownApp->GetLocalId(&ownAppId))) { |
|
2599 appId = ownAppId; |
|
2600 } |
|
2601 } |
|
2602 |
|
2603 if (OwnerIsBrowserFrame()) { |
|
2604 // You can't be both a browser and an app frame. |
|
2605 MOZ_ASSERT(!OwnerIsAppFrame()); |
|
2606 |
|
2607 nsCOMPtr<mozIApplication> containingApp = GetContainingApp(); |
|
2608 uint32_t containingAppId = nsIScriptSecurityManager::NO_APP_ID; |
|
2609 if (containingApp && NS_SUCCEEDED(containingApp->GetLocalId(&containingAppId))) { |
|
2610 appId = containingAppId; |
|
2611 } |
|
2612 } |
|
2613 |
|
2614 // Nothing changed. |
|
2615 if (appId == mAppIdSentToPermissionManager) { |
|
2616 return; |
|
2617 } |
|
2618 |
|
2619 nsCOMPtr<nsIPermissionManager> permMgr = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); |
|
2620 if (!permMgr) { |
|
2621 NS_ERROR("No PermissionManager available!"); |
|
2622 return; |
|
2623 } |
|
2624 |
|
2625 // If previously we registered an appId, we have to unregister it. |
|
2626 if (mAppIdSentToPermissionManager != nsIScriptSecurityManager::NO_APP_ID) { |
|
2627 permMgr->ReleaseAppId(mAppIdSentToPermissionManager); |
|
2628 mAppIdSentToPermissionManager = nsIScriptSecurityManager::NO_APP_ID; |
|
2629 } |
|
2630 |
|
2631 // Register the new AppId. |
|
2632 if (appId != nsIScriptSecurityManager::NO_APP_ID) { |
|
2633 mAppIdSentToPermissionManager = appId; |
|
2634 permMgr->AddrefAppId(mAppIdSentToPermissionManager); |
|
2635 } |
|
2636 } |
|
2637 |
|
2638 /* [infallible] */ NS_IMETHODIMP |
|
2639 nsFrameLoader::SetVisible(bool aVisible) |
|
2640 { |
|
2641 if (mVisible == aVisible) { |
|
2642 return NS_OK; |
|
2643 } |
|
2644 |
|
2645 mVisible = aVisible; |
|
2646 nsCOMPtr<nsIObserverService> os = services::GetObserverService(); |
|
2647 if (os) { |
|
2648 os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this), |
|
2649 "frameloader-visible-changed", nullptr); |
|
2650 } |
|
2651 return NS_OK; |
|
2652 } |
|
2653 |
|
2654 /* [infallible] */ NS_IMETHODIMP |
|
2655 nsFrameLoader::GetVisible(bool* aVisible) |
|
2656 { |
|
2657 *aVisible = mVisible; |
|
2658 return NS_OK; |
|
2659 } |
|
2660 |
|
2661 NS_IMETHODIMP |
|
2662 nsFrameLoader::GetTabParent(nsITabParent** aTabParent) |
|
2663 { |
|
2664 nsCOMPtr<nsITabParent> tp = mRemoteBrowser; |
|
2665 tp.forget(aTabParent); |
|
2666 return NS_OK; |
|
2667 } |
|
2668 |
|
2669 NS_IMETHODIMP |
|
2670 nsFrameLoader::GetLoadContext(nsILoadContext** aLoadContext) |
|
2671 { |
|
2672 nsCOMPtr<nsILoadContext> loadContext; |
|
2673 if (mRemoteBrowser) { |
|
2674 loadContext = mRemoteBrowser->GetLoadContext(); |
|
2675 } else { |
|
2676 nsCOMPtr<nsIDocShell> docShell; |
|
2677 GetDocShell(getter_AddRefs(docShell)); |
|
2678 loadContext = do_GetInterface(docShell); |
|
2679 } |
|
2680 loadContext.forget(aLoadContext); |
|
2681 return NS_OK; |
|
2682 } |