| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "webkit/glue/dom_operations.h" | 5 #include "webkit/glue/dom_operations.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 | 8 |
| 9 #include "base/compiler_specific.h" | 9 #include "base/compiler_specific.h" |
| 10 #include "base/string_number_conversions.h" | 10 #include "base/string_number_conversions.h" |
| 11 #include "base/string_split.h" | 11 #include "base/string_split.h" |
| 12 #include "base/string_util.h" |
| 12 #include "third_party/WebKit/WebKit/chromium/public/WebAnimationController.h" | 13 #include "third_party/WebKit/WebKit/chromium/public/WebAnimationController.h" |
| 13 #include "third_party/WebKit/WebKit/chromium/public/WebDocument.h" | 14 #include "third_party/WebKit/WebKit/chromium/public/WebDocument.h" |
| 14 #include "third_party/WebKit/WebKit/chromium/public/WebElement.h" | 15 #include "third_party/WebKit/WebKit/chromium/public/WebElement.h" |
| 15 #include "third_party/WebKit/WebKit/chromium/public/WebFormElement.h" | |
| 16 #include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" | 16 #include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" |
| 17 #include "third_party/WebKit/WebKit/chromium/public/WebInputElement.h" | 17 #include "third_party/WebKit/WebKit/chromium/public/WebInputElement.h" |
| 18 #include "third_party/WebKit/WebKit/chromium/public/WebNode.h" | 18 #include "third_party/WebKit/WebKit/chromium/public/WebNode.h" |
| 19 #include "third_party/WebKit/WebKit/chromium/public/WebNodeCollection.h" | 19 #include "third_party/WebKit/WebKit/chromium/public/WebNodeCollection.h" |
| 20 #include "third_party/WebKit/WebKit/chromium/public/WebNodeList.h" | 20 #include "third_party/WebKit/WebKit/chromium/public/WebNodeList.h" |
| 21 #include "third_party/WebKit/WebKit/chromium/public/WebString.h" |
| 21 #include "third_party/WebKit/WebKit/chromium/public/WebVector.h" | 22 #include "third_party/WebKit/WebKit/chromium/public/WebVector.h" |
| 22 #include "third_party/WebKit/WebKit/chromium/public/WebView.h" | 23 #include "third_party/WebKit/WebKit/chromium/public/WebView.h" |
| 23 #include "webkit/glue/form_data.h" | |
| 24 #include "webkit/glue/password_form_dom_manager.h" | |
| 25 #include "webkit/glue/webpasswordautocompletelistener_impl.h" | |
| 26 | 24 |
| 27 using WebKit::WebAnimationController; | 25 using WebKit::WebAnimationController; |
| 28 using WebKit::WebDocument; | 26 using WebKit::WebDocument; |
| 29 using WebKit::WebElement; | 27 using WebKit::WebElement; |
| 30 using WebKit::WebFormElement; | |
| 31 using WebKit::WebFrame; | 28 using WebKit::WebFrame; |
| 32 using WebKit::WebInputElement; | 29 using WebKit::WebInputElement; |
| 33 using WebKit::WebNode; | 30 using WebKit::WebNode; |
| 34 using WebKit::WebNodeCollection; | 31 using WebKit::WebNodeCollection; |
| 35 using WebKit::WebNodeList; | 32 using WebKit::WebNodeList; |
| 33 using WebKit::WebString; |
| 36 using WebKit::WebVector; | 34 using WebKit::WebVector; |
| 37 using WebKit::WebView; | 35 using WebKit::WebView; |
| 38 | 36 |
| 39 namespace { | 37 namespace { |
| 40 | 38 |
| 41 // Structure for storage the unique set of all savable resource links for | 39 // Structure for storage the unique set of all savable resource links for |
| 42 // making sure that no duplicated resource link in final result. The consumer | 40 // making sure that no duplicated resource link in final result. The consumer |
| 43 // of the SavableResourcesUniqueCheck is responsible for keeping these pointers | 41 // of the SavableResourcesUniqueCheck is responsible for keeping these pointers |
| 44 // valid for the lifetime of the SavableResourcesUniqueCheck instance. | 42 // valid for the lifetime of the SavableResourcesUniqueCheck instance. |
| 45 struct SavableResourcesUniqueCheck { | 43 struct SavableResourcesUniqueCheck { |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 146 current_doc, | 144 current_doc, |
| 147 unique_check, | 145 unique_check, |
| 148 result); | 146 result); |
| 149 } | 147 } |
| 150 } | 148 } |
| 151 | 149 |
| 152 } // namespace | 150 } // namespace |
| 153 | 151 |
| 154 namespace webkit_glue { | 152 namespace webkit_glue { |
| 155 | 153 |
| 156 // Map element name to a list of pointers to corresponding elements to simplify | |
| 157 // form filling. | |
| 158 typedef std::map<string16, WebKit::WebInputElement> | |
| 159 FormInputElementMap; | |
| 160 | |
| 161 // Utility struct for form lookup and autofill. When we parse the DOM to lookup | |
| 162 // a form, in addition to action and origin URL's we have to compare all | |
| 163 // necessary form elements. To avoid having to look these up again when we want | |
| 164 // to fill the form, the FindFormElements function stores the pointers | |
| 165 // in a FormElements* result, referenced to ensure they are safe to use. | |
| 166 struct FormElements { | |
| 167 WebFormElement form_element; | |
| 168 FormInputElementMap input_elements; | |
| 169 FormElements() { | |
| 170 } | |
| 171 }; | |
| 172 | |
| 173 typedef std::vector<FormElements*> FormElementsList; | |
| 174 | |
| 175 // Internal implementation of FillForm API. | |
| 176 static bool FillFormImpl(FormElements* fe, const FormData& data) { | |
| 177 if (!fe->form_element.autoComplete()) | |
| 178 return false; | |
| 179 | |
| 180 std::map<string16, string16> data_map; | |
| 181 for (size_t i = 0; i < data.fields.size(); i++) | |
| 182 data_map[data.fields[i].name()] = data.fields[i].value(); | |
| 183 | |
| 184 for (FormInputElementMap::iterator it = fe->input_elements.begin(); | |
| 185 it != fe->input_elements.end(); ++it) { | |
| 186 WebKit::WebInputElement& element = it->second; | |
| 187 if (!element.value().isEmpty()) // Don't overwrite pre-filled values. | |
| 188 continue; | |
| 189 if (element.isPasswordField() && | |
| 190 (!element.isEnabledFormControl() || element.hasAttribute("readonly"))) { | |
| 191 continue; // Don't fill uneditable password fields. | |
| 192 } | |
| 193 if (!element.isValidValue(data_map[it->first])) | |
| 194 continue; | |
| 195 | |
| 196 element.setValue(data_map[it->first]); | |
| 197 element.setAutofilled(true); | |
| 198 element.dispatchFormControlChangeEvent(); | |
| 199 } | |
| 200 | |
| 201 return false; | |
| 202 } | |
| 203 | |
| 204 // Helper to search the given form element for the specified input elements | |
| 205 // in |data|, and add results to |result|. | |
| 206 static bool FindFormInputElements(WebFormElement* fe, | |
| 207 const FormData& data, | |
| 208 FormElements* result) { | |
| 209 // Loop through the list of elements we need to find on the form in | |
| 210 // order to autofill it. If we don't find any one of them, abort | |
| 211 // processing this form; it can't be the right one. | |
| 212 for (size_t j = 0; j < data.fields.size(); j++) { | |
| 213 WebVector<WebNode> temp_elements; | |
| 214 fe->getNamedElements(data.fields[j].name(), temp_elements); | |
| 215 if (temp_elements.isEmpty()) { | |
| 216 // We didn't find a required element. This is not the right form. | |
| 217 // Make sure no input elements from a partially matched form | |
| 218 // in this iteration remain in the result set. | |
| 219 // Note: clear will remove a reference from each InputElement. | |
| 220 result->input_elements.clear(); | |
| 221 return false; | |
| 222 } | |
| 223 // This element matched, add it to our temporary result. It's possible | |
| 224 // there are multiple matches, but for purposes of identifying the form | |
| 225 // one suffices and if some function needs to deal with multiple | |
| 226 // matching elements it can get at them through the FormElement*. | |
| 227 // Note: This assignment adds a reference to the InputElement. | |
| 228 result->input_elements[data.fields[j].name()] = | |
| 229 temp_elements[0].to<WebInputElement>(); | |
| 230 } | |
| 231 return true; | |
| 232 } | |
| 233 | |
| 234 // Helper to locate form elements identified by |data|. | |
| 235 static void FindFormElements(WebView* view, | |
| 236 const FormData& data, | |
| 237 FormElementsList* results) { | |
| 238 DCHECK(view); | |
| 239 DCHECK(results); | |
| 240 WebFrame* main_frame = view->mainFrame(); | |
| 241 if (!main_frame) | |
| 242 return; | |
| 243 | |
| 244 GURL::Replacements rep; | |
| 245 rep.ClearQuery(); | |
| 246 rep.ClearRef(); | |
| 247 | |
| 248 // Loop through each frame. | |
| 249 for (WebFrame* f = main_frame; f; f = f->traverseNext(false)) { | |
| 250 WebDocument doc = f->document(); | |
| 251 if (!doc.isHTMLDocument()) | |
| 252 continue; | |
| 253 | |
| 254 GURL full_origin(f->url()); | |
| 255 if (data.origin != full_origin.ReplaceComponents(rep)) | |
| 256 continue; | |
| 257 | |
| 258 WebVector<WebFormElement> forms; | |
| 259 f->forms(forms); | |
| 260 | |
| 261 for (size_t i = 0; i < forms.size(); ++i) { | |
| 262 WebFormElement fe = forms[i]; | |
| 263 // Action URL must match. | |
| 264 GURL full_action(f->document().completeURL(fe.action())); | |
| 265 if (data.action != full_action.ReplaceComponents(rep)) | |
| 266 continue; | |
| 267 | |
| 268 scoped_ptr<FormElements> curr_elements(new FormElements); | |
| 269 if (!FindFormInputElements(&fe, data, curr_elements.get())) | |
| 270 continue; | |
| 271 | |
| 272 // We found the right element. | |
| 273 // Note: this assignment adds a reference to |fe|. | |
| 274 curr_elements->form_element = fe; | |
| 275 results->push_back(curr_elements.release()); | |
| 276 } | |
| 277 } | |
| 278 } | |
| 279 | |
| 280 void FillPasswordForm(WebView* view, | |
| 281 const PasswordFormFillData& data) { | |
| 282 FormElementsList forms; | |
| 283 // We own the FormElements* in forms. | |
| 284 FindFormElements(view, data.basic_data, &forms); | |
| 285 FormElementsList::iterator iter; | |
| 286 for (iter = forms.begin(); iter != forms.end(); ++iter) { | |
| 287 scoped_ptr<FormElements> form_elements(*iter); | |
| 288 | |
| 289 // If wait_for_username is true, we don't want to initially fill the form | |
| 290 // until the user types in a valid username. | |
| 291 if (!data.wait_for_username) | |
| 292 FillFormImpl(form_elements.get(), data.basic_data); | |
| 293 | |
| 294 // Attach autocomplete listener to enable selecting alternate logins. | |
| 295 // First, get pointers to username element. | |
| 296 WebInputElement username_element = | |
| 297 form_elements->input_elements[data.basic_data.fields[0].name()]; | |
| 298 | |
| 299 // Get pointer to password element. (We currently only support single | |
| 300 // password forms). | |
| 301 WebInputElement password_element = | |
| 302 form_elements->input_elements[data.basic_data.fields[1].name()]; | |
| 303 | |
| 304 username_element.document().frame()->registerPasswordListener( | |
| 305 username_element, | |
| 306 new WebPasswordAutocompleteListenerImpl( | |
| 307 new WebInputElementDelegate(username_element), | |
| 308 new WebInputElementDelegate(password_element), | |
| 309 data)); | |
| 310 } | |
| 311 } | |
| 312 | |
| 313 WebString GetSubResourceLinkFromElement(const WebElement& element) { | 154 WebString GetSubResourceLinkFromElement(const WebElement& element) { |
| 314 const char* attribute_name = NULL; | 155 const char* attribute_name = NULL; |
| 315 if (element.hasTagName("img") || | 156 if (element.hasTagName("img") || |
| 316 element.hasTagName("script")) { | 157 element.hasTagName("script")) { |
| 317 attribute_name = "src"; | 158 attribute_name = "src"; |
| 318 } else if (element.hasTagName("input")) { | 159 } else if (element.hasTagName("input")) { |
| 319 const WebInputElement input = element.toConst<WebInputElement>(); | 160 const WebInputElement input = element.toConst<WebInputElement>(); |
| 320 if (input.isImageButton()) { | 161 if (input.isImageButton()) { |
| 321 attribute_name = "src"; | 162 attribute_name = "src"; |
| 322 } | 163 } |
| (...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 620 if (!element.hasTagName("meta")) | 461 if (!element.hasTagName("meta")) |
| 621 continue; | 462 continue; |
| 622 WebString value = element.getAttribute(attribute_name); | 463 WebString value = element.getAttribute(attribute_name); |
| 623 if (value.isNull() || value != attribute_value) | 464 if (value.isNull() || value != attribute_value) |
| 624 continue; | 465 continue; |
| 625 meta_elements->push_back(element); | 466 meta_elements->push_back(element); |
| 626 } | 467 } |
| 627 } | 468 } |
| 628 | 469 |
| 629 } // webkit_glue | 470 } // webkit_glue |
| OLD | NEW |