Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "nsContextMenuInfo.h"
8 :
9 : #include "nsIImageLoadingContent.h"
10 : #include "imgLoader.h"
11 : #include "nsIDOMDocument.h"
12 : #include "nsIDOMHTMLDocument.h"
13 : #include "nsIDOMHTMLElement.h"
14 : #include "nsIDOMHTMLHtmlElement.h"
15 : #include "nsIDOMHTMLAnchorElement.h"
16 : #include "nsIDOMHTMLImageElement.h"
17 : #include "nsIDOMHTMLAreaElement.h"
18 : #include "nsIDOMHTMLLinkElement.h"
19 : #include "nsIDOMWindow.h"
20 : #include "nsICSSDeclaration.h"
21 : #include "nsIDOMCSSValue.h"
22 : #include "nsIDOMCSSPrimitiveValue.h"
23 : #include "nsNetUtil.h"
24 : #include "nsUnicharUtils.h"
25 : #include "nsIDocument.h"
26 : #include "nsIPrincipal.h"
27 : #include "nsIContentSecurityPolicy.h"
28 : #include "nsIContentPolicy.h"
29 : #include "imgRequestProxy.h"
30 :
31 : using mozilla::dom::Element;
32 : using mozilla::ErrorResult;
33 :
34 0 : NS_IMPL_ISUPPORTS(nsContextMenuInfo, nsIContextMenuInfo)
35 :
36 0 : nsContextMenuInfo::nsContextMenuInfo()
37 : {
38 0 : }
39 :
40 0 : nsContextMenuInfo::~nsContextMenuInfo()
41 : {
42 0 : }
43 :
44 : NS_IMETHODIMP
45 0 : nsContextMenuInfo::GetMouseEvent(nsIDOMEvent** aEvent)
46 : {
47 0 : NS_ENSURE_ARG_POINTER(aEvent);
48 0 : NS_IF_ADDREF(*aEvent = mMouseEvent);
49 0 : return NS_OK;
50 : }
51 :
52 : NS_IMETHODIMP
53 0 : nsContextMenuInfo::GetTargetNode(nsIDOMNode** aNode)
54 : {
55 0 : NS_ENSURE_ARG_POINTER(aNode);
56 0 : NS_IF_ADDREF(*aNode = mDOMNode);
57 0 : return NS_OK;
58 : }
59 :
60 : NS_IMETHODIMP
61 0 : nsContextMenuInfo::GetAssociatedLink(nsAString& aHRef)
62 : {
63 0 : NS_ENSURE_STATE(mAssociatedLink);
64 0 : aHRef.Truncate(0);
65 :
66 0 : nsCOMPtr<nsIDOMElement> content(do_QueryInterface(mAssociatedLink));
67 0 : nsAutoString localName;
68 0 : if (content) {
69 0 : content->GetLocalName(localName);
70 : }
71 :
72 0 : nsCOMPtr<nsIDOMElement> linkContent;
73 0 : ToLowerCase(localName);
74 0 : if (localName.EqualsLiteral("a") ||
75 0 : localName.EqualsLiteral("area") ||
76 0 : localName.EqualsLiteral("link")) {
77 : bool hasAttr;
78 0 : content->HasAttribute(NS_LITERAL_STRING("href"), &hasAttr);
79 0 : if (hasAttr) {
80 0 : linkContent = content;
81 0 : nsCOMPtr<nsIDOMHTMLAnchorElement> anchor(do_QueryInterface(linkContent));
82 0 : if (anchor) {
83 0 : anchor->GetHref(aHRef);
84 : } else {
85 0 : nsCOMPtr<nsIDOMHTMLAreaElement> area(do_QueryInterface(linkContent));
86 0 : if (area) {
87 0 : area->GetHref(aHRef);
88 : } else {
89 0 : nsCOMPtr<nsIDOMHTMLLinkElement> link(do_QueryInterface(linkContent));
90 0 : if (link) {
91 0 : link->GetHref(aHRef);
92 : }
93 : }
94 : }
95 : }
96 : } else {
97 0 : nsCOMPtr<nsIDOMNode> curr;
98 0 : mAssociatedLink->GetParentNode(getter_AddRefs(curr));
99 0 : while (curr) {
100 0 : content = do_QueryInterface(curr);
101 0 : if (!content) {
102 0 : break;
103 : }
104 0 : content->GetLocalName(localName);
105 0 : ToLowerCase(localName);
106 0 : if (localName.EqualsLiteral("a")) {
107 : bool hasAttr;
108 0 : content->HasAttribute(NS_LITERAL_STRING("href"), &hasAttr);
109 0 : if (hasAttr) {
110 0 : linkContent = content;
111 : nsCOMPtr<nsIDOMHTMLAnchorElement> anchor(
112 0 : do_QueryInterface(linkContent));
113 0 : if (anchor) {
114 0 : anchor->GetHref(aHRef);
115 : }
116 : } else {
117 0 : linkContent = nullptr; // Links can't be nested.
118 : }
119 0 : break;
120 : }
121 :
122 0 : nsCOMPtr<nsIDOMNode> temp = curr;
123 0 : temp->GetParentNode(getter_AddRefs(curr));
124 : }
125 : }
126 :
127 0 : return NS_OK;
128 : }
129 :
130 : NS_IMETHODIMP
131 0 : nsContextMenuInfo::GetImageContainer(imgIContainer** aImageContainer)
132 : {
133 0 : NS_ENSURE_ARG_POINTER(aImageContainer);
134 0 : NS_ENSURE_STATE(mDOMNode);
135 :
136 0 : nsCOMPtr<imgIRequest> request;
137 0 : GetImageRequest(mDOMNode, getter_AddRefs(request));
138 0 : if (request) {
139 0 : return request->GetImage(aImageContainer);
140 : }
141 :
142 0 : return NS_ERROR_FAILURE;
143 : }
144 :
145 : NS_IMETHODIMP
146 0 : nsContextMenuInfo::GetImageSrc(nsIURI** aURI)
147 : {
148 0 : NS_ENSURE_ARG_POINTER(aURI);
149 0 : NS_ENSURE_STATE(mDOMNode);
150 :
151 0 : nsCOMPtr<nsIImageLoadingContent> content(do_QueryInterface(mDOMNode));
152 0 : NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
153 0 : return content->GetCurrentURI(aURI);
154 : }
155 :
156 : NS_IMETHODIMP
157 0 : nsContextMenuInfo::GetBackgroundImageContainer(imgIContainer** aImageContainer)
158 : {
159 0 : NS_ENSURE_ARG_POINTER(aImageContainer);
160 0 : NS_ENSURE_STATE(mDOMNode);
161 :
162 0 : RefPtr<imgRequestProxy> request;
163 0 : GetBackgroundImageRequest(mDOMNode, getter_AddRefs(request));
164 0 : if (request) {
165 0 : return request->GetImage(aImageContainer);
166 : }
167 :
168 0 : return NS_ERROR_FAILURE;
169 : }
170 :
171 : NS_IMETHODIMP
172 0 : nsContextMenuInfo::GetBackgroundImageSrc(nsIURI** aURI)
173 : {
174 0 : NS_ENSURE_ARG_POINTER(aURI);
175 0 : NS_ENSURE_STATE(mDOMNode);
176 :
177 0 : RefPtr<imgRequestProxy> request;
178 0 : GetBackgroundImageRequest(mDOMNode, getter_AddRefs(request));
179 0 : if (request) {
180 0 : return request->GetURI(aURI);
181 : }
182 :
183 0 : return NS_ERROR_FAILURE;
184 : }
185 :
186 : nsresult
187 0 : nsContextMenuInfo::GetImageRequest(nsIDOMNode* aDOMNode, imgIRequest** aRequest)
188 : {
189 0 : NS_ENSURE_ARG(aDOMNode);
190 0 : NS_ENSURE_ARG_POINTER(aRequest);
191 :
192 : // Get content
193 0 : nsCOMPtr<nsIImageLoadingContent> content(do_QueryInterface(aDOMNode));
194 0 : NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
195 :
196 0 : return content->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST, aRequest);
197 : }
198 :
199 : bool
200 0 : nsContextMenuInfo::HasBackgroundImage(nsIDOMNode* aDOMNode)
201 : {
202 0 : NS_ENSURE_TRUE(aDOMNode, false);
203 :
204 0 : RefPtr<imgRequestProxy> request;
205 0 : GetBackgroundImageRequest(aDOMNode, getter_AddRefs(request));
206 :
207 0 : return (request != nullptr);
208 : }
209 :
210 : nsresult
211 0 : nsContextMenuInfo::GetBackgroundImageRequest(nsIDOMNode* aDOMNode,
212 : imgRequestProxy** aRequest)
213 : {
214 :
215 0 : NS_ENSURE_ARG(aDOMNode);
216 0 : NS_ENSURE_ARG_POINTER(aRequest);
217 :
218 0 : nsCOMPtr<nsIDOMNode> domNode = aDOMNode;
219 :
220 : // special case for the <html> element: if it has no background-image
221 : // we'll defer to <body>
222 0 : nsCOMPtr<nsIDOMHTMLHtmlElement> htmlElement = do_QueryInterface(domNode);
223 0 : if (htmlElement) {
224 0 : nsCOMPtr<nsIDOMHTMLElement> element = do_QueryInterface(domNode);
225 0 : nsAutoString nameSpace;
226 0 : element->GetNamespaceURI(nameSpace);
227 0 : if (nameSpace.IsEmpty()) {
228 0 : nsresult rv = GetBackgroundImageRequestInternal(domNode, aRequest);
229 0 : if (NS_SUCCEEDED(rv) && *aRequest) {
230 0 : return NS_OK;
231 : }
232 :
233 : // no background-image found
234 0 : nsCOMPtr<nsIDOMDocument> document;
235 0 : domNode->GetOwnerDocument(getter_AddRefs(document));
236 0 : nsCOMPtr<nsIDOMHTMLDocument> htmlDocument(do_QueryInterface(document));
237 0 : NS_ENSURE_TRUE(htmlDocument, NS_ERROR_FAILURE);
238 :
239 0 : nsCOMPtr<nsIDOMHTMLElement> body;
240 0 : htmlDocument->GetBody(getter_AddRefs(body));
241 0 : domNode = do_QueryInterface(body);
242 0 : NS_ENSURE_TRUE(domNode, NS_ERROR_FAILURE);
243 : }
244 : }
245 0 : return GetBackgroundImageRequestInternal(domNode, aRequest);
246 : }
247 :
248 : nsresult
249 0 : nsContextMenuInfo::GetBackgroundImageRequestInternal(nsIDOMNode* aDOMNode,
250 : imgRequestProxy** aRequest)
251 : {
252 0 : NS_ENSURE_ARG_POINTER(aDOMNode);
253 :
254 0 : nsCOMPtr<nsIDOMNode> domNode = aDOMNode;
255 0 : nsCOMPtr<nsIDOMNode> parentNode;
256 :
257 0 : nsCOMPtr<nsIDOMDocument> document;
258 0 : domNode->GetOwnerDocument(getter_AddRefs(document));
259 0 : NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
260 :
261 0 : nsCOMPtr<mozIDOMWindowProxy> window;
262 0 : document->GetDefaultView(getter_AddRefs(window));
263 0 : NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
264 :
265 0 : auto* piWindow = nsPIDOMWindowOuter::From(window);
266 0 : nsPIDOMWindowInner* innerWindow = piWindow->GetCurrentInnerWindow();
267 0 : MOZ_ASSERT(innerWindow);
268 :
269 0 : nsCOMPtr<nsIDOMCSSPrimitiveValue> primitiveValue;
270 0 : nsAutoString bgStringValue;
271 :
272 0 : nsCOMPtr<nsIDocument> doc(do_QueryInterface(document));
273 0 : nsCOMPtr<nsIPrincipal> principal = doc ? doc->NodePrincipal() : nullptr;
274 :
275 : while (true) {
276 0 : nsCOMPtr<Element> domElement(do_QueryInterface(domNode));
277 : // bail for the parent node of the root element or null argument
278 0 : if (!domElement) {
279 0 : break;
280 : }
281 :
282 0 : ErrorResult dummy;
283 : nsCOMPtr<nsICSSDeclaration> computedStyle =
284 0 : innerWindow->GetComputedStyle(*domElement, EmptyString(), dummy);
285 0 : dummy.SuppressException();
286 0 : if (computedStyle) {
287 0 : nsCOMPtr<nsIDOMCSSValue> cssValue;
288 0 : computedStyle->GetPropertyCSSValue(NS_LITERAL_STRING("background-image"),
289 0 : getter_AddRefs(cssValue));
290 0 : primitiveValue = do_QueryInterface(cssValue);
291 0 : if (primitiveValue) {
292 0 : primitiveValue->GetStringValue(bgStringValue);
293 0 : if (!bgStringValue.EqualsLiteral("none")) {
294 0 : nsCOMPtr<nsIURI> bgUri;
295 0 : NS_NewURI(getter_AddRefs(bgUri), bgStringValue);
296 0 : NS_ENSURE_TRUE(bgUri, NS_ERROR_FAILURE);
297 :
298 0 : imgLoader* il = imgLoader::NormalLoader();
299 0 : NS_ENSURE_TRUE(il, NS_ERROR_FAILURE);
300 :
301 0 : return il->LoadImage(bgUri, nullptr, nullptr,
302 : doc->GetReferrerPolicy(), principal, nullptr,
303 : nullptr, nullptr, nullptr, nsIRequest::LOAD_NORMAL,
304 : nullptr, nsIContentPolicy::TYPE_INTERNAL_IMAGE,
305 0 : EmptyString(),
306 0 : /* aUseUrgentStartForChannel */ false, aRequest);
307 : }
308 : }
309 :
310 : // bail if we encounter non-transparent background-color
311 0 : computedStyle->GetPropertyCSSValue(NS_LITERAL_STRING("background-color"),
312 0 : getter_AddRefs(cssValue));
313 0 : primitiveValue = do_QueryInterface(cssValue);
314 0 : if (primitiveValue) {
315 0 : primitiveValue->GetStringValue(bgStringValue);
316 0 : if (!bgStringValue.EqualsLiteral("transparent")) {
317 0 : return NS_ERROR_FAILURE;
318 : }
319 : }
320 : }
321 :
322 0 : domNode->GetParentNode(getter_AddRefs(parentNode));
323 0 : domNode = parentNode;
324 0 : }
325 :
326 0 : return NS_ERROR_FAILURE;
327 : }
|