1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is the Mozilla browser.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications, Inc.
19 : * Portions created by the Initial Developer are Copyright (C) 1999
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Chris Saari <saari@netscape.com>
24 : * Conrad Carlen <ccarlen@netscape.com>
25 : * Pierre Chanial <p_ch@verizon.net>
26 : * Ms2ger <ms2ger@gmail.com>
27 : *
28 : * Alternatively, the contents of this file may be used under the terms of
29 : * either the GNU General Public License Version 2 or later (the "GPL"), or
30 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 : * in which case the provisions of the GPL or the LGPL are applicable instead
32 : * of those above. If you wish to allow use of your version of this file only
33 : * under the terms of either the GPL or the LGPL, and not to allow others to
34 : * use your version of this file under the terms of the MPL, indicate your
35 : * decision by deleting the provisions above and replace them with the notice
36 : * and other provisions required by the GPL or the LGPL. If you do not delete
37 : * the provisions above, a recipient may use your version of this file under
38 : * the terms of any one of the MPL, the GPL or the LGPL.
39 : *
40 : * ***** END LICENSE BLOCK ***** */
41 :
42 : #include "nsContextMenuInfo.h"
43 :
44 : #include "nsIImageLoadingContent.h"
45 : #include "imgILoader.h"
46 : #include "nsIDOMDocument.h"
47 : #include "nsIDOMHTMLDocument.h"
48 : #include "nsIDOMHTMLElement.h"
49 : #include "nsIDOMHTMLHtmlElement.h"
50 : #include "nsIDOMHTMLAnchorElement.h"
51 : #include "nsIDOMHTMLImageElement.h"
52 : #include "nsIDOMHTMLAreaElement.h"
53 : #include "nsIDOMHTMLLinkElement.h"
54 : #include "nsIDOMWindow.h"
55 : #include "nsIDOMCSSStyleDeclaration.h"
56 : #include "nsIDOMCSSValue.h"
57 : #include "nsIDOMCSSPrimitiveValue.h"
58 : #include "nsNetUtil.h"
59 : #include "nsUnicharUtils.h"
60 : #include "nsIDocument.h"
61 : #include "nsIPrincipal.h"
62 : #include "nsIChannelPolicy.h"
63 : #include "nsIContentSecurityPolicy.h"
64 : #include "nsIContentPolicy.h"
65 :
66 : //*****************************************************************************
67 : // class nsContextMenuInfo
68 : //*****************************************************************************
69 :
70 0 : NS_IMPL_ISUPPORTS1(nsContextMenuInfo, nsIContextMenuInfo)
71 :
72 0 : nsContextMenuInfo::nsContextMenuInfo()
73 : {
74 0 : }
75 :
76 0 : nsContextMenuInfo::~nsContextMenuInfo()
77 : {
78 0 : }
79 :
80 : /* readonly attribute nsIDOMEvent mouseEvent; */
81 : NS_IMETHODIMP
82 0 : nsContextMenuInfo::GetMouseEvent(nsIDOMEvent **aEvent)
83 : {
84 0 : NS_ENSURE_ARG_POINTER(aEvent);
85 0 : NS_IF_ADDREF(*aEvent = mMouseEvent);
86 0 : return NS_OK;
87 : }
88 :
89 : /* readonly attribute nsIDOMNode targetNode; */
90 : NS_IMETHODIMP
91 0 : nsContextMenuInfo::GetTargetNode(nsIDOMNode **aNode)
92 : {
93 0 : NS_ENSURE_ARG_POINTER(aNode);
94 0 : NS_IF_ADDREF(*aNode = mDOMNode);
95 0 : return NS_OK;
96 : }
97 :
98 : /* readonly attribute AString associatedLink; */
99 : NS_IMETHODIMP
100 0 : nsContextMenuInfo::GetAssociatedLink(nsAString& aHRef)
101 : {
102 0 : NS_ENSURE_STATE(mAssociatedLink);
103 0 : aHRef.Truncate(0);
104 :
105 0 : nsCOMPtr<nsIDOMElement> content(do_QueryInterface(mAssociatedLink));
106 0 : nsAutoString localName;
107 0 : if (content)
108 0 : content->GetLocalName(localName);
109 :
110 0 : nsCOMPtr<nsIDOMElement> linkContent;
111 0 : ToLowerCase(localName);
112 0 : if (localName.EqualsLiteral("a") ||
113 0 : localName.EqualsLiteral("area") ||
114 0 : localName.EqualsLiteral("link")) {
115 : bool hasAttr;
116 0 : content->HasAttribute(NS_LITERAL_STRING("href"), &hasAttr);
117 0 : if (hasAttr) {
118 0 : linkContent = content;
119 0 : nsCOMPtr<nsIDOMHTMLAnchorElement> anchor(do_QueryInterface(linkContent));
120 0 : if (anchor)
121 0 : anchor->GetHref(aHRef);
122 : else {
123 0 : nsCOMPtr<nsIDOMHTMLAreaElement> area(do_QueryInterface(linkContent));
124 0 : if (area)
125 0 : area->GetHref(aHRef);
126 : else {
127 0 : nsCOMPtr<nsIDOMHTMLLinkElement> link(do_QueryInterface(linkContent));
128 0 : if (link)
129 0 : link->GetHref(aHRef);
130 : }
131 : }
132 : }
133 : }
134 : else {
135 0 : nsCOMPtr<nsIDOMNode> curr;
136 0 : mAssociatedLink->GetParentNode(getter_AddRefs(curr));
137 0 : while (curr) {
138 0 : content = do_QueryInterface(curr);
139 0 : if (!content)
140 0 : break;
141 0 : content->GetLocalName(localName);
142 0 : ToLowerCase(localName);
143 0 : if (localName.EqualsLiteral("a")) {
144 : bool hasAttr;
145 0 : content->HasAttribute(NS_LITERAL_STRING("href"), &hasAttr);
146 0 : if (hasAttr) {
147 0 : linkContent = content;
148 0 : nsCOMPtr<nsIDOMHTMLAnchorElement> anchor(do_QueryInterface(linkContent));
149 0 : if (anchor)
150 0 : anchor->GetHref(aHRef);
151 : }
152 : else
153 0 : linkContent = nsnull; // Links can't be nested.
154 0 : break;
155 : }
156 :
157 0 : nsCOMPtr<nsIDOMNode> temp = curr;
158 0 : temp->GetParentNode(getter_AddRefs(curr));
159 : }
160 : }
161 :
162 0 : return NS_OK;
163 : }
164 :
165 : /* readonly attribute imgIContainer imageContainer; */
166 : NS_IMETHODIMP
167 0 : nsContextMenuInfo::GetImageContainer(imgIContainer **aImageContainer)
168 : {
169 0 : NS_ENSURE_ARG_POINTER(aImageContainer);
170 0 : NS_ENSURE_STATE(mDOMNode);
171 :
172 0 : nsCOMPtr<imgIRequest> request;
173 0 : GetImageRequest(mDOMNode, getter_AddRefs(request));
174 0 : if (request)
175 0 : return request->GetImage(aImageContainer);
176 :
177 0 : return NS_ERROR_FAILURE;
178 : }
179 :
180 : /* readonly attribute nsIURI imageSrc; */
181 : NS_IMETHODIMP
182 0 : nsContextMenuInfo::GetImageSrc(nsIURI **aURI)
183 : {
184 0 : NS_ENSURE_ARG_POINTER(aURI);
185 0 : NS_ENSURE_STATE(mDOMNode);
186 :
187 0 : nsCOMPtr<nsIImageLoadingContent> content(do_QueryInterface(mDOMNode));
188 0 : NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
189 0 : return content->GetCurrentURI(aURI);
190 : }
191 :
192 : /* readonly attribute imgIContainer backgroundImageContainer; */
193 : NS_IMETHODIMP
194 0 : nsContextMenuInfo::GetBackgroundImageContainer(imgIContainer **aImageContainer)
195 : {
196 0 : NS_ENSURE_ARG_POINTER(aImageContainer);
197 0 : NS_ENSURE_STATE(mDOMNode);
198 :
199 0 : nsCOMPtr<imgIRequest> request;
200 0 : GetBackgroundImageRequest(mDOMNode, getter_AddRefs(request));
201 0 : if (request)
202 0 : return request->GetImage(aImageContainer);
203 :
204 0 : return NS_ERROR_FAILURE;
205 : }
206 :
207 : /* readonly attribute nsIURI backgroundImageSrc; */
208 : NS_IMETHODIMP
209 0 : nsContextMenuInfo::GetBackgroundImageSrc(nsIURI **aURI)
210 : {
211 0 : NS_ENSURE_ARG_POINTER(aURI);
212 0 : NS_ENSURE_STATE(mDOMNode);
213 :
214 0 : nsCOMPtr<imgIRequest> request;
215 0 : GetBackgroundImageRequest(mDOMNode, getter_AddRefs(request));
216 0 : if (request)
217 0 : return request->GetURI(aURI);
218 :
219 0 : return NS_ERROR_FAILURE;
220 : }
221 :
222 : //*****************************************************************************
223 :
224 : nsresult
225 0 : nsContextMenuInfo::GetImageRequest(nsIDOMNode *aDOMNode, imgIRequest **aRequest)
226 : {
227 0 : NS_ENSURE_ARG(aDOMNode);
228 0 : NS_ENSURE_ARG_POINTER(aRequest);
229 :
230 : // Get content
231 0 : nsCOMPtr<nsIImageLoadingContent> content(do_QueryInterface(aDOMNode));
232 0 : NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
233 :
234 0 : return content->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
235 0 : aRequest);
236 : }
237 :
238 : bool
239 0 : nsContextMenuInfo::HasBackgroundImage(nsIDOMNode * aDOMNode)
240 : {
241 0 : NS_ENSURE_TRUE(aDOMNode, false);
242 :
243 0 : nsCOMPtr<imgIRequest> request;
244 0 : GetBackgroundImageRequest(aDOMNode, getter_AddRefs(request));
245 :
246 0 : return (request != nsnull);
247 : }
248 :
249 : nsresult
250 0 : nsContextMenuInfo::GetBackgroundImageRequest(nsIDOMNode *aDOMNode, imgIRequest **aRequest)
251 : {
252 :
253 0 : NS_ENSURE_ARG(aDOMNode);
254 0 : NS_ENSURE_ARG_POINTER(aRequest);
255 :
256 0 : nsCOMPtr<nsIDOMNode> domNode = aDOMNode;
257 :
258 : // special case for the <html> element: if it has no background-image
259 : // we'll defer to <body>
260 0 : nsCOMPtr<nsIDOMHTMLHtmlElement> htmlElement = do_QueryInterface(domNode);
261 0 : if (htmlElement) {
262 0 : nsAutoString nameSpace;
263 0 : htmlElement->GetNamespaceURI(nameSpace);
264 0 : if (nameSpace.IsEmpty()) {
265 0 : nsresult rv = GetBackgroundImageRequestInternal(domNode, aRequest);
266 0 : if (NS_SUCCEEDED(rv) && *aRequest)
267 0 : return NS_OK;
268 :
269 : // no background-image found
270 0 : nsCOMPtr<nsIDOMDocument> document;
271 0 : domNode->GetOwnerDocument(getter_AddRefs(document));
272 0 : nsCOMPtr<nsIDOMHTMLDocument> htmlDocument(do_QueryInterface(document));
273 0 : NS_ENSURE_TRUE(htmlDocument, NS_ERROR_FAILURE);
274 :
275 0 : nsCOMPtr<nsIDOMHTMLElement> body;
276 0 : htmlDocument->GetBody(getter_AddRefs(body));
277 0 : domNode = do_QueryInterface(body);
278 0 : NS_ENSURE_TRUE(domNode, NS_ERROR_FAILURE);
279 : }
280 : }
281 0 : return GetBackgroundImageRequestInternal(domNode, aRequest);
282 : }
283 :
284 : nsresult
285 0 : nsContextMenuInfo::GetBackgroundImageRequestInternal(nsIDOMNode *aDOMNode, imgIRequest **aRequest)
286 : {
287 0 : NS_ENSURE_ARG_POINTER(aDOMNode);
288 :
289 0 : nsCOMPtr<nsIDOMNode> domNode = aDOMNode;
290 0 : nsCOMPtr<nsIDOMNode> parentNode;
291 :
292 0 : nsCOMPtr<nsIDOMDocument> document;
293 0 : domNode->GetOwnerDocument(getter_AddRefs(document));
294 0 : NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
295 :
296 0 : nsCOMPtr<nsIDOMWindow> window;
297 0 : document->GetDefaultView(getter_AddRefs(window));
298 0 : NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
299 :
300 0 : nsCOMPtr<nsIDOMCSSPrimitiveValue> primitiveValue;
301 0 : nsAutoString bgStringValue;
302 :
303 : // get Content Security Policy to pass to LoadImage
304 0 : nsCOMPtr<nsIDocument> doc(do_QueryInterface(document));
305 0 : nsCOMPtr<nsIPrincipal> principal;
306 0 : nsCOMPtr<nsIChannelPolicy> channelPolicy;
307 0 : nsCOMPtr<nsIContentSecurityPolicy> csp;
308 0 : if (doc) {
309 0 : principal = doc->NodePrincipal();
310 0 : nsresult rv = principal->GetCsp(getter_AddRefs(csp));
311 0 : NS_ENSURE_SUCCESS(rv, rv);
312 0 : if (csp) {
313 0 : channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
314 0 : channelPolicy->SetContentSecurityPolicy(csp);
315 0 : channelPolicy->SetLoadType(nsIContentPolicy::TYPE_IMAGE);
316 : }
317 : }
318 :
319 0 : while (true) {
320 0 : nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(domNode));
321 : // bail for the parent node of the root element or null argument
322 0 : if (!domElement)
323 : break;
324 :
325 0 : nsCOMPtr<nsIDOMCSSStyleDeclaration> computedStyle;
326 0 : window->GetComputedStyle(domElement, EmptyString(),
327 0 : getter_AddRefs(computedStyle));
328 0 : if (computedStyle) {
329 0 : nsCOMPtr<nsIDOMCSSValue> cssValue;
330 0 : computedStyle->GetPropertyCSSValue(NS_LITERAL_STRING("background-image"),
331 0 : getter_AddRefs(cssValue));
332 0 : primitiveValue = do_QueryInterface(cssValue);
333 0 : if (primitiveValue) {
334 0 : primitiveValue->GetStringValue(bgStringValue);
335 0 : if (!bgStringValue.EqualsLiteral("none")) {
336 0 : nsCOMPtr<nsIURI> bgUri;
337 0 : NS_NewURI(getter_AddRefs(bgUri), bgStringValue);
338 0 : NS_ENSURE_TRUE(bgUri, NS_ERROR_FAILURE);
339 :
340 : nsCOMPtr<imgILoader> il(do_GetService(
341 0 : "@mozilla.org/image/loader;1"));
342 0 : NS_ENSURE_TRUE(il, NS_ERROR_FAILURE);
343 :
344 0 : return il->LoadImage(bgUri, nsnull, nsnull, principal, nsnull,
345 : nsnull, nsnull, nsIRequest::LOAD_NORMAL, nsnull,
346 0 : nsnull, channelPolicy, aRequest);
347 : }
348 : }
349 :
350 : // bail if we encounter non-transparent background-color
351 0 : computedStyle->GetPropertyCSSValue(NS_LITERAL_STRING("background-color"),
352 0 : getter_AddRefs(cssValue));
353 0 : primitiveValue = do_QueryInterface(cssValue);
354 0 : if (primitiveValue) {
355 0 : primitiveValue->GetStringValue(bgStringValue);
356 0 : if (!bgStringValue.EqualsLiteral("transparent"))
357 0 : return NS_ERROR_FAILURE;
358 : }
359 : }
360 :
361 0 : domNode->GetParentNode(getter_AddRefs(parentNode));
362 0 : domNode = parentNode;
363 : }
364 :
365 0 : return NS_ERROR_FAILURE;
366 : }
|