diff -r 000000000000 -r 6474c204b198 embedding/browser/webBrowser/nsContextMenuInfo.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/embedding/browser/webBrowser/nsContextMenuInfo.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,337 @@ +/* -*- Mode: C++; 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 "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 "nsIDOMCSSStyleDeclaration.h" +#include "nsIDOMCSSValue.h" +#include "nsIDOMCSSPrimitiveValue.h" +#include "nsNetUtil.h" +#include "nsUnicharUtils.h" +#include "nsIDocument.h" +#include "nsIPrincipal.h" +#include "nsIChannelPolicy.h" +#include "nsIContentSecurityPolicy.h" +#include "nsIContentPolicy.h" +#include "nsAutoPtr.h" +#include "imgRequestProxy.h" +#include "mozIThirdPartyUtil.h" + +//***************************************************************************** +// class nsContextMenuInfo +//***************************************************************************** + +NS_IMPL_ISUPPORTS(nsContextMenuInfo, nsIContextMenuInfo) + +nsContextMenuInfo::nsContextMenuInfo() +{ +} + +nsContextMenuInfo::~nsContextMenuInfo() +{ +} + +/* readonly attribute nsIDOMEvent mouseEvent; */ +NS_IMETHODIMP +nsContextMenuInfo::GetMouseEvent(nsIDOMEvent **aEvent) +{ + NS_ENSURE_ARG_POINTER(aEvent); + NS_IF_ADDREF(*aEvent = mMouseEvent); + return NS_OK; +} + +/* readonly attribute nsIDOMNode targetNode; */ +NS_IMETHODIMP +nsContextMenuInfo::GetTargetNode(nsIDOMNode **aNode) +{ + NS_ENSURE_ARG_POINTER(aNode); + NS_IF_ADDREF(*aNode = mDOMNode); + return NS_OK; +} + +/* readonly attribute AString associatedLink; */ +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; +} + +/* readonly attribute imgIContainer imageContainer; */ +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; +} + +/* readonly attribute nsIURI imageSrc; */ +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); +} + +/* readonly attribute imgIContainer backgroundImageContainer; */ +NS_IMETHODIMP +nsContextMenuInfo::GetBackgroundImageContainer(imgIContainer **aImageContainer) +{ + NS_ENSURE_ARG_POINTER(aImageContainer); + NS_ENSURE_STATE(mDOMNode); + + nsRefPtr request; + GetBackgroundImageRequest(mDOMNode, getter_AddRefs(request)); + if (request) + return request->GetImage(aImageContainer); + + return NS_ERROR_FAILURE; +} + +/* readonly attribute nsIURI backgroundImageSrc; */ +NS_IMETHODIMP +nsContextMenuInfo::GetBackgroundImageSrc(nsIURI **aURI) +{ + NS_ENSURE_ARG_POINTER(aURI); + NS_ENSURE_STATE(mDOMNode); + + nsRefPtr 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); + + nsRefPtr 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); + + nsCOMPtr primitiveValue; + nsAutoString bgStringValue; + + // get Content Security Policy to pass to LoadImage + nsCOMPtr doc(do_QueryInterface(document)); + nsCOMPtr principal; + nsCOMPtr channelPolicy; + nsCOMPtr csp; + NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); + + principal = doc->NodePrincipal(); + nsresult rv = principal->GetCsp(getter_AddRefs(csp)); + NS_ENSURE_SUCCESS(rv, rv); + if (csp) { + channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1"); + channelPolicy->SetContentSecurityPolicy(csp); + channelPolicy->SetLoadType(nsIContentPolicy::TYPE_IMAGE); + } + + while (true) { + nsCOMPtr domElement(do_QueryInterface(domNode)); + // bail for the parent node of the root element or null argument + if (!domElement) + break; + + nsCOMPtr computedStyle; + window->GetComputedStyle(domElement, EmptyString(), + getter_AddRefs(computedStyle)); + 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); + + nsRefPtr il = imgLoader::GetInstance(); + NS_ENSURE_TRUE(il, NS_ERROR_FAILURE); + nsCOMPtr firstPartyIsolationURI; + nsCOMPtr thirdPartySvc + = do_GetService(THIRDPARTYUTIL_CONTRACTID); + thirdPartySvc->GetFirstPartyIsolationURI(nullptr, doc, + getter_AddRefs(firstPartyIsolationURI)); + return il->LoadImage(bgUri, firstPartyIsolationURI, nullptr, principal, nullptr, + nullptr, nullptr, nsIRequest::LOAD_NORMAL, + nullptr, channelPolicy, 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; +}