1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "webkit/glue/dom_operations.h"
9 #include "base/compiler_specific.h"
10 #include "base/logging.h"
11 #include "base/string_util.h"
12 #include "third_party/WebKit/Source/WebKit/chromium/public/WebAnimationController.h"
13 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
14 #include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h"
15 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
16 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputElement.h"
17 #include "third_party/WebKit/Source/WebKit/chromium/public/WebNode.h"
18 #include "third_party/WebKit/Source/WebKit/chromium/public/WebNodeCollection.h"
19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebNodeList.h"
20 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h"
21 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebVector.h"
22 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
24 using WebKit::WebAnimationController
;
25 using WebKit::WebDocument
;
26 using WebKit::WebElement
;
27 using WebKit::WebFrame
;
28 using WebKit::WebInputElement
;
29 using WebKit::WebNode
;
30 using WebKit::WebNodeCollection
;
31 using WebKit::WebNodeList
;
32 using WebKit::WebString
;
33 using WebKit::WebVector
;
34 using WebKit::WebView
;
38 // Structure for storage the unique set of all savable resource links for
39 // making sure that no duplicated resource link in final result. The consumer
40 // of the SavableResourcesUniqueCheck is responsible for keeping these pointers
41 // valid for the lifetime of the SavableResourcesUniqueCheck instance.
42 struct SavableResourcesUniqueCheck
{
43 // Unique set of all sub resource links.
44 std::set
<GURL
>* resources_set
;
45 // Unique set of all frame links.
46 std::set
<GURL
>* frames_set
;
47 // Collection of all frames we go through when getting all savable resource
49 std::vector
<WebFrame
*>* frames
;
51 SavableResourcesUniqueCheck()
52 : resources_set(NULL
),
56 SavableResourcesUniqueCheck(std::set
<GURL
>* resources_set
,
57 std::set
<GURL
>* frames_set
, std::vector
<WebFrame
*>* frames
)
58 : resources_set(resources_set
),
59 frames_set(frames_set
),
63 // Get all savable resource links from current element. One element might
64 // have more than one resource link. It is possible to have some links
65 // in one CSS stylesheet.
66 void GetSavableResourceLinkForElement(
67 const WebElement
& element
,
68 const WebDocument
& current_doc
,
69 SavableResourcesUniqueCheck
* unique_check
,
70 webkit_glue::SavableResourcesResult
* result
) {
72 // Handle frame and iframe tag.
73 if (element
.hasTagName("iframe") ||
74 element
.hasTagName("frame")) {
75 WebFrame
* sub_frame
= WebFrame::fromFrameOwnerElement(element
);
77 unique_check
->frames
->push_back(sub_frame
);
81 // Check whether the node has sub resource URL or not.
83 webkit_glue::GetSubResourceLinkFromElement(element
);
87 GURL u
= current_doc
.completeURL(value
);
91 // Ignore those URLs which are not standard protocols. Because FTP
92 // protocol does no have cache mechanism, we will skip all
93 // sub-resources if they use FTP protocol.
94 if (!u
.SchemeIs("http") && !u
.SchemeIs("https") && !u
.SchemeIs("file"))
96 // Ignore duplicated resource link.
97 if (!unique_check
->resources_set
->insert(u
).second
)
99 result
->resources_list
->push_back(u
);
100 // Insert referrer for above new resource link.
101 result
->referrer_urls_list
->push_back(GURL());
102 result
->referrer_policies_list
->push_back(WebKit::WebReferrerPolicyDefault
);
105 // Get all savable resource links from current WebFrameImpl object pointer.
106 void GetAllSavableResourceLinksForFrame(WebFrame
* current_frame
,
107 SavableResourcesUniqueCheck
* unique_check
,
108 webkit_glue::SavableResourcesResult
* result
,
109 const char** savable_schemes
) {
110 // Get current frame's URL.
111 GURL current_frame_url
= current_frame
->document().url();
113 // If url of current frame is invalid, ignore it.
114 if (!current_frame_url
.is_valid())
117 // If url of current frame is not a savable protocol, ignore it.
118 bool is_valid_protocol
= false;
119 for (int i
= 0; savable_schemes
[i
] != NULL
; ++i
) {
120 if (current_frame_url
.SchemeIs(savable_schemes
[i
])) {
121 is_valid_protocol
= true;
125 if (!is_valid_protocol
)
128 // If find same frame we have recorded, ignore it.
129 if (!unique_check
->frames_set
->insert(current_frame_url
).second
)
132 // Get current using document.
133 WebDocument current_doc
= current_frame
->document();
134 // Go through all descent nodes.
135 WebNodeCollection all
= current_doc
.all();
136 // Go through all node in this frame.
137 for (WebNode node
= all
.firstItem(); !node
.isNull();
138 node
= all
.nextItem()) {
139 // We only save HTML resources.
140 if (!node
.isElementNode())
142 WebElement element
= node
.to
<WebElement
>();
143 GetSavableResourceLinkForElement(element
,
152 namespace webkit_glue
{
154 WebString
GetSubResourceLinkFromElement(const WebElement
& element
) {
155 const char* attribute_name
= NULL
;
156 if (element
.hasTagName("img") ||
157 element
.hasTagName("script")) {
158 attribute_name
= "src";
159 } else if (element
.hasTagName("input")) {
160 const WebInputElement input
= element
.toConst
<WebInputElement
>();
161 if (input
.isImageButton()) {
162 attribute_name
= "src";
164 } else if (element
.hasTagName("body") ||
165 element
.hasTagName("table") ||
166 element
.hasTagName("tr") ||
167 element
.hasTagName("td")) {
168 attribute_name
= "background";
169 } else if (element
.hasTagName("blockquote") ||
170 element
.hasTagName("q") ||
171 element
.hasTagName("del") ||
172 element
.hasTagName("ins")) {
173 attribute_name
= "cite";
174 } else if (element
.hasTagName("link")) {
175 // If the link element is not linked to css, ignore it.
176 if (LowerCaseEqualsASCII(element
.getAttribute("type"), "text/css")) {
177 // TODO(jnd): Add support for extracting links of sub-resources which
178 // are inside style-sheet such as @import, url(), etc.
179 // See bug: http://b/issue?id=1111667.
180 attribute_name
= "href";
185 WebString value
= element
.getAttribute(WebString::fromUTF8(attribute_name
));
186 // If value has content and not start with "javascript:" then return it,
187 // otherwise return NULL.
188 if (!value
.isNull() && !value
.isEmpty() &&
189 !StartsWithASCII(value
.utf8(), "javascript:", false))
195 // Get all savable resource links from current webview, include main
196 // frame and sub-frame
197 bool GetAllSavableResourceLinksForCurrentPage(WebView
* view
,
198 const GURL
& page_url
, SavableResourcesResult
* result
,
199 const char** savable_schemes
) {
200 WebFrame
* main_frame
= view
->mainFrame();
204 std::set
<GURL
> resources_set
;
205 std::set
<GURL
> frames_set
;
206 std::vector
<WebFrame
*> frames
;
207 SavableResourcesUniqueCheck
unique_check(&resources_set
,
211 GURL
main_page_gurl(main_frame
->document().url());
213 // Make sure we are saving same page between embedder and webkit.
214 // If page has being navigated, embedder will get three empty vector,
215 // which will make the saving page job ended.
216 if (page_url
!= main_page_gurl
)
219 // First, process main frame.
220 frames
.push_back(main_frame
);
222 // Check all resource in this page, include sub-frame.
223 for (int i
= 0; i
< static_cast<int>(frames
.size()); ++i
) {
224 // Get current frame's all savable resource links.
225 GetAllSavableResourceLinksForFrame(frames
[i
], &unique_check
, result
,
229 // Since frame's src can also point to sub-resources link, so it is possible
230 // that some URLs in frames_list are also in resources_list. For those
231 // URLs, we will remove it from frame_list, only keep them in resources_list.
232 for (std::set
<GURL
>::iterator it
= frames_set
.begin();
233 it
!= frames_set
.end(); ++it
) {
234 // Append unique frame source to savable frame list.
235 if (resources_set
.find(*it
) == resources_set
.end())
236 result
->frames_list
->push_back(*it
);
242 bool PauseAnimationAtTimeOnElementWithId(WebView
* view
,
243 const std::string
& animation_name
,
245 const std::string
& element_id
) {
246 WebFrame
* web_frame
= view
->mainFrame();
250 WebAnimationController
* controller
= web_frame
->animationController();
255 web_frame
->document().getElementById(WebString::fromUTF8(element_id
));
256 if (element
.isNull())
258 return controller
->pauseAnimationAtTime(element
,
259 WebString::fromUTF8(animation_name
),
263 bool PauseTransitionAtTimeOnElementWithId(WebView
* view
,
264 const std::string
& property_name
,
266 const std::string
& element_id
) {
267 WebFrame
* web_frame
= view
->mainFrame();
271 WebAnimationController
* controller
= web_frame
->animationController();
276 web_frame
->document().getElementById(WebString::fromUTF8(element_id
));
277 if (element
.isNull())
279 return controller
->pauseTransitionAtTime(element
,
280 WebString::fromUTF8(property_name
),
284 bool ElementDoesAutoCompleteForElementWithId(WebView
* view
,
285 const std::string
& element_id
) {
286 WebFrame
* web_frame
= view
->mainFrame();
290 WebElement element
= web_frame
->document().getElementById(
291 WebString::fromUTF8(element_id
));
292 if (element
.isNull() || !element
.hasTagName("input"))
295 WebInputElement input_element
= element
.to
<WebInputElement
>();
296 return input_element
.autoComplete();
299 int NumberOfActiveAnimations(WebView
* view
) {
300 WebFrame
* web_frame
= view
->mainFrame();
304 WebAnimationController
* controller
= web_frame
->animationController();
308 return controller
->numberOfActiveAnimations();
311 void GetMetaElementsWithAttribute(WebDocument
* document
,
312 const string16
& attribute_name
,
313 const string16
& attribute_value
,
314 std::vector
<WebElement
>* meta_elements
) {
316 DCHECK(meta_elements
);
317 meta_elements
->clear();
318 WebElement head
= document
->head();
319 if (head
.isNull() || !head
.hasChildNodes())
322 WebNodeList children
= head
.childNodes();
323 for (size_t i
= 0; i
< children
.length(); ++i
) {
324 WebNode node
= children
.item(i
);
325 if (!node
.isElementNode())
327 WebElement element
= node
.to
<WebElement
>();
328 if (!element
.hasTagName("meta"))
330 WebString value
= element
.getAttribute(attribute_name
);
331 if (value
.isNull() || value
!= attribute_value
)
333 meta_elements
->push_back(element
);