Accessibility: Chromium needs methods to scroll an object into view or to a specific...
authordmazzoni@google.com <dmazzoni@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 18 Jan 2012 18:46:41 +0000 (18:46 +0000)
committerdmazzoni@google.com <dmazzoni@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 18 Jan 2012 18:46:41 +0000 (18:46 +0000)
https://bugs.webkit.org/show_bug.cgi?id=73460

Reviewed by Chris Fleizach.

Source/WebCore:

Tests: platform/chromium/accessibility/scroll-to-global-point-main-window.html
       platform/chromium/accessibility/scroll-to-global-point-nested.html
       platform/chromium/accessibility/scroll-to-global-point-iframe.html
       platform/chromium/accessibility/scroll-to-global-point-iframe-nested.html
       platform/chromium/accessibility/scroll-to-make-visible-div-overflow.html
       platform/chromium/accessibility/scroll-to-make-visible-iframe.html
       platform/chromium/accessibility/scroll-to-make-visible-main-window.html
       platform/chromium/accessibility/scroll-to-make-visible-nested.html
       platform/chromium/accessibility/scroll-to-make-visible-with-subfocus.html

* accessibility/AccessibilityObject.cpp:
(WebCore::computeBestScrollOffset):
(WebCore::AccessibilityObject::scrollToMakeVisible):
(WebCore::AccessibilityObject::scrollToMakeVisibleWithSubFocus):
(WebCore::AccessibilityObject::scrollToGlobalPoint):
* accessibility/AccessibilityObject.h:
(WebCore::AccessibilityObject::getScrollableAreaIfScrollable):
(WebCore::AccessibilityObject::scrollTo):
* accessibility/AccessibilityRenderObject.cpp:
(WebCore::AccessibilityRenderObject::getScrollableAreaIfScrollable):
(WebCore::AccessibilityRenderObject::scrollTo):
* accessibility/AccessibilityRenderObject.h:
* accessibility/AccessibilityScrollView.cpp:
(WebCore::AccessibilityScrollView::getScrollableAreaIfScrollable):
(WebCore::AccessibilityScrollView::scrollTo):
* accessibility/AccessibilityScrollView.h:

Source/WebKit/chromium:

* public/WebAccessibilityObject.h:
* src/WebAccessibilityObject.cpp:
(WebKit::WebAccessibilityObject::scrollToMakeVisible):
(WebKit::WebAccessibilityObject::scrollToMakeVisibleWithSubFocus):
(WebKit::WebAccessibilityObject::scrollToGlobalPoint):

Tools:

* DumpRenderTree/AccessibilityUIElement.h:
* DumpRenderTree/chromium/AccessibilityUIElement.cpp:
(AccessibilityUIElement::AccessibilityUIElement):
(AccessibilityUIElement::scrollToMakeVisibleCallback):
(AccessibilityUIElement::scrollToMakeVisibleWithSubFocusCallback):
(AccessibilityUIElement::scrollToGlobalPointCallback):
* DumpRenderTree/chromium/AccessibilityUIElement.h:
* DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
(AccessibilityUIElement::scrollToMakeVisible):
(AccessibilityUIElement::scrollToMakeVisibleWithSubFocus):
(AccessibilityUIElement::scrollToGlobalPoint):
* DumpRenderTree/mac/AccessibilityUIElementMac.mm:
(AccessibilityUIElement::scrollToMakeVisible):
(AccessibilityUIElement::scrollToMakeVisibleWithSubFocus):
(AccessibilityUIElement::scrollToGlobalPoint):
* DumpRenderTree/win/AccessibilityUIElementWin.cpp:
(AccessibilityUIElement::scrollToMakeVisible):
(AccessibilityUIElement::scrollToMakeVisibleWithSubFocus):
(AccessibilityUIElement::scrollToGlobalPoint):

LayoutTests:

* platform/chromium/accessibility/scroll-to-global-point-iframe-expected.txt: Added.
* platform/chromium/accessibility/scroll-to-global-point-iframe.html: Added.
* platform/chromium/accessibility/scroll-to-global-point-iframe-nested-expected.txt: Added.
* platform/chromium/accessibility/scroll-to-global-point-iframe-nested.html: Added.
* platform/chromium/accessibility/scroll-to-global-point-main-window-expected.txt: Added.
* platform/chromium/accessibility/scroll-to-global-point-main-window.html: Added.
* platform/chromium/accessibility/scroll-to-global-point-nested-expected.txt: Added.
* platform/chromium/accessibility/scroll-to-global-point-nested.html: Added.
* platform/chromium/accessibility/scroll-to-make-visible-div-overflow-expected.txt: Added.
* platform/chromium/accessibility/scroll-to-make-visible-div-overflow.html: Added.
* platform/chromium/accessibility/scroll-to-make-visible-iframe-expected.txt: Added.
* platform/chromium/accessibility/scroll-to-make-visible-iframe.html: Added.
* platform/chromium/accessibility/scroll-to-make-visible-main-window-expected.txt: Added.
* platform/chromium/accessibility/scroll-to-make-visible-main-window.html: Added.
* platform/chromium/accessibility/scroll-to-make-visible-nested-expected.txt: Added.
* platform/chromium/accessibility/scroll-to-make-visible-nested.html: Added.
* platform/chromium/accessibility/scroll-to-make-visible-with-subfocus-expected.txt: Added.
* platform/chromium/accessibility/scroll-to-make-visible-with-subfocus.html: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@105295 268f45cc-cd09-0410-ab3c-d52691b4dbfc

36 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/chromium/accessibility/scroll-to-global-point-iframe-expected.txt [new file with mode: 0644]
LayoutTests/platform/chromium/accessibility/scroll-to-global-point-iframe-nested-expected.txt [new file with mode: 0644]
LayoutTests/platform/chromium/accessibility/scroll-to-global-point-iframe-nested.html [new file with mode: 0644]
LayoutTests/platform/chromium/accessibility/scroll-to-global-point-iframe.html [new file with mode: 0644]
LayoutTests/platform/chromium/accessibility/scroll-to-global-point-main-window-expected.txt [new file with mode: 0644]
LayoutTests/platform/chromium/accessibility/scroll-to-global-point-main-window.html [new file with mode: 0644]
LayoutTests/platform/chromium/accessibility/scroll-to-global-point-nested-expected.txt [new file with mode: 0644]
LayoutTests/platform/chromium/accessibility/scroll-to-global-point-nested.html [new file with mode: 0644]
LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-div-overflow-expected.txt [new file with mode: 0644]
LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-div-overflow.html [new file with mode: 0644]
LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-iframe-expected.txt [new file with mode: 0644]
LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-iframe.html [new file with mode: 0644]
LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-main-window-expected.txt [new file with mode: 0644]
LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-main-window.html [new file with mode: 0644]
LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-nested-expected.txt [new file with mode: 0644]
LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-nested.html [new file with mode: 0644]
LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-with-subfocus-expected.txt [new file with mode: 0644]
LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-with-subfocus.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/accessibility/AccessibilityObject.cpp
Source/WebCore/accessibility/AccessibilityObject.h
Source/WebCore/accessibility/AccessibilityRenderObject.cpp
Source/WebCore/accessibility/AccessibilityRenderObject.h
Source/WebCore/accessibility/AccessibilityScrollView.cpp
Source/WebCore/accessibility/AccessibilityScrollView.h
Source/WebKit/chromium/ChangeLog
Source/WebKit/chromium/public/WebAccessibilityObject.h
Source/WebKit/chromium/src/WebAccessibilityObject.cpp
Tools/ChangeLog
Tools/DumpRenderTree/AccessibilityUIElement.h
Tools/DumpRenderTree/chromium/AccessibilityUIElement.cpp
Tools/DumpRenderTree/chromium/AccessibilityUIElement.h
Tools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp
Tools/DumpRenderTree/mac/AccessibilityUIElementMac.mm
Tools/DumpRenderTree/win/AccessibilityUIElementWin.cpp

