summaryrefslogtreecommitdiffstats
path: root/toolkit/components/browser/nsWebBrowser.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /toolkit/components/browser/nsWebBrowser.cpp
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/browser/nsWebBrowser.cpp')
-rw-r--r--toolkit/components/browser/nsWebBrowser.cpp1241
1 files changed, 1241 insertions, 0 deletions
diff --git a/toolkit/components/browser/nsWebBrowser.cpp b/toolkit/components/browser/nsWebBrowser.cpp
new file mode 100644
index 0000000000..53ed9eb1a4
--- /dev/null
+++ b/toolkit/components/browser/nsWebBrowser.cpp
@@ -0,0 +1,1241 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 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/. */
+
+// Local Includes
+#include "nsWebBrowser.h"
+
+// Helper Classes
+#include "nsGfxCIID.h"
+#include "nsWidgetsCID.h"
+
+#include "gfxUtils.h"
+#include "mozilla/gfx/2D.h"
+
+// Interfaces Needed
+#include "gfxContext.h"
+#include "nsReadableUtils.h"
+#include "nsIInterfaceRequestor.h"
+#include "nsIInterfaceRequestorUtils.h"
+#include "nsIWebBrowserChrome.h"
+#include "nsPIDOMWindow.h"
+#include "nsIWebProgress.h"
+#include "nsIWebProgressListener.h"
+#include "nsIURI.h"
+#include "nsIWebBrowserPersist.h"
+#include "nsFocusManager.h"
+#include "nsILoadContext.h"
+#include "nsComponentManagerUtils.h"
+#include "nsDocShell.h"
+#include "nsServiceManagerUtils.h"
+#include "WindowRenderer.h"
+
+#include "mozilla/dom/Element.h"
+#include "mozilla/dom/BrowsingContext.h"
+#include "mozilla/dom/LoadURIOptionsBinding.h"
+#include "mozilla/dom/WindowGlobalChild.h"
+
+// for painting the background window
+#include "mozilla/LookAndFeel.h"
+#include "mozilla/ServoStyleConsts.h"
+
+// Printing Includes
+#ifdef NS_PRINTING
+# include "nsIWebBrowserPrint.h"
+# include "nsIContentViewer.h"
+#endif
+
+// PSM2 includes
+#include "nsISecureBrowserUI.h"
+#include "nsXULAppAPI.h"
+
+using namespace mozilla;
+using namespace mozilla::gfx;
+using namespace mozilla::layers;
+
+nsWebBrowser::nsWebBrowser(int aItemType)
+ : mContentType(aItemType),
+ mShouldEnableHistory(true),
+ mWillChangeProcess(false),
+ mParentNativeWindow(nullptr),
+ mProgressListener(nullptr),
+ mWidgetListenerDelegate(this),
+ mBackgroundColor(0),
+ mPersistCurrentState(nsIWebBrowserPersist::PERSIST_STATE_READY),
+ mPersistResult(NS_OK),
+ mPersistFlags(nsIWebBrowserPersist::PERSIST_FLAGS_NONE),
+ mParentWidget(nullptr) {
+ mWWatch = do_GetService(NS_WINDOWWATCHER_CONTRACTID);
+ NS_ASSERTION(mWWatch, "failed to get WindowWatcher");
+}
+
+nsWebBrowser::~nsWebBrowser() { InternalDestroy(); }
+
+nsIWidget* nsWebBrowser::EnsureWidget() {
+ if (mParentWidget) {
+ return mParentWidget;
+ }
+
+ mInternalWidget = nsIWidget::CreateChildWindow();
+ if (NS_WARN_IF(!mInternalWidget)) {
+ return nullptr;
+ }
+
+ widget::InitData widgetInit;
+ widgetInit.mClipChildren = true;
+ widgetInit.mWindowType = widget::WindowType::Child;
+ LayoutDeviceIntRect bounds(0, 0, 0, 0);
+
+ mInternalWidget->SetWidgetListener(&mWidgetListenerDelegate);
+ NS_ENSURE_SUCCESS(mInternalWidget->Create(nullptr, mParentNativeWindow,
+ bounds, &widgetInit),
+ nullptr);
+
+ return mInternalWidget;
+}
+
+/* static */
+already_AddRefed<nsWebBrowser> nsWebBrowser::Create(
+ nsIWebBrowserChrome* aContainerWindow, nsIWidget* aParentWidget,
+ dom::BrowsingContext* aBrowsingContext,
+ dom::WindowGlobalChild* aInitialWindowChild) {
+ MOZ_ASSERT_IF(aInitialWindowChild,
+ aInitialWindowChild->BrowsingContext() == aBrowsingContext);
+
+ RefPtr<nsWebBrowser> browser = new nsWebBrowser(
+ aBrowsingContext->IsContent() ? typeContentWrapper : typeChromeWrapper);
+
+ // nsWebBrowser::SetContainer also calls nsWebBrowser::EnsureDocShellTreeOwner
+ NS_ENSURE_SUCCESS(browser->SetContainerWindow(aContainerWindow), nullptr);
+ NS_ENSURE_SUCCESS(browser->SetParentWidget(aParentWidget), nullptr);
+
+ nsCOMPtr<nsIWidget> docShellParentWidget = browser->EnsureWidget();
+ if (NS_WARN_IF(!docShellParentWidget)) {
+ return nullptr;
+ }
+
+ uint64_t outerWindowId =
+ aInitialWindowChild ? aInitialWindowChild->OuterWindowId() : 0;
+
+ RefPtr<nsDocShell> docShell =
+ nsDocShell::Create(aBrowsingContext, outerWindowId);
+ if (NS_WARN_IF(!docShell)) {
+ return nullptr;
+ }
+ browser->SetDocShell(docShell);
+ MOZ_ASSERT(browser->mDocShell == docShell);
+
+ // get the system default window background colour
+ //
+ // TODO(emilio): Can we get the color-scheme from somewhere here?
+ browser->mBackgroundColor =
+ LookAndFeel::Color(LookAndFeel::ColorID::Window, ColorScheme::Light,
+ LookAndFeel::UseStandins::No);
+
+ // HACK ALERT - this registration registers the nsDocShellTreeOwner as a
+ // nsIWebBrowserListener so it can setup its MouseListener in one of the
+ // progress callbacks. If we can register the MouseListener another way, this
+ // registration can go away, and nsDocShellTreeOwner can stop implementing
+ // nsIWebProgressListener.
+ RefPtr<nsDocShellTreeOwner> docShellTreeOwner = browser->mDocShellTreeOwner;
+ Unused << docShell->AddProgressListener(docShellTreeOwner,
+ nsIWebProgress::NOTIFY_ALL);
+
+ docShell->SetTreeOwner(docShellTreeOwner);
+
+ // If the webbrowser is a content docshell item then we won't hear any
+ // events from subframes. To solve that we install our own chrome event
+ // handler that always gets called (even for subframes) for any bubbling
+ // event.
+
+ nsresult rv = docShell->InitWindow(nullptr, docShellParentWidget, 0, 0, 0, 0);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return nullptr;
+ }
+
+ docShellTreeOwner->AddToWatcher(); // evil twin of Remove in SetDocShell(0)
+ docShellTreeOwner->AddChromeListeners();
+
+ if (aInitialWindowChild) {
+ docShell->CreateContentViewerForActor(aInitialWindowChild);
+ }
+
+ return browser.forget();
+}
+
+void nsWebBrowser::InternalDestroy() {
+ if (mInternalWidget) {
+ mInternalWidget->SetWidgetListener(nullptr);
+ mInternalWidget->Destroy();
+ mInternalWidget = nullptr; // Force release here.
+ }
+
+ SetDocShell(nullptr);
+
+ if (mDocShellTreeOwner) {
+ mDocShellTreeOwner->WebBrowser(nullptr);
+ mDocShellTreeOwner = nullptr;
+ }
+}
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsWebBrowser)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsWebBrowser)
+
+NS_IMPL_CYCLE_COLLECTION_WEAK(nsWebBrowser, mDocShell)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsWebBrowser)
+ NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebBrowser)
+ NS_INTERFACE_MAP_ENTRY(nsIWebBrowser)
+ NS_INTERFACE_MAP_ENTRY(nsIWebNavigation)
+ NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
+ NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeItem)
+ NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
+ NS_INTERFACE_MAP_ENTRY(nsIWebBrowserPersist)
+ NS_INTERFACE_MAP_ENTRY(nsICancelable)
+ NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
+ NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
+NS_INTERFACE_MAP_END
+
+///*****************************************************************************
+// nsWebBrowser::nsIInterfaceRequestor
+//*****************************************************************************
+
+NS_IMETHODIMP
+nsWebBrowser::GetInterface(const nsIID& aIID, void** aSink) {
+ NS_ENSURE_ARG_POINTER(aSink);
+
+ if (NS_SUCCEEDED(QueryInterface(aIID, aSink))) {
+ return NS_OK;
+ }
+
+ if (mDocShell) {
+#ifdef NS_PRINTING
+ if (aIID.Equals(NS_GET_IID(nsIWebBrowserPrint))) {
+ nsCOMPtr<nsIContentViewer> viewer;
+ mDocShell->GetContentViewer(getter_AddRefs(viewer));
+ if (!viewer) {
+ return NS_NOINTERFACE;
+ }
+
+ nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint(do_QueryInterface(viewer));
+ nsIWebBrowserPrint* print = (nsIWebBrowserPrint*)webBrowserPrint.get();
+ NS_ASSERTION(print, "This MUST support this interface!");
+ NS_ADDREF(print);
+ *aSink = print;
+ return NS_OK;
+ }
+#endif
+ return mDocShell->GetInterface(aIID, aSink);
+ }
+
+ return NS_NOINTERFACE;
+}
+
+//*****************************************************************************
+// nsWebBrowser::nsIWebBrowser
+//*****************************************************************************
+
+NS_IMETHODIMP
+nsWebBrowser::GetContainerWindow(nsIWebBrowserChrome** aTopWindow) {
+ NS_ENSURE_ARG_POINTER(aTopWindow);
+
+ nsCOMPtr<nsIWebBrowserChrome> top;
+ if (mDocShellTreeOwner) {
+ top = mDocShellTreeOwner->GetWebBrowserChrome();
+ }
+
+ top.forget(aTopWindow);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::SetContainerWindow(nsIWebBrowserChrome* aTopWindow) {
+ EnsureDocShellTreeOwner();
+ return mDocShellTreeOwner->SetWebBrowserChrome(aTopWindow);
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GetContentDOMWindow(mozIDOMWindowProxy** aResult) {
+ if (!mDocShell) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ nsCOMPtr<nsPIDOMWindowOuter> retval = mDocShell->GetWindow();
+ retval.forget(aResult);
+ return *aResult ? NS_OK : NS_ERROR_FAILURE;
+}
+
+void nsWebBrowser::SetOriginAttributes(const OriginAttributes& aAttrs) {
+ mOriginAttributes = aAttrs;
+}
+
+//*****************************************************************************
+// nsWebBrowser::nsIDocShellTreeItem
+//*****************************************************************************
+
+NS_IMETHODIMP
+nsWebBrowser::GetName(nsAString& aName) {
+ if (mDocShell) {
+ mDocShell->GetName(aName);
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::SetName(const nsAString& aName) {
+ if (mDocShell) {
+ return mDocShell->SetName(aName);
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::NameEquals(const nsAString& aName, bool* aResult) {
+ NS_ENSURE_ARG_POINTER(aResult);
+ if (mDocShell) {
+ return mDocShell->NameEquals(aName, aResult);
+ }
+
+ return NS_OK;
+}
+
+/* virtual */
+int32_t nsWebBrowser::ItemType() { return mContentType; }
+
+NS_IMETHODIMP
+nsWebBrowser::GetItemType(int32_t* aItemType) {
+ NS_ENSURE_ARG_POINTER(aItemType);
+
+ *aItemType = ItemType();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GetInProcessParent(nsIDocShellTreeItem** aParent) {
+ *aParent = nullptr;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GetInProcessSameTypeParent(nsIDocShellTreeItem** aParent) {
+ *aParent = nullptr;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GetInProcessRootTreeItem(nsIDocShellTreeItem** aRootTreeItem) {
+ NS_ENSURE_ARG_POINTER(aRootTreeItem);
+ *aRootTreeItem = static_cast<nsIDocShellTreeItem*>(this);
+
+ nsCOMPtr<nsIDocShellTreeItem> parent;
+ NS_ENSURE_SUCCESS(GetInProcessParent(getter_AddRefs(parent)),
+ NS_ERROR_FAILURE);
+ while (parent) {
+ *aRootTreeItem = parent;
+ NS_ENSURE_SUCCESS(
+ (*aRootTreeItem)->GetInProcessParent(getter_AddRefs(parent)),
+ NS_ERROR_FAILURE);
+ }
+ NS_ADDREF(*aRootTreeItem);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GetInProcessSameTypeRootTreeItem(
+ nsIDocShellTreeItem** aRootTreeItem) {
+ NS_ENSURE_ARG_POINTER(aRootTreeItem);
+ *aRootTreeItem = static_cast<nsIDocShellTreeItem*>(this);
+
+ nsCOMPtr<nsIDocShellTreeItem> parent;
+ NS_ENSURE_SUCCESS(GetInProcessSameTypeParent(getter_AddRefs(parent)),
+ NS_ERROR_FAILURE);
+ while (parent) {
+ *aRootTreeItem = parent;
+ NS_ENSURE_SUCCESS(
+ (*aRootTreeItem)->GetInProcessSameTypeParent(getter_AddRefs(parent)),
+ NS_ERROR_FAILURE);
+ }
+ NS_ADDREF(*aRootTreeItem);
+ return NS_OK;
+}
+
+dom::Document* nsWebBrowser::GetDocument() {
+ return mDocShell ? mDocShell->GetDocument() : nullptr;
+}
+
+nsPIDOMWindowOuter* nsWebBrowser::GetWindow() {
+ return mDocShell ? mDocShell->GetWindow() : nullptr;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GetBrowsingContextXPCOM(dom::BrowsingContext** aBrowsingContext) {
+ NS_ENSURE_STATE(mDocShell);
+ return mDocShell->GetBrowsingContextXPCOM(aBrowsingContext);
+}
+
+dom::BrowsingContext* nsWebBrowser::GetBrowsingContext() {
+ return mDocShell->GetBrowsingContext();
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GetDomWindow(mozIDOMWindowProxy** aWindow) {
+ if (!mDocShell) return NS_ERROR_NOT_INITIALIZED;
+ return mDocShell->GetDomWindow(aWindow);
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GetTreeOwner(nsIDocShellTreeOwner** aTreeOwner) {
+ NS_ENSURE_ARG_POINTER(aTreeOwner);
+ *aTreeOwner = nullptr;
+ if (mDocShellTreeOwner) {
+ if (mDocShellTreeOwner->mTreeOwner) {
+ *aTreeOwner = mDocShellTreeOwner->mTreeOwner;
+ } else {
+ *aTreeOwner = mDocShellTreeOwner;
+ }
+ }
+ NS_IF_ADDREF(*aTreeOwner);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::SetTreeOwner(nsIDocShellTreeOwner* aTreeOwner) {
+ EnsureDocShellTreeOwner();
+ return mDocShellTreeOwner->SetTreeOwner(aTreeOwner);
+}
+
+//*****************************************************************************
+// nsWebBrowser::nsIDocShellTreeItem
+//*****************************************************************************
+
+NS_IMETHODIMP
+nsWebBrowser::GetInProcessChildCount(int32_t* aChildCount) {
+ NS_ENSURE_ARG_POINTER(aChildCount);
+ *aChildCount = 0;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::AddChild(nsIDocShellTreeItem* aChild) {
+ return NS_ERROR_UNEXPECTED;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::RemoveChild(nsIDocShellTreeItem* aChild) {
+ return NS_ERROR_UNEXPECTED;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GetInProcessChildAt(int32_t aIndex,
+ nsIDocShellTreeItem** aChild) {
+ return NS_ERROR_UNEXPECTED;
+}
+
+//*****************************************************************************
+// nsWebBrowser::nsIWebNavigation
+//*****************************************************************************
+
+NS_IMETHODIMP
+nsWebBrowser::GetCanGoBack(bool* aCanGoBack) {
+ NS_ENSURE_STATE(mDocShell);
+
+ return mDocShell->GetCanGoBack(aCanGoBack);
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GetCanGoForward(bool* aCanGoForward) {
+ NS_ENSURE_STATE(mDocShell);
+
+ return mDocShell->GetCanGoForward(aCanGoForward);
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GoBack(bool aRequireUserInteraction, bool aUserActivation) {
+ NS_ENSURE_STATE(mDocShell);
+
+ RefPtr<nsDocShell> docShell = mDocShell;
+ return docShell->GoBack(aRequireUserInteraction, aUserActivation);
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GoForward(bool aRequireUserInteraction, bool aUserActivation) {
+ NS_ENSURE_STATE(mDocShell);
+
+ RefPtr<nsDocShell> docShell = mDocShell;
+ return docShell->GoForward(aRequireUserInteraction, aUserActivation);
+}
+
+nsresult nsWebBrowser::LoadURI(nsIURI* aURI,
+ const dom::LoadURIOptions& aLoadURIOptions) {
+#ifndef ANDROID
+ MOZ_ASSERT(aLoadURIOptions.mTriggeringPrincipal,
+ "nsWebBrowser::LoadURI - Need a valid triggeringPrincipal");
+#endif
+ NS_ENSURE_STATE(mDocShell);
+
+ RefPtr<nsDocShell> docShell = mDocShell;
+ return docShell->LoadURI(aURI, aLoadURIOptions);
+}
+
+NS_IMETHODIMP
+nsWebBrowser::LoadURIFromScript(nsIURI* aURI,
+ JS::Handle<JS::Value> aLoadURIOptions,
+ JSContext* aCx) {
+ // generate dictionary for loadURIOptions and forward call
+ dom::LoadURIOptions loadURIOptions;
+ if (!loadURIOptions.Init(aCx, aLoadURIOptions)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+ return LoadURI(aURI, loadURIOptions);
+}
+
+nsresult nsWebBrowser::FixupAndLoadURIString(
+ const nsAString& aURI, const dom::LoadURIOptions& aLoadURIOptions) {
+#ifndef ANDROID
+ MOZ_ASSERT(
+ aLoadURIOptions.mTriggeringPrincipal,
+ "nsWebBrowser::FixupAndLoadURIString - Need a valid triggeringPrincipal");
+#endif
+ NS_ENSURE_STATE(mDocShell);
+
+ RefPtr<nsDocShell> docShell = mDocShell;
+ return docShell->FixupAndLoadURIString(aURI, aLoadURIOptions);
+}
+
+NS_IMETHODIMP
+nsWebBrowser::FixupAndLoadURIStringFromScript(
+ const nsAString& aURI, JS::Handle<JS::Value> aLoadURIOptions,
+ JSContext* aCx) {
+ // generate dictionary for loadURIOptions and forward call
+ dom::LoadURIOptions loadURIOptions;
+ if (!loadURIOptions.Init(aCx, aLoadURIOptions)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+ return FixupAndLoadURIString(aURI, loadURIOptions);
+}
+
+NS_IMETHODIMP
+nsWebBrowser::ResumeRedirectedLoad(uint64_t aIdentifier,
+ int32_t aHistoryIndex) {
+ NS_ENSURE_STATE(mDocShell);
+
+ return mDocShell->ResumeRedirectedLoad(aIdentifier, aHistoryIndex);
+}
+
+NS_IMETHODIMP
+nsWebBrowser::Reload(uint32_t aReloadFlags) {
+ NS_ENSURE_STATE(mDocShell);
+
+ RefPtr<nsDocShell> docShell = mDocShell;
+ return docShell->Reload(aReloadFlags);
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GotoIndex(int32_t aIndex, bool aUserActivation) {
+ NS_ENSURE_STATE(mDocShell);
+
+ RefPtr<nsDocShell> docShell = mDocShell;
+ return docShell->GotoIndex(aIndex, aUserActivation);
+}
+
+NS_IMETHODIMP
+nsWebBrowser::Stop(uint32_t aStopFlags) {
+ NS_ENSURE_STATE(mDocShell);
+
+ return mDocShell->Stop(aStopFlags);
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GetCurrentURI(nsIURI** aURI) {
+ NS_ENSURE_STATE(mDocShell);
+
+ return mDocShell->GetCurrentURI(aURI);
+}
+
+// XXX(nika): Consider making the mozilla::dom::ChildSHistory version the
+// canonical one?
+NS_IMETHODIMP
+nsWebBrowser::GetSessionHistoryXPCOM(nsISupports** aSessionHistory) {
+ NS_ENSURE_ARG_POINTER(aSessionHistory);
+ *aSessionHistory = nullptr;
+ if (mDocShell) {
+ return mDocShell->GetSessionHistoryXPCOM(aSessionHistory);
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GetDocument(dom::Document** aDocument) {
+ NS_ENSURE_STATE(mDocShell);
+
+ return mDocShell->GetDocument(aDocument);
+}
+
+void nsWebBrowser::SetAllowDNSPrefetch(bool aAllowPrefetch) {
+ MOZ_ASSERT(mDocShell);
+ mDocShell->SetAllowDNSPrefetch(aAllowPrefetch);
+}
+
+//*****************************************************************************
+// nsWebBrowser::nsIWebProgressListener
+//*****************************************************************************
+
+NS_IMETHODIMP
+nsWebBrowser::OnStateChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
+ uint32_t aStateFlags, nsresult aStatus) {
+ if (mPersist) {
+ mPersist->GetCurrentState(&mPersistCurrentState);
+ }
+ if (aStateFlags & STATE_IS_NETWORK && aStateFlags & STATE_STOP) {
+ mPersist = nullptr;
+ }
+ if (mProgressListener) {
+ return mProgressListener->OnStateChange(aWebProgress, aRequest, aStateFlags,
+ aStatus);
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::OnProgressChange(nsIWebProgress* aWebProgress,
+ nsIRequest* aRequest, int32_t aCurSelfProgress,
+ int32_t aMaxSelfProgress,
+ int32_t aCurTotalProgress,
+ int32_t aMaxTotalProgress) {
+ if (mPersist) {
+ mPersist->GetCurrentState(&mPersistCurrentState);
+ }
+ if (mProgressListener) {
+ return mProgressListener->OnProgressChange(
+ aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress,
+ aCurTotalProgress, aMaxTotalProgress);
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::OnLocationChange(nsIWebProgress* aWebProgress,
+ nsIRequest* aRequest, nsIURI* aLocation,
+ uint32_t aFlags) {
+ if (mProgressListener) {
+ return mProgressListener->OnLocationChange(aWebProgress, aRequest,
+ aLocation, aFlags);
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::OnStatusChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest,
+ nsresult aStatus, const char16_t* aMessage) {
+ if (mProgressListener) {
+ return mProgressListener->OnStatusChange(aWebProgress, aRequest, aStatus,
+ aMessage);
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::OnSecurityChange(nsIWebProgress* aWebProgress,
+ nsIRequest* aRequest, uint32_t aState) {
+ if (mProgressListener) {
+ return mProgressListener->OnSecurityChange(aWebProgress, aRequest, aState);
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::OnContentBlockingEvent(nsIWebProgress* aWebProgress,
+ nsIRequest* aRequest, uint32_t aEvent) {
+ if (mProgressListener) {
+ return mProgressListener->OnContentBlockingEvent(aWebProgress, aRequest,
+ aEvent);
+ }
+ return NS_OK;
+}
+
+//*****************************************************************************
+// nsWebBrowser::nsIWebBrowserPersist
+//*****************************************************************************
+
+NS_IMETHODIMP
+nsWebBrowser::GetPersistFlags(uint32_t* aPersistFlags) {
+ NS_ENSURE_ARG_POINTER(aPersistFlags);
+ nsresult rv = NS_OK;
+ if (mPersist) {
+ rv = mPersist->GetPersistFlags(&mPersistFlags);
+ }
+ *aPersistFlags = mPersistFlags;
+ return rv;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::SetPersistFlags(uint32_t aPersistFlags) {
+ nsresult rv = NS_OK;
+ mPersistFlags = aPersistFlags;
+ if (mPersist) {
+ rv = mPersist->SetPersistFlags(mPersistFlags);
+ mPersist->GetPersistFlags(&mPersistFlags);
+ }
+ return rv;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GetCurrentState(uint32_t* aCurrentState) {
+ NS_ENSURE_ARG_POINTER(aCurrentState);
+ if (mPersist) {
+ mPersist->GetCurrentState(&mPersistCurrentState);
+ }
+ *aCurrentState = mPersistCurrentState;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GetResult(nsresult* aResult) {
+ NS_ENSURE_ARG_POINTER(aResult);
+ if (mPersist) {
+ mPersist->GetResult(&mPersistResult);
+ }
+ *aResult = mPersistResult;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GetProgressListener(nsIWebProgressListener** aProgressListener) {
+ NS_ENSURE_ARG_POINTER(aProgressListener);
+ *aProgressListener = mProgressListener;
+ NS_IF_ADDREF(*aProgressListener);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::SetProgressListener(nsIWebProgressListener* aProgressListener) {
+ mProgressListener = aProgressListener;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::SaveURI(nsIURI* aURI, nsIPrincipal* aPrincipal,
+ uint32_t aCacheKey, nsIReferrerInfo* aReferrerInfo,
+ nsICookieJarSettings* aCookieJarSettings,
+ nsIInputStream* aPostData, const char* aExtraHeaders,
+ nsISupports* aFile,
+ nsContentPolicyType aContentPolicyType, bool aIsPrivate) {
+ if (mPersist) {
+ uint32_t currentState;
+ mPersist->GetCurrentState(&currentState);
+ if (currentState == PERSIST_STATE_FINISHED) {
+ mPersist = nullptr;
+ } else {
+ // You can't save again until the last save has completed
+ return NS_ERROR_FAILURE;
+ }
+ }
+
+ nsCOMPtr<nsIURI> uri;
+ if (aURI) {
+ uri = aURI;
+ } else {
+ nsresult rv = GetCurrentURI(getter_AddRefs(uri));
+ if (NS_FAILED(rv)) {
+ return NS_ERROR_FAILURE;
+ }
+ }
+
+ // Create a throwaway persistence object to do the work
+ nsresult rv;
+ mPersist = do_CreateInstance(NS_WEBBROWSERPERSIST_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ mPersist->SetProgressListener(this);
+ mPersist->SetPersistFlags(mPersistFlags);
+ mPersist->GetCurrentState(&mPersistCurrentState);
+
+ rv = mPersist->SaveURI(uri, aPrincipal, aCacheKey, aReferrerInfo,
+ aCookieJarSettings, aPostData, aExtraHeaders, aFile,
+ aContentPolicyType, aIsPrivate);
+ if (NS_FAILED(rv)) {
+ mPersist = nullptr;
+ }
+ return rv;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::SaveChannel(nsIChannel* aChannel, nsISupports* aFile) {
+ if (mPersist) {
+ uint32_t currentState;
+ mPersist->GetCurrentState(&currentState);
+ if (currentState == PERSIST_STATE_FINISHED) {
+ mPersist = nullptr;
+ } else {
+ // You can't save again until the last save has completed
+ return NS_ERROR_FAILURE;
+ }
+ }
+
+ // Create a throwaway persistence object to do the work
+ nsresult rv;
+ mPersist = do_CreateInstance(NS_WEBBROWSERPERSIST_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ mPersist->SetProgressListener(this);
+ mPersist->SetPersistFlags(mPersistFlags);
+ mPersist->GetCurrentState(&mPersistCurrentState);
+ rv = mPersist->SaveChannel(aChannel, aFile);
+ if (NS_FAILED(rv)) {
+ mPersist = nullptr;
+ }
+ return rv;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::SaveDocument(nsISupports* aDocumentish, nsISupports* aFile,
+ nsISupports* aDataPath,
+ const char* aOutputContentType,
+ uint32_t aEncodingFlags, uint32_t aWrapColumn) {
+ if (mPersist) {
+ uint32_t currentState;
+ mPersist->GetCurrentState(&currentState);
+ if (currentState == PERSIST_STATE_FINISHED) {
+ mPersist = nullptr;
+ } else {
+ // You can't save again until the last save has completed
+ return NS_ERROR_FAILURE;
+ }
+ }
+
+ // Use the specified DOM document, or if none is specified, the one
+ // attached to the web browser.
+
+ nsCOMPtr<nsISupports> doc;
+ if (aDocumentish) {
+ doc = aDocumentish;
+ } else {
+ RefPtr<dom::Document> domDoc;
+ GetDocument(getter_AddRefs(domDoc));
+ doc = already_AddRefed<nsISupports>(ToSupports(domDoc.forget().take()));
+ }
+ if (!doc) {
+ return NS_ERROR_FAILURE;
+ }
+
+ // Create a throwaway persistence object to do the work
+ nsresult rv;
+ mPersist = do_CreateInstance(NS_WEBBROWSERPERSIST_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ RefPtr<nsIWebBrowserPersist> localPersist(mPersist);
+ Unused << localPersist;
+ mPersist->SetProgressListener(this);
+ mPersist->SetPersistFlags(mPersistFlags);
+ mPersist->GetCurrentState(&mPersistCurrentState);
+ rv = mPersist->SaveDocument(doc, aFile, aDataPath, aOutputContentType,
+ aEncodingFlags, aWrapColumn);
+ if (NS_FAILED(rv)) {
+ mPersist = nullptr;
+ }
+ return rv;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::CancelSave() {
+ if (mPersist) {
+ return mPersist->CancelSave();
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::Cancel(nsresult aReason) {
+ if (mPersist) {
+ return mPersist->Cancel(aReason);
+ }
+ return NS_OK;
+}
+
+//*****************************************************************************
+// nsWebBrowser::nsIBaseWindow
+//*****************************************************************************
+
+NS_IMETHODIMP
+nsWebBrowser::InitWindow(nativeWindow aParentNativeWindow,
+ nsIWidget* aParentWidget, int32_t aX, int32_t aY,
+ int32_t aCX, int32_t aCY) {
+ // nsIBaseWindow::InitWindow and nsIBaseWindow::Create
+ // implementations have been merged into nsWebBrowser::Create
+ MOZ_DIAGNOSTIC_ASSERT(false);
+ return NS_ERROR_NULL_POINTER;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::Destroy() {
+ InternalDestroy();
+
+ return NS_OK;
+}
+
+double nsWebBrowser::GetWidgetCSSToDeviceScale() {
+ return mParentWidget ? mParentWidget->GetDefaultScale().scale : 1.0;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GetDevicePixelsPerDesktopPixel(double* aScale) {
+ *aScale =
+ mParentWidget ? mParentWidget->GetDesktopToDeviceScale().scale : 1.0;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::SetPositionDesktopPix(int32_t aX, int32_t aY) {
+ // XXX jfkthame
+ // It's not clear to me whether this will be fully correct across
+ // potential multi-screen, mixed-DPI configurations for all platforms;
+ // we might need to add code paths that make it possible to pass the
+ // desktop-pix parameters all the way through to the native widget,
+ // to avoid the risk of device-pixel coords mapping to the wrong
+ // display on OS X with mixed retina/non-retina screens.
+ double scale = 1.0;
+ GetDevicePixelsPerDesktopPixel(&scale);
+ return SetPosition(NSToIntRound(aX * scale), NSToIntRound(aY * scale));
+}
+
+NS_IMETHODIMP
+nsWebBrowser::SetPosition(int32_t aX, int32_t aY) {
+ int32_t cx = 0;
+ int32_t cy = 0;
+
+ GetSize(&cx, &cy);
+
+ return SetPositionAndSize(aX, aY, cx, cy, 0);
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GetPosition(int32_t* aX, int32_t* aY) {
+ return GetPositionAndSize(aX, aY, nullptr, nullptr);
+}
+
+NS_IMETHODIMP
+nsWebBrowser::SetSize(int32_t aCX, int32_t aCY, bool aRepaint) {
+ int32_t x = 0;
+ int32_t y = 0;
+
+ GetPosition(&x, &y);
+
+ return SetPositionAndSize(x, y, aCX, aCY,
+ aRepaint ? nsIBaseWindow::eRepaint : 0);
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GetSize(int32_t* aCX, int32_t* aCY) {
+ return GetPositionAndSize(nullptr, nullptr, aCX, aCY);
+}
+
+NS_IMETHODIMP
+nsWebBrowser::SetPositionAndSize(int32_t aX, int32_t aY, int32_t aCX,
+ int32_t aCY, uint32_t aFlags) {
+ int32_t doc_x = aX;
+ int32_t doc_y = aY;
+
+ // If there is an internal widget we need to make the docShell coordinates
+ // relative to the internal widget rather than the calling app's parent.
+ // We also need to resize our widget then.
+ if (mInternalWidget) {
+ doc_x = doc_y = 0;
+ mInternalWidget->Resize(aX, aY, aCX, aCY,
+ !!(aFlags & nsIBaseWindow::eRepaint));
+ }
+ // Now reposition/ resize the doc
+ NS_ENSURE_SUCCESS(
+ mDocShell->SetPositionAndSize(doc_x, doc_y, aCX, aCY, aFlags),
+ NS_ERROR_FAILURE);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GetPositionAndSize(int32_t* aX, int32_t* aY, int32_t* aCX,
+ int32_t* aCY) {
+ if (mInternalWidget) {
+ LayoutDeviceIntRect bounds = mInternalWidget->GetBounds();
+
+ if (aX) {
+ *aX = bounds.X();
+ }
+ if (aY) {
+ *aY = bounds.Y();
+ }
+ if (aCX) {
+ *aCX = bounds.Width();
+ }
+ if (aCY) {
+ *aCY = bounds.Height();
+ }
+ return NS_OK;
+ }
+
+ // Can directly return this as it is the
+ // same interface, thus same returns.
+ return mDocShell->GetPositionAndSize(aX, aY, aCX, aCY);
+}
+
+NS_IMETHODIMP
+nsWebBrowser::SetDimensions(DimensionRequest&& aRequest) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GetDimensions(DimensionKind aDimensionKind, int32_t* aX,
+ int32_t* aY, int32_t* aCX, int32_t* aCY) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::Repaint(bool aForce) {
+ NS_ENSURE_STATE(mDocShell);
+ // Can directly return this as it is the
+ // same interface, thus same returns.
+ return mDocShell->Repaint(aForce);
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GetParentWidget(nsIWidget** aParentWidget) {
+ NS_ENSURE_ARG_POINTER(aParentWidget);
+
+ *aParentWidget = mParentWidget;
+
+ NS_IF_ADDREF(*aParentWidget);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::SetParentWidget(nsIWidget* aParentWidget) {
+ NS_ENSURE_STATE(!mDocShell);
+
+ mParentWidget = aParentWidget;
+ if (mParentWidget) {
+ mParentNativeWindow = mParentWidget->GetNativeData(NS_NATIVE_WIDGET);
+ } else {
+ mParentNativeWindow = nullptr;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GetParentNativeWindow(nativeWindow* aParentNativeWindow) {
+ NS_ENSURE_ARG_POINTER(aParentNativeWindow);
+
+ *aParentNativeWindow = mParentNativeWindow;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::SetParentNativeWindow(nativeWindow aParentNativeWindow) {
+ NS_ENSURE_STATE(!mDocShell);
+
+ mParentNativeWindow = aParentNativeWindow;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GetNativeHandle(nsAString& aNativeHandle) {
+ // the nativeHandle should be accessed from nsIAppWindow
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GetVisibility(bool* aVisibility) {
+ NS_ENSURE_ARG_POINTER(aVisibility);
+
+ if (mDocShell) {
+ NS_ENSURE_SUCCESS(mDocShell->GetVisibility(aVisibility), NS_ERROR_FAILURE);
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::SetVisibility(bool aVisibility) {
+ if (mDocShell) {
+ NS_ENSURE_SUCCESS(mDocShell->SetVisibility(aVisibility), NS_ERROR_FAILURE);
+ if (mInternalWidget) {
+ mInternalWidget->Show(aVisibility);
+ }
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GetEnabled(bool* aEnabled) {
+ if (mInternalWidget) {
+ *aEnabled = mInternalWidget->IsEnabled();
+ return NS_OK;
+ }
+
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::SetEnabled(bool aEnabled) {
+ if (mInternalWidget) {
+ mInternalWidget->Enable(aEnabled);
+ return NS_OK;
+ }
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GetMainWidget(nsIWidget** aMainWidget) {
+ NS_ENSURE_ARG_POINTER(aMainWidget);
+
+ if (mInternalWidget) {
+ *aMainWidget = mInternalWidget;
+ } else {
+ *aMainWidget = mParentWidget;
+ }
+
+ NS_IF_ADDREF(*aMainWidget);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::GetTitle(nsAString& aTitle) {
+ NS_ENSURE_STATE(mDocShell);
+
+ NS_ENSURE_SUCCESS(mDocShell->GetTitle(aTitle), NS_ERROR_FAILURE);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWebBrowser::SetTitle(const nsAString& aTitle) {
+ NS_ENSURE_STATE(mDocShell);
+
+ NS_ENSURE_SUCCESS(mDocShell->SetTitle(aTitle), NS_ERROR_FAILURE);
+
+ return NS_OK;
+}
+
+//*****************************************************************************
+// nsWebBrowser: Listener Helpers
+//*****************************************************************************
+
+void nsWebBrowser::SetDocShell(nsDocShell* aDocShell) {
+ // We need to keep the docshell alive while we perform the changes, but we
+ // don't need to call any methods on it.
+ nsCOMPtr<nsIDocShell> kungFuDeathGrip(mDocShell);
+ mozilla::Unused << kungFuDeathGrip;
+
+ if (aDocShell) {
+ MOZ_ASSERT(!mDocShell, "Should not overwrite an existing value!");
+
+ mDocShell = aDocShell;
+
+ // By default, do not allow DNS prefetch, so we don't break our frozen
+ // API. Embeddors who decide to enable it should do so manually.
+ mDocShell->SetAllowDNSPrefetch(false);
+ } else {
+ if (mDocShellTreeOwner) {
+ mDocShellTreeOwner->RemoveFromWatcher(); // evil twin of Add in Create()
+ }
+ if (mDocShell) {
+ mDocShell->Destroy();
+ }
+ if (!mWillChangeProcess && mDocShell) {
+ mDocShell->GetBrowsingContext()->Detach(/* aFromIPC */ true);
+ }
+
+ mDocShell = nullptr;
+ }
+}
+
+void nsWebBrowser::EnsureDocShellTreeOwner() {
+ if (mDocShellTreeOwner) {
+ return;
+ }
+
+ mDocShellTreeOwner = new nsDocShellTreeOwner();
+ mDocShellTreeOwner->WebBrowser(this);
+}
+
+void nsWebBrowser::WindowActivated() {
+#if defined(DEBUG_smaug)
+ RefPtr<dom::Document> document = mDocShell->GetDocument();
+ nsAutoString documentURI;
+ document->GetDocumentURI(documentURI);
+ printf("nsWebBrowser::NS_ACTIVATE %p %s\n", (void*)this,
+ NS_ConvertUTF16toUTF8(documentURI).get());
+#endif
+ FocusActivate(nsFocusManager::GenerateFocusActionId());
+}
+
+void nsWebBrowser::WindowDeactivated() {
+#if defined(DEBUG_smaug)
+ RefPtr<dom::Document> document = mDocShell->GetDocument();
+ nsAutoString documentURI;
+ document->GetDocumentURI(documentURI);
+ printf("nsWebBrowser::NS_DEACTIVATE %p %s\n", (void*)this,
+ NS_ConvertUTF16toUTF8(documentURI).get());
+#endif
+ FocusDeactivate(nsFocusManager::GenerateFocusActionId());
+}
+
+bool nsWebBrowser::PaintWindow(nsIWidget* aWidget,
+ LayoutDeviceIntRegion aRegion) {
+ WindowRenderer* renderer = aWidget->GetWindowRenderer();
+ NS_ASSERTION(renderer, "Must be in paint event");
+ if (FallbackRenderer* fallback = renderer->AsFallback()) {
+ if (fallback->BeginTransaction()) {
+ fallback->EndTransactionWithColor(aRegion.GetBounds().ToUnknownRect(),
+ ToDeviceColor(mBackgroundColor));
+ }
+ return true;
+ }
+ return false;
+}
+
+void nsWebBrowser::FocusActivate(uint64_t aActionId) {
+ if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
+ if (nsCOMPtr<nsPIDOMWindowOuter> window = GetWindow()) {
+ fm->WindowRaised(window, aActionId);
+ }
+ }
+}
+
+void nsWebBrowser::FocusDeactivate(uint64_t aActionId) {
+ if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
+ if (nsCOMPtr<nsPIDOMWindowOuter> window = GetWindow()) {
+ fm->WindowLowered(window, aActionId);
+ }
+ }
+}
+
+void nsWebBrowser::SetWillChangeProcess() {
+ mWillChangeProcess = true;
+ if (mDocShell) {
+ nsDocShell::Cast(mDocShell)->SetWillChangeProcess();
+ }
+}
+
+void nsWebBrowser::WidgetListenerDelegate::WindowActivated() {
+ RefPtr<nsWebBrowser> holder = mWebBrowser;
+ holder->WindowActivated();
+}
+
+void nsWebBrowser::WidgetListenerDelegate::WindowDeactivated() {
+ RefPtr<nsWebBrowser> holder = mWebBrowser;
+ holder->WindowDeactivated();
+}
+
+bool nsWebBrowser::WidgetListenerDelegate::PaintWindow(
+ nsIWidget* aWidget, mozilla::LayoutDeviceIntRegion aRegion) {
+ RefPtr<nsWebBrowser> holder = mWebBrowser;
+ return holder->PaintWindow(aWidget, aRegion);
+}