diff options
Diffstat (limited to 'WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm')
-rw-r--r-- | WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm | 425 |
1 files changed, 425 insertions, 0 deletions
diff --git a/WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm b/WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm new file mode 100644 index 0000000..81edd99 --- /dev/null +++ b/WebKitTools/DumpRenderTree/mac/AccessibilityUIElementMac.mm @@ -0,0 +1,425 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "DumpRenderTree.h" +#import "AccessibilityUIElement.h" + +#import <Foundation/Foundation.h> +#import <JavaScriptCore/JSStringRef.h> +#import <JavaScriptCore/JSStringRefCF.h> +#import <WebKit/WebFrame.h> +#import <WebKit/WebHTMLView.h> +#import <WebKit/WebTypesInternal.h> +#import <wtf/RetainPtr.h> +#import <wtf/Vector.h> + +AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element) + : m_element(element) +{ + [m_element retain]; +} + +AccessibilityUIElement::AccessibilityUIElement(const AccessibilityUIElement& other) + : m_element(other.m_element) +{ + [m_element retain]; +} + +AccessibilityUIElement::~AccessibilityUIElement() +{ + [m_element release]; +} + +@interface NSString (JSStringRefAdditions) +- (JSStringRef)createJSStringRef; +@end + +@implementation NSString (JSStringRefAdditions) + +- (JSStringRef)createJSStringRef +{ + return JSStringCreateWithCFString((CFStringRef)self); +} + +@end + +static NSString* descriptionOfValue(id valueObject, id focusedAccessibilityObject) +{ + if (!valueObject) + return NULL; + + if ([valueObject isKindOfClass:[NSArray class]]) + return [NSString stringWithFormat:@"<array of size %d>", [(NSArray*)valueObject count]]; + + if ([valueObject isKindOfClass:[NSNumber class]]) + return [(NSNumber*)valueObject stringValue]; + + if ([valueObject isKindOfClass:[NSValue class]]) { + NSString* type = [NSString stringWithCString:[valueObject objCType] encoding:NSASCIIStringEncoding]; + NSValue* value = (NSValue*)valueObject; + if ([type rangeOfString:@"NSRect"].length > 0) + return [NSString stringWithFormat:@"NSRect: %@", NSStringFromRect([value rectValue])]; + if ([type rangeOfString:@"NSPoint"].length > 0) + return [NSString stringWithFormat:@"NSPoint: %@", NSStringFromPoint([value pointValue])]; + if ([type rangeOfString:@"NSSize"].length > 0) + return [NSString stringWithFormat:@"NSSize: %@", NSStringFromSize([value sizeValue])]; + if ([type rangeOfString:@"NSRange"].length > 0) + return [NSString stringWithFormat:@"NSRange: %@", NSStringFromRange([value rangeValue])]; + } + + // Strip absolute URL paths + NSString* description = [valueObject description]; + NSRange range = [description rangeOfString:@"LayoutTests"]; + if (range.length) + return [description substringFromIndex:range.location]; + + // Strip pointer locations + if ([description rangeOfString:@"0x"].length) { + NSString* role = [focusedAccessibilityObject accessibilityAttributeValue:@"AXRole"]; + NSString* title = [focusedAccessibilityObject accessibilityAttributeValue:@"AXTitle"]; + if ([title length]) + return [NSString stringWithFormat:@"<%@: '%@'>", role, title]; + return [NSString stringWithFormat:@"<%@>", role]; + } + + return [valueObject description]; +} + +static NSString* attributesOfElement(id accessibilityObject) +{ + NSArray* supportedAttributes = [accessibilityObject accessibilityAttributeNames]; + + NSMutableString* attributesString = [NSMutableString string]; + for (NSUInteger i = 0; i < [supportedAttributes count]; ++i) { + NSString* attribute = [supportedAttributes objectAtIndex:i]; + + // Right now, position provides useless and screen-specific information, so we do not + // want to include it for the sake of universally passing tests. + if ([attribute isEqualToString:@"AXPosition"]) + continue; + + id valueObject = [accessibilityObject accessibilityAttributeValue:attribute]; + NSString* value = descriptionOfValue(valueObject, accessibilityObject); + [attributesString appendFormat:@"%@: %@\n", attribute, value]; + } + + return attributesString; +} + +static JSStringRef concatenateAttributeAndValue(NSString* attribute, NSString* value) +{ + Vector<UniChar> buffer([attribute length]); + [attribute getCharacters:buffer.data()]; + buffer.append(':'); + buffer.append(' '); + + Vector<UniChar> valueBuffer([value length]); + [value getCharacters:valueBuffer.data()]; + buffer.append(valueBuffer); + + return JSStringCreateWithCharacters(buffer.data(), buffer.size()); +} + +static void convertNSArrayToVector(NSArray* array, Vector<AccessibilityUIElement>& elementVector) +{ + NSUInteger count = [array count]; + for (NSUInteger i = 0; i < count; ++i) + elementVector.append(AccessibilityUIElement([array objectAtIndex:i])); +} + +static JSStringRef descriptionOfElements(Vector<AccessibilityUIElement>& elementVector) +{ + NSMutableString* allElementString = [NSMutableString string]; + size_t size = elementVector.size(); + for (size_t i = 0; i < size; ++i) { + NSString* attributes = attributesOfElement(elementVector[i].platformUIElement()); + [allElementString appendFormat:@"%@\n------------\n", attributes]; + } + + return [allElementString createJSStringRef]; +} + +void AccessibilityUIElement::getLinkedUIElements(Vector<AccessibilityUIElement>& elementVector) +{ + NSArray* linkedElements = [m_element accessibilityAttributeValue:NSAccessibilityLinkedUIElementsAttribute]; + convertNSArrayToVector(linkedElements, elementVector); +} + +void AccessibilityUIElement::getDocumentLinks(Vector<AccessibilityUIElement>& elementVector) +{ + NSArray* linkElements = [m_element accessibilityAttributeValue:@"AXLinkUIElements"]; + convertNSArrayToVector(linkElements, elementVector); +} + +void AccessibilityUIElement::getChildren(Vector<AccessibilityUIElement>& elementVector) +{ + NSArray* children = [m_element accessibilityAttributeValue:NSAccessibilityChildrenAttribute]; + convertNSArrayToVector(children, elementVector); +} + +AccessibilityUIElement AccessibilityUIElement::getChildAtIndex(unsigned index) +{ + Vector<AccessibilityUIElement> children; + getChildren(children); + + if (index < children.size()) + return children[index]; + return nil; +} + +AccessibilityUIElement AccessibilityUIElement::titleUIElement() +{ + id accessibilityObject = [m_element accessibilityAttributeValue:NSAccessibilityTitleUIElementAttribute]; + if (accessibilityObject) + return AccessibilityUIElement(accessibilityObject); + + return nil; +} + +JSStringRef AccessibilityUIElement::attributesOfLinkedUIElements() +{ + Vector<AccessibilityUIElement> linkedElements; + getLinkedUIElements(linkedElements); + return descriptionOfElements(linkedElements); +} + +JSStringRef AccessibilityUIElement::attributesOfDocumentLinks() +{ + Vector<AccessibilityUIElement> linkElements; + getDocumentLinks(linkElements); + return descriptionOfElements(linkElements); +} + +JSStringRef AccessibilityUIElement::attributesOfChildren() +{ + Vector<AccessibilityUIElement> children; + getChildren(children); + return descriptionOfElements(children); +} + +JSStringRef AccessibilityUIElement::allAttributes() +{ + NSString* attributes = attributesOfElement(m_element); + return [attributes createJSStringRef]; +} + +JSStringRef AccessibilityUIElement::parameterizedAttributeNames() +{ + NSArray* supportedParameterizedAttributes = [m_element accessibilityParameterizedAttributeNames]; + + NSMutableString* attributesString = [NSMutableString string]; + for (NSUInteger i = 0; i < [supportedParameterizedAttributes count]; ++i) { + [attributesString appendFormat:@"%@\n", [supportedParameterizedAttributes objectAtIndex:i]]; + } + + return [attributesString createJSStringRef]; +} + +JSStringRef AccessibilityUIElement::role() +{ + NSString* role = descriptionOfValue([m_element accessibilityAttributeValue:@"AXRole"], m_element); + return concatenateAttributeAndValue(@"AXRole", role); +} + +JSStringRef AccessibilityUIElement::title() +{ + NSString* title = descriptionOfValue([m_element accessibilityAttributeValue:@"AXTitle"], m_element); + return concatenateAttributeAndValue(@"AXTitle", title); +} + +JSStringRef AccessibilityUIElement::description() +{ + id description = descriptionOfValue([m_element accessibilityAttributeValue:@"AXDescription"], m_element); + return concatenateAttributeAndValue(@"AXDescription", description); +} + +double AccessibilityUIElement::width() +{ + NSValue* sizeValue = [m_element accessibilityAttributeValue:@"AXSize"]; + return static_cast<double>([sizeValue sizeValue].width); +} + +double AccessibilityUIElement::height() +{ + NSValue* sizeValue = [m_element accessibilityAttributeValue:@"AXSize"]; + return static_cast<double>([sizeValue sizeValue].height); +} + +double AccessibilityUIElement::intValue() +{ + id value = [m_element accessibilityAttributeValue:@"AXValue"]; + if ([value isKindOfClass:[NSNumber class]]) + return [(NSNumber*)value doubleValue]; + return 0.0f; +} + +double AccessibilityUIElement::minValue() +{ + id value = [m_element accessibilityAttributeValue:@"AXMinValue"]; + if ([value isKindOfClass:[NSNumber class]]) + return [(NSNumber*)value doubleValue]; + return 0.0f; +} + +double AccessibilityUIElement::maxValue() +{ + id value = [m_element accessibilityAttributeValue:@"AXMaxValue"]; + if ([value isKindOfClass:[NSNumber class]]) + return [(NSNumber*)value doubleValue]; + return 0.0; +} + +int AccessibilityUIElement::insertionPointLineNumber() +{ + id value = [m_element accessibilityAttributeValue:@"AXInsertionPointLineNumber"]; + if ([value isKindOfClass:[NSNumber class]]) + return [(NSNumber *)value intValue]; + return -1; +} + +bool AccessibilityUIElement::supportsPressAction() +{ + NSArray* actions = [m_element accessibilityActionNames]; + return [actions containsObject:@"AXPress"]; +} + +// parameterized attributes +int AccessibilityUIElement::lineForIndex(int index) +{ + id value = [m_element accessibilityAttributeValue:@"AXLineForIndex" forParameter:[NSNumber numberWithInt:index]]; + if ([value isKindOfClass:[NSNumber class]]) + return [(NSNumber *)value intValue]; + return -1; +} + +JSStringRef AccessibilityUIElement::boundsForRange(unsigned location, unsigned length) +{ + NSRange range = NSMakeRange(location, length); + id value = [m_element accessibilityAttributeValue:NSAccessibilityBoundsForRangeParameterizedAttribute forParameter:[NSValue valueWithRange:range]]; + NSRect rect = NSMakeRect(0,0,0,0); + if ([value isKindOfClass:[NSValue class]]) + rect = [value rectValue]; + + // don't return position information because it is platform dependent + NSMutableString* boundsDescription = [NSMutableString stringWithFormat:@"{{%f, %f}, {%f, %f}}",-1.0f,-1.0f,rect.size.width,rect.size.height]; + return [boundsDescription createJSStringRef]; +} + +JSStringRef AccessibilityUIElement::attributesOfColumnHeaders() +{ + // not yet defined in AppKit... odd + NSArray* columnHeadersArray = [m_element accessibilityAttributeValue:@"AXColumnHeaderUIElements"]; + Vector<AccessibilityUIElement> columnHeadersVector; + convertNSArrayToVector(columnHeadersArray, columnHeadersVector); + return descriptionOfElements(columnHeadersVector); +} + +JSStringRef AccessibilityUIElement::attributesOfRowHeaders() +{ + NSArray* rowHeadersArray = [m_element accessibilityAttributeValue:@"AXRowHeaderUIElements"]; + Vector<AccessibilityUIElement> rowHeadersVector; + convertNSArrayToVector(rowHeadersArray, rowHeadersVector); + return descriptionOfElements(rowHeadersVector); +} + +JSStringRef AccessibilityUIElement::attributesOfColumns() +{ + NSArray* columnsArray = [m_element accessibilityAttributeValue:NSAccessibilityColumnsAttribute]; + Vector<AccessibilityUIElement> columnsVector; + convertNSArrayToVector(columnsArray, columnsVector); + return descriptionOfElements(columnsVector); +} + +JSStringRef AccessibilityUIElement::attributesOfRows() +{ + NSArray* rowsArray = [m_element accessibilityAttributeValue:NSAccessibilityRowsAttribute]; + Vector<AccessibilityUIElement> rowsVector; + convertNSArrayToVector(rowsArray, rowsVector); + return descriptionOfElements(rowsVector); +} + +JSStringRef AccessibilityUIElement::attributesOfVisibleCells() +{ + NSArray* cellsArray = [m_element accessibilityAttributeValue:@"AXVisibleCells"]; + Vector<AccessibilityUIElement> cellsVector; + convertNSArrayToVector(cellsArray, cellsVector); + return descriptionOfElements(cellsVector); +} + +JSStringRef AccessibilityUIElement::attributesOfHeader() +{ + id headerObject = [m_element accessibilityAttributeValue:NSAccessibilityHeaderAttribute]; + if (!headerObject) + return [@"" createJSStringRef]; + + Vector<AccessibilityUIElement> headerVector; + headerVector.append(headerObject); + return descriptionOfElements(headerVector); +} + +int AccessibilityUIElement::indexInTable() +{ + NSNumber* indexNumber = [m_element accessibilityAttributeValue:NSAccessibilityIndexAttribute]; + if (!indexNumber) + return -1; + return [indexNumber intValue]; +} + +JSStringRef AccessibilityUIElement::rowIndexRange() +{ + NSValue* indexRange = [m_element accessibilityAttributeValue:@"AXRowIndexRange"]; + NSRange range = indexRange ? [indexRange rangeValue] : NSMakeRange(0,0); + NSMutableString* rangeDescription = [NSMutableString stringWithFormat:@"{%d, %d}",range.location, range.length]; + return [rangeDescription createJSStringRef]; +} + +JSStringRef AccessibilityUIElement::columnIndexRange() +{ + NSNumber* indexRange = [m_element accessibilityAttributeValue:@"AXColumnIndexRange"]; + NSRange range = indexRange ? [indexRange rangeValue] : NSMakeRange(0,0); + NSMutableString* rangeDescription = [NSMutableString stringWithFormat:@"{%d, %d}",range.location, range.length]; + return [rangeDescription createJSStringRef]; +} + +AccessibilityUIElement AccessibilityUIElement::cellForColumnAndRow(unsigned col, unsigned row) +{ + NSArray *colRowArray = [NSArray arrayWithObjects:[NSNumber numberWithUnsignedInt:col], [NSNumber numberWithUnsignedInt:row], nil]; + return [m_element accessibilityAttributeValue:@"AXCellForColumnAndRow" forParameter:colRowArray]; +} + +JSStringRef AccessibilityUIElement::selectedTextRange() +{ + NSNumber *indexRange = [m_element accessibilityAttributeValue:NSAccessibilitySelectedTextRangeAttribute]; + NSRange range = indexRange ? [indexRange rangeValue] : NSMakeRange(0,0); + NSMutableString *rangeDescription = [NSMutableString stringWithFormat:@"{%d, %d}",range.location, range.length]; + return [rangeDescription createJSStringRef]; +} + +void AccessibilityUIElement::setSelectedTextRange(unsigned location, unsigned length) +{ + NSRange textRange = NSMakeRange(location, length); + NSValue *textRangeValue = [NSValue valueWithRange:textRange]; + [m_element accessibilitySetValue:textRangeValue forAttribute:NSAccessibilitySelectedTextRangeAttribute]; +} |