index de321c3..fa069a4 100644 (file)
@@ -1,3 +1,29 @@
+2012-01-18  Dominic Mazzoni  <dmazzoni@google.com>
+
+        Accessibility: Chromium needs methods to scroll an object into view or to a specific location.
+        https://bugs.webkit.org/show_bug.cgi?id=73460
+
+        Reviewed by Chris Fleizach.
+
+        * platform/chromium/accessibility/scroll-to-global-point-iframe-expected.txt: Added.
+        * platform/chromium/accessibility/scroll-to-global-point-iframe.html: Added.
+        * platform/chromium/accessibility/scroll-to-global-point-iframe-nested-expected.txt: Added.
+        * platform/chromium/accessibility/scroll-to-global-point-iframe-nested.html: Added.
+        * platform/chromium/accessibility/scroll-to-global-point-main-window-expected.txt: Added.
+        * platform/chromium/accessibility/scroll-to-global-point-main-window.html: Added.
+        * platform/chromium/accessibility/scroll-to-global-point-nested-expected.txt: Added.
+        * platform/chromium/accessibility/scroll-to-global-point-nested.html: Added.
+        * platform/chromium/accessibility/scroll-to-make-visible-div-overflow-expected.txt: Added.
+        * platform/chromium/accessibility/scroll-to-make-visible-div-overflow.html: Added.
+        * platform/chromium/accessibility/scroll-to-make-visible-iframe-expected.txt: Added.
+        * platform/chromium/accessibility/scroll-to-make-visible-iframe.html: Added.
+        * platform/chromium/accessibility/scroll-to-make-visible-main-window-expected.txt: Added.
+        * platform/chromium/accessibility/scroll-to-make-visible-main-window.html: Added.
+        * platform/chromium/accessibility/scroll-to-make-visible-nested-expected.txt: Added.
+        * platform/chromium/accessibility/scroll-to-make-visible-nested.html: Added.
+        * platform/chromium/accessibility/scroll-to-make-visible-with-subfocus-expected.txt: Added.
+        * platform/chromium/accessibility/scroll-to-make-visible-with-subfocus.html: Added.
+
 2012-01-17  Alexey Proskuryakov  <ap@apple.com>
 
         file:// doesn't work as base URL
