/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8; -*- */ /* vim: set sw=2 sts=2 ts=8 et tw=80 : */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "base/basictypes.h" #include "TabChild.h" #include "BasicLayers.h" #include "Blob.h" #include "ContentChild.h" #include "IndexedDBChild.h" #include "mozilla/ClearOnShutdown.h" #include "mozilla/IntentionalCrash.h" #include "mozilla/docshell/OfflineCacheUpdateChild.h" #include "mozilla/dom/PContentChild.h" #include "mozilla/dom/PContentDialogChild.h" #include "mozilla/ipc/DocumentRendererChild.h" #include "mozilla/layers/AsyncPanZoomController.h" #include "mozilla/layers/CompositorChild.h" #include "mozilla/layers/PLayersChild.h" #include "mozilla/layout/RenderFrameChild.h" #include "mozilla/StaticPtr.h" #include "mozilla/unused.h" #include "mozIApplication.h" #include "nsComponentManagerUtils.h" #include "nsComponentManagerUtils.h" #include "nsContentUtils.h" #include "nsEmbedCID.h" #include "nsEventListenerManager.h" #include "mozilla/dom/Element.h" #include "nsIAppsService.h" #include "nsIBaseWindow.h" #include "nsIComponentManager.h" #include "nsIDOMClassInfo.h" #include "nsIDOMElement.h" #include "nsIDOMEvent.h" #include "nsIDOMWindow.h" #include "nsIDOMWindowUtils.h" #include "nsIDocShell.h" #include "nsIDocShellTreeItem.h" #include "nsIInterfaceRequestorUtils.h" #include "nsIInterfaceRequestorUtils.h" #include "nsIJSContextStack.h" #include "nsIJSRuntimeService.h" #include "nsISSLStatusProvider.h" #include "nsIScriptContext.h" #include "nsIScriptGlobalObject.h" #include "nsIScriptSecurityManager.h" #include "nsISecureBrowserUI.h" #include "nsIServiceManager.h" #include "nsISupportsImpl.h" #include "nsIURI.h" #include "nsIURIFixup.h" #include "nsCDefaultURIFixup.h" #include "nsIView.h" #include "nsIWebBrowser.h" #include "nsIWebBrowserFocus.h" #include "nsIWebBrowserSetup.h" #include "nsIWebProgress.h" #include "nsIXPCSecurityManager.h" #include "nsInterfaceHashtable.h" #include "nsPIDOMWindow.h" #include "nsPIWindowRoot.h" #include "nsGlobalWindow.h" #include "nsPresContext.h" #include "nsPrintfCString.h" #include "nsScriptLoader.h" #include "nsSerializationHelper.h" #include "nsThreadUtils.h" #include "nsWeakReference.h" #include "PCOMContentPermissionRequestChild.h" #include "PuppetWidget.h" #include "StructuredCloneUtils.h" #include "xpcpublic.h" #include "nsViewportInfo.h" #define BROWSER_ELEMENT_CHILD_SCRIPT \ NS_LITERAL_STRING("chrome://global/content/BrowserElementChild.js") using namespace mozilla; using namespace mozilla::dom; using namespace mozilla::dom::ipc; using namespace mozilla::ipc; using namespace mozilla::layers; using namespace mozilla::layout; using namespace mozilla::docshell; using namespace mozilla::dom::indexedDB; using namespace mozilla::widget; NS_IMPL_ISUPPORTS1(ContentListener, nsIDOMEventListener) static const nsIntSize kDefaultViewportSize(980, 480); static const char CANCEL_DEFAULT_PAN_ZOOM[] = "cancel-default-pan-zoom"; static const char BROWSER_ZOOM_TO_RECT[] = "browser-zoom-to-rect"; static const char BEFORE_FIRST_PAINT[] = "before-first-paint"; NS_IMETHODIMP ContentListener::HandleEvent(nsIDOMEvent* aEvent) { RemoteDOMEvent remoteEvent; remoteEvent.mEvent = do_QueryInterface(aEvent); NS_ENSURE_STATE(remoteEvent.mEvent); mTabChild->SendEvent(remoteEvent); return NS_OK; } class ContentDialogChild : public PContentDialogChild { public: virtual bool Recv__delete__(const InfallibleTArray& aIntParams, const InfallibleTArray& aStringParams); }; StaticRefPtr sPreallocatedTab; /*static*/ void TabChild::PreloadSlowThings() { MOZ_ASSERT(!sPreallocatedTab); nsRefPtr tab(new TabChild(TabContext(), /* chromeFlags */ 0)); if (!NS_SUCCEEDED(tab->Init()) || !tab->InitTabChildGlobal(DONT_LOAD_SCRIPTS)) { return; } tab->TryCacheLoadAndCompileScript(BROWSER_ELEMENT_CHILD_SCRIPT); sPreallocatedTab = tab; ClearOnShutdown(&sPreallocatedTab); } /*static*/ already_AddRefed TabChild::Create(const TabContext &aContext, uint32_t aChromeFlags) { if (sPreallocatedTab && sPreallocatedTab->mChromeFlags == aChromeFlags && aContext.IsBrowserOrApp()) { nsRefPtr child = sPreallocatedTab.get(); sPreallocatedTab = nullptr; MOZ_ASSERT(!child->mTriedBrowserInit); child->SetTabContext(aContext); child->NotifyTabContextUpdated(); return child.forget(); } nsRefPtr iframe = new TabChild(aContext, aChromeFlags); return NS_SUCCEEDED(iframe->Init()) ? iframe.forget() : nullptr; } TabChild::TabChild(const TabContext& aContext, uint32_t aChromeFlags) : TabContext(aContext) , mRemoteFrame(nullptr) , mTabChildGlobal(nullptr) , mChromeFlags(aChromeFlags) , mOuterRect(0, 0, 0, 0) , mInnerSize(0, 0) , mOldViewportWidth(0.0f) , mLastBackgroundColor(NS_RGB(255, 255, 255)) , mDidFakeShow(false) , mNotified(false) , mContentDocumentIsDisplayed(false) , mTriedBrowserInit(false) , mOrientation(eScreenOrientation_PortraitPrimary) { printf("creating %d!\n", NS_IsMainThread()); } NS_IMETHODIMP TabChild::HandleEvent(nsIDOMEvent* aEvent) { nsAutoString eventType; aEvent->GetType(eventType); if (eventType.EqualsLiteral("DOMMetaAdded")) { // This meta data may or may not have been a meta viewport tag. If it was, // we should handle it immediately. HandlePossibleViewportChange(); } return NS_OK; } NS_IMETHODIMP TabChild::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *aData) { if (!strcmp(aTopic, CANCEL_DEFAULT_PAN_ZOOM)) { nsCOMPtr docShell(do_QueryInterface(aSubject)); nsCOMPtr tabChild(GetTabChildFrom(docShell)); if (tabChild == this) { mRemoteFrame->CancelDefaultPanZoom(); } } else if (!strcmp(aTopic, BROWSER_ZOOM_TO_RECT)) { nsCOMPtr docShell(do_QueryInterface(aSubject)); nsCOMPtr tabChild(GetTabChildFrom(docShell)); if (tabChild == this) { gfxRect rect; sscanf(NS_ConvertUTF16toUTF8(aData).get(), "{\"x\":%lf,\"y\":%lf,\"w\":%lf,\"h\":%lf}", &rect.x, &rect.y, &rect.width, &rect.height); SendZoomToRect(rect); } } else if (!strcmp(aTopic, BEFORE_FIRST_PAINT)) { if (IsAsyncPanZoomEnabled()) { nsCOMPtr subject(do_QueryInterface(aSubject)); nsCOMPtr domDoc; mWebNav->GetDocument(getter_AddRefs(domDoc)); nsCOMPtr doc(do_QueryInterface(domDoc)); if (SameCOMIdentity(subject, doc)) { nsCOMPtr utils(GetDOMWindowUtils()); mContentDocumentIsDisplayed = true; // Reset CSS viewport and zoom to default on new page, then // calculate them properly using the actual metadata from the // page. SetCSSViewport(kDefaultViewportSize.width, kDefaultViewportSize.height); // Calculate a really simple resolution that we probably won't // be keeping, as well as putting the scroll offset back to // the top-left of the page. mLastMetrics.mZoom = gfxSize(1.0, 1.0); mLastMetrics.mViewport = gfx::Rect(0, 0, kDefaultViewportSize.width, kDefaultViewportSize.height); mLastMetrics.mCompositionBounds = nsIntRect(nsIntPoint(0, 0), mInnerSize); mLastMetrics.mResolution = AsyncPanZoomController::CalculateResolution(mLastMetrics); mLastMetrics.mScrollOffset = gfx::Point(0, 0); utils->SetResolution(mLastMetrics.mResolution.width, mLastMetrics.mResolution.height); HandlePossibleViewportChange(); } } } return NS_OK; } NS_IMETHODIMP TabChild::OnStateChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest, uint32_t aStateFlags, nsresult aStatus) { NS_NOTREACHED("not implemented in TabChild"); return NS_OK; } NS_IMETHODIMP TabChild::OnProgressChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest, int32_t aCurSelfProgress, int32_t aMaxSelfProgress, int32_t aCurTotalProgress, int32_t aMaxTotalProgress) { NS_NOTREACHED("not implemented in TabChild"); return NS_OK; } NS_IMETHODIMP TabChild::OnLocationChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest, nsIURI *aLocation, uint32_t aFlags) { if (!IsAsyncPanZoomEnabled()) { return NS_OK; } nsCOMPtr window; aWebProgress->GetDOMWindow(getter_AddRefs(window)); if (!window) { return NS_OK; } nsCOMPtr utils(do_GetInterface(window)); utils->SetIsFirstPaint(true); nsCOMPtr progressDoc; window->GetDocument(getter_AddRefs(progressDoc)); if (!progressDoc) { return NS_OK; } nsCOMPtr domDoc; mWebNav->GetDocument(getter_AddRefs(domDoc)); if (!domDoc || !SameCOMIdentity(domDoc, progressDoc)) { return NS_OK; } nsCOMPtr urifixup(do_GetService(NS_URIFIXUP_CONTRACTID)); if (!urifixup) { return NS_OK; } nsCOMPtr exposableURI; urifixup->CreateExposableURI(aLocation, getter_AddRefs(exposableURI)); if (!exposableURI) { return NS_OK; } if (!(aFlags & nsIWebProgressListener::LOCATION_CHANGE_SAME_DOCUMENT)) { mContentDocumentIsDisplayed = false; } else if (mLastURI != nullptr) { bool exposableEqualsLast, exposableEqualsNew; exposableURI->Equals(mLastURI.get(), &exposableEqualsLast); exposableURI->Equals(aLocation, &exposableEqualsNew); if (exposableEqualsLast && !exposableEqualsNew) { mContentDocumentIsDisplayed = false; } } return NS_OK; } NS_IMETHODIMP TabChild::OnStatusChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest, nsresult aStatus, const PRUnichar* aMessage) { NS_NOTREACHED("not implemented in TabChild"); return NS_OK; } NS_IMETHODIMP TabChild::OnSecurityChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest, uint32_t aState) { NS_NOTREACHED("not implemented in TabChild"); return NS_OK; } void TabChild::SetCSSViewport(float aWidth, float aHeight) { mOldViewportWidth = aWidth; if (mContentDocumentIsDisplayed) { nsCOMPtr utils(GetDOMWindowUtils()); utils->SetCSSViewport(aWidth, aHeight); } } void TabChild::HandlePossibleViewportChange() { if (!IsAsyncPanZoomEnabled()) { return; } nsCOMPtr domDoc; mWebNav->GetDocument(getter_AddRefs(domDoc)); nsCOMPtr document(do_QueryInterface(domDoc)); nsCOMPtr utils(GetDOMWindowUtils()); nsViewportInfo viewportInfo = nsContentUtils::GetViewportInfo(document, mInnerSize.width, mInnerSize.height); SendUpdateZoomConstraints(viewportInfo.IsZoomAllowed(), viewportInfo.GetMinZoom(), viewportInfo.GetMaxZoom()); float screenW = mInnerSize.width; float screenH = mInnerSize.height; float viewportW = viewportInfo.GetWidth(); float viewportH = viewportInfo.GetHeight(); // We're not being displayed in any way; don't bother doing anything because // that will just confuse future adjustments. if (!screenW || !screenH) { return; } // Make sure the viewport height is not shorter than the window when the page // is zoomed out to show its full width. Note that before we set the viewport // width, the "full width" of the page isn't properly defined, so that's why // we have to call SetCSSViewport twice - once to set the width, and the // second time to figure out the height based on the layout at that width. float oldBrowserWidth = mOldViewportWidth; mLastMetrics.mViewport.width = viewportW; mLastMetrics.mViewport.height = viewportH; if (!oldBrowserWidth) { oldBrowserWidth = kDefaultViewportSize.width; } SetCSSViewport(viewportW, viewportH); // If this page has not been painted yet, then this must be getting run // because a meta-viewport element was added (via the DOMMetaAdded handler). // in this case, we should not do anything that forces a reflow (see bug // 759678) such as requesting the page size or sending a viewport update. this // code will get run again in the before-first-paint handler and that point we // will run though all of it. the reason we even bother executing up to this // point on the DOMMetaAdded handler is so that scripts that use // window.innerWidth before they are painted have a correct value (bug // 771575). if (!mContentDocumentIsDisplayed) { return; } float minScale = 1.0f; nsCOMPtr htmlDOMElement = do_QueryInterface(document->GetHtmlElement()); nsCOMPtr bodyDOMElement = do_QueryInterface(document->GetBodyElement()); int32_t htmlWidth = 0, htmlHeight = 0; if (htmlDOMElement) { htmlDOMElement->GetScrollWidth(&htmlWidth); htmlDOMElement->GetScrollHeight(&htmlHeight); } int32_t bodyWidth = 0, bodyHeight = 0; if (bodyDOMElement) { bodyDOMElement->GetScrollWidth(&bodyWidth); bodyDOMElement->GetScrollHeight(&bodyHeight); } float pageWidth, pageHeight; if (htmlDOMElement || bodyDOMElement) { pageWidth = NS_MAX(htmlWidth, bodyWidth); pageHeight = NS_MAX(htmlHeight, bodyHeight); } else { // For non-HTML content (e.g. SVG), just assume page size == viewport size. pageWidth = viewportW; pageHeight = viewportH; } NS_ENSURE_TRUE_VOID(pageWidth); // (return early rather than divide by 0) minScale = mInnerSize.width / pageWidth; minScale = clamped((double)minScale, viewportInfo.GetMinZoom(), viewportInfo.GetMaxZoom()); NS_ENSURE_TRUE_VOID(minScale); // (return early rather than divide by 0) viewportH = NS_MAX(viewportH, screenH / minScale); SetCSSViewport(viewportW, viewportH); // This change to the zoom accounts for all types of changes I can conceive: // 1. screen size changes, CSS viewport does not (pages with no meta viewport // or a fixed size viewport) // 2. screen size changes, CSS viewport also does (pages with a device-width // viewport) // 3. screen size remains constant, but CSS viewport changes (meta viewport // tag is added or removed) // 4. neither screen size nor CSS viewport changes // // In all of these cases, we maintain how much actual content is visible // within the screen width. Note that "actual content" may be different with // respect to CSS pixels because of the CSS viewport size changing. int32_t oldScreenWidth = mLastMetrics.mCompositionBounds.width; if (!oldScreenWidth) { oldScreenWidth = mInnerSize.width; } FrameMetrics metrics(mLastMetrics); metrics.mViewport = gfx::Rect(0.0f, 0.0f, viewportW, viewportH); metrics.mScrollableRect = gfx::Rect(0.0f, 0.0f, pageWidth, pageHeight); metrics.mCompositionBounds = nsIntRect(0, 0, mInnerSize.width, mInnerSize.height); // Changing the zoom when we're not doing a first paint will get ignored // by AsyncPanZoomController and causes a blurry flash. bool isFirstPaint; nsresult rv = utils->GetIsFirstPaint(&isFirstPaint); MOZ_ASSERT(NS_SUCCEEDED(rv)); if (NS_FAILED(rv) || isFirstPaint) { gfxSize intrinsicScale = AsyncPanZoomController::CalculateIntrinsicScale(metrics); // FIXME/bug 799585(?): GetViewportInfo() returns a defaultZoom of // 0.0 to mean "did not calculate a zoom". In that case, we default // it to the intrinsic scale. if (viewportInfo.GetDefaultZoom() < 0.01f) { viewportInfo.SetDefaultZoom(intrinsicScale.width); } double defaultZoom = viewportInfo.GetDefaultZoom(); MOZ_ASSERT(viewportInfo.GetMinZoom() <= defaultZoom && defaultZoom <= viewportInfo.GetMaxZoom()); // GetViewportInfo() returns a resolution-dependent scale factor. // Convert that to a resolution-indepedent zoom. metrics.mZoom = gfxSize(defaultZoom / intrinsicScale.width, defaultZoom / intrinsicScale.height); } metrics.mDisplayPort = AsyncPanZoomController::CalculatePendingDisplayPort( // The page must have been refreshed in some way such as a new document or // new CSS viewport, so we know that there's no velocity, acceleration, and // we have no idea how long painting will take. metrics, gfx::Point(0.0f, 0.0f), gfx::Point(0.0f, 0.0f), 0.0); gfxSize resolution = AsyncPanZoomController::CalculateResolution(metrics); // XXX is this actually hysteresis? This calculation is not well // understood. It's taken from the previous JS implementation. gfxFloat hysteresis/*?*/ = gfxFloat(oldBrowserWidth) / gfxFloat(oldScreenWidth); resolution.width *= hysteresis; resolution.height *= hysteresis; metrics.mResolution = resolution; utils->SetResolution(metrics.mResolution.width, metrics.mResolution.height); // Force a repaint with these metrics. This, among other things, sets the // displayport, so we start with async painting. RecvUpdateFrame(metrics); } nsresult TabChild::Init() { nsCOMPtr webBrowser = do_CreateInstance(NS_WEBBROWSER_CONTRACTID); if (!webBrowser) { NS_ERROR("Couldn't create a nsWebBrowser?"); return NS_ERROR_FAILURE; } webBrowser->SetContainerWindow(this); mWebNav = do_QueryInterface(webBrowser); NS_ASSERTION(mWebNav, "nsWebBrowser doesn't implement nsIWebNavigation?"); nsCOMPtr docShellItem(do_QueryInterface(mWebNav)); docShellItem->SetItemType(nsIDocShellTreeItem::typeContentWrapper); nsCOMPtr baseWindow = do_QueryInterface(mWebNav); if (!baseWindow) { NS_ERROR("mWebNav doesn't QI to nsIBaseWindow"); return NS_ERROR_FAILURE; } mWidget = nsIWidget::CreatePuppetWidget(this); if (!mWidget) { NS_ERROR("couldn't create fake widget"); return NS_ERROR_FAILURE; } mWidget->Create( nullptr, 0, // no parents nsIntRect(nsIntPoint(0, 0), nsIntSize(0, 0)), nullptr, // HandleWidgetEvent nullptr // nsDeviceContext ); baseWindow->InitWindow(0, mWidget, 0, 0, 0, 0); baseWindow->Create(); NotifyTabContextUpdated(); // IPC uses a WebBrowser object for which DNS prefetching is turned off // by default. But here we really want it, so enable it explicitly nsCOMPtr webBrowserSetup = do_QueryInterface(baseWindow); if (webBrowserSetup) { webBrowserSetup->SetProperty(nsIWebBrowserSetup::SETUP_ALLOW_DNS_PREFETCH, true); } else { NS_WARNING("baseWindow doesn't QI to nsIWebBrowserSetup, skipping " "DNS prefetching enable step."); } nsCOMPtr docShell = do_GetInterface(mWebNav); MOZ_ASSERT(docShell); nsCOMPtr webProgress = do_GetInterface(docShell); NS_ENSURE_TRUE(webProgress, NS_ERROR_FAILURE); webProgress->AddProgressListener(this, nsIWebProgress::NOTIFY_LOCATION); return NS_OK; } void TabChild::NotifyTabContextUpdated() { nsCOMPtr docShell = do_GetInterface(mWebNav); MOZ_ASSERT(docShell); if (docShell) { // nsDocShell will do the right thing if we pass NO_APP_ID or // UNKNOWN_APP_ID for aOwnOrContainingAppId. if (IsBrowserElement()) { docShell->SetIsBrowserInsideApp(BrowserOwnerAppId()); } else { docShell->SetIsApp(OwnAppId()); } } } NS_INTERFACE_MAP_BEGIN(TabChild) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebBrowserChrome) NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome) NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome2) NS_INTERFACE_MAP_ENTRY(nsIEmbeddingSiteWindow) NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChromeFocus) NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) NS_INTERFACE_MAP_ENTRY(nsIWindowProvider) NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener) NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener) NS_INTERFACE_MAP_ENTRY(nsITabChild) NS_INTERFACE_MAP_ENTRY(nsIDialogCreator) NS_INTERFACE_MAP_ENTRY(nsIObserver) NS_INTERFACE_MAP_ENTRY(nsSupportsWeakReference) NS_INTERFACE_MAP_END NS_IMPL_ADDREF(TabChild) NS_IMPL_RELEASE(TabChild) NS_IMETHODIMP TabChild::SetStatus(uint32_t aStatusType, const PRUnichar* aStatus) { // FIXME/bug 617804: should the platform support this? return NS_OK; } NS_IMETHODIMP TabChild::GetWebBrowser(nsIWebBrowser** aWebBrowser) { NS_NOTREACHED("TabChild::GetWebBrowser not supported in TabChild"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChild::SetWebBrowser(nsIWebBrowser* aWebBrowser) { NS_NOTREACHED("TabChild::SetWebBrowser not supported in TabChild"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChild::GetChromeFlags(uint32_t* aChromeFlags) { *aChromeFlags = mChromeFlags; return NS_OK; } NS_IMETHODIMP TabChild::SetChromeFlags(uint32_t aChromeFlags) { NS_NOTREACHED("trying to SetChromeFlags from content process?"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChild::DestroyBrowserWindow() { NS_NOTREACHED("TabChild::SetWebBrowser not supported in TabChild"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChild::SizeBrowserTo(int32_t aCX, int32_t aCY) { NS_NOTREACHED("TabChild::SizeBrowserTo not supported in TabChild"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChild::ShowAsModal() { NS_NOTREACHED("TabChild::ShowAsModal not supported in TabChild"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChild::IsWindowModal(bool* aRetVal) { *aRetVal = false; return NS_OK; } NS_IMETHODIMP TabChild::ExitModalEventLoop(nsresult aStatus) { NS_NOTREACHED("TabChild::ExitModalEventLoop not supported in TabChild"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChild::SetStatusWithContext(uint32_t aStatusType, const nsAString& aStatusText, nsISupports* aStatusContext) { // FIXME/bug 617804: should the platform support this? return NS_OK; } NS_IMETHODIMP TabChild::SetDimensions(uint32_t aFlags, int32_t aX, int32_t aY, int32_t aCx, int32_t aCy) { NS_NOTREACHED("TabChild::SetDimensions not supported in TabChild"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChild::GetDimensions(uint32_t aFlags, int32_t* aX, int32_t* aY, int32_t* aCx, int32_t* aCy) { if (aX) { *aX = mOuterRect.x; } if (aY) { *aY = mOuterRect.y; } if (aCx) { *aCx = mOuterRect.width; } if (aCy) { *aCy = mOuterRect.height; } return NS_OK; } NS_IMETHODIMP TabChild::SetFocus() { NS_NOTREACHED("TabChild::SetFocus not supported in TabChild"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChild::GetVisibility(bool* aVisibility) { *aVisibility = true; return NS_OK; } NS_IMETHODIMP TabChild::SetVisibility(bool aVisibility) { // should the platform support this? Bug 666365 return NS_OK; } NS_IMETHODIMP TabChild::GetTitle(PRUnichar** aTitle) { NS_NOTREACHED("TabChild::GetTitle not supported in TabChild"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChild::SetTitle(const PRUnichar* aTitle) { // FIXME/bug 617804: should the platform support this? return NS_OK; } NS_IMETHODIMP TabChild::GetSiteWindow(void** aSiteWindow) { NS_NOTREACHED("TabChild::GetSiteWindow not supported in TabChild"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChild::Blur() { NS_NOTREACHED("TabChild::Blur not supported in TabChild"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP TabChild::FocusNextElement() { SendMoveFocus(true); return NS_OK; } NS_IMETHODIMP TabChild::FocusPrevElement() { SendMoveFocus(false); return NS_OK; } NS_IMETHODIMP TabChild::GetInterface(const nsIID & aIID, void **aSink) { // XXXbz should we restrict the set of interfaces we hand out here? // See bug 537429 return QueryInterface(aIID, aSink); } NS_IMETHODIMP TabChild::ProvideWindow(nsIDOMWindow* aParent, uint32_t aChromeFlags, bool aCalledFromJS, bool aPositionSpecified, bool aSizeSpecified, nsIURI* aURI, const nsAString& aName, const nsACString& aFeatures, bool* aWindowIsNew, nsIDOMWindow** aReturn) { *aReturn = nullptr; // If aParent is inside an