AX: WK2: iOS web page scrolling doesn't work with VoiceOver
authorcfleizach@apple.com <cfleizach@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 2 May 2014 16:19:32 +0000 (16:19 +0000)
committercfleizach@apple.com <cfleizach@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 2 May 2014 16:19:32 +0000 (16:19 +0000)
https://bugs.webkit.org/show_bug.cgi?id=132028

Reviewed by Mario Sanchez Prada.

With the AX tree residing in the WebProcess, scrolling needs to be implemented in
WebCore using accessibilityScroll: in order for accessibility clients to scroll through the AX API.

* accessibility/AccessibilityObject.cpp:
(WebCore::AccessibilityObject::scrollViewAncestor):
(WebCore::AccessibilityObject::scrollToMakeVisibleWithSubFocus):
* accessibility/AccessibilityObject.h:
* accessibility/ios/WebAccessibilityObjectWrapperIOS.h:
* accessibility/ios/WebAccessibilityObjectWrapperIOS.mm:
(-[WebAccessibilityObjectWrapper _accessibilityConvertPointToViewSpace:]):
(-[WebAccessibilityObjectWrapper _accessibilityScrollToVisible]):
(-[WebAccessibilityObjectWrapper accessibilityScroll:]):
(-[WebAccessibilityObjectWrapper postScrollStatusChangeNotification]):
(-[WebAccessibilityObjectWrapper _accessibilityScrollPosition]):
(-[WebAccessibilityObjectWrapper _accessibilityScrollSize]):
(-[WebAccessibilityObjectWrapper _accessibilityScrollVisibleRect]):

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

Source/WebCore/ChangeLog
Source/WebCore/accessibility/AccessibilityObject.cpp
Source/WebCore/accessibility/AccessibilityObject.h
Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.h
Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm

index a4446c5..846eb5b 100644 (file)
@@ -1,3 +1,27 @@
+2014-05-02  Chris Fleizach  <cfleizach@apple.com>
+
+        AX: WK2: iOS web page scrolling doesn't work with VoiceOver
+        https://bugs.webkit.org/show_bug.cgi?id=132028
+
+        Reviewed by Mario Sanchez Prada.
+
+        With the AX tree residing in the WebProcess, scrolling needs to be implemented in
+        WebCore using accessibilityScroll: in order for accessibility clients to scroll through the AX API.
+
+        * accessibility/AccessibilityObject.cpp:
+        (WebCore::AccessibilityObject::scrollViewAncestor):
+        (WebCore::AccessibilityObject::scrollToMakeVisibleWithSubFocus):
+        * accessibility/AccessibilityObject.h:
+        * accessibility/ios/WebAccessibilityObjectWrapperIOS.h:
+        * accessibility/ios/WebAccessibilityObjectWrapperIOS.mm:
+        (-[WebAccessibilityObjectWrapper _accessibilityConvertPointToViewSpace:]):
+        (-[WebAccessibilityObjectWrapper _accessibilityScrollToVisible]):
+        (-[WebAccessibilityObjectWrapper accessibilityScroll:]):
+        (-[WebAccessibilityObjectWrapper postScrollStatusChangeNotification]):
+        (-[WebAccessibilityObjectWrapper _accessibilityScrollPosition]):
+        (-[WebAccessibilityObjectWrapper _accessibilityScrollSize]):
+        (-[WebAccessibilityObjectWrapper _accessibilityScrollVisibleRect]):
+
 2014-05-02  Jeremy Jones  <jeremyj@apple.com>
 
         Pause playback on exit fullscreen when inline playback not allowed.
index 74d7be8..521c459 100644 (file)
@@ -31,6 +31,7 @@
 
 #include "AXObjectCache.h"
 #include "AccessibilityRenderObject.h"
+#include "AccessibilityScrollView.h"
 #include "AccessibilityTable.h"
 #include "DOMTokenList.h"
 #include "Editor.h"
@@ -1408,7 +1409,17 @@ void AccessibilityObject::updateBackingStore()
     updateChildrenIfNecessary();
 }
 #endif
-
+    
+ScrollView* AccessibilityObject::scrollViewAncestor() const
+{
+    for (const AccessibilityObject* scrollParent = this; scrollParent; scrollParent = scrollParent->parentObject()) {
+        if (scrollParent->isAccessibilityScrollView())
+            return toAccessibilityScrollView(scrollParent)->scrollView();
+    }
+    
+    return nullptr;
+}
+    
 Document* AccessibilityObject::document() const
 {
     FrameView* frameView = documentFrameView();
index c4b8f5f..7d8c9e1 100644 (file)
@@ -86,6 +86,7 @@ class Page;
 class RenderObject;
 class RenderListItem;
 class ScrollableArea;
+class ScrollView;
 class Widget;
 
 typedef unsigned AXID;
@@ -709,6 +710,7 @@ public:
     Frame* frame() const;
     MainFrame* mainFrame() const;
     Document* topDocument() const;
+    ScrollView* scrollViewAncestor() const;
     String language() const;
     // 1-based, to match the aria-level spec.
     virtual unsigned hierarchicalLevel() const { return 0; }
index 7738525..cba74f7 100644 (file)
@@ -61,6 +61,7 @@
 - (void)postChildrenChangedNotification;
 - (void)postInvalidStatusChangedNotification;
 - (void)postLiveRegionCreatedNotification;
+- (void)postScrollStatusChangeNotification;
 
 @end
 
index 6d21acb..7684258 100644 (file)
 using namespace WebCore;
 using namespace HTMLNames;
 
+typedef NS_ENUM(NSInteger, UIAccessibilityScrollDirection) {
+    UIAccessibilityScrollDirectionRight = 1,
+    UIAccessibilityScrollDirectionLeft,
+    UIAccessibilityScrollDirectionUp,
+    UIAccessibilityScrollDirectionDown,
+    UIAccessibilityScrollDirectionNext,
+    UIAccessibilityScrollDirectionPrevious
+};
+
 // These are tokens accessibility uses to denote attributes. 
 static NSString * const UIAccessibilityTokenBlockquoteLevel = @"UIAccessibilityTokenBlockquoteLevel";
 static NSString * const UIAccessibilityTokenHeadingLevel = @"UIAccessibilityTokenHeadingLevel";
@@ -994,6 +1003,80 @@ static void appendStringToResult(NSMutableString *result, NSString *string)
     return (NSURL*)url;
 }
 