diff --git a/LayoutTests/platform/chromium/accessibility/scroll-to-global-point-iframe-expected.txt b/LayoutTests/platform/chromium/accessibility/scroll-to-global-point-iframe-expected.txt
new file mode 100644 (file)
index 0000000..ab7072d
--- /dev/null
@@ -0,0 +1,17 @@
+Tests that scrolling to move an element to a specific point successfully scrolls an iframe.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+5000-pixel box
+
+5000-pixel box
+PASS window.pageYOffset is 0
+PASS frameWindow.pageYOffset is 0
+PASS target.getBoundingClientRect().top is 0
+PASS target.getBoundingClientRect().top is 300
+PASS target.getBoundingClientRect().top is 3000
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/platform/chromium/accessibility/scroll-to-global-point-iframe-nested-expected.txt b/LayoutTests/platform/chromium/accessibility/scroll-to-global-point-iframe-nested-expected.txt
new file mode 100644 (file)
index 0000000..11435a3
--- /dev/null
@@ -0,0 +1,18 @@
+Tests that scrolling to move an element to a specific point successfully scrolls both an iframe and a div with overflow.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+5000-pixel box
+
+5000-pixel box
+PASS window.pageYOffset is 0
+PASS frameWindow.pageYOffset is 0
+PASS container.scrollTop is 0
+PASS target.getBoundingClientRect().top is 0
+PASS target.getBoundingClientRect().top is 300
+PASS target.getBoundingClientRect().top is 3000
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/platform/chromium/accessibility/scroll-to-global-point-iframe-nested.html b/LayoutTests/platform/chromium/accessibility/scroll-to-global-point-iframe-nested.html
new file mode 100644 (file)
index 0000000..d734029
--- /dev/null
@@ -0,0 +1,79 @@
+<html>
+<head>
+<link rel="stylesheet" href="../../../fast/js/resources/js-test-style.css">
+<script src="../../../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body>
+
+<p id="description"></p>
+
+<div style="border: 1px solid #000; height: 5000px;">5000-pixel box</div>
+
+<!-- The contents of this iframe, more nicely formatted:
+ <body>
+   <div style='border: 1px solid #000; height: 5000px;'>5000-pixel box</div>
+   <div id='container' style='height: 100px; overflow: scroll'>
+     <div style='border: 1px solid #000; height: 5000px;'>5000-pixel box</div>
+     <button id='target'>Target</button>
+     <div style='border: 1px solid #000; height: 5000px;'>5000-pixel box</div>
+   </div>
+   <div style='border: 1px solid #000; height: 5000px;'>5000-pixel box</div>
+  </body>
+ -->
+<iframe id="frame" src="data:text/html,<body><div style='border: 1px solid #000; height: 5000px;'>5000-pixel box</div><div id='container' style='height: 100px; overflow: scroll'><div style='border: 1px solid #000; height: 5000px;'>5000-pixel box</div><button id='target'>Target</button><div style='border: 1px solid #000; height: 5000px;'>5000-pixel box</div></div><div style='border: 1px solid #000; height: 5000px;'>5000-pixel box</div></body>"></iframe>
+
+<div style="border: 1px solid #000; height: 5000px;">5000-pixel box</div>
+
+<div id="console"></div>
+
+<script>
+description("Tests that scrolling to move an element to a specific point successfully scrolls both an iframe and a div with overflow.");
+
+if (window.layoutTestController)
+        layoutTestController.waitUntilDone();
+
+window.jsTestIsAsync = true;
+
+function runTest() {
+    window.frame = document.getElementById("frame");
+    window.frameWindow = frame.contentWindow;
+    window.frameDoc = frameWindow.document;
+    window.container = frameDoc.getElementById("container");
+    window.target = frameDoc.getElementById("target");
+
+    if (window.accessibilityController) {
+        target.focus();
+        var targetAccessibleObject = accessibilityController.focusedElement;
+    }
+
+    // Reset the initial scroll position (since calling focus() can scroll the page too).
+    window.scrollTo(0, 0);
+    frameWindow.scrollTo(0, 0);
+    container.scrollTop = 0;
+    shouldBe("window.pageYOffset", "0");
+    shouldBe("frameWindow.pageYOffset", "0");
+    shouldBe("container.scrollTop", "0");
+
+    // Scroll to various locations and check.
+    if (window.accessibilityController)
+        targetAccessibleObject.scrollToGlobalPoint(0, 0);
+    shouldBe("target.getBoundingClientRect().top", "0");
+    if (window.accessibilityController)
+        targetAccessibleObject.scrollToGlobalPoint(0, 300);
+    shouldBe("target.getBoundingClientRect().top", "300");
+    if (window.accessibilityController)
+        targetAccessibleObject.scrollToGlobalPoint(0, 3000);
+    shouldBe("target.getBoundingClientRect().top", "3000");
+
+    finishJSTest();
+}
+
+window.addEventListener('load', function() {
+    setTimeout(runTest, 10);
+}, false);
+
+</script>
+
+<script src="../../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/platform/chromium/accessibility/scroll-to-global-point-iframe.html b/LayoutTests/platform/chromium/accessibility/scroll-to-global-point-iframe.html
new file mode 100644 (file)
index 0000000..49a4887
--- /dev/null
@@ -0,0 +1,65 @@
+<html>
+<head>
+<link rel="stylesheet" href="../../../fast/js/resources/js-test-style.css">
+<script src="../../../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body>
+
+<p id="description"></p>
+
+<div style="border: 1px solid #000; height: 5000px;">5000-pixel box</div>
+
+<iframe id="frame" src="data:text/html,<body><div style='border: 1px solid #000; height: 5000px;'>5000-pixel box</div><button id='target'>Target</button><div style='border: 1px solid #000; height: 5000px;'>5000-pixel box</div></body>"></iframe>
+
+<div style="border: 1px solid #000; height: 5000px;">5000-pixel box</div>
+
+<div id="console"></div>
+
+<script>
+description("Tests that scrolling to move an element to a specific point successfully scrolls an iframe.");
+
+if (window.layoutTestController)
+        layoutTestController.waitUntilDone();
+
+window.jsTestIsAsync = true;
+
+function runTest() {
+    window.frame = document.getElementById("frame");
+    window.frameWindow = frame.contentWindow;
+    window.frameDoc = frameWindow.document;
+    window.target = frameDoc.getElementById("target");
+
+    if (window.accessibilityController) {
+        target.focus();
+        var targetAccessibleObject = accessibilityController.focusedElement;
+    }
+
+    // Reset the initial scroll position (since calling focus() can scroll the page too).
+    window.scrollTo(0, 0);
+    frameWindow.scrollTo(0, 0);
+    shouldBe("window.pageYOffset", "0");
+    shouldBe("frameWindow.pageYOffset", "0");
+
+    // Scroll to various locations and check.
+    if (window.accessibilityController)
+        targetAccessibleObject.scrollToGlobalPoint(0, 0);
+    shouldBe("target.getBoundingClientRect().top", "0");
+    if (window.accessibilityController)
+        targetAccessibleObject.scrollToGlobalPoint(0, 300);
+    shouldBe("target.getBoundingClientRect().top", "300");
+    if (window.accessibilityController)
+        targetAccessibleObject.scrollToGlobalPoint(0, 3000);
+    shouldBe("target.getBoundingClientRect().top", "3000");
+
+    finishJSTest();
+}
+
+window.addEventListener('load', function() {
+    setTimeout(runTest, 10);
+}, false);
+
+</script>
+
+<script src="../../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/platform/chromium/accessibility/scroll-to-global-point-main-window-expected.txt b/LayoutTests/platform/chromium/accessibility/scroll-to-global-point-main-window-expected.txt
new file mode 100644 (file)
index 0000000..d228740
--- /dev/null
@@ -0,0 +1,16 @@
+Tests that scrolling an element to a specific point successfully scrolls the main window.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+5000-pixel box
+Target
+5000-pixel box
+PASS window.pageYOffset is 0
+PASS target.getBoundingClientRect().top is 0
+PASS target.getBoundingClientRect().top is 300
+PASS target.getBoundingClientRect().top is 3000
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/platform/chromium/accessibility/scroll-to-global-point-main-window.html b/LayoutTests/platform/chromium/accessibility/scroll-to-global-point-main-window.html
new file mode 100644 (file)
index 0000000..5b17110
--- /dev/null
@@ -0,0 +1,51 @@
+<html>
+<head>
+<link rel="stylesheet" href="../../../fast/js/resources/js-test-style.css">
+<script src="../../../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body>
+
+<p id="description"></p>
+
+<div style="border: 1px solid #000; height: 5000px;">5000-pixel box</div>
+<button id="target">Target</button>
+<div style="border: 1px solid #000; height: 5000px;">5000-pixel box</div>
+
+<div id="console"></div>
+
+<script>
+description("Tests that scrolling an element to a specific point successfully scrolls the main window.");
+
+function runTest() {
+    var target = document.getElementById("target");
+
+    if (window.accessibilityController) {
+        target.focus();
+        var targetAccessibleObject = accessibilityController.focusedElement;
+    }
+
+    // Reset the initial scroll position (since calling focus() can scroll the page too).
+    window.scrollTo(0, 0);
+    shouldBe("window.pageYOffset", "0");
+
+    // Scroll to various locations and check.
+    if (window.accessibilityController)
+        targetAccessibleObject.scrollToGlobalPoint(0, 0);
+    shouldBe("target.getBoundingClientRect().top", "0");
+    if (window.accessibilityController)
+        targetAccessibleObject.scrollToGlobalPoint(0, 300);
+    shouldBe("target.getBoundingClientRect().top", "300");
+    if (window.accessibilityController)
+        targetAccessibleObject.scrollToGlobalPoint(0, 3000);
+    shouldBe("target.getBoundingClientRect().top", "3000");
+
+    finishJSTest();
+}
+
+runTest();
+
+</script>
+
+<script src="../../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/platform/chromium/accessibility/scroll-to-global-point-nested-expected.txt b/LayoutTests/platform/chromium/accessibility/scroll-to-global-point-nested-expected.txt
new file mode 100644 (file)
index 0000000..a81a1fd
--- /dev/null
@@ -0,0 +1,23 @@
+Tests that scrolling an element to a specific point can successfully scroll multiple nested scrolling views'.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+5000-pixel box
+5000-pixel box
+5000-pixel box
+Target
+5000-pixel box
+5000-pixel box
+5000-pixel box
+PASS window.pageYOffset is 0
+PASS outerContainer.scrollTop is 0
+PASS innerContainer.scrollTop is 0
+PASS target.getBoundingClientRect().top is >= 15000
+PASS target.getBoundingClientRect().top is 0
+PASS target.getBoundingClientRect().top is 300
+PASS target.getBoundingClientRect().top is 3000
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/platform/chromium/accessibility/scroll-to-global-point-nested.html b/LayoutTests/platform/chromium/accessibility/scroll-to-global-point-nested.html
new file mode 100644 (file)
index 0000000..5c6ea82
--- /dev/null
@@ -0,0 +1,71 @@
+<html>
+<head>
+<link rel="stylesheet" href="../../../fast/js/resources/js-test-style.css">
+<script src="../../../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body>
+
+<p id="description"></p>
+
+<div style="border: 1px solid #000; height: 5000px;">5000-pixel box</div>
+
+<div id="outer_container" style="height: 100px; overflow: scroll">
+  <div style="border: 1px solid #000; height: 5000px;">5000-pixel box</div>
+  <div id="inner_container" style="height: 100px; overflow: scroll">
+    <div style="border: 1px solid #000; height: 5000px;">5000-pixel box</div>
+    <button id="target">Target</button>
+    <div style="border: 1px solid #000; height: 5000px;">5000-pixel box</div>
+  </div>
+  <div style="border: 1px solid #000; height: 5000px;">5000-pixel box</div>
+</div>
+
+<div style="border: 1px solid #000; height: 5000px;">5000-pixel box</div>
+
+<div id="console"></div>
+
+<script>
+description("Tests that scrolling an element to a specific point can successfully scroll multiple nested scrolling views'.");
+
+function runTest() {
+    window.outerContainer = document.getElementById("outer_container");
+    window.innerContainer = document.getElementById("inner_container");
+    window.target = document.getElementById("target");
+
+    if (window.accessibilityController) {
+        target.focus();
+        var targetAccessibleObject = accessibilityController.focusedElement;
+    }
+
+    // Reset the initial scroll positions (since calling focus() can scroll the page too).
+    window.scrollTo(0, 0);
+    outerContainer.scrollTop = 0;
+    innerContainer.scrollTop = 0;
+    shouldBe("window.pageYOffset", "0");
+    shouldBe("outerContainer.scrollTop", "0");
+    shouldBe("innerContainer.scrollTop", "0");
+    shouldBeGreaterThanOrEqual("target.getBoundingClientRect().top", "15000");
+
+    // Scroll to various locations and check.
+
+    if (window.accessibilityController)
+        targetAccessibleObject.scrollToGlobalPoint(0, 0);
+    shouldBe("target.getBoundingClientRect().top", "0");
+
+    if (window.accessibilityController)
+        targetAccessibleObject.scrollToGlobalPoint(0, 300);
+    shouldBe("target.getBoundingClientRect().top", "300");
+
+    if (window.accessibilityController)
+        targetAccessibleObject.scrollToGlobalPoint(0, 3000);
+    shouldBe("target.getBoundingClientRect().top", "3000");
+
+  finishJSTest();
+}
+
+runTest();
+
+</script>
+
+<script src="../../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-div-overflow-expected.txt b/LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-div-overflow-expected.txt
new file mode 100644 (file)
index 0000000..cc2ea60
--- /dev/null
@@ -0,0 +1,17 @@
+Tests that scrolling to make an element visible successfully scrolls an arbitrary HTML element that has CSS overflow set to 'scroll'.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Upper Target
+5000-pixel box
+Lower Target
+PASS container.scrollTop is 0
+PASS container.scrollTop is >= 4952
+PASS 5030 is >= container.scrollTop
+PASS container.scrollTop is >= -76
+PASS 2 is >= container.scrollTop
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-div-overflow.html b/LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-div-overflow.html
new file mode 100644 (file)
index 0000000..333cbb1
--- /dev/null
@@ -0,0 +1,64 @@
+<html>
+<head>
+<link rel="stylesheet" href="../../../fast/js/resources/js-test-style.css">
+<script src="../../../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body>
+
+<p id="description"></p>
+
+<div id="container" style="height: 100px; overflow: scroll">
+  <button id="upper_target">Upper Target</button>
+  <div style="border: 1px solid #000; height: 5000px;">5000-pixel box</div>
+  <button id="lower_target">Lower Target</button>
+</div>
+
+<div id="console"></div>
+
+<script>
+description("Tests that scrolling to make an element visible successfully scrolls an arbitrary HTML element that has CSS overflow set to 'scroll'.");
+
+function runTest() {
+    window.container = document.getElementById("container");
+    var upperTarget = document.getElementById("upper_target");
+    var lowerTarget = document.getElementById("lower_target");
+
+    if (window.accessibilityController) {
+        lowerTarget.focus();
+        var lowerTargetAccessibleObject = accessibilityController.focusedElement;
+        upperTarget.focus();
+        var upperTargetAccessibleObject = accessibilityController.focusedElement;
+    }
+
+    // Reset the initial scroll position (since calling focus() can scroll the page too).
+    container.scrollTop = 0;
+    shouldBe("container.scrollTop", "0");
+
+    // Scroll to make lower target visible and check.
+    if (window.accessibilityController)
+        lowerTargetAccessibleObject.scrollToMakeVisible();
+    var top = lowerTarget.offsetTop - container.offsetTop;
+    var minYOffset = top + lowerTarget.offsetHeight - container.offsetHeight;
+    var maxYOffset = top;
+    shouldBeGreaterThanOrEqual("container.scrollTop", "" + minYOffset);
+    shouldBeGreaterThanOrEqual("" + maxYOffset, "container.scrollTop");
+
+    // Scroll to make upper target visible and check.
+    if (window.accessibilityController)
+        upperTargetAccessibleObject.scrollToMakeVisible();
+    top = upperTarget.offsetTop - container.offsetTop;
+    minYOffset = top + upperTarget.offsetHeight - container.offsetHeight;
+    maxYOffset = top;
+    shouldBeGreaterThanOrEqual("container.scrollTop", "" + minYOffset);
+    shouldBeGreaterThanOrEqual("" + maxYOffset, "container.scrollTop");
+
+    finishJSTest();
+}
+
+runTest();
+
+</script>
+
+<script src="../../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-iframe-expected.txt b/LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-iframe-expected.txt
new file mode 100644 (file)
index 0000000..9b13028
--- /dev/null
@@ -0,0 +1,15 @@
+Tests that scrolling to make an element visible successfully scrolls an iframe.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+
+PASS frameWindow.pageYOffset is 0
+PASS frameWindow.pageYOffset is >= 4910
+PASS 5038 is >= frameWindow.pageYOffset
+PASS frameWindow.pageYOffset is >= -118
+PASS 10 is >= frameWindow.pageYOffset
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-iframe.html b/LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-iframe.html
new file mode 100644 (file)
index 0000000..41a0e39
--- /dev/null
@@ -0,0 +1,68 @@
+<html>
+<head>
+<link rel="stylesheet" href="../../../fast/js/resources/js-test-style.css">
+<script src="../../../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body>
+
+<p id="description"></p>
+
+<iframe id="frame" src="data:text/html,<body><button id='upper_target'>Upper Target</button><div style='border: 1px solid #000; height: 5000px;'>5000-pixel box</div><button id='lower_target'>Lower Target</button></body>"></iframe>
+
+<div id="console"></div>
+
+<script>
+description("Tests that scrolling to make an element visible successfully scrolls an iframe.");
+
+if (window.layoutTestController)
+        layoutTestController.waitUntilDone();
+
+window.jsTestIsAsync = true;
+
+function runTest() {
+    window.frame = document.getElementById("frame");
+    window.frameWindow = frame.contentWindow;
+    window.frameDoc = frameWindow.document;
+
+    var upperTarget = frameDoc.getElementById("upper_target");
+    var lowerTarget = frameDoc.getElementById("lower_target");
+
+    if (window.accessibilityController) {
+        lowerTarget.focus();
+        var lowerTargetAccessibleObject = accessibilityController.focusedElement;
+        upperTarget.focus();
+        var upperTargetAccessibleObject = accessibilityController.focusedElement;
+    }
+
+    // Reset the initial scroll position (since calling focus() can scroll the page too).
+    frameWindow.scrollTo(0, 0);
+    shouldBe("frameWindow.pageYOffset", "0");
+
+    // Scroll to make lower target visible and check.
+    if (window.accessibilityController)
+        lowerTargetAccessibleObject.scrollToMakeVisible();
+    var minYOffset = lowerTarget.offsetTop + lowerTarget.offsetHeight - frameWindow.innerHeight;
+    var maxYOffset = lowerTarget.offsetTop;
+    shouldBeGreaterThanOrEqual("frameWindow.pageYOffset", "" + minYOffset);
+    shouldBeGreaterThanOrEqual("" + maxYOffset, "frameWindow.pageYOffset");
+
+    // Scroll to make upper target visible and check.
+    if (window.accessibilityController)
+        upperTargetAccessibleObject.scrollToMakeVisible();
+    minYOffset = upperTarget.offsetTop + upperTarget.offsetHeight - frameWindow.innerHeight;
+    maxYOffset = upperTarget.offsetTop;
+    shouldBeGreaterThanOrEqual("frameWindow.pageYOffset", "" + minYOffset);
+    shouldBeGreaterThanOrEqual("" + maxYOffset, "frameWindow.pageYOffset");
+
+    finishJSTest();
+}
+
+window.addEventListener('load', function() {
+    setTimeout(runTest, 10);
+}, false);
+
+</script>
+
+<script src="../../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-main-window-expected.txt b/LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-main-window-expected.txt
new file mode 100644 (file)
index 0000000..0e61812
--- /dev/null
@@ -0,0 +1,17 @@
+Tests that scrolling to make an element visible successfully scrolls the main window.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Upper Target
+5000-pixel box
+Lower Target
+PASS window.pageYOffset is 0
+PASS window.pageYOffset is >= 4532
+PASS 5110 is >= window.pageYOffset
+PASS window.pageYOffset is >= -496
+PASS 82 is >= window.pageYOffset
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-main-window.html b/LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-main-window.html
new file mode 100644 (file)
index 0000000..383bd13
--- /dev/null
@@ -0,0 +1,59 @@
+<html>
+<head>
+<link rel="stylesheet" href="../../../fast/js/resources/js-test-style.css">
+<script src="../../../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body>
+
+<p id="description"></p>
+
+<button id="upper_target">Upper Target</button>
+<div style="border: 1px solid #000; height: 5000px;">5000-pixel box</div>
+<button id="lower_target">Lower Target</button>
+
+<div id="console"></div>
+
+<script>
+description("Tests that scrolling to make an element visible successfully scrolls the main window.");
+
+function runTest() {
+    var upperTarget = document.getElementById("upper_target");
+    var lowerTarget = document.getElementById("lower_target");
+
+    if (window.accessibilityController) {
+        lowerTarget.focus();
+        var lowerTargetAccessibleObject = accessibilityController.focusedElement;
+        upperTarget.focus();
+        var upperTargetAccessibleObject = accessibilityController.focusedElement;
+    }
+
+    // Reset the initial scroll position (since calling focus() can scroll the page too).
+    window.scrollTo(0, 0);
+    shouldBe("window.pageYOffset", "0");
+
+    // Scroll to make lower target visible and check.
+    if (window.accessibilityController)
+        lowerTargetAccessibleObject.scrollToMakeVisible();
+    var minYOffset = lowerTarget.offsetTop + lowerTarget.offsetHeight - window.innerHeight;
+    var maxYOffset = lowerTarget.offsetTop;
+    shouldBeGreaterThanOrEqual("window.pageYOffset", "" + minYOffset);
+    shouldBeGreaterThanOrEqual("" + maxYOffset, "window.pageYOffset");
+
+    // Scroll to make upper target visible and check.
+    if (window.accessibilityController)
+        upperTargetAccessibleObject.scrollToMakeVisible();
+    minYOffset = upperTarget.offsetTop + upperTarget.offsetHeight - window.innerHeight;
+    maxYOffset = upperTarget.offsetTop;
+    shouldBeGreaterThanOrEqual("window.pageYOffset", "" + minYOffset);
+    shouldBeGreaterThanOrEqual("" + maxYOffset, "window.pageYOffset");
+
+    finishJSTest();
+}
+
+runTest();
+
+</script>
+
+<script src="../../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-nested-expected.txt b/LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-nested-expected.txt
new file mode 100644 (file)
index 0000000..d3df09f
--- /dev/null
@@ -0,0 +1,18 @@
+Tests that scrolling to make an element visible successfully scrolls multiple nested scrolling views'.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+5000-pixel box
+5000-pixel box
+5000-pixel box
+Target
+PASS window.pageYOffset is 0
+PASS outerContainer.scrollTop is 0
+PASS innerContainer.scrollTop is 0
+PASS target.getBoundingClientRect().top is >= 15000
+PASS window.innerHeight is >= target.getBoundingClientRect().bottom
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-nested.html b/LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-nested.html
new file mode 100644 (file)
index 0000000..1c56832
--- /dev/null
@@ -0,0 +1,61 @@
+<html>
+<head>
+<link rel="stylesheet" href="../../../fast/js/resources/js-test-style.css">
+<script src="../../../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body>
+
+<p id="description"></p>
+
+<div style="border: 1px solid #000; height: 5000px;">5000-pixel box</div>
+
+<div id="outer_container" style="height: 100px; overflow: scroll">
+  <div style="border: 1px solid #000; height: 5000px;">5000-pixel box</div>
+  <div id="inner_container" style="height: 100px; overflow: scroll">
+    <div style="border: 1px solid #000; height: 5000px;">5000-pixel box</div>
+    <button id="target">Target</button>
+  </div>
+</div>
+
+<div id="console"></div>
+
+<script>
+description("Tests that scrolling to make an element visible successfully scrolls multiple nested scrolling views'.");
+
+function runTest() {
+    window.outerContainer = document.getElementById("outer_container");
+    window.innerContainer = document.getElementById("inner_container");
+    window.target = document.getElementById("target");
+
+    if (window.accessibilityController) {
+        target.focus();
+        var targetAccessibleObject = accessibilityController.focusedElement;
+    }
+
+    // Reset the initial scroll positions (since calling focus() can scroll the page too).
+    window.scrollTo(0, 0);
+    outerContainer.scrollTop = 0;
+    innerContainer.scrollTop = 0;
+    shouldBe("window.pageYOffset", "0");
+    shouldBe("outerContainer.scrollTop", "0");
+    shouldBe("innerContainer.scrollTop", "0");
+    shouldBeGreaterThanOrEqual("target.getBoundingClientRect().top", "15000");
+
+    // Scroll to make target visible.
+    if (window.accessibilityController)
+        targetAccessibleObject.scrollToMakeVisible();
+
+    // Instead of testing the exact scroll offsets of the two containers, just test that
+    // the new absolute position of the target is on-screen.
+    shouldBeGreaterThanOrEqual("window.innerHeight", "target.getBoundingClientRect().bottom");
+
+    finishJSTest();
+}
+
+runTest();
+
+</script>
+
+<script src="../../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-with-subfocus-expected.txt b/LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-with-subfocus-expected.txt
new file mode 100644 (file)
index 0000000..d3f6e33
--- /dev/null
@@ -0,0 +1,14 @@
+Tests that scrolling to make a certain region within an element visible successfully scrolls the main window.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+5000-pixel box
+Target
+PASS window.pageYOffset is 0
+PASS window.pageYOffset is >= 6982
+PASS 7582 is >= window.pageYOffset
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-with-subfocus.html b/LayoutTests/platform/chromium/accessibility/scroll-to-make-visible-with-subfocus.html
new file mode 100644 (file)
index 0000000..13bbefb
--- /dev/null
@@ -0,0 +1,47 @@
+<html>
+<head>
+<link rel="stylesheet" href="../../../fast/js/resources/js-test-style.css">
+<script src="../../../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body>
+
+<p id="description"></p>
+
+<div style="border: 1px solid #000; height: 5000px;">5000-pixel box</div>
+<button id="target" style="height: 5000px;">Target</button>
+
+<div id="console"></div>
+
+<script>
+description("Tests that scrolling to make a certain region within an element visible successfully scrolls the main window.");
+
+function runTest() {
+    var target = document.getElementById("target");
+
+    if (window.accessibilityController) {
+        target.focus();
+        var targetAccessibleObject = accessibilityController.focusedElement;
+    }
+
+    // Reset the initial scroll position (since calling focus() can scroll the page too).
+    window.scrollTo(0, 0);
+    shouldBe("window.pageYOffset", "0");
+
+    // Scroll to make the midpoint of the target visible and check.
+    if (window.accessibilityController)
+        targetAccessibleObject.scrollToMakeVisibleWithSubFocus(0, 2500, 100, 2600);
+    var minYOffset = target.offsetTop + 2500 - window.innerHeight;
+    var maxYOffset = target.offsetTop + 2500;
+    shouldBeGreaterThanOrEqual("window.pageYOffset", "" + minYOffset);
+    shouldBeGreaterThanOrEqual("" + maxYOffset, "window.pageYOffset");
+
+    finishJSTest();
+}
+
+runTest();
+
+</script>
+
+<script src="../../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
index 926bf33..df1eadd 100644 (file)
@@ -1,3 +1,37 @@
+2012-01-18  Dominic Mazzoni  <dmazzoni@google.com>
+
+        Accessibility: Chromium needs methods to scroll an object into view or to a specific location.
+        https://bugs.webkit.org/show_bug.cgi?id=73460
+
+        Reviewed by Chris Fleizach.
+
+        Tests: platform/chromium/accessibility/scroll-to-global-point-main-window.html
+               platform/chromium/accessibility/scroll-to-global-point-nested.html
+               platform/chromium/accessibility/scroll-to-global-point-iframe.html
+               platform/chromium/accessibility/scroll-to-global-point-iframe-nested.html
+               platform/chromium/accessibility/scroll-to-make-visible-div-overflow.html
+               platform/chromium/accessibility/scroll-to-make-visible-iframe.html
+               platform/chromium/accessibility/scroll-to-make-visible-main-window.html
+               platform/chromium/accessibility/scroll-to-make-visible-nested.html
+               platform/chromium/accessibility/scroll-to-make-visible-with-subfocus.html
+
+        * accessibility/AccessibilityObject.cpp:
+        (WebCore::computeBestScrollOffset):
+        (WebCore::AccessibilityObject::scrollToMakeVisible):
+        (WebCore::AccessibilityObject::scrollToMakeVisibleWithSubFocus):
+        (WebCore::AccessibilityObject::scrollToGlobalPoint):
+        * accessibility/AccessibilityObject.h:
+        (WebCore::AccessibilityObject::getScrollableAreaIfScrollable):
+        (WebCore::AccessibilityObject::scrollTo):
+        * accessibility/AccessibilityRenderObject.cpp:
+        (WebCore::AccessibilityRenderObject::getScrollableAreaIfScrollable):
+        (WebCore::AccessibilityRenderObject::scrollTo):
+        * accessibility/AccessibilityRenderObject.h:
+        * accessibility/AccessibilityScrollView.cpp:
+        (WebCore::AccessibilityScrollView::getScrollableAreaIfScrollable):
+        (WebCore::AccessibilityScrollView::scrollTo):
+        * accessibility/AccessibilityScrollView.h:
+
 2012-01-17  Alexey Proskuryakov  <ap@apple.com>
 
         file:// doesn't work as base URL
