Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 "chrome/test/chromedriver/element_util.h" | 5 #include "chrome/test/chromedriver/element_util.h" |
| 6 | 6 |
| 7 #include "base/string_util.h" | 7 #include "base/string_util.h" |
| 8 #include "base/stringprintf.h" | |
| 9 #include "base/strings/string_number_conversions.cc" | |
| 8 #include "base/threading/platform_thread.h" | 10 #include "base/threading/platform_thread.h" |
| 9 #include "base/time.h" | 11 #include "base/time.h" |
| 10 #include "base/values.h" | 12 #include "base/values.h" |
| 11 #include "chrome/test/chromedriver/basic_types.h" | 13 #include "chrome/test/chromedriver/basic_types.h" |
| 12 #include "chrome/test/chromedriver/js.h" | 14 #include "chrome/test/chromedriver/js.h" |
| 13 #include "chrome/test/chromedriver/session.h" | 15 #include "chrome/test/chromedriver/session.h" |
| 14 #include "chrome/test/chromedriver/status.h" | 16 #include "chrome/test/chromedriver/status.h" |
| 15 #include "chrome/test/chromedriver/web_view.h" | 17 #include "chrome/test/chromedriver/web_view.h" |
| 16 #include "third_party/webdriver/atoms.h" | 18 #include "third_party/webdriver/atoms.h" |
| 17 | 19 |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 79 base::Value* CreateValueFrom(const WebRect* rect) { | 81 base::Value* CreateValueFrom(const WebRect* rect) { |
| 80 base::DictionaryValue* dict = new base::DictionaryValue(); | 82 base::DictionaryValue* dict = new base::DictionaryValue(); |
| 81 dict->SetInteger("left", rect->origin.x); | 83 dict->SetInteger("left", rect->origin.x); |
| 82 dict->SetInteger("top", rect->origin.y); | 84 dict->SetInteger("top", rect->origin.y); |
| 83 dict->SetInteger("width", rect->size.width); | 85 dict->SetInteger("width", rect->size.width); |
| 84 dict->SetInteger("height", rect->size.height); | 86 dict->SetInteger("height", rect->size.height); |
| 85 return dict; | 87 return dict; |
| 86 } | 88 } |
| 87 | 89 |
| 88 Status CallAtomsJs( | 90 Status CallAtomsJs( |
| 89 Session* session, | 91 const std::string& frame, |
| 90 WebView* web_view, | 92 WebView* web_view, |
| 91 const char* const* atom_function, | 93 const char* const* atom_function, |
| 92 const base::ListValue& args, | 94 const base::ListValue& args, |
| 93 scoped_ptr<base::Value>* result) { | 95 scoped_ptr<base::Value>* result) { |
| 94 return web_view->CallFunction( | 96 return web_view->CallFunction( |
| 95 session->frame, webdriver::atoms::asString(atom_function), | 97 frame, webdriver::atoms::asString(atom_function), args, result); |
| 96 args, result); | 98 } |
| 99 | |
| 100 Status VerifyElementClickable( | |
| 101 const std::string& frame, | |
| 102 WebView* web_view, | |
| 103 const std::string& element_id, | |
| 104 WebPoint* location) { | |
|
kkania
2013/03/12 18:34:25
make this const WebPoint&; also, change all the Cr
chrisgao (Use stgao instead)
2013/03/12 23:17:41
Done.
| |
| 105 base::ListValue args; | |
| 106 args.Append(CreateElement(element_id)); | |
| 107 args.Append(CreateValueFrom(location)); | |
| 108 scoped_ptr<base::Value> result; | |
| 109 Status status = CallAtomsJs( | |
| 110 frame, web_view, webdriver::atoms::IS_ELEMENT_CLICKABLE, | |
| 111 args, &result); | |
| 112 if (status.IsError()) | |
| 113 return status; | |
| 114 base::DictionaryValue* dict; | |
| 115 bool is_clickable; | |
| 116 if (!result->GetAsDictionary(&dict) || | |
| 117 !dict->GetBoolean("clickable", &is_clickable)) | |
| 118 return Status(kUnknownError, "fail to parse value of IS_ELEMENT_CLICKABLE"); | |
| 119 | |
| 120 if (!is_clickable) { | |
| 121 std::string message; | |
| 122 if (!dict->GetString("message", &message)) | |
| 123 message = "element is not clickable"; | |
| 124 return Status(kUnknownError, message); | |
| 125 } | |
| 126 return Status(kOk); | |
| 127 } | |
| 128 | |
| 129 Status ScrollElementRegionIntoViewHelper( | |
| 130 const std::string& frame, | |
| 131 WebView* web_view, | |
| 132 const std::string& element_id, | |
| 133 const WebRect& region, | |
| 134 bool center, | |
| 135 bool verify_clickable, | |
| 136 WebPoint* location) { | |
| 137 base::ListValue args; | |
| 138 args.Append(CreateElement(element_id)); | |
| 139 args.AppendBoolean(center); | |
| 140 args.Append(CreateValueFrom(®ion)); | |
| 141 scoped_ptr<base::Value> result; | |
| 142 Status status = web_view->CallFunction( | |
| 143 frame, webdriver::atoms::asString(webdriver::atoms::GET_LOCATION_IN_VIEW), | |
| 144 args, &result); | |
| 145 if (status.IsError()) | |
| 146 return status; | |
| 147 if (!ParseFromValue(result.get(), location)) | |
|
kkania
2013/03/12 18:34:25
usually we've been trying to keep to the conventio
chrisgao (Use stgao instead)
2013/03/12 23:17:41
Done.
| |
| 148 return Status(kUnknownError, "fail to parse value of GET_LOCATION_IN_VIEW"); | |
| 149 if (verify_clickable) { | |
| 150 WebPoint middle = *location; | |
| 151 middle.Offset(region.width() / 2, region.height() / 2); | |
| 152 return VerifyElementClickable(frame, web_view, element_id, &middle); | |
| 153 } | |
| 154 return Status(kOk); | |
| 155 } | |
| 156 | |
| 157 Status GetElementEffectiveStyle( | |
| 158 const std::string& frame, | |
| 159 WebView* web_view, | |
| 160 const std::string& element_id, | |
| 161 const std::string& property, | |
| 162 std::string* value) { | |
| 163 base::ListValue args; | |
| 164 args.Append(CreateElement(element_id)); | |
| 165 args.AppendString(property); | |
| 166 scoped_ptr<base::Value> result; | |
| 167 Status status = web_view->CallFunction( | |
| 168 frame, webdriver::atoms::asString(webdriver::atoms::GET_EFFECTIVE_STYLE), | |
| 169 args, &result); | |
| 170 if (status.IsError()) | |
| 171 return status; | |
| 172 if (!result->GetAsString(value)) | |
| 173 return Status(kUnknownError, "fail to parse value of GET_EFFECTIVE_STYLE"); | |
| 174 return Status(kOk); | |
| 175 } | |
| 176 | |
| 177 Status GetElementBorder( | |
| 178 const std::string& frame, | |
| 179 WebView* web_view, | |
| 180 const std::string& element_id, | |
| 181 int* border_left, | |
| 182 int* border_top) { | |
| 183 std::string border_left_str; | |
| 184 Status status = GetElementEffectiveStyle( | |
| 185 frame, web_view, element_id, "border-left-width", &border_left_str); | |
| 186 if (status.IsError()) | |
| 187 return status; | |
| 188 std::string border_top_str; | |
| 189 status = GetElementEffectiveStyle( | |
| 190 frame, web_view, element_id, "border-top-width", &border_top_str); | |
| 191 if (status.IsError()) | |
| 192 return status; | |
| 193 int border_left_tmp = -1; | |
| 194 int border_top_tmp = -1; | |
| 195 base::StringToInt(border_left_str, &border_left_tmp); | |
| 196 base::StringToInt(border_top_str, &border_top_tmp); | |
| 197 if (border_left_tmp == -1 || border_top_tmp == -1) | |
| 198 return Status(kUnknownError, "fail to get border width of element"); | |
| 199 *border_left = border_left_tmp; | |
| 200 *border_top = border_top_tmp; | |
| 201 return Status(kOk); | |
| 97 } | 202 } |
| 98 | 203 |
| 99 } // namespace | 204 } // namespace |
| 100 | 205 |
| 101 base::DictionaryValue* CreateElement(const std::string& element_id) { | 206 base::DictionaryValue* CreateElement(const std::string& element_id) { |
| 102 base::DictionaryValue* element = new base::DictionaryValue(); | 207 base::DictionaryValue* element = new base::DictionaryValue(); |
| 103 element->SetString(kElementKey, element_id); | 208 element->SetString(kElementKey, element_id); |
| 104 return element; | 209 return element; |
| 105 } | 210 } |
| 106 | 211 |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 173 Status GetElementAttribute( | 278 Status GetElementAttribute( |
| 174 Session* session, | 279 Session* session, |
| 175 WebView* web_view, | 280 WebView* web_view, |
| 176 const std::string& element_id, | 281 const std::string& element_id, |
| 177 const std::string& attribute_name, | 282 const std::string& attribute_name, |
| 178 scoped_ptr<base::Value>* value) { | 283 scoped_ptr<base::Value>* value) { |
| 179 base::ListValue args; | 284 base::ListValue args; |
| 180 args.Append(CreateElement(element_id)); | 285 args.Append(CreateElement(element_id)); |
| 181 args.AppendString(attribute_name); | 286 args.AppendString(attribute_name); |
| 182 return CallAtomsJs( | 287 return CallAtomsJs( |
| 183 session, web_view, webdriver::atoms::GET_ATTRIBUTE, args, value); | 288 session->frame, web_view, webdriver::atoms::GET_ATTRIBUTE, args, value); |
| 184 } | 289 } |
| 185 | 290 |
| 186 Status IsElementAttributeEqualToIgnoreCase( | 291 Status IsElementAttributeEqualToIgnoreCase( |
| 187 Session* session, | 292 Session* session, |
| 188 WebView* web_view, | 293 WebView* web_view, |
| 189 const std::string& element_id, | 294 const std::string& element_id, |
| 190 const std::string& attribute_name, | 295 const std::string& attribute_name, |
| 191 const std::string& attribute_value, | 296 const std::string& attribute_value, |
| 192 bool* is_equal) { | 297 bool* is_equal) { |
| 193 scoped_ptr<base::Value> result; | 298 scoped_ptr<base::Value> result; |
| 194 Status status = GetElementAttribute( | 299 Status status = GetElementAttribute( |
| 195 session, web_view, element_id, attribute_name, &result); | 300 session, web_view, element_id, attribute_name, &result); |
| 196 if (status.IsError()) | 301 if (status.IsError()) |
| 197 return status; | 302 return status; |
| 198 std::string actual_value; | 303 std::string actual_value; |
| 199 if (result->GetAsString(&actual_value)) | 304 if (result->GetAsString(&actual_value)) |
| 200 *is_equal = LowerCaseEqualsASCII(actual_value, attribute_value.c_str()); | 305 *is_equal = LowerCaseEqualsASCII(actual_value, attribute_value.c_str()); |
| 201 else | 306 else |
| 202 *is_equal = false; | 307 *is_equal = false; |
| 203 return status; | 308 return status; |
| 204 } | 309 } |
| 205 | 310 |
| 206 Status GetElementClickableLocation( | 311 Status GetElementClickableLocation( |
| 207 Session* session, | 312 Session* session, |
| 208 WebView* web_view, | 313 WebView* web_view, |
| 209 const std::string& element_id, | 314 const std::string& element_id, |
| 210 WebPoint* location, | 315 WebPoint* location) { |
| 211 bool* is_clickable) { | |
| 212 bool is_displayed = false; | 316 bool is_displayed = false; |
| 213 Status status = IsElementDisplayed( | 317 Status status = IsElementDisplayed( |
| 214 session, web_view, element_id, true, &is_displayed); | 318 session, web_view, element_id, true, &is_displayed); |
| 215 if (status.IsError()) | 319 if (status.IsError()) |
| 216 return status; | 320 return status; |
| 217 if (!is_displayed) | 321 if (!is_displayed) |
| 218 return Status(kElementNotVisible); | 322 return Status(kElementNotVisible); |
| 219 | 323 |
| 220 WebRect rect; | 324 WebRect rect; |
| 221 status = GetElementRegion(session, web_view, element_id, &rect); | 325 status = GetElementRegion(session, web_view, element_id, &rect); |
| 222 if (status.IsError()) | 326 if (status.IsError()) |
| 223 return status; | 327 return status; |
| 224 | 328 |
| 225 status = ScrollElementRegionIntoView( | 329 status = ScrollElementRegionIntoView( |
| 226 session, web_view, element_id, rect, true, location); | 330 session, web_view, element_id, rect, |
| 331 true /* center */, true /* verify_clickable */, location); | |
| 227 if (status.IsError()) | 332 if (status.IsError()) |
| 228 return status; | 333 return status; |
| 229 location->offset(rect.width() / 2, rect.height() / 2); | 334 location->Offset(rect.width() / 2, rect.height() / 2); |
| 230 if (is_clickable) { | |
| 231 return IsElementClickable( | |
| 232 session, web_view, element_id, location, is_clickable); | |
| 233 } | |
| 234 return Status(kOk); | 335 return Status(kOk); |
| 235 } | 336 } |
| 236 | 337 |
| 237 Status GetElementRegion( | 338 Status GetElementRegion( |
| 238 Session* session, | 339 Session* session, |
| 239 WebView* web_view, | 340 WebView* web_view, |
| 240 const std::string& element_id, | 341 const std::string& element_id, |
| 241 WebRect* rect) { | 342 WebRect* rect) { |
| 242 base::ListValue args; | 343 base::ListValue args; |
| 243 args.Append(CreateElement(element_id)); | 344 args.Append(CreateElement(element_id)); |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 273 | 374 |
| 274 Status GetElementSize( | 375 Status GetElementSize( |
| 275 Session* session, | 376 Session* session, |
| 276 WebView* web_view, | 377 WebView* web_view, |
| 277 const std::string& element_id, | 378 const std::string& element_id, |
| 278 WebSize* size) { | 379 WebSize* size) { |
| 279 base::ListValue args; | 380 base::ListValue args; |
| 280 args.Append(CreateElement(element_id)); | 381 args.Append(CreateElement(element_id)); |
| 281 scoped_ptr<base::Value> result; | 382 scoped_ptr<base::Value> result; |
| 282 Status status = CallAtomsJs( | 383 Status status = CallAtomsJs( |
| 283 session, web_view, webdriver::atoms::GET_SIZE, args, &result); | 384 session->frame, web_view, webdriver::atoms::GET_SIZE, args, &result); |
| 284 if (status.IsError()) | 385 if (status.IsError()) |
| 285 return status; | 386 return status; |
| 286 if (!ParseFromValue(result.get(), size)) | 387 if (!ParseFromValue(result.get(), size)) |
| 287 return Status(kUnknownError, "fail to parse value of GET_SIZE"); | 388 return Status(kUnknownError, "fail to parse value of GET_SIZE"); |
| 288 return Status(kOk); | 389 return Status(kOk); |
| 289 } | 390 } |
| 290 | 391 |
| 291 Status IsElementClickable( | |
| 292 Session* session, | |
| 293 WebView* web_view, | |
| 294 const std::string& element_id, | |
| 295 WebPoint* location, | |
| 296 bool* is_clickable) { | |
| 297 base::ListValue args; | |
| 298 args.Append(CreateElement(element_id)); | |
| 299 args.Append(CreateValueFrom(location)); | |
| 300 scoped_ptr<base::Value> result; | |
| 301 Status status = CallAtomsJs( | |
| 302 session, web_view, webdriver::atoms::IS_ELEMENT_CLICKABLE, args, &result); | |
| 303 if (status.IsError()) | |
| 304 return status; | |
| 305 base::DictionaryValue* dict; | |
| 306 if (!result->GetAsDictionary(&dict) || | |
| 307 !dict->GetBoolean("clickable", is_clickable)) | |
| 308 return Status(kUnknownError, "fail to parse value of IS_ELEMENT_CLICKABLE"); | |
| 309 | |
| 310 if (!*is_clickable) { | |
| 311 std::string message; | |
| 312 if (!dict->GetString("message", &message)) | |
| 313 message = "element is not clickable"; | |
| 314 return Status(kOk, message); | |
| 315 } | |
| 316 return Status(kOk); | |
| 317 } | |
| 318 | |
| 319 Status IsElementDisplayed( | 392 Status IsElementDisplayed( |
| 320 Session* session, | 393 Session* session, |
| 321 WebView* web_view, | 394 WebView* web_view, |
| 322 const std::string& element_id, | 395 const std::string& element_id, |
| 323 bool ignore_opacity, | 396 bool ignore_opacity, |
| 324 bool* is_displayed) { | 397 bool* is_displayed) { |
| 325 base::ListValue args; | 398 base::ListValue args; |
| 326 args.Append(CreateElement(element_id)); | 399 args.Append(CreateElement(element_id)); |
| 327 args.AppendBoolean(ignore_opacity); | 400 args.AppendBoolean(ignore_opacity); |
| 328 scoped_ptr<base::Value> result; | 401 scoped_ptr<base::Value> result; |
| 329 Status status = CallAtomsJs( | 402 Status status = CallAtomsJs( |
| 330 session, web_view, webdriver::atoms::IS_DISPLAYED, args, &result); | 403 session->frame, web_view, webdriver::atoms::IS_DISPLAYED, args, &result); |
| 331 if (status.IsError()) | 404 if (status.IsError()) |
| 332 return status; | 405 return status; |
| 333 if (!result->GetAsBoolean(is_displayed)) | 406 if (!result->GetAsBoolean(is_displayed)) |
| 334 return Status(kUnknownError, "IS_DISPLAYED should return a boolean value"); | 407 return Status(kUnknownError, "IS_DISPLAYED should return a boolean value"); |
| 335 return Status(kOk); | 408 return Status(kOk); |
| 336 } | 409 } |
| 337 | 410 |
| 338 Status IsElementEnabled( | 411 Status IsElementEnabled( |
| 339 Session* session, | 412 Session* session, |
| 340 WebView* web_view, | 413 WebView* web_view, |
| 341 const std::string& element_id, | 414 const std::string& element_id, |
| 342 bool* is_enabled) { | 415 bool* is_enabled) { |
| 343 base::ListValue args; | 416 base::ListValue args; |
| 344 args.Append(CreateElement(element_id)); | 417 args.Append(CreateElement(element_id)); |
| 345 scoped_ptr<base::Value> result; | 418 scoped_ptr<base::Value> result; |
| 346 Status status = CallAtomsJs( | 419 Status status = CallAtomsJs( |
| 347 session, web_view, webdriver::atoms::IS_ENABLED, args, &result); | 420 session->frame, web_view, webdriver::atoms::IS_ENABLED, args, &result); |
| 348 if (status.IsError()) | 421 if (status.IsError()) |
| 349 return status; | 422 return status; |
| 350 if (!result->GetAsBoolean(is_enabled)) | 423 if (!result->GetAsBoolean(is_enabled)) |
| 351 return Status(kUnknownError, "IS_ENABLED should return a boolean value"); | 424 return Status(kUnknownError, "IS_ENABLED should return a boolean value"); |
| 352 return Status(kOk); | 425 return Status(kOk); |
| 353 } | 426 } |
| 354 | 427 |
| 355 Status IsOptionElementSelected( | 428 Status IsOptionElementSelected( |
| 356 Session* session, | 429 Session* session, |
| 357 WebView* web_view, | 430 WebView* web_view, |
| 358 const std::string& element_id, | 431 const std::string& element_id, |
| 359 bool* is_selected) { | 432 bool* is_selected) { |
| 360 base::ListValue args; | 433 base::ListValue args; |
| 361 args.Append(CreateElement(element_id)); | 434 args.Append(CreateElement(element_id)); |
| 362 scoped_ptr<base::Value> result; | 435 scoped_ptr<base::Value> result; |
| 363 Status status = CallAtomsJs( | 436 Status status = CallAtomsJs( |
| 364 session, web_view, webdriver::atoms::IS_SELECTED, args, &result); | 437 session->frame, web_view, webdriver::atoms::IS_SELECTED, args, &result); |
| 365 if (status.IsError()) | 438 if (status.IsError()) |
| 366 return status; | 439 return status; |
| 367 if (!result->GetAsBoolean(is_selected)) | 440 if (!result->GetAsBoolean(is_selected)) |
| 368 return Status(kUnknownError, "IS_SELECTED should return a boolean value"); | 441 return Status(kUnknownError, "IS_SELECTED should return a boolean value"); |
| 369 return Status(kOk); | 442 return Status(kOk); |
| 370 } | 443 } |
| 371 | 444 |
| 372 Status IsOptionElementTogglable( | 445 Status IsOptionElementTogglable( |
| 373 Session* session, | 446 Session* session, |
| 374 WebView* web_view, | 447 WebView* web_view, |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 390 Session* session, | 463 Session* session, |
| 391 WebView* web_view, | 464 WebView* web_view, |
| 392 const std::string& element_id, | 465 const std::string& element_id, |
| 393 bool selected) { | 466 bool selected) { |
| 394 // TODO(171034): need to fix throwing error if an alert is triggered. | 467 // TODO(171034): need to fix throwing error if an alert is triggered. |
| 395 base::ListValue args; | 468 base::ListValue args; |
| 396 args.Append(CreateElement(element_id)); | 469 args.Append(CreateElement(element_id)); |
| 397 args.AppendBoolean(selected); | 470 args.AppendBoolean(selected); |
| 398 scoped_ptr<base::Value> result; | 471 scoped_ptr<base::Value> result; |
| 399 return CallAtomsJs( | 472 return CallAtomsJs( |
| 400 session, web_view, webdriver::atoms::CLICK, args, &result); | 473 session->frame, web_view, webdriver::atoms::CLICK, args, &result); |
| 401 } | 474 } |
| 402 | 475 |
| 403 Status ToggleOptionElement( | 476 Status ToggleOptionElement( |
| 404 Session* session, | 477 Session* session, |
| 405 WebView* web_view, | 478 WebView* web_view, |
| 406 const std::string& element_id) { | 479 const std::string& element_id) { |
| 407 bool is_selected; | 480 bool is_selected; |
| 408 Status status = IsOptionElementSelected( | 481 Status status = IsOptionElementSelected( |
| 409 session, web_view, element_id, &is_selected); | 482 session, web_view, element_id, &is_selected); |
| 410 if (status.IsError()) | 483 if (status.IsError()) |
| 411 return status; | 484 return status; |
| 412 return SetOptionElementSelected(session, web_view, element_id, !is_selected); | 485 return SetOptionElementSelected(session, web_view, element_id, !is_selected); |
| 413 } | 486 } |
| 414 | 487 |
| 415 Status ScrollElementIntoView( | 488 Status ScrollElementIntoView( |
| 416 Session* session, | 489 Session* session, |
| 417 WebView* web_view, | 490 WebView* web_view, |
| 418 const std::string& id, | 491 const std::string& id, |
| 419 WebPoint* location) { | 492 WebPoint* location) { |
| 420 WebSize size; | 493 WebSize size; |
| 421 Status status = GetElementSize(session, web_view, id, &size); | 494 Status status = GetElementSize(session, web_view, id, &size); |
| 422 if (status.IsError()) | 495 if (status.IsError()) |
| 423 return status; | 496 return status; |
| 424 return ScrollElementRegionIntoView( | 497 return ScrollElementRegionIntoView( |
| 425 session, web_view, id, WebRect(WebPoint(0, 0), size), false, location); | 498 session, web_view, id, WebRect(WebPoint(0, 0), size), |
| 499 false /* center */, false /* verify_clickable */, location); | |
| 426 } | 500 } |
| 427 | 501 |
| 428 Status ScrollElementRegionIntoView( | 502 Status ScrollElementRegionIntoView( |
| 429 Session* session, | 503 Session* session, |
| 430 WebView* web_view, | 504 WebView* web_view, |
| 431 const std::string& element_id, | 505 const std::string& element_id, |
| 432 const WebRect& region, | 506 const WebRect& region, |
| 433 bool center, | 507 bool center, |
| 508 bool verify_clickable, | |
| 434 WebPoint* location) { | 509 WebPoint* location) { |
| 435 WebPoint region_offset = region.origin; | 510 WebPoint region_offset = region.origin; |
| 436 base::ListValue args; | 511 WebSize region_size = region.size; |
| 437 args.Append(CreateElement(element_id)); | 512 Status status = ScrollElementRegionIntoViewHelper( |
| 438 args.AppendBoolean(center); | 513 session->frame, web_view, element_id, region, |
| 439 args.Append(CreateValueFrom(®ion)); | 514 center, verify_clickable, ®ion_offset); |
| 440 scoped_ptr<base::Value> result; | |
| 441 | |
| 442 // TODO(chrisgao): Nested frame. See http://crbug.com/170998. | |
| 443 Status status = CallAtomsJs( | |
| 444 session, web_view, webdriver::atoms::GET_LOCATION_IN_VIEW, args, &result); | |
| 445 if (status.IsError()) | 515 if (status.IsError()) |
| 446 return status; | 516 return status; |
| 447 if (!ParseFromValue(result.get(), ®ion_offset)) | 517 const char* kFindSubFrameScript = |
| 448 return Status(kUnknownError, "fail to parse value of GET_LOCATION_IN_VIEW"); | 518 "function(xpath) {" |
| 519 " return document.evaluate(xpath, document, null," | |
| 520 " XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;" | |
| 521 "}"; | |
| 522 for (std::list<FrameInfo>::reverse_iterator rit = | |
| 523 session->frame_elements.rbegin(); | |
| 524 rit != session->frame_elements.rend(); ++rit) { | |
| 525 base::ListValue args; | |
| 526 args.AppendString(rit->xpath); | |
| 527 scoped_ptr<base::Value> result; | |
| 528 status = web_view->CallFunction( | |
| 529 rit->parent_id, kFindSubFrameScript, args, &result); | |
| 530 if (status.IsError()) | |
| 531 return status; | |
| 532 const base::DictionaryValue* element_dict; | |
| 533 if (!result->GetAsDictionary(&element_dict)) | |
| 534 return Status(kUnknownError, "no element reference returned by script"); | |
| 535 std::string frame_element_id; | |
| 536 if (!element_dict->GetString(kElementKey, &frame_element_id)) | |
| 537 return Status(kUnknownError, "fail to locate a sub frame"); | |
| 538 | |
| 539 // Modify |region_offset| by the frame's border. | |
| 540 int border_lef, border_top; | |
| 541 status = GetElementBorder( | |
| 542 rit->parent_id, web_view, frame_element_id, | |
| 543 &border_lef, &border_top); | |
| 544 if (status.IsError()) | |
| 545 return status; | |
| 546 region_offset.Offset(border_lef, border_top); | |
| 547 | |
| 548 status = ScrollElementRegionIntoViewHelper( | |
| 549 rit->parent_id, web_view, frame_element_id, | |
| 550 WebRect(region_offset, region_size), | |
| 551 center, verify_clickable, ®ion_offset); | |
| 552 if (status.IsError()) | |
| 553 return status; | |
| 554 } | |
| 449 *location = region_offset; | 555 *location = region_offset; |
| 450 return Status(kOk); | 556 return Status(kOk); |
| 451 } | 557 } |
| OLD | NEW |