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 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Mozilla Communicator client code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Netscape Communications Corporation.
20 : * Portions created by the Initial Developer are Copyright (C) 1998
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Johnny Stenback <jst@netscape.com> (original author)
25 : * Boris Zbarsky <bzbarsky@mit.edu>
26 : * Frederic Plourde <frederic.plourde@polymtl.ca>
27 : *
28 : * Alternatively, the contents of this file may be used under the terms of
29 : * either of the GNU General Public License Version 2 or later (the "GPL"),
30 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 : * in which case the provisions of the GPL or the LGPL are applicable instead
32 : * of those above. If you wish to allow use of your version of this file only
33 : * under the terms of either the GPL or the LGPL, and not to allow others to
34 : * use your version of this file under the terms of the MPL, indicate your
35 : * decision by deleting the provisions above and replace them with the notice
36 : * and other provisions required by the GPL or the LGPL. If you do not delete
37 : * the provisions above, a recipient may use your version of this file under
38 : * the terms of any one of the MPL, the GPL or the LGPL.
39 : *
40 : * ***** END LICENSE BLOCK ***** */
41 :
42 : /*
43 : * Class for managing loading of a subframe (creation of the docshell,
44 : * handling of loads in it, recursion-checking).
45 : */
46 :
47 : #include "base/basictypes.h"
48 :
49 : #include "prenv.h"
50 :
51 : #include "nsIDOMHTMLIFrameElement.h"
52 : #include "nsIDOMHTMLFrameElement.h"
53 : #include "nsIDOMWindow.h"
54 : #include "nsIPresShell.h"
55 : #include "nsIContent.h"
56 : #include "nsIContentViewer.h"
57 : #include "nsIDocument.h"
58 : #include "nsIDOMDocument.h"
59 : #include "nsIDOMWindow.h"
60 : #include "nsPIDOMWindow.h"
61 : #include "nsIWebNavigation.h"
62 : #include "nsIWebProgress.h"
63 : #include "nsIDocShell.h"
64 : #include "nsIDocShellTreeItem.h"
65 : #include "nsIDocShellTreeNode.h"
66 : #include "nsIDocShellTreeOwner.h"
67 : #include "nsIDocShellLoadInfo.h"
68 : #include "nsIBaseWindow.h"
69 : #include "nsContentUtils.h"
70 : #include "nsIXPConnect.h"
71 : #include "nsIJSContextStack.h"
72 : #include "nsUnicharUtils.h"
73 : #include "nsIScriptGlobalObject.h"
74 : #include "nsIScriptSecurityManager.h"
75 : #include "nsIScrollable.h"
76 : #include "nsFrameLoader.h"
77 : #include "nsIDOMEventTarget.h"
78 : #include "nsIFrame.h"
79 : #include "nsIScrollableFrame.h"
80 : #include "nsSubDocumentFrame.h"
81 : #include "nsDOMError.h"
82 : #include "nsGUIEvent.h"
83 : #include "nsEventDispatcher.h"
84 : #include "nsISHistory.h"
85 : #include "nsISHistoryInternal.h"
86 : #include "nsIDocShellHistory.h"
87 : #include "nsIDOMHTMLDocument.h"
88 : #include "nsIXULWindow.h"
89 : #include "nsIEditor.h"
90 : #include "nsIEditorDocShell.h"
91 : #include "nsIMozBrowserFrame.h"
92 :
93 : #include "nsLayoutUtils.h"
94 : #include "nsIView.h"
95 : #include "nsAsyncDOMEvent.h"
96 :
97 : #include "nsIURI.h"
98 : #include "nsIURL.h"
99 : #include "nsNetUtil.h"
100 :
101 : #include "nsGkAtoms.h"
102 : #include "nsINameSpaceManager.h"
103 :
104 : #include "nsThreadUtils.h"
105 : #include "nsIContentViewer.h"
106 : #include "nsIView.h"
107 :
108 : #include "nsIDOMChromeWindow.h"
109 : #include "nsInProcessTabChildGlobal.h"
110 :
111 : #include "Layers.h"
112 :
113 : #include "ContentParent.h"
114 : #include "TabParent.h"
115 : #include "mozilla/GuardObjects.h"
116 : #include "mozilla/Preferences.h"
117 : #include "mozilla/unused.h"
118 : #include "mozilla/dom/Element.h"
119 : #include "mozilla/layout/RenderFrameParent.h"
120 :
121 : #include "jsapi.h"
122 :
123 : using namespace mozilla;
124 : using namespace mozilla::dom;
125 : using namespace mozilla::layers;
126 : using namespace mozilla::layout;
127 : typedef FrameMetrics::ViewID ViewID;
128 :
129 : class nsAsyncDocShellDestroyer : public nsRunnable
130 0 : {
131 : public:
132 0 : nsAsyncDocShellDestroyer(nsIDocShell* aDocShell)
133 0 : : mDocShell(aDocShell)
134 : {
135 0 : }
136 :
137 0 : NS_IMETHOD Run()
138 : {
139 0 : nsCOMPtr<nsIBaseWindow> base_win(do_QueryInterface(mDocShell));
140 0 : if (base_win) {
141 0 : base_win->Destroy();
142 : }
143 0 : return NS_OK;
144 : }
145 : nsRefPtr<nsIDocShell> mDocShell;
146 : };
147 :
148 0 : static void InvalidateFrame(nsIFrame* aFrame, PRUint32 aFlags)
149 : {
150 0 : if (!aFrame)
151 0 : return;
152 0 : nsRect rect = nsRect(nsPoint(0, 0), aFrame->GetRect().Size());
153 0 : aFrame->InvalidateWithFlags(rect, aFlags);
154 : }
155 :
156 0 : NS_IMPL_ISUPPORTS1(nsContentView, nsIContentView)
157 :
158 : bool
159 0 : nsContentView::IsRoot() const
160 : {
161 0 : return mScrollId == FrameMetrics::ROOT_SCROLL_ID;
162 : }
163 :
164 : nsresult
165 0 : nsContentView::Update(const ViewConfig& aConfig)
166 : {
167 0 : if (aConfig == mConfig) {
168 0 : return NS_OK;
169 : }
170 0 : mConfig = aConfig;
171 :
172 : // View changed. Try to locate our subdoc frame and invalidate
173 : // it if found.
174 0 : if (!mFrameLoader) {
175 0 : if (IsRoot()) {
176 : // Oops, don't have a frame right now. That's OK; the view
177 : // config persists and will apply to the next frame we get, if we
178 : // ever get one.
179 0 : return NS_OK;
180 : } else {
181 : // This view is no longer valid.
182 0 : return NS_ERROR_NOT_AVAILABLE;
183 : }
184 : }
185 :
186 0 : if (RenderFrameParent* rfp = mFrameLoader->GetCurrentRemoteFrame()) {
187 0 : rfp->ContentViewScaleChanged(this);
188 : }
189 :
190 : // XXX could be clever here and compute a smaller invalidation
191 : // rect
192 : // NB: we pass INVALIDATE_NO_THEBES_LAYERS here to keep view
193 : // semantics the same for both in-process and out-of-process
194 : // <browser>. This is just a transform of the layer subtree in
195 : // both.
196 0 : InvalidateFrame(mFrameLoader->GetPrimaryFrameOfOwningContent(), nsIFrame::INVALIDATE_NO_THEBES_LAYERS);
197 0 : return NS_OK;
198 : }
199 :
200 : NS_IMETHODIMP
201 0 : nsContentView::ScrollTo(float aXpx, float aYpx)
202 : {
203 0 : ViewConfig config(mConfig);
204 : config.mScrollOffset = nsPoint(nsPresContext::CSSPixelsToAppUnits(aXpx),
205 0 : nsPresContext::CSSPixelsToAppUnits(aYpx));
206 0 : return Update(config);
207 : }
208 :
209 : NS_IMETHODIMP
210 0 : nsContentView::ScrollBy(float aDXpx, float aDYpx)
211 : {
212 0 : ViewConfig config(mConfig);
213 : config.mScrollOffset.MoveBy(nsPresContext::CSSPixelsToAppUnits(aDXpx),
214 0 : nsPresContext::CSSPixelsToAppUnits(aDYpx));
215 0 : return Update(config);
216 : }
217 :
218 : NS_IMETHODIMP
219 0 : nsContentView::SetScale(float aXScale, float aYScale)
220 : {
221 0 : ViewConfig config(mConfig);
222 0 : config.mXScale = aXScale;
223 0 : config.mYScale = aYScale;
224 0 : return Update(config);
225 : }
226 :
227 : NS_IMETHODIMP
228 0 : nsContentView::GetScrollX(float* aViewScrollX)
229 : {
230 : *aViewScrollX = nsPresContext::AppUnitsToFloatCSSPixels(
231 0 : mConfig.mScrollOffset.x);
232 0 : return NS_OK;
233 : }
234 :
235 : NS_IMETHODIMP
236 0 : nsContentView::GetScrollY(float* aViewScrollY)
237 : {
238 : *aViewScrollY = nsPresContext::AppUnitsToFloatCSSPixels(
239 0 : mConfig.mScrollOffset.y);
240 0 : return NS_OK;
241 : }
242 :
243 : NS_IMETHODIMP
244 0 : nsContentView::GetViewportWidth(float* aWidth)
245 : {
246 0 : *aWidth = nsPresContext::AppUnitsToFloatCSSPixels(mViewportSize.width);
247 0 : return NS_OK;
248 : }
249 :
250 : NS_IMETHODIMP
251 0 : nsContentView::GetViewportHeight(float* aHeight)
252 : {
253 0 : *aHeight = nsPresContext::AppUnitsToFloatCSSPixels(mViewportSize.height);
254 0 : return NS_OK;
255 : }
256 :
257 : NS_IMETHODIMP
258 0 : nsContentView::GetContentWidth(float* aWidth)
259 : {
260 0 : *aWidth = nsPresContext::AppUnitsToFloatCSSPixels(mContentSize.width);
261 0 : return NS_OK;
262 : }
263 :
264 : NS_IMETHODIMP
265 0 : nsContentView::GetContentHeight(float* aHeight)
266 : {
267 0 : *aHeight = nsPresContext::AppUnitsToFloatCSSPixels(mContentSize.height);
268 0 : return NS_OK;
269 : }
270 :
271 : NS_IMETHODIMP
272 0 : nsContentView::GetId(nsContentViewId* aId)
273 : {
274 : NS_ASSERTION(sizeof(nsContentViewId) == sizeof(ViewID),
275 : "ID size for XPCOM ID and internal ID type are not the same!");
276 0 : *aId = mScrollId;
277 0 : return NS_OK;
278 : }
279 :
280 : // Bug 136580: Limit to the number of nested content frames that can have the
281 : // same URL. This is to stop content that is recursively loading
282 : // itself. Note that "#foo" on the end of URL doesn't affect
283 : // whether it's considered identical, but "?foo" or ";foo" are
284 : // considered and compared.
285 : // Bug 228829: Limit this to 1, like IE does.
286 : #define MAX_SAME_URL_CONTENT_FRAMES 1
287 :
288 : // Bug 8065: Limit content frame depth to some reasonable level. This
289 : // does not count chrome frames when determining depth, nor does it
290 : // prevent chrome recursion. Number is fairly arbitrary, but meant to
291 : // keep number of shells to a reasonable number on accidental recursion with a
292 : // small (but not 1) branching factor. With large branching factors the number
293 : // of shells can rapidly become huge and run us out of memory. To solve that,
294 : // we'd need to re-institute a fixed version of bug 98158.
295 : #define MAX_DEPTH_CONTENT_FRAMES 10
296 :
297 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsFrameLoader)
298 :
299 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsFrameLoader)
300 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocShell)
301 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mMessageManager)
302 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mChildMessageManager)
303 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
304 :
305 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFrameLoader)
306 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocShell)
307 0 : NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "nsFrameLoader::mMessageManager");
308 0 : cb.NoteXPCOMChild(static_cast<nsIContentFrameMessageManager*>(tmp->mMessageManager.get()));
309 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChildMessageManager)
310 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
311 :
312 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFrameLoader)
313 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFrameLoader)
314 :
315 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFrameLoader)
316 0 : NS_INTERFACE_MAP_ENTRY(nsIFrameLoader)
317 0 : NS_INTERFACE_MAP_ENTRY(nsIContentViewManager)
318 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIFrameLoader)
319 0 : NS_INTERFACE_MAP_END
320 :
321 0 : nsFrameLoader::nsFrameLoader(Element* aOwner, bool aNetworkCreated)
322 : : mOwnerContent(aOwner)
323 : , mDepthTooGreat(false)
324 : , mIsTopLevelContent(false)
325 : , mDestroyCalled(false)
326 : , mNeedsAsyncDestroy(false)
327 : , mInSwap(false)
328 : , mInShow(false)
329 : , mHideCalled(false)
330 : , mNetworkCreated(aNetworkCreated)
331 : , mDelayRemoteDialogs(false)
332 : , mRemoteBrowserShown(false)
333 : , mRemoteFrame(false)
334 : , mClipSubdocument(true)
335 : , mClampScrollPosition(true)
336 : , mCurrentRemoteFrame(nsnull)
337 : , mRemoteBrowser(nsnull)
338 : , mRenderMode(RENDER_MODE_DEFAULT)
339 0 : , mEventMode(EVENT_MODE_NORMAL_DISPATCH)
340 : {
341 0 : }
342 :
343 : nsFrameLoader*
344 0 : nsFrameLoader::Create(Element* aOwner, bool aNetworkCreated)
345 : {
346 0 : NS_ENSURE_TRUE(aOwner, nsnull);
347 0 : nsIDocument* doc = aOwner->OwnerDoc();
348 0 : NS_ENSURE_TRUE(!doc->GetDisplayDocument() &&
349 : ((!doc->IsLoadedAsData() && aOwner->GetCurrentDoc()) ||
350 : doc->IsStaticDocument()),
351 : nsnull);
352 :
353 0 : return new nsFrameLoader(aOwner, aNetworkCreated);
354 : }
355 :
356 : NS_IMETHODIMP
357 0 : nsFrameLoader::LoadFrame()
358 : {
359 0 : NS_ENSURE_TRUE(mOwnerContent, NS_ERROR_NOT_INITIALIZED);
360 :
361 0 : nsAutoString src;
362 0 : GetURL(src);
363 :
364 0 : src.Trim(" \t\n\r");
365 :
366 0 : if (src.IsEmpty()) {
367 0 : src.AssignLiteral("about:blank");
368 : }
369 :
370 0 : nsIDocument* doc = mOwnerContent->OwnerDoc();
371 0 : if (doc->IsStaticDocument()) {
372 0 : return NS_OK;
373 : }
374 :
375 0 : nsCOMPtr<nsIURI> base_uri = mOwnerContent->GetBaseURI();
376 0 : const nsAFlatCString &doc_charset = doc->GetDocumentCharacterSet();
377 0 : const char *charset = doc_charset.IsEmpty() ? nsnull : doc_charset.get();
378 :
379 0 : nsCOMPtr<nsIURI> uri;
380 0 : nsresult rv = NS_NewURI(getter_AddRefs(uri), src, charset, base_uri);
381 :
382 : // If the URI was malformed, try to recover by loading about:blank.
383 0 : if (rv == NS_ERROR_MALFORMED_URI) {
384 0 : rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_STRING("about:blank"),
385 0 : charset, base_uri);
386 : }
387 :
388 0 : if (NS_SUCCEEDED(rv)) {
389 0 : rv = LoadURI(uri);
390 : }
391 :
392 0 : if (NS_FAILED(rv)) {
393 0 : FireErrorEvent();
394 :
395 0 : return rv;
396 : }
397 :
398 0 : return NS_OK;
399 : }
400 :
401 : void
402 0 : nsFrameLoader::FireErrorEvent()
403 : {
404 0 : if (mOwnerContent) {
405 : nsRefPtr<nsAsyncDOMEvent> event =
406 0 : new nsLoadBlockingAsyncDOMEvent(mOwnerContent, NS_LITERAL_STRING("error"),
407 0 : false, false);
408 0 : event->PostDOMEvent();
409 : }
410 0 : }
411 :
412 : NS_IMETHODIMP
413 0 : nsFrameLoader::LoadURI(nsIURI* aURI)
414 : {
415 0 : if (!aURI)
416 0 : return NS_ERROR_INVALID_POINTER;
417 0 : NS_ENSURE_STATE(!mDestroyCalled && mOwnerContent);
418 :
419 0 : nsCOMPtr<nsIDocument> doc = mOwnerContent->OwnerDoc();
420 :
421 0 : nsresult rv = CheckURILoad(aURI);
422 0 : NS_ENSURE_SUCCESS(rv, rv);
423 :
424 0 : mURIToLoad = aURI;
425 0 : rv = doc->InitializeFrameLoader(this);
426 0 : if (NS_FAILED(rv)) {
427 0 : mURIToLoad = nsnull;
428 : }
429 0 : return rv;
430 : }
431 :
432 : nsresult
433 0 : nsFrameLoader::ReallyStartLoading()
434 : {
435 0 : nsresult rv = ReallyStartLoadingInternal();
436 0 : if (NS_FAILED(rv)) {
437 0 : FireErrorEvent();
438 : }
439 :
440 0 : return rv;
441 : }
442 :
443 : nsresult
444 0 : nsFrameLoader::ReallyStartLoadingInternal()
445 : {
446 0 : NS_ENSURE_STATE(mURIToLoad && mOwnerContent && mOwnerContent->IsInDoc());
447 :
448 0 : nsresult rv = MaybeCreateDocShell();
449 0 : if (NS_FAILED(rv)) {
450 0 : return rv;
451 : }
452 :
453 0 : if (mRemoteFrame) {
454 0 : if (!mRemoteBrowser) {
455 0 : TryRemoteBrowser();
456 :
457 0 : if (!mRemoteBrowser) {
458 0 : NS_WARNING("Couldn't create child process for iframe.");
459 0 : return NS_ERROR_FAILURE;
460 : }
461 : }
462 :
463 : // FIXME get error codes from child
464 0 : mRemoteBrowser->LoadURL(mURIToLoad);
465 0 : return NS_OK;
466 : }
467 :
468 0 : NS_ASSERTION(mDocShell,
469 : "MaybeCreateDocShell succeeded with a null mDocShell");
470 :
471 : // Just to be safe, recheck uri.
472 0 : rv = CheckURILoad(mURIToLoad);
473 0 : NS_ENSURE_SUCCESS(rv, rv);
474 :
475 0 : nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
476 0 : mDocShell->CreateLoadInfo(getter_AddRefs(loadInfo));
477 0 : NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE);
478 :
479 : // We'll use our principal, not that of the document loaded inside us. This
480 : // is very important; needed to prevent XSS attacks on documents loaded in
481 : // subframes!
482 0 : loadInfo->SetOwner(mOwnerContent->NodePrincipal());
483 :
484 0 : nsCOMPtr<nsIURI> referrer;
485 0 : rv = mOwnerContent->NodePrincipal()->GetURI(getter_AddRefs(referrer));
486 0 : NS_ENSURE_SUCCESS(rv, rv);
487 :
488 0 : loadInfo->SetReferrer(referrer);
489 :
490 : // Kick off the load...
491 0 : bool tmpState = mNeedsAsyncDestroy;
492 0 : mNeedsAsyncDestroy = true;
493 0 : rv = mDocShell->LoadURI(mURIToLoad, loadInfo,
494 0 : nsIWebNavigation::LOAD_FLAGS_NONE, false);
495 0 : mNeedsAsyncDestroy = tmpState;
496 0 : mURIToLoad = nsnull;
497 0 : NS_ENSURE_SUCCESS(rv, rv);
498 :
499 0 : return NS_OK;
500 : }
501 :
502 : nsresult
503 0 : nsFrameLoader::CheckURILoad(nsIURI* aURI)
504 : {
505 : // Check for security. The fun part is trying to figure out what principals
506 : // to use. The way I figure it, if we're doing a LoadFrame() accidentally
507 : // (eg someone created a frame/iframe node, we're being parsed, XUL iframes
508 : // are being reframed, etc.) then we definitely want to use the node
509 : // principal of mOwnerContent for security checks. If, on the other hand,
510 : // someone's setting the src on our owner content, or created it via script,
511 : // or whatever, then they can clearly access it... and we should still use
512 : // the principal of mOwnerContent. I don't think that leads to privilege
513 : // escalation, and it's reasonably guaranteed to not lead to XSS issues
514 : // (since caller can already access mOwnerContent in this case). So just use
515 : // the principal of mOwnerContent no matter what. If script wants to run
516 : // things with its own permissions, which differ from those of mOwnerContent
517 : // (which means the script is privileged in some way) it should set
518 : // window.location instead.
519 0 : nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
520 :
521 : // Get our principal
522 0 : nsIPrincipal* principal = mOwnerContent->NodePrincipal();
523 :
524 : // Check if we are allowed to load absURL
525 : nsresult rv =
526 : secMan->CheckLoadURIWithPrincipal(principal, aURI,
527 0 : nsIScriptSecurityManager::STANDARD);
528 0 : if (NS_FAILED(rv)) {
529 0 : return rv; // We're not
530 : }
531 :
532 : // Bail out if this is an infinite recursion scenario
533 0 : rv = MaybeCreateDocShell();
534 0 : if (NS_FAILED(rv)) {
535 0 : return rv;
536 : }
537 0 : if (mRemoteFrame) {
538 0 : return NS_OK;
539 : }
540 0 : return CheckForRecursiveLoad(aURI);
541 : }
542 :
543 : NS_IMETHODIMP
544 0 : nsFrameLoader::GetDocShell(nsIDocShell **aDocShell)
545 : {
546 0 : *aDocShell = nsnull;
547 0 : nsresult rv = NS_OK;
548 :
549 : // If we have an owner, make sure we have a docshell and return
550 : // that. If not, we're most likely in the middle of being torn down,
551 : // then we just return null.
552 0 : if (mOwnerContent) {
553 0 : nsresult rv = MaybeCreateDocShell();
554 0 : if (NS_FAILED(rv))
555 0 : return rv;
556 0 : if (mRemoteFrame) {
557 0 : NS_WARNING("No docshells for remote frames!");
558 0 : return rv;
559 : }
560 0 : NS_ASSERTION(mDocShell,
561 : "MaybeCreateDocShell succeeded, but null mDocShell");
562 : }
563 :
564 0 : *aDocShell = mDocShell;
565 0 : NS_IF_ADDREF(*aDocShell);
566 :
567 0 : return rv;
568 : }
569 :
570 : void
571 0 : nsFrameLoader::Finalize()
572 : {
573 0 : nsCOMPtr<nsIBaseWindow> base_win(do_QueryInterface(mDocShell));
574 0 : if (base_win) {
575 0 : base_win->Destroy();
576 : }
577 0 : mDocShell = nsnull;
578 0 : }
579 :
580 : static void
581 0 : FirePageHideEvent(nsIDocShellTreeItem* aItem,
582 : nsIDOMEventTarget* aChromeEventHandler)
583 : {
584 0 : nsCOMPtr<nsIDOMDocument> doc = do_GetInterface(aItem);
585 0 : nsCOMPtr<nsIDocument> internalDoc = do_QueryInterface(doc);
586 0 : NS_ASSERTION(internalDoc, "What happened here?");
587 0 : internalDoc->OnPageHide(true, aChromeEventHandler);
588 :
589 0 : PRInt32 childCount = 0;
590 0 : aItem->GetChildCount(&childCount);
591 0 : nsAutoTArray<nsCOMPtr<nsIDocShellTreeItem>, 8> kids;
592 0 : kids.AppendElements(childCount);
593 0 : for (PRInt32 i = 0; i < childCount; ++i) {
594 0 : aItem->GetChildAt(i, getter_AddRefs(kids[i]));
595 : }
596 :
597 0 : for (PRUint32 i = 0; i < kids.Length(); ++i) {
598 0 : if (kids[i]) {
599 0 : FirePageHideEvent(kids[i], aChromeEventHandler);
600 : }
601 : }
602 0 : }
603 :
604 : // The pageshow event is fired for a given document only if IsShowing() returns
605 : // the same thing as aFireIfShowing. This gives us a way to fire pageshow only
606 : // on documents that are still loading or only on documents that are already
607 : // loaded.
608 : static void
609 0 : FirePageShowEvent(nsIDocShellTreeItem* aItem,
610 : nsIDOMEventTarget* aChromeEventHandler,
611 : bool aFireIfShowing)
612 : {
613 0 : PRInt32 childCount = 0;
614 0 : aItem->GetChildCount(&childCount);
615 0 : nsAutoTArray<nsCOMPtr<nsIDocShellTreeItem>, 8> kids;
616 0 : kids.AppendElements(childCount);
617 0 : for (PRInt32 i = 0; i < childCount; ++i) {
618 0 : aItem->GetChildAt(i, getter_AddRefs(kids[i]));
619 : }
620 :
621 0 : for (PRUint32 i = 0; i < kids.Length(); ++i) {
622 0 : if (kids[i]) {
623 0 : FirePageShowEvent(kids[i], aChromeEventHandler, aFireIfShowing);
624 : }
625 : }
626 :
627 0 : nsCOMPtr<nsIDOMDocument> doc = do_GetInterface(aItem);
628 0 : nsCOMPtr<nsIDocument> internalDoc = do_QueryInterface(doc);
629 0 : NS_ASSERTION(internalDoc, "What happened here?");
630 0 : if (internalDoc->IsShowing() == aFireIfShowing) {
631 0 : internalDoc->OnPageShow(true, aChromeEventHandler);
632 : }
633 0 : }
634 :
635 : static void
636 0 : SetTreeOwnerAndChromeEventHandlerOnDocshellTree(nsIDocShellTreeItem* aItem,
637 : nsIDocShellTreeOwner* aOwner,
638 : nsIDOMEventTarget* aHandler)
639 : {
640 0 : NS_PRECONDITION(aItem, "Must have item");
641 :
642 0 : aItem->SetTreeOwner(aOwner);
643 0 : nsCOMPtr<nsIDocShell> shell(do_QueryInterface(aItem));
644 0 : shell->SetChromeEventHandler(aHandler);
645 :
646 0 : PRInt32 childCount = 0;
647 0 : aItem->GetChildCount(&childCount);
648 0 : for (PRInt32 i = 0; i < childCount; ++i) {
649 0 : nsCOMPtr<nsIDocShellTreeItem> item;
650 0 : aItem->GetChildAt(i, getter_AddRefs(item));
651 0 : SetTreeOwnerAndChromeEventHandlerOnDocshellTree(item, aOwner, aHandler);
652 : }
653 0 : }
654 :
655 : /**
656 : * Set the type of the treeitem and hook it up to the treeowner.
657 : * @param aItem the treeitem we're wrking working with
658 : * @param aOwningContent the content node that owns aItem
659 : * @param aTreeOwner the relevant treeowner; might be null
660 : * @param aParentType the nsIDocShellTreeItem::GetType of our parent docshell
661 : * @param aParentNode if non-null, the docshell we should be added as a child to
662 : *
663 : * @return whether aItem is top-level content
664 : */
665 : static bool
666 0 : AddTreeItemToTreeOwner(nsIDocShellTreeItem* aItem, nsIContent* aOwningContent,
667 : nsIDocShellTreeOwner* aOwner, PRInt32 aParentType,
668 : nsIDocShellTreeNode* aParentNode)
669 : {
670 0 : NS_PRECONDITION(aItem, "Must have docshell treeitem");
671 0 : NS_PRECONDITION(aOwningContent, "Must have owning content");
672 :
673 0 : nsAutoString value;
674 0 : bool isContent = false;
675 :
676 0 : if (aOwningContent->IsXUL()) {
677 0 : aOwningContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, value);
678 : }
679 :
680 : // we accept "content" and "content-xxx" values.
681 : // at time of writing, we expect "xxx" to be "primary" or "targetable", but
682 : // someday it might be an integer expressing priority or something else.
683 :
684 0 : isContent = value.LowerCaseEqualsLiteral("content") ||
685 0 : StringBeginsWith(value, NS_LITERAL_STRING("content-"),
686 0 : nsCaseInsensitiveStringComparator());
687 :
688 0 : if (isContent) {
689 : // The web shell's type is content.
690 :
691 0 : aItem->SetItemType(nsIDocShellTreeItem::typeContent);
692 : } else {
693 : // Inherit our type from our parent docshell. If it is
694 : // chrome, we'll be chrome. If it is content, we'll be
695 : // content.
696 :
697 0 : aItem->SetItemType(aParentType);
698 : }
699 :
700 : // Now that we have our type set, add ourselves to the parent, as needed.
701 0 : if (aParentNode) {
702 0 : aParentNode->AddChild(aItem);
703 : }
704 :
705 0 : bool retval = false;
706 0 : if (aParentType == nsIDocShellTreeItem::typeChrome && isContent) {
707 0 : retval = true;
708 :
709 0 : bool is_primary = value.LowerCaseEqualsLiteral("content-primary");
710 :
711 0 : if (aOwner) {
712 : bool is_targetable = is_primary ||
713 0 : value.LowerCaseEqualsLiteral("content-targetable");
714 0 : aOwner->ContentShellAdded(aItem, is_primary, is_targetable, value);
715 : }
716 : }
717 :
718 0 : return retval;
719 : }
720 :
721 : static bool
722 0 : AllDescendantsOfType(nsIDocShellTreeItem* aParentItem, PRInt32 aType)
723 : {
724 0 : PRInt32 childCount = 0;
725 0 : aParentItem->GetChildCount(&childCount);
726 :
727 0 : for (PRInt32 i = 0; i < childCount; ++i) {
728 0 : nsCOMPtr<nsIDocShellTreeItem> kid;
729 0 : aParentItem->GetChildAt(i, getter_AddRefs(kid));
730 :
731 : PRInt32 kidType;
732 0 : kid->GetItemType(&kidType);
733 0 : if (kidType != aType || !AllDescendantsOfType(kid, aType)) {
734 0 : return false;
735 : }
736 : }
737 :
738 0 : return true;
739 : }
740 :
741 : /**
742 : * A class that automatically sets mInShow to false when it goes
743 : * out of scope.
744 : */
745 : class NS_STACK_CLASS AutoResetInShow {
746 : private:
747 : nsFrameLoader* mFrameLoader;
748 : MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
749 : public:
750 0 : AutoResetInShow(nsFrameLoader* aFrameLoader MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
751 0 : : mFrameLoader(aFrameLoader)
752 : {
753 0 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
754 0 : }
755 0 : ~AutoResetInShow() { mFrameLoader->mInShow = false; }
756 : };
757 :
758 :
759 : bool
760 0 : nsFrameLoader::Show(PRInt32 marginWidth, PRInt32 marginHeight,
761 : PRInt32 scrollbarPrefX, PRInt32 scrollbarPrefY,
762 : nsSubDocumentFrame* frame)
763 : {
764 0 : if (mInShow) {
765 0 : return false;
766 : }
767 : // Reset mInShow if we exit early.
768 0 : AutoResetInShow resetInShow(this);
769 0 : mInShow = true;
770 :
771 0 : nsresult rv = MaybeCreateDocShell();
772 0 : if (NS_FAILED(rv)) {
773 0 : return false;
774 : }
775 :
776 0 : if (!mRemoteFrame) {
777 0 : if (!mDocShell)
778 0 : return false;
779 0 : nsCOMPtr<nsIPresShell> presShell;
780 0 : mDocShell->GetPresShell(getter_AddRefs(presShell));
781 0 : if (presShell)
782 0 : return true;
783 :
784 0 : mDocShell->SetMarginWidth(marginWidth);
785 0 : mDocShell->SetMarginHeight(marginHeight);
786 :
787 0 : nsCOMPtr<nsIScrollable> sc = do_QueryInterface(mDocShell);
788 0 : if (sc) {
789 0 : sc->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_X,
790 0 : scrollbarPrefX);
791 0 : sc->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_Y,
792 0 : scrollbarPrefY);
793 : }
794 : }
795 :
796 0 : nsIView* view = frame->EnsureInnerView();
797 0 : if (!view)
798 0 : return false;
799 :
800 0 : if (mRemoteFrame) {
801 0 : return ShowRemoteFrame(GetSubDocumentSize(frame));
802 : }
803 :
804 0 : nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(mDocShell);
805 0 : NS_ASSERTION(baseWindow, "Found a nsIDocShell that isn't a nsIBaseWindow.");
806 0 : nsIntSize size;
807 0 : if (!(frame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
808 : // We have a useful size already; use it, since we might get no
809 : // more size updates.
810 0 : size = GetSubDocumentSize(frame);
811 : } else {
812 : // Pick some default size for now. Using 10x10 because that's what the
813 : // code here used to do.
814 0 : size.SizeTo(10, 10);
815 : }
816 0 : baseWindow->InitWindow(nsnull, view->GetWidget(), 0, 0,
817 0 : size.width, size.height);
818 : // This is kinda whacky, this "Create()" call doesn't really
819 : // create anything, one starts to wonder why this was named
820 : // "Create"...
821 0 : baseWindow->Create();
822 0 : baseWindow->SetVisibility(true);
823 :
824 : // Trigger editor re-initialization if midas is turned on in the
825 : // sub-document. This shouldn't be necessary, but given the way our
826 : // editor works, it is. See
827 : // https://bugzilla.mozilla.org/show_bug.cgi?id=284245
828 0 : nsCOMPtr<nsIPresShell> presShell;
829 0 : mDocShell->GetPresShell(getter_AddRefs(presShell));
830 0 : if (presShell) {
831 : nsCOMPtr<nsIDOMHTMLDocument> doc =
832 0 : do_QueryInterface(presShell->GetDocument());
833 :
834 0 : if (doc) {
835 0 : nsAutoString designMode;
836 0 : doc->GetDesignMode(designMode);
837 :
838 0 : if (designMode.EqualsLiteral("on")) {
839 : // Hold on to the editor object to let the document reattach to the
840 : // same editor object, instead of creating a new one.
841 0 : nsCOMPtr<nsIEditorDocShell> editorDocshell = do_QueryInterface(mDocShell);
842 0 : nsCOMPtr<nsIEditor> editor;
843 0 : nsresult rv = editorDocshell->GetEditor(getter_AddRefs(editor));
844 0 : NS_ENSURE_SUCCESS(rv, false);
845 :
846 0 : doc->SetDesignMode(NS_LITERAL_STRING("off"));
847 0 : doc->SetDesignMode(NS_LITERAL_STRING("on"));
848 : } else {
849 : // Re-initialize the presentation for contenteditable documents
850 0 : nsCOMPtr<nsIEditorDocShell> editorDocshell = do_QueryInterface(mDocShell);
851 0 : if (editorDocshell) {
852 0 : bool editable = false,
853 0 : hasEditingSession = false;
854 0 : editorDocshell->GetEditable(&editable);
855 0 : editorDocshell->GetHasEditingSession(&hasEditingSession);
856 0 : nsCOMPtr<nsIEditor> editor;
857 0 : editorDocshell->GetEditor(getter_AddRefs(editor));
858 0 : if (editable && hasEditingSession && editor) {
859 0 : editor->PostCreate();
860 : }
861 : }
862 : }
863 : }
864 : }
865 :
866 0 : mInShow = false;
867 0 : if (mHideCalled) {
868 0 : mHideCalled = false;
869 0 : Hide();
870 0 : return false;
871 : }
872 0 : return true;
873 : }
874 :
875 : void
876 0 : nsFrameLoader::MarginsChanged(PRUint32 aMarginWidth,
877 : PRUint32 aMarginHeight)
878 : {
879 : // We assume that the margins are always zero for remote frames.
880 0 : if (mRemoteFrame)
881 0 : return;
882 :
883 : // If there's no docshell, we're probably not up and running yet.
884 : // nsFrameLoader::Show() will take care of setting the right
885 : // margins.
886 0 : if (!mDocShell)
887 0 : return;
888 :
889 : // Set the margins
890 0 : mDocShell->SetMarginWidth(aMarginWidth);
891 0 : mDocShell->SetMarginHeight(aMarginHeight);
892 :
893 : // Trigger a restyle if there's a prescontext
894 0 : nsRefPtr<nsPresContext> presContext;
895 0 : mDocShell->GetPresContext(getter_AddRefs(presContext));
896 0 : if (presContext)
897 0 : presContext->RebuildAllStyleData(nsChangeHint(0));
898 : }
899 :
900 : bool
901 0 : nsFrameLoader::ShowRemoteFrame(const nsIntSize& size)
902 : {
903 0 : NS_ASSERTION(mRemoteFrame, "ShowRemote only makes sense on remote frames.");
904 :
905 0 : if (!mRemoteBrowser) {
906 0 : TryRemoteBrowser();
907 :
908 0 : if (!mRemoteBrowser) {
909 0 : NS_ERROR("Couldn't create child process.");
910 0 : return false;
911 : }
912 : }
913 :
914 : // FIXME/bug 589337: Show()/Hide() is pretty expensive for
915 : // cross-process layers; need to figure out what behavior we really
916 : // want here. For now, hack.
917 0 : if (!mRemoteBrowserShown) {
918 0 : mRemoteBrowser->Show(size);
919 0 : mRemoteBrowserShown = true;
920 :
921 0 : EnsureMessageManager();
922 : } else {
923 0 : nsRect dimensions;
924 0 : NS_ENSURE_SUCCESS(GetWindowDimensions(dimensions), false);
925 0 : mRemoteBrowser->UpdateDimensions(dimensions, size);
926 : }
927 :
928 0 : return true;
929 : }
930 :
931 : void
932 0 : nsFrameLoader::Hide()
933 : {
934 0 : if (mHideCalled) {
935 0 : return;
936 : }
937 0 : if (mInShow) {
938 0 : mHideCalled = true;
939 0 : return;
940 : }
941 :
942 0 : if (!mDocShell)
943 0 : return;
944 :
945 0 : nsCOMPtr<nsIContentViewer> contentViewer;
946 0 : mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
947 0 : if (contentViewer)
948 0 : contentViewer->SetSticky(false);
949 :
950 0 : nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(mDocShell);
951 0 : NS_ASSERTION(baseWin,
952 : "Found an nsIDocShell which doesn't implement nsIBaseWindow.");
953 0 : baseWin->SetVisibility(false);
954 0 : baseWin->SetParentWidget(nsnull);
955 : }
956 :
957 : nsresult
958 0 : nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
959 : nsRefPtr<nsFrameLoader>& aFirstToSwap,
960 : nsRefPtr<nsFrameLoader>& aSecondToSwap)
961 : {
962 0 : NS_PRECONDITION((aFirstToSwap == this && aSecondToSwap == aOther) ||
963 : (aFirstToSwap == aOther && aSecondToSwap == this),
964 : "Swapping some sort of random loaders?");
965 0 : NS_ENSURE_STATE(!mInShow && !aOther->mInShow);
966 :
967 0 : Element* ourContent = mOwnerContent;
968 0 : Element* otherContent = aOther->mOwnerContent;
969 :
970 0 : if (!ourContent || !otherContent) {
971 : // Can't handle this
972 0 : return NS_ERROR_NOT_IMPLEMENTED;
973 : }
974 :
975 : // Make sure there are no same-origin issues
976 : bool equal;
977 : nsresult rv =
978 0 : ourContent->NodePrincipal()->Equals(otherContent->NodePrincipal(), &equal);
979 0 : if (NS_FAILED(rv) || !equal) {
980 : // Security problems loom. Just bail on it all
981 0 : return NS_ERROR_DOM_SECURITY_ERR;
982 : }
983 :
984 0 : nsCOMPtr<nsIDocShell> ourDocshell = GetExistingDocShell();
985 0 : nsCOMPtr<nsIDocShell> otherDocshell = aOther->GetExistingDocShell();
986 0 : if (!ourDocshell || !otherDocshell) {
987 : // How odd
988 0 : return NS_ERROR_NOT_IMPLEMENTED;
989 : }
990 :
991 : // To avoid having to mess with session history, avoid swapping
992 : // frameloaders that don't correspond to root same-type docshells,
993 : // unless both roots have session history disabled.
994 0 : nsCOMPtr<nsIDocShellTreeItem> ourTreeItem = do_QueryInterface(ourDocshell);
995 : nsCOMPtr<nsIDocShellTreeItem> otherTreeItem =
996 0 : do_QueryInterface(otherDocshell);
997 0 : nsCOMPtr<nsIDocShellTreeItem> ourRootTreeItem, otherRootTreeItem;
998 0 : ourTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(ourRootTreeItem));
999 0 : otherTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(otherRootTreeItem));
1000 : nsCOMPtr<nsIWebNavigation> ourRootWebnav =
1001 0 : do_QueryInterface(ourRootTreeItem);
1002 : nsCOMPtr<nsIWebNavigation> otherRootWebnav =
1003 0 : do_QueryInterface(otherRootTreeItem);
1004 :
1005 0 : if (!ourRootWebnav || !otherRootWebnav) {
1006 0 : return NS_ERROR_NOT_IMPLEMENTED;
1007 : }
1008 :
1009 0 : nsCOMPtr<nsISHistory> ourHistory;
1010 0 : nsCOMPtr<nsISHistory> otherHistory;
1011 0 : ourRootWebnav->GetSessionHistory(getter_AddRefs(ourHistory));
1012 0 : otherRootWebnav->GetSessionHistory(getter_AddRefs(otherHistory));
1013 :
1014 0 : if ((ourRootTreeItem != ourTreeItem || otherRootTreeItem != otherTreeItem) &&
1015 0 : (ourHistory || otherHistory)) {
1016 0 : return NS_ERROR_NOT_IMPLEMENTED;
1017 : }
1018 :
1019 : // Also make sure that the two docshells are the same type. Otherwise
1020 : // swapping is certainly not safe.
1021 0 : PRInt32 ourType = nsIDocShellTreeItem::typeChrome;
1022 0 : PRInt32 otherType = nsIDocShellTreeItem::typeChrome;
1023 0 : ourTreeItem->GetItemType(&ourType);
1024 0 : otherTreeItem->GetItemType(&otherType);
1025 0 : if (ourType != otherType) {
1026 0 : return NS_ERROR_NOT_IMPLEMENTED;
1027 : }
1028 :
1029 : // One more twist here. Setting up the right treeowners in a heterogeneous
1030 : // tree is a bit of a pain. So make sure that if ourType is not
1031 : // nsIDocShellTreeItem::typeContent then all of our descendants are the same
1032 : // type as us.
1033 0 : if (ourType != nsIDocShellTreeItem::typeContent &&
1034 0 : (!AllDescendantsOfType(ourTreeItem, ourType) ||
1035 0 : !AllDescendantsOfType(otherTreeItem, otherType))) {
1036 0 : return NS_ERROR_NOT_IMPLEMENTED;
1037 : }
1038 :
1039 : // Save off the tree owners, frame elements, chrome event handlers, and
1040 : // docshell and document parents before doing anything else.
1041 0 : nsCOMPtr<nsIDocShellTreeOwner> ourOwner, otherOwner;
1042 0 : ourTreeItem->GetTreeOwner(getter_AddRefs(ourOwner));
1043 0 : otherTreeItem->GetTreeOwner(getter_AddRefs(otherOwner));
1044 : // Note: it's OK to have null treeowners.
1045 :
1046 0 : nsCOMPtr<nsIDocShellTreeItem> ourParentItem, otherParentItem;
1047 0 : ourTreeItem->GetParent(getter_AddRefs(ourParentItem));
1048 0 : otherTreeItem->GetParent(getter_AddRefs(otherParentItem));
1049 0 : if (!ourParentItem || !otherParentItem) {
1050 0 : return NS_ERROR_NOT_IMPLEMENTED;
1051 : }
1052 :
1053 : // Make sure our parents are the same type too
1054 0 : PRInt32 ourParentType = nsIDocShellTreeItem::typeContent;
1055 0 : PRInt32 otherParentType = nsIDocShellTreeItem::typeContent;
1056 0 : ourParentItem->GetItemType(&ourParentType);
1057 0 : otherParentItem->GetItemType(&otherParentType);
1058 0 : if (ourParentType != otherParentType) {
1059 0 : return NS_ERROR_NOT_IMPLEMENTED;
1060 : }
1061 :
1062 0 : nsCOMPtr<nsPIDOMWindow> ourWindow = do_GetInterface(ourDocshell);
1063 0 : nsCOMPtr<nsPIDOMWindow> otherWindow = do_GetInterface(otherDocshell);
1064 :
1065 : nsCOMPtr<nsIDOMElement> ourFrameElement =
1066 0 : ourWindow->GetFrameElementInternal();
1067 : nsCOMPtr<nsIDOMElement> otherFrameElement =
1068 0 : otherWindow->GetFrameElementInternal();
1069 :
1070 : nsCOMPtr<nsIDOMEventTarget> ourChromeEventHandler =
1071 0 : do_QueryInterface(ourWindow->GetChromeEventHandler());
1072 : nsCOMPtr<nsIDOMEventTarget> otherChromeEventHandler =
1073 0 : do_QueryInterface(otherWindow->GetChromeEventHandler());
1074 :
1075 0 : NS_ASSERTION(SameCOMIdentity(ourFrameElement, ourContent) &&
1076 : SameCOMIdentity(otherFrameElement, otherContent) &&
1077 : SameCOMIdentity(ourChromeEventHandler, ourContent) &&
1078 : SameCOMIdentity(otherChromeEventHandler, otherContent),
1079 : "How did that happen, exactly?");
1080 :
1081 : nsCOMPtr<nsIDocument> ourChildDocument =
1082 0 : do_QueryInterface(ourWindow->GetExtantDocument());
1083 : nsCOMPtr<nsIDocument> otherChildDocument =
1084 0 : do_QueryInterface(otherWindow->GetExtantDocument());
1085 0 : if (!ourChildDocument || !otherChildDocument) {
1086 : // This shouldn't be happening
1087 0 : return NS_ERROR_NOT_IMPLEMENTED;
1088 : }
1089 :
1090 : nsCOMPtr<nsIDocument> ourParentDocument =
1091 0 : ourChildDocument->GetParentDocument();
1092 : nsCOMPtr<nsIDocument> otherParentDocument =
1093 0 : otherChildDocument->GetParentDocument();
1094 :
1095 : // Make sure to swap docshells between the two frames.
1096 0 : nsIDocument* ourDoc = ourContent->GetCurrentDoc();
1097 0 : nsIDocument* otherDoc = otherContent->GetCurrentDoc();
1098 0 : if (!ourDoc || !otherDoc) {
1099 : // Again, how odd, given that we had docshells
1100 0 : return NS_ERROR_NOT_IMPLEMENTED;
1101 : }
1102 :
1103 0 : NS_ASSERTION(ourDoc == ourParentDocument, "Unexpected parent document");
1104 0 : NS_ASSERTION(otherDoc == otherParentDocument, "Unexpected parent document");
1105 :
1106 0 : nsIPresShell* ourShell = ourDoc->GetShell();
1107 0 : nsIPresShell* otherShell = otherDoc->GetShell();
1108 0 : if (!ourShell || !otherShell) {
1109 0 : return NS_ERROR_NOT_IMPLEMENTED;
1110 : }
1111 :
1112 0 : bool weAreBrowserFrame = false;
1113 0 : bool otherIsBrowserFrame = false;
1114 0 : ourDocshell->GetIsBrowserFrame(&weAreBrowserFrame);
1115 0 : otherDocshell->GetIsBrowserFrame(&otherIsBrowserFrame);
1116 0 : if (weAreBrowserFrame != otherIsBrowserFrame) {
1117 0 : return NS_ERROR_NOT_IMPLEMENTED;
1118 : }
1119 :
1120 0 : if (mInSwap || aOther->mInSwap) {
1121 0 : return NS_ERROR_NOT_IMPLEMENTED;
1122 : }
1123 0 : mInSwap = aOther->mInSwap = true;
1124 :
1125 : // Fire pageshow events on still-loading pages, and then fire pagehide
1126 : // events. Note that we do NOT fire these in the normal way, but just fire
1127 : // them on the chrome event handlers.
1128 0 : FirePageShowEvent(ourTreeItem, ourChromeEventHandler, false);
1129 0 : FirePageShowEvent(otherTreeItem, otherChromeEventHandler, false);
1130 0 : FirePageHideEvent(ourTreeItem, ourChromeEventHandler);
1131 0 : FirePageHideEvent(otherTreeItem, otherChromeEventHandler);
1132 :
1133 0 : nsIFrame* ourFrame = ourContent->GetPrimaryFrame();
1134 0 : nsIFrame* otherFrame = otherContent->GetPrimaryFrame();
1135 0 : if (!ourFrame || !otherFrame) {
1136 0 : mInSwap = aOther->mInSwap = false;
1137 0 : FirePageShowEvent(ourTreeItem, ourChromeEventHandler, true);
1138 0 : FirePageShowEvent(otherTreeItem, otherChromeEventHandler, true);
1139 0 : return NS_ERROR_NOT_IMPLEMENTED;
1140 : }
1141 :
1142 0 : nsSubDocumentFrame* ourFrameFrame = do_QueryFrame(ourFrame);
1143 0 : if (!ourFrameFrame) {
1144 0 : mInSwap = aOther->mInSwap = false;
1145 0 : FirePageShowEvent(ourTreeItem, ourChromeEventHandler, true);
1146 0 : FirePageShowEvent(otherTreeItem, otherChromeEventHandler, true);
1147 0 : return NS_ERROR_NOT_IMPLEMENTED;
1148 : }
1149 :
1150 : // OK. First begin to swap the docshells in the two nsIFrames
1151 0 : rv = ourFrameFrame->BeginSwapDocShells(otherFrame);
1152 0 : if (NS_FAILED(rv)) {
1153 0 : mInSwap = aOther->mInSwap = false;
1154 0 : FirePageShowEvent(ourTreeItem, ourChromeEventHandler, true);
1155 0 : FirePageShowEvent(otherTreeItem, otherChromeEventHandler, true);
1156 0 : return rv;
1157 : }
1158 :
1159 : // Now move the docshells to the right docshell trees. Note that this
1160 : // resets their treeowners to null.
1161 0 : ourParentItem->RemoveChild(ourTreeItem);
1162 0 : otherParentItem->RemoveChild(otherTreeItem);
1163 0 : if (ourType == nsIDocShellTreeItem::typeContent) {
1164 0 : ourOwner->ContentShellRemoved(ourTreeItem);
1165 0 : otherOwner->ContentShellRemoved(otherTreeItem);
1166 : }
1167 :
1168 0 : ourParentItem->AddChild(otherTreeItem);
1169 0 : otherParentItem->AddChild(ourTreeItem);
1170 :
1171 : // Restore the correct treeowners
1172 : SetTreeOwnerAndChromeEventHandlerOnDocshellTree(ourTreeItem, otherOwner,
1173 0 : otherChromeEventHandler);
1174 : SetTreeOwnerAndChromeEventHandlerOnDocshellTree(otherTreeItem, ourOwner,
1175 0 : ourChromeEventHandler);
1176 :
1177 : AddTreeItemToTreeOwner(ourTreeItem, otherContent, otherOwner,
1178 0 : otherParentType, nsnull);
1179 : AddTreeItemToTreeOwner(otherTreeItem, ourContent, ourOwner, ourParentType,
1180 0 : nsnull);
1181 :
1182 : // SetSubDocumentFor nulls out parent documents on the old child doc if a
1183 : // new non-null document is passed in, so just go ahead and remove both
1184 : // kids before reinserting in the parent subdoc maps, to avoid
1185 : // complications.
1186 0 : ourParentDocument->SetSubDocumentFor(ourContent, nsnull);
1187 0 : otherParentDocument->SetSubDocumentFor(otherContent, nsnull);
1188 0 : ourParentDocument->SetSubDocumentFor(ourContent, otherChildDocument);
1189 0 : otherParentDocument->SetSubDocumentFor(otherContent, ourChildDocument);
1190 :
1191 0 : ourWindow->SetFrameElementInternal(otherFrameElement);
1192 0 : otherWindow->SetFrameElementInternal(ourFrameElement);
1193 :
1194 0 : SetOwnerContent(otherContent);
1195 0 : aOther->SetOwnerContent(ourContent);
1196 :
1197 0 : nsRefPtr<nsFrameMessageManager> ourMessageManager = mMessageManager;
1198 0 : nsRefPtr<nsFrameMessageManager> otherMessageManager = aOther->mMessageManager;
1199 : // Swap pointers in child message managers.
1200 0 : if (mChildMessageManager) {
1201 : nsInProcessTabChildGlobal* tabChild =
1202 0 : static_cast<nsInProcessTabChildGlobal*>(mChildMessageManager.get());
1203 0 : tabChild->SetOwner(otherContent);
1204 0 : tabChild->SetChromeMessageManager(otherMessageManager);
1205 : }
1206 0 : if (aOther->mChildMessageManager) {
1207 : nsInProcessTabChildGlobal* otherTabChild =
1208 0 : static_cast<nsInProcessTabChildGlobal*>(aOther->mChildMessageManager.get());
1209 0 : otherTabChild->SetOwner(ourContent);
1210 0 : otherTabChild->SetChromeMessageManager(ourMessageManager);
1211 : }
1212 : // Swap and setup things in parent message managers.
1213 : nsFrameMessageManager* ourParentManager = mMessageManager ?
1214 0 : mMessageManager->GetParentManager() : nsnull;
1215 : nsFrameMessageManager* otherParentManager = aOther->mMessageManager ?
1216 0 : aOther->mMessageManager->GetParentManager() : nsnull;
1217 : JSContext* thisCx =
1218 0 : mMessageManager ? mMessageManager->GetJSContext() : nsnull;
1219 : JSContext* otherCx =
1220 0 : aOther->mMessageManager ? aOther->mMessageManager->GetJSContext() : nsnull;
1221 0 : if (mMessageManager) {
1222 0 : mMessageManager->RemoveFromParent();
1223 0 : mMessageManager->SetJSContext(otherCx);
1224 0 : mMessageManager->SetParentManager(otherParentManager);
1225 0 : mMessageManager->SetCallbackData(aOther, false);
1226 : }
1227 0 : if (aOther->mMessageManager) {
1228 0 : aOther->mMessageManager->RemoveFromParent();
1229 0 : aOther->mMessageManager->SetJSContext(thisCx);
1230 0 : aOther->mMessageManager->SetParentManager(ourParentManager);
1231 0 : aOther->mMessageManager->SetCallbackData(this, false);
1232 : }
1233 0 : mMessageManager.swap(aOther->mMessageManager);
1234 :
1235 0 : aFirstToSwap.swap(aSecondToSwap);
1236 :
1237 : // Drop any cached content viewers in the two session histories.
1238 : nsCOMPtr<nsISHistoryInternal> ourInternalHistory =
1239 0 : do_QueryInterface(ourHistory);
1240 : nsCOMPtr<nsISHistoryInternal> otherInternalHistory =
1241 0 : do_QueryInterface(otherHistory);
1242 0 : if (ourInternalHistory) {
1243 0 : ourInternalHistory->EvictAllContentViewers();
1244 : }
1245 0 : if (otherInternalHistory) {
1246 0 : otherInternalHistory->EvictAllContentViewers();
1247 : }
1248 :
1249 0 : NS_ASSERTION(ourFrame == ourContent->GetPrimaryFrame() &&
1250 : otherFrame == otherContent->GetPrimaryFrame(),
1251 : "changed primary frame");
1252 :
1253 0 : ourFrameFrame->EndSwapDocShells(otherFrame);
1254 :
1255 0 : ourParentDocument->FlushPendingNotifications(Flush_Layout);
1256 0 : otherParentDocument->FlushPendingNotifications(Flush_Layout);
1257 :
1258 0 : FirePageShowEvent(ourTreeItem, otherChromeEventHandler, true);
1259 0 : FirePageShowEvent(otherTreeItem, ourChromeEventHandler, true);
1260 :
1261 0 : mInSwap = aOther->mInSwap = false;
1262 0 : return NS_OK;
1263 : }
1264 :
1265 : void
1266 0 : nsFrameLoader::DestroyChild()
1267 : {
1268 0 : if (mRemoteBrowser) {
1269 0 : mRemoteBrowser->SetOwnerElement(nsnull);
1270 0 : mRemoteBrowser->Destroy();
1271 0 : mRemoteBrowser = nsnull;
1272 : }
1273 0 : }
1274 :
1275 : NS_IMETHODIMP
1276 0 : nsFrameLoader::Destroy()
1277 : {
1278 0 : if (mDestroyCalled) {
1279 0 : return NS_OK;
1280 : }
1281 0 : mDestroyCalled = true;
1282 :
1283 0 : if (mMessageManager) {
1284 0 : mMessageManager->Disconnect();
1285 : }
1286 0 : if (mChildMessageManager) {
1287 0 : static_cast<nsInProcessTabChildGlobal*>(mChildMessageManager.get())->Disconnect();
1288 : }
1289 :
1290 0 : nsCOMPtr<nsIDocument> doc;
1291 0 : bool dynamicSubframeRemoval = false;
1292 0 : if (mOwnerContent) {
1293 0 : doc = mOwnerContent->OwnerDoc();
1294 0 : dynamicSubframeRemoval = !mIsTopLevelContent && !doc->InUnlinkOrDeletion();
1295 0 : doc->SetSubDocumentFor(mOwnerContent, nsnull);
1296 :
1297 0 : SetOwnerContent(nsnull);
1298 : }
1299 0 : DestroyChild();
1300 :
1301 : // Seems like this is a dynamic frame removal.
1302 0 : if (dynamicSubframeRemoval) {
1303 0 : nsCOMPtr<nsIDocShellHistory> dhistory = do_QueryInterface(mDocShell);
1304 0 : if (dhistory) {
1305 0 : dhistory->RemoveFromSessionHistory();
1306 : }
1307 : }
1308 :
1309 : // Let the tree owner know we're gone.
1310 0 : if (mIsTopLevelContent) {
1311 0 : nsCOMPtr<nsIDocShellTreeItem> ourItem = do_QueryInterface(mDocShell);
1312 0 : if (ourItem) {
1313 0 : nsCOMPtr<nsIDocShellTreeItem> parentItem;
1314 0 : ourItem->GetParent(getter_AddRefs(parentItem));
1315 0 : nsCOMPtr<nsIDocShellTreeOwner> owner = do_GetInterface(parentItem);
1316 0 : if (owner) {
1317 0 : owner->ContentShellRemoved(ourItem);
1318 : }
1319 : }
1320 : }
1321 :
1322 : // Let our window know that we are gone
1323 0 : nsCOMPtr<nsPIDOMWindow> win_private(do_GetInterface(mDocShell));
1324 0 : if (win_private) {
1325 0 : win_private->SetFrameElementInternal(nsnull);
1326 : }
1327 :
1328 0 : if ((mNeedsAsyncDestroy || !doc ||
1329 0 : NS_FAILED(doc->FinalizeFrameLoader(this))) && mDocShell) {
1330 0 : nsCOMPtr<nsIRunnable> event = new nsAsyncDocShellDestroyer(mDocShell);
1331 0 : NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
1332 0 : NS_DispatchToCurrentThread(event);
1333 :
1334 : // Let go of our docshell now that the async destroyer holds on to
1335 : // the docshell.
1336 :
1337 0 : mDocShell = nsnull;
1338 : }
1339 :
1340 : // NOTE: 'this' may very well be gone by now.
1341 :
1342 0 : return NS_OK;
1343 : }
1344 :
1345 : NS_IMETHODIMP
1346 0 : nsFrameLoader::GetDepthTooGreat(bool* aDepthTooGreat)
1347 : {
1348 0 : *aDepthTooGreat = mDepthTooGreat;
1349 0 : return NS_OK;
1350 : }
1351 :
1352 : void
1353 0 : nsFrameLoader::SetOwnerContent(Element* aContent)
1354 : {
1355 0 : mOwnerContent = aContent;
1356 0 : if (RenderFrameParent* rfp = GetCurrentRemoteFrame()) {
1357 0 : rfp->OwnerContentChanged(aContent);
1358 : }
1359 0 : }
1360 :
1361 : bool
1362 0 : nsFrameLoader::ShouldUseRemoteProcess()
1363 : {
1364 : // Check for *disabled* multi-process first: environment, pref
1365 : // Then check for *enabled* multi-process attribute
1366 : // Default is not-remote.
1367 :
1368 0 : if (PR_GetEnv("MOZ_DISABLE_OOP_TABS") ||
1369 0 : Preferences::GetBool("dom.ipc.tabs.disabled", false)) {
1370 0 : return false;
1371 : }
1372 :
1373 : return (bool) mOwnerContent->AttrValueIs(kNameSpaceID_None,
1374 : nsGkAtoms::Remote,
1375 : nsGkAtoms::_true,
1376 0 : eCaseMatters);
1377 : }
1378 :
1379 : nsresult
1380 0 : nsFrameLoader::MaybeCreateDocShell()
1381 : {
1382 0 : if (mDocShell) {
1383 0 : return NS_OK;
1384 : }
1385 0 : if (mRemoteFrame) {
1386 0 : return NS_OK;
1387 : }
1388 0 : NS_ENSURE_STATE(!mDestroyCalled);
1389 :
1390 0 : if (ShouldUseRemoteProcess()) {
1391 0 : mRemoteFrame = true;
1392 0 : return NS_OK;
1393 : }
1394 :
1395 : // Get our parent docshell off the document of mOwnerContent
1396 : // XXXbz this is such a total hack.... We really need to have a
1397 : // better setup for doing this.
1398 0 : nsIDocument* doc = mOwnerContent->OwnerDoc();
1399 0 : if (!(doc->IsStaticDocument() || mOwnerContent->IsInDoc())) {
1400 0 : return NS_ERROR_UNEXPECTED;
1401 : }
1402 :
1403 0 : if (doc->IsResourceDoc() || !doc->IsActive()) {
1404 : // Don't allow subframe loads in resource documents, nor
1405 : // in non-active documents.
1406 0 : return NS_ERROR_NOT_AVAILABLE;
1407 : }
1408 :
1409 : nsCOMPtr<nsISupports> container =
1410 0 : doc->GetContainer();
1411 0 : nsCOMPtr<nsIWebNavigation> parentAsWebNav = do_QueryInterface(container);
1412 0 : NS_ENSURE_STATE(parentAsWebNav);
1413 :
1414 : // Create the docshell...
1415 0 : mDocShell = do_CreateInstance("@mozilla.org/docshell;1");
1416 0 : NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
1417 :
1418 0 : if (!mNetworkCreated) {
1419 0 : nsCOMPtr<nsIDocShellHistory> history = do_QueryInterface(mDocShell);
1420 0 : if (history) {
1421 0 : history->SetCreatedDynamically(true);
1422 : }
1423 : }
1424 :
1425 : // Get the frame name and tell the docshell about it.
1426 0 : nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
1427 0 : NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE);
1428 0 : nsAutoString frameName;
1429 :
1430 0 : PRInt32 namespaceID = mOwnerContent->GetNameSpaceID();
1431 0 : if (namespaceID == kNameSpaceID_XHTML && !mOwnerContent->IsInHTMLDocument()) {
1432 0 : mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, frameName);
1433 : } else {
1434 0 : mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::name, frameName);
1435 : // XXX if no NAME then use ID, after a transition period this will be
1436 : // changed so that XUL only uses ID too (bug 254284).
1437 0 : if (frameName.IsEmpty() && namespaceID == kNameSpaceID_XUL) {
1438 0 : mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::id, frameName);
1439 : }
1440 : }
1441 :
1442 0 : if (!frameName.IsEmpty()) {
1443 0 : docShellAsItem->SetName(frameName.get());
1444 : }
1445 :
1446 : // If our container is a web-shell, inform it that it has a new
1447 : // child. If it's not a web-shell then some things will not operate
1448 : // properly.
1449 :
1450 0 : nsCOMPtr<nsIDocShellTreeNode> parentAsNode(do_QueryInterface(parentAsWebNav));
1451 0 : if (parentAsNode) {
1452 : // Note: This logic duplicates a lot of logic in
1453 : // nsSubDocumentFrame::AttributeChanged. We should fix that.
1454 :
1455 : nsCOMPtr<nsIDocShellTreeItem> parentAsItem =
1456 0 : do_QueryInterface(parentAsNode);
1457 :
1458 : PRInt32 parentType;
1459 0 : parentAsItem->GetItemType(&parentType);
1460 :
1461 : // XXXbz why is this in content code, exactly? We should handle
1462 : // this some other way..... Not sure how yet.
1463 0 : nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner;
1464 0 : parentAsItem->GetTreeOwner(getter_AddRefs(parentTreeOwner));
1465 0 : NS_ENSURE_STATE(parentTreeOwner);
1466 : mIsTopLevelContent =
1467 : AddTreeItemToTreeOwner(docShellAsItem, mOwnerContent, parentTreeOwner,
1468 0 : parentType, parentAsNode);
1469 :
1470 : // Make sure all shells have links back to the content element
1471 : // in the nearest enclosing chrome shell.
1472 0 : nsCOMPtr<nsIDOMEventTarget> chromeEventHandler;
1473 :
1474 0 : if (parentType == nsIDocShellTreeItem::typeChrome) {
1475 : // Our parent shell is a chrome shell. It is therefore our nearest
1476 : // enclosing chrome shell.
1477 :
1478 0 : chromeEventHandler = do_QueryInterface(mOwnerContent);
1479 0 : NS_ASSERTION(chromeEventHandler,
1480 : "This mContent should implement this.");
1481 : } else {
1482 0 : nsCOMPtr<nsIDocShell> parentShell(do_QueryInterface(parentAsNode));
1483 :
1484 : // Our parent shell is a content shell. Get the chrome event
1485 : // handler from it and use that for our shell as well.
1486 :
1487 0 : parentShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
1488 : }
1489 :
1490 0 : mDocShell->SetChromeEventHandler(chromeEventHandler);
1491 : }
1492 :
1493 0 : nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwnerContent);
1494 0 : if (browserFrame) {
1495 0 : bool isBrowserFrame = false;
1496 0 : browserFrame->GetReallyIsBrowser(&isBrowserFrame);
1497 0 : mDocShell->SetIsBrowserFrame(isBrowserFrame);
1498 : }
1499 :
1500 : // This is nasty, this code (the do_GetInterface(mDocShell) below)
1501 : // *must* come *after* the above call to
1502 : // mDocShell->SetChromeEventHandler() for the global window to get
1503 : // the right chrome event handler.
1504 :
1505 : // Tell the window about the frame that hosts it.
1506 0 : nsCOMPtr<nsIDOMElement> frame_element(do_QueryInterface(mOwnerContent));
1507 0 : NS_ASSERTION(frame_element, "frame loader owner element not a DOM element!");
1508 :
1509 0 : nsCOMPtr<nsPIDOMWindow> win_private(do_GetInterface(mDocShell));
1510 0 : nsCOMPtr<nsIBaseWindow> base_win(do_QueryInterface(mDocShell));
1511 0 : if (win_private) {
1512 0 : win_private->SetFrameElementInternal(frame_element);
1513 : }
1514 :
1515 : // This is kinda whacky, this call doesn't really create anything,
1516 : // but it must be called to make sure things are properly
1517 : // initialized.
1518 0 : if (NS_FAILED(base_win->Create()) || !win_private) {
1519 : // Do not call Destroy() here. See bug 472312.
1520 0 : NS_WARNING("Something wrong when creating the docshell for a frameloader!");
1521 0 : return NS_ERROR_FAILURE;
1522 : }
1523 :
1524 0 : EnsureMessageManager();
1525 :
1526 0 : return NS_OK;
1527 : }
1528 :
1529 : void
1530 0 : nsFrameLoader::GetURL(nsString& aURI)
1531 : {
1532 0 : aURI.Truncate();
1533 :
1534 0 : if (mOwnerContent->Tag() == nsGkAtoms::object) {
1535 0 : mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::data, aURI);
1536 : } else {
1537 0 : mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::src, aURI);
1538 : }
1539 0 : }
1540 :
1541 : nsresult
1542 0 : nsFrameLoader::CheckForRecursiveLoad(nsIURI* aURI)
1543 : {
1544 : nsresult rv;
1545 :
1546 0 : mDepthTooGreat = false;
1547 0 : rv = MaybeCreateDocShell();
1548 0 : if (NS_FAILED(rv)) {
1549 0 : return rv;
1550 : }
1551 0 : NS_ASSERTION(!mRemoteFrame,
1552 : "Shouldn't call CheckForRecursiveLoad on remote frames.");
1553 0 : if (!mDocShell) {
1554 0 : return NS_ERROR_FAILURE;
1555 : }
1556 :
1557 0 : nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(mDocShell);
1558 0 : NS_ASSERTION(treeItem, "docshell must be a treeitem!");
1559 :
1560 : // Check that we're still in the docshell tree.
1561 0 : nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
1562 0 : treeItem->GetTreeOwner(getter_AddRefs(treeOwner));
1563 0 : NS_WARN_IF_FALSE(treeOwner,
1564 : "Trying to load a new url to a docshell without owner!");
1565 0 : NS_ENSURE_STATE(treeOwner);
1566 :
1567 :
1568 : PRInt32 ourType;
1569 0 : rv = treeItem->GetItemType(&ourType);
1570 0 : if (NS_SUCCEEDED(rv) && ourType != nsIDocShellTreeItem::typeContent) {
1571 : // No need to do recursion-protection here XXXbz why not?? Do we really
1572 : // trust people not to screw up with non-content docshells?
1573 0 : return NS_OK;
1574 : }
1575 :
1576 : // Bug 8065: Don't exceed some maximum depth in content frames
1577 : // (MAX_DEPTH_CONTENT_FRAMES)
1578 0 : nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
1579 0 : treeItem->GetSameTypeParent(getter_AddRefs(parentAsItem));
1580 0 : PRInt32 depth = 0;
1581 0 : while (parentAsItem) {
1582 0 : ++depth;
1583 :
1584 0 : if (depth >= MAX_DEPTH_CONTENT_FRAMES) {
1585 0 : mDepthTooGreat = true;
1586 0 : NS_WARNING("Too many nested content frames so giving up");
1587 :
1588 0 : return NS_ERROR_UNEXPECTED; // Too deep, give up! (silently?)
1589 : }
1590 :
1591 0 : nsCOMPtr<nsIDocShellTreeItem> temp;
1592 0 : temp.swap(parentAsItem);
1593 0 : temp->GetSameTypeParent(getter_AddRefs(parentAsItem));
1594 : }
1595 :
1596 : // Bug 136580: Check for recursive frame loading
1597 0 : PRInt32 matchCount = 0;
1598 0 : treeItem->GetSameTypeParent(getter_AddRefs(parentAsItem));
1599 0 : while (parentAsItem) {
1600 : // Check the parent URI with the URI we're loading
1601 0 : nsCOMPtr<nsIWebNavigation> parentAsNav(do_QueryInterface(parentAsItem));
1602 0 : if (parentAsNav) {
1603 : // Does the URI match the one we're about to load?
1604 0 : nsCOMPtr<nsIURI> parentURI;
1605 0 : parentAsNav->GetCurrentURI(getter_AddRefs(parentURI));
1606 0 : if (parentURI) {
1607 : // Bug 98158/193011: We need to ignore data after the #
1608 : bool equal;
1609 0 : rv = aURI->EqualsExceptRef(parentURI, &equal);
1610 0 : NS_ENSURE_SUCCESS(rv, rv);
1611 :
1612 0 : if (equal) {
1613 0 : matchCount++;
1614 0 : if (matchCount >= MAX_SAME_URL_CONTENT_FRAMES) {
1615 0 : NS_WARNING("Too many nested content frames have the same url (recursion?) so giving up");
1616 0 : return NS_ERROR_UNEXPECTED;
1617 : }
1618 : }
1619 : }
1620 : }
1621 0 : nsCOMPtr<nsIDocShellTreeItem> temp;
1622 0 : temp.swap(parentAsItem);
1623 0 : temp->GetSameTypeParent(getter_AddRefs(parentAsItem));
1624 : }
1625 :
1626 0 : return NS_OK;
1627 : }
1628 :
1629 : nsresult
1630 0 : nsFrameLoader::GetWindowDimensions(nsRect& aRect)
1631 : {
1632 : // Need to get outer window position here
1633 0 : nsIDocument* doc = mOwnerContent->GetDocument();
1634 0 : if (!doc) {
1635 0 : return NS_ERROR_FAILURE;
1636 : }
1637 :
1638 0 : if (doc->GetDisplayDocument()) {
1639 0 : return NS_ERROR_FAILURE;
1640 : }
1641 :
1642 : nsCOMPtr<nsIWebNavigation> parentAsWebNav =
1643 0 : do_GetInterface(doc->GetScriptGlobalObject());
1644 :
1645 0 : if (!parentAsWebNav) {
1646 0 : return NS_ERROR_FAILURE;
1647 : }
1648 :
1649 0 : nsCOMPtr<nsIDocShellTreeItem> parentAsItem(do_QueryInterface(parentAsWebNav));
1650 :
1651 0 : nsCOMPtr<nsIDocShellTreeOwner> parentOwner;
1652 0 : if (NS_FAILED(parentAsItem->GetTreeOwner(getter_AddRefs(parentOwner))) ||
1653 0 : !parentOwner) {
1654 0 : return NS_ERROR_FAILURE;
1655 : }
1656 :
1657 0 : nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_GetInterface(parentOwner));
1658 0 : treeOwnerAsWin->GetPosition(&aRect.x, &aRect.y);
1659 0 : treeOwnerAsWin->GetSize(&aRect.width, &aRect.height);
1660 0 : return NS_OK;
1661 : }
1662 :
1663 : NS_IMETHODIMP
1664 0 : nsFrameLoader::UpdatePositionAndSize(nsIFrame *aIFrame)
1665 : {
1666 0 : if (mRemoteFrame) {
1667 0 : if (mRemoteBrowser) {
1668 0 : nsIntSize size = GetSubDocumentSize(aIFrame);
1669 0 : nsRect dimensions;
1670 0 : NS_ENSURE_SUCCESS(GetWindowDimensions(dimensions), NS_ERROR_FAILURE);
1671 0 : mRemoteBrowser->UpdateDimensions(dimensions, size);
1672 : }
1673 0 : return NS_OK;
1674 : }
1675 0 : return UpdateBaseWindowPositionAndSize(aIFrame);
1676 : }
1677 :
1678 : nsresult
1679 0 : nsFrameLoader::UpdateBaseWindowPositionAndSize(nsIFrame *aIFrame)
1680 : {
1681 0 : nsCOMPtr<nsIDocShell> docShell;
1682 0 : GetDocShell(getter_AddRefs(docShell));
1683 0 : nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(docShell));
1684 :
1685 : // resize the sub document
1686 0 : if (baseWindow) {
1687 0 : PRInt32 x = 0;
1688 0 : PRInt32 y = 0;
1689 :
1690 0 : nsWeakFrame weakFrame(aIFrame);
1691 :
1692 0 : baseWindow->GetPositionAndSize(&x, &y, nsnull, nsnull);
1693 :
1694 0 : if (!weakFrame.IsAlive()) {
1695 : // GetPositionAndSize() killed us
1696 0 : return NS_OK;
1697 : }
1698 :
1699 0 : nsIntSize size = GetSubDocumentSize(aIFrame);
1700 :
1701 0 : baseWindow->SetPositionAndSize(x, y, size.width, size.height, false);
1702 : }
1703 :
1704 0 : return NS_OK;
1705 : }
1706 :
1707 : NS_IMETHODIMP
1708 0 : nsFrameLoader::GetRenderMode(PRUint32* aRenderMode)
1709 : {
1710 0 : *aRenderMode = mRenderMode;
1711 0 : return NS_OK;
1712 : }
1713 :
1714 : NS_IMETHODIMP
1715 0 : nsFrameLoader::SetRenderMode(PRUint32 aRenderMode)
1716 : {
1717 0 : if (aRenderMode == mRenderMode) {
1718 0 : return NS_OK;
1719 : }
1720 :
1721 0 : mRenderMode = aRenderMode;
1722 : // NB: we pass INVALIDATE_NO_THEBES_LAYERS here to keep view
1723 : // semantics the same for both in-process and out-of-process
1724 : // <browser>. This is just a transform of the layer subtree in
1725 : // both.
1726 0 : InvalidateFrame(GetPrimaryFrameOfOwningContent(), nsIFrame::INVALIDATE_NO_THEBES_LAYERS);
1727 0 : return NS_OK;
1728 : }
1729 :
1730 : NS_IMETHODIMP
1731 0 : nsFrameLoader::GetEventMode(PRUint32* aEventMode)
1732 : {
1733 0 : *aEventMode = mEventMode;
1734 0 : return NS_OK;
1735 : }
1736 :
1737 : NS_IMETHODIMP
1738 0 : nsFrameLoader::SetEventMode(PRUint32 aEventMode)
1739 : {
1740 0 : mEventMode = aEventMode;
1741 0 : return NS_OK;
1742 : }
1743 :
1744 : NS_IMETHODIMP
1745 0 : nsFrameLoader::GetClipSubdocument(bool* aResult)
1746 : {
1747 0 : *aResult = mClipSubdocument;
1748 0 : return NS_OK;
1749 : }
1750 :
1751 : NS_IMETHODIMP
1752 0 : nsFrameLoader::SetClipSubdocument(bool aClip)
1753 : {
1754 0 : mClipSubdocument = aClip;
1755 0 : nsIFrame* frame = GetPrimaryFrameOfOwningContent();
1756 0 : if (frame) {
1757 0 : InvalidateFrame(frame, 0);
1758 0 : frame->PresContext()->PresShell()->
1759 0 : FrameNeedsReflow(frame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
1760 0 : nsSubDocumentFrame* subdocFrame = do_QueryFrame(frame);
1761 0 : if (subdocFrame) {
1762 0 : nsIFrame* subdocRootFrame = subdocFrame->GetSubdocumentRootFrame();
1763 0 : if (subdocRootFrame) {
1764 : nsIFrame* subdocRootScrollFrame = subdocRootFrame->PresContext()->PresShell()->
1765 0 : GetRootScrollFrame();
1766 0 : if (subdocRootScrollFrame) {
1767 0 : frame->PresContext()->PresShell()->
1768 0 : FrameNeedsReflow(frame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
1769 : }
1770 : }
1771 : }
1772 : }
1773 0 : return NS_OK;
1774 : }
1775 :
1776 : NS_IMETHODIMP
1777 0 : nsFrameLoader::GetClampScrollPosition(bool* aResult)
1778 : {
1779 0 : *aResult = mClampScrollPosition;
1780 0 : return NS_OK;
1781 : }
1782 :
1783 : NS_IMETHODIMP
1784 0 : nsFrameLoader::SetClampScrollPosition(bool aClamp)
1785 : {
1786 0 : mClampScrollPosition = aClamp;
1787 :
1788 : // When turning clamping on, make sure the current position is clamped.
1789 0 : if (aClamp) {
1790 0 : nsIFrame* frame = GetPrimaryFrameOfOwningContent();
1791 0 : if (frame) {
1792 0 : nsSubDocumentFrame* subdocFrame = do_QueryFrame(frame);
1793 0 : if (subdocFrame) {
1794 0 : nsIFrame* subdocRootFrame = subdocFrame->GetSubdocumentRootFrame();
1795 0 : if (subdocRootFrame) {
1796 : nsIScrollableFrame* subdocRootScrollFrame = subdocRootFrame->PresContext()->PresShell()->
1797 0 : GetRootScrollFrameAsScrollable();
1798 0 : if (subdocRootScrollFrame) {
1799 0 : subdocRootScrollFrame->ScrollTo(subdocRootScrollFrame->GetScrollPosition(), nsIScrollableFrame::INSTANT);
1800 : }
1801 : }
1802 : }
1803 : }
1804 : }
1805 0 : return NS_OK;
1806 : }
1807 :
1808 : nsIntSize
1809 0 : nsFrameLoader::GetSubDocumentSize(const nsIFrame *aIFrame)
1810 : {
1811 0 : nsSize docSizeAppUnits;
1812 0 : nsPresContext* presContext = aIFrame->PresContext();
1813 : nsCOMPtr<nsIDOMHTMLFrameElement> frameElem =
1814 0 : do_QueryInterface(aIFrame->GetContent());
1815 0 : if (frameElem) {
1816 0 : docSizeAppUnits = aIFrame->GetSize();
1817 : } else {
1818 0 : docSizeAppUnits = aIFrame->GetContentRect().Size();
1819 : }
1820 : return nsIntSize(presContext->AppUnitsToDevPixels(docSizeAppUnits.width),
1821 0 : presContext->AppUnitsToDevPixels(docSizeAppUnits.height));
1822 : }
1823 :
1824 : bool
1825 0 : nsFrameLoader::TryRemoteBrowser()
1826 : {
1827 0 : NS_ASSERTION(!mRemoteBrowser, "TryRemoteBrowser called with a remote browser already?");
1828 :
1829 0 : nsIDocument* doc = mOwnerContent->GetDocument();
1830 0 : if (!doc) {
1831 0 : return false;
1832 : }
1833 :
1834 0 : if (doc->GetDisplayDocument()) {
1835 : // Don't allow subframe loads in external reference documents
1836 0 : return false;
1837 : }
1838 :
1839 : nsCOMPtr<nsIWebNavigation> parentAsWebNav =
1840 0 : do_GetInterface(doc->GetScriptGlobalObject());
1841 :
1842 0 : if (!parentAsWebNav) {
1843 0 : return false;
1844 : }
1845 :
1846 0 : nsCOMPtr<nsIDocShellTreeItem> parentAsItem(do_QueryInterface(parentAsWebNav));
1847 :
1848 : PRInt32 parentType;
1849 0 : parentAsItem->GetItemType(&parentType);
1850 :
1851 0 : if (parentType != nsIDocShellTreeItem::typeChrome) {
1852 0 : return false;
1853 : }
1854 :
1855 0 : if (!mOwnerContent->IsXUL()) {
1856 0 : return false;
1857 : }
1858 :
1859 0 : nsAutoString value;
1860 0 : mOwnerContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, value);
1861 :
1862 0 : if (!value.LowerCaseEqualsLiteral("content") &&
1863 0 : !StringBeginsWith(value, NS_LITERAL_STRING("content-"),
1864 0 : nsCaseInsensitiveStringComparator())) {
1865 0 : return false;
1866 : }
1867 :
1868 0 : PRUint32 chromeFlags = 0;
1869 0 : nsCOMPtr<nsIDocShellTreeOwner> parentOwner;
1870 0 : if (NS_FAILED(parentAsItem->GetTreeOwner(getter_AddRefs(parentOwner))) ||
1871 0 : !parentOwner) {
1872 0 : return false;
1873 : }
1874 0 : nsCOMPtr<nsIXULWindow> window(do_GetInterface(parentOwner));
1875 0 : if (!window) {
1876 0 : return false;
1877 : }
1878 0 : if (NS_FAILED(window->GetChromeFlags(&chromeFlags))) {
1879 0 : return false;
1880 : }
1881 :
1882 0 : ContentParent* parent = ContentParent::GetNewOrUsed();
1883 0 : NS_ASSERTION(parent->IsAlive(), "Process parent should be alive; something is very wrong!");
1884 0 : mRemoteBrowser = parent->CreateTab(chromeFlags);
1885 0 : if (mRemoteBrowser) {
1886 0 : nsCOMPtr<nsIDOMElement> element = do_QueryInterface(mOwnerContent);
1887 0 : mRemoteBrowser->SetOwnerElement(element);
1888 :
1889 0 : nsCOMPtr<nsIDocShellTreeItem> rootItem;
1890 0 : parentAsItem->GetRootTreeItem(getter_AddRefs(rootItem));
1891 0 : nsCOMPtr<nsIDOMWindow> rootWin = do_GetInterface(rootItem);
1892 0 : nsCOMPtr<nsIDOMChromeWindow> rootChromeWin = do_QueryInterface(rootWin);
1893 0 : NS_ABORT_IF_FALSE(rootChromeWin, "How did we not get a chrome window here?");
1894 :
1895 0 : nsCOMPtr<nsIBrowserDOMWindow> browserDOMWin;
1896 0 : rootChromeWin->GetBrowserDOMWindow(getter_AddRefs(browserDOMWin));
1897 0 : mRemoteBrowser->SetBrowserDOMWindow(browserDOMWin);
1898 :
1899 0 : mChildHost = parent;
1900 : }
1901 0 : return true;
1902 : }
1903 :
1904 : mozilla::dom::PBrowserParent*
1905 0 : nsFrameLoader::GetRemoteBrowser()
1906 : {
1907 0 : return mRemoteBrowser;
1908 : }
1909 :
1910 : NS_IMETHODIMP
1911 0 : nsFrameLoader::ActivateRemoteFrame() {
1912 0 : if (mRemoteBrowser) {
1913 0 : mRemoteBrowser->Activate();
1914 0 : return NS_OK;
1915 : }
1916 0 : return NS_ERROR_UNEXPECTED;
1917 : }
1918 :
1919 : NS_IMETHODIMP
1920 0 : nsFrameLoader::DeactivateRemoteFrame() {
1921 0 : if (mRemoteBrowser) {
1922 0 : mRemoteBrowser->Deactivate();
1923 0 : return NS_OK;
1924 : }
1925 0 : return NS_ERROR_UNEXPECTED;
1926 : }
1927 :
1928 : NS_IMETHODIMP
1929 0 : nsFrameLoader::SendCrossProcessMouseEvent(const nsAString& aType,
1930 : float aX,
1931 : float aY,
1932 : PRInt32 aButton,
1933 : PRInt32 aClickCount,
1934 : PRInt32 aModifiers,
1935 : bool aIgnoreRootScrollFrame)
1936 : {
1937 0 : if (mRemoteBrowser) {
1938 : mRemoteBrowser->SendMouseEvent(aType, aX, aY, aButton,
1939 : aClickCount, aModifiers,
1940 0 : aIgnoreRootScrollFrame);
1941 0 : return NS_OK;
1942 : }
1943 0 : return NS_ERROR_FAILURE;
1944 : }
1945 :
1946 : NS_IMETHODIMP
1947 0 : nsFrameLoader::ActivateFrameEvent(const nsAString& aType,
1948 : bool aCapture)
1949 : {
1950 0 : if (mRemoteBrowser) {
1951 0 : return mRemoteBrowser->SendActivateFrameEvent(nsString(aType), aCapture) ?
1952 0 : NS_OK : NS_ERROR_NOT_AVAILABLE;
1953 : }
1954 0 : return NS_ERROR_FAILURE;
1955 : }
1956 :
1957 : NS_IMETHODIMP
1958 0 : nsFrameLoader::SendCrossProcessKeyEvent(const nsAString& aType,
1959 : PRInt32 aKeyCode,
1960 : PRInt32 aCharCode,
1961 : PRInt32 aModifiers,
1962 : bool aPreventDefault)
1963 : {
1964 0 : if (mRemoteBrowser) {
1965 : mRemoteBrowser->SendKeyEvent(aType, aKeyCode, aCharCode, aModifiers,
1966 0 : aPreventDefault);
1967 0 : return NS_OK;
1968 : }
1969 0 : return NS_ERROR_FAILURE;
1970 : }
1971 :
1972 : NS_IMETHODIMP
1973 0 : nsFrameLoader::GetDelayRemoteDialogs(bool* aRetVal)
1974 : {
1975 0 : *aRetVal = mDelayRemoteDialogs;
1976 0 : return NS_OK;
1977 : }
1978 :
1979 : NS_IMETHODIMP
1980 0 : nsFrameLoader::SetDelayRemoteDialogs(bool aDelay)
1981 : {
1982 0 : if (mRemoteBrowser && mDelayRemoteDialogs && !aDelay) {
1983 : nsRefPtr<nsIRunnable> ev =
1984 : NS_NewRunnableMethod(mRemoteBrowser,
1985 0 : &mozilla::dom::TabParent::HandleDelayedDialogs);
1986 0 : NS_DispatchToCurrentThread(ev);
1987 : }
1988 0 : mDelayRemoteDialogs = aDelay;
1989 0 : return NS_OK;
1990 : }
1991 :
1992 : nsresult
1993 0 : nsFrameLoader::CreateStaticClone(nsIFrameLoader* aDest)
1994 : {
1995 0 : nsFrameLoader* dest = static_cast<nsFrameLoader*>(aDest);
1996 0 : dest->MaybeCreateDocShell();
1997 0 : NS_ENSURE_STATE(dest->mDocShell);
1998 :
1999 0 : nsCOMPtr<nsIDOMDocument> dummy = do_GetInterface(dest->mDocShell);
2000 0 : nsCOMPtr<nsIContentViewer> viewer;
2001 0 : dest->mDocShell->GetContentViewer(getter_AddRefs(viewer));
2002 0 : NS_ENSURE_STATE(viewer);
2003 :
2004 0 : nsCOMPtr<nsIDocShell> origDocShell;
2005 0 : GetDocShell(getter_AddRefs(origDocShell));
2006 0 : nsCOMPtr<nsIDOMDocument> domDoc = do_GetInterface(origDocShell);
2007 :
2008 0 : nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
2009 0 : NS_ENSURE_STATE(doc);
2010 0 : nsCOMPtr<nsIDocument> clonedDoc = doc->CreateStaticClone(dest->mDocShell);
2011 0 : nsCOMPtr<nsIDOMDocument> clonedDOMDoc = do_QueryInterface(clonedDoc);
2012 :
2013 0 : viewer->SetDOMDocument(clonedDOMDoc);
2014 0 : return NS_OK;
2015 : }
2016 :
2017 0 : bool LoadScript(void* aCallbackData, const nsAString& aURL)
2018 : {
2019 : mozilla::dom::PBrowserParent* tabParent =
2020 0 : static_cast<nsFrameLoader*>(aCallbackData)->GetRemoteBrowser();
2021 0 : if (tabParent) {
2022 0 : return tabParent->SendLoadRemoteScript(nsString(aURL));
2023 : }
2024 0 : nsFrameLoader* fl = static_cast<nsFrameLoader*>(aCallbackData);
2025 : nsRefPtr<nsInProcessTabChildGlobal> tabChild =
2026 0 : static_cast<nsInProcessTabChildGlobal*>(fl->GetTabChildGlobalAsEventTarget());
2027 0 : if (tabChild) {
2028 0 : tabChild->LoadFrameScript(aURL);
2029 : }
2030 0 : return true;
2031 : }
2032 :
2033 : class nsAsyncMessageToChild : public nsRunnable
2034 0 : {
2035 : public:
2036 0 : nsAsyncMessageToChild(nsFrameLoader* aFrameLoader,
2037 : const nsAString& aMessage, const nsAString& aJSON)
2038 0 : : mFrameLoader(aFrameLoader), mMessage(aMessage), mJSON(aJSON) {}
2039 :
2040 0 : NS_IMETHOD Run()
2041 : {
2042 : nsInProcessTabChildGlobal* tabChild =
2043 0 : static_cast<nsInProcessTabChildGlobal*>(mFrameLoader->mChildMessageManager.get());
2044 0 : if (tabChild && tabChild->GetInnerManager()) {
2045 0 : nsFrameScriptCx cx(static_cast<nsIDOMEventTarget*>(tabChild), tabChild);
2046 0 : nsRefPtr<nsFrameMessageManager> mm = tabChild->GetInnerManager();
2047 : mm->ReceiveMessage(static_cast<nsIDOMEventTarget*>(tabChild), mMessage,
2048 0 : false, mJSON, nsnull, nsnull);
2049 : }
2050 0 : return NS_OK;
2051 : }
2052 : nsRefPtr<nsFrameLoader> mFrameLoader;
2053 : nsString mMessage;
2054 : nsString mJSON;
2055 : };
2056 :
2057 0 : bool SendAsyncMessageToChild(void* aCallbackData,
2058 : const nsAString& aMessage,
2059 : const nsAString& aJSON)
2060 : {
2061 : mozilla::dom::PBrowserParent* tabParent =
2062 0 : static_cast<nsFrameLoader*>(aCallbackData)->GetRemoteBrowser();
2063 0 : if (tabParent) {
2064 0 : return tabParent->SendAsyncMessage(nsString(aMessage), nsString(aJSON));
2065 : }
2066 : nsRefPtr<nsIRunnable> ev =
2067 : new nsAsyncMessageToChild(static_cast<nsFrameLoader*>(aCallbackData),
2068 0 : aMessage, aJSON);
2069 0 : NS_DispatchToCurrentThread(ev);
2070 0 : return true;
2071 : }
2072 :
2073 : NS_IMETHODIMP
2074 0 : nsFrameLoader::GetMessageManager(nsIChromeFrameMessageManager** aManager)
2075 : {
2076 0 : EnsureMessageManager();
2077 0 : if (mMessageManager) {
2078 0 : CallQueryInterface(mMessageManager, aManager);
2079 : }
2080 0 : return NS_OK;
2081 : }
2082 :
2083 : NS_IMETHODIMP
2084 0 : nsFrameLoader::GetContentViewsIn(float aXPx, float aYPx,
2085 : float aTopSize, float aRightSize,
2086 : float aBottomSize, float aLeftSize,
2087 : PRUint32* aLength,
2088 : nsIContentView*** aResult)
2089 : {
2090 0 : nscoord x = nsPresContext::CSSPixelsToAppUnits(aXPx - aLeftSize);
2091 0 : nscoord y = nsPresContext::CSSPixelsToAppUnits(aYPx - aTopSize);
2092 0 : nscoord w = nsPresContext::CSSPixelsToAppUnits(aLeftSize + aRightSize) + 1;
2093 0 : nscoord h = nsPresContext::CSSPixelsToAppUnits(aTopSize + aBottomSize) + 1;
2094 0 : nsRect target(x, y, w, h);
2095 :
2096 0 : nsIFrame* frame = GetPrimaryFrameOfOwningContent();
2097 :
2098 0 : nsTArray<ViewID> ids;
2099 0 : nsLayoutUtils::GetRemoteContentIds(frame, target, ids, true);
2100 0 : if (ids.Length() == 0 || !GetCurrentRemoteFrame()) {
2101 0 : *aResult = nsnull;
2102 0 : *aLength = 0;
2103 0 : return NS_OK;
2104 : }
2105 :
2106 : nsIContentView** result = reinterpret_cast<nsIContentView**>(
2107 0 : NS_Alloc(ids.Length() * sizeof(nsIContentView*)));
2108 :
2109 0 : for (PRUint32 i = 0; i < ids.Length(); i++) {
2110 0 : nsIContentView* view = GetCurrentRemoteFrame()->GetContentView(ids[i]);
2111 0 : NS_ABORT_IF_FALSE(view, "Retrieved ID from RenderFrameParent, it should be valid!");
2112 0 : nsRefPtr<nsIContentView>(view).forget(&result[i]);
2113 : }
2114 :
2115 0 : *aResult = result;
2116 0 : *aLength = ids.Length();
2117 :
2118 0 : return NS_OK;
2119 : }
2120 :
2121 : NS_IMETHODIMP
2122 0 : nsFrameLoader::GetRootContentView(nsIContentView** aContentView)
2123 : {
2124 0 : RenderFrameParent* rfp = GetCurrentRemoteFrame();
2125 0 : if (!rfp) {
2126 0 : *aContentView = nsnull;
2127 0 : return NS_OK;
2128 : }
2129 :
2130 0 : nsContentView* view = rfp->GetContentView();
2131 0 : NS_ABORT_IF_FALSE(view, "Should always be able to create root scrollable!");
2132 0 : nsRefPtr<nsIContentView>(view).forget(aContentView);
2133 :
2134 0 : return NS_OK;
2135 : }
2136 :
2137 : nsresult
2138 0 : nsFrameLoader::EnsureMessageManager()
2139 : {
2140 0 : NS_ENSURE_STATE(mOwnerContent);
2141 :
2142 0 : nsresult rv = MaybeCreateDocShell();
2143 0 : if (NS_FAILED(rv)) {
2144 0 : return rv;
2145 : }
2146 :
2147 0 : if (!mIsTopLevelContent && !mRemoteFrame) {
2148 0 : return NS_OK;
2149 : }
2150 :
2151 0 : if (mMessageManager) {
2152 0 : if (ShouldUseRemoteProcess()) {
2153 0 : mMessageManager->SetCallbackData(mRemoteBrowserShown ? this : nsnull);
2154 : }
2155 0 : return NS_OK;
2156 : }
2157 :
2158 0 : nsIScriptContext* sctx = mOwnerContent->GetContextForEventHandlers(&rv);
2159 0 : NS_ENSURE_SUCCESS(rv, rv);
2160 0 : NS_ENSURE_STATE(sctx);
2161 0 : JSContext* cx = sctx->GetNativeContext();
2162 0 : NS_ENSURE_STATE(cx);
2163 :
2164 : nsCOMPtr<nsIDOMChromeWindow> chromeWindow =
2165 0 : do_QueryInterface(mOwnerContent->OwnerDoc()->GetWindow());
2166 0 : NS_ENSURE_STATE(chromeWindow);
2167 0 : nsCOMPtr<nsIChromeFrameMessageManager> parentManager;
2168 0 : chromeWindow->GetMessageManager(getter_AddRefs(parentManager));
2169 :
2170 0 : if (ShouldUseRemoteProcess()) {
2171 : mMessageManager = new nsFrameMessageManager(true,
2172 : nsnull,
2173 : SendAsyncMessageToChild,
2174 : LoadScript,
2175 : mRemoteBrowserShown ? this : nsnull,
2176 0 : static_cast<nsFrameMessageManager*>(parentManager.get()),
2177 0 : cx);
2178 0 : NS_ENSURE_TRUE(mMessageManager, NS_ERROR_OUT_OF_MEMORY);
2179 : } else
2180 : {
2181 :
2182 : mMessageManager = new nsFrameMessageManager(true,
2183 : nsnull,
2184 : SendAsyncMessageToChild,
2185 : LoadScript,
2186 : nsnull,
2187 0 : static_cast<nsFrameMessageManager*>(parentManager.get()),
2188 0 : cx);
2189 0 : NS_ENSURE_TRUE(mMessageManager, NS_ERROR_OUT_OF_MEMORY);
2190 : mChildMessageManager =
2191 0 : new nsInProcessTabChildGlobal(mDocShell, mOwnerContent, mMessageManager);
2192 0 : mMessageManager->SetCallbackData(this);
2193 : }
2194 0 : return NS_OK;
2195 : }
2196 :
2197 : nsIDOMEventTarget*
2198 0 : nsFrameLoader::GetTabChildGlobalAsEventTarget()
2199 : {
2200 0 : return static_cast<nsInProcessTabChildGlobal*>(mChildMessageManager.get());
2201 4392 : }
|