index 2db0222..1b8cd98 100644 (file)
@@ -1505,5 +1505,178 @@ AccessibilityButtonState AccessibilityObject::checkboxOrRadioValue() const
     
     return ButtonStateOff;
 }
+
+// This is a 1-dimensional scroll offset helper function that's applied
+// separately in the horizontal and vertical directions, because the
+// logic is the same. The goal is to compute the best scroll offset
+// in order to make an object visible within a viewport.
+//
+// In case the whole object cannot fit, you can specify a
+// subfocus - a smaller region within the object that should
+// be prioritized. If the whole object can fit, the subfocus is
+// ignored.
+//
+// Example: the viewport is scrolled to the right just enough
+// that the object is in view.
+//   Before:
+//   +----------Viewport---------+
+//                         +---Object---+
+//                         +--SubFocus--+
+//
+//   After:
+//          +----------Viewport---------+
+//                         +---Object---+
+//                         +--SubFocus--+
+//
+// When constraints cannot be fully satisfied, the min
+// (left/top) position takes precedence over the max (right/bottom).
+//
+// Note that the return value represents the ideal new scroll offset.
+// This may be out of range - the calling function should clip this
+// to the available range.
+static int computeBestScrollOffset(int currentScrollOffset,
+                                   int subfocusMin, int subfocusMax,
+                                   int objectMin, int objectMax,
+                                   int viewportMin, int viewportMax) {
+    int viewportSize = viewportMax - viewportMin;
+
+    // If the focus size is larger than the viewport size, shrink it in the
+    // direction of subfocus.
+    if (objectMax - objectMin > viewportSize) {
+        // Subfocus must be within focus:
+        subfocusMin = std::max(subfocusMin, objectMin);
+        subfocusMax = std::min(subfocusMax, objectMax);
+
+        // Subfocus must be no larger than the viewport size; favor top/left.
+        if (subfocusMax - subfocusMin > viewportSize)
+            subfocusMax = subfocusMin + viewportSize;
+
+        if (subfocusMin + viewportSize > objectMax)
+            objectMin = objectMax - viewportSize;
+        else {
+            objectMin = subfocusMin;
+            objectMax = subfocusMin + viewportSize;
+        }
+    }
+
+    // Exit now if the focus is already within the viewport.
+    if (objectMin - currentScrollOffset >= viewportMin
+        && objectMax - currentScrollOffset <= viewportMax)
+        return currentScrollOffset;
+
+    // Scroll left if we're too far to the right.
+    if (objectMax - currentScrollOffset > viewportMax)
+        return objectMax - viewportMax;
+
+    // Scroll right if we're too far to the left.
+    if (objectMin - currentScrollOffset < viewportMin)
+        return objectMin - viewportMin;
+
+    ASSERT_NOT_REACHED();
+
+    // This shouldn't happen.
+    return currentScrollOffset;
+}
+
+void AccessibilityObject::scrollToMakeVisible() const
+{
+    IntRect objectRect = boundingBoxRect();
+    objectRect.move(-objectRect.x(), -objectRect.y());
+    scrollToMakeVisibleWithSubFocus(objectRect);
+}
+
+void AccessibilityObject::scrollToMakeVisibleWithSubFocus(const IntRect& subfocus) const
+{
+    // Search up the parent chain until we find the first one that's scrollable.
+    AccessibilityObject* scrollParent = parentObject();
+    ScrollableArea* scrollableArea;
+    for (scrollableArea = 0;
+         scrollParent && !(scrollableArea = scrollParent->getScrollableAreaIfScrollable());
+         scrollParent = scrollParent->parentObject()) { }
+    if (!scrollableArea)
+        return;
+
+    LayoutRect objectRect = boundingBoxRect();
+    IntPoint scrollPosition = scrollableArea->scrollPosition();
+    IntRect scrollVisibleRect = scrollableArea->visibleContentRect();
+
+    int desiredX = computeBestScrollOffset(
+        scrollPosition.x(),
+        objectRect.x() + subfocus.x(), objectRect.x() + subfocus.maxX(),
+        objectRect.x(), objectRect.maxX(),
+        0, scrollVisibleRect.width());
+    int desiredY = computeBestScrollOffset(
+        scrollPosition.y(),
+        objectRect.y() + subfocus.y(), objectRect.y() + subfocus.maxY(),
+        objectRect.y(), objectRect.maxY(),
+        0, scrollVisibleRect.height());
+
+    scrollParent->scrollTo(IntPoint(desiredX, desiredY));
+
+    // Recursively make sure the scroll parent itself is visible.
+    if (scrollParent->parentObject())
+        scrollParent->scrollToMakeVisible();
+}
+
+void AccessibilityObject::scrollToGlobalPoint(const IntPoint& globalPoint) const
+{
+    // Search up the parent chain and create a vector of all scrollable parent objects
+    // and ending with this object itself.
+    Vector<const AccessibilityObject*> objects;
+    AccessibilityObject* parentObject;
+    for (parentObject = this->parentObject(); parentObject; parentObject = parentObject->parentObject()) {
+        if (parentObject->getScrollableAreaIfScrollable())
+            objects.prepend(parentObject);
+    }
+    objects.append(this);
+
+    // Start with the outermost scrollable (the main window) and try to scroll the
+    // next innermost object to the given point.
+    int offsetX = 0, offsetY = 0;
+    IntPoint point = globalPoint;
+    size_t levels = objects.size() - 1;
+    for (size_t i = 0; i < levels; i++) {
+        const AccessibilityObject* outer = objects[i];
+        const AccessibilityObject* inner = objects[i + 1];
+
+        ScrollableArea* scrollableArea = outer->getScrollableAreaIfScrollable();
+
+        LayoutRect innerRect = inner->isAccessibilityScrollView() ? inner->parentObject()->boundingBoxRect() : inner->boundingBoxRect();
+        LayoutRect objectRect = innerRect;
+        IntPoint scrollPosition = scrollableArea->scrollPosition();
+
+        // Convert the object rect into local coordinates.
+        objectRect.move(offsetX, offsetY);
+        if (!outer->isAccessibilityScrollView())
+            objectRect.move(scrollPosition.x(), scrollPosition.y());
+
+        int desiredX = computeBestScrollOffset(
+            0,
+            objectRect.x(), objectRect.maxX(),
+            objectRect.x(), objectRect.maxX(),
+            point.x(), point.x());
+        int desiredY = computeBestScrollOffset(
+            0,
+            objectRect.y(), objectRect.maxY(),
+            objectRect.y(), objectRect.maxY(),
+            point.y(), point.y());
+        outer->scrollTo(IntPoint(desiredX, desiredY));
+
+        if (outer->isAccessibilityScrollView() && !inner->isAccessibilityScrollView()) {
+            // If outer object we just scrolled is a scroll view (main window or iframe) but the
+            // inner object is not, keep track of the coordinate transformation to apply to
+            // future nested calculations.
+            scrollPosition = scrollableArea->scrollPosition();
+            offsetX -= (scrollPosition.x() + point.x());
+            offsetY -= (scrollPosition.y() + point.y());
+            point.move(scrollPosition.x() - innerRect.x(),
+                       scrollPosition.y() - innerRect.y());
+        } else if (inner->isAccessibilityScrollView()) {
+            // Otherwise, if the inner object is a scroll view, reset the coordinate transformation.
+            offsetX = 0;
+            offsetY = 0;
+        }
+    }
+}
     
 } // namespace WebCore
