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