summaryrefslogtreecommitdiffstats
path: root/webkit/glue/dom_operations.cc
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-27 00:20:51 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-27 00:20:51 +0000
commitf5b16fed647e941aa66933178da85db2860d639b (patch)
treef00e9856c04aad3b558a140955e7674add33f051 /webkit/glue/dom_operations.cc
parent920c091ac3ee15079194c82ae8a7a18215f3f23c (diff)
downloadchromium_src-f5b16fed647e941aa66933178da85db2860d639b.zip
chromium_src-f5b16fed647e941aa66933178da85db2860d639b.tar.gz
chromium_src-f5b16fed647e941aa66933178da85db2860d639b.tar.bz2
Add webkit to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/glue/dom_operations.cc')
-rw-r--r--webkit/glue/dom_operations.cc791
1 files changed, 791 insertions, 0 deletions
diff --git a/webkit/glue/dom_operations.cc b/webkit/glue/dom_operations.cc
new file mode 100644
index 0000000..dd89d84
--- /dev/null
+++ b/webkit/glue/dom_operations.cc
@@ -0,0 +1,791 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "config.h"
+
+#pragma warning(push, 0)
+#include "FrameLoader.h"
+#include "FrameTree.h"
+#include "Document.h"
+#include "Element.h"
+#include "EventListener.h"
+#include "EventNames.h"
+#include "HTMLCollection.h"
+#include "HTMLElement.h"
+#include "HTMLFormElement.h"
+#include "HTMLFrameOwnerElement.h"
+#include "HTMLHeadElement.h"
+#include "HTMLInputElement.h"
+#include "HTMLLinkElement.h"
+#include "HTMLMetaElement.h"
+#include "HTMLNames.h"
+#include "KURL.h"
+#pragma warning(pop)
+#undef LOG
+
+#include "webkit/glue/dom_operations.h"
+
+#include "base/string_util.h"
+#include "webkit/glue/autocomplete_input_listener.h"
+#include "webkit/glue/form_data.h"
+#include "webkit/glue/glue_util.h"
+#include "webkit/glue/password_autocomplete_listener.h"
+#include "webkit/glue/webframe_impl.h"
+#include "webkit/glue/webview_impl.h"
+
+using WebCore::String;
+
+namespace {
+
+// Structure for storage the unique set of all savable resource links for
+// making sure that no duplicated resource link in final result. The consumer
+// of the SavableResourcesUniqueCheck is responsible for keeping these pointers
+// valid for the lifetime of the SavableResourcesUniqueCheck instance.
+struct SavableResourcesUniqueCheck {
+ // Unique set of all sub resource links.
+ std::set<GURL>* resources_set;
+ // Unique set of all frame links.
+ std::set<GURL>* frames_set;
+ // Collection of all frames we go through when getting all savable resource
+ // links.
+ std::vector<WebFrameImpl*>* frames;
+
+ SavableResourcesUniqueCheck()
+ : resources_set(NULL),
+ frames_set(NULL),
+ frames(NULL) {}
+
+ SavableResourcesUniqueCheck(std::set<GURL>* resources_set,
+ std::set<GURL>* frames_set, std::vector<WebFrameImpl*>* frames)
+ : resources_set(resources_set),
+ frames_set(frames_set),
+ frames(frames) {}
+};
+
+// Get all savable resource links from current element. One element might
+// have more than one resource link. It is possible to have some links
+// in one CSS stylesheet.
+void GetSavableResourceLinkForElement(WebCore::Element* element,
+ WebCore::Document* current_doc, SavableResourcesUniqueCheck* unique_check,
+ webkit_glue::SavableResourcesResult* result) {
+ // Handle frame and iframe tag.
+ bool is_frame_element;
+ WebFrameImpl* web_frame =
+ webkit_glue::GetWebFrameImplFromElement(element, &is_frame_element);
+ if (is_frame_element) {
+ if (web_frame)
+ unique_check->frames->push_back(web_frame);
+ return;
+ }
+ // Check whether the node has sub resource URL or not.
+ const WebCore::AtomicString* value =
+ webkit_glue::GetSubResourceLinkFromElement(element);
+ if (!value)
+ return;
+ // Get absolute URL.
+ GURL u(webkit_glue::KURLToGURL(current_doc->completeURL((*value).
+ deprecatedString())));
+ // ignore invalid URL
+ if (!u.is_valid())
+ return;
+ // Ignore those URLs which are not standard protocols. Because FTP
+ // protocol does no have cache mechanism, we will skip all
+ // sub-resources if they use FTP protocol.
+ if (!u.SchemeIs("http") && !u.SchemeIs("https") && !u.SchemeIs("file"))
+ return;
+ // Ignore duplicated resource link.
+ if (!unique_check->resources_set->insert(u).second)
+ return;
+ result->resources_list->push_back(u);
+ // Insert referrer for above new resource link.
+ if (current_doc->frame()) {
+ GURL u(webkit_glue::KURLToGURL(
+ current_doc->frame()->loader()->outgoingReferrer().
+ deprecatedString()));
+ result->referrers_list->push_back(u);
+ } else {
+ // Insert blank referrer.
+ result->referrers_list->push_back(GURL());
+ }
+}
+
+// Get all savable resource links from current WebFrameImpl object pointer.
+void GetAllSavableResourceLinksForFrame(WebFrameImpl* current_frame,
+ SavableResourcesUniqueCheck* unique_check,
+ webkit_glue::SavableResourcesResult* result) {
+ // Get current frame's URL.
+ const WebCore::KURL& current_frame_kurl =
+ current_frame->frame()->loader()->url();
+ GURL current_frame_gurl(webkit_glue::KURLToGURL(current_frame_kurl));
+
+ // If url of current frame is invalid or not standard protocol, ignore it.
+ if (!current_frame_gurl.is_valid())
+ return;
+ if (!current_frame_gurl.SchemeIs("http") &&
+ !current_frame_gurl.SchemeIs("https") &&
+ !current_frame_gurl.SchemeIs("ftp") &&
+ !current_frame_gurl.SchemeIs("file"))
+ return;
+ // If find same frame we have recorded, ignore it.
+ if (!unique_check->frames_set->insert(current_frame_gurl).second)
+ return;
+
+ // Get current using document.
+ WebCore::Document* current_doc = current_frame->frame()->document();
+ // Go through all descent nodes.
+ PassRefPtr<WebCore::HTMLCollection> all = current_doc->all();
+ // Go through all node in this frame.
+ for (WebCore::Node* node = all->firstItem(); node != NULL;
+ node = all->nextItem()) {
+ // We only save HTML resources.
+ if (!node->isHTMLElement())
+ continue;
+ WebCore::Element* element = static_cast<WebCore::Element*>(node);
+ GetSavableResourceLinkForElement(element,
+ current_doc,
+ unique_check,
+ result);
+ }
+}
+
+} // namespace
+
+namespace webkit_glue {
+
+// Map element name to a list of pointers to corresponding elements to simplify
+// form filling.
+typedef std::map<std::wstring, RefPtr<WebCore::HTMLInputElement> >
+ FormElementRefMap;
+
+// Utility struct for form lookup and autofill. When we parse the DOM to lookup
+// a form, in addition to action and origin URL's we have to compare all
+// necessary form elements. To avoid having to look these up again when we want
+// to fill the form, the FindFormElements function stores the pointers
+// in a FormElements* result, referenced to ensure they are safe to use.
+struct FormElements {
+ RefPtr<WebCore::HTMLFormElement> form_element;
+ FormElementRefMap input_elements;
+ FormElements() : form_element(NULL) {
+ }
+};
+
+typedef std::vector<FormElements*> FormElementsList;
+
+static bool FillFormToUploadFileImpl(WebCore::HTMLFormElement* fe,
+ const FileUploadData& data) {
+ std::vector<WebCore::HTMLInputElement*> changed;
+ PassRefPtr<WebCore::HTMLCollection> elements = fe->elements();
+ int i, c;
+
+ bool file_found = false;
+ bool submit_found = false;
+
+ // We reference the form element itself just in case it is destroyed by one
+ // of the onLoad() handler.
+ fe->ref();
+
+ for (i = 0, c = elements->length(); i < c; ++i) {
+ WebCore::HTMLInputElement* ie =
+ static_cast<WebCore::HTMLInputElement*>(elements->item(i));
+
+ std::wstring name = StringToStdWString(ie->name());
+ std::wstring id = StringToStdWString(ie->id());
+
+ if (!file_found &&
+ ie->inputType() == WebCore::HTMLInputElement::FILE &&
+ (name == data.file_name || id == data.file_name)) {
+ ie->setValueFromRenderer(StdWStringToString(data.file_path));
+ ie->ref();
+ changed.push_back(ie);
+ file_found = true;
+ } else if (!submit_found &&
+ ie->inputType() == WebCore::HTMLInputElement::SUBMIT &&
+ (name == data.submit_name || id == data.submit_name)) {
+ ie->setActivatedSubmit(true);
+ submit_found = true;
+ } else {
+ FormValueMap::const_iterator val = data.other_form_values.find(name);
+ if (val != data.other_form_values.end()) {
+ ie->setValueFromRenderer(StdWStringToString(val->second));
+ ie->ref();
+ changed.push_back(ie);
+ } else {
+ val = data.other_form_values.find(id);
+ if (val != data.other_form_values.end()) {
+ ie->setValueFromRenderer(StdWStringToString(val->second));
+ ie->ref();
+ changed.push_back(ie);
+ }
+ }
+ }
+ }
+
+ // Call all the onChange functions.
+ std::vector<WebCore::HTMLInputElement*>::iterator changed_ie;
+ for (changed_ie = changed.begin(); changed_ie != changed.end();
+ ++changed_ie) {
+ (*changed_ie)->onChange();
+ (*changed_ie)->deref();
+ }
+
+ // If we found both the file and the submit button, let's submit.
+ if (file_found && submit_found) {
+ fe->submit();
+ }
+
+ fe->deref();
+
+ // This operation is successful if the file input has been
+ // configured.
+ return file_found;
+}
+
+bool FillFormToUploadFile(WebView* view, const FileUploadData& data) {
+ WebFrame* main_frame = view->GetMainFrame();
+ if (!main_frame)
+ return false;
+ WebFrameImpl* main_frame_impl = static_cast<WebFrameImpl*>(main_frame);
+ WebCore::Frame* frame = main_frame_impl->frame();
+ WebCore::Frame* f;
+ for (f = frame; f; f = f->tree()->traverseNext()) {
+ WebCore::Document* doc = f->document();
+ if (doc->isHTMLDocument()) {
+ PassRefPtr<WebCore::HTMLCollection> forms = doc->forms();
+ int i, c;
+ for (i = 0, c = forms->length(); i < c; ++i) {
+ WebCore::HTMLFormElement* fe =
+ static_cast<WebCore::HTMLFormElement*>(forms->item(i));
+ std::wstring name = StringToStdWString(fe->name());
+ std::wstring id = StringToStdWString(fe->id());
+ if (data.form_name.empty() ||
+ id == data.form_name || name == data.form_name) {
+ if (FillFormToUploadFileImpl(fe, data))
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+// Internal implementation of FillForm API.
+static bool FillFormImpl(FormElements* fe, const FormData& data, bool submit) {
+ if (!fe->form_element->autoComplete())
+ return false;
+
+ FormValueMap data_map;
+ for (unsigned int i = 0; i < data.elements.size(); i++) {
+ data_map[data.elements[i]] = data.values[i];
+ }
+
+ bool submit_found = false;
+ for (FormElementRefMap::iterator it = fe->input_elements.begin();
+ it != fe->input_elements.end(); ++it) {
+ if (it->first == data.submit) {
+ it->second->setActivatedSubmit(true);
+ submit_found = true;
+ continue;
+ }
+ it->second->setValue(StdWStringToString(data_map[it->first]));
+ it->second->setAutofilled(true);
+ it->second->onChange();
+ }
+
+ if (submit && submit_found) {
+ fe->form_element->submit();
+ return true;
+ }
+ return false;
+}
+
+// Helper function to cast a Node as an HTMLInputElement.
+static WebCore::HTMLInputElement* GetNodeAsInputElement(WebCore::Node* node) {
+ DCHECK(node->nodeType() == WebCore::Node::ELEMENT_NODE);
+ DCHECK(static_cast<WebCore::Element*>(node)->hasTagName(
+ WebCore::HTMLNames::inputTag));
+ return static_cast<WebCore::HTMLInputElement*>(node);
+}
+
+// Helper to search the given form element for the specified input elements
+// in |data|, and add results to |result|.
+static bool FindFormInputElements(WebCore::HTMLFormElement* fe,
+ const FormData& data,
+ FormElements* result) {
+ Vector<RefPtr<WebCore::Node> > temp_elements;
+ bool found_elements = true;
+ // Loop through the list of elements we need to find on the form in
+ // order to autofill it. If we don't find any one of them, abort
+ // processing this form; it can't be the right one.
+ for (size_t j = 0; j < data.elements.size(); j++, temp_elements.clear()) {
+ fe->getNamedElements(StdWStringToString(data.elements[j]),
+ temp_elements);
+ if (temp_elements.isEmpty()) {
+ // We didn't find a required element. This is not the right form.
+ // Make sure no input elements from a partially matched form
+ // in this iteration remain in the result set.
+ // Note: clear will remove a reference from each InputElement.
+ result->input_elements.clear();
+ return false;
+ }
+ // This element matched, add it to our temporary result. It's possible
+ // there are multiple matches, but for purposes of identifying the form
+ // one suffices and if some function needs to deal with multiple
+ // matching elements it can get at them through the FormElement*.
+ // Note: This assignment adds a reference to the InputElement.
+ result->input_elements[data.elements[j]] =
+ GetNodeAsInputElement(temp_elements[0].get());
+ }
+ return true;
+}
+
+// Helper to locate form elements identified by |data|.
+static void FindFormElements(WebView* view,
+ const FormData& data,
+ FormElementsList* results) {
+ DCHECK(view);
+ DCHECK(results);
+ WebFrame* main_frame = view->GetMainFrame();
+ if (!main_frame)
+ return;
+
+ GURL::Replacements rep;
+ rep.ClearQuery();
+ rep.ClearRef();
+ WebFrameImpl* main_frame_impl = static_cast<WebFrameImpl*>(main_frame);
+ WebCore::Frame* frame = main_frame_impl->frame();
+
+ // Loop through each frame.
+ for (WebCore::Frame* f = frame; f; f = f->tree()->traverseNext()) {
+ WebCore::Document* doc = f->document();
+ if (!doc->isHTMLDocument())
+ continue;
+
+ GURL full_origin(StringToStdWString(doc->documentURI()));
+ if (data.origin != full_origin.ReplaceComponents(rep))
+ continue;
+
+ WebCore::FrameLoader* loader = f->loader();
+ if (loader == NULL)
+ continue;
+
+ PassRefPtr<WebCore::HTMLCollection> forms = doc->forms();
+ for (size_t i = 0; i < forms->length(); ++i) {
+ WebCore::HTMLFormElement* fe =
+ static_cast<WebCore::HTMLFormElement*>(forms->item(i));
+
+ // Action URL must match.
+ GURL full_action(KURLToGURL(loader->completeURL(fe->action())));
+ if (data.action != full_action.ReplaceComponents(rep))
+ continue;
+
+ scoped_ptr<FormElements> curr_elements(new FormElements);
+ if (!FindFormInputElements(fe, data, curr_elements.get()))
+ continue;
+
+ // We found the right element.
+ // Note: this assignment adds a reference to |fe|.
+ curr_elements->form_element = fe;
+ results->push_back(curr_elements.release());
+ }
+ }
+}
+
+bool FillForm(WebView* view, const FormData& data) {
+ FormElementsList forms;
+ FindFormElements(view, data, &forms);
+ bool success = false;
+ if (!forms.empty())
+ success = FillFormImpl(forms[0], data, false);
+
+ // TODO(timsteele): Move STLDeleteElements to base/ and have FormElementsList
+ // use that.
+ FormElementsList::iterator iter;
+ for (iter = forms.begin(); iter != forms.end(); ++iter)
+ delete *iter;
+ return success;
+}
+
+void FillPasswordForm(WebView* view,
+ const PasswordFormDomManager::FillData& data) {
+ FormElementsList forms;
+ // We own the FormElements* in forms.
+ FindFormElements(view, data.basic_data, &forms);
+ FormElementsList::iterator iter;
+ for (iter = forms.begin(); iter != forms.end(); ++iter) {
+ // TODO(timsteele): Move STLDeleteElements to base/ and have
+ // FormElementsList use that.
+ scoped_ptr<FormElements> form_elements(*iter);
+
+ // False param to FillFormByAction is so we don't auto-submit password
+ // forms. If wait_for_username is true, we don't want to initially fill
+ // the form until the user types in a valid username.
+ if (!data.wait_for_username)
+ FillFormImpl(form_elements.get(), data.basic_data, false);
+
+ // Attach autocomplete listener to enable selecting alternate logins.
+ // First, get pointers to username element.
+ WebCore::HTMLInputElement* username_element =
+ form_elements->input_elements[data.basic_data.elements[0]].get();
+
+ // Get pointer to password element. (We currently only support single
+ // password forms).
+ WebCore::HTMLInputElement* password_element =
+ form_elements->input_elements[data.basic_data.elements[1]].get();
+
+ AttachForInlineAutocomplete(username_element,
+ new PasswordAutocompleteListener(
+ new HTMLInputDelegate(username_element),
+ new HTMLInputDelegate(password_element),
+ data));
+ }
+}
+
+WebFrameImpl* GetWebFrameImplFromElement(WebCore::Element* element,
+ bool* is_frame_element) {
+ *is_frame_element = false;
+ if (element->hasTagName(WebCore::HTMLNames::iframeTag) ||
+ element->hasTagName(WebCore::HTMLNames::frameTag)) {
+ *is_frame_element = true;
+ if (element->isFrameOwnerElement()) {
+ // Check whether this frame has content.
+ WebCore::HTMLFrameOwnerElement* frame_element =
+ static_cast<WebCore::HTMLFrameOwnerElement*>(element);
+ WebCore::Frame* content_frame = frame_element->contentFrame();
+ return content_frame ? WebFrameImpl::FromFrame(content_frame) : NULL;
+ }
+ }
+ return NULL;
+}
+
+const WebCore::AtomicString* GetSubResourceLinkFromElement(
+ const WebCore::Element* element) {
+ const WebCore::QualifiedName* attribute_name = NULL;
+ if (element->hasTagName(WebCore::HTMLNames::imgTag) ||
+ element->hasTagName(WebCore::HTMLNames::scriptTag) ||
+ element->hasTagName(WebCore::HTMLNames::linkTag)) {
+ // Get value.
+ if (element->hasTagName(WebCore::HTMLNames::linkTag)) {
+ // If the link element is not linked to css, ignore it.
+ const WebCore::HTMLLinkElement* link =
+ static_cast<const WebCore::HTMLLinkElement*>(element);
+ if (!link->sheet())
+ return NULL;
+ // TODO(jnd). Add support for extracting links of sub-resources which
+ // are inside style-sheet such as @import, url(), etc.
+ // See bug: http://b/issue?id=1111667.
+ attribute_name = &WebCore::HTMLNames::hrefAttr;
+ } else {
+ attribute_name = &WebCore::HTMLNames::srcAttr;
+ }
+ } else if (element->hasTagName(WebCore::HTMLNames::inputTag)) {
+ const WebCore::HTMLInputElement* input =
+ static_cast<const WebCore::HTMLInputElement*>(element);
+ if (input->inputType() == WebCore::HTMLInputElement::IMAGE) {
+ attribute_name = &WebCore::HTMLNames::srcAttr;
+ }
+ } else if (element->hasTagName(WebCore::HTMLNames::bodyTag) ||
+ element->hasTagName(WebCore::HTMLNames::tableTag) ||
+ element->hasTagName(WebCore::HTMLNames::trTag) ||
+ element->hasTagName(WebCore::HTMLNames::tdTag)) {
+ attribute_name = &WebCore::HTMLNames::backgroundAttr;
+ } else if (element->hasTagName(WebCore::HTMLNames::blockquoteTag) ||
+ element->hasTagName(WebCore::HTMLNames::qTag) ||
+ element->hasTagName(WebCore::HTMLNames::delTag) ||
+ element->hasTagName(WebCore::HTMLNames::insTag)) {
+ attribute_name = &WebCore::HTMLNames::citeAttr;
+ }
+ if (!attribute_name)
+ return NULL;
+ const WebCore::AtomicString* value =
+ &element->getAttribute(*attribute_name);
+ // If value has content and not start with "javascript:" then return it,
+ // otherwise return NULL.
+ if (value && !value->isEmpty() &&
+ !value->domString().startsWith("javascript:", false))
+ return value;
+
+ return NULL;
+}
+
+bool ElementHasLegalLinkAttribute(const WebCore::Element* element,
+ const WebCore::QualifiedName& attr_name) {
+ if (attr_name == WebCore::HTMLNames::srcAttr) {
+ // Check src attribute.
+ if (element->hasTagName(WebCore::HTMLNames::imgTag) ||
+ element->hasTagName(WebCore::HTMLNames::scriptTag) ||
+ element->hasTagName(WebCore::HTMLNames::iframeTag) ||
+ element->hasTagName(WebCore::HTMLNames::frameTag))
+ return true;
+ if (element->hasTagName(WebCore::HTMLNames::inputTag)) {
+ const WebCore::HTMLInputElement* input =
+ static_cast<const WebCore::HTMLInputElement*>(element);
+ if (input->inputType() == WebCore::HTMLInputElement::IMAGE)
+ return true;
+ }
+ } else if (attr_name == WebCore::HTMLNames::hrefAttr) {
+ // Check href attribute.
+ if (element->hasTagName(WebCore::HTMLNames::linkTag) ||
+ element->hasTagName(WebCore::HTMLNames::aTag) ||
+ element->hasTagName(WebCore::HTMLNames::areaTag))
+ return true;
+ } else if (attr_name == WebCore::HTMLNames::actionAttr) {
+ if (element->hasTagName(WebCore::HTMLNames::formTag))
+ return true;
+ } else if (attr_name == WebCore::HTMLNames::backgroundAttr) {
+ if (element->hasTagName(WebCore::HTMLNames::bodyTag) ||
+ element->hasTagName(WebCore::HTMLNames::tableTag) ||
+ element->hasTagName(WebCore::HTMLNames::trTag) ||
+ element->hasTagName(WebCore::HTMLNames::tdTag))
+ return true;
+ } else if (attr_name == WebCore::HTMLNames::citeAttr) {
+ if (element->hasTagName(WebCore::HTMLNames::blockquoteTag) ||
+ element->hasTagName(WebCore::HTMLNames::qTag) ||
+ element->hasTagName(WebCore::HTMLNames::delTag) ||
+ element->hasTagName(WebCore::HTMLNames::insTag))
+ return true;
+ } else if (attr_name == WebCore::HTMLNames::classidAttr ||
+ attr_name == WebCore::HTMLNames::dataAttr) {
+ if (element->hasTagName(WebCore::HTMLNames::objectTag))
+ return true;
+ } else if (attr_name == WebCore::HTMLNames::codebaseAttr) {
+ if (element->hasTagName(WebCore::HTMLNames::objectTag) ||
+ element->hasTagName(WebCore::HTMLNames::appletTag))
+ return true;
+ }
+ return false;
+}
+
+WebFrameImpl* GetWebFrameImplFromWebViewForSpecificURL(WebView* view,
+ const GURL& page_url) {
+ WebFrame* main_frame = view->GetMainFrame();
+ if (!main_frame)
+ return NULL;
+ WebFrameImpl* main_frame_impl = static_cast<WebFrameImpl*>(main_frame);
+
+ std::vector<WebFrameImpl*> frames;
+ // First, process main frame.
+ frames.push_back(main_frame_impl);
+ // Collect all frames inside the specified frame.
+ for (int i = 0; i < static_cast<int>(frames.size()); ++i) {
+ WebFrameImpl* current_frame = frames[i];
+ // Get current using document.
+ WebCore::Document* current_doc = current_frame->frame()->document();
+ // Check whether current frame is target or not.
+ const WebCore::KURL& current_frame_kurl =
+ current_frame->frame()->loader()->url();
+ GURL current_frame_gurl(KURLToGURL(current_frame_kurl));
+ if (page_url == current_frame_gurl)
+ return current_frame;
+ // Go through sub-frames.
+ RefPtr<WebCore::HTMLCollection> all = current_doc->all();
+ for (WebCore::Node* node = all->firstItem(); node != NULL;
+ node = all->nextItem()) {
+ if (!node->isHTMLElement())
+ continue;
+ WebCore::Element* element = static_cast<WebCore::Element*>(node);
+ // Check frame tag and iframe tag.
+ bool is_frame_element;
+ WebFrameImpl* web_frame = GetWebFrameImplFromElement(
+ element, &is_frame_element);
+ if (is_frame_element && web_frame)
+ frames.push_back(web_frame);
+ }
+ }
+
+ return NULL;
+}
+
+// Get all savable resource links from current webview, include main
+// frame and sub-frame
+bool GetAllSavableResourceLinksForCurrentPage(WebView* view,
+ const GURL& page_url, SavableResourcesResult* result) {
+ WebFrame* main_frame = view->GetMainFrame();
+ if (!main_frame)
+ return false;
+ WebFrameImpl* main_frame_impl = static_cast<WebFrameImpl*>(main_frame);
+
+ std::set<GURL> resources_set;
+ std::set<GURL> frames_set;
+ std::vector<WebFrameImpl*> frames;
+ SavableResourcesUniqueCheck unique_check(&resources_set,
+ &frames_set,
+ &frames);
+
+ GURL main_page_gurl(KURLToGURL(main_frame_impl->frame()->loader()->url()));
+
+ // Make sure we are saving same page between embedder and webkit.
+ // If page has being navigated, embedder will get three empty vector,
+ // which will make the saving page job ended.
+ if (page_url != main_page_gurl)
+ return true;
+
+ // First, process main frame.
+ frames.push_back(main_frame_impl);
+
+ // Check all resource in this page, include sub-frame.
+ for (int i = 0; i < static_cast<int>(frames.size()); ++i) {
+ // Get current frame's all savable resource links.
+ GetAllSavableResourceLinksForFrame(frames[i], &unique_check, result);
+ }
+
+ // Since frame's src can also point to sub-resources link, so it is possible
+ // that some URLs in frames_list are also in resources_list. For those
+ // URLs, we will remove it from frame_list, only keep them in resources_list.
+ for (std::set<GURL>::iterator it = frames_set.begin();
+ it != frames_set.end(); ++it) {
+ // Append unique frame source to savable frame list.
+ if (resources_set.find(*it) == resources_set.end())
+ result->frames_list->push_back(*it);
+ }
+
+ return true;
+}
+
+// Sizes a single size (the width or height) from a 'sizes' attribute. A size
+// matches must match the following regex: [1-9][0-9]*.
+static int ParseSingleIconSize(const std::wstring& text) {
+ // Size must not start with 0, and be between 0 and 9.
+ if (text.empty() || !(text[0] >= L'1' && text[0] <= L'9'))
+ return 0;
+ // Make sure all chars are from 0-9.
+ for (size_t i = 1; i < text.length(); ++i) {
+ if (!(text[i] >= L'0' && text[i] <= L'9'))
+ return 0;
+ }
+ return _wtoi(text.c_str());
+}
+
+// Parses an icon size. An icon size must match the following regex:
+// [1-9][0-9]*x[1-9][0-9]*.
+// If the input couldn't be parsed, a size with a width/height < 0 is returned.
+static gfx::Size ParseIconSize(const std::wstring& text) {
+ std::vector<std::wstring> sizes;
+ SplitStringDontTrim(text, L'x', &sizes);
+ if (sizes.size() != 2)
+ return gfx::Size();
+
+ return gfx::Size(ParseSingleIconSize(sizes[0]),
+ ParseSingleIconSize(sizes[1]));
+}
+
+bool ParseIconSizes(const std::wstring& text,
+ std::vector<gfx::Size>* sizes,
+ bool* is_any) {
+ *is_any = false;
+ std::vector<std::wstring> size_strings;
+ SplitStringAlongWhitespace(text, &size_strings);
+ for (size_t i = 0; i < size_strings.size(); ++i) {
+ if (size_strings[i] == L"any") {
+ *is_any = true;
+ } else {
+ gfx::Size size = ParseIconSize(size_strings[i]);
+ if (size.width() <= 0 || size.height() <= 0)
+ return false; // Bogus size.
+ sizes->push_back(size);
+ }
+ }
+ if (*is_any && !sizes->empty()) {
+ // If is_any is true, it must occur by itself.
+ return false;
+ }
+ return (*is_any || !sizes->empty());
+}
+
+static void AddInstallIcon(WebCore::HTMLLinkElement* link,
+ std::vector<WebApplicationInfo::IconInfo>* icons) {
+ String href = link->href();
+ if (href.isEmpty() || href.isNull())
+ return;
+
+ GURL url(webkit_glue::StringToStdWString(href));
+ if (!url.is_valid())
+ return;
+
+ const String sizes_attr = "sizes";
+ if (!link->hasAttribute(sizes_attr))
+ return;
+
+ bool is_any = false;
+ std::vector<gfx::Size> icon_sizes;
+ if (!ParseIconSizes(webkit_glue::StringToStdWString(
+ link->getAttribute(sizes_attr)), &icon_sizes, &is_any) || is_any ||
+ icon_sizes.size() != 1) {
+ return;
+ }
+ WebApplicationInfo::IconInfo icon_info;
+ icon_info.width = icon_sizes[0].width();
+ icon_info.height = icon_sizes[0].height();
+ icon_info.url = url;
+ icons->push_back(icon_info);
+}
+
+void GetApplicationInfo(WebView* view, WebApplicationInfo* app_info) {
+ WebFrame* main_frame = view->GetMainFrame();
+ if (!main_frame)
+ return;
+ WebFrameImpl* main_frame_impl = static_cast<WebFrameImpl*>(main_frame);
+
+ WebCore::HTMLHeadElement* head;
+ if (!main_frame_impl->frame() ||
+ !main_frame_impl->frame()->document() ||
+ !(head = main_frame_impl->frame()->document()->head())) {
+ return;
+ }
+ WTF::PassRefPtr<WebCore::HTMLCollection> children = head->children();
+ for (unsigned i = 0; i < children->length(); ++i) {
+ WebCore::Node* child = children->item(i);
+ WebCore::HTMLLinkElement* link = CastHTMLElement<WebCore::HTMLLinkElement>(
+ child, WebCore::HTMLNames::linkTag);
+ if (link) {
+ if (link->isIcon())
+ AddInstallIcon(link, &app_info->icons);
+ } else {
+ WebCore::HTMLMetaElement* meta =
+ CastHTMLElement<WebCore::HTMLMetaElement>(
+ child, WebCore::HTMLNames::metaTag);
+ if (meta) {
+ if (meta->name() == String("application-name")) {
+ app_info->title = webkit_glue::StringToStdWString(meta->content());
+ } else if (meta->name() == String("description")) {
+ app_info->description =
+ webkit_glue::StringToStdWString(meta->content());
+ } else if (meta->name() == String("application-url")) {
+ std::wstring url = webkit_glue::StringToStdWString(meta->content());
+ GURL main_url = main_frame->GetURL();
+ app_info->app_url = main_url.is_valid() ?
+ main_url.Resolve(url) : GURL(url);
+ if (!app_info->app_url.is_valid())
+ app_info->app_url = GURL();
+ }
+ }
+ }
+ }
+}
+
+} // webkit_glue