index 737e2df..bd5741c 100644 (file)
@@ -84,6 +84,7 @@ class Node;
 class Page;
 class RenderObject;
 class RenderListItem;
+class ScrollableArea;
 class VisibleSelection;
 class Widget;
 
@@ -642,7 +643,14 @@ public:
     
     // CSS3 Speech properties.
     virtual ESpeak speakProperty() const { return SpeakNormal; }
-    
+
+    // Make this object visible by scrolling as many nested scrollable views as needed.
+    virtual void scrollToMakeVisible() const;
+    // Same, but if the whole object can't be made visible, try for this subrect, in local coordinates.
+    virtual void scrollToMakeVisibleWithSubFocus(const IntRect&) const;
+    // Scroll this object to a given point in global coordinates of the top-level window.
+    virtual void scrollToGlobalPoint(const IntPoint&) const;
+
 #if HAVE(ACCESSIBILITY)
 #if PLATFORM(GTK)
     AccessibilityObjectWrapper* wrapper() const;
@@ -676,6 +684,10 @@ protected:
     mutable bool m_haveChildren;
     AccessibilityRole m_role;
     
+    // If this object itself scrolls, return its ScrollableArea.
+    virtual ScrollableArea* getScrollableAreaIfScrollable() const { return 0; }
+    virtual void scrollTo(const IntPoint&) const { }
+
     virtual bool isDetached() const { return true; }
     static bool isAccessibilityObjectSearchMatch(AccessibilityObject*, AccessibilitySearchCriteria*);
     static bool isAccessibilityTextSearchMatch(AccessibilityObject*, AccessibilitySearchCriteria*);
