| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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.h" | 5 #include "content/browser/accessibility/browser_accessibility.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 | 10 |
| (...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 332 } | 332 } |
| 333 | 333 |
| 334 const ui::AXNodeData& BrowserAccessibility::GetData() const { | 334 const ui::AXNodeData& BrowserAccessibility::GetData() const { |
| 335 CR_DEFINE_STATIC_LOCAL(ui::AXNodeData, empty_data, ()); | 335 CR_DEFINE_STATIC_LOCAL(ui::AXNodeData, empty_data, ()); |
| 336 if (node_) | 336 if (node_) |
| 337 return node_->data(); | 337 return node_->data(); |
| 338 else | 338 else |
| 339 return empty_data; | 339 return empty_data; |
| 340 } | 340 } |
| 341 | 341 |
| 342 gfx::Rect BrowserAccessibility::GetLocation() const { | 342 gfx::RectF BrowserAccessibility::GetLocation() const { |
| 343 return gfx::ToEnclosingRect(GetData().location); | 343 return GetData().location; |
| 344 } | 344 } |
| 345 | 345 |
| 346 int32_t BrowserAccessibility::GetRole() const { | 346 int32_t BrowserAccessibility::GetRole() const { |
| 347 return GetData().role; | 347 return GetData().role; |
| 348 } | 348 } |
| 349 | 349 |
| 350 int32_t BrowserAccessibility::GetState() const { | 350 int32_t BrowserAccessibility::GetState() const { |
| 351 return GetData().state; | 351 return GetData().state; |
| 352 } | 352 } |
| 353 | 353 |
| 354 const BrowserAccessibility::HtmlAttributes& | 354 const BrowserAccessibility::HtmlAttributes& |
| 355 BrowserAccessibility::GetHtmlAttributes() const { | 355 BrowserAccessibility::GetHtmlAttributes() const { |
| 356 return GetData().html_attributes; | 356 return GetData().html_attributes; |
| 357 } | 357 } |
| 358 | 358 |
| 359 gfx::Rect BrowserAccessibility::GetLocalBoundsRect() const { | 359 gfx::Rect BrowserAccessibility::GetFrameBoundsRect() const { |
| 360 gfx::Rect bounds = GetLocation(); | 360 gfx::RectF bounds = GetLocation(); |
| 361 FixEmptyBounds(&bounds); | 361 FixEmptyBounds(&bounds); |
| 362 return ElementBoundsToLocalBounds(bounds); | 362 return RelativeToAbsoluteBounds(bounds, true); |
| 363 } | 363 } |
| 364 | 364 |
| 365 gfx::Rect BrowserAccessibility::GetGlobalBoundsRect() const { | 365 gfx::Rect BrowserAccessibility::GetPageBoundsRect() const { |
| 366 gfx::Rect bounds = GetLocalBoundsRect(); | 366 gfx::RectF bounds = GetLocation(); |
| 367 FixEmptyBounds(&bounds); |
| 368 return RelativeToAbsoluteBounds(bounds, false); |
| 369 } |
| 370 |
| 371 gfx::Rect BrowserAccessibility::GetScreenBoundsRect() const { |
| 372 gfx::Rect bounds = GetPageBoundsRect(); |
| 367 | 373 |
| 368 // Adjust the bounds by the top left corner of the containing view's bounds | 374 // Adjust the bounds by the top left corner of the containing view's bounds |
| 369 // in screen coordinates. | 375 // in screen coordinates. |
| 370 bounds.Offset(manager_->GetViewBounds().OffsetFromOrigin()); | 376 bounds.Offset(manager_->GetViewBounds().OffsetFromOrigin()); |
| 371 | 377 |
| 372 return bounds; | 378 return bounds; |
| 373 } | 379 } |
| 374 | 380 |
| 375 gfx::Rect BrowserAccessibility::GetLocalBoundsForRange(int start, int len) | 381 gfx::Rect BrowserAccessibility::GetPageBoundsForRange(int start, int len) |
| 376 const { | 382 const { |
| 377 DCHECK_GE(start, 0); | 383 DCHECK_GE(start, 0); |
| 378 DCHECK_GE(len, 0); | 384 DCHECK_GE(len, 0); |
| 379 | 385 |
| 380 // Standard text fields such as textarea have an embedded div inside them that | 386 // Standard text fields such as textarea have an embedded div inside them that |
| 381 // holds all the text. | 387 // holds all the text. |
| 382 // TODO(nektar): This is fragile! Replace with code that flattens tree. | 388 // TODO(nektar): This is fragile! Replace with code that flattens tree. |
| 383 if (IsSimpleTextControl() && InternalChildCount() == 1) | 389 if (IsSimpleTextControl() && InternalChildCount() == 1) |
| 384 return InternalGetChild(0)->GetLocalBoundsForRange(start, len); | 390 return InternalGetChild(0)->GetPageBoundsForRange(start, len); |
| 385 | 391 |
| 386 if (GetRole() != ui::AX_ROLE_STATIC_TEXT) { | 392 if (GetRole() != ui::AX_ROLE_STATIC_TEXT) { |
| 387 gfx::Rect bounds; | 393 gfx::Rect bounds; |
| 388 for (size_t i = 0; i < InternalChildCount() && len > 0; ++i) { | 394 for (size_t i = 0; i < InternalChildCount() && len > 0; ++i) { |
| 389 BrowserAccessibility* child = InternalGetChild(i); | 395 BrowserAccessibility* child = InternalGetChild(i); |
| 390 // Child objects are of length one, since they are represented by a single | 396 // Child objects are of length one, since they are represented by a single |
| 391 // embedded object character. The exception is text-only objects. | 397 // embedded object character. The exception is text-only objects. |
| 392 int child_length_in_parent = 1; | 398 int child_length_in_parent = 1; |
| 393 if (child->IsTextOnlyObject()) | 399 if (child->IsTextOnlyObject()) |
| 394 child_length_in_parent = static_cast<int>(child->GetText().size()); | 400 child_length_in_parent = static_cast<int>(child->GetText().size()); |
| 395 if (start < child_length_in_parent) { | 401 if (start < child_length_in_parent) { |
| 396 gfx::Rect child_rect; | 402 gfx::Rect child_rect; |
| 397 if (child->IsTextOnlyObject()) { | 403 if (child->IsTextOnlyObject()) { |
| 398 child_rect = child->GetLocalBoundsForRange(start, len); | 404 child_rect = child->GetPageBoundsForRange(start, len); |
| 399 } else { | 405 } else { |
| 400 child_rect = child->GetLocalBoundsForRange( | 406 child_rect = child->GetPageBoundsForRange( |
| 401 0, static_cast<int>(child->GetText().size())); | 407 0, static_cast<int>(child->GetText().size())); |
| 402 } | 408 } |
| 403 bounds.Union(child_rect); | 409 bounds.Union(child_rect); |
| 404 len -= (child_length_in_parent - start); | 410 len -= (child_length_in_parent - start); |
| 405 } | 411 } |
| 406 if (start > child_length_in_parent) | 412 if (start > child_length_in_parent) |
| 407 start -= child_length_in_parent; | 413 start -= child_length_in_parent; |
| 408 else | 414 else |
| 409 start = 0; | 415 start = 0; |
| 410 } | 416 } |
| 411 return ElementBoundsToLocalBounds(bounds); | 417 return RelativeToAbsoluteBounds(gfx::RectF(bounds), false); |
| 412 } | 418 } |
| 413 | 419 |
| 414 int end = start + len; | 420 int end = start + len; |
| 415 int child_start = 0; | 421 int child_start = 0; |
| 416 int child_end = 0; | 422 int child_end = 0; |
| 417 gfx::Rect bounds; | 423 gfx::Rect bounds; |
| 418 for (size_t i = 0; i < InternalChildCount() && child_end < start + len; ++i) { | 424 for (size_t i = 0; i < InternalChildCount() && child_end < start + len; ++i) { |
| 419 BrowserAccessibility* child = InternalGetChild(i); | 425 BrowserAccessibility* child = InternalGetChild(i); |
| 420 if (child->GetRole() != ui::AX_ROLE_INLINE_TEXT_BOX) { | 426 if (child->GetRole() != ui::AX_ROLE_INLINE_TEXT_BOX) { |
| 421 DLOG(WARNING) << "BrowserAccessibility objects with role STATIC_TEXT " << | 427 DLOG(WARNING) << "BrowserAccessibility objects with role STATIC_TEXT " << |
| (...skipping 22 matching lines...) Expand all Loading... |
| 444 | 450 |
| 445 const std::vector<int32_t>& character_offsets = | 451 const std::vector<int32_t>& character_offsets = |
| 446 child->GetIntListAttribute(ui::AX_ATTR_CHARACTER_OFFSETS); | 452 child->GetIntListAttribute(ui::AX_ATTR_CHARACTER_OFFSETS); |
| 447 if (static_cast<int>(character_offsets.size()) != child_length) | 453 if (static_cast<int>(character_offsets.size()) != child_length) |
| 448 continue; | 454 continue; |
| 449 int start_pixel_offset = | 455 int start_pixel_offset = |
| 450 local_start > 0 ? character_offsets[local_start - 1] : 0; | 456 local_start > 0 ? character_offsets[local_start - 1] : 0; |
| 451 int end_pixel_offset = | 457 int end_pixel_offset = |
| 452 local_end > 0 ? character_offsets[local_end - 1] : 0; | 458 local_end > 0 ? character_offsets[local_end - 1] : 0; |
| 453 | 459 |
| 454 gfx::Rect child_rect = child->GetLocation(); | 460 gfx::Rect child_rect = gfx::ToEnclosingRect(child->GetLocation()); |
| 455 auto text_direction = static_cast<ui::AXTextDirection>( | 461 auto text_direction = static_cast<ui::AXTextDirection>( |
| 456 child->GetIntAttribute(ui::AX_ATTR_TEXT_DIRECTION)); | 462 child->GetIntAttribute(ui::AX_ATTR_TEXT_DIRECTION)); |
| 457 gfx::Rect child_overlap_rect; | 463 gfx::Rect child_overlap_rect; |
| 458 switch (text_direction) { | 464 switch (text_direction) { |
| 459 case ui::AX_TEXT_DIRECTION_NONE: | 465 case ui::AX_TEXT_DIRECTION_NONE: |
| 460 case ui::AX_TEXT_DIRECTION_LTR: { | 466 case ui::AX_TEXT_DIRECTION_LTR: { |
| 461 int left = child_rect.x() + start_pixel_offset; | 467 int left = child_rect.x() + start_pixel_offset; |
| 462 int right = child_rect.x() + end_pixel_offset; | 468 int right = child_rect.x() + end_pixel_offset; |
| 463 child_overlap_rect = gfx::Rect(left, child_rect.y(), | 469 child_overlap_rect = gfx::Rect(left, child_rect.y(), |
| 464 right - left, child_rect.height()); | 470 right - left, child_rect.height()); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 488 default: | 494 default: |
| 489 NOTREACHED(); | 495 NOTREACHED(); |
| 490 } | 496 } |
| 491 | 497 |
| 492 if (bounds.width() == 0 && bounds.height() == 0) | 498 if (bounds.width() == 0 && bounds.height() == 0) |
| 493 bounds = child_overlap_rect; | 499 bounds = child_overlap_rect; |
| 494 else | 500 else |
| 495 bounds.Union(child_overlap_rect); | 501 bounds.Union(child_overlap_rect); |
| 496 } | 502 } |
| 497 | 503 |
| 498 return ElementBoundsToLocalBounds(bounds); | 504 return RelativeToAbsoluteBounds(gfx::RectF(bounds), false); |
| 499 } | 505 } |
| 500 | 506 |
| 501 gfx::Rect BrowserAccessibility::GetGlobalBoundsForRange(int start, int len) | 507 gfx::Rect BrowserAccessibility::GetScreenBoundsForRange(int start, int len) |
| 502 const { | 508 const { |
| 503 gfx::Rect bounds = GetLocalBoundsForRange(start, len); | 509 gfx::Rect bounds = GetPageBoundsForRange(start, len); |
| 504 | 510 |
| 505 // Adjust the bounds by the top left corner of the containing view's bounds | 511 // Adjust the bounds by the top left corner of the containing view's bounds |
| 506 // in screen coordinates. | 512 // in screen coordinates. |
| 507 bounds.Offset(manager_->GetViewBounds().OffsetFromOrigin()); | 513 bounds.Offset(manager_->GetViewBounds().OffsetFromOrigin()); |
| 508 | 514 |
| 509 return bounds; | 515 return bounds; |
| 510 } | 516 } |
| 511 | 517 |
| 512 base::string16 BrowserAccessibility::GetValue() const { | 518 base::string16 BrowserAccessibility::GetValue() const { |
| 513 base::string16 value = GetString16Attribute(ui::AX_ATTR_VALUE); | 519 base::string16 value = GetString16Attribute(ui::AX_ATTR_VALUE); |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 724 // the absence of any other information, we assume the object that occurs | 730 // the absence of any other information, we assume the object that occurs |
| 725 // later in the tree is on top of one that comes before it. | 731 // later in the tree is on top of one that comes before it. |
| 726 for (int i = static_cast<int>(PlatformChildCount()) - 1; i >= 0; --i) { | 732 for (int i = static_cast<int>(PlatformChildCount()) - 1; i >= 0; --i) { |
| 727 BrowserAccessibility* child = PlatformGetChild(i); | 733 BrowserAccessibility* child = PlatformGetChild(i); |
| 728 | 734 |
| 729 // Skip table columns because cells are only contained in rows, | 735 // Skip table columns because cells are only contained in rows, |
| 730 // not columns. | 736 // not columns. |
| 731 if (child->GetRole() == ui::AX_ROLE_COLUMN) | 737 if (child->GetRole() == ui::AX_ROLE_COLUMN) |
| 732 continue; | 738 continue; |
| 733 | 739 |
| 734 if (child->GetGlobalBoundsRect().Contains(point)) { | 740 if (child->GetScreenBoundsRect().Contains(point)) { |
| 735 BrowserAccessibility* result = child->BrowserAccessibilityForPoint(point); | 741 BrowserAccessibility* result = child->BrowserAccessibilityForPoint(point); |
| 736 if (result == child && !child_result) | 742 if (result == child && !child_result) |
| 737 child_result = result; | 743 child_result = result; |
| 738 if (result != child && !descendant_result) | 744 if (result != child && !descendant_result) |
| 739 descendant_result = result; | 745 descendant_result = result; |
| 740 } | 746 } |
| 741 | 747 |
| 742 if (child_result && descendant_result) | 748 if (child_result && descendant_result) |
| 743 break; | 749 break; |
| 744 } | 750 } |
| (...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1139 base::string16 BrowserAccessibility::GetInnerText() const { | 1145 base::string16 BrowserAccessibility::GetInnerText() const { |
| 1140 if (IsTextOnlyObject()) | 1146 if (IsTextOnlyObject()) |
| 1141 return GetString16Attribute(ui::AX_ATTR_NAME); | 1147 return GetString16Attribute(ui::AX_ATTR_NAME); |
| 1142 | 1148 |
| 1143 base::string16 text; | 1149 base::string16 text; |
| 1144 for (size_t i = 0; i < InternalChildCount(); ++i) | 1150 for (size_t i = 0; i < InternalChildCount(); ++i) |
| 1145 text += InternalGetChild(i)->GetInnerText(); | 1151 text += InternalGetChild(i)->GetInnerText(); |
| 1146 return text; | 1152 return text; |
| 1147 } | 1153 } |
| 1148 | 1154 |
| 1149 void BrowserAccessibility::FixEmptyBounds(gfx::Rect* bounds) const | 1155 void BrowserAccessibility::FixEmptyBounds(gfx::RectF* bounds) const |
| 1150 { | 1156 { |
| 1151 if (bounds->width() > 0 && bounds->height() > 0) | 1157 if (bounds->width() > 0 && bounds->height() > 0) |
| 1152 return; | 1158 return; |
| 1153 | 1159 |
| 1154 for (size_t i = 0; i < InternalChildCount(); ++i) { | 1160 for (size_t i = 0; i < InternalChildCount(); ++i) { |
| 1155 // Compute the bounds of each child - this calls FixEmptyBounds | 1161 // Compute the bounds of each child - this calls FixEmptyBounds |
| 1156 // recursively if necessary. | 1162 // recursively if necessary. |
| 1157 BrowserAccessibility* child = InternalGetChild(i); | 1163 BrowserAccessibility* child = InternalGetChild(i); |
| 1158 gfx::Rect child_bounds = child->GetLocalBoundsRect(); | 1164 gfx::Rect child_bounds = child->GetPageBoundsRect(); |
| 1159 | 1165 |
| 1160 // Ignore children that don't have valid bounds themselves. | 1166 // Ignore children that don't have valid bounds themselves. |
| 1161 if (child_bounds.width() == 0 || child_bounds.height() == 0) | 1167 if (child_bounds.width() == 0 || child_bounds.height() == 0) |
| 1162 continue; | 1168 continue; |
| 1163 | 1169 |
| 1164 // For the first valid child, just set the bounds to that child's bounds. | 1170 // For the first valid child, just set the bounds to that child's bounds. |
| 1165 if (bounds->width() == 0 || bounds->height() == 0) { | 1171 if (bounds->width() == 0 || bounds->height() == 0) { |
| 1166 *bounds = child_bounds; | 1172 *bounds = gfx::RectF(child_bounds); |
| 1167 continue; | 1173 continue; |
| 1168 } | 1174 } |
| 1169 | 1175 |
| 1170 // Union each additional child's bounds. | 1176 // Union each additional child's bounds. |
| 1171 bounds->Union(child_bounds); | 1177 bounds->Union(gfx::RectF(child_bounds)); |
| 1172 } | 1178 } |
| 1173 } | 1179 } |
| 1174 | 1180 |
| 1175 gfx::Rect BrowserAccessibility::ElementBoundsToLocalBounds(gfx::Rect bounds) | 1181 gfx::Rect BrowserAccessibility::RelativeToAbsoluteBounds( |
| 1176 const { | 1182 gfx::RectF bounds, |
| 1177 BrowserAccessibilityManager* manager = this->manager(); | 1183 bool frame_only) const { |
| 1178 BrowserAccessibility* root = manager->GetRoot(); | 1184 const BrowserAccessibility* node = this; |
| 1179 while (manager && root) { | 1185 while (node) { |
| 1180 // Apply scroll offsets. | 1186 if (node->GetData().transform) |
| 1181 if (root != this && (root->GetParent() || | 1187 node->GetData().transform->TransformRect(&bounds); |
| 1182 manager->UseRootScrollOffsetsWhenComputingBounds())) { | 1188 |
| 1189 const BrowserAccessibility* container = |
| 1190 node->manager()->GetFromID(node->GetData().offset_container_id); |
| 1191 if (!container) { |
| 1192 if (node == node->manager()->GetRoot() && !frame_only) { |
| 1193 container = node->GetParent(); |
| 1194 } else { |
| 1195 container = node->manager()->GetRoot(); |
| 1196 } |
| 1197 } |
| 1198 |
| 1199 if (!container || container == node) |
| 1200 break; |
| 1201 |
| 1202 gfx::RectF container_bounds = container->GetLocation(); |
| 1203 bounds.Offset(container_bounds.x(), container_bounds.y()); |
| 1204 |
| 1205 if (container->manager()->UseRootScrollOffsetsWhenComputingBounds() || |
| 1206 container->GetParent()) { |
| 1183 int sx = 0; | 1207 int sx = 0; |
| 1184 int sy = 0; | 1208 int sy = 0; |
| 1185 if (root->GetIntAttribute(ui::AX_ATTR_SCROLL_X, &sx) && | 1209 if (container->GetIntAttribute(ui::AX_ATTR_SCROLL_X, &sx) && |
| 1186 root->GetIntAttribute(ui::AX_ATTR_SCROLL_Y, &sy)) { | 1210 container->GetIntAttribute(ui::AX_ATTR_SCROLL_Y, &sy)) { |
| 1187 bounds.Offset(-sx, -sy); | 1211 bounds.Offset(-sx, -sy); |
| 1188 } | 1212 } |
| 1189 } | 1213 } |
| 1190 | 1214 |
| 1191 // If the parent accessibility tree is in a different site instance, | 1215 node = container; |
| 1192 // ask the delegate to transform our coordinates into the root | |
| 1193 // coordinate space and then we're done. | |
| 1194 if (manager->delegate() && | |
| 1195 root->GetParent() && | |
| 1196 root->GetParent()->manager()->delegate()) { | |
| 1197 BrowserAccessibilityManager* parent_manager = | |
| 1198 root->GetParent()->manager(); | |
| 1199 if (manager->delegate()->AccessibilityGetSiteInstance() != | |
| 1200 parent_manager->delegate()->AccessibilityGetSiteInstance()) { | |
| 1201 return manager->delegate()->AccessibilityTransformToRootCoordSpace( | |
| 1202 bounds); | |
| 1203 } | |
| 1204 } | |
| 1205 | |
| 1206 // Otherwise, apply the transform from this frame into the coordinate | |
| 1207 // space of its parent frame. | |
| 1208 if (root->GetData().transform) { | |
| 1209 gfx::RectF boundsf(bounds); | |
| 1210 root->GetData().transform->TransformRect(&boundsf); | |
| 1211 bounds = gfx::Rect(boundsf.x(), boundsf.y(), | |
| 1212 boundsf.width(), boundsf.height()); | |
| 1213 } | |
| 1214 | |
| 1215 if (!root->GetParent()) | |
| 1216 break; | |
| 1217 | |
| 1218 manager = root->GetParent()->manager(); | |
| 1219 root = manager->GetRoot(); | |
| 1220 } | 1216 } |
| 1221 | 1217 |
| 1222 return bounds; | 1218 return gfx::ToEnclosingRect(bounds); |
| 1223 } | 1219 } |
| 1224 | 1220 |
| 1225 } // namespace content | 1221 } // namespace content |
| OLD | NEW |