Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(11)

Side by Side Diff: webkit/glue/searchable_form_data.cc

Issue 306057: Move SearchableFormData over to the WebKit API. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « webkit/glue/searchable_form_data.h ('k') | webkit/glue/webview_impl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2009 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 "config.h"
6
7 #include "base/compiler_specific.h"
8
9 MSVC_PUSH_WARNING_LEVEL(0);
10 #include "Document.h"
11 #include "FormDataBuilder.h"
12 #include "FormDataList.h"
13 #include "Frame.h"
14 #include "HTMLFormControlElement.h"
15 #include "HTMLFormElement.h"
16 #include "HTMLOptionElement.h"
17 #include "HTMLInputElement.h"
18 #include "HTMLNames.h"
19 #include "HTMLOptionsCollection.h"
20 #include "HTMLSelectElement.h"
21 #include "TextEncoding.h"
22 MSVC_POP_WARNING();
23
24 #undef LOG
25
26 #include "webkit/glue/glue_util.h"
27 #include "webkit/glue/searchable_form_data.h"
28
29 using namespace WebCore;
30
31 namespace webkit_glue {
32
33 namespace {
34
35 // Gets the encoding for the form.
36 void GetFormEncoding(HTMLFormElement* form, TextEncoding* encoding) {
37 String str(form->getAttribute(HTMLNames::accept_charsetAttr));
38 str.replace(',', ' ');
39 Vector<String> charsets;
40 str.split(' ', charsets);
41 for (Vector<String>::const_iterator i(charsets.begin()); i != charsets.end();
42 ++i) {
43 *encoding = TextEncoding(*i);
44 if (encoding->isValid())
45 return;
46 }
47 const Frame* frame = form->document()->frame();
48 *encoding = frame ?
49 TextEncoding(frame->loader()->encoding()) : Latin1Encoding();
50 }
51
52 // Returns true if the submit request results in an HTTP URL.
53 bool IsHTTPFormSubmit(HTMLFormElement* form) {
54 String action(form->action());
55 return form->document()->frame()->loader()->
56 completeURL(action.isNull() ? "" : action).protocol() == "http";
57 }
58
59 // If the form does not have an activated submit button, the first submit
60 // button is returned.
61 HTMLFormControlElement* GetButtonToActivate(HTMLFormElement* form) {
62 HTMLFormControlElement* first_submit_button = NULL;
63 for (Vector<HTMLFormControlElement*>::const_iterator
64 i(form->formElements.begin()); i != form->formElements.end(); ++i) {
65 HTMLFormControlElement* form_element = *i;
66 if (form_element->isActivatedSubmit()) {
67 // There's a button that is already activated for submit, return NULL.
68 return NULL;
69 } else if (first_submit_button == NULL &&
70 form_element->isSuccessfulSubmitButton()) {
71 first_submit_button = form_element;
72 }
73 }
74 return first_submit_button;
75 }
76
77 // Returns true if the selected state of all the options matches the default
78 // selected state.
79 bool IsSelectInDefaultState(HTMLSelectElement* select) {
80 const Vector<Element*>& list_items = select->listItems();
81 if (select->multiple() || select->size() > 1) {
82 for (Vector<Element*>::const_iterator i(list_items.begin());
83 i != list_items.end(); ++i) {
84 if (!(*i)->hasLocalName(HTMLNames::optionTag))
85 continue;
86 const HTMLOptionElement* option_element =
87 static_cast<const HTMLOptionElement*>(*i);
88 if (option_element->selected() != option_element->defaultSelected())
89 return false;
90 }
91 return true;
92 }
93
94 // The select is rendered as a combobox (called menulist in WebKit). At
95 // least one item is selected, determine which one.
96 const HTMLOptionElement* initial_selected = NULL;
97 for (Vector<Element*>::const_iterator i(list_items.begin());
98 i != list_items.end(); ++i) {
99 if (!(*i)->hasLocalName(HTMLNames::optionTag))
100 continue;
101 const HTMLOptionElement* option_element =
102 static_cast<const HTMLOptionElement*>(*i);
103 if (option_element->defaultSelected()) {
104 // The page specified the option to select.
105 initial_selected = option_element;
106 break;
107 } else if (!initial_selected) {
108 initial_selected = option_element;
109 }
110 }
111 return initial_selected ? initial_selected->selected() : true;
112 }
113
114 // Returns true if the form element is in its default state, false otherwise.
115 // The default state is the state of the form element on initial load of the
116 // page, and varies depending upon the form element. For example, a checkbox is
117 // in its default state if the checked state matches the defaultChecked state.
118 bool IsInDefaultState(HTMLFormControlElement* form_element) {
119 if (form_element->hasTagName(HTMLNames::inputTag)) {
120 const HTMLInputElement* input_element =
121 static_cast<const HTMLInputElement*>(form_element);
122 if (input_element->inputType() == HTMLInputElement::CHECKBOX ||
123 input_element->inputType() == HTMLInputElement::RADIO) {
124 return input_element->checked() == input_element->defaultChecked();
125 }
126 } else if (form_element->hasTagName(HTMLNames::selectTag)) {
127 return IsSelectInDefaultState(
128 static_cast<HTMLSelectElement*>(form_element));
129 }
130 return true;
131 }
132
133 // If form has only one text input element, return true. If a valid input
134 // element is not found, return false. Additionally, the form data for all
135 // elements is added to enc_string and the encoding used is set in
136 // encoding_name.
137 bool HasSuitableTextElement(HTMLFormElement* form,
138 Vector<char>* enc_string,
139 std::string* encoding_name) {
140 TextEncoding encoding;
141 GetFormEncoding(form, &encoding);
142 if (!encoding.isValid()) {
143 // Need a valid encoding to encode the form elements.
144 // If the encoding isn't found webkit ends up replacing the params with
145 // empty strings. So, we don't try to do anything here.
146 return NULL;
147 }
148 *encoding_name = encoding.name();
149
150 HTMLInputElement* text_element = NULL;
151 for (Vector<HTMLFormControlElement*>::const_iterator
152 i(form->formElements.begin()); i != form->formElements.end(); ++i) {
153 HTMLFormControlElement* form_element = *i;
154 if (form_element->disabled() || form_element->name().isNull())
155 continue;
156
157 if (!IsInDefaultState(form_element) ||
158 form_element->hasTagName(HTMLNames::textareaTag))
159 return NULL;
160
161 bool is_text_element = false;
162 if (form_element->hasTagName(HTMLNames::inputTag)) {
163 switch (static_cast<const HTMLInputElement*>(form_element)->inputType()) {
164 case HTMLInputElement::TEXT:
165 case HTMLInputElement::ISINDEX:
166 is_text_element = true;
167 break;
168 case HTMLInputElement::PASSWORD:
169 // Don't store passwords! This is most likely an https anyway.
170 // Fall through.
171 case HTMLInputElement::FILE:
172 // Too big, don't try to index this.
173 return NULL;
174 default:
175 // All other input types are indexable.
176 break;
177 }
178 }
179
180 FormDataList data_list(encoding);
181 if (!form_element->appendFormData(data_list, false))
182 continue;
183
184 const Vector<FormDataList::Item>& item_list = data_list.list();
185 if (is_text_element && !item_list.isEmpty()) {
186 if (text_element != NULL) {
187 // The auto-complete bar only knows how to fill in one value.
188 // This form has multiple fields; don't treat it as searchable.
189 return false;
190 }
191 text_element = static_cast<HTMLInputElement*>(form_element);
192 }
193 for (Vector<FormDataList::Item>::const_iterator j(item_list.begin());
194 j != item_list.end(); ++j) {
195 // Handle ISINDEX / <input name=isindex> specially, but only if it's
196 // the first entry.
197 if (!enc_string->isEmpty() || j->data() != "isindex") {
198 if (!enc_string->isEmpty())
199 enc_string->append('&');
200 FormDataBuilder::encodeStringAsFormData(*enc_string, j->data());
201 enc_string->append('=');
202 }
203 ++j;
204 if (form_element == text_element)
205 enc_string->append("{searchTerms}", 13);
206 else
207 FormDataBuilder::encodeStringAsFormData(*enc_string, j->data());
208 }
209 }
210
211 return text_element != NULL;
212 }
213
214 } // namespace
215
216 SearchableFormData* SearchableFormData::Create(const WebKit::WebForm& webform) {
217 RefPtr<HTMLFormElement> form = WebFormToHTMLFormElement(webform);
218 const Frame* frame = form->document()->frame();
219 if (frame == NULL)
220 return NULL;
221
222 // Only consider forms that GET data and the action targets an http page.
223 if (equalIgnoringCase(form->getAttribute(HTMLNames::methodAttr), "post") ||
224 !IsHTTPFormSubmit(form.get()))
225 return NULL;
226
227 HTMLFormControlElement* first_submit_button = GetButtonToActivate(form.get());
228 if (first_submit_button) {
229 // The form does not have an active submit button, make the first button
230 // active. We need to do this, otherwise the URL will not contain the
231 // name of the submit button.
232 first_submit_button->setActivatedSubmit(true);
233 }
234 Vector<char> enc_string;
235 std::string encoding;
236 bool has_element = HasSuitableTextElement(form.get(), &enc_string, &encoding);
237 if (first_submit_button)
238 first_submit_button->setActivatedSubmit(false);
239 if (!has_element) {
240 // Not a searchable form.
241 return NULL;
242 }
243
244 // It's a valid form.
245 // Generate the URL and create a new SearchableFormData.
246 RefPtr<FormData> form_data = FormData::create(enc_string);
247 String action(form->action());
248 KURL url = frame->loader()->completeURL(action.isNull() ? "" : action);
249 url.setQuery(form_data->flattenToString());
250 GURL gurl(KURLToGURL(url));
251 return new SearchableFormData(gurl, encoding);
252 }
253
254 } // namespace webkit_glue
OLDNEW
« no previous file with comments | « webkit/glue/searchable_form_data.h ('k') | webkit/glue/webview_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698