michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsContextMenuInfo.h" michael@0: michael@0: #include "nsIImageLoadingContent.h" michael@0: #include "imgLoader.h" michael@0: #include "nsIDOMDocument.h" michael@0: #include "nsIDOMHTMLDocument.h" michael@0: #include "nsIDOMHTMLElement.h" michael@0: #include "nsIDOMHTMLHtmlElement.h" michael@0: #include "nsIDOMHTMLAnchorElement.h" michael@0: #include "nsIDOMHTMLImageElement.h" michael@0: #include "nsIDOMHTMLAreaElement.h" michael@0: #include "nsIDOMHTMLLinkElement.h" michael@0: #include "nsIDOMWindow.h" michael@0: #include "nsIDOMCSSStyleDeclaration.h" michael@0: #include "nsIDOMCSSValue.h" michael@0: #include "nsIDOMCSSPrimitiveValue.h" michael@0: #include "nsNetUtil.h" michael@0: #include "nsUnicharUtils.h" michael@0: #include "nsIDocument.h" michael@0: #include "nsIPrincipal.h" michael@0: #include "nsIChannelPolicy.h" michael@0: #include "nsIContentSecurityPolicy.h" michael@0: #include "nsIContentPolicy.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "imgRequestProxy.h" michael@0: #include "mozIThirdPartyUtil.h" michael@0: michael@0: //***************************************************************************** michael@0: // class nsContextMenuInfo michael@0: //***************************************************************************** michael@0: michael@0: NS_IMPL_ISUPPORTS(nsContextMenuInfo, nsIContextMenuInfo) michael@0: michael@0: nsContextMenuInfo::nsContextMenuInfo() michael@0: { michael@0: } michael@0: michael@0: nsContextMenuInfo::~nsContextMenuInfo() michael@0: { michael@0: } michael@0: michael@0: /* readonly attribute nsIDOMEvent mouseEvent; */ michael@0: NS_IMETHODIMP michael@0: nsContextMenuInfo::GetMouseEvent(nsIDOMEvent **aEvent) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aEvent); michael@0: NS_IF_ADDREF(*aEvent = mMouseEvent); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute nsIDOMNode targetNode; */ michael@0: NS_IMETHODIMP michael@0: nsContextMenuInfo::GetTargetNode(nsIDOMNode **aNode) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aNode); michael@0: NS_IF_ADDREF(*aNode = mDOMNode); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute AString associatedLink; */ michael@0: NS_IMETHODIMP michael@0: nsContextMenuInfo::GetAssociatedLink(nsAString& aHRef) michael@0: { michael@0: NS_ENSURE_STATE(mAssociatedLink); michael@0: aHRef.Truncate(0); michael@0: michael@0: nsCOMPtr content(do_QueryInterface(mAssociatedLink)); michael@0: nsAutoString localName; michael@0: if (content) michael@0: content->GetLocalName(localName); michael@0: michael@0: nsCOMPtr linkContent; michael@0: ToLowerCase(localName); michael@0: if (localName.EqualsLiteral("a") || michael@0: localName.EqualsLiteral("area") || michael@0: localName.EqualsLiteral("link")) { michael@0: bool hasAttr; michael@0: content->HasAttribute(NS_LITERAL_STRING("href"), &hasAttr); michael@0: if (hasAttr) { michael@0: linkContent = content; michael@0: nsCOMPtr anchor(do_QueryInterface(linkContent)); michael@0: if (anchor) michael@0: anchor->GetHref(aHRef); michael@0: else { michael@0: nsCOMPtr area(do_QueryInterface(linkContent)); michael@0: if (area) michael@0: area->GetHref(aHRef); michael@0: else { michael@0: nsCOMPtr link(do_QueryInterface(linkContent)); michael@0: if (link) michael@0: link->GetHref(aHRef); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: else { michael@0: nsCOMPtr curr; michael@0: mAssociatedLink->GetParentNode(getter_AddRefs(curr)); michael@0: while (curr) { michael@0: content = do_QueryInterface(curr); michael@0: if (!content) michael@0: break; michael@0: content->GetLocalName(localName); michael@0: ToLowerCase(localName); michael@0: if (localName.EqualsLiteral("a")) { michael@0: bool hasAttr; michael@0: content->HasAttribute(NS_LITERAL_STRING("href"), &hasAttr); michael@0: if (hasAttr) { michael@0: linkContent = content; michael@0: nsCOMPtr anchor(do_QueryInterface(linkContent)); michael@0: if (anchor) michael@0: anchor->GetHref(aHRef); michael@0: } michael@0: else michael@0: linkContent = nullptr; // Links can't be nested. michael@0: break; michael@0: } michael@0: michael@0: nsCOMPtr temp = curr; michael@0: temp->GetParentNode(getter_AddRefs(curr)); michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute imgIContainer imageContainer; */ michael@0: NS_IMETHODIMP michael@0: nsContextMenuInfo::GetImageContainer(imgIContainer **aImageContainer) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aImageContainer); michael@0: NS_ENSURE_STATE(mDOMNode); michael@0: michael@0: nsCOMPtr request; michael@0: GetImageRequest(mDOMNode, getter_AddRefs(request)); michael@0: if (request) michael@0: return request->GetImage(aImageContainer); michael@0: michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: /* readonly attribute nsIURI imageSrc; */ michael@0: NS_IMETHODIMP michael@0: nsContextMenuInfo::GetImageSrc(nsIURI **aURI) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aURI); michael@0: NS_ENSURE_STATE(mDOMNode); michael@0: michael@0: nsCOMPtr content(do_QueryInterface(mDOMNode)); michael@0: NS_ENSURE_TRUE(content, NS_ERROR_FAILURE); michael@0: return content->GetCurrentURI(aURI); michael@0: } michael@0: michael@0: /* readonly attribute imgIContainer backgroundImageContainer; */ michael@0: NS_IMETHODIMP michael@0: nsContextMenuInfo::GetBackgroundImageContainer(imgIContainer **aImageContainer) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aImageContainer); michael@0: NS_ENSURE_STATE(mDOMNode); michael@0: michael@0: nsRefPtr request; michael@0: GetBackgroundImageRequest(mDOMNode, getter_AddRefs(request)); michael@0: if (request) michael@0: return request->GetImage(aImageContainer); michael@0: michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: /* readonly attribute nsIURI backgroundImageSrc; */ michael@0: NS_IMETHODIMP michael@0: nsContextMenuInfo::GetBackgroundImageSrc(nsIURI **aURI) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aURI); michael@0: NS_ENSURE_STATE(mDOMNode); michael@0: michael@0: nsRefPtr request; michael@0: GetBackgroundImageRequest(mDOMNode, getter_AddRefs(request)); michael@0: if (request) michael@0: return request->GetURI(aURI); michael@0: michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: //***************************************************************************** michael@0: michael@0: nsresult michael@0: nsContextMenuInfo::GetImageRequest(nsIDOMNode *aDOMNode, imgIRequest **aRequest) michael@0: { michael@0: NS_ENSURE_ARG(aDOMNode); michael@0: NS_ENSURE_ARG_POINTER(aRequest); michael@0: michael@0: // Get content michael@0: nsCOMPtr content(do_QueryInterface(aDOMNode)); michael@0: NS_ENSURE_TRUE(content, NS_ERROR_FAILURE); michael@0: michael@0: return content->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST, michael@0: aRequest); michael@0: } michael@0: michael@0: bool michael@0: nsContextMenuInfo::HasBackgroundImage(nsIDOMNode * aDOMNode) michael@0: { michael@0: NS_ENSURE_TRUE(aDOMNode, false); michael@0: michael@0: nsRefPtr request; michael@0: GetBackgroundImageRequest(aDOMNode, getter_AddRefs(request)); michael@0: michael@0: return (request != nullptr); michael@0: } michael@0: michael@0: nsresult michael@0: nsContextMenuInfo::GetBackgroundImageRequest(nsIDOMNode *aDOMNode, imgRequestProxy **aRequest) michael@0: { michael@0: michael@0: NS_ENSURE_ARG(aDOMNode); michael@0: NS_ENSURE_ARG_POINTER(aRequest); michael@0: michael@0: nsCOMPtr domNode = aDOMNode; michael@0: michael@0: // special case for the element: if it has no background-image michael@0: // we'll defer to michael@0: nsCOMPtr htmlElement = do_QueryInterface(domNode); michael@0: if (htmlElement) { michael@0: nsCOMPtr element = do_QueryInterface(domNode); michael@0: nsAutoString nameSpace; michael@0: element->GetNamespaceURI(nameSpace); michael@0: if (nameSpace.IsEmpty()) { michael@0: nsresult rv = GetBackgroundImageRequestInternal(domNode, aRequest); michael@0: if (NS_SUCCEEDED(rv) && *aRequest) michael@0: return NS_OK; michael@0: michael@0: // no background-image found michael@0: nsCOMPtr document; michael@0: domNode->GetOwnerDocument(getter_AddRefs(document)); michael@0: nsCOMPtr htmlDocument(do_QueryInterface(document)); michael@0: NS_ENSURE_TRUE(htmlDocument, NS_ERROR_FAILURE); michael@0: michael@0: nsCOMPtr body; michael@0: htmlDocument->GetBody(getter_AddRefs(body)); michael@0: domNode = do_QueryInterface(body); michael@0: NS_ENSURE_TRUE(domNode, NS_ERROR_FAILURE); michael@0: } michael@0: } michael@0: return GetBackgroundImageRequestInternal(domNode, aRequest); michael@0: } michael@0: michael@0: nsresult michael@0: nsContextMenuInfo::GetBackgroundImageRequestInternal(nsIDOMNode *aDOMNode, imgRequestProxy **aRequest) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aDOMNode); michael@0: michael@0: nsCOMPtr domNode = aDOMNode; michael@0: nsCOMPtr parentNode; michael@0: michael@0: nsCOMPtr document; michael@0: domNode->GetOwnerDocument(getter_AddRefs(document)); michael@0: NS_ENSURE_TRUE(document, NS_ERROR_FAILURE); michael@0: michael@0: nsCOMPtr window; michael@0: document->GetDefaultView(getter_AddRefs(window)); michael@0: NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); michael@0: michael@0: nsCOMPtr primitiveValue; michael@0: nsAutoString bgStringValue; michael@0: michael@0: // get Content Security Policy to pass to LoadImage michael@0: nsCOMPtr doc(do_QueryInterface(document)); michael@0: nsCOMPtr principal; michael@0: nsCOMPtr channelPolicy; michael@0: nsCOMPtr csp; michael@0: NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); michael@0: michael@0: principal = doc->NodePrincipal(); michael@0: nsresult rv = principal->GetCsp(getter_AddRefs(csp)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: if (csp) { michael@0: channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1"); michael@0: channelPolicy->SetContentSecurityPolicy(csp); michael@0: channelPolicy->SetLoadType(nsIContentPolicy::TYPE_IMAGE); michael@0: } michael@0: michael@0: while (true) { michael@0: nsCOMPtr domElement(do_QueryInterface(domNode)); michael@0: // bail for the parent node of the root element or null argument michael@0: if (!domElement) michael@0: break; michael@0: michael@0: nsCOMPtr computedStyle; michael@0: window->GetComputedStyle(domElement, EmptyString(), michael@0: getter_AddRefs(computedStyle)); michael@0: if (computedStyle) { michael@0: nsCOMPtr cssValue; michael@0: computedStyle->GetPropertyCSSValue(NS_LITERAL_STRING("background-image"), michael@0: getter_AddRefs(cssValue)); michael@0: primitiveValue = do_QueryInterface(cssValue); michael@0: if (primitiveValue) { michael@0: primitiveValue->GetStringValue(bgStringValue); michael@0: if (!bgStringValue.EqualsLiteral("none")) { michael@0: nsCOMPtr bgUri; michael@0: NS_NewURI(getter_AddRefs(bgUri), bgStringValue); michael@0: NS_ENSURE_TRUE(bgUri, NS_ERROR_FAILURE); michael@0: michael@0: nsRefPtr il = imgLoader::GetInstance(); michael@0: NS_ENSURE_TRUE(il, NS_ERROR_FAILURE); michael@0: nsCOMPtr firstPartyIsolationURI; michael@0: nsCOMPtr thirdPartySvc michael@0: = do_GetService(THIRDPARTYUTIL_CONTRACTID); michael@0: thirdPartySvc->GetFirstPartyIsolationURI(nullptr, doc, michael@0: getter_AddRefs(firstPartyIsolationURI)); michael@0: return il->LoadImage(bgUri, firstPartyIsolationURI, nullptr, principal, nullptr, michael@0: nullptr, nullptr, nsIRequest::LOAD_NORMAL, michael@0: nullptr, channelPolicy, EmptyString(), aRequest); michael@0: } michael@0: } michael@0: michael@0: // bail if we encounter non-transparent background-color michael@0: computedStyle->GetPropertyCSSValue(NS_LITERAL_STRING("background-color"), michael@0: getter_AddRefs(cssValue)); michael@0: primitiveValue = do_QueryInterface(cssValue); michael@0: if (primitiveValue) { michael@0: primitiveValue->GetStringValue(bgStringValue); michael@0: if (!bgStringValue.EqualsLiteral("transparent")) michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: } michael@0: michael@0: domNode->GetParentNode(getter_AddRefs(parentNode)); michael@0: domNode = parentNode; michael@0: } michael@0: michael@0: return NS_ERROR_FAILURE; michael@0: }