index 942f200..dc0d33b 100644 (file)
@@ -3937,4 +3937,33 @@ AccessibilityRole AccessibilityRenderObject::roleValueForMSAA() const
     return m_roleForMSAA;
 }
 
+ScrollableArea* AccessibilityRenderObject::getScrollableAreaIfScrollable() const
+{
+    // If the parent is a scroll view, then this object isn't really scrollable, the parent ScrollView should handle the scrolling.
+    if (parentObject() && parentObject()->isAccessibilityScrollView())
+        return 0;
+
+    if (!m_renderer || !m_renderer->isBox())
+        return 0;
+
+    RenderBox* box = toRenderBox(m_renderer);
+    if (!box->canBeScrolledAndHasScrollableArea())
+        return 0;
+
+    return box->layer();
+}
+
+void AccessibilityRenderObject::scrollTo(const IntPoint& point) const
+{
+    if (!m_renderer || !m_renderer->isBox())
+        return;
+
+    RenderBox* box = toRenderBox(m_renderer);
+    if (!box->canBeScrolledAndHasScrollableArea())
+        return;
+
+    RenderLayer* layer = box->layer();
+    layer->scrollToOffset(point.x(), point.y(), RenderLayer::ScrollOffsetClamped);
+}
+
 } // namespace WebCore
index e651805..3ea5809 100644 (file)
@@ -266,6 +266,8 @@ protected:
     void setRenderObject(RenderObject* renderer) { m_renderer = renderer; }
     void ariaLabeledByElements(Vector<Element*>& elements) const;
     bool needsToUpdateChildren() const { return m_childrenDirty; }
+    ScrollableArea* getScrollableAreaIfScrollable() const;
+    void scrollTo(const IntPoint&) const;
     
     virtual bool isDetached() const { return !m_renderer; }
 
index 30be1b1..537b094 100644 (file)
@@ -214,4 +214,14 @@ AccessibilityObject* AccessibilityScrollView::parentObjectIfExists() const
     return 0;
 }
 
+ScrollableArea* AccessibilityScrollView::getScrollableAreaIfScrollable() const
+{
+    return m_scrollView.get();
+}
+
+void AccessibilityScrollView::scrollTo(const IntPoint& point) const
+{
+    m_scrollView->setScrollPosition(point);
+}
+
 } // namespace WebCore    
index 3486f9b..c65b262 100644 (file)
@@ -39,6 +39,10 @@ public:
     static PassRefPtr<AccessibilityScrollView> create(ScrollView*);    
     virtual AccessibilityRole roleValue() const { return ScrollAreaRole; }
     ScrollView* scrollView() const { return m_scrollView.get(); }
+
+protected:
+    virtual ScrollableArea* getScrollableAreaIfScrollable() const;
+    virtual void scrollTo(const IntPoint&) const;
     
 private:
     AccessibilityScrollView(ScrollView*);
@@ -86,4 +90,3 @@ inline AccessibilityScrollView* toAccessibilityScrollView(AccessibilityObject* o
 } // namespace WebCore
 
 #endif // AccessibilityScrollView_h
-
index d9d3396..b678d6c 100644 (file)
@@ -1,3 +1,16 @@
+2012-01-18  Dominic Mazzoni  <dmazzoni@google.com>
+
+        Accessibility: Chromium needs methods to scroll an object into view or to a specific location.
+        https://bugs.webkit.org/show_bug.cgi?id=73460
+
+        Reviewed by Chris Fleizach.
+
+        * public/WebAccessibilityObject.h:
+        * src/WebAccessibilityObject.cpp:
+        (WebKit::WebAccessibilityObject::scrollToMakeVisible):
+        (WebKit::WebAccessibilityObject::scrollToMakeVisibleWithSubFocus):
+        (WebKit::WebAccessibilityObject::scrollToGlobalPoint):
+
 2012-01-17  Sheriff Bot  <webkit.review.bot@gmail.com>
 
         Unreviewed, rolling out r105244.
index 9c67b77..c52b830 100644 (file)
@@ -164,6 +164,13 @@ public:
     WEBKIT_EXPORT unsigned cellRowIndex() const;
     WEBKIT_EXPORT unsigned cellRowSpan() const;
 
+    // Make this object visible by scrolling as many nested scrollable views as needed.
+    WEBKIT_EXPORT void scrollToMakeVisible() const;
+    // Same, but if the whole object can't be made visible, try for this subrect, in local coordinates.
+    WEBKIT_EXPORT void scrollToMakeVisibleWithSubFocus(const WebRect&) const;
+    // Scroll this object to a given point in global coordinates of the top-level window.
+    WEBKIT_EXPORT void scrollToGlobalPoint(const WebPoint&) const;
+
 #if WEBKIT_IMPLEMENTATION
     WebAccessibilityObject(const WTF::PassRefPtr<WebCore::AccessibilityObject>&);
     WebAccessibilityObject& operator=(const WTF::PassRefPtr<WebCore::AccessibilityObject>&);
index 806bfd8..489347b 100644 (file)
@@ -870,6 +870,24 @@ unsigned WebAccessibilityObject::cellRowSpan() const
     return rowRange.second;
 }
 
