Commit 481ddeb1 authored by dmazzoni@chromium.org's avatar dmazzoni@chromium.org

Fix accessibility coordinates within iframes.

WebKit returns local coordinates within an iframe, we need
to convert them to page-global coordinates. In addition,
the test code needs to print page-global coordinates
(not screen-global) for easier debugging and reliable
test output.

BUG=171705
TBR=dtseng


Review URL: https://chromiumcodereview.appspot.com/12084028

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@179468 0039d316-1c4b-4281-b951-d872f2087c98
parent 257abfa8
...@@ -133,15 +133,30 @@ BrowserAccessibility* BrowserAccessibility::GetNextSibling() { ...@@ -133,15 +133,30 @@ BrowserAccessibility* BrowserAccessibility::GetNextSibling() {
gfx::Rect BrowserAccessibility::GetLocalBoundsRect() { gfx::Rect BrowserAccessibility::GetLocalBoundsRect() {
gfx::Rect bounds = location_; gfx::Rect bounds = location_;
// Adjust top left position by the root document's scroll offset. // Walk up the parent chain. Every time we encounter a Web Area, offset
BrowserAccessibility* root = manager_->GetRoot(); // based on the scroll bars and then offset based on the origin of that
int scroll_x = 0; // nested web area.
int scroll_y = 0; BrowserAccessibility* parent = parent_;
if (!root->GetIntAttribute(AccessibilityNodeData::ATTR_SCROLL_X, &scroll_x) || bool need_to_offset_web_area =
!root->GetIntAttribute(AccessibilityNodeData::ATTR_SCROLL_Y, &scroll_y)) { (role_ == AccessibilityNodeData::ROLE_WEB_AREA);
return bounds; while (parent) {
if (need_to_offset_web_area &&
parent->location().width() > 0 &&
parent->location().height() > 0) {
bounds.Offset(parent->location().x(), parent->location().y());
need_to_offset_web_area = false;
}
if (parent->role() == AccessibilityNodeData::ROLE_WEB_AREA) {
int sx = 0;
int sy = 0;
if (parent->GetIntAttribute(AccessibilityNodeData::ATTR_SCROLL_X, &sx) &&
parent->GetIntAttribute(AccessibilityNodeData::ATTR_SCROLL_Y, &sy)) {
bounds.Offset(-sx, -sy);
}
need_to_offset_web_area = true;
}
parent = parent->parent();
} }
bounds.Offset(-scroll_x, -scroll_y);
return bounds; return bounds;
} }
......
...@@ -363,6 +363,11 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityHR) { ...@@ -363,6 +363,11 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityHR) {
RunTest(FILE_PATH_LITERAL("hr.html")); RunTest(FILE_PATH_LITERAL("hr.html"));
} }
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest,
AccessibilityIframeCoordinates) {
RunTest(FILE_PATH_LITERAL("iframe-coordinates.html"));
}
IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputButton) { IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityInputButton) {
RunTest(FILE_PATH_LITERAL("input-button.html")); RunTest(FILE_PATH_LITERAL("input-button.html"));
} }
......
...@@ -10,9 +10,12 @@ ...@@ -10,9 +10,12 @@
#include "base/utf_string_conversions.h" #include "base/utf_string_conversions.h"
#include "content/browser/accessibility/browser_accessibility_cocoa.h" #include "content/browser/accessibility/browser_accessibility_cocoa.h"
#include "content/browser/accessibility/browser_accessibility_mac.h" #include "content/browser/accessibility/browser_accessibility_mac.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
namespace content { namespace content {
namespace { namespace {
string16 Format(BrowserAccessibility* node, string16 Format(BrowserAccessibility* node,
const char *prefix, const char *prefix,
SEL selector, SEL selector,
...@@ -26,8 +29,43 @@ string16 Format(BrowserAccessibility* node, ...@@ -26,8 +29,43 @@ string16 Format(BrowserAccessibility* node,
NSString* tmp = [NSString stringWithFormat:format_str, value]; NSString* tmp = [NSString stringWithFormat:format_str, value];
return UTF8ToUTF16([tmp cStringUsingEncoding:NSUTF8StringEncoding]); return UTF8ToUTF16([tmp cStringUsingEncoding:NSUTF8StringEncoding]);
} }
string16 FormatPosition(BrowserAccessibility* node) {
// The NSAccessibility position of an object is in global coordinates and
// based on the lower-left corner of the object. To make this easier and less
// confusing, convert it to local window coordinates using the top-left
// corner when dumping the position.
BrowserAccessibility* root = node->manager()->GetRoot();
BrowserAccessibilityCocoa* cocoa_root = root->ToBrowserAccessibilityCocoa();
NSPoint root_position = [[cocoa_root position] pointValue];
NSSize root_size = [[cocoa_root size] sizeValue];
int root_top = -static_cast<int>(root_position.y + root_size.height);
int root_left = static_cast<int>(root_position.x);
BrowserAccessibilityCocoa* cocoa_node = node->ToBrowserAccessibilityCocoa();
NSPoint node_position = [[cocoa_node position] pointValue];
NSSize node_size = [[cocoa_node size] sizeValue];
NSString* position_str =
[NSString stringWithFormat:@"position=(%d, %d)",
static_cast<int>(node_position.x - root_left),
static_cast<int>(
-node_position.y - node_size.height - root_top)];
return UTF8ToUTF16([position_str cStringUsingEncoding:NSUTF8StringEncoding]);
} }
string16 FormatSize(BrowserAccessibility* node) {
BrowserAccessibilityCocoa* cocoa_node = node->ToBrowserAccessibilityCocoa();
NSSize node_size = [[cocoa_node size] sizeValue];
NSString* size_str =
[NSString stringWithFormat:@"size=(%d, %d)",
static_cast<int>(node_size.width),
static_cast<int>(node_size.height)];
return UTF8ToUTF16([size_str cStringUsingEncoding:NSUTF8StringEncoding]);
}
} // namespace
void DumpAccessibilityTreeHelper::Initialize() {} void DumpAccessibilityTreeHelper::Initialize() {}
string16 DumpAccessibilityTreeHelper::ToString(BrowserAccessibility* node, string16 DumpAccessibilityTreeHelper::ToString(BrowserAccessibility* node,
...@@ -63,13 +101,14 @@ string16 DumpAccessibilityTreeHelper::ToString(BrowserAccessibility* node, ...@@ -63,13 +101,14 @@ string16 DumpAccessibilityTreeHelper::ToString(BrowserAccessibility* node,
Add(false, Format(node, "numberOfCharacters='", Add(false, Format(node, "numberOfCharacters='",
@selector(numberOfCharacters), "'")); @selector(numberOfCharacters), "'"));
Add(false, Format(node, "orientation='", @selector(orientation), "'")); Add(false, Format(node, "orientation='", @selector(orientation), "'"));
Add(false, Format(node, "position='", @selector(position), "'"));
Add(false, Format(node, "required='", @selector(required), "'")); Add(false, Format(node, "required='", @selector(required), "'"));
Add(false, Format(node, "size='", @selector(size), "'"));
Add(false, Format(node, "url='", @selector(url), "'")); Add(false, Format(node, "url='", @selector(url), "'"));
Add(false, Format(node, "visibleCharacterRange='", Add(false, Format(node, "visibleCharacterRange='",
@selector(visibleCharacterRange), "'")); @selector(visibleCharacterRange), "'"));
Add(false, Format(node, "visited='", @selector(visited), "'")); Add(false, Format(node, "visited='", @selector(visited), "'"));
Add(false, FormatPosition(node));
Add(false, FormatSize(node));
return ASCIIToUTF16(prefix) + FinishLine() + ASCIIToUTF16("\n"); return ASCIIToUTF16(prefix) + FinishLine() + ASCIIToUTF16("\n");
} }
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "base/string_util.h" #include "base/string_util.h"
#include "base/stringprintf.h" #include "base/stringprintf.h"
#include "base/utf_string_conversions.h" #include "base/utf_string_conversions.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/accessibility/browser_accessibility_win.h" #include "content/browser/accessibility/browser_accessibility_win.h"
#include "content/common/accessibility_node_data.h" #include "content/common/accessibility_node_data.h"
#include "content/public/test/accessibility_test_utils_win.h" #include "content/public/test/accessibility_test_utils_win.h"
...@@ -100,10 +101,15 @@ string16 DumpAccessibilityTreeHelper::ToString( ...@@ -100,10 +101,15 @@ string16 DumpAccessibilityTreeHelper::ToString(
Add(false, L"description='" + description + L"'"); Add(false, L"description='" + description + L"'");
Add(false, L"default_action='" + default_action + L"'"); Add(false, L"default_action='" + default_action + L"'");
Add(false, L"keyboard_shortcut='" + keyboard_shortcut + L"'"); Add(false, L"keyboard_shortcut='" + keyboard_shortcut + L"'");
LONG x_left, y_top, width, height; BrowserAccessibility* root = node->manager()->GetRoot();
if (acc_obj->accLocation(&x_left, &y_top, &width, &height, variant_self) != LONG left, top, width, height;
S_FALSE) { LONG root_left, root_top, root_width, root_height;
Add(false, StringPrintf(L"location=(%d, %d)", x_left, y_top)); if (S_FALSE != acc_obj->accLocation(
&left, &top, &width, &height, variant_self) &&
S_FALSE != root->ToBrowserAccessibilityWin()->accLocation(
&root_left, &root_top, &root_width, &root_height, variant_self)) {
Add(false, StringPrintf(L"location=(%d, %d)",
left - root_left, top - root_top));
Add(false, StringPrintf(L"size=(%d, %d)", width, height)); Add(false, StringPrintf(L"size=(%d, %d)", width, height));
} }
LONG index_in_parent; LONG index_in_parent;
......
AXWebArea position=(0, 0) size=(800, 600)
AXGroup position=(0, 0) size=(300, 150)
AXButton position=(25, 25) size=(250, 50)
AXGroup position=(0, 150) size=(300, 150)
AXButton position=(25, 175) size=(250, 50)
AXGroup position=(0, 300) size=(300, 150)
AXUnknown position=(0, 300) size=(300, 100)
AXUnknown position=(0, 0) size=(0, 0)
AXWebArea position=(0, 300) size=(300, 100)
AXGroup position=(0, 300) size=(300, 100)
AXButton position=(25, 325) size=(250, 50)
AXGroup position=(0, 450) size=(300, 150)
AXUnknown position=(0, 450) size=(150, 50)
AXUnknown position=(0, 0) size=(0, 0)
AXWebArea position=(0, 450) size=(300, 100)
AXGroup position=(-150, 400) size=(300, 100)
AXButton position=(-125, 425) size=(250, 50)
AXScrollBar position=(0, 0) size=(0, 0)
AXScrollBar position=(0, 0) size=(0, 0)
ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE location=(0, 0) size=(800, 600)
IA2_ROLE_SECTION location=(0, 0) size=(300, 150)
ROLE_SYSTEM_PUSHBUTTON name='Button' FOCUSABLE location=(25, 25) size=(250, 50)
IA2_ROLE_SECTION location=(0, 150) size=(300, 150)
ROLE_SYSTEM_PUSHBUTTON name='Button' FOCUSABLE location=(25, 175) size=(250, 50)
IA2_ROLE_SECTION location=(0, 300) size=(300, 150)
ROLE_SYSTEM_CLIENT FOCUSABLE location=(0, 300) size=(300, 100)
IA2_ROLE_SCROLL_PANE location=(0, 0) size=(0, 0)
ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE location=(0, 300) size=(300, 100)
IA2_ROLE_SECTION location=(0, 300) size=(300, 100)
ROLE_SYSTEM_PUSHBUTTON name='Button' FOCUSABLE location=(25, 325) size=(250, 50)
IA2_ROLE_SECTION location=(0, 450) size=(300, 150)
ROLE_SYSTEM_CLIENT FOCUSABLE location=(0, 450) size=(150, 50)
IA2_ROLE_SCROLL_PANE location=(0, 0) size=(0, 0)
ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE location=(0, 450) size=(300, 100)
IA2_ROLE_SECTION location=(-150, 400) size=(300, 100)
ROLE_SYSTEM_PUSHBUTTON name='Button' FOCUSABLE location=(-125, 425) size=(250, 50)
ROLE_SYSTEM_SCROLLBAR location=(0, 0) size=(0, 0)
ROLE_SYSTEM_SCROLLBAR location=(0, 0) size=(0, 0)
<!doctype html>
<!--
@MAC-DENY:title*
@MAC-DENY:value*
@MAC-ALLOW:position*
@MAC-ALLOW:size*
@WIN-DENY:title*
@WIN-ALLOW:location*
@WIN-ALLOW:size*
-->
<html>
<head>
<style>
iframe {
border: 0;
margin: 0;
padding: 0;
}
div {
width: 300px;
height: 150px;
}
</style>
</head>
<body style="margin: 0; padding: 0;">
<div>
<button style="margin: 25px; border: 0; width: 250px; height: 50px">
Button
</button>
</div>
<div>
<button style="margin: 25px; border: 0; width: 250px; height: 50px">
Button
</button>
</div>
<div><iframe id="frame1" style="width: 300px; height: 100px;"></iframe></div>
<div><iframe id="frame2" style="width: 150px; height: 50px;"></iframe></div>
<script>
var frameCode =
'<body style="margin: 0; padding: 0;">\n' +
'<div style="width: 300px; height: 100px;">\n' +
' <button style="margin: 25px; border: 0; width: 250px; height: 50px">\n' +
' Button\n' +
' </button>\n' +
'</div>\n' +
'</body>\n';
function writeFrameCode(frame) {
var doc = frame.contentWindow.document;
doc.open();
doc.write(frameCode);
doc.close();
}
var frame1 = document.getElementById('frame1');
writeFrameCode(frame1);
var frame2 = document.getElementById('frame2');
writeFrameCode(frame2);
frame2.contentWindow.scrollTo(150, 50);
</script>
</body>
</html>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment