AX: The bounding paths should be made available through accessibility
authorcfleizach@apple.com <cfleizach@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 9 Apr 2013 18:53:19 +0000 (18:53 +0000)
committercfleizach@apple.com <cfleizach@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 9 Apr 2013 18:53:19 +0000 (18:53 +0000)
https://bugs.webkit.org/show_bug.cgi?id=113817

Reviewed by David Kilzer.

Source/WebCore:

This allows bounding paths to be returned for some web elements (image map areas and SVG shapes).
This provides more accuracy when assistive technologies highlight elements.
The Mac and iOS platforms share some code to help transform paths to their screen coordinates.

Tests: platform/iphone-simulator/accessibility/element-paths.html
       platform/mac/accessibility/element-paths.html

* accessibility/AccessibilityImageMapLink.cpp:
(WebCore::AccessibilityImageMapLink::imageMapLinkRenderer):
(WebCore):
(WebCore::AccessibilityImageMapLink::elementPath):
(WebCore::AccessibilityImageMapLink::elementRect):
* accessibility/AccessibilityImageMapLink.h:
(AccessibilityImageMapLink):
(WebCore::AccessibilityImageMapLink::supportsPath):
* accessibility/AccessibilityObject.h:
(WebCore::AccessibilityObject::elementPath):
(WebCore::AccessibilityObject::supportsPath):
* accessibility/AccessibilityRenderObject.cpp:
(WebCore):
(WebCore::AccessibilityRenderObject::supportsPath):
(WebCore::AccessibilityRenderObject::elementPath):
* accessibility/AccessibilityRenderObject.h:
(AccessibilityRenderObject):
* accessibility/ios/WebAccessibilityObjectWrapperIOS.mm:
(-[WebAccessibilityObjectWrapper _accessibilityPath]):
(-[WebAccessibilityObjectWrapper convertPointToScreenSpace:]):
(-[WebAccessibilityObjectWrapper convertRectToScreenSpace:]):
(-[WebAccessibilityObjectWrapper accessibilityActivationPoint]):
(-[WebAccessibilityObjectWrapper accessibilityFrame]):
(-[WebAccessibilityObjectWrapper frameForTextMarkers:]):
* accessibility/mac/WebAccessibilityObjectWrapperBase.h:
(WebCore):
* accessibility/mac/WebAccessibilityObjectWrapperBase.mm:
(PathConversionInfo):
(ConvertPathToScreenSpaceFunction):
(-[WebAccessibilityObjectWrapperBase convertPathToScreenSpace:]):
(-[WebAccessibilityObjectWrapperBase convertPointToScreenSpace:]):
* accessibility/mac/WebAccessibilityObjectWrapperMac.mm:
(-[WebAccessibilityObjectWrapper additionalAccessibilityAttributeNames]):
(-[WebAccessibilityObjectWrapper convertPointToScreenSpace:]):
(WebTransformCGPathToNSBezierPath):
(-[WebAccessibilityObjectWrapper bezierPathFromPath:]):
(-[WebAccessibilityObjectWrapper path]):
(-[WebAccessibilityObjectWrapper position]):
(-[WebAccessibilityObjectWrapper accessibilityAttributeValue:]):

Tools:

Add a pathDescription property for testing so that it's possible
to verify that a path is being returned correctly.

* DumpRenderTree/AccessibilityUIElement.cpp:
(getPathDescriptionCallback):
(AccessibilityUIElement::pathDescription):
(AccessibilityUIElement::getJSClass):
* DumpRenderTree/AccessibilityUIElement.h:
(AccessibilityUIElement):
* DumpRenderTree/ios/AccessibilityUIElementIOS.mm:
(_CGPathEnumerationIteration):
(AccessibilityUIElement::pathDescription):
* DumpRenderTree/mac/AccessibilityUIElementMac.mm:
(AccessibilityUIElement::pathDescription):
* WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp:
(WTR::AccessibilityUIElement::pathDescription):
(WTR):
* WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h:
(AccessibilityUIElement):
* WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl:
* WebKitTestRunner/InjectedBundle/mac/AccessibilityUIElementMac.mm:
(WTR::AccessibilityUIElement::pathDescription):
(WTR):

LayoutTests:

Add new tests for Mac and iOS to verify that path output works.
Modify existing tests to indicate that there is a new AXAttribute, AXPath.

* platform/iphone-simulator/accessibility/element-paths-expected.txt: Added.
* platform/iphone-simulator/accessibility/element-paths.html: Added.
* platform/mac/accessibility/document-links-expected.txt:
* platform/mac/accessibility/element-paths-expected.txt: Added.
* platform/mac/accessibility/element-paths.html: Added.
* platform/mac/accessibility/image-map2-expected.txt:

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

26 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/iphone-simulator/accessibility/element-paths-expected.txt [new file with mode: 0644]
LayoutTests/platform/iphone-simulator/accessibility/element-paths.html [new file with mode: 0644]
LayoutTests/platform/mac/accessibility/document-links-expected.txt
LayoutTests/platform/mac/accessibility/element-paths-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac/accessibility/element-paths.html [new file with mode: 0644]
LayoutTests/platform/mac/accessibility/image-map2-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/accessibility/AccessibilityImageMapLink.cpp
Source/WebCore/accessibility/AccessibilityImageMapLink.h
Source/WebCore/accessibility/AccessibilityObject.h
Source/WebCore/accessibility/AccessibilityRenderObject.cpp
Source/WebCore/accessibility/AccessibilityRenderObject.h
Source/WebCore/accessibility/ios/WebAccessibilityObjectWrapperIOS.mm
Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperBase.h
Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperBase.mm
Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm
Tools/ChangeLog
Tools/DumpRenderTree/AccessibilityUIElement.cpp
Tools/DumpRenderTree/AccessibilityUIElement.h
Tools/DumpRenderTree/ios/AccessibilityUIElementIOS.mm
Tools/DumpRenderTree/mac/AccessibilityUIElementMac.mm
Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp
Tools/WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h
Tools/WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl
Tools/WebKitTestRunner/InjectedBundle/mac/AccessibilityUIElementMac.mm

index f746b5901b583e6dc49ee26958c29d999177e1bc..a05b32d3b88112ef247944d9d3822d9856ba70d1 100644 (file)
@@ -1,3 +1,20 @@
+2013-04-09  Chris Fleizach  <cfleizach@apple.com>
+
+        AX: The bounding paths should be made available through accessibility
+        https://bugs.webkit.org/show_bug.cgi?id=113817
+
+        Reviewed by David Kilzer.
+
+        Add new tests for Mac and iOS to verify that path output works.
+        Modify existing tests to indicate that there is a new AXAttribute, AXPath.
+
+        * platform/iphone-simulator/accessibility/element-paths-expected.txt: Added.
+        * platform/iphone-simulator/accessibility/element-paths.html: Added.
+        * platform/mac/accessibility/document-links-expected.txt:
+        * platform/mac/accessibility/element-paths-expected.txt: Added.
+        * platform/mac/accessibility/element-paths.html: Added.
+        * platform/mac/accessibility/image-map2-expected.txt:
+
 2013-04-09  Arnaud Renevier  <a.renevier@sisa.samsung.com>
 
         Whitespace in particular source code changes rendering; does not in Firefox
diff --git a/LayoutTests/platform/iphone-simulator/accessibility/element-paths-expected.txt b/LayoutTests/platform/iphone-simulator/accessibility/element-paths-expected.txt
new file mode 100644 (file)
index 0000000..176eefd
--- /dev/null
@@ -0,0 +1,35 @@
+This tests SVG group elements are accessible and that the svg:title element is returned properly.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+SVG path description
+Start Path
+       Move to point
+       Line to
+       Line to
+       Close
+
+Map1 path description
+Start Path
+       Move to point
+       Line to
+       Line to
+       Line to
+       Line to
+       Close
+
+Map2 path description
+Start Path
+       Move to point
+       Curve to
+       Curve to
+       Curve to
+       Curve to
+       Close
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/platform/iphone-simulator/accessibility/element-paths.html b/LayoutTests/platform/iphone-simulator/accessibility/element-paths.html
new file mode 100644 (file)
index 0000000..5fe4fa9
--- /dev/null
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body id="body">
+
+<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
+  <path role="button" id="svg" d="M150 0 L75 200 L225 200 Z" />
+</svg>
+
+<map name="imagemap1">
+    <AREA id="map1" shape="polygon" coords="90,25,162,26,163,96,89,25,90,24" href="triangle.html">
+    <AREA id="map2" shape="circle" coords="130,304,110" href="circle.html">
+</map>
+
+<img src="resources/cake.png"  border="0" align="left" usemap="#imagemap1" vspace="1">
+
+<div id="console"></div>
+
+<script>
+
+    description("This tests SVG group elements are accessible and that the svg:title element is returned properly.");
+
+    if (window.accessibilityController) {
+
+          var svg = accessibilityController.accessibleElementById("svg");
+          debug("SVG path description" + svg.pathDescription);
+
+          var map1 = accessibilityController.accessibleElementById("map1");
+          debug("Map1 path description" + map1.pathDescription);
+
+          var map2 = accessibilityController.accessibleElementById("map2");
+          debug("Map2 path description"  + map2.pathDescription);
+    }
+
+</script>
+
+<script src="../../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
index bba30e302493ed54b841c535128f7ad1442fbeaa..5780bf19e7f5ca26a49a09907be5b89abdc39cfd 100644 (file)
@@ -24,6 +24,7 @@ AXTopLevelUIElement: <AXLink: 'Link1'>
 AXURL: http://www.apple.com/
 AXAccessKey: (null)
 AXARIABusy: 0
+AXPath: <AXLink: 'Link1'>
 
 ------------
 AXRole: AXLink
@@ -50,6 +51,7 @@ AXTopLevelUIElement: <AXLink: 'Link2'>
 AXURL: http://www.apple.com/
 AXAccessKey: (null)
 AXARIABusy: 0
+AXPath: <AXLink: 'Link2'>
 
 ------------
 AXRole: AXLink
diff --git a/LayoutTests/platform/mac/accessibility/element-paths-expected.txt b/LayoutTests/platform/mac/accessibility/element-paths-expected.txt
new file mode 100644 (file)
index 0000000..6374e82
--- /dev/null
@@ -0,0 +1,41 @@
+This tests SVG group elements are accessible and that the svg:title element is returned properly.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS svg.isAttributeSupported('AXPath') is true
+SVG path description
+Start Path
+       Move to point
+       Line to
+       Line to
+       Close
+       Move to point
+
+PASS map1.isAttributeSupported('AXPath') is true
+Map1 path description
+Start Path
+       Move to point
+       Line to
+       Line to
+       Line to
+       Line to
+       Close
+       Move to point
+
+PASS map2.isAttributeSupported('AXPath') is true
+Map2 path description
+Start Path
+       Move to point
+       Curve to
+       Curve to
+       Curve to
+       Curve to
+       Close
+       Move to point
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/platform/mac/accessibility/element-paths.html b/LayoutTests/platform/mac/accessibility/element-paths.html
new file mode 100644 (file)
index 0000000..d81f378
--- /dev/null
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src="../../../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body id="body">
+
+<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
+  <path role="button" id="svg" d="M150 0 L75 200 L225 200 Z" />
+</svg>
+
+<map name="imagemap1">
+    <AREA id="map1" shape="polygon" coords="90,25,162,26,163,96,89,25,90,24" href="triangle.html">
+    <AREA id="map2" shape="circle" coords="130,304,110" href="circle.html">
+</map>
+
+<img src="resources/cake.png"  border="1" align="left" usemap="#imagemap1" vspace="1">
+
+<div id="console"></div>
+
+<script>
+
+    description("This tests SVG group elements are accessible and that the svg:title element is returned properly.");
+
+    if (window.accessibilityController) {
+
+          var svg = accessibilityController.accessibleElementById("svg");
+          shouldBeTrue("svg.isAttributeSupported('AXPath')");
+          debug("SVG path description" + svg.pathDescription);
+
+          var map1 = accessibilityController.accessibleElementById("map1");
+          shouldBeTrue("map1.isAttributeSupported('AXPath')");
+          debug("Map1 path description" + map1.pathDescription);
+
+          var map2 = accessibilityController.accessibleElementById("map2");
+          shouldBeTrue("map2.isAttributeSupported('AXPath')");
+          debug("Map2 path description"  + map2.pathDescription);
+    }
+
+</script>
+
+<script src="../../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
index 1872e2f0cf577bcd057a457ccfd08401eb6be48e..426cee2ee184a79a208bbd9edfb9bc42c3d01c87 100644 (file)
@@ -48,6 +48,7 @@ AXTopLevelUIElement: <AXLink>
 AXURL: http://www.apple.com/
 AXAccessKey: (null)
 AXARIABusy: 0
+AXPath: <AXLink>
 
 ------------
 AXRole: AXLink
@@ -74,6 +75,7 @@ AXTopLevelUIElement: <AXLink>
 AXURL: http://www.apple.com/
 AXAccessKey: (null)
 AXARIABusy: 0
+AXPath: <AXLink>
 
 ------------
 
index cee547752232fbda6a9992a36fc25b7c54829da7..98d3f9ad9d3e33ac2ecc975d1661e7ee8e4767e5 100644 (file)
@@ -1,3 +1,57 @@
+2013-04-09  Chris Fleizach  <cfleizach@apple.com>
+
+        AX: The bounding paths should be made available through accessibility
+        https://bugs.webkit.org/show_bug.cgi?id=113817
+
+        Reviewed by David Kilzer.
+
+        This allows bounding paths to be returned for some web elements (image map areas and SVG shapes).
+        This provides more accuracy when assistive technologies highlight elements.
+        The Mac and iOS platforms share some code to help transform paths to their screen coordinates.
+
+        Tests: platform/iphone-simulator/accessibility/element-paths.html
+               platform/mac/accessibility/element-paths.html
+
+        * accessibility/AccessibilityImageMapLink.cpp:
+        (WebCore::AccessibilityImageMapLink::imageMapLinkRenderer):
+        (WebCore):
+        (WebCore::AccessibilityImageMapLink::elementPath):
+        (WebCore::AccessibilityImageMapLink::elementRect):
+        * accessibility/AccessibilityImageMapLink.h:
+        (AccessibilityImageMapLink):
+        (WebCore::AccessibilityImageMapLink::supportsPath):
+        * accessibility/AccessibilityObject.h:
+        (WebCore::AccessibilityObject::elementPath):
+        (WebCore::AccessibilityObject::supportsPath):
+        * accessibility/AccessibilityRenderObject.cpp:
+        (WebCore):
+        (WebCore::AccessibilityRenderObject::supportsPath):
+        (WebCore::AccessibilityRenderObject::elementPath):
+        * accessibility/AccessibilityRenderObject.h:
+        (AccessibilityRenderObject):
+        * accessibility/ios/WebAccessibilityObjectWrapperIOS.mm:
+        (-[WebAccessibilityObjectWrapper _accessibilityPath]):
+        (-[WebAccessibilityObjectWrapper convertPointToScreenSpace:]):
+        (-[WebAccessibilityObjectWrapper convertRectToScreenSpace:]):
+        (-[WebAccessibilityObjectWrapper accessibilityActivationPoint]):
+        (-[WebAccessibilityObjectWrapper accessibilityFrame]):
+        (-[WebAccessibilityObjectWrapper frameForTextMarkers:]):
+        * accessibility/mac/WebAccessibilityObjectWrapperBase.h:
+        (WebCore):
+        * accessibility/mac/WebAccessibilityObjectWrapperBase.mm:
+        (PathConversionInfo):
+        (ConvertPathToScreenSpaceFunction):
+        (-[WebAccessibilityObjectWrapperBase convertPathToScreenSpace:]):
+        (-[WebAccessibilityObjectWrapperBase convertPointToScreenSpace:]):
+        * accessibility/mac/WebAccessibilityObjectWrapperMac.mm:
+        (-[WebAccessibilityObjectWrapper additionalAccessibilityAttributeNames]):
+        (-[WebAccessibilityObjectWrapper convertPointToScreenSpace:]):
+        (WebTransformCGPathToNSBezierPath):
+        (-[WebAccessibilityObjectWrapper bezierPathFromPath:]):
+        (-[WebAccessibilityObjectWrapper path]):
+        (-[WebAccessibilityObjectWrapper position]):
+        (-[WebAccessibilityObjectWrapper accessibilityAttributeValue:]):
+
 2013-04-09  Benjamin Poulain  <bpoulain@apple.com>
 
         Remove the WebKit copy of GLU and the file using it
index 9089f66f32f9cbf72df4f0c756d2803e1f7ee88d..132f16b0b6050c1853f2097d8ec438a1a3b87483 100644 (file)
@@ -134,17 +134,32 @@ String AccessibilityImageMapLink::title() const
     return String();
 }
 
-LayoutRect AccessibilityImageMapLink::elementRect() const
+RenderObject* AccessibilityImageMapLink::imageMapLinkRenderer() const
 {
     if (!m_mapElement.get() || !m_areaElement.get())
-        return LayoutRect();
+        return 0;
 
-    RenderObject* renderer;
+    RenderObject* renderer = 0;
     if (m_parent && m_parent->isAccessibilityRenderObject())
         renderer = static_cast<AccessibilityRenderObject*>(m_parent)->renderer();
     else
         renderer = m_mapElement->renderer();
     
+    return renderer;
+}
+    
+Path AccessibilityImageMapLink::elementPath() const
+{
+    RenderObject* renderer = imageMapLinkRenderer();
+    if (!renderer)
+        return Path();
+    
+    return m_areaElement->computePath(renderer);
+}
+    
+LayoutRect AccessibilityImageMapLink::elementRect() const
+{
+    RenderObject* renderer = imageMapLinkRenderer();
     if (!renderer)
         return LayoutRect();
     
index 3e20049e7d30d02391576f8cc1a3264cd6474948..40fb926780294dca15bc19dd037ddb014ce8f34a 100644 (file)
@@ -72,8 +72,11 @@ private:
     RefPtr<HTMLAreaElement> m_areaElement;
     RefPtr<HTMLMapElement> m_mapElement;
     
+    virtual Path elementPath() const;
+    RenderObject* imageMapLinkRenderer() const;
     virtual void accessibilityText(Vector<AccessibilityText>&);
     virtual bool isImageMapLink() const { return true; }
+    virtual bool supportsPath() const { return true; }
 };
     
 } // namespace WebCore
index 6980dcaea4784b9c248e7cd029eedb8ed86bd2bf..2aa376d5314d38ca0e2bf6c59a2955b6f5ce9950 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "FloatQuad.h"
 #include "LayoutRect.h"
+#include "Path.h"
 #include "TextIterator.h"
 #include "VisiblePosition.h"
 #include "VisibleSelection.h"
@@ -605,6 +606,8 @@ public:
     IntSize pixelSnappedSize() const { return elementRect().pixelSnappedSize(); }
     virtual IntPoint clickPoint();
     static IntRect boundingBoxForQuads(RenderObject*, const Vector<FloatQuad>&);
+    virtual Path elementPath() const { return Path(); }
+    virtual bool supportsPath() const { return false; }
     
     TextIteratorBehavior textIteratorBehaviorForTextRange() const;
     virtual PlainTextRange selectedTextRange() const { return PlainTextRange(); }
@@ -671,7 +674,7 @@ public:
     bool isDescendantOfObject(const AccessibilityObject*) const;
     bool isAncestorOfObject(const AccessibilityObject*) const;
     AccessibilityObject* firstAnonymousBlockChild() const;
-    
+
     static AccessibilityRole ariaRoleToWebCoreRole(const String&);
     bool hasAttribute(const QualifiedName&) const;
     const AtomicString& getAttribute(const QualifiedName&) const;
index 04e2700b699c3e959127c94137aeed5000351238..e9ea020e7672d608036f49df4a6fa87111ce402d 100644 (file)
@@ -836,6 +836,26 @@ LayoutRect AccessibilityRenderObject::elementRect() const
     
     return boundingBoxRect();
 }
