From f1a32c0101a8e0567773986d403ab92853482f75 Mon Sep 17 00:00:00 2001 From: dmazzoni Date: Tue, 23 Jun 2015 18:50:57 -0700 Subject: [PATCH] Fix accessibility objects with zero width and height. VoiceOver totally ignores a container object with zero width and height, which can happen when an object's children all come from aria-owns. BUG=489590 Review URL: https://codereview.chromium.org/1198203002 Cr-Commit-Position: refs/heads/master@{#335852} --- .../browser/accessibility/browser_accessibility.cc | 27 ++++++++++++++++++++++ .../browser/accessibility/browser_accessibility.h | 6 +++++ .../dump_accessibility_tree_browsertest.cc | 4 ++++ .../aria/aria-owns-list-expected-android.txt | 1 + .../aria/aria-owns-list-expected-mac.txt | 6 +++++ .../aria/aria-owns-list-expected-win.txt | 1 + .../data/accessibility/aria/aria-owns-list.html | 16 +++++++++++++ 7 files changed, 61 insertions(+) create mode 100644 content/test/data/accessibility/aria/aria-owns-list-expected-android.txt create mode 100644 content/test/data/accessibility/aria/aria-owns-list-expected-mac.txt create mode 100644 content/test/data/accessibility/aria/aria-owns-list-expected-win.txt create mode 100644 content/test/data/accessibility/aria/aria-owns-list.html diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc index b50a47662f01..9d4fe101afc5 100644 --- a/content/browser/accessibility/browser_accessibility.cc +++ b/content/browser/accessibility/browser_accessibility.cc @@ -188,6 +188,7 @@ BrowserAccessibility::GetHtmlAttributes() const { gfx::Rect BrowserAccessibility::GetLocalBoundsRect() const { gfx::Rect bounds = GetLocation(); + FixEmptyBounds(&bounds); return ElementBoundsToLocalBounds(bounds); } @@ -695,6 +696,32 @@ BrowserAccessibility* BrowserAccessibility::GetParentForBoundsCalculation() return manager_->delegate()->AccessibilityGetParentFrame(); } +void BrowserAccessibility::FixEmptyBounds(gfx::Rect* bounds) const +{ + if (bounds->width() > 0 && bounds->height() > 0) + return; + + for (size_t i = 0; i < InternalChildCount(); ++i) { + // Compute the bounds of each child - this calls FixEmptyBounds + // recursively if necessary. + BrowserAccessibility* child = InternalGetChild(i); + gfx::Rect child_bounds = child->GetLocalBoundsRect(); + + // Ignore children that don't have valid bounds themselves. + if (child_bounds.width() == 0 || child_bounds.height() == 0) + continue; + + // For the first valid child, just set the bounds to that child's bounds. + if (bounds->width() == 0 || bounds->height() == 0) { + *bounds = child_bounds; + continue; + } + + // Union each additional child's bounds. + bounds->Union(child_bounds); + } +} + gfx::Rect BrowserAccessibility::ElementBoundsToLocalBounds(gfx::Rect bounds) const { // Walk up the parent chain. Every time we encounter a Web Area, offset diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h index 643e5950d5a4..27f6a74c8b2f 100644 --- a/content/browser/accessibility/browser_accessibility.h +++ b/content/browser/accessibility/browser_accessibility.h @@ -283,6 +283,12 @@ class CONTENT_EXPORT BrowserAccessibility { // bounds offsets. BrowserAccessibility* GetParentForBoundsCalculation() const; + // If a bounding rectangle is empty, compute it based on the union of its + // children, since most accessibility APIs don't like elements with no + // bounds, but "virtual" elements in the accessibility tree that don't + // correspond to a layed-out element sometimes don't have bounds. + void FixEmptyBounds(gfx::Rect* bounds) const; + // Convert the bounding rectangle of an element (which is relative to // its nearest scrollable ancestor) to local bounds (which are relative // to the top of the web accessibility tree). diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc index 4ccdd78ea045..b138380a857a 100644 --- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc +++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc @@ -405,6 +405,10 @@ IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaOwns) { RunAriaTest(FILE_PATH_LITERAL("aria-owns.html")); } +IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaOwnsList) { + RunAriaTest(FILE_PATH_LITERAL("aria-owns-list.html")); +} + IN_PROC_BROWSER_TEST_F(DumpAccessibilityTreeTest, AccessibilityAriaMath) { RunAriaTest(FILE_PATH_LITERAL("aria-math.html")); } diff --git a/content/test/data/accessibility/aria/aria-owns-list-expected-android.txt b/content/test/data/accessibility/aria/aria-owns-list-expected-android.txt new file mode 100644 index 000000000000..8620d591800d --- /dev/null +++ b/content/test/data/accessibility/aria/aria-owns-list-expected-android.txt @@ -0,0 +1 @@ +# diff --git a/content/test/data/accessibility/aria/aria-owns-list-expected-mac.txt b/content/test/data/accessibility/aria/aria-owns-list-expected-mac.txt new file mode 100644 index 000000000000..27ecebdf6e52 --- /dev/null +++ b/content/test/data/accessibility/aria/aria-owns-list-expected-mac.txt @@ -0,0 +1,6 @@ +AXWebArea +++AXList size=(400, 400) +++++AXGroup AXTitle='One' size=(400, 200) +++++++AXStaticText AXValue='One' +++++AXGroup AXTitle='Two' size=(400, 200) +++++++AXStaticText AXValue='Two' diff --git a/content/test/data/accessibility/aria/aria-owns-list-expected-win.txt b/content/test/data/accessibility/aria/aria-owns-list-expected-win.txt new file mode 100644 index 000000000000..8620d591800d --- /dev/null +++ b/content/test/data/accessibility/aria/aria-owns-list-expected-win.txt @@ -0,0 +1 @@ +# diff --git a/content/test/data/accessibility/aria/aria-owns-list.html b/content/test/data/accessibility/aria/aria-owns-list.html new file mode 100644 index 000000000000..8112c6501723 --- /dev/null +++ b/content/test/data/accessibility/aria/aria-owns-list.html @@ -0,0 +1,16 @@ + + + + +
+
One
+
Two
+ + -- 2.11.4.GIT