blob: 6185e658e3a1b4162f5b74671f1aa144d9b8dbaf [file] [log] [blame]
/*
* Copyright (C) 2009 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 "config.h"
#import "AccessibilityUIElement.h"
#import "AccessibilityCommonMac.h"
#import "AccessibilityNotificationHandler.h"
#import "DumpRenderTree.h"
#import "JSBasics.h"
#import <Foundation/Foundation.h>
#import <JavaScriptCore/JSStringRefCF.h>
#import <WebCore/TextGranularity.h>
#import <WebKit/WebFrame.h>
#import <WebKit/WebHTMLView.h>
#import <wtf/RetainPtr.h>
#import <wtf/Vector.h>
#import <UIKit/UIKit.h>
typedef void (*AXPostedNotificationCallback)(id element, NSString* notification, void* context);
@interface NSObject (UIAccessibilityHidden)
- (id)accessibilityHitTest:(CGPoint)point;
- (id)accessibilityLinkedElement;
- (NSRange)accessibilityColumnRange;
- (NSRange)accessibilityRowRange;
- (id)accessibilityElementForRow:(NSInteger)row andColumn:(NSInteger)column;
- (NSURL *)accessibilityURL;
- (NSArray *)accessibilityHeaderElements;
- (NSString *)accessibilityPlaceholderValue;
- (NSString *)stringForRange:(NSRange)range;
- (NSAttributedString *)attributedStringForRange:(NSRange)range;
- (NSAttributedString *)attributedStringForElement;
- (NSArray *)elementsForRange:(NSRange)range;
- (NSString *)selectionRangeString;
- (BOOL)accessibilityInsertText:(NSString *)text;
- (CGPoint)accessibilityClickPoint;
- (void)accessibilityModifySelection:(WebCore::TextGranularity)granularity increase:(BOOL)increase;
- (void)accessibilitySetPostedNotificationCallback:(AXPostedNotificationCallback)function withContext:(void*)context;
- (CGFloat)_accessibilityMinValue;
- (CGFloat)_accessibilityMaxValue;
- (void)_accessibilitySetValue:(NSString *)value;
- (void)_accessibilityActivate;
- (UIAccessibilityTraits)_axSelectedTrait;
- (UIAccessibilityTraits)_axTextAreaTrait;
- (UIAccessibilityTraits)_axSearchFieldTrait;
- (NSString *)accessibilityARIACurrentStatus;
- (NSUInteger)accessibilityRowCount;
- (NSUInteger)accessibilityColumnCount;
- (NSUInteger)accessibilityARIARowCount;
- (NSUInteger)accessibilityARIAColumnCount;
- (NSUInteger)accessibilityARIARowIndex;
- (NSUInteger)accessibilityARIAColumnIndex;
- (UIAccessibilityTraits)_axContainedByFieldsetTrait;
- (id)_accessibilityFieldsetAncestor;
- (BOOL)_accessibilityHasTouchEventListener;
- (NSString *)accessibilityExpandedTextValue;
- (NSString *)accessibilitySortDirection;
- (BOOL)accessibilityIsExpanded;
- (NSUInteger)accessibilityBlockquoteLevel;
- (NSArray *)accessibilityFindMatchingObjects:(NSDictionary *)parameters;
- (NSArray *)accessibilitySpeechHint;
- (BOOL)_accessibilityIsStrongPasswordField;
- (NSString *)accessibilityTextualContext;
- (BOOL)accessibilityHasPopup;
- (NSString *)accessibilityPopupValue;
- (NSString *)_accessibilityPhotoDescription;
- (BOOL)accessibilityPerformEscape;
// TextMarker related
- (NSArray *)textMarkerRange;
- (NSInteger)lengthForTextMarkers:(NSArray *)textMarkers;
- (NSString *)stringForTextMarkers:(NSArray *)markers;
- (id)startOrEndTextMarkerForTextMarkers:(NSArray*)textMarkers isStart:(BOOL)isStart;
- (NSArray *)textMarkerRangeForMarkers:(NSArray *)textMarkers;
- (id)nextMarkerForMarker:(id)marker;
- (id)previousMarkerForMarker:(id)marker;
- (id)accessibilityObjectForTextMarker:(id)marker;
- (id)lineStartMarkerForMarker:(id)marker;
- (id)lineEndMarkerForMarker:(id)marker;
- (NSArray *)misspellingTextMarkerRange:(NSArray *)startTextMarkerRange forward:(BOOL)forward;
- (NSArray *)textMarkerRangeFromMarkers:(NSArray *)markers withText:(NSString *)text;
@end
@interface NSObject (WebAccessibilityObjectWrapperPrivate)
- (CGPathRef)_accessibilityPath;
@end
AccessibilityUIElement::AccessibilityUIElement(id element)
: m_element(element)
{
}
static JSRetainPtr<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.appendVector(valueBuffer);
return adopt(JSStringCreateWithCharacters(buffer.data(), buffer.size()));
}
#pragma mark iPhone Attributes
JSRetainPtr<JSStringRef> AccessibilityUIElement::identifier()
{
return concatenateAttributeAndValue(@"AXIdentifier", [m_element accessibilityIdentifier]);
}
bool AccessibilityUIElement::isTextArea() const
{
return ([m_element accessibilityTraits] & [m_element _axTextAreaTrait]) == [m_element _axTextAreaTrait];
}
bool AccessibilityUIElement::isSearchField() const
{
return ([m_element accessibilityTraits] & [m_element _axSearchFieldTrait]) == [m_element _axSearchFieldTrait];
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::traits()
{
return concatenateAttributeAndValue(@"AXTraits", [NSString stringWithFormat:@"%qu", [m_element accessibilityTraits]]);
}
int AccessibilityUIElement::elementTextPosition()
{
NSRange range = [[m_element valueForKey:@"elementTextRange"] rangeValue];
return range.location;
}
int AccessibilityUIElement::elementTextLength()
{
NSRange range = [[m_element valueForKey:@"elementTextRange"] rangeValue];
return range.length;
}
bool AccessibilityUIElement::hasContainedByFieldsetTrait()
{
UIAccessibilityTraits traits = [m_element accessibilityTraits];
return (traits & [m_element _axContainedByFieldsetTrait]) == [m_element _axContainedByFieldsetTrait];
}
AccessibilityUIElement AccessibilityUIElement::fieldsetAncestorElement()
{
id ancestorElement = [m_element _accessibilityFieldsetAncestor];
if (ancestorElement)
return AccessibilityUIElement(ancestorElement);
return nullptr;
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::url()
{
NSURL *url = [m_element accessibilityURL];
return [[url absoluteString] createJSStringRef];
}
double AccessibilityUIElement::x()
{
CGRect frame = [m_element accessibilityFrame];
return frame.origin.x;
}
double AccessibilityUIElement::y()
{
CGRect frame = [m_element accessibilityFrame];
return frame.origin.y;
}
double AccessibilityUIElement::width()
{
CGRect frame = [m_element accessibilityFrame];
return frame.size.width;
}
double AccessibilityUIElement::height()
{
CGRect frame = [m_element accessibilityFrame];
return frame.size.height;
}
double AccessibilityUIElement::clickPointX()
{
CGPoint centerPoint = [m_element accessibilityClickPoint];
return centerPoint.x;
}
double AccessibilityUIElement::clickPointY()
{
CGPoint centerPoint = [m_element accessibilityClickPoint];
return centerPoint.y;
}
void AccessibilityUIElement::getChildren(Vector<AccessibilityUIElement>& elementVector)
{
NSInteger childCount = [m_element accessibilityElementCount];
for (NSInteger k = 0; k < childCount; ++k)
elementVector.append(AccessibilityUIElement([m_element accessibilityElementAtIndex:k]));
}
void AccessibilityUIElement::getChildrenWithRange(Vector<AccessibilityUIElement>& elementVector, unsigned location, unsigned length)
{
// accessibilityElementAtIndex: takes an NSInteger.
// We want to preserve that in order to test against invalid indexes being input.
NSInteger maxValue = static_cast<NSInteger>(location + length);
for (NSInteger k = location; k < maxValue; ++k)
elementVector.append(AccessibilityUIElement([m_element accessibilityElementAtIndex:k]));
}
int AccessibilityUIElement::childrenCount()
{
Vector<AccessibilityUIElement> children;
getChildren(children);
return children.size();
}
AccessibilityUIElement AccessibilityUIElement::elementAtPoint(int x, int y)
{
id element = [m_element accessibilityHitTest:NSMakePoint(x, y)];
if (!element)
return nil;
return AccessibilityUIElement(element);
}
unsigned AccessibilityUIElement::indexOfChild(AccessibilityUIElement* element)
{
return 0;
}
AccessibilityUIElement AccessibilityUIElement::getChildAtIndex(unsigned index)
{
Vector<AccessibilityUIElement> children;
getChildrenWithRange(children, index, 1);
if (children.size() == 1)
return children[0];
return nil;
}
AccessibilityUIElement AccessibilityUIElement::headerElementAtIndex(unsigned index)
{
NSArray *headers = [m_element accessibilityHeaderElements];
if (index < [headers count])
return [headers objectAtIndex:index];
return 0;
}
AccessibilityUIElement AccessibilityUIElement::linkedElement()
{
id linkedElement = [m_element accessibilityLinkedElement];
if (linkedElement)
return AccessibilityUIElement(linkedElement);
return 0;
}
AccessibilityUIElement AccessibilityUIElement::linkedUIElementAtIndex(unsigned index)
{
return 0;
}
AccessibilityUIElement AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index)
{
return 0;
}
AccessibilityUIElement AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index)
{
return 0;
}
AccessibilityUIElement AccessibilityUIElement::ariaControlsElementAtIndex(unsigned index)
{
return 0;
}
AccessibilityUIElement AccessibilityUIElement::disclosedRowAtIndex(unsigned index)
{
return 0;
}
AccessibilityUIElement AccessibilityUIElement::selectedRowAtIndex(unsigned index)
{
return 0;
}
AccessibilityUIElement AccessibilityUIElement::rowAtIndex(unsigned index)
{
return 0;
}
AccessibilityUIElement AccessibilityUIElement::titleUIElement()
{
return 0;
}
void AccessibilityUIElement::dismiss()
{
[m_element accessibilityPerformEscape];
}
AccessibilityUIElement AccessibilityUIElement::parentElement()
{
id accessibilityObject = [m_element accessibilityContainer];
if (accessibilityObject)
return AccessibilityUIElement(accessibilityObject);
return nil;
}
AccessibilityUIElement AccessibilityUIElement::disclosedByRow()
{
return 0;
}
void AccessibilityUIElement::increaseTextSelection()
{
[m_element accessibilityModifySelection:WebCore::TextGranularity::CharacterGranularity increase:YES];
}
void AccessibilityUIElement::decreaseTextSelection()
{
[m_element accessibilityModifySelection:WebCore::TextGranularity::CharacterGranularity increase:NO];
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::speakAs()
{
return [[[m_element accessibilitySpeechHint] componentsJoinedByString:@", "] createJSStringRef];
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForSelection()
{
NSString *stringForRange = [m_element selectionRangeString];
return [stringForRange createJSStringRef];
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForRange(unsigned location, unsigned length)
{
NSString *stringForRange = [m_element stringForRange:NSMakeRange(location, length)];
return [stringForRange createJSStringRef];
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::attributedStringForRange(unsigned location, unsigned length)
{
NSRange range = NSMakeRange(location, length);
NSAttributedString* string = [m_element attributedStringForRange:range];
if (![string isKindOfClass:[NSAttributedString class]])
return 0;
NSString* stringWithAttrs = [string description];
return [stringWithAttrs createJSStringRef];
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::attributedStringForElement()
{
NSAttributedString *string = [m_element attributedStringForElement];
if (![string isKindOfClass:[NSAttributedString class]])
return nullptr;
return [[string description] createJSStringRef];
}
bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned, unsigned)
{
return false;
}
void AccessibilityUIElement::elementsForRange(unsigned location, unsigned length, Vector<AccessibilityUIElement>& elements)
{
NSArray *elementsForRange = [m_element elementsForRange:NSMakeRange(location, length)];
for (id object in elementsForRange) {
AccessibilityUIElement element = AccessibilityUIElement(object);
elements.append(element);
}
}
static void _CGPathEnumerationIteration(void *info, const CGPathElement *element)
{
NSMutableString *result = (NSMutableString *)info;
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;
}
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::pathDescription() const
{
NSMutableString *result = [NSMutableString stringWithString:@"\nStart Path\n"];
CGPathRef pathRef = [m_element _accessibilityPath];
CGPathApply(pathRef, result, _CGPathEnumerationIteration);
return [result createJSStringRef];
}
#if SUPPORTS_AX_TEXTMARKERS && PLATFORM(IOS_FAMILY)
// Text markers
AccessibilityTextMarkerRange AccessibilityUIElement::lineTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
{
id startTextMarker = [m_element lineStartMarkerForMarker:textMarker->platformTextMarker()];
id endTextMarker = [m_element lineEndMarkerForMarker:textMarker->platformTextMarker()];
NSArray *textMarkers = @[startTextMarker, endTextMarker];
id textMarkerRange = [m_element textMarkerRangeForMarkers:textMarkers];
return AccessibilityTextMarkerRange(textMarkerRange);
}
AccessibilityTextMarkerRange AccessibilityUIElement::misspellingTextMarkerRange(AccessibilityTextMarkerRange* startRange, bool forward)
{
id misspellingRange = [m_element misspellingTextMarkerRange:startRange->platformTextMarkerRange() forward:forward];
return AccessibilityTextMarkerRange(misspellingRange);
}
AccessibilityTextMarkerRange AccessibilityUIElement::textMarkerRangeForElement(AccessibilityUIElement* element)
{
id textMarkerRange = [element->platformUIElement() textMarkerRange];
return AccessibilityTextMarkerRange(textMarkerRange);
}
AccessibilityTextMarkerRange AccessibilityUIElement::selectedTextMarkerRange()
{
return nullptr;
}
bool AccessibilityUIElement::replaceTextInRange(JSStringRef, int, int)
{
return false;
}
bool AccessibilityUIElement::insertText(JSStringRef text)
{
return [m_element accessibilityInsertText:[NSString stringWithJSStringRef:text]];
}
void AccessibilityUIElement::resetSelectedTextMarkerRange()
{
}
int AccessibilityUIElement::textMarkerRangeLength(AccessibilityTextMarkerRange* range)
{
id textMarkers = range->platformTextMarkerRange();
return [m_element lengthForTextMarkers:textMarkers];
}
AccessibilityTextMarkerRange AccessibilityUIElement::textMarkerRangeForMarkers(AccessibilityTextMarker* startMarker, AccessibilityTextMarker* endMarker)
{
NSArray *textMarkers = @[startMarker->platformTextMarker(), endMarker->platformTextMarker()];
id textMarkerRange = [m_element textMarkerRangeForMarkers:textMarkers];
return AccessibilityTextMarkerRange(textMarkerRange);
}
AccessibilityTextMarker AccessibilityUIElement::startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range)
{
id textMarkers = range->platformTextMarkerRange();
id textMarker = [m_element startOrEndTextMarkerForTextMarkers:textMarkers isStart:YES];
return AccessibilityTextMarker(textMarker);
}
AccessibilityTextMarker AccessibilityUIElement::endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range)
{
id textMarkers = range->platformTextMarkerRange();
id textMarker = [m_element startOrEndTextMarkerForTextMarkers:textMarkers isStart:NO];
return AccessibilityTextMarker(textMarker);
}
AccessibilityUIElement AccessibilityUIElement::accessibilityElementForTextMarker(AccessibilityTextMarker* marker)
{
id obj = [m_element accessibilityObjectForTextMarker:marker->platformTextMarker()];
if (obj)
return AccessibilityUIElement(obj);
return nullptr;
}
AccessibilityTextMarker AccessibilityUIElement::endTextMarkerForBounds(int x, int y, int width, int height)
{
return nullptr;
}
AccessibilityTextMarker AccessibilityUIElement::startTextMarkerForBounds(int x, int y, int width, int height)
{
return nullptr;
}
AccessibilityTextMarker AccessibilityUIElement::textMarkerForPoint(int x, int y)
{
return nullptr;
}
AccessibilityTextMarker AccessibilityUIElement::previousTextMarker(AccessibilityTextMarker* textMarker)
{
id previousMarker = [m_element previousMarkerForMarker:textMarker->platformTextMarker()];
return AccessibilityTextMarker(previousMarker);
}
AccessibilityTextMarker AccessibilityUIElement::nextTextMarker(AccessibilityTextMarker* textMarker)
{
id nextMarker = [m_element nextMarkerForMarker:textMarker->platformTextMarker()];
return AccessibilityTextMarker(nextMarker);
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForTextMarkerRange(AccessibilityTextMarkerRange* markerRange)
{
id textMarkers = markerRange->platformTextMarkerRange();
if (!textMarkers || ![textMarkers isKindOfClass:[NSArray class]])
return WTR::createJSString();
return [[m_element stringForTextMarkers:textMarkers] createJSStringRef];
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::attributedStringForTextMarkerRange(AccessibilityTextMarkerRange*)
{
return nullptr;
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::attributedStringForTextMarkerRangeWithOptions(AccessibilityTextMarkerRange*, bool)
{
return nullptr;
}
bool AccessibilityUIElement::attributedStringForTextMarkerRangeContainsAttribute(JSStringRef, AccessibilityTextMarkerRange*)
{
return false;
}
int AccessibilityUIElement::indexForTextMarker(AccessibilityTextMarker*)
{
return -1;
}
bool AccessibilityUIElement::isTextMarkerValid(AccessibilityTextMarker*)
{
return false;
}
AccessibilityTextMarker AccessibilityUIElement::textMarkerForIndex(int)
{
return nullptr;
}
AccessibilityTextMarker AccessibilityUIElement::startTextMarker()
{
return nullptr;
}
AccessibilityTextMarker AccessibilityUIElement::endTextMarker()
{
return nullptr;
}
bool AccessibilityUIElement::setSelectedTextMarkerRange(AccessibilityTextMarkerRange*)
{
return false;
}
AccessibilityTextMarkerRange AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*)
{
return nullptr;
}
AccessibilityTextMarkerRange AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker*)
{
return nullptr;
}
AccessibilityTextMarker AccessibilityUIElement::previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker*)
{
return nullptr;
}
AccessibilityTextMarker AccessibilityUIElement::nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker*)
{
return nullptr;
}
AccessibilityTextMarkerRange AccessibilityUIElement::paragraphTextMarkerRangeForTextMarker(AccessibilityTextMarker*)
{
return nullptr;
}
AccessibilityTextMarker AccessibilityUIElement::previousParagraphStartTextMarkerForTextMarker(AccessibilityTextMarker*)
{
return nullptr;
}
AccessibilityTextMarker AccessibilityUIElement::nextParagraphEndTextMarkerForTextMarker(AccessibilityTextMarker*)
{
return nullptr;
}
AccessibilityTextMarkerRange AccessibilityUIElement::sentenceTextMarkerRangeForTextMarker(AccessibilityTextMarker*)
{
return nullptr;
}
AccessibilityTextMarker AccessibilityUIElement::previousSentenceStartTextMarkerForTextMarker(AccessibilityTextMarker*)
{
return nullptr;
}
AccessibilityTextMarker AccessibilityUIElement::nextSentenceEndTextMarkerForTextMarker(AccessibilityTextMarker*)
{
return nullptr;
}
AccessibilityTextMarkerRange AccessibilityUIElement::textMarkerRangeMatchesTextNearMarkers(JSStringRef text, AccessibilityTextMarker* startMarker, AccessibilityTextMarker* endMarker)
{
NSArray *textMarkers = nil;
if (startMarker->platformTextMarker() && endMarker->platformTextMarker())
textMarkers = @[startMarker->platformTextMarker(), endMarker->platformTextMarker()];
id textMarkerRange = [m_element textMarkerRangeFromMarkers:textMarkers withText:[NSString stringWithJSStringRef:text]];
return AccessibilityTextMarkerRange(textMarkerRange);
}
#endif // SUPPORTS_AX_TEXTMARKERS && PLATFORM(IOS_FAMILY)
#pragma mark Unused
void AccessibilityUIElement::getLinkedUIElements(Vector<AccessibilityUIElement>& elementVector)
{
}
void AccessibilityUIElement::getDocumentLinks(Vector<AccessibilityUIElement>& elementVector)
{
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfLinkedUIElements()
{
return WTR::createJSString();
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfDocumentLinks()
{
return WTR::createJSString();
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfChildren()
{
return WTR::createJSString();
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::allAttributes()
{
return WTR::createJSString();
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::stringAttributeValue(JSStringRef attribute)
{
if (JSStringIsEqualToUTF8CString(attribute, "AXPlaceholderValue"))
return [[m_element accessibilityPlaceholderValue] createJSStringRef];
if (JSStringIsEqualToUTF8CString(attribute, "AXARIACurrent"))
return [[m_element accessibilityARIACurrentStatus] createJSStringRef];
if (JSStringIsEqualToUTF8CString(attribute, "AXExpandedTextValue"))
return [[m_element accessibilityExpandedTextValue] createJSStringRef];
if (JSStringIsEqualToUTF8CString(attribute, "AXSortDirection"))
return [[m_element accessibilitySortDirection] createJSStringRef];
if (JSStringIsEqualToUTF8CString(attribute, "AXTextualContext"))
return [[m_element accessibilityTextualContext] createJSStringRef];
return WTR::createJSString();
}
bool AccessibilityUIElement::isPressActionSupported()
{
return false;
}
bool AccessibilityUIElement::isIncrementActionSupported()
{
return false;
}
bool AccessibilityUIElement::isDecrementActionSupported()
{
return false;
}
bool AccessibilityUIElement::boolAttributeValue(JSStringRef attribute)
{
if (JSStringIsEqualToUTF8CString(attribute, "AXHasTouchEventListener"))
return [m_element _accessibilityHasTouchEventListener];
if (JSStringIsEqualToUTF8CString(attribute, "AXIsStrongPasswordField"))
return [m_element _accessibilityIsStrongPasswordField];
return false;
}
bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute)
{
return false;
}
bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute)
{
return false;
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::parameterizedAttributeNames()
{
return WTR::createJSString();
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::role()
{
return WTR::createJSString();
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::subrole()
{
return WTR::createJSString();
}
bool AccessibilityUIElement::scrollPageUp()
{
return [m_element accessibilityScroll:UIAccessibilityScrollDirectionUp];
}
bool AccessibilityUIElement::scrollPageDown()
{
return [m_element accessibilityScroll:UIAccessibilityScrollDirectionDown];
}
bool AccessibilityUIElement::scrollPageLeft()
{
return [m_element accessibilityScroll:UIAccessibilityScrollDirectionLeft];
}
bool AccessibilityUIElement::scrollPageRight()
{
return [m_element accessibilityScroll:UIAccessibilityScrollDirectionRight];
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::roleDescription()
{
return WTR::createJSString();
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::computedRoleString()
{
return WTR::createJSString();
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::title()
{
return WTR::createJSString();
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::description()
{
return concatenateAttributeAndValue(@"AXLabel", [m_element accessibilityLabel]);
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::orientation() const
{
return WTR::createJSString();
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::stringValue()
{
return concatenateAttributeAndValue(@"AXValue", [m_element accessibilityValue]);
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::language()
{
return WTR::createJSString();
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::helpText() const
{
return concatenateAttributeAndValue(@"AXHint", [m_element accessibilityHint]);
}
double AccessibilityUIElement::intValue() const
{
return 0.0f;
}
double AccessibilityUIElement::minValue()
{
return [m_element _accessibilityMinValue];
}
double AccessibilityUIElement::maxValue()
{
return [m_element _accessibilityMaxValue];
}
void AccessibilityUIElement::setValue(JSStringRef valueText)
{
[m_element _accessibilitySetValue:[NSString stringWithJSStringRef:valueText]];
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::valueDescription()
{
return WTR::createJSString();
}
int AccessibilityUIElement::insertionPointLineNumber()
{
return -1;
}
bool AccessibilityUIElement::isEnabled()
{
return false;
}
bool AccessibilityUIElement::isRequired() const
{
return false;
}
bool AccessibilityUIElement::isFocused() const
{
return false;
}
bool AccessibilityUIElement::isSelected() const
{
UIAccessibilityTraits traits = [m_element accessibilityTraits];
bool result = (traits & [m_element _axSelectedTrait]) == [m_element _axSelectedTrait];
return result;
}
bool AccessibilityUIElement::isExpanded() const
{
return [m_element accessibilityIsExpanded];
}
bool AccessibilityUIElement::isChecked() const
{
return false;
}
bool AccessibilityUIElement::isIndeterminate() const
{
return false;
}
int AccessibilityUIElement::hierarchicalLevel() const
{
return 0;
}
bool AccessibilityUIElement::ariaIsGrabbed() const
{
return false;
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::ariaDropEffects() const
{
return WTR::createJSString();
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::embeddedImageDescription() const
{
return [[m_element _accessibilityPhotoDescription] createJSStringRef];
}
int AccessibilityUIElement::lineForIndex(int index)
{
return -1;
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::boundsForRange(unsigned location, unsigned length)
{
return WTR::createJSString();
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfColumnHeaders()
{
return WTR::createJSString();
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfRowHeaders()
{
return WTR::createJSString();
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfColumns()
{
return WTR::createJSString();
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfRows()
{
return WTR::createJSString();
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfVisibleCells()
{
return WTR::createJSString();
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfHeader()
{
return WTR::createJSString();
}
int AccessibilityUIElement::rowCount()
{
return [m_element accessibilityRowCount];
}
int AccessibilityUIElement::columnCount()
{
return [m_element accessibilityColumnCount];
}
int AccessibilityUIElement::indexInTable()
{
return -1;
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::rowIndexRange()
{
NSRange range = [m_element accessibilityRowRange];
NSMutableString* rangeDescription = [NSMutableString stringWithFormat:@"{%lu, %lu}", (unsigned long)range.location, (unsigned long)range.length];
return [rangeDescription createJSStringRef];
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::columnIndexRange()
{
NSRange range = [m_element accessibilityColumnRange];
NSMutableString* rangeDescription = [NSMutableString stringWithFormat:@"{%lu, %lu}", (unsigned long)range.location, (unsigned long)range.length];
return [rangeDescription createJSStringRef];
}
AccessibilityUIElement AccessibilityUIElement::cellForColumnAndRow(unsigned col, unsigned row)
{
return AccessibilityUIElement([m_element accessibilityElementForRow:row andColumn:col]);
}
void AccessibilityUIElement::scrollToMakeVisible()
{
}
void AccessibilityUIElement::scrollToMakeVisibleWithSubFocus(int x, int y, int width, int height)
{
}
void AccessibilityUIElement::scrollToGlobalPoint(int x, int y)
{
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::selectedTextRange()
{
return WTR::createJSString();
}
void AccessibilityUIElement::assistiveTechnologySimulatedFocus()
{
[m_element accessibilityElementDidBecomeFocused];
}
void AccessibilityUIElement::setSelectedTextRange(unsigned location, unsigned length)
{
}
void AccessibilityUIElement::increment()
{
[m_element accessibilityIncrement];
}
void AccessibilityUIElement::decrement()
{
[m_element accessibilityDecrement];
}
void AccessibilityUIElement::showMenu()
{
}
void AccessibilityUIElement::press()
{
[m_element _accessibilityActivate];
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::accessibilityValue() const
{
return WTR::createJSString();
}
void AccessibilityUIElement::clearSelectedChildren() const
{
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::documentEncoding()
{
return WTR::createJSString();
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::documentURI()
{
return WTR::createJSString();
}
bool AccessibilityUIElement::addNotificationListener(JSObjectRef functionCallback)
{
if (!functionCallback)
return false;
// iOS programmers should not be adding more than one notification listener per element.
// Other platforms may be different.
if (m_notificationHandler)
return false;
m_notificationHandler = adoptNS([[AccessibilityNotificationHandler alloc] init]);
[m_notificationHandler setPlatformElement:platformUIElement()];
[m_notificationHandler setCallback:functionCallback];
[m_notificationHandler startObserving];
return true;
}
void AccessibilityUIElement::removeNotificationListener()
{
// iOS programmers should not be trying to remove a listener that's already removed.
ASSERT(m_notificationHandler);
[m_notificationHandler stopObserving];
m_notificationHandler = nil;
}
bool AccessibilityUIElement::isFocusable() const
{
return false;
}
bool AccessibilityUIElement::isSelectable() const
{
return false;
}
bool AccessibilityUIElement::isMultiSelectable() const
{
return false;
}
bool AccessibilityUIElement::isSelectedOptionActive() const
{
return false;
}
bool AccessibilityUIElement::isVisible() const
{
return false;
}
bool AccessibilityUIElement::isOffScreen() const
{
return false;
}
bool AccessibilityUIElement::isCollapsed() const
{
return false;
}
bool AccessibilityUIElement::isIgnored() const
{
return ![m_element isAccessibilityElement];
}
bool AccessibilityUIElement::isSingleLine() const
{
return false;
}
bool AccessibilityUIElement::isMultiLine() const
{
return false;
}
bool AccessibilityUIElement::hasPopup() const
{
return [m_element accessibilityHasPopup];
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::popupValue() const
{
return [[m_element accessibilityPopupValue] createJSStringRef];
}
void AccessibilityUIElement::takeFocus()
{
}
void AccessibilityUIElement::takeSelection()
{
}
void AccessibilityUIElement::addSelection()
{
}
void AccessibilityUIElement::removeSelection()
{
}
unsigned AccessibilityUIElement::uiElementCountForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly, bool immediateDescendantsOnly)
{
return 0;
}
AccessibilityUIElement AccessibilityUIElement::uiElementForSearchPredicate(JSContextRef context, AccessibilityUIElement *startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly, bool immediateDescendantsOnly)
{
NSDictionary *parameterizedAttribute = searchPredicateParameterizedAttributeForSearchCriteria(context, startElement, isDirectionNext, 5, searchKey, searchText, visibleOnly, immediateDescendantsOnly);
id value = [m_element accessibilityFindMatchingObjects:parameterizedAttribute];
if (![value isKindOfClass:[NSArray class]])
return nullptr;
for (id element in value) {
if ([element isAccessibilityElement])
return AccessibilityUIElement(element);
}
return AccessibilityUIElement([value firstObject]);
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::selectTextWithCriteria(JSContextRef context, JSStringRef ambiguityResolution, JSValueRef searchStrings, JSStringRef replacementString, JSStringRef activity)
{
// FIXME: Implement.
return nullptr;
}
double AccessibilityUIElement::numberAttributeValue(JSStringRef attribute)
{
// Support test for table related attributes.
if (JSStringIsEqualToUTF8CString(attribute, "AXARIAColumnCount"))
return [m_element accessibilityARIAColumnCount];
if (JSStringIsEqualToUTF8CString(attribute, "AXARIARowCount"))
return [m_element accessibilityARIARowCount];
if (JSStringIsEqualToUTF8CString(attribute, "AXARIAColumnIndex"))
return [m_element accessibilityARIAColumnIndex];
if (JSStringIsEqualToUTF8CString(attribute, "AXARIARowIndex"))
return [m_element accessibilityARIARowIndex];
if (JSStringIsEqualToUTF8CString(attribute, "AXBlockquoteLevel"))
return [m_element accessibilityBlockquoteLevel];
return 0;
}
JSRetainPtr<JSStringRef> AccessibilityUIElement::classList() const
{
return nullptr;
}
void AccessibilityUIElement::uiElementArrayAttributeValue(JSStringRef, Vector<AccessibilityUIElement>&) const
{
}
void AccessibilityUIElement::columnHeaders(Vector<AccessibilityUIElement>&) const
{
}
void AccessibilityUIElement::rowHeaders(Vector<AccessibilityUIElement>&) const
{
}
unsigned AccessibilityUIElement::selectedChildrenCount() const
{
return 0;
}
AccessibilityUIElement AccessibilityUIElement::selectedChildAtIndex(unsigned) const
{
return 0;
}