+void WebAccessibilityObject::scrollToMakeVisible() const
+{
+    m_private->updateBackingStore();
+    m_private->scrollToMakeVisible();
+}
+
+void WebAccessibilityObject::scrollToMakeVisibleWithSubFocus(const WebRect& subfocus) const
+{
+    m_private->updateBackingStore();
+    m_private->scrollToMakeVisibleWithSubFocus(subfocus);
+}
+
+void WebAccessibilityObject::scrollToGlobalPoint(const WebPoint& point) const
+{
+    m_private->updateBackingStore();
+    m_private->scrollToGlobalPoint(point);
+}
+
 WebAccessibilityObject::WebAccessibilityObject(const WTF::PassRefPtr<WebCore::AccessibilityObject>& object)
     : m_private(object)
 {
index 17ac3b3..31440e3 100644 (file)
@@ -1,3 +1,30 @@
+2012-01-18  Dominic Mazzoni  <dmazzoni@google.com>
+
+        Accessibility: Chromium needs methods to scroll an object into view or to a specific location.
+        https://bugs.webkit.org/show_bug.cgi?id=73460
+
+        Reviewed by Chris Fleizach.
+
+        * DumpRenderTree/AccessibilityUIElement.h:
+        * DumpRenderTree/chromium/AccessibilityUIElement.cpp:
+        (AccessibilityUIElement::AccessibilityUIElement):
+        (AccessibilityUIElement::scrollToMakeVisibleCallback):
+        (AccessibilityUIElement::scrollToMakeVisibleWithSubFocusCallback):
+        (AccessibilityUIElement::scrollToGlobalPointCallback):
+        * DumpRenderTree/chromium/AccessibilityUIElement.h:
+        * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+        (AccessibilityUIElement::scrollToMakeVisible):
+        (AccessibilityUIElement::scrollToMakeVisibleWithSubFocus):
+        (AccessibilityUIElement::scrollToGlobalPoint):
+        * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+        (AccessibilityUIElement::scrollToMakeVisible):
+        (AccessibilityUIElement::scrollToMakeVisibleWithSubFocus):
+        (AccessibilityUIElement::scrollToGlobalPoint):
+        * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+        (AccessibilityUIElement::scrollToMakeVisible):
+        (AccessibilityUIElement::scrollToMakeVisibleWithSubFocus):
+        (AccessibilityUIElement::scrollToGlobalPoint):
+
 2012-01-17  Enrica Casucci  <enrica@apple.com>
 
         Missing NSForegroundColorAttributeName should be treated as black instead of transparent.
index 38d35cf..cd6fee0 100644 (file)
@@ -216,7 +216,11 @@ public:
     JSStringRef stringForTextMarkerRange(AccessibilityTextMarkerRange*);
     int textMarkerRangeLength(AccessibilityTextMarkerRange*);
     bool attributedStringForTextMarkerRangeContainsAttribute(JSStringRef, AccessibilityTextMarkerRange*);
-    
+
+    void scrollToMakeVisible();
+    void scrollToMakeVisibleWithSubFocus(int x, int y, int width, int height);
+    void scrollToGlobalPoint(int x, int y);
+
     // Notifications
     // Function callback should take one argument, the name of the notification.
     bool addNotificationListener(JSObjectRef functionCallback);
index 3ca1ee7..5838065 100644 (file)
@@ -33,6 +33,7 @@
 
 #include "WebAccessibilityObject.h"
 #include "platform/WebCString.h"
+#include "platform/WebPoint.h"
 #include "platform/WebRect.h"
 #include "platform/WebString.h"
 #include <wtf/Assertions.h>
@@ -355,6 +356,9 @@ AccessibilityUIElement::AccessibilityUIElement(const WebAccessibilityObject& obj
     bindMethod("addNotificationListener", &AccessibilityUIElement::addNotificationListenerCallback);
     bindMethod("removeNotificationListener", &AccessibilityUIElement::removeNotificationListenerCallback);
     bindMethod("takeFocus", &AccessibilityUIElement::takeFocusCallback);
+    bindMethod("scrollToMakeVisible", &AccessibilityUIElement::scrollToMakeVisibleCallback);
+    bindMethod("scrollToMakeVisibleWithSubFocus", &AccessibilityUIElement::scrollToMakeVisibleWithSubFocusCallback);
+    bindMethod("scrollToGlobalPoint", &AccessibilityUIElement::scrollToGlobalPointCallback);
 
     bindFallbackMethod(&AccessibilityUIElement::fallbackCallback);
 }
@@ -763,6 +767,47 @@ void AccessibilityUIElement::takeFocusCallback(const CppArgumentList&, CppVarian
     result->setNull();
 }
 
+void AccessibilityUIElement::scrollToMakeVisibleCallback(const CppArgumentList&, CppVariant* result)
+{
+    accessibilityObject().scrollToMakeVisible();
+    result->setNull();
+}
+
+void AccessibilityUIElement::scrollToMakeVisibleWithSubFocusCallback(const CppArgumentList& arguments, CppVariant* result)
+{
+    result->setNull();
+
+    if (arguments.size() != 4
+        || !arguments[0].isNumber()
+        || !arguments[1].isNumber()
+        || !arguments[2].isNumber()
+        || !arguments[3].isNumber())
+        return;
+
+    int x = arguments[0].toInt32();
+    int y = arguments[1].toInt32();
+    int width = arguments[2].toInt32();
+    int height = arguments[3].toInt32();
+    accessibilityObject().scrollToMakeVisibleWithSubFocus(WebRect(x, y, width, height));
+    result->setNull();
+}
+
+void AccessibilityUIElement::scrollToGlobalPointCallback(const CppArgumentList& arguments, CppVariant* result)
+{
+    result->setNull();
+
+    if (arguments.size() != 2
+        || !arguments[0].isNumber()
+        || !arguments[1].isNumber())
+        return;
+
+    int x = arguments[0].toInt32();
+    int y = arguments[1].toInt32();
+
+    accessibilityObject().scrollToGlobalPoint(WebPoint(x, y));
+    result->setNull();
+}
+
 void AccessibilityUIElement::fallbackCallback(const CppArgumentList &, CppVariant* result)
 {
     // FIXME: Implement this.
index b5fce86..8ae6d41 100644 (file)
@@ -126,6 +126,9 @@ private:
     void addNotificationListenerCallback(const CppArgumentList&, CppVariant*);
     void removeNotificationListenerCallback(const CppArgumentList&, CppVariant*);
     void takeFocusCallback(const CppArgumentList&, CppVariant*);
+    void scrollToMakeVisibleCallback(const CppArgumentList&, CppVariant*);
+    void scrollToMakeVisibleWithSubFocusCallback(const CppArgumentList&, CppVariant*);
+    void scrollToGlobalPointCallback(const CppArgumentList&, CppVariant*);
 
     void fallbackCallback(const CppArgumentList&, CppVariant*);
 
index fe69b85..56d3a4e 100644 (file)
@@ -825,3 +825,18 @@ void AccessibilityUIElement::removeSelection()
 {
     // FIXME: implement
 }
+
+void AccessibilityUIElement::scrollToMakeVisible()
+{
+    // FIXME: implement
+}
+
+void AccessibilityUIElement::scrollToMakeVisibleWithSubFocus(int x, int y, int width, int height)
+{
+    // FIXME: implement
+}
+
+void AccessibilityUIElement::scrollToGlobalPoint(int x, int y)
+{
+    // FIXME: implement
+}
index 9360ef1..c5545f6 100644 (file)
@@ -1392,3 +1392,18 @@ AccessibilityUIElement AccessibilityUIElement::accessibilityElementForTextMarker
 }
 
 #endif // SUPPORTS_AX_TEXTMARKERS
+
+void AccessibilityUIElement::scrollToMakeVisible()
+{
+    // FIXME: implement
+}
+
+void AccessibilityUIElement::scrollToMakeVisibleWithSubFocus(int x, int y, int width, int height)
+{
+    // FIXME: implement
+}
+
+void AccessibilityUIElement::scrollToGlobalPoint(int x, int y)
+{
+    // FIXME: implement
+}
index 2863b5c..3b77680 100644 (file)
@@ -696,3 +696,18 @@ void AccessibilityUIElement::removeSelection()
 {
     m_element->accSelect(SELFLAG_REMOVESELECTION, self());
 }
+
+void AccessibilityUIElement::scrollToMakeVisible()
+{
+    // FIXME: implement
+}
+
+void AccessibilityUIElement::scrollToMakeVisibleWithSubFocus(int x, int y, int width, int height)
+{
+    // FIXME: implement
+}
+
+void AccessibilityUIElement::scrollToGlobalPoint(int x, int y)
+{
+    // FIXME: implement
+}