From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- embedding/browser/build/moz.build | 14 + embedding/browser/build/nsWebBrowserModule.cpp | 53 + embedding/browser/moz.build | 57 + embedding/browser/nsCTooltipTextProvider.h | 17 + embedding/browser/nsCWebBrowser.idl | 34 + embedding/browser/nsCommandHandler.cpp | 139 ++ embedding/browser/nsCommandHandler.h | 35 + embedding/browser/nsContextMenuInfo.cpp | 326 ++++ embedding/browser/nsContextMenuInfo.h | 54 + embedding/browser/nsDocShellTreeOwner.cpp | 1674 +++++++++++++++++++ embedding/browser/nsDocShellTreeOwner.h | 246 +++ embedding/browser/nsEmbedStream.cpp | 101 ++ embedding/browser/nsEmbedStream.h | 37 + embedding/browser/nsICommandHandler.idl | 40 + embedding/browser/nsIContextMenuListener.idl | 65 + embedding/browser/nsIContextMenuListener2.idl | 121 ++ embedding/browser/nsIEmbeddingSiteWindow.idl | 157 ++ embedding/browser/nsIPrintPreviewNavigation.idl | 52 + embedding/browser/nsIPrintingPromptService.idl | 165 ++ embedding/browser/nsITooltipListener.idl | 44 + embedding/browser/nsITooltipTextProvider.idl | 44 + embedding/browser/nsIWebBrowser.idl | 163 ++ embedding/browser/nsIWebBrowserChrome.idl | 147 ++ embedding/browser/nsIWebBrowserChrome2.idl | 33 + embedding/browser/nsIWebBrowserChrome3.idl | 61 + embedding/browser/nsIWebBrowserChromeFocus.idl | 32 + embedding/browser/nsIWebBrowserFocus.idl | 76 + embedding/browser/nsIWebBrowserPrint.idl | 152 ++ embedding/browser/nsIWebBrowserSetup.idl | 109 ++ embedding/browser/nsIWebBrowserStream.idl | 56 + embedding/browser/nsWebBrowser.cpp | 1952 +++++++++++++++++++++++ embedding/browser/nsWebBrowser.h | 185 +++ embedding/browser/nsWebBrowserContentPolicy.cpp | 108 ++ embedding/browser/nsWebBrowserContentPolicy.h | 26 + 34 files changed, 6575 insertions(+) create mode 100644 embedding/browser/build/moz.build create mode 100644 embedding/browser/build/nsWebBrowserModule.cpp create mode 100644 embedding/browser/moz.build create mode 100644 embedding/browser/nsCTooltipTextProvider.h create mode 100644 embedding/browser/nsCWebBrowser.idl create mode 100644 embedding/browser/nsCommandHandler.cpp create mode 100644 embedding/browser/nsCommandHandler.h create mode 100644 embedding/browser/nsContextMenuInfo.cpp create mode 100644 embedding/browser/nsContextMenuInfo.h create mode 100644 embedding/browser/nsDocShellTreeOwner.cpp create mode 100644 embedding/browser/nsDocShellTreeOwner.h create mode 100644 embedding/browser/nsEmbedStream.cpp create mode 100644 embedding/browser/nsEmbedStream.h create mode 100644 embedding/browser/nsICommandHandler.idl create mode 100644 embedding/browser/nsIContextMenuListener.idl create mode 100644 embedding/browser/nsIContextMenuListener2.idl create mode 100644 embedding/browser/nsIEmbeddingSiteWindow.idl create mode 100644 embedding/browser/nsIPrintPreviewNavigation.idl create mode 100644 embedding/browser/nsIPrintingPromptService.idl create mode 100644 embedding/browser/nsITooltipListener.idl create mode 100644 embedding/browser/nsITooltipTextProvider.idl create mode 100644 embedding/browser/nsIWebBrowser.idl create mode 100644 embedding/browser/nsIWebBrowserChrome.idl create mode 100644 embedding/browser/nsIWebBrowserChrome2.idl create mode 100644 embedding/browser/nsIWebBrowserChrome3.idl create mode 100644 embedding/browser/nsIWebBrowserChromeFocus.idl create mode 100644 embedding/browser/nsIWebBrowserFocus.idl create mode 100644 embedding/browser/nsIWebBrowserPrint.idl create mode 100644 embedding/browser/nsIWebBrowserSetup.idl create mode 100644 embedding/browser/nsIWebBrowserStream.idl create mode 100644 embedding/browser/nsWebBrowser.cpp create mode 100644 embedding/browser/nsWebBrowser.h create mode 100644 embedding/browser/nsWebBrowserContentPolicy.cpp create mode 100644 embedding/browser/nsWebBrowserContentPolicy.h (limited to 'embedding/browser') diff --git a/embedding/browser/build/moz.build b/embedding/browser/build/moz.build new file mode 100644 index 000000000..cdd0f5a76 --- /dev/null +++ b/embedding/browser/build/moz.build @@ -0,0 +1,14 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +SOURCES += [ + 'nsWebBrowserModule.cpp', +] + +FINAL_LIBRARY = 'xul' +LOCAL_INCLUDES += [ + '..', +] diff --git a/embedding/browser/build/nsWebBrowserModule.cpp b/embedding/browser/build/nsWebBrowserModule.cpp new file mode 100644 index 000000000..a061a2b43 --- /dev/null +++ b/embedding/browser/build/nsWebBrowserModule.cpp @@ -0,0 +1,53 @@ +/* -*- 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/. */ + +#include "mozilla/ModuleUtils.h" +#include "nsIServiceManager.h" +#include "nsXPIDLString.h" + +#include "nsEmbedCID.h" + +#include "nsWebBrowser.h" +#include "nsCommandHandler.h" +#include "nsWebBrowserContentPolicy.h" + +// Factory Constructors + +NS_GENERIC_FACTORY_CONSTRUCTOR(nsWebBrowser) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsWebBrowserContentPolicy) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsCommandHandler) + +NS_DEFINE_NAMED_CID(NS_WEBBROWSER_CID); +NS_DEFINE_NAMED_CID(NS_COMMANDHANDLER_CID); +NS_DEFINE_NAMED_CID(NS_WEBBROWSERCONTENTPOLICY_CID); + +static const mozilla::Module::CIDEntry kWebBrowserCIDs[] = { + { &kNS_WEBBROWSER_CID, false, nullptr, nsWebBrowserConstructor }, + { &kNS_COMMANDHANDLER_CID, false, nullptr, nsCommandHandlerConstructor }, + { &kNS_WEBBROWSERCONTENTPOLICY_CID, false, nullptr, nsWebBrowserContentPolicyConstructor }, + { nullptr } +}; + +static const mozilla::Module::ContractIDEntry kWebBrowserContracts[] = { + { NS_WEBBROWSER_CONTRACTID, &kNS_WEBBROWSER_CID }, + { NS_COMMANDHANDLER_CONTRACTID, &kNS_COMMANDHANDLER_CID }, + { NS_WEBBROWSERCONTENTPOLICY_CONTRACTID, &kNS_WEBBROWSERCONTENTPOLICY_CID }, + { nullptr } +}; + +static const mozilla::Module::CategoryEntry kWebBrowserCategories[] = { + { "content-policy", NS_WEBBROWSERCONTENTPOLICY_CONTRACTID, NS_WEBBROWSERCONTENTPOLICY_CONTRACTID }, + { nullptr } +}; + +static const mozilla::Module kWebBrowserModule = { + mozilla::Module::kVersion, + kWebBrowserCIDs, + kWebBrowserContracts, + kWebBrowserCategories +}; + +NSMODULE_DEFN(Browser_Embedding_Module) = &kWebBrowserModule; diff --git a/embedding/browser/moz.build b/embedding/browser/moz.build new file mode 100644 index 000000000..179a6b6c8 --- /dev/null +++ b/embedding/browser/moz.build @@ -0,0 +1,57 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +DIRS += ['build'] + +XPIDL_SOURCES += [ + 'nsCWebBrowser.idl', + 'nsICommandHandler.idl', + 'nsIContextMenuListener.idl', + 'nsIContextMenuListener2.idl', + 'nsIEmbeddingSiteWindow.idl', + 'nsITooltipListener.idl', + 'nsITooltipTextProvider.idl', + 'nsIWebBrowser.idl', + 'nsIWebBrowserChrome.idl', + 'nsIWebBrowserChrome2.idl', + 'nsIWebBrowserChrome3.idl', + 'nsIWebBrowserChromeFocus.idl', + 'nsIWebBrowserFocus.idl', + 'nsIWebBrowserSetup.idl', + 'nsIWebBrowserStream.idl', +] + +if CONFIG['NS_PRINTING']: + XPIDL_SOURCES += [ + 'nsIPrintingPromptService.idl', + 'nsIWebBrowserPrint.idl', + ] + +XPIDL_MODULE = 'webBrowser_core' + +EXPORTS += [ + 'nsCTooltipTextProvider.h', +] + +UNIFIED_SOURCES += [ + 'nsCommandHandler.cpp', + 'nsContextMenuInfo.cpp', + 'nsDocShellTreeOwner.cpp', + 'nsEmbedStream.cpp', + 'nsWebBrowser.cpp', + 'nsWebBrowserContentPolicy.cpp', +] + +FINAL_LIBRARY = 'xul' +LOCAL_INCLUDES += [ + '/docshell/base', + '/dom/base', + '/dom/svg', + '/layout/style', +] + +if CONFIG['GNU_CXX']: + CXXFLAGS += ['-Wno-error=shadow'] diff --git a/embedding/browser/nsCTooltipTextProvider.h b/embedding/browser/nsCTooltipTextProvider.h new file mode 100644 index 000000000..95fb00432 --- /dev/null +++ b/embedding/browser/nsCTooltipTextProvider.h @@ -0,0 +1,17 @@ +/* -*- 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/. */ + +#ifndef NSCTOOLTIPTEXTPROVIDER_H +#define NSCTOOLTIPTEXTPROVIDER_H + +#include "nsITooltipTextProvider.h" + +#define NS_TOOLTIPTEXTPROVIDER_CONTRACTID \ + "@mozilla.org/embedcomp/tooltiptextprovider;1" +#define NS_DEFAULTTOOLTIPTEXTPROVIDER_CONTRACTID \ + "@mozilla.org/embedcomp/default-tooltiptextprovider;1" + +#endif diff --git a/embedding/browser/nsCWebBrowser.idl b/embedding/browser/nsCWebBrowser.idl new file mode 100644 index 000000000..21927f7c7 --- /dev/null +++ b/embedding/browser/nsCWebBrowser.idl @@ -0,0 +1,34 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsIWebBrowser.idl" +#include "nsIBaseWindow.idl" +#include "nsIScrollable.idl" +#include "nsITextScroll.idl" + +/* +nsCWebBrowser implements: +------------------------- +nsIWebBrowser +nsIDocShellTreeItem +nsIWebNavigation +nsIWebProgress +nsIBaseWindow +nsIScrollable +nsITextScroll +nsIInterfaceRequestor + + +Outwardly communicates with: +---------------------------- +nsIWebBrowserChrome +nsIBaseWindow +nsIInterfaceRequestor +*/ + +%{ C++ +#include "nsEmbedCID.h" +%} diff --git a/embedding/browser/nsCommandHandler.cpp b/embedding/browser/nsCommandHandler.cpp new file mode 100644 index 000000000..1e41e265a --- /dev/null +++ b/embedding/browser/nsCommandHandler.cpp @@ -0,0 +1,139 @@ +/* -*- 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/. */ + +#include "nsCommandHandler.h" +#include "nsWebBrowser.h" +#include "nsDocShellTreeOwner.h" + +#include "nsMemory.h" +#include "nsPIDOMWindow.h" + +nsCommandHandler::nsCommandHandler() + : mWindow(nullptr) +{ +} + +nsCommandHandler::~nsCommandHandler() +{ +} + +nsresult +nsCommandHandler::GetCommandHandler(nsICommandHandler** aCommandHandler) +{ + NS_ENSURE_ARG_POINTER(aCommandHandler); + + *aCommandHandler = nullptr; + if (!mWindow) { + return NS_ERROR_FAILURE; + } + + // Get the document tree owner + + nsCOMPtr docShellAsTreeItem = + do_QueryInterface(mWindow->GetDocShell()); + nsIDocShellTreeOwner* treeOwner = nullptr; + docShellAsTreeItem->GetTreeOwner(&treeOwner); + + // Make sure the tree owner is an an nsDocShellTreeOwner object + // by QI'ing for a hidden interface. If it doesn't have the interface + // then it's not safe to do the casting. + + nsCOMPtr realTreeOwner(do_QueryInterface(treeOwner)); + if (realTreeOwner) { + nsDocShellTreeOwner* tree = static_cast(treeOwner); + if (tree->mTreeOwner) { + nsresult rv; + rv = tree->mTreeOwner->QueryInterface(NS_GET_IID(nsICommandHandler), + (void**)aCommandHandler); + NS_RELEASE(treeOwner); + return rv; + } + + NS_RELEASE(treeOwner); + } + + *aCommandHandler = nullptr; + + return NS_OK; +} + +NS_IMPL_ADDREF(nsCommandHandler) +NS_IMPL_RELEASE(nsCommandHandler) + +NS_INTERFACE_MAP_BEGIN(nsCommandHandler) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsICommandHandler) + NS_INTERFACE_MAP_ENTRY(nsICommandHandlerInit) + NS_INTERFACE_MAP_ENTRY(nsICommandHandler) +NS_INTERFACE_MAP_END + +/////////////////////////////////////////////////////////////////////////////// +// nsICommandHandlerInit implementation + +NS_IMETHODIMP +nsCommandHandler::GetWindow(mozIDOMWindowProxy** aWindow) +{ + *aWindow = nullptr; + return NS_OK; +} + +NS_IMETHODIMP +nsCommandHandler::SetWindow(mozIDOMWindowProxy* aWindow) +{ + if (!aWindow) { + return NS_ERROR_FAILURE; + } + mWindow = nsPIDOMWindowOuter::From(aWindow); + return NS_OK; +} + +/////////////////////////////////////////////////////////////////////////////// +// nsICommandHandler implementation + +NS_IMETHODIMP +nsCommandHandler::Exec(const char* aCommand, const char* aStatus, + char** aResult) +{ + NS_ENSURE_ARG_POINTER(aCommand); + NS_ENSURE_ARG_POINTER(aResult); + + nsCOMPtr commandHandler; + GetCommandHandler(getter_AddRefs(commandHandler)); + + // Call the client's command handler to deal with this command + if (commandHandler) { + *aResult = nullptr; + return commandHandler->Exec(aCommand, aStatus, aResult); + } + + // Return an empty string + const char szEmpty[] = ""; + *aResult = (char*)nsMemory::Clone(szEmpty, sizeof(szEmpty)); + + return NS_OK; +} + +NS_IMETHODIMP +nsCommandHandler::Query(const char* aCommand, const char* aStatus, + char** aResult) +{ + NS_ENSURE_ARG_POINTER(aCommand); + NS_ENSURE_ARG_POINTER(aResult); + + nsCOMPtr commandHandler; + GetCommandHandler(getter_AddRefs(commandHandler)); + + // Call the client's command handler to deal with this command + if (commandHandler) { + *aResult = nullptr; + return commandHandler->Query(aCommand, aStatus, aResult); + } + + // Return an empty string + const char szEmpty[] = ""; + *aResult = (char*)nsMemory::Clone(szEmpty, sizeof(szEmpty)); + + return NS_OK; +} diff --git a/embedding/browser/nsCommandHandler.h b/embedding/browser/nsCommandHandler.h new file mode 100644 index 000000000..3d229b9d6 --- /dev/null +++ b/embedding/browser/nsCommandHandler.h @@ -0,0 +1,35 @@ +/* -*- 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/. */ + +#ifndef NSCOMMANDHANDLER_H +#define NSCOMMANDHANDLER_H + +#include "nsISupports.h" +#include "nsICommandHandler.h" + +class nsPIDOMWindowOuter; + +class nsCommandHandler + : public nsICommandHandlerInit + , public nsICommandHandler +{ +public: + nsCommandHandler(); + + NS_DECL_ISUPPORTS + NS_DECL_NSICOMMANDHANDLERINIT + NS_DECL_NSICOMMANDHANDLER + +protected: + virtual ~nsCommandHandler(); + +private: + nsresult GetCommandHandler(nsICommandHandler** aCommandHandler); + + nsPIDOMWindowOuter* mWindow; +}; + +#endif diff --git a/embedding/browser/nsContextMenuInfo.cpp b/embedding/browser/nsContextMenuInfo.cpp new file mode 100644 index 000000000..5052dda65 --- /dev/null +++ b/embedding/browser/nsContextMenuInfo.cpp @@ -0,0 +1,326 @@ +/* -*- 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/. */ + +#include "nsContextMenuInfo.h" + +#include "nsIImageLoadingContent.h" +#include "imgLoader.h" +#include "nsIDOMDocument.h" +#include "nsIDOMHTMLDocument.h" +#include "nsIDOMHTMLElement.h" +#include "nsIDOMHTMLHtmlElement.h" +#include "nsIDOMHTMLAnchorElement.h" +#include "nsIDOMHTMLImageElement.h" +#include "nsIDOMHTMLAreaElement.h" +#include "nsIDOMHTMLLinkElement.h" +#include "nsIDOMWindow.h" +#include "nsICSSDeclaration.h" +#include "nsIDOMCSSValue.h" +#include "nsIDOMCSSPrimitiveValue.h" +#include "nsNetUtil.h" +#include "nsUnicharUtils.h" +#include "nsIDocument.h" +#include "nsIPrincipal.h" +#include "nsIContentSecurityPolicy.h" +#include "nsIContentPolicy.h" +#include "imgRequestProxy.h" + +using mozilla::dom::Element; +using mozilla::ErrorResult; + +NS_IMPL_ISUPPORTS(nsContextMenuInfo, nsIContextMenuInfo) + +nsContextMenuInfo::nsContextMenuInfo() +{ +} + +nsContextMenuInfo::~nsContextMenuInfo() +{ +} + +NS_IMETHODIMP +nsContextMenuInfo::GetMouseEvent(nsIDOMEvent** aEvent) +{ + NS_ENSURE_ARG_POINTER(aEvent); + NS_IF_ADDREF(*aEvent = mMouseEvent); + return NS_OK; +} + +NS_IMETHODIMP +nsContextMenuInfo::GetTargetNode(nsIDOMNode** aNode) +{ + NS_ENSURE_ARG_POINTER(aNode); + NS_IF_ADDREF(*aNode = mDOMNode); + return NS_OK; +} + +NS_IMETHODIMP +nsContextMenuInfo::GetAssociatedLink(nsAString& aHRef) +{ + NS_ENSURE_STATE(mAssociatedLink); + aHRef.Truncate(0); + + nsCOMPtr content(do_QueryInterface(mAssociatedLink)); + nsAutoString localName; + if (content) { + content->GetLocalName(localName); + } + + nsCOMPtr linkContent; + ToLowerCase(localName); + if (localName.EqualsLiteral("a") || + localName.EqualsLiteral("area") || + localName.EqualsLiteral("link")) { + bool hasAttr; + content->HasAttribute(NS_LITERAL_STRING("href"), &hasAttr); + if (hasAttr) { + linkContent = content; + nsCOMPtr anchor(do_QueryInterface(linkContent)); + if (anchor) { + anchor->GetHref(aHRef); + } else { + nsCOMPtr area(do_QueryInterface(linkContent)); + if (area) { + area->GetHref(aHRef); + } else { + nsCOMPtr link(do_QueryInterface(linkContent)); + if (link) { + link->GetHref(aHRef); + } + } + } + } + } else { + nsCOMPtr curr; + mAssociatedLink->GetParentNode(getter_AddRefs(curr)); + while (curr) { + content = do_QueryInterface(curr); + if (!content) { + break; + } + content->GetLocalName(localName); + ToLowerCase(localName); + if (localName.EqualsLiteral("a")) { + bool hasAttr; + content->HasAttribute(NS_LITERAL_STRING("href"), &hasAttr); + if (hasAttr) { + linkContent = content; + nsCOMPtr anchor( + do_QueryInterface(linkContent)); + if (anchor) { + anchor->GetHref(aHRef); + } + } else { + linkContent = nullptr; // Links can't be nested. + } + break; + } + + nsCOMPtr temp = curr; + temp->GetParentNode(getter_AddRefs(curr)); + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsContextMenuInfo::GetImageContainer(imgIContainer** aImageContainer) +{ + NS_ENSURE_ARG_POINTER(aImageContainer); + NS_ENSURE_STATE(mDOMNode); + + nsCOMPtr request; + GetImageRequest(mDOMNode, getter_AddRefs(request)); + if (request) { + return request->GetImage(aImageContainer); + } + + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsContextMenuInfo::GetImageSrc(nsIURI** aURI) +{ + NS_ENSURE_ARG_POINTER(aURI); + NS_ENSURE_STATE(mDOMNode); + + nsCOMPtr content(do_QueryInterface(mDOMNode)); + NS_ENSURE_TRUE(content, NS_ERROR_FAILURE); + return content->GetCurrentURI(aURI); +} + +NS_IMETHODIMP +nsContextMenuInfo::GetBackgroundImageContainer(imgIContainer** aImageContainer) +{ + NS_ENSURE_ARG_POINTER(aImageContainer); + NS_ENSURE_STATE(mDOMNode); + + RefPtr request; + GetBackgroundImageRequest(mDOMNode, getter_AddRefs(request)); + if (request) { + return request->GetImage(aImageContainer); + } + + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsContextMenuInfo::GetBackgroundImageSrc(nsIURI** aURI) +{ + NS_ENSURE_ARG_POINTER(aURI); + NS_ENSURE_STATE(mDOMNode); + + RefPtr request; + GetBackgroundImageRequest(mDOMNode, getter_AddRefs(request)); + if (request) { + return request->GetURI(aURI); + } + + return NS_ERROR_FAILURE; +} + +nsresult +nsContextMenuInfo::GetImageRequest(nsIDOMNode* aDOMNode, imgIRequest** aRequest) +{ + NS_ENSURE_ARG(aDOMNode); + NS_ENSURE_ARG_POINTER(aRequest); + + // Get content + nsCOMPtr content(do_QueryInterface(aDOMNode)); + NS_ENSURE_TRUE(content, NS_ERROR_FAILURE); + + return content->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST, aRequest); +} + +bool +nsContextMenuInfo::HasBackgroundImage(nsIDOMNode* aDOMNode) +{ + NS_ENSURE_TRUE(aDOMNode, false); + + RefPtr request; + GetBackgroundImageRequest(aDOMNode, getter_AddRefs(request)); + + return (request != nullptr); +} + +nsresult +nsContextMenuInfo::GetBackgroundImageRequest(nsIDOMNode* aDOMNode, + imgRequestProxy** aRequest) +{ + + NS_ENSURE_ARG(aDOMNode); + NS_ENSURE_ARG_POINTER(aRequest); + + nsCOMPtr domNode = aDOMNode; + + // special case for the element: if it has no background-image + // we'll defer to + nsCOMPtr htmlElement = do_QueryInterface(domNode); + if (htmlElement) { + nsCOMPtr element = do_QueryInterface(domNode); + nsAutoString nameSpace; + element->GetNamespaceURI(nameSpace); + if (nameSpace.IsEmpty()) { + nsresult rv = GetBackgroundImageRequestInternal(domNode, aRequest); + if (NS_SUCCEEDED(rv) && *aRequest) { + return NS_OK; + } + + // no background-image found + nsCOMPtr document; + domNode->GetOwnerDocument(getter_AddRefs(document)); + nsCOMPtr htmlDocument(do_QueryInterface(document)); + NS_ENSURE_TRUE(htmlDocument, NS_ERROR_FAILURE); + + nsCOMPtr body; + htmlDocument->GetBody(getter_AddRefs(body)); + domNode = do_QueryInterface(body); + NS_ENSURE_TRUE(domNode, NS_ERROR_FAILURE); + } + } + return GetBackgroundImageRequestInternal(domNode, aRequest); +} + +nsresult +nsContextMenuInfo::GetBackgroundImageRequestInternal(nsIDOMNode* aDOMNode, + imgRequestProxy** aRequest) +{ + NS_ENSURE_ARG_POINTER(aDOMNode); + + nsCOMPtr domNode = aDOMNode; + nsCOMPtr parentNode; + + nsCOMPtr document; + domNode->GetOwnerDocument(getter_AddRefs(document)); + NS_ENSURE_TRUE(document, NS_ERROR_FAILURE); + + nsCOMPtr window; + document->GetDefaultView(getter_AddRefs(window)); + NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); + + auto* piWindow = nsPIDOMWindowOuter::From(window); + nsPIDOMWindowInner* innerWindow = piWindow->GetCurrentInnerWindow(); + MOZ_ASSERT(innerWindow); + + nsCOMPtr primitiveValue; + nsAutoString bgStringValue; + + nsCOMPtr doc(do_QueryInterface(document)); + nsCOMPtr principal = doc ? doc->NodePrincipal() : nullptr; + + while (true) { + nsCOMPtr domElement(do_QueryInterface(domNode)); + // bail for the parent node of the root element or null argument + if (!domElement) { + break; + } + + ErrorResult dummy; + nsCOMPtr computedStyle = + innerWindow->GetComputedStyle(*domElement, EmptyString(), dummy); + dummy.SuppressException(); + if (computedStyle) { + nsCOMPtr cssValue; + computedStyle->GetPropertyCSSValue(NS_LITERAL_STRING("background-image"), + getter_AddRefs(cssValue)); + primitiveValue = do_QueryInterface(cssValue); + if (primitiveValue) { + primitiveValue->GetStringValue(bgStringValue); + if (!bgStringValue.EqualsLiteral("none")) { + nsCOMPtr bgUri; + NS_NewURI(getter_AddRefs(bgUri), bgStringValue); + NS_ENSURE_TRUE(bgUri, NS_ERROR_FAILURE); + + imgLoader* il = imgLoader::NormalLoader(); + NS_ENSURE_TRUE(il, NS_ERROR_FAILURE); + + return il->LoadImage(bgUri, nullptr, nullptr, + doc->GetReferrerPolicy(), principal, nullptr, + nullptr, nullptr, nullptr, nsIRequest::LOAD_NORMAL, + nullptr, nsIContentPolicy::TYPE_INTERNAL_IMAGE, + EmptyString(), aRequest); + } + } + + // bail if we encounter non-transparent background-color + computedStyle->GetPropertyCSSValue(NS_LITERAL_STRING("background-color"), + getter_AddRefs(cssValue)); + primitiveValue = do_QueryInterface(cssValue); + if (primitiveValue) { + primitiveValue->GetStringValue(bgStringValue); + if (!bgStringValue.EqualsLiteral("transparent")) { + return NS_ERROR_FAILURE; + } + } + } + + domNode->GetParentNode(getter_AddRefs(parentNode)); + domNode = parentNode; + } + + return NS_ERROR_FAILURE; +} diff --git a/embedding/browser/nsContextMenuInfo.h b/embedding/browser/nsContextMenuInfo.h new file mode 100644 index 000000000..998045f97 --- /dev/null +++ b/embedding/browser/nsContextMenuInfo.h @@ -0,0 +1,54 @@ +/* -*- 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/. */ + +#ifndef nsContextMenuInfo_h__ +#define nsContextMenuInfo_h__ + +#include "nsCOMPtr.h" +#include "nsIContextMenuListener2.h" +#include "nsIDOMNode.h" +#include "nsIDOMEvent.h" +#include "imgIContainer.h" +#include "imgIRequest.h" + +class ChromeContextMenuListener; +class imgRequestProxy; + +// Helper class for implementors of nsIContextMenuListener2 +class nsContextMenuInfo : public nsIContextMenuInfo +{ + friend class ChromeContextMenuListener; + +public: + nsContextMenuInfo(); + + NS_DECL_ISUPPORTS + NS_DECL_NSICONTEXTMENUINFO + +private: + virtual ~nsContextMenuInfo(); + + void SetMouseEvent(nsIDOMEvent* aEvent) { mMouseEvent = aEvent; } + void SetDOMNode(nsIDOMNode* aNode) { mDOMNode = aNode; } + void SetAssociatedLink(nsIDOMNode* aLink) { mAssociatedLink = aLink; } + + nsresult GetImageRequest(nsIDOMNode* aDOMNode, imgIRequest** aRequest); + + bool HasBackgroundImage(nsIDOMNode* aDOMNode); + + nsresult GetBackgroundImageRequest(nsIDOMNode* aDOMNode, + imgRequestProxy** aRequest); + + nsresult GetBackgroundImageRequestInternal(nsIDOMNode* aDOMNode, + imgRequestProxy** aRequest); + +private: + nsCOMPtr mMouseEvent; + nsCOMPtr mDOMNode; + nsCOMPtr mAssociatedLink; +}; + +#endif // nsContextMenuInfo_h__ diff --git a/embedding/browser/nsDocShellTreeOwner.cpp b/embedding/browser/nsDocShellTreeOwner.cpp new file mode 100644 index 000000000..73397cc8b --- /dev/null +++ b/embedding/browser/nsDocShellTreeOwner.cpp @@ -0,0 +1,1674 @@ +/* -*- 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 "nsDocShellTreeOwner.h" +#include "nsWebBrowser.h" + +// Helper Classes +#include "nsStyleCoord.h" +#include "nsSize.h" +#include "mozilla/ReflowInput.h" +#include "nsIServiceManager.h" +#include "nsComponentManagerUtils.h" +#include "nsXPIDLString.h" +#include "nsIAtom.h" +#include "nsReadableUtils.h" +#include "nsUnicharUtils.h" +#include "nsISimpleEnumerator.h" +#include "mozilla/LookAndFeel.h" + +// Interfaces needed to be included +#include "nsPresContext.h" +#include "nsIContextMenuListener.h" +#include "nsIContextMenuListener2.h" +#include "nsITooltipListener.h" +#include "nsIDOMNode.h" +#include "nsIDOMNodeList.h" +#include "nsIDOMDocument.h" +#include "nsIDOMDocumentType.h" +#include "nsIDOMElement.h" +#include "Link.h" +#include "mozilla/dom/Element.h" +#include "mozilla/dom/SVGTitleElement.h" +#include "nsIDOMEvent.h" +#include "nsIDOMFileList.h" +#include "nsIDOMMouseEvent.h" +#include "nsIFormControl.h" +#include "nsIDOMHTMLInputElement.h" +#include "nsIDOMHTMLTextAreaElement.h" +#include "nsIDOMHTMLHtmlElement.h" +#include "nsIDOMHTMLAppletElement.h" +#include "nsIDOMHTMLObjectElement.h" +#include "nsIDOMHTMLEmbedElement.h" +#include "nsIDOMHTMLDocument.h" +#include "nsIImageLoadingContent.h" +#include "nsIWebNavigation.h" +#include "nsIDOMHTMLElement.h" +#include "nsIPresShell.h" +#include "nsIStringBundle.h" +#include "nsPIDOMWindow.h" +#include "nsPIWindowRoot.h" +#include "nsIDOMWindowCollection.h" +#include "nsIWindowWatcher.h" +#include "nsPIWindowWatcher.h" +#include "nsIPrompt.h" +#include "nsITabParent.h" +#include "nsITabChild.h" +#include "nsRect.h" +#include "nsIWebBrowserChromeFocus.h" +#include "nsIContent.h" +#include "imgIContainer.h" +#include "nsContextMenuInfo.h" +#include "nsPresContext.h" +#include "nsViewManager.h" +#include "nsView.h" +#include "nsIDOMDragEvent.h" +#include "nsIConstraintValidation.h" +#include "mozilla/Attributes.h" +#include "mozilla/EventListenerManager.h" +#include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent() +#include "mozilla/dom/File.h" // for input type=file +#include "mozilla/dom/FileList.h" // for input type=file + +using namespace mozilla; +using namespace mozilla::dom; + +// A helper routine that navigates the tricky path from a |nsWebBrowser| to +// a |EventTarget| via the window root and chrome event handler. +static nsresult +GetDOMEventTarget(nsWebBrowser* aInBrowser, EventTarget** aTarget) +{ + if (!aInBrowser) { + return NS_ERROR_INVALID_POINTER; + } + + nsCOMPtr domWindow; + aInBrowser->GetContentDOMWindow(getter_AddRefs(domWindow)); + if (!domWindow) { + return NS_ERROR_FAILURE; + } + + auto* outerWindow = nsPIDOMWindowOuter::From(domWindow); + nsPIDOMWindowOuter* rootWindow = outerWindow->GetPrivateRoot(); + NS_ENSURE_TRUE(rootWindow, NS_ERROR_FAILURE); + nsCOMPtr target = rootWindow->GetChromeEventHandler(); + NS_ENSURE_TRUE(target, NS_ERROR_FAILURE); + target.forget(aTarget); + + return NS_OK; +} + +nsDocShellTreeOwner::nsDocShellTreeOwner() + : mWebBrowser(nullptr) + , mTreeOwner(nullptr) + , mPrimaryContentShell(nullptr) + , mWebBrowserChrome(nullptr) + , mOwnerWin(nullptr) + , mOwnerRequestor(nullptr) +{ +} + +nsDocShellTreeOwner::~nsDocShellTreeOwner() +{ + RemoveChromeListeners(); +} + +NS_IMPL_ADDREF(nsDocShellTreeOwner) +NS_IMPL_RELEASE(nsDocShellTreeOwner) + +NS_INTERFACE_MAP_BEGIN(nsDocShellTreeOwner) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocShellTreeOwner) + NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeOwner) + NS_INTERFACE_MAP_ENTRY(nsIBaseWindow) + NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) + NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener) + NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener) + NS_INTERFACE_MAP_ENTRY(nsICDocShellTreeOwner) + NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) +NS_INTERFACE_MAP_END + +//***************************************************************************** +// nsDocShellTreeOwner::nsIInterfaceRequestor +//***************************************************************************** + +NS_IMETHODIMP +nsDocShellTreeOwner::GetInterface(const nsIID& aIID, void** aSink) +{ + NS_ENSURE_ARG_POINTER(aSink); + + if (NS_SUCCEEDED(QueryInterface(aIID, aSink))) { + return NS_OK; + } + + if (aIID.Equals(NS_GET_IID(nsIWebBrowserChromeFocus))) { + if (mWebBrowserChromeWeak != nullptr) { + return mWebBrowserChromeWeak->QueryReferent(aIID, aSink); + } + return mOwnerWin->QueryInterface(aIID, aSink); + } + + if (aIID.Equals(NS_GET_IID(nsIPrompt))) { + nsCOMPtr prompt; + EnsurePrompter(); + prompt = mPrompter; + if (prompt) { + prompt.forget(aSink); + return NS_OK; + } + return NS_NOINTERFACE; + } + + if (aIID.Equals(NS_GET_IID(nsIAuthPrompt))) { + nsCOMPtr prompt; + EnsureAuthPrompter(); + prompt = mAuthPrompter; + if (prompt) { + prompt.forget(aSink); + return NS_OK; + } + return NS_NOINTERFACE; + } + + nsCOMPtr req = GetOwnerRequestor(); + if (req) { + return req->GetInterface(aIID, aSink); + } + + return NS_NOINTERFACE; +} + +//***************************************************************************** +// nsDocShellTreeOwner::nsIDocShellTreeOwner +//***************************************************************************** + +void +nsDocShellTreeOwner::EnsurePrompter() +{ + if (mPrompter) { + return; + } + + nsCOMPtr wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID)); + if (wwatch && mWebBrowser) { + nsCOMPtr domWindow; + mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow)); + if (domWindow) { + wwatch->GetNewPrompter(domWindow, getter_AddRefs(mPrompter)); + } + } +} + +void +nsDocShellTreeOwner::EnsureAuthPrompter() +{ + if (mAuthPrompter) { + return; + } + + nsCOMPtr wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID)); + if (wwatch && mWebBrowser) { + nsCOMPtr domWindow; + mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow)); + if (domWindow) { + wwatch->GetNewAuthPrompter(domWindow, getter_AddRefs(mAuthPrompter)); + } + } +} + +void +nsDocShellTreeOwner::AddToWatcher() +{ + if (mWebBrowser) { + nsCOMPtr domWindow; + mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow)); + if (domWindow) { + nsCOMPtr wwatch( + do_GetService(NS_WINDOWWATCHER_CONTRACTID)); + if (wwatch) { + nsCOMPtr webBrowserChrome = GetWebBrowserChrome(); + if (webBrowserChrome) { + wwatch->AddWindow(domWindow, webBrowserChrome); + } + } + } + } +} + +void +nsDocShellTreeOwner::RemoveFromWatcher() +{ + if (mWebBrowser) { + nsCOMPtr domWindow; + mWebBrowser->GetContentDOMWindow(getter_AddRefs(domWindow)); + if (domWindow) { + nsCOMPtr wwatch( + do_GetService(NS_WINDOWWATCHER_CONTRACTID)); + if (wwatch) { + wwatch->RemoveWindow(domWindow); + } + } + } +} + +void +nsDocShellTreeOwner::EnsureContentTreeOwner() +{ + if (mContentTreeOwner) { + return; + } + + mContentTreeOwner = new nsDocShellTreeOwner(); + nsCOMPtr browserChrome = GetWebBrowserChrome(); + if (browserChrome) { + mContentTreeOwner->SetWebBrowserChrome(browserChrome); + } + + if (mWebBrowser) { + mContentTreeOwner->WebBrowser(mWebBrowser); + } +} + +NS_IMETHODIMP +nsDocShellTreeOwner::ContentShellAdded(nsIDocShellTreeItem* aContentShell, + bool aPrimary, bool aTargetable, + const nsAString& aID) +{ + if (mTreeOwner) + return mTreeOwner->ContentShellAdded(aContentShell, aPrimary, aTargetable, + aID); + + EnsureContentTreeOwner(); + aContentShell->SetTreeOwner(mContentTreeOwner); + + if (aPrimary) { + mPrimaryContentShell = aContentShell; + mPrimaryTabParent = nullptr; + } + return NS_OK; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::ContentShellRemoved(nsIDocShellTreeItem* aContentShell) +{ + if (mTreeOwner) { + return mTreeOwner->ContentShellRemoved(aContentShell); + } + + if (mPrimaryContentShell == aContentShell) { + mPrimaryContentShell = nullptr; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::GetPrimaryContentShell(nsIDocShellTreeItem** aShell) +{ + NS_ENSURE_ARG_POINTER(aShell); + + if (mTreeOwner) { + return mTreeOwner->GetPrimaryContentShell(aShell); + } + + nsCOMPtr shell; + if (!mPrimaryTabParent) { + shell = + mPrimaryContentShell ? mPrimaryContentShell : mWebBrowser->mDocShell; + } + shell.forget(aShell); + + return NS_OK; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::TabParentAdded(nsITabParent* aTab, bool aPrimary) +{ + if (mTreeOwner) { + return mTreeOwner->TabParentAdded(aTab, aPrimary); + } + + if (aPrimary) { + mPrimaryTabParent = aTab; + mPrimaryContentShell = nullptr; + } else if (mPrimaryTabParent == aTab) { + mPrimaryTabParent = nullptr; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::TabParentRemoved(nsITabParent* aTab) +{ + if (mTreeOwner) { + return mTreeOwner->TabParentRemoved(aTab); + } + + if (aTab == mPrimaryTabParent) { + mPrimaryTabParent = nullptr; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::GetPrimaryTabParent(nsITabParent** aTab) +{ + if (mTreeOwner) { + return mTreeOwner->GetPrimaryTabParent(aTab); + } + + nsCOMPtr tab = mPrimaryTabParent; + tab.forget(aTab); + return NS_OK; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::GetPrimaryContentSize(int32_t* aWidth, + int32_t* aHeight) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::SetPrimaryContentSize(int32_t aWidth, + int32_t aHeight) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::GetRootShellSize(int32_t* aWidth, + int32_t* aHeight) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::SetRootShellSize(int32_t aWidth, + int32_t aHeight) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::SizeShellTo(nsIDocShellTreeItem* aShellItem, + int32_t aCX, int32_t aCY) +{ + nsCOMPtr webBrowserChrome = GetWebBrowserChrome(); + + NS_ENSURE_STATE(mTreeOwner || webBrowserChrome); + + if (mTreeOwner) { + return mTreeOwner->SizeShellTo(aShellItem, aCX, aCY); + } + + if (aShellItem == mWebBrowser->mDocShell) { + nsCOMPtr tabChild = do_QueryInterface(webBrowserChrome); + if (tabChild) { + // The XUL window to resize is in the parent process, but there we + // won't be able to get aShellItem to do the hack in nsXULWindow::SizeShellTo, + // so let's send the width and height of aShellItem too. + nsCOMPtr shellAsWin(do_QueryInterface(aShellItem)); + NS_ENSURE_TRUE(shellAsWin, NS_ERROR_FAILURE); + + int32_t width = 0; + int32_t height = 0; + shellAsWin->GetSize(&width, &height); + return tabChild->RemoteSizeShellTo(aCX, aCY, width, height); + } + return webBrowserChrome->SizeBrowserTo(aCX, aCY); + } + + nsCOMPtr webNav(do_QueryInterface(aShellItem)); + NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE); + + nsCOMPtr domDocument; + webNav->GetDocument(getter_AddRefs(domDocument)); + NS_ENSURE_TRUE(domDocument, NS_ERROR_FAILURE); + + nsCOMPtr domElement; + domDocument->GetDocumentElement(getter_AddRefs(domElement)); + NS_ENSURE_TRUE(domElement, NS_ERROR_FAILURE); + + // Set the preferred Size + //XXX + NS_ERROR("Implement this"); + /* + Set the preferred size on the aShellItem. + */ + + RefPtr presContext; + mWebBrowser->mDocShell->GetPresContext(getter_AddRefs(presContext)); + NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE); + + nsIPresShell* presShell = presContext->GetPresShell(); + NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); + + NS_ENSURE_SUCCESS( + presShell->ResizeReflow(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE), + NS_ERROR_FAILURE); + + nsRect shellArea = presContext->GetVisibleArea(); + + int32_t browserCX = presContext->AppUnitsToDevPixels(shellArea.width); + int32_t browserCY = presContext->AppUnitsToDevPixels(shellArea.height); + + return webBrowserChrome->SizeBrowserTo(browserCX, browserCY); +} + +NS_IMETHODIMP +nsDocShellTreeOwner::SetPersistence(bool aPersistPosition, + bool aPersistSize, + bool aPersistSizeMode) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::GetPersistence(bool* aPersistPosition, + bool* aPersistSize, + bool* aPersistSizeMode) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::GetTargetableShellCount(uint32_t* aResult) +{ + if (mTreeOwner) { + mTreeOwner->GetTargetableShellCount(aResult); + } else { + *aResult = 0; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::GetHasPrimaryContent(bool* aResult) +{ + *aResult = mPrimaryTabParent || mPrimaryContentShell; + return NS_OK; +} + +//***************************************************************************** +// nsDocShellTreeOwner::nsIBaseWindow +//***************************************************************************** + +NS_IMETHODIMP +nsDocShellTreeOwner::InitWindow(nativeWindow aParentNativeWindow, + nsIWidget* aParentWidget, int32_t aX, + int32_t aY, int32_t aCX, int32_t aCY) +{ + return NS_ERROR_NULL_POINTER; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::Create() +{ + return NS_ERROR_NULL_POINTER; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::Destroy() +{ + nsCOMPtr webBrowserChrome = GetWebBrowserChrome(); + if (webBrowserChrome) { + return webBrowserChrome->DestroyBrowserWindow(); + } + + return NS_ERROR_NULL_POINTER; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::GetUnscaledDevicePixelsPerCSSPixel(double* aScale) +{ + if (mWebBrowser) { + return mWebBrowser->GetUnscaledDevicePixelsPerCSSPixel(aScale); + } + + *aScale = 1.0; + return NS_OK; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::GetDevicePixelsPerDesktopPixel(double* aScale) +{ + if (mWebBrowser) { + return mWebBrowser->GetDevicePixelsPerDesktopPixel(aScale); + } + + *aScale = 1.0; + return NS_OK; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::SetPositionDesktopPix(int32_t aX, int32_t aY) +{ + if (mWebBrowser) { + nsresult rv = mWebBrowser->SetPositionDesktopPix(aX, aY); + NS_ENSURE_SUCCESS(rv, rv); + } + + double scale = 1.0; + GetDevicePixelsPerDesktopPixel(&scale); + return SetPosition(NSToIntRound(aX * scale), NSToIntRound(aY * scale)); +} + +NS_IMETHODIMP +nsDocShellTreeOwner::SetPosition(int32_t aX, int32_t aY) +{ + nsCOMPtr ownerWin = GetOwnerWin(); + if (ownerWin) { + return ownerWin->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION, + aX, aY, 0, 0); + } + return NS_ERROR_NULL_POINTER; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::GetPosition(int32_t* aX, int32_t* aY) +{ + nsCOMPtr ownerWin = GetOwnerWin(); + if (ownerWin) { + return ownerWin->GetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION, + aX, aY, nullptr, nullptr); + } + return NS_ERROR_NULL_POINTER; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::SetSize(int32_t aCX, int32_t aCY, bool aRepaint) +{ + nsCOMPtr ownerWin = GetOwnerWin(); + if (ownerWin) { + return ownerWin->SetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER, + 0, 0, aCX, aCY); + } + return NS_ERROR_NULL_POINTER; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::GetSize(int32_t* aCX, int32_t* aCY) +{ + nsCOMPtr ownerWin = GetOwnerWin(); + if (ownerWin) { + return ownerWin->GetDimensions(nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER, + nullptr, nullptr, aCX, aCY); + } + return NS_ERROR_NULL_POINTER; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::SetPositionAndSize(int32_t aX, int32_t aY, int32_t aCX, + int32_t aCY, uint32_t aFlags) +{ + nsCOMPtr ownerWin = GetOwnerWin(); + if (ownerWin) { + return ownerWin->SetDimensions( + nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER | + nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION, + aX, aY, aCX, aCY); + } + return NS_ERROR_NULL_POINTER; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::GetPositionAndSize(int32_t* aX, int32_t* aY, int32_t* aCX, + int32_t* aCY) +{ + nsCOMPtr ownerWin = GetOwnerWin(); + if (ownerWin) { + return ownerWin->GetDimensions( + nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_OUTER | + nsIEmbeddingSiteWindow::DIM_FLAGS_POSITION, + aX, aY, aCX, aCY); + } + return NS_ERROR_NULL_POINTER; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::Repaint(bool aForce) +{ + return NS_ERROR_NULL_POINTER; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::GetParentWidget(nsIWidget** aParentWidget) +{ + return NS_ERROR_NULL_POINTER; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::SetParentWidget(nsIWidget* aParentWidget) +{ + return NS_ERROR_NULL_POINTER; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::GetParentNativeWindow(nativeWindow* aParentNativeWindow) +{ + nsCOMPtr ownerWin = GetOwnerWin(); + if (ownerWin) { + return ownerWin->GetSiteWindow(aParentNativeWindow); + } + return NS_ERROR_NULL_POINTER; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::SetParentNativeWindow(nativeWindow aParentNativeWindow) +{ + return NS_ERROR_NULL_POINTER; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::GetNativeHandle(nsAString& aNativeHandle) +{ + // the nativeHandle should be accessed from nsIXULWindow + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::GetVisibility(bool* aVisibility) +{ + nsCOMPtr ownerWin = GetOwnerWin(); + if (ownerWin) { + return ownerWin->GetVisibility(aVisibility); + } + return NS_ERROR_NULL_POINTER; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::SetVisibility(bool aVisibility) +{ + nsCOMPtr ownerWin = GetOwnerWin(); + if (ownerWin) { + return ownerWin->SetVisibility(aVisibility); + } + return NS_ERROR_NULL_POINTER; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::GetEnabled(bool* aEnabled) +{ + NS_ENSURE_ARG_POINTER(aEnabled); + *aEnabled = true; + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::SetEnabled(bool aEnabled) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::GetMainWidget(nsIWidget** aMainWidget) +{ + return NS_ERROR_NULL_POINTER; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::SetFocus() +{ + nsCOMPtr ownerWin = GetOwnerWin(); + if (ownerWin) { + return ownerWin->SetFocus(); + } + return NS_ERROR_NULL_POINTER; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::GetTitle(char16_t** aTitle) +{ + nsCOMPtr ownerWin = GetOwnerWin(); + if (ownerWin) { + return ownerWin->GetTitle(aTitle); + } + return NS_ERROR_NULL_POINTER; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::SetTitle(const char16_t* aTitle) +{ + nsCOMPtr ownerWin = GetOwnerWin(); + if (ownerWin) { + return ownerWin->SetTitle(aTitle); + } + return NS_ERROR_NULL_POINTER; +} + +//***************************************************************************** +// nsDocShellTreeOwner::nsIWebProgressListener +//***************************************************************************** + +NS_IMETHODIMP +nsDocShellTreeOwner::OnProgressChange(nsIWebProgress* aProgress, + nsIRequest* aRequest, + int32_t aCurSelfProgress, + int32_t aMaxSelfProgress, + int32_t aCurTotalProgress, + int32_t aMaxTotalProgress) +{ + // In the absence of DOM document creation event, this method is the + // most convenient place to install the mouse listener on the + // DOM document. + return AddChromeListeners(); +} + +NS_IMETHODIMP +nsDocShellTreeOwner::OnStateChange(nsIWebProgress* aProgress, + nsIRequest* aRequest, + uint32_t aProgressStateFlags, + nsresult aStatus) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::OnLocationChange(nsIWebProgress* aWebProgress, + nsIRequest* aRequest, + nsIURI* aURI, + uint32_t aFlags) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::OnStatusChange(nsIWebProgress* aWebProgress, + nsIRequest* aRequest, + nsresult aStatus, + const char16_t* aMessage) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::OnSecurityChange(nsIWebProgress* aWebProgress, + nsIRequest* aRequest, + uint32_t aState) +{ + return NS_OK; +} + +//***************************************************************************** +// nsDocShellTreeOwner: Accessors +//***************************************************************************** + +void +nsDocShellTreeOwner::WebBrowser(nsWebBrowser* aWebBrowser) +{ + if (!aWebBrowser) { + RemoveChromeListeners(); + } + if (aWebBrowser != mWebBrowser) { + mPrompter = nullptr; + mAuthPrompter = nullptr; + } + + mWebBrowser = aWebBrowser; + + if (mContentTreeOwner) { + mContentTreeOwner->WebBrowser(aWebBrowser); + if (!aWebBrowser) { + mContentTreeOwner = nullptr; + } + } +} + +nsWebBrowser* +nsDocShellTreeOwner::WebBrowser() +{ + return mWebBrowser; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::SetTreeOwner(nsIDocShellTreeOwner* aTreeOwner) +{ + if (aTreeOwner) { + nsCOMPtr webBrowserChrome(do_GetInterface(aTreeOwner)); + NS_ENSURE_TRUE(webBrowserChrome, NS_ERROR_INVALID_ARG); + NS_ENSURE_SUCCESS(SetWebBrowserChrome(webBrowserChrome), + NS_ERROR_INVALID_ARG); + mTreeOwner = aTreeOwner; + } else { + mTreeOwner = nullptr; + nsCOMPtr webBrowserChrome = GetWebBrowserChrome(); + if (!webBrowserChrome) { + NS_ENSURE_SUCCESS(SetWebBrowserChrome(nullptr), NS_ERROR_FAILURE); + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::SetWebBrowserChrome(nsIWebBrowserChrome* aWebBrowserChrome) +{ + if (!aWebBrowserChrome) { + mWebBrowserChrome = nullptr; + mOwnerWin = nullptr; + mOwnerRequestor = nullptr; + mWebBrowserChromeWeak = nullptr; + } else { + nsCOMPtr supportsweak = + do_QueryInterface(aWebBrowserChrome); + if (supportsweak) { + supportsweak->GetWeakReference(getter_AddRefs(mWebBrowserChromeWeak)); + } else { + nsCOMPtr ownerWin( + do_QueryInterface(aWebBrowserChrome)); + nsCOMPtr requestor( + do_QueryInterface(aWebBrowserChrome)); + + // it's ok for ownerWin or requestor to be null. + mWebBrowserChrome = aWebBrowserChrome; + mOwnerWin = ownerWin; + mOwnerRequestor = requestor; + } + } + + if (mContentTreeOwner) { + mContentTreeOwner->SetWebBrowserChrome(aWebBrowserChrome); + } + + return NS_OK; +} + +// Hook up things to the chrome like context menus and tooltips, if the chrome +// has implemented the right interfaces. +NS_IMETHODIMP +nsDocShellTreeOwner::AddChromeListeners() +{ + nsresult rv = NS_OK; + + nsCOMPtr webBrowserChrome = GetWebBrowserChrome(); + if (!webBrowserChrome) { + return NS_ERROR_FAILURE; + } + + // install tooltips + if (!mChromeTooltipListener) { + nsCOMPtr tooltipListener( + do_QueryInterface(webBrowserChrome)); + if (tooltipListener) { + mChromeTooltipListener = new ChromeTooltipListener(mWebBrowser, + webBrowserChrome); + rv = mChromeTooltipListener->AddChromeListeners(); + } + } + + // install context menus + if (!mChromeContextMenuListener) { + nsCOMPtr contextListener2( + do_QueryInterface(webBrowserChrome)); + nsCOMPtr contextListener( + do_QueryInterface(webBrowserChrome)); + if (contextListener2 || contextListener) { + mChromeContextMenuListener = + new ChromeContextMenuListener(mWebBrowser, webBrowserChrome); + rv = mChromeContextMenuListener->AddChromeListeners(); + } + } + + // register dragover and drop event listeners with the listener manager + nsCOMPtr target; + GetDOMEventTarget(mWebBrowser, getter_AddRefs(target)); + + EventListenerManager* elmP = target->GetOrCreateListenerManager(); + if (elmP) { + elmP->AddEventListenerByType(this, NS_LITERAL_STRING("dragover"), + TrustedEventsAtSystemGroupBubble()); + elmP->AddEventListenerByType(this, NS_LITERAL_STRING("drop"), + TrustedEventsAtSystemGroupBubble()); + } + + return rv; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::RemoveChromeListeners() +{ + if (mChromeTooltipListener) { + mChromeTooltipListener->RemoveChromeListeners(); + mChromeTooltipListener = nullptr; + } + if (mChromeContextMenuListener) { + mChromeContextMenuListener->RemoveChromeListeners(); + mChromeContextMenuListener = nullptr; + } + + nsCOMPtr piTarget; + GetDOMEventTarget(mWebBrowser, getter_AddRefs(piTarget)); + if (!piTarget) { + return NS_OK; + } + + EventListenerManager* elmP = piTarget->GetOrCreateListenerManager(); + if (elmP) { + elmP->RemoveEventListenerByType(this, NS_LITERAL_STRING("dragover"), + TrustedEventsAtSystemGroupBubble()); + elmP->RemoveEventListenerByType(this, NS_LITERAL_STRING("drop"), + TrustedEventsAtSystemGroupBubble()); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsDocShellTreeOwner::HandleEvent(nsIDOMEvent* aEvent) +{ + nsCOMPtr dragEvent = do_QueryInterface(aEvent); + NS_ENSURE_TRUE(dragEvent, NS_ERROR_INVALID_ARG); + + bool defaultPrevented; + aEvent->GetDefaultPrevented(&defaultPrevented); + if (defaultPrevented) { + return NS_OK; + } + + nsCOMPtr handler = + do_GetService("@mozilla.org/content/dropped-link-handler;1"); + if (handler) { + nsAutoString eventType; + aEvent->GetType(eventType); + if (eventType.EqualsLiteral("dragover")) { + bool canDropLink = false; + handler->CanDropLink(dragEvent, false, &canDropLink); + if (canDropLink) { + aEvent->PreventDefault(); + } + } else if (eventType.EqualsLiteral("drop")) { + nsIWebNavigation* webnav = static_cast(mWebBrowser); + + uint32_t linksCount; + nsIDroppedLinkItem** links; + if (webnav && + NS_SUCCEEDED(handler->DropLinks(dragEvent, true, &linksCount, &links))) { + if (linksCount >= 1) { + nsCOMPtr webBrowserChrome = GetWebBrowserChrome(); + if (webBrowserChrome) { + nsCOMPtr tabChild = do_QueryInterface(webBrowserChrome); + if (tabChild) { + nsresult rv = tabChild->RemoteDropLinks(linksCount, links); + for (uint32_t i = 0; i < linksCount; i++) { + NS_RELEASE(links[i]); + } + free(links); + return rv; + } + } + nsAutoString url; + if (NS_SUCCEEDED(links[0]->GetUrl(url))) { + if (!url.IsEmpty()) { + webnav->LoadURI(url.get(), 0, nullptr, nullptr, nullptr); + } + } + + for (uint32_t i = 0; i < linksCount; i++) { + NS_RELEASE(links[i]); + } + free(links); + } + } else { + aEvent->StopPropagation(); + aEvent->PreventDefault(); + } + } + } + + return NS_OK; +} + +already_AddRefed +nsDocShellTreeOwner::GetWebBrowserChrome() +{ + nsCOMPtr chrome; + if (mWebBrowserChromeWeak) { + chrome = do_QueryReferent(mWebBrowserChromeWeak); + } else if (mWebBrowserChrome) { + chrome = mWebBrowserChrome; + } + return chrome.forget(); +} + +already_AddRefed +nsDocShellTreeOwner::GetOwnerWin() +{ + nsCOMPtr win; + if (mWebBrowserChromeWeak) { + win = do_QueryReferent(mWebBrowserChromeWeak); + } else if (mOwnerWin) { + win = mOwnerWin; + } + return win.forget(); +} + +already_AddRefed +nsDocShellTreeOwner::GetOwnerRequestor() +{ + nsCOMPtr req; + if (mWebBrowserChromeWeak) { + req = do_QueryReferent(mWebBrowserChromeWeak); + } else if (mOwnerRequestor) { + req = mOwnerRequestor; + } + return req.forget(); +} + +NS_IMPL_ISUPPORTS(ChromeTooltipListener, nsIDOMEventListener) + +ChromeTooltipListener::ChromeTooltipListener(nsWebBrowser* aInBrowser, + nsIWebBrowserChrome* aInChrome) + : mWebBrowser(aInBrowser) + , mWebBrowserChrome(aInChrome) + , mTooltipListenerInstalled(false) + , mMouseClientX(0) + , mMouseClientY(0) + , mMouseScreenX(0) + , mMouseScreenY(0) + , mShowingTooltip(false) + , mTooltipShownOnce(false) +{ + mTooltipTextProvider = do_GetService(NS_TOOLTIPTEXTPROVIDER_CONTRACTID); + if (!mTooltipTextProvider) { + mTooltipTextProvider = do_GetService(NS_DEFAULTTOOLTIPTEXTPROVIDER_CONTRACTID); + } +} + +ChromeTooltipListener::~ChromeTooltipListener() +{ +} + +// Hook up things to the chrome like context menus and tooltips, if the chrome +// has implemented the right interfaces. +NS_IMETHODIMP +ChromeTooltipListener::AddChromeListeners() +{ + if (!mEventTarget) { + GetDOMEventTarget(mWebBrowser, getter_AddRefs(mEventTarget)); + } + + // Register the appropriate events for tooltips, but only if + // the embedding chrome cares. + nsresult rv = NS_OK; + nsCOMPtr tooltipListener( + do_QueryInterface(mWebBrowserChrome)); + if (tooltipListener && !mTooltipListenerInstalled) { + rv = AddTooltipListener(); + if (NS_FAILED(rv)) { + return rv; + } + } + + return rv; +} + +// Subscribe to the events that will allow us to track tooltips. We need "mouse" +// for mouseExit, "mouse motion" for mouseMove, and "key" for keyDown. As we +// add the listeners, keep track of how many succeed so we can clean up +// correctly in Release(). +NS_IMETHODIMP +ChromeTooltipListener::AddTooltipListener() +{ + if (mEventTarget) { + nsresult rv = NS_OK; + rv = mEventTarget->AddSystemEventListener(NS_LITERAL_STRING("keydown"), + this, false, false); + NS_ENSURE_SUCCESS(rv, rv); + rv = mEventTarget->AddSystemEventListener(NS_LITERAL_STRING("mousedown"), + this, false, false); + NS_ENSURE_SUCCESS(rv, rv); + rv = mEventTarget->AddSystemEventListener(NS_LITERAL_STRING("mouseout"), + this, false, false); + NS_ENSURE_SUCCESS(rv, rv); + rv = mEventTarget->AddSystemEventListener(NS_LITERAL_STRING("mousemove"), + this, false, false); + NS_ENSURE_SUCCESS(rv, rv); + + mTooltipListenerInstalled = true; + } + + return NS_OK; +} + +// Unsubscribe from the various things we've hooked up to the window root. +NS_IMETHODIMP +ChromeTooltipListener::RemoveChromeListeners() +{ + HideTooltip(); + + if (mTooltipListenerInstalled) { + RemoveTooltipListener(); + } + + mEventTarget = nullptr; + + // it really doesn't matter if these fail... + return NS_OK; +} + +// Unsubscribe from all the various tooltip events that we were listening to. +NS_IMETHODIMP +ChromeTooltipListener::RemoveTooltipListener() +{ + if (mEventTarget) { + nsresult rv = NS_OK; + rv = mEventTarget->RemoveSystemEventListener(NS_LITERAL_STRING("keydown"), + this, false); + NS_ENSURE_SUCCESS(rv, rv); + rv = mEventTarget->RemoveSystemEventListener(NS_LITERAL_STRING("mousedown"), + this, false); + NS_ENSURE_SUCCESS(rv, rv); + rv = mEventTarget->RemoveSystemEventListener(NS_LITERAL_STRING("mouseout"), + this, false); + NS_ENSURE_SUCCESS(rv, rv); + rv = mEventTarget->RemoveSystemEventListener(NS_LITERAL_STRING("mousemove"), + this, false); + NS_ENSURE_SUCCESS(rv, rv); + + mTooltipListenerInstalled = false; + } + + return NS_OK; +} + +NS_IMETHODIMP +ChromeTooltipListener::HandleEvent(nsIDOMEvent* aEvent) +{ + nsAutoString eventType; + aEvent->GetType(eventType); + + if (eventType.EqualsLiteral("keydown") || + eventType.EqualsLiteral("mousedown")) { + return HideTooltip(); + } else if (eventType.EqualsLiteral("mouseout")) { + // Reset flag so that tooltip will display on the next MouseMove + mTooltipShownOnce = false; + return HideTooltip(); + } else if (eventType.EqualsLiteral("mousemove")) { + return MouseMove(aEvent); + } + + NS_ERROR("Unexpected event type"); + return NS_OK; +} + +// If we're a tooltip, fire off a timer to see if a tooltip should be shown. If +// the timer fires, we cache the node in |mPossibleTooltipNode|. +nsresult +ChromeTooltipListener::MouseMove(nsIDOMEvent* aMouseEvent) +{ + nsCOMPtr mouseEvent(do_QueryInterface(aMouseEvent)); + if (!mouseEvent) { + return NS_OK; + } + + // stash the coordinates of the event so that we can still get back to it from + // within the timer callback. On win32, we'll get a MouseMove event even when + // a popup goes away -- even when the mouse doesn't change position! To get + // around this, we make sure the mouse has really moved before proceeding. + int32_t newMouseX, newMouseY; + mouseEvent->GetClientX(&newMouseX); + mouseEvent->GetClientY(&newMouseY); + if (mMouseClientX == newMouseX && mMouseClientY == newMouseY) { + return NS_OK; + } + + // Filter out minor mouse movements. + if (mShowingTooltip && + (abs(mMouseClientX - newMouseX) <= kTooltipMouseMoveTolerance) && + (abs(mMouseClientY - newMouseY) <= kTooltipMouseMoveTolerance)) { + return NS_OK; + } + + mMouseClientX = newMouseX; + mMouseClientY = newMouseY; + mouseEvent->GetScreenX(&mMouseScreenX); + mouseEvent->GetScreenY(&mMouseScreenY); + + if (mTooltipTimer) { + mTooltipTimer->Cancel(); + } + + if (!mShowingTooltip && !mTooltipShownOnce) { + mTooltipTimer = do_CreateInstance("@mozilla.org/timer;1"); + if (mTooltipTimer) { + nsCOMPtr eventTarget = + aMouseEvent->InternalDOMEvent()->GetTarget(); + if (eventTarget) { + mPossibleTooltipNode = do_QueryInterface(eventTarget); + } + if (mPossibleTooltipNode) { + nsresult rv = mTooltipTimer->InitWithFuncCallback( + sTooltipCallback, this, + LookAndFeel::GetInt(LookAndFeel::eIntID_TooltipDelay, 500), + nsITimer::TYPE_ONE_SHOT); + if (NS_FAILED(rv)) { + mPossibleTooltipNode = nullptr; + } + } + } else { + NS_WARNING("Could not create a timer for tooltip tracking"); + } + } else { + mTooltipShownOnce = true; + return HideTooltip(); + } + + return NS_OK; +} + +// Tell the registered chrome that they should show the tooltip. +NS_IMETHODIMP +ChromeTooltipListener::ShowTooltip(int32_t aInXCoords, int32_t aInYCoords, + const nsAString& aInTipText, + const nsAString& aTipDir) +{ + nsresult rv = NS_OK; + + // do the work to call the client + nsCOMPtr tooltipListener( + do_QueryInterface(mWebBrowserChrome)); + if (tooltipListener) { + rv = tooltipListener->OnShowTooltip(aInXCoords, aInYCoords, + PromiseFlatString(aInTipText).get(), + PromiseFlatString(aTipDir).get()); + if (NS_SUCCEEDED(rv)) { + mShowingTooltip = true; + } + } + + return rv; +} + +// Tell the registered chrome that they should rollup the tooltip +// NOTE: This routine is safe to call even if the popup is already closed. +NS_IMETHODIMP +ChromeTooltipListener::HideTooltip() +{ + nsresult rv = NS_OK; + + // shut down the relevant timers + if (mTooltipTimer) { + mTooltipTimer->Cancel(); + mTooltipTimer = nullptr; + // release tooltip target + mPossibleTooltipNode = nullptr; + } + + // if we're showing the tip, tell the chrome to hide it + if (mShowingTooltip) { + nsCOMPtr tooltipListener( + do_QueryInterface(mWebBrowserChrome)); + if (tooltipListener) { + rv = tooltipListener->OnHideTooltip(); + if (NS_SUCCEEDED(rv)) { + mShowingTooltip = false; + } + } + } + + return rv; +} + +// A timer callback, fired when the mouse has hovered inside of a frame for the +// appropriate amount of time. Getting to this point means that we should show +// the tooltip, but only after we determine there is an appropriate TITLE +// element. +// +// This relies on certain things being cached into the |aChromeTooltipListener| +// object passed to us by the timer: +// -- the x/y coordinates of the mouse (mMouseClientY, mMouseClientX) +// -- the dom node the user hovered over (mPossibleTooltipNode) +void +ChromeTooltipListener::sTooltipCallback(nsITimer* aTimer, + void* aChromeTooltipListener) +{ + auto self = static_cast(aChromeTooltipListener); + if (self && self->mPossibleTooltipNode) { + // The actual coordinates we want to put the tooltip at are relative to the + // toplevel docshell of our mWebBrowser. We know what the screen + // coordinates of the mouse event were, which means we just need the screen + // coordinates of the docshell. Unfortunately, there is no good way to + // find those short of groveling for the presentation in that docshell and + // finding the screen coords of its toplevel widget... + nsCOMPtr docShell = + do_GetInterface(static_cast(self->mWebBrowser)); + nsCOMPtr shell; + if (docShell) { + shell = docShell->GetPresShell(); + } + + nsIWidget* widget = nullptr; + if (shell) { + nsViewManager* vm = shell->GetViewManager(); + if (vm) { + nsView* view = vm->GetRootView(); + if (view) { + nsPoint offset; + widget = view->GetNearestWidget(&offset); + } + } + } + + if (!widget) { + // release tooltip target if there is one, NO MATTER WHAT + self->mPossibleTooltipNode = nullptr; + return; + } + + // if there is text associated with the node, show the tip and fire + // off a timer to auto-hide it. + + nsXPIDLString tooltipText; + nsXPIDLString directionText; + if (self->mTooltipTextProvider) { + bool textFound = false; + + self->mTooltipTextProvider->GetNodeText( + self->mPossibleTooltipNode, getter_Copies(tooltipText), + getter_Copies(directionText), &textFound); + + if (textFound) { + nsString tipText(tooltipText); + nsString dirText(directionText); + LayoutDeviceIntPoint screenDot = widget->WidgetToScreenOffset(); + double scaleFactor = 1.0; + if (shell->GetPresContext()) { + nsDeviceContext* dc = shell->GetPresContext()->DeviceContext(); + scaleFactor = double(nsPresContext::AppUnitsPerCSSPixel()) / + dc->AppUnitsPerDevPixelAtUnitFullZoom(); + } + // ShowTooltip expects widget-relative position. + self->ShowTooltip(self->mMouseScreenX - screenDot.x / scaleFactor, + self->mMouseScreenY - screenDot.y / scaleFactor, + tipText, dirText); + } + } + + // release tooltip target if there is one, NO MATTER WHAT + self->mPossibleTooltipNode = nullptr; + } +} + +NS_IMPL_ISUPPORTS(ChromeContextMenuListener, nsIDOMEventListener) + +ChromeContextMenuListener::ChromeContextMenuListener( + nsWebBrowser* aInBrowser, + nsIWebBrowserChrome* aInChrome) + : mContextMenuListenerInstalled(false) + , mWebBrowser(aInBrowser) + , mWebBrowserChrome(aInChrome) +{ +} + +ChromeContextMenuListener::~ChromeContextMenuListener() +{ +} + +// Subscribe to the events that will allow us to track context menus. Bascially, +// this is just the context-menu DOM event. +NS_IMETHODIMP +ChromeContextMenuListener::AddContextMenuListener() +{ + if (mEventTarget) { + nsresult rv = mEventTarget->AddEventListener( + NS_LITERAL_STRING("contextmenu"), this, false, false); + NS_ENSURE_SUCCESS(rv, rv); + + mContextMenuListenerInstalled = true; + } + + return NS_OK; +} + +// Unsubscribe from all the various context menu events that we were listening +// to. +NS_IMETHODIMP +ChromeContextMenuListener::RemoveContextMenuListener() +{ + if (mEventTarget) { + nsresult rv = mEventTarget->RemoveEventListener( + NS_LITERAL_STRING("contextmenu"), this, false); + NS_ENSURE_SUCCESS(rv, rv); + + mContextMenuListenerInstalled = false; + } + + return NS_OK; +} + +// Hook up things to the chrome like context menus and tooltips, if the chrome +// has implemented the right interfaces. +NS_IMETHODIMP +ChromeContextMenuListener::AddChromeListeners() +{ + if (!mEventTarget) { + GetDOMEventTarget(mWebBrowser, getter_AddRefs(mEventTarget)); + } + + // Register the appropriate events for context menus, but only if + // the embedding chrome cares. + nsresult rv = NS_OK; + + nsCOMPtr contextListener2( + do_QueryInterface(mWebBrowserChrome)); + nsCOMPtr contextListener( + do_QueryInterface(mWebBrowserChrome)); + if ((contextListener || contextListener2) && !mContextMenuListenerInstalled) { + rv = AddContextMenuListener(); + } + + return rv; +} + +// Unsubscribe from the various things we've hooked up to the window root. +NS_IMETHODIMP +ChromeContextMenuListener::RemoveChromeListeners() +{ + if (mContextMenuListenerInstalled) { + RemoveContextMenuListener(); + } + + mEventTarget = nullptr; + + // it really doesn't matter if these fail... + return NS_OK; +} + +// We're on call to show the context menu. Dig around in the DOM to find the +// type of object we're dealing with and notify the front end chrome. +NS_IMETHODIMP +ChromeContextMenuListener::HandleEvent(nsIDOMEvent* aMouseEvent) +{ + nsCOMPtr mouseEvent = do_QueryInterface(aMouseEvent); + NS_ENSURE_TRUE(mouseEvent, NS_ERROR_UNEXPECTED); + + bool isDefaultPrevented = false; + aMouseEvent->GetDefaultPrevented(&isDefaultPrevented); + if (isDefaultPrevented) { + return NS_OK; + } + + nsCOMPtr targetNode = + aMouseEvent->InternalDOMEvent()->GetTarget(); + if (!targetNode) { + return NS_ERROR_NULL_POINTER; + } + + nsCOMPtr targetDOMnode; + nsCOMPtr node = do_QueryInterface(targetNode); + if (!node) { + return NS_OK; + } + + // Stop the context menu event going to other windows (bug 78396) + aMouseEvent->PreventDefault(); + + // If the listener is a nsIContextMenuListener2, create the info object + nsCOMPtr menuListener2( + do_QueryInterface(mWebBrowserChrome)); + nsContextMenuInfo* menuInfoImpl = nullptr; + nsCOMPtr menuInfo; + if (menuListener2) { + menuInfoImpl = new nsContextMenuInfo; + menuInfo = menuInfoImpl; + } + + uint32_t flags = nsIContextMenuListener::CONTEXT_NONE; + uint32_t flags2 = nsIContextMenuListener2::CONTEXT_NONE; + + // XXX test for selected text + + uint16_t nodeType; + nsresult res = node->GetNodeType(&nodeType); + NS_ENSURE_SUCCESS(res, res); + + // First, checks for nodes that never have children. + if (nodeType == nsIDOMNode::ELEMENT_NODE) { + nsCOMPtr content(do_QueryInterface(node)); + if (content) { + nsCOMPtr imgUri; + content->GetCurrentURI(getter_AddRefs(imgUri)); + if (imgUri) { + flags |= nsIContextMenuListener::CONTEXT_IMAGE; + flags2 |= nsIContextMenuListener2::CONTEXT_IMAGE; + targetDOMnode = node; + } + } + + nsCOMPtr formControl(do_QueryInterface(node)); + if (formControl) { + if (formControl->GetType() == NS_FORM_TEXTAREA) { + flags |= nsIContextMenuListener::CONTEXT_TEXT; + flags2 |= nsIContextMenuListener2::CONTEXT_TEXT; + targetDOMnode = node; + } else { + nsCOMPtr inputElement( + do_QueryInterface(formControl)); + if (inputElement) { + flags |= nsIContextMenuListener::CONTEXT_INPUT; + flags2 |= nsIContextMenuListener2::CONTEXT_INPUT; + + if (menuListener2) { + if (formControl->IsSingleLineTextControl(false)) { + flags2 |= nsIContextMenuListener2::CONTEXT_TEXT; + } + } + + targetDOMnode = node; + } + } + } + + // always consume events for plugins and Java who may throw their + // own context menus but not for image objects. Document objects + // will never be targets or ancestors of targets, so that's OK. + nsCOMPtr objectElement; + if (!(flags & nsIContextMenuListener::CONTEXT_IMAGE)) { + objectElement = do_QueryInterface(node); + } + nsCOMPtr embedElement(do_QueryInterface(node)); + nsCOMPtr appletElement(do_QueryInterface(node)); + + if (objectElement || embedElement || appletElement) { + return NS_OK; + } + } + + // Bubble out, looking for items of interest + do { + uint16_t nodeType; + res = node->GetNodeType(&nodeType); + NS_ENSURE_SUCCESS(res, res); + + if (nodeType == nsIDOMNode::ELEMENT_NODE) { + + // Test if the element has an associated link + nsCOMPtr element(do_QueryInterface(node)); + + bool hasAttr = false; + res = element->HasAttribute(NS_LITERAL_STRING("href"), &hasAttr); + + if (NS_SUCCEEDED(res) && hasAttr) { + flags |= nsIContextMenuListener::CONTEXT_LINK; + flags2 |= nsIContextMenuListener2::CONTEXT_LINK; + if (!targetDOMnode) { + targetDOMnode = node; + } + if (menuInfoImpl) { + menuInfoImpl->SetAssociatedLink(node); + } + break; // exit do-while + } + } + + // walk-up-the-tree + nsCOMPtr parentNode; + node->GetParentNode(getter_AddRefs(parentNode)); + node = parentNode; + } while (node); + + if (!flags && !flags2) { + // We found nothing of interest so far, check if we + // have at least an html document. + nsCOMPtr document; + node = do_QueryInterface(targetNode); + node->GetOwnerDocument(getter_AddRefs(document)); + nsCOMPtr htmlDocument(do_QueryInterface(document)); + if (htmlDocument) { + flags |= nsIContextMenuListener::CONTEXT_DOCUMENT; + flags2 |= nsIContextMenuListener2::CONTEXT_DOCUMENT; + targetDOMnode = node; + if (!(flags & nsIContextMenuListener::CONTEXT_IMAGE)) { + // check if this is a background image that the user was trying to click + // on and if the listener is ready for that (only + // nsIContextMenuListener2 and up) + if (menuInfoImpl && menuInfoImpl->HasBackgroundImage(targetDOMnode)) { + flags2 |= nsIContextMenuListener2::CONTEXT_BACKGROUND_IMAGE; + // For the embedder to get the correct background image + // targetDOMnode must point to the original node. + targetDOMnode = do_QueryInterface(targetNode); + } + } + } + } + + // we need to cache the event target into the focus controller's popupNode + // so we can get at it later from command code, etc.: + + // get the dom window + nsCOMPtr win; + res = mWebBrowser->GetContentDOMWindow(getter_AddRefs(win)); + NS_ENSURE_SUCCESS(res, res); + NS_ENSURE_TRUE(win, NS_ERROR_FAILURE); + + auto* window = nsPIDOMWindowOuter::From(win); + nsCOMPtr root = window->GetTopWindowRoot(); + NS_ENSURE_TRUE(root, NS_ERROR_FAILURE); + if (root) { + // set the window root's popup node to the event target + root->SetPopupNode(targetDOMnode); + } + + // Tell the listener all about the event + if (menuListener2) { + menuInfoImpl->SetMouseEvent(aMouseEvent); + menuInfoImpl->SetDOMNode(targetDOMnode); + menuListener2->OnShowContextMenu(flags2, menuInfo); + } else { + nsCOMPtr menuListener( + do_QueryInterface(mWebBrowserChrome)); + if (menuListener) { + menuListener->OnShowContextMenu(flags, aMouseEvent, targetDOMnode); + } + } + + return NS_OK; +} diff --git a/embedding/browser/nsDocShellTreeOwner.h b/embedding/browser/nsDocShellTreeOwner.h new file mode 100644 index 000000000..d935ba165 --- /dev/null +++ b/embedding/browser/nsDocShellTreeOwner.h @@ -0,0 +1,246 @@ +/* -*- 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/. */ + +#ifndef nsDocShellTreeOwner_h__ +#define nsDocShellTreeOwner_h__ + +// Helper Classes +#include "nsCOMPtr.h" +#include "nsString.h" + +// Interfaces Needed +#include "nsIBaseWindow.h" +#include "nsIDocShellTreeOwner.h" +#include "nsIInterfaceRequestor.h" +#include "nsIInterfaceRequestorUtils.h" +#include "nsIWebBrowserChrome.h" +#include "nsIDOMEventListener.h" +#include "nsIEmbeddingSiteWindow.h" +#include "nsIWebProgressListener.h" +#include "nsWeakReference.h" +#include "nsITimer.h" +#include "nsIPrompt.h" +#include "nsIAuthPrompt.h" +#include "nsITooltipListener.h" +#include "nsITooltipTextProvider.h" +#include "nsCTooltipTextProvider.h" +#include "nsIDroppedLinkHandler.h" +#include "nsCommandHandler.h" + +namespace mozilla { +namespace dom { +class EventTarget; +} // namespace dom +} // namespace mozilla + +class nsWebBrowser; +class ChromeTooltipListener; +class ChromeContextMenuListener; + +// {6D10C180-6888-11d4-952B-0020183BF181} +#define NS_ICDOCSHELLTREEOWNER_IID \ + { 0x6d10c180, 0x6888, 0x11d4, { 0x95, 0x2b, 0x0, 0x20, 0x18, 0x3b, 0xf1, 0x81 } } + +// This is a fake 'hidden' interface that nsDocShellTreeOwner implements. +// Classes such as nsCommandHandler can QI for this interface to be sure that +// they're dealing with a valid nsDocShellTreeOwner and not some other object +// that implements nsIDocShellTreeOwner. +class nsICDocShellTreeOwner : public nsISupports +{ +public: + NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICDOCSHELLTREEOWNER_IID) +}; + +NS_DEFINE_STATIC_IID_ACCESSOR(nsICDocShellTreeOwner, NS_ICDOCSHELLTREEOWNER_IID) + +class nsDocShellTreeOwner final : public nsIDocShellTreeOwner, + public nsIBaseWindow, + public nsIInterfaceRequestor, + public nsIWebProgressListener, + public nsIDOMEventListener, + public nsICDocShellTreeOwner, + public nsSupportsWeakReference +{ + friend class nsWebBrowser; + friend class nsCommandHandler; + +public: + NS_DECL_ISUPPORTS + + NS_DECL_NSIBASEWINDOW + NS_DECL_NSIDOCSHELLTREEOWNER + NS_DECL_NSIDOMEVENTLISTENER + NS_DECL_NSIINTERFACEREQUESTOR + NS_DECL_NSIWEBPROGRESSLISTENER + +protected: + nsDocShellTreeOwner(); + virtual ~nsDocShellTreeOwner(); + + void WebBrowser(nsWebBrowser* aWebBrowser); + + nsWebBrowser* WebBrowser(); + NS_IMETHOD SetTreeOwner(nsIDocShellTreeOwner* aTreeOwner); + NS_IMETHOD SetWebBrowserChrome(nsIWebBrowserChrome* aWebBrowserChrome); + + NS_IMETHOD AddChromeListeners(); + NS_IMETHOD RemoveChromeListeners(); + + nsresult FindItemWithNameAcrossWindows( + const char16_t* aName, + nsIDocShellTreeItem* aRequestor, nsIDocShellTreeItem* aOriginalRequestor, + nsIDocShellTreeItem** aFoundItem); + + void EnsurePrompter(); + void EnsureAuthPrompter(); + + void AddToWatcher(); + void RemoveFromWatcher(); + + void EnsureContentTreeOwner(); + + // These helper functions return the correct instances of the requested + // interfaces. If the object passed to SetWebBrowserChrome() implements + // nsISupportsWeakReference, then these functions call QueryReferent on + // that object. Otherwise, they return an addrefed pointer. If the + // WebBrowserChrome object doesn't exist, they return nullptr. + already_AddRefed GetWebBrowserChrome(); + already_AddRefed GetOwnerWin(); + already_AddRefed GetOwnerRequestor(); + +protected: + // Weak References + nsWebBrowser* mWebBrowser; + nsIDocShellTreeOwner* mTreeOwner; + nsIDocShellTreeItem* mPrimaryContentShell; + + nsIWebBrowserChrome* mWebBrowserChrome; + nsIEmbeddingSiteWindow* mOwnerWin; + nsIInterfaceRequestor* mOwnerRequestor; + + nsWeakPtr mWebBrowserChromeWeak; // nsIWebBrowserChrome + + // the objects that listen for chrome events like context menus and tooltips. + // They are separate objects to avoid circular references between |this| + // and the DOM. + RefPtr mChromeTooltipListener; + RefPtr mChromeContextMenuListener; + + RefPtr mContentTreeOwner; + + nsCOMPtr mPrompter; + nsCOMPtr mAuthPrompter; + nsCOMPtr mPrimaryTabParent; +}; + + +// The class that listens to the chrome events and tells the embedding chrome to +// show tooltips, as appropriate. Handles registering itself with the DOM with +// AddChromeListeners() and removing itself with RemoveChromeListeners(). +class ChromeTooltipListener final : public nsIDOMEventListener +{ +protected: + virtual ~ChromeTooltipListener(); + +public: + NS_DECL_ISUPPORTS + + ChromeTooltipListener(nsWebBrowser* aInBrowser, nsIWebBrowserChrome* aInChrome); + + NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) override; + NS_IMETHOD MouseMove(nsIDOMEvent* aMouseEvent); + + // Add/remove the relevant listeners, based on what interfaces the embedding + // chrome implements. + NS_IMETHOD AddChromeListeners(); + NS_IMETHOD RemoveChromeListeners(); + +private: + // various delays for tooltips + enum + { + kTooltipAutoHideTime = 5000, // ms + kTooltipMouseMoveTolerance = 7 // pixel tolerance for mousemove event + }; + + NS_IMETHOD AddTooltipListener(); + NS_IMETHOD RemoveTooltipListener(); + + NS_IMETHOD ShowTooltip(int32_t aInXCoords, int32_t aInYCoords, + const nsAString& aInTipText, + const nsAString& aDirText); + NS_IMETHOD HideTooltip(); + + nsWebBrowser* mWebBrowser; + nsCOMPtr mEventTarget; + nsCOMPtr mTooltipTextProvider; + + // This must be a strong ref in order to make sure we can hide the tooltip if + // the window goes away while we're displaying one. If we don't hold a strong + // ref, the chrome might have been disposed of before we get a chance to tell + // it, and no one would ever tell us of that fact. + nsCOMPtr mWebBrowserChrome; + + bool mTooltipListenerInstalled; + + nsCOMPtr mTooltipTimer; + static void sTooltipCallback(nsITimer* aTimer, void* aListener); + + // Mouse coordinates for last mousemove event we saw + int32_t mMouseClientX; + int32_t mMouseClientY; + + // Mouse coordinates for tooltip event + int32_t mMouseScreenX; + int32_t mMouseScreenY; + + bool mShowingTooltip; + bool mTooltipShownOnce; + + // The node hovered over that fired the timer. This may turn into the node + // that triggered the tooltip, but only if the timer ever gets around to + // firing. This is a strong reference, because the tooltip content can be + // destroyed while we're waiting for the tooltip to pup up, and we need to + // detect that. It's set only when the tooltip timer is created and launched. + // The timer must either fire or be cancelled (or possibly released?), and we + // release this reference in each of those cases. So we don't leak. + nsCOMPtr mPossibleTooltipNode; +}; + +// The class that listens to the chrome events and tells the embedding chrome to +// show context menus, as appropriate. Handles registering itself with the DOM +// with AddChromeListeners() and removing itself with RemoveChromeListeners(). +class ChromeContextMenuListener : public nsIDOMEventListener +{ +protected: + virtual ~ChromeContextMenuListener(); + +public: + NS_DECL_ISUPPORTS + + ChromeContextMenuListener(nsWebBrowser* aInBrowser, + nsIWebBrowserChrome* aInChrome); + + // nsIDOMContextMenuListener + NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) override; + + // Add/remove the relevant listeners, based on what interfaces + // the embedding chrome implements. + NS_IMETHOD AddChromeListeners(); + NS_IMETHOD RemoveChromeListeners(); + +private: + NS_IMETHOD AddContextMenuListener(); + NS_IMETHOD RemoveContextMenuListener(); + + bool mContextMenuListenerInstalled; + + nsWebBrowser* mWebBrowser; + nsCOMPtr mEventTarget; + nsCOMPtr mWebBrowserChrome; +}; + +#endif /* nsDocShellTreeOwner_h__ */ diff --git a/embedding/browser/nsEmbedStream.cpp b/embedding/browser/nsEmbedStream.cpp new file mode 100644 index 000000000..35347060c --- /dev/null +++ b/embedding/browser/nsEmbedStream.cpp @@ -0,0 +1,101 @@ +/* -*- 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/. */ + +#include "nsIAsyncInputStream.h" +#include "nsIAsyncOutputStream.h" +#include "nsIDocShell.h" +#include "nsIInterfaceRequestorUtils.h" +#include "nsIPipe.h" + +#include "nsEmbedStream.h" +#include "nsError.h" +#include "nsString.h" + +NS_IMPL_ISUPPORTS0(nsEmbedStream) + +nsEmbedStream::nsEmbedStream() +{ + mOwner = nullptr; +} + +nsEmbedStream::~nsEmbedStream() +{ +} + +void +nsEmbedStream::InitOwner(nsIWebBrowser* aOwner) +{ + mOwner = aOwner; +} + +nsresult +nsEmbedStream::Init(void) +{ + return NS_OK; +} + +nsresult +nsEmbedStream::OpenStream(nsIURI* aBaseURI, const nsACString& aContentType) +{ + nsresult rv; + NS_ENSURE_ARG_POINTER(aBaseURI); + NS_ENSURE_TRUE(IsASCII(aContentType), NS_ERROR_INVALID_ARG); + + // if we're already doing a stream, return an error + if (mOutputStream) { + return NS_ERROR_IN_PROGRESS; + } + + nsCOMPtr inputStream; + nsCOMPtr outputStream; + rv = NS_NewPipe2(getter_AddRefs(inputStream), getter_AddRefs(outputStream), + true, false, 0, UINT32_MAX); + if (NS_FAILED(rv)) { + return rv; + } + + nsCOMPtr docShell = do_GetInterface(mOwner); + rv = docShell->LoadStream(inputStream, aBaseURI, aContentType, + EmptyCString(), nullptr); + if (NS_FAILED(rv)) { + return rv; + } + + mOutputStream = outputStream; + return rv; +} + +nsresult +nsEmbedStream::AppendToStream(const uint8_t* aData, uint32_t aLen) +{ + nsresult rv; + NS_ENSURE_STATE(mOutputStream); + + uint32_t bytesWritten = 0; + rv = mOutputStream->Write(reinterpret_cast(aData), + aLen, &bytesWritten); + if (NS_FAILED(rv)) { + return rv; + } + + NS_ASSERTION(bytesWritten == aLen, + "underlying buffer couldn't handle the write"); + return rv; +} + +nsresult +nsEmbedStream::CloseStream(void) +{ + nsresult rv = NS_OK; + + // NS_ENSURE_STATE returns NS_ERROR_UNEXPECTED if the condition isn't + // satisfied; this is exactly what we want to return. + NS_ENSURE_STATE(mOutputStream); + mOutputStream->Close(); + mOutputStream = nullptr; + + return rv; +} diff --git a/embedding/browser/nsEmbedStream.h b/embedding/browser/nsEmbedStream.h new file mode 100644 index 000000000..03dca7936 --- /dev/null +++ b/embedding/browser/nsEmbedStream.h @@ -0,0 +1,37 @@ +/* -*- 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/. */ + +#ifndef nsEmbedStream_h__ +#define nsEmbedStream_h__ + +#include "nsCOMPtr.h" +#include "nsIOutputStream.h" +#include "nsIURI.h" +#include "nsIWebBrowser.h" + +class nsEmbedStream : public nsISupports +{ +public: + nsEmbedStream(); + + void InitOwner(nsIWebBrowser* aOwner); + nsresult Init(void); + + nsresult OpenStream(nsIURI* aBaseURI, const nsACString& aContentType); + nsresult AppendToStream(const uint8_t* aData, uint32_t aLen); + nsresult CloseStream(void); + + NS_DECL_ISUPPORTS + +protected: + virtual ~nsEmbedStream(); + +private: + nsIWebBrowser* mOwner; + nsCOMPtr mOutputStream; +}; + +#endif // nsEmbedStream_h__ diff --git a/embedding/browser/nsICommandHandler.idl b/embedding/browser/nsICommandHandler.idl new file mode 100644 index 000000000..15a2fd23b --- /dev/null +++ b/embedding/browser/nsICommandHandler.idl @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +interface mozIDOMWindowProxy; + +[scriptable, uuid(08aed3cc-69f7-47ba-a110-f2efa8a6d7ea)] +interface nsICommandHandlerInit : nsISupports +{ + attribute mozIDOMWindowProxy window; +}; + +[scriptable, uuid(34A4FCF0-66FC-11d4-9528-0020183BF181)] +interface nsICommandHandler : nsISupports +{ + /* + * Execute the specified command with the specified parameters and return + * the result to the caller. The format of the command, parameters and + * the result are determined by the acutal implementation. + */ + string exec(in string aCommand, in string aParameters); + /* + * Query the status of the specified command with the specified parameters + * and return the result to the caller. The format of the command, + * parameters and the result are determined by the implementation. + */ + string query(in string aCommand, in string aParameters); +}; + +%{ C++ +// {3A449110-66FD-11d4-9528-0020183BF181} - +#define NS_COMMANDHANDLER_CID \ +{ 0x3a449110, 0x66fd, 0x11d4, { 0x95, 0x28, 0x0, 0x20, 0x18, 0x3b, 0xf1, 0x81 } } +#define NS_COMMANDHANDLER_CONTRACTID \ +"@mozilla.org/embedding/browser/nsCommandHandler;1" +%} + diff --git a/embedding/browser/nsIContextMenuListener.idl b/embedding/browser/nsIContextMenuListener.idl new file mode 100644 index 000000000..2e4d1c1e9 --- /dev/null +++ b/embedding/browser/nsIContextMenuListener.idl @@ -0,0 +1,65 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +interface nsIDOMEvent; +interface nsIDOMNode; + +/** + * An optional interface for embedding clients wishing to receive + * notifications for context menu events (e.g. generated by + * a user right-mouse clicking on a link). The embedder implements + * this interface on the web browser chrome object associated + * with the window that notifications are required for. When a context + * menu event, the browser will call this interface if present. + * + * @see nsIDOMNode + * @see nsIDOMEvent + */ +[scriptable, uuid(3478b6b0-3875-11d4-94ef-0020183bf181)] +interface nsIContextMenuListener : nsISupports +{ + /** Flag. No context. */ + const unsigned long CONTEXT_NONE = 0; + /** Flag. Context is a link element. */ + const unsigned long CONTEXT_LINK = 1; + /** Flag. Context is an image element. */ + const unsigned long CONTEXT_IMAGE = 2; + /** Flag. Context is the whole document. */ + const unsigned long CONTEXT_DOCUMENT = 4; + /** Flag. Context is a text area element. */ + const unsigned long CONTEXT_TEXT = 8; + /** Flag. Context is an input element. */ + const unsigned long CONTEXT_INPUT = 16; + + /** + * Called when the browser receives a context menu event (e.g. user is right-mouse + * clicking somewhere on the document). The combination of flags, event and node + * provided in the call indicate where and what was clicked on. + * + * The following table describes what context flags and node combinations are + * possible. + * + * + * + * + * + * + * + * + * + *
aContextFlagaNode
CONTEXT_LINK<A>
CONTEXT_IMAGE<IMG>
CONTEXT_IMAGE | CONTEXT_LINK<IMG> + * with an <A> as an ancestor
CONTEXT_INPUT<INPUT>
CONTEXT_TEXT<TEXTAREA>
CONTEXT_DOCUMENT<HTML>
+ * + * @param aContextFlags Flags indicating the kind of context. + * @param aEvent The DOM context menu event. + * @param aNode The DOM node most relevant to the context. + * + * @return NS_OK always. + */ + void onShowContextMenu(in unsigned long aContextFlags, in nsIDOMEvent aEvent, in nsIDOMNode aNode); +}; + diff --git a/embedding/browser/nsIContextMenuListener2.idl b/embedding/browser/nsIContextMenuListener2.idl new file mode 100644 index 000000000..19d898011 --- /dev/null +++ b/embedding/browser/nsIContextMenuListener2.idl @@ -0,0 +1,121 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +interface nsIDOMEvent; +interface nsIDOMNode; +interface imgIContainer; +interface nsIURI; +interface nsIContextMenuInfo; + +/* THIS IS A PUBLIC EMBEDDING API */ + +/** + * nsIContextMenuListener2 + * + * This is an extended version of nsIContextMenuListener + * It provides a helper class, nsIContextMenuInfo, to allow access to + * background images as well as various utilities. + * + * @see nsIContextMenuListener + * @see nsIContextMenuInfo + */ + +[scriptable, uuid(7fb719b3-d804-4964-9596-77cf924ee314)] +interface nsIContextMenuListener2 : nsISupports +{ + /** Flag. No context. */ + const unsigned long CONTEXT_NONE = 0; + /** Flag. Context is a link element. */ + const unsigned long CONTEXT_LINK = 1; + /** Flag. Context is an image element. */ + const unsigned long CONTEXT_IMAGE = 2; + /** Flag. Context is the whole document. */ + const unsigned long CONTEXT_DOCUMENT = 4; + /** Flag. Context is a text area element. */ + const unsigned long CONTEXT_TEXT = 8; + /** Flag. Context is an input element. */ + const unsigned long CONTEXT_INPUT = 16; + /** Flag. Context is a background image. */ + const unsigned long CONTEXT_BACKGROUND_IMAGE = 32; + + /** + * Called when the browser receives a context menu event (e.g. user is right-mouse + * clicking somewhere on the document). The combination of flags, along with the + * attributes of aUtils, indicate where and what was clicked on. + * + * The following table describes what context flags and node combinations are + * possible. + * + * aContextFlags aUtils.targetNode + * + * CONTEXT_LINK + * CONTEXT_IMAGE + * CONTEXT_IMAGE | CONTEXT_LINK with as an ancestor + * CONTEXT_INPUT + * CONTEXT_INPUT | CONTEXT_IMAGE with type=image + * CONTEXT_TEXT