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 |