• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2010 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.
4 
5 #include "webkit/glue/dom_operations.h"
6 
7 #include <set>
8 
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/WebString.h"
21 #include "third_party/WebKit/Source/WebKit/chromium/public/WebVector.h"
22 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
23 
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;
35 
36 namespace {
37 
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
48   // links.
49   std::vector<WebFrame*>* frames;
50 
SavableResourcesUniqueCheck__anon906038720111::SavableResourcesUniqueCheck51   SavableResourcesUniqueCheck()
52       : resources_set(NULL),
53         frames_set(NULL),
54         frames(NULL) {}
55 
SavableResourcesUniqueCheck__anon906038720111::SavableResourcesUniqueCheck56   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),
60         frames(frames) {}
61 };
62 
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.
GetSavableResourceLinkForElement(const WebElement & element,const WebDocument & current_doc,SavableResourcesUniqueCheck * unique_check,webkit_glue::SavableResourcesResult * result)66 void GetSavableResourceLinkForElement(
67     const WebElement& element,
68     const WebDocument& current_doc,
69     SavableResourcesUniqueCheck* unique_check,
70     webkit_glue::SavableResourcesResult* result) {
71 
72   // Handle frame and iframe tag.
73   if (element.hasTagName("iframe") ||
74       element.hasTagName("frame")) {
75     WebFrame* sub_frame = WebFrame::fromFrameOwnerElement(element);
76     if (sub_frame)
77       unique_check->frames->push_back(sub_frame);
78     return;
79   }
80 
81   // Check whether the node has sub resource URL or not.
82   WebString value =
83       webkit_glue::GetSubResourceLinkFromElement(element);
84   if (value.isNull())
85     return;
86   // Get absolute URL.
87   GURL u = current_doc.completeURL(value);
88   // ignore invalid URL
89   if (!u.is_valid())
90     return;
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"))
95     return;
96   // Ignore duplicated resource link.
97   if (!unique_check->resources_set->insert(u).second)
98     return;
99   result->resources_list->push_back(u);
100   // Insert referrer for above new resource link.
101   result->referrers_list->push_back(GURL());
102 }
103 
104 // Get all savable resource links from current WebFrameImpl object pointer.
GetAllSavableResourceLinksForFrame(WebFrame * current_frame,SavableResourcesUniqueCheck * unique_check,webkit_glue::SavableResourcesResult * result,const char ** savable_schemes)105 void GetAllSavableResourceLinksForFrame(WebFrame* current_frame,
106     SavableResourcesUniqueCheck* unique_check,
107     webkit_glue::SavableResourcesResult* result,
108     const char** savable_schemes) {
109   // Get current frame's URL.
110   GURL current_frame_url = current_frame->url();
111 
112   // If url of current frame is invalid, ignore it.
113   if (!current_frame_url.is_valid())
114     return;
115 
116   // If url of current frame is not a savable protocol, ignore it.
117   bool is_valid_protocol = false;
118   for (int i = 0; savable_schemes[i] != NULL; ++i) {
119     if (current_frame_url.SchemeIs(savable_schemes[i])) {
120       is_valid_protocol = true;
121       break;
122     }
123   }
124   if (!is_valid_protocol)
125     return;
126 
127   // If find same frame we have recorded, ignore it.
128   if (!unique_check->frames_set->insert(current_frame_url).second)
129     return;
130 
131   // Get current using document.
132   WebDocument current_doc = current_frame->document();
133   // Go through all descent nodes.
134   WebNodeCollection all = current_doc.all();
135   // Go through all node in this frame.
136   for (WebNode node = all.firstItem(); !node.isNull();
137        node = all.nextItem()) {
138     // We only save HTML resources.
139     if (!node.isElementNode())
140       continue;
141     WebElement element = node.to<WebElement>();
142     GetSavableResourceLinkForElement(element,
143                                      current_doc,
144                                      unique_check,
145                                      result);
146   }
147 }
148 
149 }  // namespace
150 
151 namespace webkit_glue {
152 
GetSubResourceLinkFromElement(const WebElement & element)153 WebString GetSubResourceLinkFromElement(const WebElement& element) {
154   const char* attribute_name = NULL;
155   if (element.hasTagName("img") ||
156       element.hasTagName("script")) {
157     attribute_name = "src";
158   } else if (element.hasTagName("input")) {
159     const WebInputElement input = element.toConst<WebInputElement>();
160     if (input.isImageButton()) {
161       attribute_name = "src";
162     }
163   } else if (element.hasTagName("body") ||
164              element.hasTagName("table") ||
165              element.hasTagName("tr") ||
166              element.hasTagName("td")) {
167     attribute_name = "background";
168   } else if (element.hasTagName("blockquote") ||
169              element.hasTagName("q") ||
170              element.hasTagName("del") ||
171              element.hasTagName("ins")) {
172     attribute_name = "cite";
173   } else if (element.hasTagName("link")) {
174     // If the link element is not linked to css, ignore it.
175     if (LowerCaseEqualsASCII(element.getAttribute("type"), "text/css")) {
176       // TODO(jnd): Add support for extracting links of sub-resources which
177       // are inside style-sheet such as @import, url(), etc.
178       // See bug: http://b/issue?id=1111667.
179       attribute_name = "href";
180     }
181   }
182   if (!attribute_name)
183     return WebString();
184   WebString value = element.getAttribute(WebString::fromUTF8(attribute_name));
185   // If value has content and not start with "javascript:" then return it,
186   // otherwise return NULL.
187   if (!value.isNull() && !value.isEmpty() &&
188       !StartsWithASCII(value.utf8(), "javascript:", false))
189     return value;
190 
191   return WebString();
192 }
193 
194 // Get all savable resource links from current webview, include main
195 // frame and sub-frame
GetAllSavableResourceLinksForCurrentPage(WebView * view,const GURL & page_url,SavableResourcesResult * result,const char ** savable_schemes)196 bool GetAllSavableResourceLinksForCurrentPage(WebView* view,
197     const GURL& page_url, SavableResourcesResult* result,
198     const char** savable_schemes) {
199   WebFrame* main_frame = view->mainFrame();
200   if (!main_frame)
201     return false;
202 
203   std::set<GURL> resources_set;
204   std::set<GURL> frames_set;
205   std::vector<WebFrame*> frames;
206   SavableResourcesUniqueCheck unique_check(&resources_set,
207                                            &frames_set,
208                                            &frames);
209 
210   GURL main_page_gurl(main_frame->url());
211 
212   // Make sure we are saving same page between embedder and webkit.
213   // If page has being navigated, embedder will get three empty vector,
214   // which will make the saving page job ended.
215   if (page_url != main_page_gurl)
216     return true;
217 
218   // First, process main frame.
219   frames.push_back(main_frame);
220 
221   // Check all resource in this page, include sub-frame.
222   for (int i = 0; i < static_cast<int>(frames.size()); ++i) {
223     // Get current frame's all savable resource links.
224     GetAllSavableResourceLinksForFrame(frames[i], &unique_check, result,
225                                        savable_schemes);
226   }
227 
228   // Since frame's src can also point to sub-resources link, so it is possible
229   // that some URLs in frames_list are also in resources_list. For those
230   // URLs, we will remove it from frame_list, only keep them in resources_list.
231   for (std::set<GURL>::iterator it = frames_set.begin();
232        it != frames_set.end(); ++it) {
233     // Append unique frame source to savable frame list.
234     if (resources_set.find(*it) == resources_set.end())
235       result->frames_list->push_back(*it);
236   }
237 
238   return true;
239 }
240 
PauseAnimationAtTimeOnElementWithId(WebView * view,const std::string & animation_name,double time,const std::string & element_id)241 bool PauseAnimationAtTimeOnElementWithId(WebView* view,
242                                          const std::string& animation_name,
243                                          double time,
244                                          const std::string& element_id) {
245   WebFrame* web_frame = view->mainFrame();
246   if (!web_frame)
247     return false;
248 
249   WebAnimationController* controller = web_frame->animationController();
250   if (!controller)
251     return false;
252 
253   WebElement element =
254     web_frame->document().getElementById(WebString::fromUTF8(element_id));
255   if (element.isNull())
256     return false;
257   return controller->pauseAnimationAtTime(element,
258                                           WebString::fromUTF8(animation_name),
259                                           time);
260 }
261 
PauseTransitionAtTimeOnElementWithId(WebView * view,const std::string & property_name,double time,const std::string & element_id)262 bool PauseTransitionAtTimeOnElementWithId(WebView* view,
263                                           const std::string& property_name,
264                                           double time,
265                                           const std::string& element_id) {
266   WebFrame* web_frame = view->mainFrame();
267   if (!web_frame)
268     return false;
269 
270   WebAnimationController* controller = web_frame->animationController();
271   if (!controller)
272     return false;
273 
274   WebElement element =
275       web_frame->document().getElementById(WebString::fromUTF8(element_id));
276   if (element.isNull())
277     return false;
278   return controller->pauseTransitionAtTime(element,
279                                            WebString::fromUTF8(property_name),
280                                            time);
281 }
282 
ElementDoesAutoCompleteForElementWithId(WebView * view,const std::string & element_id)283 bool ElementDoesAutoCompleteForElementWithId(WebView* view,
284                                              const std::string& element_id) {
285   WebFrame* web_frame = view->mainFrame();
286   if (!web_frame)
287     return false;
288 
289   WebElement element = web_frame->document().getElementById(
290       WebString::fromUTF8(element_id));
291   if (element.isNull() || !element.hasTagName("input"))
292     return false;
293 
294   WebInputElement input_element = element.to<WebInputElement>();
295   return input_element.autoComplete();
296 }
297 
NumberOfActiveAnimations(WebView * view)298 int NumberOfActiveAnimations(WebView* view) {
299   WebFrame* web_frame = view->mainFrame();
300   if (!web_frame)
301     return -1;
302 
303   WebAnimationController* controller = web_frame->animationController();
304   if (!controller)
305     return -1;
306 
307   return controller->numberOfActiveAnimations();
308 }
309 
GetMetaElementsWithAttribute(WebDocument * document,const string16 & attribute_name,const string16 & attribute_value,std::vector<WebElement> * meta_elements)310 void GetMetaElementsWithAttribute(WebDocument* document,
311                                   const string16& attribute_name,
312                                   const string16& attribute_value,
313                                   std::vector<WebElement>* meta_elements) {
314   DCHECK(document);
315   DCHECK(meta_elements);
316   meta_elements->clear();
317   WebElement head = document->head();
318   if (head.isNull() || !head.hasChildNodes())
319     return;
320 
321   WebNodeList children = head.childNodes();
322   for (size_t i = 0; i < children.length(); ++i) {
323     WebNode node = children.item(i);
324     if (!node.isElementNode())
325       continue;
326     WebElement element = node.to<WebElement>();
327     if (!element.hasTagName("meta"))
328       continue;
329     WebString value = element.getAttribute(attribute_name);
330     if (value.isNull() || value != attribute_value)
331       continue;
332     meta_elements->push_back(element);
333   }
334 }
335 
336 }  // webkit_glue
337