+- (CGPoint)_accessibilityConvertPointToViewSpace:(CGPoint)point
+{
+    if (![self _prepareAccessibilityCall])
+        return point;
+    
+    FloatPoint floatPoint = FloatPoint(point);
+    return [self convertPointToScreenSpace:floatPoint];
+}
+
+- (BOOL)_accessibilityScrollToVisible
+{
+    if (![self _prepareAccessibilityCall])
+        return NO;
+    
+    m_object->scrollToMakeVisible();
+    return YES;
+}
+
+
+- (BOOL)accessibilityScroll:(UIAccessibilityScrollDirection)direction
+{
+    if (![self _prepareAccessibilityCall])
+        return NO;
+    
+    ScrollView* scrollView = m_object->scrollViewAncestor();
+    if (!scrollView)
+        return NO;
+    
+    IntPoint scrollPosition = scrollView->scrollPosition();
+    IntPoint newScrollPosition = scrollPosition;
+    IntSize scrollSize = scrollView->contentsSize();
+    IntRect scrollVisibleRect = scrollView->visibleContentRect(ScrollableArea::LegacyIOSDocumentVisibleRect);
+    switch (direction) {
+    case UIAccessibilityScrollDirectionRight: {
+        int scrollAmount = scrollVisibleRect.size().width();
+        int newX = scrollPosition.x() - scrollAmount;
+        newScrollPosition.setX(std::max(newX, 0));
+        break;
+    }
+    case UIAccessibilityScrollDirectionLeft: {
+        int scrollAmount = scrollVisibleRect.size().width();
+        int newX = scrollAmount + scrollPosition.x();
+        int maxX = scrollSize.width() - scrollAmount;
+        newScrollPosition.setX(std::min(newX, maxX));
+        break;
+    }
+    case UIAccessibilityScrollDirectionUp: {
+        int scrollAmount = scrollVisibleRect.size().height();
+        int newY = scrollPosition.y() - scrollAmount;
+        newScrollPosition.setY(std::max(newY, 0));
+        break;
+    }
+    case UIAccessibilityScrollDirectionDown: {
+        int scrollAmount = scrollVisibleRect.size().height();
+        int newY = scrollAmount + scrollPosition.y();
+        int maxY = scrollSize.height() - scrollAmount;
+        newScrollPosition.setY(std::min(newY, maxY));
+        break;
+    }
+    default:
+        break;
+    }
+    
+    if (newScrollPosition != scrollPosition) {
+        scrollView->setScrollPosition(newScrollPosition);
+        m_object->document()->updateLayoutIgnorePendingStylesheets();
+    }
+    
+    [self postScrollStatusChangeNotification];
+    
+    // This means that this object handled the scroll and no other ancestor should attempt scrolling.
+    return YES;
+}
+
 - (CGPoint)convertPointToScreenSpace:(FloatPoint &)point
 {
     if (!m_object)
@@ -1387,6 +1470,45 @@ static RenderObject* rendererForView(WAKView* view)
     // The UIKit accessibility wrapper will override and post appropriate notification.        
 }
 
+- (void)postScrollStatusChangeNotification
+{
+    // The UIKit accessibility wrapper will override and post appropriate notification.
+}
+
+// These will be used by the UIKit wrapper to calculate an appropriate description of scroll status.
+- (CGPoint)_accessibilityScrollPosition
+{
+    if (![self _prepareAccessibilityCall])
+        return CGPointZero;
+    
+    ScrollView* scrollView = m_object->scrollViewAncestor();
+    if (!scrollView)
+        return CGPointZero;
+    return scrollView->scrollPosition();
+}
+
+- (CGSize)_accessibilityScrollSize
+{
+    if (![self _prepareAccessibilityCall])
+        return CGSizeZero;
+    
+    ScrollView* scrollView = m_object->scrollViewAncestor();
+    if (!scrollView)
+        return CGSizeZero;
+    return scrollView->contentsSize();
+}
+
+- (CGRect)_accessibilityScrollVisibleRect
+{
+    if (![self _prepareAccessibilityCall])
+        return CGRectZero;
+    
+    ScrollView* scrollView = m_object->scrollViewAncestor();
+    if (!scrollView)
+        return CGRectZero;
+    return scrollView->visibleContentRect(ScrollableArea::LegacyIOSDocumentVisibleRect);
+}
+
 - (void)accessibilityElementDidBecomeFocused
 {
     if (![self _prepareAccessibilityCall])