+    
+bool AccessibilityRenderObject::supportsPath() const
+{
+#if ENABLE(SVG)
+    if (m_renderer && m_renderer->isSVGShape())
+        return true;
+#endif
+    
+    return false;
+}
+    
+Path AccessibilityRenderObject::elementPath() const
+{
+#if ENABLE(SVG)
+    if (m_renderer && m_renderer->isSVGShape())
+        return toRenderSVGShape(m_renderer)->path();
+#endif
+    
+    return Path();
+}
 
 IntPoint AccessibilityRenderObject::clickPoint()
 {
index c364dcf603637a195fe9447e1f130fb796e1676e..a5e64a1f9b2b8d3dd910c19a70215bb625a5ba28 100644 (file)
@@ -235,7 +235,8 @@ private:
     Element* rootEditableElementForPosition(const Position&) const;
     bool nodeIsTextControl(const Node*) const;
     virtual void setNeedsToUpdateChildren() { m_childrenDirty = true; }
-
+    virtual Path elementPath() const;
+    
     bool isTabItemSelected() const;
     LayoutRect checkboxOrRadioRect() const;
     void addRadioButtonGroupMembers(AccessibilityChildrenVector& linkedUIElements) const;
@@ -253,7 +254,8 @@ private:
     AccessibilitySVGRoot* remoteSVGRootElement() const;
     AccessibilityObject* remoteSVGElementHitTest(const IntPoint&) const;
     void offsetBoundingBoxForRemoteSVGElement(LayoutRect&) const;
-    
+    virtual bool supportsPath() const;
+
     void addHiddenChildren();
     void addTextFieldChildren();
     void addImageMapChildren();
@@ -275,7 +277,7 @@ private:
     virtual const AtomicString& ariaLiveRegionRelevant() const;
     virtual bool ariaLiveRegionAtomic() const;
     virtual bool ariaLiveRegionBusy() const;    
-    
+
     bool inheritsPresentationalRole() const;
 
 #if ENABLE(MATHML)
index 35b61835f2e659c7048f8eabc691d5abc4ef3084..e12c001006b04dd1ac6bdda74394fad15472d19b 100644 (file)
@@ -368,6 +368,22 @@ static AccessibilityObjectWrapper* AccessibilityUnignoredAncestor(AccessibilityO
     return NSNotFound;
 }
 
+- (CGPathRef)_accessibilityPath
+{
+    if (![self _prepareAccessibilityCall])
+        return NULL;
+
+    if (!m_object->supportsPath())
+        return NULL;
+    
+    Path path = m_object->elementPath();
+    if (path.isEmpty())
+        return NULL;
+    
+    Path transformedPath = [self convertPathToScreenSpace:path];
+    return transformedPath.platformPath();
+}
+
 - (NSString *)accessibilityLanguage
 {
     if (![self _prepareAccessibilityCall])
@@ -937,7 +953,29 @@ static AccessibilityObjectWrapper* AccessibilityUnignoredAncestor(AccessibilityO
     return (NSURL*)url;
 }
 
-- (CGRect)_convertIntRectToScreenCoordinates:(IntRect)rect
+- (CGPoint)convertPointToScreenSpace:(FloatPoint &)point
+{
+    if (!m_object)
+        return CGPointZero;
+    
+    CGPoint cgPoint = CGPointMake(point.x(), point.y());
+    
+    FrameView* frameView = m_object->documentFrameView();
+    if (frameView) {
+        WAKView* view = frameView->documentView();
+        cgPoint = [view convertPoint:cgPoint toView:nil];
+    }
+    
+    // we need the web document view to give us our final screen coordinates
+    // because that can take account of the scroller
+    id webDocument = [self _accessibilityWebDocumentView];
+    if (webDocument)
+        cgPoint = [webDocument convertPoint:cgPoint toView:nil];
+    
+    return cgPoint;
+}
+
+- (CGRect)convertRectToScreenSpace:(IntRect &)rect
 {
     if (!m_object)
         return CGRectZero;
@@ -980,7 +1018,7 @@ static AccessibilityObjectWrapper* AccessibilityUnignoredAncestor(AccessibilityO
         return CGPointZero;
     
     IntRect rect = pixelSnappedIntRect(m_object->boundingBoxRect());
-    CGRect cgRect = [self _convertIntRectToScreenCoordinates:rect];
+    CGRect cgRect = [self convertRectToScreenSpace:rect];
     return CGPointMake(CGRectGetMidX(cgRect), CGRectGetMidY(cgRect));
 }
 
@@ -990,7 +1028,7 @@ static AccessibilityObjectWrapper* AccessibilityUnignoredAncestor(AccessibilityO
         return CGRectZero;
     
     IntRect rect = pixelSnappedIntRect(m_object->elementRect());
-    return [self _convertIntRectToScreenCoordinates:rect];
+    return [self convertRectToScreenSpace:rect];
 }
 
 // Checks whether a link contains only static text and images (and has been divided unnaturally by <spans> and other nefarious mechanisms).
@@ -1879,7 +1917,7 @@ static void AXAttributedStringAppendText(NSMutableAttributedString* attrString,
         return CGRectZero;
 
     IntRect rect = m_object->boundsForVisiblePositionRange(VisiblePositionRange([startMarker visiblePosition], [endMarker visiblePosition]));
-    return [self _convertIntRectToScreenCoordinates:rect];
+    return [self convertRectToScreenSpace:rect];
 }
 
 - (WebAccessibilityTextMarker *)textMarkerForPoint:(CGPoint)point
index b9b70da23187896254c0c97d0579b28d86719f48..698688d8eb3cb63b5265dc08f38c1b394b147cf6 100644 (file)
@@ -31,6 +31,9 @@
 
 namespace WebCore {
 class AccessibilityObject;
+class IntRect;
+class FloatPoint;
+class Path;
 class VisiblePosition;
 }
 
@@ -51,6 +54,9 @@ class VisiblePosition;
 // Used to inform an element when a notification is posted for it. Used by DRT.
 - (void)accessibilityPostedNotification:(NSString *)notificationName;
 
+- (CGPathRef)convertPathToScreenSpace:(WebCore::Path &)path;
+- (CGPoint)convertPointToScreenSpace:(WebCore::FloatPoint &)point;
+
 @end
 
 #endif // WebAccessibilityObjectWrapperBase_h
index 0b52ca02d739669d855698653bd72dd7c3eb8fa4..d24d6b736189f31b6d44435078f994bf3fdede2e 100644 (file)
@@ -232,6 +232,66 @@ using namespace std;
     return [NSString string];
 }
 
+struct PathConversionInfo {
+    WebAccessibilityObjectWrapperBase *wrapper;
+    CGMutablePathRef path;
+};
+
+static void ConvertPathToScreenSpaceFunction(void* info, const PathElement* element)
+{
+    PathConversionInfo* conversion = (PathConversionInfo*)info;
+    WebAccessibilityObjectWrapperBase *wrapper = conversion->wrapper;
+    CGMutablePathRef newPath = conversion->path;
+    switch (element->type) {
+    case PathElementMoveToPoint:
+    {
+        CGPoint newPoint = [wrapper convertPointToScreenSpace:element->points[0]];
+        CGPathMoveToPoint(newPath, nil, newPoint.x, newPoint.y);
+        break;
+    }
+    case PathElementAddLineToPoint:
+    {
+        CGPoint newPoint = [wrapper convertPointToScreenSpace:element->points[0]];
+        CGPathAddLineToPoint(newPath, nil, newPoint.x, newPoint.y);
+        break;
+    }
+    case PathElementAddQuadCurveToPoint:
+    {
+        CGPoint newPoint1 = [wrapper convertPointToScreenSpace:element->points[0]];
+        CGPoint newPoint2 = [wrapper convertPointToScreenSpace:element->points[1]];
+        CGPathAddQuadCurveToPoint(newPath, nil, newPoint1.x, newPoint1.y, newPoint2.x, newPoint2.y);
+        break;
+    }
+    case PathElementAddCurveToPoint:
+    {
+        CGPoint newPoint1 = [wrapper convertPointToScreenSpace:element->points[0]];
+        CGPoint newPoint2 = [wrapper convertPointToScreenSpace:element->points[1]];
+        CGPoint newPoint3 = [wrapper convertPointToScreenSpace:element->points[2]];
+        CGPathAddCurveToPoint(newPath, nil, newPoint1.x, newPoint1.y, newPoint2.x, newPoint2.y, newPoint3.x, newPoint3.y);
+        break;
+    }
+    case PathElementCloseSubpath:
+    {
+        CGPathCloseSubpath(newPath);
+        break;
+    }
+    }
+}
+
+- (CGPathRef)convertPathToScreenSpace:(Path &)path
+{
+    PathConversionInfo conversion = { self, CGPathCreateMutable() };
+    path.apply(&conversion, ConvertPathToScreenSpaceFunction);    
+    return (CGPathRef)[(id)conversion.path autorelease];
+}
+
+- (CGPoint)convertPointToScreenSpace:(FloatPoint &)point
+{
+    UNUSED_PARAM(point);
+    ASSERT_NOT_REACHED();
+    return CGPointZero;
+}
+
 // This is set by DRT when it wants to listen for notifications.
 static BOOL accessibilityShouldRepostNotifications;
 + (void)accessibilitySetShouldRepostNotifications:(BOOL)repost
index 958928164cbbd8386c878d0f471e63ade7c1cf9c..b7e29eca120f80ff4c9f13d2a2d035aca5eed3c7 100644 (file)
@@ -350,6 +350,10 @@ using namespace std;
 #define NSAccessibilityScrollToVisibleAction @"AXScrollToVisible"
 #endif
 
+#ifndef NSAccessibilityPathAttribute
+#define NSAccessibilityPathAttribute @"AXPath"
+#endif
+
 // Math attributes
 #define NSAccessibilityMathRootRadicandAttribute @"AXMathRootRadicand"
 #define NSAccessibilityMathRootIndexAttribute @"AXMathRootIndex"
@@ -1035,6 +1039,9 @@ static id textMarkerRangeFromVisiblePositions(AXObjectCache *cache, VisiblePosit
         [additional addObject:NSAccessibilityMathFencedCloseAttribute];
     }
     
+    if (m_object->supportsPath())
+        [additional addObject:NSAccessibilityPathAttribute];
+    
     return additional;
 }
 
@@ -1478,23 +1485,18 @@ static NSMutableArray* convertToNSArray(const AccessibilityObject::Accessibility
     return [self textMarkerRangeFromVisiblePositions:selection.visibleStart() endPosition:selection.visibleEnd()];
 }
 
-- (NSValue *)position
+- (CGPoint)convertPointToScreenSpace:(FloatPoint &)point
 {
-    IntRect rect = pixelSnappedIntRect(m_object->elementRect());
-    NSPoint point;
-    
     FrameView* frameView = m_object->documentFrameView();
     
     // WebKit1 code path... platformWidget() exists.
     if (frameView && frameView->platformWidget()) {
         
-        // The Cocoa accessibility API wants the lower-left corner.
-        point = NSMakePoint(rect.x(), rect.maxY());
-        
-        if (frameView) {
-            NSView* view = frameView->documentView();
-            point = [[view window] convertBaseToScreen:[view convertPoint: point toView:nil]];
-        }
+        NSPoint nsPoint = (NSPoint)point;
+        NSView* view = frameView->documentView();
+        nsPoint = [[view window] convertBaseToScreen:[view convertPoint:nsPoint toView:nil]];
+        return CGPointMake(nsPoint.x, nsPoint.y);
+
     } else {
         
         // Find the appropriate scroll view to use to convert the contents to the window.
@@ -1507,8 +1509,9 @@ static NSMutableArray* convertToNSArray(const AccessibilityObject::Accessibility
             }
         }
         
+        IntPoint intPoint = (IntPoint)point;
         if (scrollView)
-            rect = scrollView->contentsToRootView(rect);
+            intPoint = scrollView->contentsToRootView(intPoint);
         
         Page* page = m_object->page();
         
@@ -1517,13 +1520,63 @@ static NSMutableArray* convertToNSArray(const AccessibilityObject::Accessibility
         if (parent && page && page->chrome()->client()->isEmptyChromeClient())
             page = parent->page();
         
-        if (page)
-            point = page->chrome()->rootViewToScreen(rect).location();
-        else
-            point = rect.location();
+        if (page) {
+            IntRect rect = IntRect(intPoint, IntSize(0, 0));            
+            intPoint = page->chrome()->rootViewToScreen(rect).location();
+        }
+        
+        return intPoint;
+    }
+}
+
+static void WebTransformCGPathToNSBezierPath(void *info, const CGPathElement *element)
+{
+    NSBezierPath *bezierPath = (NSBezierPath *)info;
+    switch (element->type) {
+    case kCGPathElementMoveToPoint:
+        [bezierPath moveToPoint:element->points[0]];
+        break;
+    case kCGPathElementAddLineToPoint:
+        [bezierPath lineToPoint:element->points[0]];
+        break;
+    case kCGPathElementAddCurveToPoint:
+        [bezierPath curveToPoint:element->points[0] controlPoint1:element->points[1] controlPoint2:element->points[2]];
+        break;
+    case kCGPathElementCloseSubpath:
+        [bezierPath closePath];
+        break;
+    default:
+        break;
     }
+}
+
+- (NSBezierPath *)bezierPathFromPath:(CGPathRef)path
+{
+    NSBezierPath *bezierPath = [NSBezierPath bezierPath];
+    CGPathApply(path, bezierPath, WebTransformCGPathToNSBezierPath);
+    return bezierPath;
+}
+
+- (NSBezierPath *)path
+{
+    Path path = m_object->elementPath();
+    if (path.isEmpty())
+        return NULL;
+    
+    CGPathRef transformedPath = [self convertPathToScreenSpace:path];
+    return [self bezierPathFromPath:transformedPath];
+}
+
+- (NSValue *)position
+{
+    IntRect rect = pixelSnappedIntRect(m_object->elementRect());
+    
+    // The Cocoa accessibility API wants the lower-left corner.
+    FloatPoint floatPoint = FloatPoint(rect.x(), rect.maxY());
+
+    CGPoint cgPoint = [self convertPointToScreenSpace:floatPoint];
     
-    return [NSValue valueWithPoint:point];
+    return [NSValue valueWithPoint:NSMakePoint(cgPoint.x, cgPoint.y)];
 }
 
 typedef HashMap<int, NSString*> AccessibilityRoleMap;
@@ -2295,6 +2348,8 @@ static NSString* roleValueToNSString(AccessibilityRole value)
     
     if ([attributeName isEqualToString: NSAccessibilityPositionAttribute])
         return [self position];
+    if ([attributeName isEqualToString:NSAccessibilityPathAttribute])
+        return [self path];
     
     if ([attributeName isEqualToString: NSAccessibilityWindowAttribute] ||
         [attributeName isEqualToString: NSAccessibilityTopLevelUIElementAttribute]) {
index 4a98a3d33aec056eeb7a4b7fadc3ef3b7e352433..73a0c17c8573380bc4fb73de5b8b9f8823435c61 100644 (file)
@@ -1,3 +1,34 @@
+2013-04-09  Chris Fleizach  <cfleizach@apple.com>
+
+        AX: The bounding paths should be made available through accessibility
+        https://bugs.webkit.org/show_bug.cgi?id=113817
+
+        Reviewed by David Kilzer.
+
+        Add a pathDescription property for testing so that it's possible
+        to verify that a path is being returned correctly.
+
+        * DumpRenderTree/AccessibilityUIElement.cpp:
+        (getPathDescriptionCallback):
+        (AccessibilityUIElement::pathDescription):
+        (AccessibilityUIElement::getJSClass):
+        * DumpRenderTree/AccessibilityUIElement.h:
+        (AccessibilityUIElement):
+        * DumpRenderTree/ios/AccessibilityUIElementIOS.mm:
+        (_CGPathEnumerationIteration):
+        (AccessibilityUIElement::pathDescription):
+        * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+        (AccessibilityUIElement::pathDescription):
+        * WebKitTestRunner/InjectedBundle/AccessibilityUIElement.cpp:
+        (WTR::AccessibilityUIElement::pathDescription):
+        (WTR):
+        * WebKitTestRunner/InjectedBundle/AccessibilityUIElement.h:
+        (AccessibilityUIElement):
+        * WebKitTestRunner/InjectedBundle/Bindings/AccessibilityUIElement.idl:
+        * WebKitTestRunner/InjectedBundle/mac/AccessibilityUIElementMac.mm:
+        (WTR::AccessibilityUIElement::pathDescription):
+        (WTR):
+
 2013-04-09  Raphael Kubo da Costa  <raphael.kubo.da.costa@intel.com>
 
         [EFL] Declare TEST_THEME_DIR in a single place.
index 76b44deb91785df0e13b93b55a3024a01d5298d8..4cb3dae34c916dada12160f9c67da3fe16cdfe77 100644 (file)
@@ -855,6 +855,12 @@ static JSValueRef getInsertionPointLineNumberCallback(JSContextRef context, JSOb
     return JSValueMakeNumber(context, toAXElement(thisObject)->insertionPointLineNumber());
 }
 
+static JSValueRef getPathDescriptionCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
+{
+    JSRetainPtr<JSStringRef> pathDescription(Adopt, toAXElement(thisObject)->pathDescription());
+    return JSValueMakeString(context, pathDescription.get());
+}
+
 static JSValueRef getSelectedTextRangeCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception)
 {
     JSRetainPtr<JSStringRef> selectedTextRange(Adopt, toAXElement(thisObject)->selectedTextRange());
@@ -1087,6 +1093,10 @@ AccessibilityUIElement AccessibilityUIElement::verticalScrollbar() const { retur
 AccessibilityUIElement AccessibilityUIElement::uiElementAttributeValue(JSStringRef) const { return 0; }
 #endif
 
+#if !PLATFORM(MAC) && !PLATFORM(IOS)
+JSStringRef AccessibilityUIElement::pathDescription() const { return 0; }
+#endif
+
 #if !PLATFORM(WIN)
 bool AccessibilityUIElement::isEqual(AccessibilityUIElement* otherElement)
 {
@@ -1205,6 +1215,7 @@ JSClassRef AccessibilityUIElement::getJSClass()
         { "intValue", getIntValueCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "minValue", getMinValueCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "maxValue", getMaxValueCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+        { "pathDescription", getPathDescriptionCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "childrenCount", getChildrenCountCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "rowCount", rowCountCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
         { "columnCount", columnCountCallback, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
index 03b56697514d5a2f496001ea315ee9ab5d3e3e67..f27ad117c5ba7cf7bf6063b5a77c2333c35a0661 100644 (file)
@@ -129,6 +129,7 @@ public:
     double intValue() const;
     double minValue();
     double maxValue();
+    JSStringRef pathDescription() const;
     JSStringRef valueDescription();
     int insertionPointLineNumber();
     JSStringRef selectedTextRange();
index 81d7643ae6adfe514540f968e956606dc663a725..61387010f588383a7960948fd684ba32be479422 100644 (file)
@@ -341,6 +341,43 @@ void AccessibilityUIElement::elementsForRange(unsigned location, unsigned length
     }
 }
 
+static void _CGPathEnumerationIteration(void *info, const CGPathElement *element)
+{
+    NSMutableString *result = (NSMutableString *)info;
+    CGPoint* points = element->points;
+    switch (element->type) {
+    case kCGPathElementMoveToPoint:
+        [result appendString:@"\tMove to point\n"];
+        break;
+        
+    case kCGPathElementAddLineToPoint:
+        [result appendString:@"\tLine to\n"];
+        break;
+        
+    case kCGPathElementAddQuadCurveToPoint:
+        [result appendString:@"\tQuad curve to\n"];
+        break;
+        
+    case kCGPathElementAddCurveToPoint:
+        [result appendString:@"\tCurve to\n"];
+        break;
+        
+    case kCGPathElementCloseSubpath:
+        [result appendString:@"\tClose\n"];
+        break;
+    }
+}
+
+JSStringRef AccessibilityUIElement::pathDescription() const
+{
+    NSMutableString *result = [NSMutableString stringWithString:@"\nStart Path\n"];
+    CGPathRef pathRef = [m_element _accessibilityPath];
+    
+    CGPathApply(pathRef, result, _CGPathEnumerationIteration);
+    
+    return [result createJSStringRef];
+}
+
 #pragma mark Unused
 
 void AccessibilityUIElement::getLinkedUIElements(Vector<AccessibilityUIElement>& elementVector)
index 168038e42c979ea52ce206756bce1949714017fb..353ea8d67c93d96963d1aab485a2daea4dfe6507 100644 (file)
 #define NSAccessibilityDropEffectsAttribute @"AXDropEffects"
 #endif
 
+#ifndef NSAccessibilityPathAttribute
+#define NSAccessibilityPathAttribute @"AXPath"
+#endif
+
 typedef void (*AXPostedNotificationCallback)(id element, NSString* notification, void* context);
 
 @interface NSObject (WebKitAccessibilityAdditions)
@@ -1126,6 +1130,39 @@ AccessibilityUIElement AccessibilityUIElement::verticalScrollbar() const
     return 0;
 }
 
+JSStringRef AccessibilityUIElement::pathDescription() const
+{
+    BEGIN_AX_OBJC_EXCEPTIONS
+    NSMutableString *result = [NSMutableString stringWithString:@"\nStart Path\n"];
+    NSBezierPath *bezierPath = [m_element accessibilityAttributeValue:NSAccessibilityPathAttribute];
+    
+    NSUInteger elementCount = [bezierPath elementCount];
+    for (NSUInteger i = 0; i < elementCount; i++) {
+        switch ([bezierPath elementAtIndex:i]) {
+        case NSMoveToBezierPathElement:
+            [result appendString:@"\tMove to point\n"];
+            break;
+            
+        case NSLineToBezierPathElement:
+            [result appendString:@"\tLine to\n"];
+            break;
+            
+        case NSCurveToBezierPathElement:
+            [result appendString:@"\tCurve to\n"];
+            break;
+            
+        case NSClosePathBezierPathElement:
+            [result appendString:@"\tClose\n"];
+            break;
+        }
+    }
+    
+    return [result createJSStringRef];
+    END_AX_OBJC_EXCEPTIONS
+
+    return 0;
+}
+
 JSStringRef AccessibilityUIElement::selectedTextRange()
 {
     NSRange range = NSMakeRange(NSNotFound, 0);
index 1c23a6352d8818972574e420c635242187ab3026..e9ae39796639a93a73ef49714a4c40b48ccc3f58 100644 (file)
@@ -181,6 +181,8 @@ bool AccessibilityUIElement::isTextMarkerValid(AccessibilityTextMarker*) { retur
 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForIndex(int) { return 0; }
 void AccessibilityUIElement::scrollToMakeVisible() { }
 JSRetainPtr<JSStringRef> AccessibilityUIElement::supportedActions() const { return 0; }
+JSRetainPtr<JSStringRef> AccessibilityUIElement::pathDescription() const { return 0; }
+
 #endif
 
 } // namespace WTR
index 0da3fc7ac20430f82e78bf506f3b3fdb93fe161a..ed31099147139b0fe1d35769fc03b25e35d1f345 100644 (file)
@@ -232,6 +232,8 @@ public:
     // Returns an ordered list of supported actions for an element.
     JSRetainPtr<JSStringRef> supportedActions() const;
 
+    JSRetainPtr<JSStringRef> pathDescription() const;
+    
     // Notifications
     // Function callback should take one argument, the name of the notification.
     bool addNotificationListener(JSValueRef functionCallback);
index 546ec5bf7206c8abf2eecd5e9ca84ab5fa9c805e..6425cf84e99a8719673ef7b464f5839406e082f9 100644 (file)
@@ -169,6 +169,8 @@ interface AccessibilityUIElement {
     // Returns an ordered list of supported actions for an element.
     readonly attribute DOMString supportedActions;
 
+    readonly attribute DOMString pathDescription;
+    
     // Notification support.
     boolean addNotificationListener(in object callbackFunction);
     boolean removeNotificationListener();
index 1aab6e490c62aff5e67bcd0bfec941199ff483ff..8a9551c85fa8a87bde405a397af5e8020e8b9916 100644 (file)
 #define NSAccessibilityDropEffectsAttribute @"AXDropEffects"
 #endif
 
+#ifndef NSAccessibilityPathAttribute
+#define NSAccessibilityPathAttribute @"AXPath"
+#endif
+
 typedef void (*AXPostedNotificationCallback)(id element, NSString* notification, void* context);
 
 @interface NSObject (WebKitAccessibilityAdditions)
@@ -1483,6 +1487,40 @@ PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForIndex(i
     return 0;                                                                          
 }
 
+JSRetainPtr<JSStringRef> AccessibilityUIElement::pathDescription() const
+{
+    BEGIN_AX_OBJC_EXCEPTIONS
+    NSMutableString *result = [NSMutableString stringWithString:@"\nStart Path\n"];
+    NSBezierPath *bezierPath = [m_element accessibilityAttributeValue:NSAccessibilityPathAttribute];
+    
+    NSUInteger elementCount = [bezierPath elementCount];
+    NSPoint points[3];
+    for (NSUInteger i = 0; i < elementCount; i++) {
+        switch ([bezierPath elementAtIndex:i associatedPoints:points]) {
+        case NSMoveToBezierPathElement:
+            [result appendString:@"\tMove to point\n"];
+            break;
+            
+        case NSLineToBezierPathElement:
+            [result appendString:@"\tLine to\n"];
+            break;
+            
+        case NSCurveToBezierPathElement:
+            [result appendString:@"\tCurve to\n"];
+            break;
+            
+        case NSClosePathBezierPathElement:
+            [result appendString:@"\tClose\n"];
+            break;
+        }
+    }
+    
+    return [result createJSStringRef];
+    END_AX_OBJC_EXCEPTIONS
+    
+    return 0;
+}
+    
 JSRetainPtr<JSStringRef> AccessibilityUIElement::supportedActions() const
 {
     BEGIN_AX_OBJC_EXCEPTIONS