| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 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 "content/browser/accessibility/browser_accessibility_android.h" | 5 #include "content/browser/accessibility/browser_accessibility_android.h" |
| 6 | 6 |
| 7 #include "base/i18n/break_iterator.h" | 7 #include "base/i18n/break_iterator.h" |
| 8 #include "base/strings/string_util.h" | 8 #include "base/strings/string_util.h" |
| 9 #include "base/strings/stringprintf.h" | 9 #include "base/strings/stringprintf.h" |
| 10 #include "base/strings/utf_string_conversions.h" | 10 #include "base/strings/utf_string_conversions.h" |
| (...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 308 | 308 |
| 309 return class_name; | 309 return class_name; |
| 310 } | 310 } |
| 311 | 311 |
| 312 base::string16 BrowserAccessibilityAndroid::GetText() const { | 312 base::string16 BrowserAccessibilityAndroid::GetText() const { |
| 313 if (IsIframe() || | 313 if (IsIframe() || |
| 314 GetRole() == ui::AX_ROLE_WEB_AREA) { | 314 GetRole() == ui::AX_ROLE_WEB_AREA) { |
| 315 return base::string16(); | 315 return base::string16(); |
| 316 } | 316 } |
| 317 | 317 |
| 318 // See comment in browser_accessibility_win.cc for details. | 318 // We can only expose one accessible name on Android, |
| 319 // The difference here is that we can only expose one accessible | 319 // not 2 or 3 like on Windows or Mac. |
| 320 // name on Android, not 2 or 3 like on Windows or Mac. | |
| 321 | 320 |
| 322 // First, always return the |value| attribute if this is an | 321 // First, always return the |value| attribute if this is an |
| 323 // input field. | 322 // input field. |
| 324 base::string16 value = GetString16Attribute(ui::AX_ATTR_VALUE); | 323 base::string16 value = GetString16Attribute(ui::AX_ATTR_VALUE); |
| 325 if (!value.empty()) { | 324 if (!value.empty()) { |
| 326 if (HasState(ui::AX_STATE_EDITABLE)) | 325 if (HasState(ui::AX_STATE_EDITABLE)) |
| 327 return value; | 326 return value; |
| 328 | 327 |
| 329 switch (GetRole()) { | 328 switch (GetRole()) { |
| 330 case ui::AX_ROLE_COMBO_BOX: | 329 case ui::AX_ROLE_COMBO_BOX: |
| 331 case ui::AX_ROLE_POP_UP_BUTTON: | 330 case ui::AX_ROLE_POP_UP_BUTTON: |
| 332 case ui::AX_ROLE_TEXT_FIELD: | 331 case ui::AX_ROLE_TEXT_FIELD: |
| 333 return value; | 332 return value; |
| 334 } | 333 } |
| 335 } | 334 } |
| 336 | 335 |
| 337 // For color wells, the color is stored in separate attributes. | 336 // For color wells, the color is stored in separate attributes. |
| 338 // Perhaps we could return color names in the future? | 337 // Perhaps we could return color names in the future? |
| 339 if (GetRole() == ui::AX_ROLE_COLOR_WELL) { | 338 if (GetRole() == ui::AX_ROLE_COLOR_WELL) { |
| 340 int color = GetIntAttribute(ui::AX_ATTR_COLOR_VALUE); | 339 int color = GetIntAttribute(ui::AX_ATTR_COLOR_VALUE); |
| 341 int red = (color >> 16) & 0xFF; | 340 int red = (color >> 16) & 0xFF; |
| 342 int green = (color >> 8) & 0xFF; | 341 int green = (color >> 8) & 0xFF; |
| 343 int blue = color & 0xFF; | 342 int blue = color & 0xFF; |
| 344 return base::UTF8ToUTF16( | 343 return base::UTF8ToUTF16( |
| 345 base::StringPrintf("#%02X%02X%02X", red, green, blue)); | 344 base::StringPrintf("#%02X%02X%02X", red, green, blue)); |
| 346 } | 345 } |
| 347 | 346 |
| 348 // Always prefer visible text if this is a link. Sites sometimes add | 347 base::string16 text = GetString16Attribute(ui::AX_ATTR_NAME); |
| 349 // a "title" attribute to a link with more information, but we can't | |
| 350 // lose the link text. | |
| 351 base::string16 name = GetString16Attribute(ui::AX_ATTR_NAME); | |
| 352 if (!name.empty() && GetRole() == ui::AX_ROLE_LINK) | |
| 353 return name; | |
| 354 | |
| 355 // If there's no text value, the basic rule is: prefer description | |
| 356 // (aria-labelledby or aria-label), then help (title), then name | |
| 357 // (inner text), then value (control value). However, if | |
| 358 // title_elem_id is set, that means there's a label element | |
| 359 // supplying the name and then name takes precedence over help. | |
| 360 // TODO(dmazzoni): clean this up by providing more granular labels in | |
| 361 // Blink, making the platform-specific mapping to accessible text simpler. | |
| 362 base::string16 description = GetString16Attribute(ui::AX_ATTR_DESCRIPTION); | 348 base::string16 description = GetString16Attribute(ui::AX_ATTR_DESCRIPTION); |
| 363 base::string16 help = GetString16Attribute(ui::AX_ATTR_HELP); | 349 if (!description.empty()) { |
| 364 | 350 if (!text.empty()) |
| 365 base::string16 placeholder; | 351 text += base::ASCIIToUTF16(" "); |
| 366 switch (GetRole()) { | 352 text += description; |
| 367 case ui::AX_ROLE_DATE: | |
| 368 case ui::AX_ROLE_INPUT_TIME: | |
| 369 case ui::AX_ROLE_TEXT_FIELD: | |
| 370 GetHtmlAttribute("placeholder", &placeholder); | |
| 371 } | 353 } |
| 372 | 354 |
| 373 int title_elem_id = GetIntAttribute( | 355 if (text.empty()) |
| 374 ui::AX_ATTR_TITLE_UI_ELEMENT); | |
| 375 base::string16 text; | |
| 376 if (!description.empty()) | |
| 377 text = description; | |
| 378 else if (!name.empty()) { | |
| 379 text = name; | |
| 380 if (!help.empty()) { | |
| 381 // TODO(vkuzkokov): This is not the best way to pass 2 texts but this is | |
| 382 // how Blink seems to be doing it. | |
| 383 text += base::ASCIIToUTF16(" "); | |
| 384 text += help; | |
| 385 } | |
| 386 } else if (!help.empty()) | |
| 387 text = help; | |
| 388 else if (!placeholder.empty()) | |
| 389 text = placeholder; | |
| 390 else if (!value.empty()) | |
| 391 text = value; | 356 text = value; |
| 392 else if (title_elem_id) { | |
| 393 BrowserAccessibility* title_elem = | |
| 394 manager()->GetFromID(title_elem_id); | |
| 395 if (title_elem) | |
| 396 text = static_cast<BrowserAccessibilityAndroid*>(title_elem)->GetText(); | |
| 397 } | |
| 398 | 357 |
| 399 // This is called from PlatformIsLeaf, so don't call PlatformChildCount | 358 // This is called from PlatformIsLeaf, so don't call PlatformChildCount |
| 400 // from within this! | 359 // from within this! |
| 401 if (text.empty() && | 360 if (text.empty() && |
| 402 (HasOnlyStaticTextChildren() || | 361 (HasOnlyStaticTextChildren() || |
| 403 (IsFocusable() && HasOnlyTextAndImageChildren()))) { | 362 (IsFocusable() && HasOnlyTextAndImageChildren()))) { |
| 404 for (uint32 i = 0; i < InternalChildCount(); i++) { | 363 for (uint32 i = 0; i < InternalChildCount(); i++) { |
| 405 BrowserAccessibility* child = InternalGetChild(i); | 364 BrowserAccessibility* child = InternalGetChild(i); |
| 406 text += static_cast<BrowserAccessibilityAndroid*>(child)->GetText(); | 365 text += static_cast<BrowserAccessibilityAndroid*>(child)->GetText(); |
| 407 } | 366 } |
| 408 } | 367 } |
| 409 | 368 |
| 410 if (text.empty() && (IsLink() || GetRole() == ui::AX_ROLE_IMAGE)) { | 369 if (text.empty() && (IsLink() || GetRole() == ui::AX_ROLE_IMAGE)) { |
| 411 base::string16 url = GetString16Attribute(ui::AX_ATTR_URL); | 370 base::string16 url = GetString16Attribute(ui::AX_ATTR_URL); |
| 412 // Given a url like http://foo.com/bar/baz.png, just return the | 371 // Given a url like http://foo.com/bar/baz.png, just return the |
| 413 // base name, e.g., "baz". | 372 // base text, e.g., "baz". |
| 414 int trailing_slashes = 0; | 373 int trailing_slashes = 0; |
| 415 while (url.size() - trailing_slashes > 0 && | 374 while (url.size() - trailing_slashes > 0 && |
| 416 url[url.size() - trailing_slashes - 1] == '/') { | 375 url[url.size() - trailing_slashes - 1] == '/') { |
| 417 trailing_slashes++; | 376 trailing_slashes++; |
| 418 } | 377 } |
| 419 if (trailing_slashes) | 378 if (trailing_slashes) |
| 420 url = url.substr(0, url.size() - trailing_slashes); | 379 url = url.substr(0, url.size() - trailing_slashes); |
| 421 size_t slash_index = url.rfind('/'); | 380 size_t slash_index = url.rfind('/'); |
| 422 if (slash_index != std::string::npos) | 381 if (slash_index != std::string::npos) |
| 423 url = url.substr(slash_index + 1); | 382 url = url.substr(slash_index + 1); |
| (...skipping 570 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 994 int BrowserAccessibilityAndroid::CountChildrenWithRole(ui::AXRole role) const { | 953 int BrowserAccessibilityAndroid::CountChildrenWithRole(ui::AXRole role) const { |
| 995 int count = 0; | 954 int count = 0; |
| 996 for (uint32 i = 0; i < PlatformChildCount(); i++) { | 955 for (uint32 i = 0; i < PlatformChildCount(); i++) { |
| 997 if (PlatformGetChild(i)->GetRole() == role) | 956 if (PlatformGetChild(i)->GetRole() == role) |
| 998 count++; | 957 count++; |
| 999 } | 958 } |
| 1000 return count; | 959 return count; |
| 1001 } | 960 } |
| 1002 | 961 |
| 1003 } // namespace content | 962 } // namespace content |
| OLD | NEW |