michael@0: /* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8; -*- */ michael@0: /* vim: set sw=2 ts=8 et tw=80 : */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "base/basictypes.h" michael@0: michael@0: #include "TabParent.h" michael@0: michael@0: #include "AppProcessChecker.h" michael@0: #include "IDBFactory.h" michael@0: #include "IndexedDBParent.h" michael@0: #include "mozIApplication.h" michael@0: #include "mozilla/BrowserElementParent.h" michael@0: #include "mozilla/docshell/OfflineCacheUpdateParent.h" michael@0: #include "mozilla/dom/ContentParent.h" michael@0: #include "mozilla/dom/PContentPermissionRequestParent.h" michael@0: #include "mozilla/EventStateManager.h" michael@0: #include "mozilla/Hal.h" michael@0: #include "mozilla/ipc/DocumentRendererParent.h" michael@0: #include "mozilla/layers/CompositorParent.h" michael@0: #include "mozilla/layout/RenderFrameParent.h" michael@0: #include "mozilla/MouseEvents.h" michael@0: #include "mozilla/Preferences.h" michael@0: #include "mozilla/TextEvents.h" michael@0: #include "mozilla/TouchEvents.h" michael@0: #include "mozilla/unused.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsContentPermissionHelper.h" michael@0: #include "nsContentUtils.h" michael@0: #include "nsDebug.h" michael@0: #include "nsFocusManager.h" michael@0: #include "nsFrameLoader.h" michael@0: #include "nsIContent.h" michael@0: #include "nsIDocShell.h" michael@0: #include "nsIDocShellTreeOwner.h" michael@0: #include "nsIDOMElement.h" michael@0: #include "nsIDOMEvent.h" michael@0: #include "nsIDOMWindow.h" michael@0: #include "nsIDOMWindowUtils.h" michael@0: #include "nsIInterfaceRequestorUtils.h" michael@0: #include "nsIPromptFactory.h" michael@0: #include "nsIURI.h" michael@0: #include "nsIWebBrowserChrome.h" michael@0: #include "nsIXULBrowserWindow.h" michael@0: #include "nsIXULWindow.h" michael@0: #include "nsViewManager.h" michael@0: #include "nsIWidget.h" michael@0: #include "nsIWindowWatcher.h" michael@0: #include "nsPIDOMWindow.h" michael@0: #include "nsPrintfCString.h" michael@0: #include "nsServiceManagerUtils.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "private/pprio.h" michael@0: #include "PermissionMessageUtils.h" michael@0: #include "StructuredCloneUtils.h" michael@0: #include "ColorPickerParent.h" michael@0: #include "JavaScriptParent.h" michael@0: #include "FilePickerParent.h" michael@0: #include "TabChild.h" michael@0: #include "LoadContext.h" michael@0: #include "nsNetCID.h" michael@0: #include michael@0: michael@0: using namespace mozilla::dom; michael@0: using namespace mozilla::ipc; michael@0: using namespace mozilla::layers; michael@0: using namespace mozilla::layout; michael@0: using namespace mozilla::services; michael@0: using namespace mozilla::widget; michael@0: using namespace mozilla::dom::indexedDB; michael@0: using namespace mozilla::jsipc; michael@0: michael@0: // The flags passed by the webProgress notifications are 16 bits shifted michael@0: // from the ones registered by webProgressListeners. michael@0: #define NOTIFY_FLAG_SHIFT 16 michael@0: michael@0: class OpenFileAndSendFDRunnable : public nsRunnable michael@0: { michael@0: const nsString mPath; michael@0: nsRefPtr mTabParent; michael@0: nsCOMPtr mEventTarget; michael@0: PRFileDesc* mFD; michael@0: michael@0: public: michael@0: OpenFileAndSendFDRunnable(const nsAString& aPath, TabParent* aTabParent) michael@0: : mPath(aPath), mTabParent(aTabParent), mFD(nullptr) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: MOZ_ASSERT(!aPath.IsEmpty()); michael@0: MOZ_ASSERT(aTabParent); michael@0: } michael@0: michael@0: void Dispatch() michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: mEventTarget = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); michael@0: NS_ENSURE_TRUE_VOID(mEventTarget); michael@0: michael@0: nsresult rv = mEventTarget->Dispatch(this, NS_DISPATCH_NORMAL); michael@0: NS_ENSURE_SUCCESS_VOID(rv); michael@0: } michael@0: michael@0: private: michael@0: ~OpenFileAndSendFDRunnable() michael@0: { michael@0: MOZ_ASSERT(!mFD); michael@0: } michael@0: michael@0: // This shouldn't be called directly except by the event loop. Use Dispatch michael@0: // to start the sequence. michael@0: NS_IMETHOD Run() michael@0: { michael@0: if (NS_IsMainThread()) { michael@0: SendResponse(); michael@0: } else if (mFD) { michael@0: CloseFile(); michael@0: } else { michael@0: OpenFile(); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void SendResponse() michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: MOZ_ASSERT(mTabParent); michael@0: MOZ_ASSERT(mEventTarget); michael@0: MOZ_ASSERT(mFD); michael@0: michael@0: nsRefPtr tabParent; michael@0: mTabParent.swap(tabParent); michael@0: michael@0: using mozilla::ipc::FileDescriptor; michael@0: michael@0: FileDescriptor::PlatformHandleType handle = michael@0: FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(mFD)); michael@0: michael@0: mozilla::unused << tabParent->SendCacheFileDescriptor(mPath, handle); michael@0: michael@0: nsCOMPtr eventTarget; michael@0: mEventTarget.swap(eventTarget); michael@0: michael@0: if (NS_FAILED(eventTarget->Dispatch(this, NS_DISPATCH_NORMAL))) { michael@0: NS_WARNING("Failed to dispatch to stream transport service!"); michael@0: michael@0: // It's probably safer to take the main thread IO hit here rather michael@0: // than leak a file descriptor. michael@0: CloseFile(); michael@0: } michael@0: } michael@0: michael@0: void OpenFile() michael@0: { michael@0: MOZ_ASSERT(!NS_IsMainThread()); michael@0: MOZ_ASSERT(!mFD); michael@0: michael@0: nsCOMPtr file; michael@0: nsresult rv = NS_NewLocalFile(mPath, false, getter_AddRefs(file)); michael@0: NS_ENSURE_SUCCESS_VOID(rv); michael@0: michael@0: PRFileDesc* fd; michael@0: rv = file->OpenNSPRFileDesc(PR_RDONLY, 0, &fd); michael@0: NS_ENSURE_SUCCESS_VOID(rv); michael@0: michael@0: mFD = fd; michael@0: michael@0: if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) { michael@0: NS_WARNING("Failed to dispatch to main thread!"); michael@0: michael@0: CloseFile(); michael@0: } michael@0: } michael@0: michael@0: void CloseFile() michael@0: { michael@0: // It's possible for this to happen on the main thread if the dispatch michael@0: // to the stream service fails after we've already opened the file so michael@0: // we can't assert the thread we're running on. michael@0: michael@0: MOZ_ASSERT(mFD); michael@0: michael@0: PRStatus prrc; michael@0: prrc = PR_Close(mFD); michael@0: if (prrc != PR_SUCCESS) { michael@0: NS_ERROR("PR_Close() failed."); michael@0: } michael@0: mFD = nullptr; michael@0: } michael@0: }; michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: michael@0: TabParent* sEventCapturer; michael@0: michael@0: TabParent *TabParent::mIMETabParent = nullptr; michael@0: michael@0: NS_IMPL_ISUPPORTS(TabParent, nsITabParent, nsIAuthPromptProvider, nsISecureBrowserUI) michael@0: michael@0: TabParent::TabParent(ContentParent* aManager, const TabContext& aContext, uint32_t aChromeFlags) michael@0: : TabContext(aContext) michael@0: , mFrameElement(nullptr) michael@0: , mIMESelectionAnchor(0) michael@0: , mIMESelectionFocus(0) michael@0: , mIMEComposing(false) michael@0: , mIMECompositionEnding(false) michael@0: , mIMECompositionStart(0) michael@0: , mIMESeqno(0) michael@0: , mIMECompositionRectOffset(0) michael@0: , mEventCaptureDepth(0) michael@0: , mRect(0, 0, 0, 0) michael@0: , mDimensions(0, 0) michael@0: , mOrientation(0) michael@0: , mDPI(0) michael@0: , mDefaultScale(0) michael@0: , mShown(false) michael@0: , mUpdatedDimensions(false) michael@0: , mManager(aManager) michael@0: , mMarkedDestroying(false) michael@0: , mIsDestroyed(false) michael@0: , mAppPackageFileDescriptorSent(false) michael@0: , mChromeFlags(aChromeFlags) michael@0: { michael@0: } michael@0: michael@0: TabParent::~TabParent() michael@0: { michael@0: } michael@0: michael@0: void michael@0: TabParent::SetOwnerElement(Element* aElement) michael@0: { michael@0: mFrameElement = aElement; michael@0: TryCacheDPIAndScale(); michael@0: } michael@0: michael@0: void michael@0: TabParent::GetAppType(nsAString& aOut) michael@0: { michael@0: aOut.Truncate(); michael@0: nsCOMPtr elem = do_QueryInterface(mFrameElement); michael@0: if (!elem) { michael@0: return; michael@0: } michael@0: michael@0: elem->GetAttr(kNameSpaceID_None, nsGkAtoms::mozapptype, aOut); michael@0: } michael@0: michael@0: bool michael@0: TabParent::IsVisible() michael@0: { michael@0: nsRefPtr frameLoader = GetFrameLoader(); michael@0: if (!frameLoader) { michael@0: return false; michael@0: } michael@0: michael@0: bool visible = false; michael@0: frameLoader->GetVisible(&visible); michael@0: return visible; michael@0: } michael@0: michael@0: void michael@0: TabParent::Destroy() michael@0: { michael@0: if (mIsDestroyed) { michael@0: return; michael@0: } michael@0: michael@0: // If this fails, it's most likely due to a content-process crash, michael@0: // and auto-cleanup will kick in. Otherwise, the child side will michael@0: // destroy itself and send back __delete__(). michael@0: unused << SendDestroy(); michael@0: michael@0: const InfallibleTArray& idbParents = michael@0: ManagedPIndexedDBParent(); michael@0: for (uint32_t i = 0; i < idbParents.Length(); ++i) { michael@0: static_cast(idbParents[i])->Disconnect(); michael@0: } michael@0: michael@0: const InfallibleTArray& ocuParents = michael@0: ManagedPOfflineCacheUpdateParent(); michael@0: for (uint32_t i = 0; i < ocuParents.Length(); ++i) { michael@0: nsRefPtr ocuParent = michael@0: static_cast(ocuParents[i]); michael@0: ocuParent->StopSendingMessagesToChild(); michael@0: } michael@0: michael@0: if (RenderFrameParent* frame = GetRenderFrame()) { michael@0: frame->Destroy(); michael@0: } michael@0: mIsDestroyed = true; michael@0: michael@0: Manager()->NotifyTabDestroying(this); michael@0: mMarkedDestroying = true; michael@0: } michael@0: michael@0: bool michael@0: TabParent::Recv__delete__() michael@0: { michael@0: Manager()->NotifyTabDestroyed(this, mMarkedDestroying); michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: TabParent::ActorDestroy(ActorDestroyReason why) michael@0: { michael@0: if (sEventCapturer == this) { michael@0: sEventCapturer = nullptr; michael@0: } michael@0: if (mIMETabParent == this) { michael@0: mIMETabParent = nullptr; michael@0: } michael@0: nsRefPtr frameLoader = GetFrameLoader(); michael@0: nsCOMPtr os = services::GetObserverService(); michael@0: nsRefPtr fmm; michael@0: if (frameLoader) { michael@0: fmm = frameLoader->GetFrameMessageManager(); michael@0: nsCOMPtr frameElement(mFrameElement); michael@0: ReceiveMessage(CHILD_PROCESS_SHUTDOWN_MESSAGE, false, nullptr, nullptr, michael@0: nullptr); michael@0: frameLoader->DestroyChild(); michael@0: michael@0: if (why == AbnormalShutdown && os) { michael@0: os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, frameLoader), michael@0: "oop-frameloader-crashed", nullptr); michael@0: nsContentUtils::DispatchTrustedEvent(frameElement->OwnerDoc(), frameElement, michael@0: NS_LITERAL_STRING("oop-browser-crashed"), michael@0: true, true); michael@0: } michael@0: } michael@0: michael@0: if (os) { michael@0: os->NotifyObservers(NS_ISUPPORTS_CAST(nsITabParent*, this), "ipc:browser-destroyed", nullptr); michael@0: } michael@0: if (fmm) { michael@0: fmm->Disconnect(); michael@0: } michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvMoveFocus(const bool& aForward) michael@0: { michael@0: nsCOMPtr fm = do_GetService(FOCUSMANAGER_CONTRACTID); michael@0: if (fm) { michael@0: nsCOMPtr dummy; michael@0: uint32_t type = aForward ? uint32_t(nsIFocusManager::MOVEFOCUS_FORWARD) michael@0: : uint32_t(nsIFocusManager::MOVEFOCUS_BACKWARD); michael@0: nsCOMPtr frame = do_QueryInterface(mFrameElement); michael@0: fm->MoveFocus(nullptr, frame, type, nsIFocusManager::FLAG_BYKEY, michael@0: getter_AddRefs(dummy)); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvEvent(const RemoteDOMEvent& aEvent) michael@0: { michael@0: nsCOMPtr event = do_QueryInterface(aEvent.mEvent); michael@0: NS_ENSURE_TRUE(event, true); michael@0: michael@0: nsCOMPtr target = do_QueryInterface(mFrameElement); michael@0: NS_ENSURE_TRUE(target, true); michael@0: michael@0: event->SetOwner(target); michael@0: michael@0: bool dummy; michael@0: target->DispatchEvent(event, &dummy); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabParent::AnswerCreateWindow(PBrowserParent** retval) michael@0: { michael@0: if (!mBrowserDOMWindow) { michael@0: return false; michael@0: } michael@0: michael@0: // Only non-app, non-browser processes may call CreateWindow. michael@0: if (IsBrowserOrApp()) { michael@0: return false; michael@0: } michael@0: michael@0: // Get a new rendering area from the browserDOMWin. We don't want michael@0: // to be starting any loads here, so get it with a null URI. michael@0: nsCOMPtr frameLoaderOwner; michael@0: mBrowserDOMWindow->OpenURIInFrame(nullptr, nullptr, michael@0: nsIBrowserDOMWindow::OPEN_NEWTAB, michael@0: nsIBrowserDOMWindow::OPEN_NEW, michael@0: getter_AddRefs(frameLoaderOwner)); michael@0: if (!frameLoaderOwner) { michael@0: return false; michael@0: } michael@0: michael@0: nsRefPtr frameLoader = frameLoaderOwner->GetFrameLoader(); michael@0: if (!frameLoader) { michael@0: return false; michael@0: } michael@0: michael@0: *retval = frameLoader->GetRemoteBrowser(); michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: TabParent::LoadURL(nsIURI* aURI) michael@0: { michael@0: MOZ_ASSERT(aURI); michael@0: michael@0: if (mIsDestroyed) { michael@0: return; michael@0: } michael@0: michael@0: nsCString spec; michael@0: aURI->GetSpec(spec); michael@0: michael@0: if (!mShown) { michael@0: NS_WARNING(nsPrintfCString("TabParent::LoadURL(%s) called before " michael@0: "Show(). Ignoring LoadURL.\n", michael@0: spec.get()).get()); michael@0: return; michael@0: } michael@0: michael@0: unused << SendLoadURL(spec); michael@0: michael@0: // If this app is a packaged app then we can speed startup by sending over michael@0: // the file descriptor for the "application.zip" file that it will michael@0: // invariably request. Only do this once. michael@0: if (!mAppPackageFileDescriptorSent) { michael@0: mAppPackageFileDescriptorSent = true; michael@0: michael@0: nsCOMPtr app = GetOwnOrContainingApp(); michael@0: if (app) { michael@0: nsString manifestURL; michael@0: nsresult rv = app->GetManifestURL(manifestURL); michael@0: NS_ENSURE_SUCCESS_VOID(rv); michael@0: michael@0: if (StringBeginsWith(manifestURL, NS_LITERAL_STRING("app:"))) { michael@0: nsString basePath; michael@0: rv = app->GetBasePath(basePath); michael@0: NS_ENSURE_SUCCESS_VOID(rv); michael@0: michael@0: nsString appId; michael@0: rv = app->GetId(appId); michael@0: NS_ENSURE_SUCCESS_VOID(rv); michael@0: michael@0: nsCOMPtr packageFile; michael@0: rv = NS_NewLocalFile(basePath, false, michael@0: getter_AddRefs(packageFile)); michael@0: NS_ENSURE_SUCCESS_VOID(rv); michael@0: michael@0: rv = packageFile->Append(appId); michael@0: NS_ENSURE_SUCCESS_VOID(rv); michael@0: michael@0: rv = packageFile->Append(NS_LITERAL_STRING("application.zip")); michael@0: NS_ENSURE_SUCCESS_VOID(rv); michael@0: michael@0: nsString path; michael@0: rv = packageFile->GetPath(path); michael@0: NS_ENSURE_SUCCESS_VOID(rv); michael@0: michael@0: nsRefPtr openFileRunnable = michael@0: new OpenFileAndSendFDRunnable(path, this); michael@0: openFileRunnable->Dispatch(); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: void michael@0: TabParent::Show(const nsIntSize& size) michael@0: { michael@0: // sigh michael@0: mShown = true; michael@0: mDimensions = size; michael@0: if (!mIsDestroyed) { michael@0: unused << SendShow(size); michael@0: } michael@0: } michael@0: michael@0: void michael@0: TabParent::UpdateDimensions(const nsRect& rect, const nsIntSize& size) michael@0: { michael@0: if (mIsDestroyed) { michael@0: return; michael@0: } michael@0: hal::ScreenConfiguration config; michael@0: hal::GetCurrentScreenConfiguration(&config); michael@0: ScreenOrientation orientation = config.orientation(); michael@0: michael@0: if (!mUpdatedDimensions || mOrientation != orientation || michael@0: mDimensions != size || !mRect.IsEqualEdges(rect)) { michael@0: mUpdatedDimensions = true; michael@0: mRect = rect; michael@0: mDimensions = size; michael@0: mOrientation = orientation; michael@0: michael@0: unused << SendUpdateDimensions(mRect, mDimensions, mOrientation); michael@0: } michael@0: } michael@0: michael@0: void michael@0: TabParent::UpdateFrame(const FrameMetrics& aFrameMetrics) michael@0: { michael@0: if (!mIsDestroyed) { michael@0: unused << SendUpdateFrame(aFrameMetrics); michael@0: } michael@0: } michael@0: michael@0: void michael@0: TabParent::AcknowledgeScrollUpdate(const ViewID& aScrollId, const uint32_t& aScrollGeneration) michael@0: { michael@0: if (!mIsDestroyed) { michael@0: unused << SendAcknowledgeScrollUpdate(aScrollId, aScrollGeneration); michael@0: } michael@0: } michael@0: michael@0: void TabParent::HandleDoubleTap(const CSSPoint& aPoint, michael@0: int32_t aModifiers, michael@0: const ScrollableLayerGuid &aGuid) michael@0: { michael@0: if (!mIsDestroyed) { michael@0: unused << SendHandleDoubleTap(aPoint, aGuid); michael@0: } michael@0: } michael@0: michael@0: void TabParent::HandleSingleTap(const CSSPoint& aPoint, michael@0: int32_t aModifiers, michael@0: const ScrollableLayerGuid &aGuid) michael@0: { michael@0: // TODO Send the modifier data to TabChild for use in mouse events. michael@0: if (!mIsDestroyed) { michael@0: unused << SendHandleSingleTap(aPoint, aGuid); michael@0: } michael@0: } michael@0: michael@0: void TabParent::HandleLongTap(const CSSPoint& aPoint, michael@0: int32_t aModifiers, michael@0: const ScrollableLayerGuid &aGuid) michael@0: { michael@0: if (!mIsDestroyed) { michael@0: unused << SendHandleLongTap(aPoint, aGuid); michael@0: } michael@0: } michael@0: michael@0: void TabParent::HandleLongTapUp(const CSSPoint& aPoint, michael@0: int32_t aModifiers, michael@0: const ScrollableLayerGuid &aGuid) michael@0: { michael@0: if (!mIsDestroyed) { michael@0: unused << SendHandleLongTapUp(aPoint, aGuid); michael@0: } michael@0: } michael@0: michael@0: void TabParent::NotifyAPZStateChange(ViewID aViewId, michael@0: APZStateChange aChange, michael@0: int aArg) michael@0: { michael@0: if (!mIsDestroyed) { michael@0: unused << SendNotifyAPZStateChange(aViewId, aChange, aArg); michael@0: } michael@0: } michael@0: michael@0: void michael@0: TabParent::Activate() michael@0: { michael@0: if (!mIsDestroyed) { michael@0: unused << SendActivate(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: TabParent::Deactivate() michael@0: { michael@0: if (!mIsDestroyed) { michael@0: unused << SendDeactivate(); michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: TabParent::Init(nsIDOMWindow *window) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: TabParent::GetState(uint32_t *aState) michael@0: { michael@0: NS_ENSURE_ARG(aState); michael@0: NS_WARNING("SecurityState not valid here"); michael@0: *aState = 0; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: TabParent::SetDocShell(nsIDocShell *aDocShell) michael@0: { michael@0: NS_ENSURE_ARG(aDocShell); michael@0: NS_WARNING("No mDocShell member in TabParent so there is no docShell to set"); michael@0: return NS_OK; michael@0: } michael@0: michael@0: PDocumentRendererParent* michael@0: TabParent::AllocPDocumentRendererParent(const nsRect& documentRect, michael@0: const gfx::Matrix& transform, michael@0: const nsString& bgcolor, michael@0: const uint32_t& renderFlags, michael@0: const bool& flushLayout, michael@0: const nsIntSize& renderSize) michael@0: { michael@0: return new DocumentRendererParent(); michael@0: } michael@0: michael@0: bool michael@0: TabParent::DeallocPDocumentRendererParent(PDocumentRendererParent* actor) michael@0: { michael@0: delete actor; michael@0: return true; michael@0: } michael@0: michael@0: PContentPermissionRequestParent* michael@0: TabParent::AllocPContentPermissionRequestParent(const InfallibleTArray& aRequests, michael@0: const IPC::Principal& aPrincipal) michael@0: { michael@0: return CreateContentPermissionRequestParent(aRequests, mFrameElement, aPrincipal); michael@0: } michael@0: michael@0: bool michael@0: TabParent::DeallocPContentPermissionRequestParent(PContentPermissionRequestParent* actor) michael@0: { michael@0: delete actor; michael@0: return true; michael@0: } michael@0: michael@0: PFilePickerParent* michael@0: TabParent::AllocPFilePickerParent(const nsString& aTitle, const int16_t& aMode) michael@0: { michael@0: return new FilePickerParent(aTitle, aMode); michael@0: } michael@0: michael@0: bool michael@0: TabParent::DeallocPFilePickerParent(PFilePickerParent* actor) michael@0: { michael@0: delete actor; michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: TabParent::SendMouseEvent(const nsAString& aType, float aX, float aY, michael@0: int32_t aButton, int32_t aClickCount, michael@0: int32_t aModifiers, bool aIgnoreRootScrollFrame) michael@0: { michael@0: if (!mIsDestroyed) { michael@0: unused << PBrowserParent::SendMouseEvent(nsString(aType), aX, aY, michael@0: aButton, aClickCount, michael@0: aModifiers, aIgnoreRootScrollFrame); michael@0: } michael@0: } michael@0: michael@0: void michael@0: TabParent::SendKeyEvent(const nsAString& aType, michael@0: int32_t aKeyCode, michael@0: int32_t aCharCode, michael@0: int32_t aModifiers, michael@0: bool aPreventDefault) michael@0: { michael@0: if (!mIsDestroyed) { michael@0: unused << PBrowserParent::SendKeyEvent(nsString(aType), aKeyCode, aCharCode, michael@0: aModifiers, aPreventDefault); michael@0: } michael@0: } michael@0: michael@0: bool michael@0: TabParent::MapEventCoordinatesForChildProcess(WidgetEvent* aEvent) michael@0: { michael@0: nsRefPtr frameLoader = GetFrameLoader(); michael@0: if (!frameLoader) { michael@0: return false; michael@0: } michael@0: LayoutDeviceIntPoint offset = michael@0: EventStateManager::GetChildProcessOffset(frameLoader, *aEvent); michael@0: MapEventCoordinatesForChildProcess(offset, aEvent); michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: TabParent::MapEventCoordinatesForChildProcess( michael@0: const LayoutDeviceIntPoint& aOffset, WidgetEvent* aEvent) michael@0: { michael@0: if (aEvent->eventStructType != NS_TOUCH_EVENT) { michael@0: aEvent->refPoint = aOffset; michael@0: } else { michael@0: aEvent->refPoint = LayoutDeviceIntPoint(); michael@0: // Then offset all the touch points by that distance, to put them michael@0: // in the space where top-left is 0,0. michael@0: const nsTArray< nsRefPtr >& touches = michael@0: aEvent->AsTouchEvent()->touches; michael@0: for (uint32_t i = 0; i < touches.Length(); ++i) { michael@0: Touch* touch = touches[i]; michael@0: if (touch) { michael@0: touch->mRefPoint += LayoutDeviceIntPoint::ToUntyped(aOffset); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: bool TabParent::SendRealMouseEvent(WidgetMouseEvent& event) michael@0: { michael@0: if (mIsDestroyed) { michael@0: return false; michael@0: } michael@0: MaybeForwardEventToRenderFrame(event, nullptr); michael@0: if (!MapEventCoordinatesForChildProcess(&event)) { michael@0: return false; michael@0: } michael@0: return PBrowserParent::SendRealMouseEvent(event); michael@0: } michael@0: michael@0: CSSPoint TabParent::AdjustTapToChildWidget(const CSSPoint& aPoint) michael@0: { michael@0: nsCOMPtr content = do_QueryInterface(mFrameElement); michael@0: michael@0: if (!content || !content->OwnerDoc()) { michael@0: return aPoint; michael@0: } michael@0: michael@0: nsIDocument* doc = content->OwnerDoc(); michael@0: if (!doc || !doc->GetShell()) { michael@0: return aPoint; michael@0: } michael@0: nsPresContext* presContext = doc->GetShell()->GetPresContext(); michael@0: michael@0: return aPoint + CSSPoint( michael@0: presContext->DevPixelsToFloatCSSPixels(mChildProcessOffsetAtTouchStart.x), michael@0: presContext->DevPixelsToFloatCSSPixels(mChildProcessOffsetAtTouchStart.y)); michael@0: } michael@0: michael@0: bool TabParent::SendHandleSingleTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid) michael@0: { michael@0: if (mIsDestroyed) { michael@0: return false; michael@0: } michael@0: michael@0: return PBrowserParent::SendHandleSingleTap(AdjustTapToChildWidget(aPoint), aGuid); michael@0: } michael@0: michael@0: bool TabParent::SendHandleLongTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid) michael@0: { michael@0: if (mIsDestroyed) { michael@0: return false; michael@0: } michael@0: michael@0: return PBrowserParent::SendHandleLongTap(AdjustTapToChildWidget(aPoint), aGuid); michael@0: } michael@0: michael@0: bool TabParent::SendHandleLongTapUp(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid) michael@0: { michael@0: if (mIsDestroyed) { michael@0: return false; michael@0: } michael@0: michael@0: return PBrowserParent::SendHandleLongTapUp(AdjustTapToChildWidget(aPoint), aGuid); michael@0: } michael@0: michael@0: bool TabParent::SendHandleDoubleTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid) michael@0: { michael@0: if (mIsDestroyed) { michael@0: return false; michael@0: } michael@0: michael@0: return PBrowserParent::SendHandleDoubleTap(AdjustTapToChildWidget(aPoint), aGuid); michael@0: } michael@0: michael@0: bool TabParent::SendMouseWheelEvent(WidgetWheelEvent& event) michael@0: { michael@0: if (mIsDestroyed) { michael@0: return false; michael@0: } michael@0: MaybeForwardEventToRenderFrame(event, nullptr); michael@0: if (!MapEventCoordinatesForChildProcess(&event)) { michael@0: return false; michael@0: } michael@0: return PBrowserParent::SendMouseWheelEvent(event); michael@0: } michael@0: michael@0: static void michael@0: DoCommandCallback(mozilla::Command aCommand, void* aData) michael@0: { michael@0: static_cast*>(aData)->AppendElement(aCommand); michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvRequestNativeKeyBindings(const WidgetKeyboardEvent& aEvent, michael@0: MaybeNativeKeyBinding* aBindings) michael@0: { michael@0: AutoInfallibleTArray singleLine; michael@0: AutoInfallibleTArray multiLine; michael@0: AutoInfallibleTArray richText; michael@0: michael@0: *aBindings = mozilla::void_t(); michael@0: michael@0: nsCOMPtr widget = GetWidget(); michael@0: if (!widget) { michael@0: return true; michael@0: } michael@0: michael@0: WidgetKeyboardEvent localEvent(aEvent); michael@0: michael@0: if (NS_FAILED(widget->AttachNativeKeyEvent(localEvent))) { michael@0: return true; michael@0: } michael@0: michael@0: widget->ExecuteNativeKeyBinding(nsIWidget::NativeKeyBindingsForSingleLineEditor, michael@0: localEvent, DoCommandCallback, &singleLine); michael@0: widget->ExecuteNativeKeyBinding(nsIWidget::NativeKeyBindingsForMultiLineEditor, michael@0: localEvent, DoCommandCallback, &multiLine); michael@0: widget->ExecuteNativeKeyBinding(nsIWidget::NativeKeyBindingsForRichTextEditor, michael@0: localEvent, DoCommandCallback, &richText); michael@0: michael@0: if (!singleLine.IsEmpty() || !multiLine.IsEmpty() || !richText.IsEmpty()) { michael@0: *aBindings = NativeKeyBinding(singleLine, multiLine, richText); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool TabParent::SendRealKeyEvent(WidgetKeyboardEvent& event) michael@0: { michael@0: if (mIsDestroyed) { michael@0: return false; michael@0: } michael@0: MaybeForwardEventToRenderFrame(event, nullptr); michael@0: if (!MapEventCoordinatesForChildProcess(&event)) { michael@0: return false; michael@0: } michael@0: michael@0: michael@0: MaybeNativeKeyBinding bindings; michael@0: bindings = void_t(); michael@0: if (event.message == NS_KEY_PRESS) { michael@0: nsCOMPtr widget = GetWidget(); michael@0: michael@0: AutoInfallibleTArray singleLine; michael@0: AutoInfallibleTArray multiLine; michael@0: AutoInfallibleTArray richText; michael@0: michael@0: widget->ExecuteNativeKeyBinding(nsIWidget::NativeKeyBindingsForSingleLineEditor, michael@0: event, DoCommandCallback, &singleLine); michael@0: widget->ExecuteNativeKeyBinding(nsIWidget::NativeKeyBindingsForMultiLineEditor, michael@0: event, DoCommandCallback, &multiLine); michael@0: widget->ExecuteNativeKeyBinding(nsIWidget::NativeKeyBindingsForRichTextEditor, michael@0: event, DoCommandCallback, &richText); michael@0: michael@0: if (!singleLine.IsEmpty() || !multiLine.IsEmpty() || !richText.IsEmpty()) { michael@0: bindings = NativeKeyBinding(singleLine, multiLine, richText); michael@0: } michael@0: } michael@0: michael@0: return PBrowserParent::SendRealKeyEvent(event, bindings); michael@0: } michael@0: michael@0: bool TabParent::SendRealTouchEvent(WidgetTouchEvent& event) michael@0: { michael@0: if (mIsDestroyed) { michael@0: return false; michael@0: } michael@0: if (event.message == NS_TOUCH_START) { michael@0: // Adjust the widget coordinates to be relative to our frame. michael@0: nsRefPtr frameLoader = GetFrameLoader(); michael@0: if (!frameLoader) { michael@0: // No frame anymore? michael@0: sEventCapturer = nullptr; michael@0: return false; michael@0: } michael@0: michael@0: mChildProcessOffsetAtTouchStart = michael@0: EventStateManager::GetChildProcessOffset(frameLoader, event); michael@0: michael@0: MOZ_ASSERT((!sEventCapturer && mEventCaptureDepth == 0) || michael@0: (sEventCapturer == this && mEventCaptureDepth > 0)); michael@0: // We want to capture all remaining touch events in this series michael@0: // for fast-path dispatch. michael@0: sEventCapturer = this; michael@0: ++mEventCaptureDepth; michael@0: } michael@0: michael@0: // PresShell::HandleEventInternal adds touches on touch end/cancel. This michael@0: // confuses remote content and the panning and zooming logic into thinking michael@0: // that the added touches are part of the touchend/cancel, when actually michael@0: // they're not. michael@0: if (event.message == NS_TOUCH_END || event.message == NS_TOUCH_CANCEL) { michael@0: for (int i = event.touches.Length() - 1; i >= 0; i--) { michael@0: if (!event.touches[i]->mChanged) { michael@0: event.touches.RemoveElementAt(i); michael@0: } michael@0: } michael@0: } michael@0: michael@0: ScrollableLayerGuid guid; michael@0: MaybeForwardEventToRenderFrame(event, &guid); michael@0: michael@0: if (mIsDestroyed) { michael@0: return false; michael@0: } michael@0: michael@0: MapEventCoordinatesForChildProcess(mChildProcessOffsetAtTouchStart, &event); michael@0: michael@0: return (event.message == NS_TOUCH_MOVE) ? michael@0: PBrowserParent::SendRealTouchMoveEvent(event, guid) : michael@0: PBrowserParent::SendRealTouchEvent(event, guid); michael@0: } michael@0: michael@0: /*static*/ TabParent* michael@0: TabParent::GetEventCapturer() michael@0: { michael@0: return sEventCapturer; michael@0: } michael@0: michael@0: bool michael@0: TabParent::TryCapture(const WidgetGUIEvent& aEvent) michael@0: { michael@0: MOZ_ASSERT(sEventCapturer == this && mEventCaptureDepth > 0); michael@0: michael@0: if (aEvent.eventStructType != NS_TOUCH_EVENT) { michael@0: // Only capture of touch events is implemented, for now. michael@0: return false; michael@0: } michael@0: michael@0: WidgetTouchEvent event(*aEvent.AsTouchEvent()); michael@0: michael@0: bool isTouchPointUp = (event.message == NS_TOUCH_END || michael@0: event.message == NS_TOUCH_CANCEL); michael@0: if (event.message == NS_TOUCH_START || isTouchPointUp) { michael@0: // Let the DOM see touch start/end events so that its touch-point michael@0: // state stays consistent. michael@0: if (isTouchPointUp && 0 == --mEventCaptureDepth) { michael@0: // All event series are un-captured, don't try to catch any michael@0: // more. michael@0: sEventCapturer = nullptr; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: SendRealTouchEvent(event); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvSyncMessage(const nsString& aMessage, michael@0: const ClonedMessageData& aData, michael@0: const InfallibleTArray& aCpows, michael@0: const IPC::Principal& aPrincipal, michael@0: InfallibleTArray* aJSONRetVal) michael@0: { michael@0: nsIPrincipal* principal = aPrincipal; michael@0: ContentParent* parent = static_cast(Manager()); michael@0: if (!Preferences::GetBool("dom.testing.ignore_ipc_principal", false) && michael@0: principal && !AssertAppPrincipal(parent, principal)) { michael@0: return false; michael@0: } michael@0: michael@0: StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData); michael@0: CpowIdHolder cpows(parent->GetCPOWManager(), aCpows); michael@0: return ReceiveMessage(aMessage, true, &cloneData, &cpows, aPrincipal, aJSONRetVal); michael@0: } michael@0: michael@0: bool michael@0: TabParent::AnswerRpcMessage(const nsString& aMessage, michael@0: const ClonedMessageData& aData, michael@0: const InfallibleTArray& aCpows, michael@0: const IPC::Principal& aPrincipal, michael@0: InfallibleTArray* aJSONRetVal) michael@0: { michael@0: nsIPrincipal* principal = aPrincipal; michael@0: ContentParent* parent = static_cast(Manager()); michael@0: if (!Preferences::GetBool("dom.testing.ignore_ipc_principal", false) && michael@0: principal && !AssertAppPrincipal(parent, principal)) { michael@0: return false; michael@0: } michael@0: michael@0: StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData); michael@0: CpowIdHolder cpows(parent->GetCPOWManager(), aCpows); michael@0: return ReceiveMessage(aMessage, true, &cloneData, &cpows, aPrincipal, aJSONRetVal); michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvAsyncMessage(const nsString& aMessage, michael@0: const ClonedMessageData& aData, michael@0: const InfallibleTArray& aCpows, michael@0: const IPC::Principal& aPrincipal) michael@0: { michael@0: nsIPrincipal* principal = aPrincipal; michael@0: ContentParent* parent = static_cast(Manager()); michael@0: if (!Preferences::GetBool("dom.testing.ignore_ipc_principal", false) && michael@0: principal && !AssertAppPrincipal(parent, principal)) { michael@0: return false; michael@0: } michael@0: michael@0: StructuredCloneData cloneData = ipc::UnpackClonedMessageDataForParent(aData); michael@0: CpowIdHolder cpows(parent->GetCPOWManager(), aCpows); michael@0: return ReceiveMessage(aMessage, false, &cloneData, &cpows, aPrincipal, nullptr); michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvSetCursor(const uint32_t& aCursor) michael@0: { michael@0: nsCOMPtr widget = GetWidget(); michael@0: if (widget) { michael@0: widget->SetCursor((nsCursor) aCursor); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvSetBackgroundColor(const nscolor& aColor) michael@0: { michael@0: if (RenderFrameParent* frame = GetRenderFrame()) { michael@0: frame->SetBackgroundColor(aColor); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: nsIXULBrowserWindow* michael@0: TabParent::GetXULBrowserWindow() michael@0: { michael@0: nsCOMPtr frame = do_QueryInterface(mFrameElement); michael@0: if (!frame) { michael@0: return nullptr; michael@0: } michael@0: michael@0: nsCOMPtr docShell = frame->OwnerDoc()->GetDocShell(); michael@0: if (!docShell) { michael@0: return nullptr; michael@0: } michael@0: michael@0: nsCOMPtr treeOwner; michael@0: docShell->GetTreeOwner(getter_AddRefs(treeOwner)); michael@0: if (!treeOwner) { michael@0: return nullptr; michael@0: } michael@0: michael@0: nsCOMPtr window = do_GetInterface(treeOwner); michael@0: if (!window) { michael@0: return nullptr; michael@0: } michael@0: michael@0: nsCOMPtr xulBrowserWindow; michael@0: window->GetXULBrowserWindow(getter_AddRefs(xulBrowserWindow)); michael@0: return xulBrowserWindow; michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvSetStatus(const uint32_t& aType, const nsString& aStatus) michael@0: { michael@0: nsCOMPtr xulBrowserWindow = GetXULBrowserWindow(); michael@0: if (!xulBrowserWindow) { michael@0: return true; michael@0: } michael@0: michael@0: switch (aType) { michael@0: case nsIWebBrowserChrome::STATUS_SCRIPT: michael@0: xulBrowserWindow->SetJSStatus(aStatus); michael@0: break; michael@0: case nsIWebBrowserChrome::STATUS_LINK: michael@0: xulBrowserWindow->SetOverLink(aStatus, nullptr); michael@0: break; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvShowTooltip(const uint32_t& aX, const uint32_t& aY, const nsString& aTooltip) michael@0: { michael@0: nsCOMPtr xulBrowserWindow = GetXULBrowserWindow(); michael@0: if (!xulBrowserWindow) { michael@0: return true; michael@0: } michael@0: michael@0: xulBrowserWindow->ShowTooltip(aX, aY, aTooltip); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvHideTooltip() michael@0: { michael@0: nsCOMPtr xulBrowserWindow = GetXULBrowserWindow(); michael@0: if (!xulBrowserWindow) { michael@0: return true; michael@0: } michael@0: michael@0: xulBrowserWindow->HideTooltip(); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvNotifyIMEFocus(const bool& aFocus, michael@0: nsIMEUpdatePreference* aPreference, michael@0: uint32_t* aSeqno) michael@0: { michael@0: nsCOMPtr widget = GetWidget(); michael@0: if (!widget) { michael@0: *aPreference = nsIMEUpdatePreference(); michael@0: return true; michael@0: } michael@0: michael@0: *aSeqno = mIMESeqno; michael@0: mIMETabParent = aFocus ? this : nullptr; michael@0: mIMESelectionAnchor = 0; michael@0: mIMESelectionFocus = 0; michael@0: widget->NotifyIME(IMENotification(aFocus ? NOTIFY_IME_OF_FOCUS : michael@0: NOTIFY_IME_OF_BLUR)); michael@0: michael@0: if (aFocus) { michael@0: *aPreference = widget->GetIMEUpdatePreference(); michael@0: } else { michael@0: mIMECacheText.Truncate(0); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvNotifyIMETextChange(const uint32_t& aStart, michael@0: const uint32_t& aEnd, michael@0: const uint32_t& aNewEnd, michael@0: const bool& aCausedByComposition) michael@0: { michael@0: nsCOMPtr widget = GetWidget(); michael@0: if (!widget) michael@0: return true; michael@0: michael@0: #ifdef DEBUG michael@0: nsIMEUpdatePreference updatePreference = widget->GetIMEUpdatePreference(); michael@0: NS_ASSERTION(updatePreference.WantTextChange(), michael@0: "Don't call Send/RecvNotifyIMETextChange without NOTIFY_TEXT_CHANGE"); michael@0: MOZ_ASSERT(!aCausedByComposition || michael@0: updatePreference.WantChangesCausedByComposition(), michael@0: "The widget doesn't want text change notification caused by composition"); michael@0: #endif michael@0: michael@0: IMENotification notification(NOTIFY_IME_OF_TEXT_CHANGE); michael@0: notification.mTextChangeData.mStartOffset = aStart; michael@0: notification.mTextChangeData.mOldEndOffset = aEnd; michael@0: notification.mTextChangeData.mNewEndOffset = aNewEnd; michael@0: notification.mTextChangeData.mCausedByComposition = aCausedByComposition; michael@0: widget->NotifyIME(notification); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvNotifyIMESelectedCompositionRect(const uint32_t& aOffset, michael@0: const nsIntRect& aRect, michael@0: const nsIntRect& aCaretRect) michael@0: { michael@0: // add rect to cache for another query michael@0: mIMECompositionRectOffset = aOffset; michael@0: mIMECompositionRect = aRect; michael@0: mIMECaretRect = aCaretRect; michael@0: michael@0: nsCOMPtr widget = GetWidget(); michael@0: if (!widget) { michael@0: return true; michael@0: } michael@0: widget->NotifyIME(IMENotification(NOTIFY_IME_OF_COMPOSITION_UPDATE)); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvNotifyIMESelection(const uint32_t& aSeqno, michael@0: const uint32_t& aAnchor, michael@0: const uint32_t& aFocus, michael@0: const bool& aCausedByComposition) michael@0: { michael@0: nsCOMPtr widget = GetWidget(); michael@0: if (!widget) michael@0: return true; michael@0: michael@0: if (aSeqno == mIMESeqno) { michael@0: mIMESelectionAnchor = aAnchor; michael@0: mIMESelectionFocus = aFocus; michael@0: const nsIMEUpdatePreference updatePreference = michael@0: widget->GetIMEUpdatePreference(); michael@0: if (updatePreference.WantSelectionChange() && michael@0: (updatePreference.WantChangesCausedByComposition() || michael@0: !aCausedByComposition)) { michael@0: IMENotification notification(NOTIFY_IME_OF_SELECTION_CHANGE); michael@0: notification.mSelectionChangeData.mCausedByComposition = michael@0: aCausedByComposition; michael@0: widget->NotifyIME(notification); michael@0: } michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvNotifyIMETextHint(const nsString& aText) michael@0: { michael@0: // Replace our cache with new text michael@0: mIMECacheText = aText; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvRequestFocus(const bool& aCanRaise) michael@0: { michael@0: nsCOMPtr fm = nsFocusManager::GetFocusManager(); michael@0: if (!fm) { michael@0: return true; michael@0: } michael@0: michael@0: nsCOMPtr content = do_QueryInterface(mFrameElement); michael@0: if (!content || !content->OwnerDoc()) { michael@0: return true; michael@0: } michael@0: michael@0: uint32_t flags = nsIFocusManager::FLAG_NOSCROLL; michael@0: if (aCanRaise) michael@0: flags |= nsIFocusManager::FLAG_RAISE; michael@0: michael@0: nsCOMPtr node = do_QueryInterface(mFrameElement); michael@0: fm->SetFocus(node, flags); michael@0: return true; michael@0: } michael@0: michael@0: nsIntPoint michael@0: TabParent::GetChildProcessOffset() michael@0: { michael@0: // The "toplevel widget" in child processes is always at position michael@0: // 0,0. Map the event coordinates to match that. michael@0: michael@0: nsIntPoint offset(0, 0); michael@0: nsRefPtr frameLoader = GetFrameLoader(); michael@0: if (!frameLoader) { michael@0: return offset; michael@0: } michael@0: nsIFrame* targetFrame = frameLoader->GetPrimaryFrameOfOwningContent(); michael@0: if (!targetFrame) { michael@0: return offset; michael@0: } michael@0: michael@0: // Find out how far we're offset from the nearest widget. michael@0: nsCOMPtr widget = GetWidget(); michael@0: if (!widget) { michael@0: return offset; michael@0: } michael@0: nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(widget, michael@0: nsIntPoint(0, 0), michael@0: targetFrame); michael@0: michael@0: return LayoutDeviceIntPoint::ToUntyped(LayoutDeviceIntPoint::FromAppUnitsToNearest( michael@0: pt, targetFrame->PresContext()->AppUnitsPerDevPixel())); michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvReplyKeyEvent(const WidgetKeyboardEvent& event) michael@0: { michael@0: NS_ENSURE_TRUE(mFrameElement, true); michael@0: michael@0: WidgetKeyboardEvent localEvent(event); michael@0: // Set mNoCrossProcessBoundaryForwarding to avoid this event from michael@0: // being infinitely redispatched and forwarded to the child again. michael@0: localEvent.mFlags.mNoCrossProcessBoundaryForwarding = true; michael@0: michael@0: // Here we convert the WidgetEvent that we received to an nsIDOMEvent michael@0: // to be able to dispatch it to the element as the target element. michael@0: nsIDocument* doc = mFrameElement->OwnerDoc(); michael@0: nsIPresShell* presShell = doc->GetShell(); michael@0: NS_ENSURE_TRUE(presShell, true); michael@0: nsPresContext* presContext = presShell->GetPresContext(); michael@0: NS_ENSURE_TRUE(presContext, true); michael@0: michael@0: EventDispatcher::Dispatch(mFrameElement, presContext, &localEvent); michael@0: return true; michael@0: } michael@0: michael@0: /** michael@0: * Try to answer query event using cached text. michael@0: * michael@0: * For NS_QUERY_SELECTED_TEXT, fail if the cache doesn't contain the whole michael@0: * selected range. (This shouldn't happen because PuppetWidget should have michael@0: * already sent the whole selection.) michael@0: * michael@0: * For NS_QUERY_TEXT_CONTENT, fail only if the cache doesn't overlap with michael@0: * the queried range. Note the difference from above. We use michael@0: * this behavior because a normal NS_QUERY_TEXT_CONTENT event is allowed to michael@0: * have out-of-bounds offsets, so that widget can request content without michael@0: * knowing the exact length of text. It's up to widget to handle cases when michael@0: * the returned offset/length are different from the queried offset/length. michael@0: * michael@0: * For NS_QUERY_TEXT_RECT, fail if cached offset/length aren't equals to input. michael@0: * Cocoa widget always queries selected offset, so it works on it. michael@0: * michael@0: * For NS_QUERY_CARET_RECT, fail if cached offset isn't equals to input michael@0: */ michael@0: bool michael@0: TabParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent) michael@0: { michael@0: aEvent.mSucceeded = false; michael@0: aEvent.mWasAsync = false; michael@0: aEvent.mReply.mFocusedWidget = nsCOMPtr(GetWidget()).get(); michael@0: michael@0: switch (aEvent.message) michael@0: { michael@0: case NS_QUERY_SELECTED_TEXT: michael@0: { michael@0: aEvent.mReply.mOffset = std::min(mIMESelectionAnchor, mIMESelectionFocus); michael@0: if (mIMESelectionAnchor == mIMESelectionFocus) { michael@0: aEvent.mReply.mString.Truncate(0); michael@0: } else { michael@0: if (mIMESelectionAnchor > mIMECacheText.Length() || michael@0: mIMESelectionFocus > mIMECacheText.Length()) { michael@0: break; michael@0: } michael@0: uint32_t selLen = mIMESelectionAnchor > mIMESelectionFocus ? michael@0: mIMESelectionAnchor - mIMESelectionFocus : michael@0: mIMESelectionFocus - mIMESelectionAnchor; michael@0: aEvent.mReply.mString = Substring(mIMECacheText, michael@0: aEvent.mReply.mOffset, michael@0: selLen); michael@0: } michael@0: aEvent.mReply.mReversed = mIMESelectionFocus < mIMESelectionAnchor; michael@0: aEvent.mReply.mHasSelection = true; michael@0: aEvent.mSucceeded = true; michael@0: } michael@0: break; michael@0: case NS_QUERY_TEXT_CONTENT: michael@0: { michael@0: uint32_t inputOffset = aEvent.mInput.mOffset, michael@0: inputEnd = inputOffset + aEvent.mInput.mLength; michael@0: michael@0: if (inputEnd > mIMECacheText.Length()) { michael@0: inputEnd = mIMECacheText.Length(); michael@0: } michael@0: if (inputEnd < inputOffset) { michael@0: break; michael@0: } michael@0: aEvent.mReply.mOffset = inputOffset; michael@0: aEvent.mReply.mString = Substring(mIMECacheText, michael@0: inputOffset, michael@0: inputEnd - inputOffset); michael@0: aEvent.mSucceeded = true; michael@0: } michael@0: break; michael@0: case NS_QUERY_TEXT_RECT: michael@0: { michael@0: if (aEvent.mInput.mOffset != mIMECompositionRectOffset || michael@0: aEvent.mInput.mLength != 1) { michael@0: break; michael@0: } michael@0: michael@0: aEvent.mReply.mOffset = mIMECompositionRectOffset; michael@0: aEvent.mReply.mRect = mIMECompositionRect - GetChildProcessOffset(); michael@0: aEvent.mSucceeded = true; michael@0: } michael@0: break; michael@0: case NS_QUERY_CARET_RECT: michael@0: { michael@0: if (aEvent.mInput.mOffset != mIMECompositionRectOffset) { michael@0: break; michael@0: } michael@0: michael@0: aEvent.mReply.mOffset = mIMECompositionRectOffset; michael@0: aEvent.mReply.mRect = mIMECaretRect - GetChildProcessOffset(); michael@0: aEvent.mSucceeded = true; michael@0: } michael@0: break; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabParent::SendCompositionEvent(WidgetCompositionEvent& event) michael@0: { michael@0: if (mIsDestroyed) { michael@0: return false; michael@0: } michael@0: mIMEComposing = event.message != NS_COMPOSITION_END; michael@0: mIMECompositionStart = std::min(mIMESelectionAnchor, mIMESelectionFocus); michael@0: if (mIMECompositionEnding) michael@0: return true; michael@0: event.mSeqno = ++mIMESeqno; michael@0: return PBrowserParent::SendCompositionEvent(event); michael@0: } michael@0: michael@0: /** michael@0: * During REQUEST_TO_COMMIT_COMPOSITION or REQUEST_TO_CANCEL_COMPOSITION, michael@0: * widget usually sends a NS_TEXT_TEXT event to finalize or clear the michael@0: * composition, respectively michael@0: * michael@0: * Because the event will not reach content in time, we intercept it michael@0: * here and pass the text as the EndIMEComposition return value michael@0: */ michael@0: bool michael@0: TabParent::SendTextEvent(WidgetTextEvent& event) michael@0: { michael@0: if (mIsDestroyed) { michael@0: return false; michael@0: } michael@0: if (mIMECompositionEnding) { michael@0: mIMECompositionText = event.theText; michael@0: return true; michael@0: } michael@0: michael@0: // We must be able to simulate the selection because michael@0: // we might not receive selection updates in time michael@0: if (!mIMEComposing) { michael@0: mIMECompositionStart = std::min(mIMESelectionAnchor, mIMESelectionFocus); michael@0: } michael@0: mIMESelectionAnchor = mIMESelectionFocus = michael@0: mIMECompositionStart + event.theText.Length(); michael@0: michael@0: event.mSeqno = ++mIMESeqno; michael@0: return PBrowserParent::SendTextEvent(event); michael@0: } michael@0: michael@0: bool michael@0: TabParent::SendSelectionEvent(WidgetSelectionEvent& event) michael@0: { michael@0: if (mIsDestroyed) { michael@0: return false; michael@0: } michael@0: mIMESelectionAnchor = event.mOffset + (event.mReversed ? event.mLength : 0); michael@0: mIMESelectionFocus = event.mOffset + (!event.mReversed ? event.mLength : 0); michael@0: event.mSeqno = ++mIMESeqno; michael@0: return PBrowserParent::SendSelectionEvent(event); michael@0: } michael@0: michael@0: /*static*/ TabParent* michael@0: TabParent::GetFrom(nsFrameLoader* aFrameLoader) michael@0: { michael@0: if (!aFrameLoader) { michael@0: return nullptr; michael@0: } michael@0: PBrowserParent* remoteBrowser = aFrameLoader->GetRemoteBrowser(); michael@0: return static_cast(remoteBrowser); michael@0: } michael@0: michael@0: /*static*/ TabParent* michael@0: TabParent::GetFrom(nsIContent* aContent) michael@0: { michael@0: nsCOMPtr loaderOwner = do_QueryInterface(aContent); michael@0: if (!loaderOwner) { michael@0: return nullptr; michael@0: } michael@0: nsRefPtr frameLoader = loaderOwner->GetFrameLoader(); michael@0: return GetFrom(frameLoader); michael@0: } michael@0: michael@0: RenderFrameParent* michael@0: TabParent::GetRenderFrame() michael@0: { michael@0: if (ManagedPRenderFrameParent().IsEmpty()) { michael@0: return nullptr; michael@0: } michael@0: return static_cast(ManagedPRenderFrameParent()[0]); michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvEndIMEComposition(const bool& aCancel, michael@0: nsString* aComposition) michael@0: { michael@0: nsCOMPtr widget = GetWidget(); michael@0: if (!widget) michael@0: return true; michael@0: michael@0: mIMECompositionEnding = true; michael@0: michael@0: widget->NotifyIME(IMENotification(aCancel ? REQUEST_TO_CANCEL_COMPOSITION : michael@0: REQUEST_TO_COMMIT_COMPOSITION)); michael@0: michael@0: mIMECompositionEnding = false; michael@0: *aComposition = mIMECompositionText; michael@0: mIMECompositionText.Truncate(0); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvGetInputContext(int32_t* aIMEEnabled, michael@0: int32_t* aIMEOpen, michael@0: intptr_t* aNativeIMEContext) michael@0: { michael@0: nsCOMPtr widget = GetWidget(); michael@0: if (!widget) { michael@0: *aIMEEnabled = IMEState::DISABLED; michael@0: *aIMEOpen = IMEState::OPEN_STATE_NOT_SUPPORTED; michael@0: *aNativeIMEContext = 0; michael@0: return true; michael@0: } michael@0: michael@0: InputContext context = widget->GetInputContext(); michael@0: *aIMEEnabled = static_cast(context.mIMEState.mEnabled); michael@0: *aIMEOpen = static_cast(context.mIMEState.mOpen); michael@0: *aNativeIMEContext = reinterpret_cast(context.mNativeIMEContext); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvSetInputContext(const int32_t& aIMEEnabled, michael@0: const int32_t& aIMEOpen, michael@0: const nsString& aType, michael@0: const nsString& aInputmode, michael@0: const nsString& aActionHint, michael@0: const int32_t& aCause, michael@0: const int32_t& aFocusChange) michael@0: { michael@0: // mIMETabParent (which is actually static) tracks which if any TabParent has IMEFocus michael@0: // When the input mode is set to anything but IMEState::DISABLED, michael@0: // mIMETabParent should be set to this michael@0: mIMETabParent = michael@0: aIMEEnabled != static_cast(IMEState::DISABLED) ? this : nullptr; michael@0: nsCOMPtr widget = GetWidget(); michael@0: if (!widget || !AllowContentIME()) michael@0: return true; michael@0: michael@0: InputContext context; michael@0: context.mIMEState.mEnabled = static_cast(aIMEEnabled); michael@0: context.mIMEState.mOpen = static_cast(aIMEOpen); michael@0: context.mHTMLInputType.Assign(aType); michael@0: context.mHTMLInputInputmode.Assign(aInputmode); michael@0: context.mActionHint.Assign(aActionHint); michael@0: InputContextAction action( michael@0: static_cast(aCause), michael@0: static_cast(aFocusChange)); michael@0: widget->SetInputContext(context, action); michael@0: michael@0: nsCOMPtr observerService = mozilla::services::GetObserverService(); michael@0: if (!observerService) michael@0: return true; michael@0: michael@0: nsAutoString state; michael@0: state.AppendInt(aIMEEnabled); michael@0: observerService->NotifyObservers(nullptr, "ime-enabled-state-changed", state.get()); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvIsParentWindowMainWidgetVisible(bool* aIsVisible) michael@0: { michael@0: nsCOMPtr frame = do_QueryInterface(mFrameElement); michael@0: if (!frame) michael@0: return true; michael@0: nsCOMPtr windowUtils = michael@0: do_QueryInterface(frame->OwnerDoc()->GetWindow()); michael@0: nsresult rv = windowUtils->GetIsParentWindowMainWidgetVisible(aIsVisible); michael@0: return NS_SUCCEEDED(rv); michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvGetDPI(float* aValue) michael@0: { michael@0: TryCacheDPIAndScale(); michael@0: michael@0: NS_ABORT_IF_FALSE(mDPI > 0, michael@0: "Must not ask for DPI before OwnerElement is received!"); michael@0: *aValue = mDPI; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvGetDefaultScale(double* aValue) michael@0: { michael@0: TryCacheDPIAndScale(); michael@0: michael@0: NS_ABORT_IF_FALSE(mDefaultScale.scale > 0, michael@0: "Must not ask for scale before OwnerElement is received!"); michael@0: *aValue = mDefaultScale.scale; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvGetWidgetNativeData(WindowsHandle* aValue) michael@0: { michael@0: nsCOMPtr content = do_QueryInterface(mFrameElement); michael@0: if (content) { michael@0: nsIPresShell* shell = content->OwnerDoc()->GetShell(); michael@0: if (shell) { michael@0: nsViewManager* vm = shell->GetViewManager(); michael@0: nsCOMPtr widget; michael@0: vm->GetRootWidget(getter_AddRefs(widget)); michael@0: if (widget) { michael@0: *aValue = reinterpret_cast( michael@0: widget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW)); michael@0: return true; michael@0: } michael@0: } michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: bool michael@0: TabParent::ReceiveMessage(const nsString& aMessage, michael@0: bool aSync, michael@0: const StructuredCloneData* aCloneData, michael@0: CpowHolder* aCpows, michael@0: nsIPrincipal* aPrincipal, michael@0: InfallibleTArray* aJSONRetVal) michael@0: { michael@0: nsRefPtr frameLoader = GetFrameLoader(); michael@0: if (frameLoader && frameLoader->GetFrameMessageManager()) { michael@0: nsRefPtr manager = michael@0: frameLoader->GetFrameMessageManager(); michael@0: michael@0: manager->ReceiveMessage(mFrameElement, michael@0: aMessage, michael@0: aSync, michael@0: aCloneData, michael@0: aCpows, michael@0: aPrincipal, michael@0: aJSONRetVal); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: PIndexedDBParent* michael@0: TabParent::AllocPIndexedDBParent( michael@0: const nsCString& aGroup, michael@0: const nsCString& aASCIIOrigin, bool* /* aAllowed */) michael@0: { michael@0: return new IndexedDBParent(this); michael@0: } michael@0: michael@0: bool michael@0: TabParent::DeallocPIndexedDBParent(PIndexedDBParent* aActor) michael@0: { michael@0: delete aActor; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvPIndexedDBConstructor(PIndexedDBParent* aActor, michael@0: const nsCString& aGroup, michael@0: const nsCString& aASCIIOrigin, michael@0: bool* aAllowed) michael@0: { michael@0: nsRefPtr mgr = IndexedDatabaseManager::GetOrCreate(); michael@0: NS_ENSURE_TRUE(mgr, false); michael@0: michael@0: if (!IndexedDatabaseManager::IsMainProcess()) { michael@0: NS_RUNTIMEABORT("Not supported yet!"); michael@0: } michael@0: michael@0: nsresult rv; michael@0: michael@0: // XXXbent Need to make sure we have a whitelist for chrome databases! michael@0: michael@0: // Verify that the child is requesting to access a database it's allowed to michael@0: // see. (aASCIIOrigin here specifies a TabContext + a website origin, and michael@0: // we're checking that the TabContext may access it.) michael@0: // michael@0: // We have to check IsBrowserOrApp() because TabContextMayAccessOrigin will michael@0: // fail if we're not a browser-or-app, since aASCIIOrigin will be a plain URI, michael@0: // but TabContextMayAccessOrigin will construct an extended origin using michael@0: // app-id 0. Note that as written below, we allow a non browser-or-app child michael@0: // to read any database. That's a security hole, but we don't ship a michael@0: // configuration which creates non browser-or-app children, so it's not a big michael@0: // deal. michael@0: if (!aASCIIOrigin.EqualsLiteral("chrome") && IsBrowserOrApp() && michael@0: !IndexedDatabaseManager::TabContextMayAccessOrigin(*this, aASCIIOrigin)) { michael@0: michael@0: NS_WARNING("App attempted to open databases that it does not have " michael@0: "permission to access!"); michael@0: return false; michael@0: } michael@0: michael@0: nsCOMPtr node = do_QueryInterface(GetOwnerElement()); michael@0: NS_ENSURE_TRUE(node, false); michael@0: michael@0: nsIDocument* doc = node->GetOwnerDocument(); michael@0: NS_ENSURE_TRUE(doc, false); michael@0: michael@0: nsCOMPtr window = doc->GetInnerWindow(); michael@0: NS_ENSURE_TRUE(window, false); michael@0: michael@0: // Let's do a current inner check to see if the inner is active or is in michael@0: // bf cache, and bail out if it's not active. michael@0: nsCOMPtr outer = doc->GetWindow(); michael@0: if (!outer || outer->GetCurrentInnerWindow() != window) { michael@0: *aAllowed = false; michael@0: return true; michael@0: } michael@0: michael@0: ContentParent* contentParent = Manager(); michael@0: NS_ASSERTION(contentParent, "Null manager?!"); michael@0: michael@0: nsRefPtr factory; michael@0: rv = IDBFactory::Create(window, aGroup, aASCIIOrigin, contentParent, michael@0: getter_AddRefs(factory)); michael@0: NS_ENSURE_SUCCESS(rv, false); michael@0: michael@0: if (!factory) { michael@0: *aAllowed = false; michael@0: return true; michael@0: } michael@0: michael@0: IndexedDBParent* actor = static_cast(aActor); michael@0: actor->mFactory = factory; michael@0: actor->mASCIIOrigin = aASCIIOrigin; michael@0: michael@0: *aAllowed = true; michael@0: return true; michael@0: } michael@0: michael@0: // nsIAuthPromptProvider michael@0: michael@0: // This method is largely copied from nsDocShell::GetAuthPrompt michael@0: NS_IMETHODIMP michael@0: TabParent::GetAuthPrompt(uint32_t aPromptReason, const nsIID& iid, michael@0: void** aResult) michael@0: { michael@0: // we're either allowing auth, or it's a proxy request michael@0: nsresult rv; michael@0: nsCOMPtr wwatch = michael@0: do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsCOMPtr window; michael@0: nsCOMPtr frame = do_QueryInterface(mFrameElement); michael@0: if (frame) michael@0: window = do_QueryInterface(frame->OwnerDoc()->GetWindow()); michael@0: michael@0: // Get an auth prompter for our window so that the parenting michael@0: // of the dialogs works as it should when using tabs. michael@0: return wwatch->GetPrompt(window, iid, michael@0: reinterpret_cast(aResult)); michael@0: } michael@0: michael@0: PColorPickerParent* michael@0: TabParent::AllocPColorPickerParent(const nsString& aTitle, michael@0: const nsString& aInitialColor) michael@0: { michael@0: return new ColorPickerParent(aTitle, aInitialColor); michael@0: } michael@0: michael@0: bool michael@0: TabParent::DeallocPColorPickerParent(PColorPickerParent* actor) michael@0: { michael@0: delete actor; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvInitRenderFrame(PRenderFrameParent* aFrame, michael@0: ScrollingBehavior* aScrolling, michael@0: TextureFactoryIdentifier* aTextureFactoryIdentifier, michael@0: uint64_t* aLayersId, michael@0: bool *aSuccess) michael@0: { michael@0: *aScrolling = UseAsyncPanZoom() ? ASYNC_PAN_ZOOM : DEFAULT_SCROLLING; michael@0: *aTextureFactoryIdentifier = TextureFactoryIdentifier(); michael@0: *aLayersId = 0; michael@0: michael@0: nsRefPtr frameLoader = GetFrameLoader(); michael@0: if (!frameLoader) { michael@0: NS_WARNING("Can't allocate graphics resources. May already be shutting down."); michael@0: *aSuccess = false; michael@0: return true; michael@0: } michael@0: michael@0: static_cast(aFrame)->Init(frameLoader, *aScrolling, michael@0: aTextureFactoryIdentifier, aLayersId); michael@0: michael@0: *aSuccess = true; michael@0: return true; michael@0: } michael@0: michael@0: PRenderFrameParent* michael@0: TabParent::AllocPRenderFrameParent() michael@0: { michael@0: MOZ_ASSERT(ManagedPRenderFrameParent().IsEmpty()); michael@0: return new RenderFrameParent(); michael@0: } michael@0: michael@0: bool michael@0: TabParent::DeallocPRenderFrameParent(PRenderFrameParent* aFrame) michael@0: { michael@0: delete aFrame; michael@0: return true; michael@0: } michael@0: michael@0: mozilla::docshell::POfflineCacheUpdateParent* michael@0: TabParent::AllocPOfflineCacheUpdateParent(const URIParams& aManifestURI, michael@0: const URIParams& aDocumentURI, michael@0: const bool& aStickDocument) michael@0: { michael@0: nsRefPtr update = michael@0: new mozilla::docshell::OfflineCacheUpdateParent(OwnOrContainingAppId(), michael@0: IsBrowserElement()); michael@0: // Use this reference as the IPDL reference. michael@0: return update.forget().take(); michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvPOfflineCacheUpdateConstructor(POfflineCacheUpdateParent* aActor, michael@0: const URIParams& aManifestURI, michael@0: const URIParams& aDocumentURI, michael@0: const bool& aStickDocument) michael@0: { michael@0: MOZ_ASSERT(aActor); michael@0: michael@0: nsRefPtr update = michael@0: static_cast(aActor); michael@0: michael@0: nsresult rv = update->Schedule(aManifestURI, aDocumentURI, aStickDocument); michael@0: if (NS_FAILED(rv) && !IsDestroyed()) { michael@0: // Inform the child of failure. michael@0: unused << update->SendFinish(false, false); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabParent::DeallocPOfflineCacheUpdateParent(POfflineCacheUpdateParent* aActor) michael@0: { michael@0: // Reclaim the IPDL reference. michael@0: nsRefPtr update = michael@0: dont_AddRef( michael@0: static_cast(aActor)); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvSetOfflinePermission(const IPC::Principal& aPrincipal) michael@0: { michael@0: nsIPrincipal* principal = aPrincipal; michael@0: nsContentUtils::MaybeAllowOfflineAppByDefault(principal, nullptr); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabParent::AllowContentIME() michael@0: { michael@0: nsFocusManager* fm = nsFocusManager::GetFocusManager(); michael@0: NS_ENSURE_TRUE(fm, false); michael@0: michael@0: nsCOMPtr focusedContent = fm->GetFocusedContent(); michael@0: if (focusedContent && focusedContent->IsEditable()) michael@0: return false; michael@0: michael@0: return true; michael@0: } michael@0: michael@0: already_AddRefed michael@0: TabParent::GetFrameLoader() const michael@0: { michael@0: nsCOMPtr frameLoaderOwner = do_QueryInterface(mFrameElement); michael@0: return frameLoaderOwner ? frameLoaderOwner->GetFrameLoader() : nullptr; michael@0: } michael@0: michael@0: void michael@0: TabParent::TryCacheDPIAndScale() michael@0: { michael@0: if (mDPI > 0) { michael@0: return; michael@0: } michael@0: michael@0: nsCOMPtr widget = GetWidget(); michael@0: michael@0: if (!widget && mFrameElement) { michael@0: // Even if we don't have a widget (e.g. because we're display:none), there's michael@0: // probably a widget somewhere in the hierarchy our frame element lives in. michael@0: widget = nsContentUtils::WidgetForDocument(mFrameElement->OwnerDoc()); michael@0: } michael@0: michael@0: if (widget) { michael@0: mDPI = widget->GetDPI(); michael@0: mDefaultScale = widget->GetDefaultScale(); michael@0: } michael@0: } michael@0: michael@0: already_AddRefed michael@0: TabParent::GetWidget() const michael@0: { michael@0: nsCOMPtr content = do_QueryInterface(mFrameElement); michael@0: if (!content) michael@0: return nullptr; michael@0: michael@0: nsIFrame *frame = content->GetPrimaryFrame(); michael@0: if (!frame) michael@0: return nullptr; michael@0: michael@0: nsCOMPtr widget = frame->GetNearestWidget(); michael@0: return widget.forget(); michael@0: } michael@0: michael@0: bool michael@0: TabParent::UseAsyncPanZoom() michael@0: { michael@0: bool usingOffMainThreadCompositing = !!CompositorParent::CompositorLoop(); michael@0: bool asyncPanZoomEnabled = michael@0: Preferences::GetBool("layers.async-pan-zoom.enabled", false); michael@0: return (usingOffMainThreadCompositing && asyncPanZoomEnabled && michael@0: GetScrollingBehavior() == ASYNC_PAN_ZOOM); michael@0: } michael@0: michael@0: void michael@0: TabParent::MaybeForwardEventToRenderFrame(WidgetInputEvent& aEvent, michael@0: ScrollableLayerGuid* aOutTargetGuid) michael@0: { michael@0: if (RenderFrameParent* rfp = GetRenderFrame()) { michael@0: rfp->NotifyInputEvent(aEvent, aOutTargetGuid); michael@0: } michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvBrowserFrameOpenWindow(PBrowserParent* aOpener, michael@0: const nsString& aURL, michael@0: const nsString& aName, michael@0: const nsString& aFeatures, michael@0: bool* aOutWindowOpened) michael@0: { michael@0: BrowserElementParent::OpenWindowResult opened = michael@0: BrowserElementParent::OpenWindowOOP(static_cast(aOpener), michael@0: this, aURL, aName, aFeatures); michael@0: *aOutWindowOpened = (opened != BrowserElementParent::OPEN_WINDOW_CANCELLED); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvPRenderFrameConstructor(PRenderFrameParent* actor) michael@0: { michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvZoomToRect(const uint32_t& aPresShellId, michael@0: const ViewID& aViewId, michael@0: const CSSRect& aRect) michael@0: { michael@0: if (RenderFrameParent* rfp = GetRenderFrame()) { michael@0: rfp->ZoomToRect(aPresShellId, aViewId, aRect); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvUpdateZoomConstraints(const uint32_t& aPresShellId, michael@0: const ViewID& aViewId, michael@0: const bool& aIsRoot, michael@0: const ZoomConstraints& aConstraints) michael@0: { michael@0: if (RenderFrameParent* rfp = GetRenderFrame()) { michael@0: rfp->UpdateZoomConstraints(aPresShellId, aViewId, aIsRoot, aConstraints); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: TabParent::RecvContentReceivedTouch(const ScrollableLayerGuid& aGuid, michael@0: const bool& aPreventDefault) michael@0: { michael@0: if (RenderFrameParent* rfp = GetRenderFrame()) { michael@0: rfp->ContentReceivedTouch(aGuid, aPreventDefault); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: already_AddRefed michael@0: TabParent::GetLoadContext() michael@0: { michael@0: nsCOMPtr loadContext; michael@0: if (mLoadContext) { michael@0: loadContext = mLoadContext; michael@0: } else { michael@0: loadContext = new LoadContext(GetOwnerElement(), michael@0: OwnOrContainingAppId(), michael@0: true /* aIsContent */, michael@0: mChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW, michael@0: mChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW, michael@0: IsBrowserElement()); michael@0: mLoadContext = loadContext; michael@0: } michael@0: return loadContext.forget(); michael@0: } michael@0: michael@0: /* Be careful if you call this method while proceding a real touch event. For michael@0: * example sending a touchstart during a real touchend may results into michael@0: * a busted mEventCaptureDepth and following touch events may not do what you michael@0: * expect. michael@0: */ michael@0: NS_IMETHODIMP michael@0: TabParent::InjectTouchEvent(const nsAString& aType, michael@0: uint32_t* aIdentifiers, michael@0: int32_t* aXs, michael@0: int32_t* aYs, michael@0: uint32_t* aRxs, michael@0: uint32_t* aRys, michael@0: float* aRotationAngles, michael@0: float* aForces, michael@0: uint32_t aCount, michael@0: int32_t aModifiers) michael@0: { michael@0: uint32_t msg; michael@0: nsContentUtils::GetEventIdAndAtom(aType, NS_TOUCH_EVENT, &msg); michael@0: if (msg != NS_TOUCH_START && msg != NS_TOUCH_MOVE && michael@0: msg != NS_TOUCH_END && msg != NS_TOUCH_CANCEL) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsCOMPtr widget = GetWidget(); michael@0: if (!widget) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: WidgetTouchEvent event(true, msg, widget); michael@0: event.modifiers = aModifiers; michael@0: event.time = PR_IntervalNow(); michael@0: michael@0: event.touches.SetCapacity(aCount); michael@0: for (uint32_t i = 0; i < aCount; ++i) { michael@0: nsRefPtr t = new Touch(aIdentifiers[i], michael@0: nsIntPoint(aXs[i], aYs[i]), michael@0: nsIntPoint(aRxs[i], aRys[i]), michael@0: aRotationAngles[i], michael@0: aForces[i]); michael@0: michael@0: // Consider all injected touch events as changedTouches. For more details michael@0: // about the meaning of changedTouches for each event, see michael@0: // https://developer.mozilla.org/docs/Web/API/TouchEvent.changedTouches michael@0: t->mChanged = true; michael@0: event.touches.AppendElement(t); michael@0: } michael@0: michael@0: if ((msg == NS_TOUCH_END || msg == NS_TOUCH_CANCEL) && sEventCapturer) { michael@0: WidgetGUIEvent* guiEvent = event.AsGUIEvent(); michael@0: TryCapture(*guiEvent); michael@0: } michael@0: michael@0: SendRealTouchEvent(event); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: TabParent::GetUseAsyncPanZoom(bool* useAsyncPanZoom) michael@0: { michael@0: *useAsyncPanZoom = UseAsyncPanZoom(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: TabParent::SetIsDocShellActive(bool isActive) michael@0: { michael@0: unused << SendSetIsDocShellActive(isActive); michael@0: return NS_OK; michael@0: } michael@0: michael@0: } // namespace tabs michael@0: } // namespace mozilla