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