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

Side by Side Diff: webkit/api/src/WebSearchableFormData.cpp

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/api/public/WebSearchableFormData.h ('k') | webkit/glue/searchable_form_data.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 /*
2 // Use of this source code is governed by a BSD-style license that can be 2 * Copyright (C) 2009 Google Inc. All rights reserved.
3 // found in the LICENSE file. 3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
4 30
5 #include "config.h" 31 #include "config.h"
32 #include "WebSearchableFormData.h"
6 33
7 #include "base/compiler_specific.h"
8
9 MSVC_PUSH_WARNING_LEVEL(0);
10 #include "Document.h" 34 #include "Document.h"
11 #include "FormDataBuilder.h" 35 #include "FormDataBuilder.h"
12 #include "FormDataList.h" 36 #include "FormDataList.h"
13 #include "Frame.h" 37 #include "Frame.h"
14 #include "HTMLFormControlElement.h" 38 #include "HTMLFormControlElement.h"
15 #include "HTMLFormElement.h" 39 #include "HTMLFormElement.h"
16 #include "HTMLOptionElement.h" 40 #include "HTMLOptionElement.h"
17 #include "HTMLInputElement.h" 41 #include "HTMLInputElement.h"
18 #include "HTMLNames.h" 42 #include "HTMLNames.h"
19 #include "HTMLOptionsCollection.h" 43 #include "HTMLOptionsCollection.h"
20 #include "HTMLSelectElement.h" 44 #include "HTMLSelectElement.h"
21 #include "TextEncoding.h" 45 #include "TextEncoding.h"
22 MSVC_POP_WARNING(); 46 #include "WebForm.h"
23
24 #undef LOG
25
26 #include "webkit/glue/glue_util.h"
27 #include "webkit/glue/searchable_form_data.h"
28 47
29 using namespace WebCore; 48 using namespace WebCore;
30 49
31 namespace webkit_glue {
32
33 namespace { 50 namespace {
34 51
35 // Gets the encoding for the form. 52 // Gets the encoding for the form.
36 void GetFormEncoding(HTMLFormElement* form, TextEncoding* encoding) { 53 void GetFormEncoding(const HTMLFormElement* form, TextEncoding* encoding)
37 String str(form->getAttribute(HTMLNames::accept_charsetAttr)); 54 {
38 str.replace(',', ' '); 55 String str(form->getAttribute(HTMLNames::accept_charsetAttr));
39 Vector<String> charsets; 56 str.replace(',', ' ');
40 str.split(' ', charsets); 57 Vector<String> charsets;
41 for (Vector<String>::const_iterator i(charsets.begin()); i != charsets.end(); 58 str.split(' ', charsets);
42 ++i) { 59 for (Vector<String>::const_iterator i(charsets.begin()); i != charsets.end(); ++i) {
43 *encoding = TextEncoding(*i); 60 *encoding = TextEncoding(*i);
44 if (encoding->isValid()) 61 if (encoding->isValid())
45 return; 62 return;
46 } 63 }
47 const Frame* frame = form->document()->frame(); 64 const Frame* frame = form->document()->frame();
48 *encoding = frame ? 65 *encoding = frame ? TextEncoding(frame->loader()->encoding()) : Latin1Encoding();
49 TextEncoding(frame->loader()->encoding()) : Latin1Encoding();
50 } 66 }
51 67
52 // Returns true if the submit request results in an HTTP URL. 68 // Returns true if the submit request results in an HTTP URL.
53 bool IsHTTPFormSubmit(HTMLFormElement* form) { 69 bool IsHTTPFormSubmit(const HTMLFormElement* form)
54 String action(form->action()); 70 {
55 return form->document()->frame()->loader()-> 71 String action(form->action());
56 completeURL(action.isNull() ? "" : action).protocol() == "http"; 72 return form->document()->frame()->loader()->completeURL(action.isNull() ? "" : action).protocol() == "http";
57 } 73 }
58 74
59 // If the form does not have an activated submit button, the first submit 75 // If the form does not have an activated submit button, the first submit
60 // button is returned. 76 // button is returned.
61 HTMLFormControlElement* GetButtonToActivate(HTMLFormElement* form) { 77 HTMLFormControlElement* GetButtonToActivate(HTMLFormElement* form)
62 HTMLFormControlElement* first_submit_button = NULL; 78 {
63 for (Vector<HTMLFormControlElement*>::const_iterator 79 HTMLFormControlElement* firstSubmitButton = 0;
64 i(form->formElements.begin()); i != form->formElements.end(); ++i) { 80 for (Vector<HTMLFormControlElement*>::const_iterator i(form->formElements.begin()); i != form->formElements.end(); ++i) {
65 HTMLFormControlElement* form_element = *i; 81 HTMLFormControlElement* formElement = *i;
66 if (form_element->isActivatedSubmit()) { 82 if (formElement->isActivatedSubmit()) {
67 // There's a button that is already activated for submit, return NULL. 83 // There's a button that is already activated for submit, return 0.
68 return NULL; 84 return 0;
69 } else if (first_submit_button == NULL && 85 } else if (!firstSubmitButton && formElement->isSuccessfulSubmitButton())
70 form_element->isSuccessfulSubmitButton()) { 86 firstSubmitButton = formElement;
71 first_submit_button = form_element; 87 }
72 } 88 return firstSubmitButton;
73 }
74 return first_submit_button;
75 } 89 }
76 90
77 // Returns true if the selected state of all the options matches the default 91 // Returns true if the selected state of all the options matches the default
78 // selected state. 92 // selected state.
79 bool IsSelectInDefaultState(HTMLSelectElement* select) { 93 bool IsSelectInDefaultState(const HTMLSelectElement* select)
80 const Vector<Element*>& list_items = select->listItems(); 94 {
81 if (select->multiple() || select->size() > 1) { 95 const Vector<Element*>& listItems = select->listItems();
82 for (Vector<Element*>::const_iterator i(list_items.begin()); 96 if (select->multiple() || select->size() > 1) {
83 i != list_items.end(); ++i) { 97 for (Vector<Element*>::const_iterator i(listItems.begin()); i != listItems.end(); ++i) {
84 if (!(*i)->hasLocalName(HTMLNames::optionTag)) 98 if (!(*i)->hasLocalName(HTMLNames::optionTag))
85 continue; 99 continue;
86 const HTMLOptionElement* option_element = 100 const HTMLOptionElement* optionElement = static_cast<const HTMLOptionElement*>(*i);
87 static_cast<const HTMLOptionElement*>(*i); 101 if (optionElement->selected() != optionElement->defaultSelected())
88 if (option_element->selected() != option_element->defaultSelected()) 102 return false;
89 return false; 103 }
90 } 104 return true;
91 return true; 105 }
92 } 106
93 107 // The select is rendered as a combobox (called menulist in WebKit). At
94 // The select is rendered as a combobox (called menulist in WebKit). At 108 // least one item is selected, determine which one.
95 // least one item is selected, determine which one. 109 const HTMLOptionElement* initialSelected = 0;
96 const HTMLOptionElement* initial_selected = NULL; 110 for (Vector<Element*>::const_iterator i(listItems.begin()); i != listItems.end(); ++i) {
97 for (Vector<Element*>::const_iterator i(list_items.begin()); 111 if (!(*i)->hasLocalName(HTMLNames::optionTag))
98 i != list_items.end(); ++i) { 112 continue;
99 if (!(*i)->hasLocalName(HTMLNames::optionTag)) 113 const HTMLOptionElement* optionElement = static_cast<const HTMLOptionElement*>(*i);
100 continue; 114 if (optionElement->defaultSelected()) {
101 const HTMLOptionElement* option_element = 115 // The page specified the option to select.
102 static_cast<const HTMLOptionElement*>(*i); 116 initialSelected = optionElement;
103 if (option_element->defaultSelected()) { 117 break;
104 // The page specified the option to select. 118 } else if (!initialSelected)
105 initial_selected = option_element; 119 initialSelected = optionElement;
106 break; 120 }
107 } else if (!initial_selected) { 121 return initialSelected ? initialSelected->selected() : true;
108 initial_selected = option_element;
109 }
110 }
111 return initial_selected ? initial_selected->selected() : true;
112 } 122 }
113 123
114 // Returns true if the form element is in its default state, false otherwise. 124 // 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 125 // 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 126 // 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. 127 // in its default state if the checked state matches the defaultChecked state.
118 bool IsInDefaultState(HTMLFormControlElement* form_element) { 128 bool IsInDefaultState(const HTMLFormControlElement* formElement)
119 if (form_element->hasTagName(HTMLNames::inputTag)) { 129 {
120 const HTMLInputElement* input_element = 130 if (formElement->hasTagName(HTMLNames::inputTag)) {
121 static_cast<const HTMLInputElement*>(form_element); 131 const HTMLInputElement* inputElement = static_cast<const HTMLInputElement*>(formElement);
122 if (input_element->inputType() == HTMLInputElement::CHECKBOX || 132 if (inputElement->inputType() == HTMLInputElement::CHECKBOX || inputElement->inputType() == HTMLInputElement::RADIO)
123 input_element->inputType() == HTMLInputElement::RADIO) { 133 return inputElement->checked() == inputElement->defaultChecked();
124 return input_element->checked() == input_element->defaultChecked(); 134 } else if (formElement->hasTagName(HTMLNames::selectTag))
125 } 135 return IsSelectInDefaultState(static_cast<const HTMLSelectElement*>(formElement));
126 } else if (form_element->hasTagName(HTMLNames::selectTag)) { 136 return true;
127 return IsSelectInDefaultState(
128 static_cast<HTMLSelectElement*>(form_element));
129 }
130 return true;
131 } 137 }
132 138
133 // If form has only one text input element, return true. If a valid input 139 // 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 140 // 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 141 // elements is added to enc_string and the encoding used is set in
136 // encoding_name. 142 // encoding_name.
137 bool HasSuitableTextElement(HTMLFormElement* form, 143 bool HasSuitableTextElement(const HTMLFormElement* form, Vector<char>* encodedString, String* encodingName)
138 Vector<char>* enc_string, 144 {
139 std::string* encoding_name) { 145 TextEncoding encoding;
140 TextEncoding encoding; 146 GetFormEncoding(form, &encoding);
141 GetFormEncoding(form, &encoding); 147 if (!encoding.isValid()) {
142 if (!encoding.isValid()) { 148 // Need a valid encoding to encode the form elements.
143 // Need a valid encoding to encode the form elements. 149 // If the encoding isn't found webkit ends up replacing the params with
144 // If the encoding isn't found webkit ends up replacing the params with 150 // empty strings. So, we don't try to do anything here.
145 // empty strings. So, we don't try to do anything here. 151 return 0;
146 return NULL; 152 }
147 } 153 *encodingName = encoding.name();
148 *encoding_name = encoding.name(); 154
149 155 HTMLInputElement* textElement = 0;
150 HTMLInputElement* text_element = NULL; 156 for (Vector<HTMLFormControlElement*>::const_iterator i(form->formElements.begin()); i != form->formElements.end(); ++i) {
151 for (Vector<HTMLFormControlElement*>::const_iterator 157 HTMLFormControlElement* formElement = *i;
152 i(form->formElements.begin()); i != form->formElements.end(); ++i) { 158 if (formElement->disabled() || formElement->name().isNull())
153 HTMLFormControlElement* form_element = *i; 159 continue;
154 if (form_element->disabled() || form_element->name().isNull()) 160
155 continue; 161 if (!IsInDefaultState(formElement) || formElement->hasTagName(HTMLNames::textareaTag))
156 162 return 0;
157 if (!IsInDefaultState(form_element) || 163
158 form_element->hasTagName(HTMLNames::textareaTag)) 164 bool isTextElement = false;
159 return NULL; 165 if (formElement->hasTagName(HTMLNames::inputTag)) {
160 166 switch (static_cast<const HTMLInputElement*>(formElement)->inputType()) {
161 bool is_text_element = false; 167 case HTMLInputElement::TEXT:
162 if (form_element->hasTagName(HTMLNames::inputTag)) { 168 case HTMLInputElement::ISINDEX:
163 switch (static_cast<const HTMLInputElement*>(form_element)->inputType()) { 169 isTextElement = true;
164 case HTMLInputElement::TEXT: 170 break;
165 case HTMLInputElement::ISINDEX: 171 case HTMLInputElement::PASSWORD:
166 is_text_element = true; 172 // Don't store passwords! This is most likely an https anyway.
167 break; 173 // Fall through.
168 case HTMLInputElement::PASSWORD: 174 case HTMLInputElement::FILE:
169 // Don't store passwords! This is most likely an https anyway. 175 // Too big, don't try to index this.
170 // Fall through. 176 return 0;
171 case HTMLInputElement::FILE: 177 default:
172 // Too big, don't try to index this. 178 // All other input types are indexable.
173 return NULL; 179 break;
174 default: 180 }
175 // All other input types are indexable.
176 break;
177 } 181 }
178 } 182
179 183 FormDataList dataList(encoding);
180 FormDataList data_list(encoding); 184 if (!formElement->appendFormData(dataList, false))
181 if (!form_element->appendFormData(data_list, false)) 185 continue;
182 continue; 186
183 187 const Vector<FormDataList::Item>& itemList = dataList.list();
184 const Vector<FormDataList::Item>& item_list = data_list.list(); 188 if (isTextElement && !itemList.isEmpty()) {
185 if (is_text_element && !item_list.isEmpty()) { 189 if (textElement) {
186 if (text_element != NULL) { 190 // The auto-complete bar only knows how to fill in one value.
187 // The auto-complete bar only knows how to fill in one value. 191 // This form has multiple fields; don't treat it as searchable.
188 // This form has multiple fields; don't treat it as searchable. 192 return false;
189 return false; 193 }
194 textElement = static_cast<HTMLInputElement*>(formElement);
190 } 195 }
191 text_element = static_cast<HTMLInputElement*>(form_element); 196 for (Vector<FormDataList::Item>::const_iterator j(itemList.begin()); j != itemList.end(); ++j) {
192 } 197 // Handle ISINDEX / <input name=isindex> specially, but only if it's
193 for (Vector<FormDataList::Item>::const_iterator j(item_list.begin()); 198 // the first entry.
194 j != item_list.end(); ++j) { 199 if (!encodedString->isEmpty() || j->data() != "isindex") {
195 // Handle ISINDEX / <input name=isindex> specially, but only if it's 200 if (!encodedString->isEmpty())
196 // the first entry. 201 encodedString->append('&');
197 if (!enc_string->isEmpty() || j->data() != "isindex") { 202 FormDataBuilder::encodeStringAsFormData(*encodedString, j->data());
198 if (!enc_string->isEmpty()) 203 encodedString->append('=');
199 enc_string->append('&'); 204 }
200 FormDataBuilder::encodeStringAsFormData(*enc_string, j->data()); 205 ++j;
201 enc_string->append('='); 206 if (formElement == textElement)
207 encodedString->append("{searchTerms}", 13);
208 else
209 FormDataBuilder::encodeStringAsFormData(*encodedString, j->data());
202 } 210 }
203 ++j; 211 }
204 if (form_element == text_element) 212
205 enc_string->append("{searchTerms}", 13); 213 return textElement;
206 else
207 FormDataBuilder::encodeStringAsFormData(*enc_string, j->data());
208 }
209 }
210
211 return text_element != NULL;
212 } 214 }
213 215
214 } // namespace 216 } // namespace
215 217
216 SearchableFormData* SearchableFormData::Create(const WebKit::WebForm& webform) { 218 namespace WebKit {
217 RefPtr<HTMLFormElement> form = WebFormToHTMLFormElement(webform); 219
218 const Frame* frame = form->document()->frame(); 220 WebSearchableFormData::WebSearchableFormData(const WebForm& form)
219 if (frame == NULL) 221 {
220 return NULL; 222 RefPtr<HTMLFormElement> formElement = form.operator PassRefPtr<HTMLFormElement>();
221 223 const Frame* frame = formElement->document()->frame();
222 // Only consider forms that GET data and the action targets an http page. 224 if (!frame)
223 if (equalIgnoringCase(form->getAttribute(HTMLNames::methodAttr), "post") || 225 return;
224 !IsHTTPFormSubmit(form.get())) 226
225 return NULL; 227 // Only consider forms that GET data and the action targets an http page.
226 228 if (equalIgnoringCase(formElement->getAttribute(HTMLNames::methodAttr), "post") || !IsHTTPFormSubmit(formElement.get()))
227 HTMLFormControlElement* first_submit_button = GetButtonToActivate(form.get()); 229 return;
228 if (first_submit_button) { 230
229 // The form does not have an active submit button, make the first button 231 HTMLFormControlElement* firstSubmitButton = GetButtonToActivate(formElement.get());
230 // active. We need to do this, otherwise the URL will not contain the 232 if (firstSubmitButton) {
231 // name of the submit button. 233 // The form does not have an active submit button, make the first button
232 first_submit_button->setActivatedSubmit(true); 234 // active. We need to do this, otherwise the URL will not contain the
233 } 235 // name of the submit button.
234 Vector<char> enc_string; 236 firstSubmitButton->setActivatedSubmit(true);
235 std::string encoding; 237 }
236 bool has_element = HasSuitableTextElement(form.get(), &enc_string, &encoding); 238 Vector<char> encodedString;
237 if (first_submit_button) 239 String encoding;
238 first_submit_button->setActivatedSubmit(false); 240 bool hasElement = HasSuitableTextElement(formElement.get(), &encodedString, &encoding);
239 if (!has_element) { 241 if (firstSubmitButton)
240 // Not a searchable form. 242 firstSubmitButton->setActivatedSubmit(false);
241 return NULL; 243 if (!hasElement) {
242 } 244 // Not a searchable form.
243 245 return;
244 // It's a valid form. 246 }
245 // Generate the URL and create a new SearchableFormData. 247
246 RefPtr<FormData> form_data = FormData::create(enc_string); 248 String action(formElement->action());
247 String action(form->action()); 249 KURL url(frame->loader()->completeURL(action.isNull() ? "" : action));
248 KURL url = frame->loader()->completeURL(action.isNull() ? "" : action); 250 RefPtr<FormData> formData = FormData::create(encodedString);
249 url.setQuery(form_data->flattenToString()); 251 url.setQuery(formData->flattenToString());
250 GURL gurl(KURLToGURL(url)); 252 m_url = url;
251 return new SearchableFormData(gurl, encoding); 253 m_encoding = encoding;
252 } 254 }
253 255
254 } // namespace webkit_glue 256 } // namespace WebKit
OLDNEW
« no previous file with comments | « webkit/api/public/WebSearchableFormData.h ('k') | webkit/glue/searchable_form_data.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698