/* * Copyright (C) 2014 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. AND ITS CONTRIBUTORS ``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 ITS 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 "InjectedBundle.h" #import "InjectedBundlePage.h" #import #import #import #import #import #import #import #import typedef void (*AXPostedNotificationCallback)(id element, NSString* notification, void* context); @interface NSObject (UIAccessibilityHidden) - (id)accessibilityFocusedUIElement; - (id)accessibilityHitTest:(CGPoint)point; - (id)accessibilityLinkedElement; - (id)accessibilityTitleElement; - (NSRange)accessibilityColumnRange; - (NSRange)accessibilityRowRange; - (id)accessibilityElementForRow:(NSInteger)row andColumn:(NSInteger)column; - (NSURL *)accessibilityURL; - (NSArray *)accessibilityHeaderElements; - (NSArray *)accessibilityDetailsElements; - (NSArray *)accessibilityErrorMessageElements; - (NSString *)accessibilityPlaceholderValue; - (NSString *)stringForRange:(NSRange)range; - (NSAttributedString *)attributedStringForRange:(NSRange)range; - (NSAttributedString *)attributedStringForElement; - (NSArray *)elementsForRange:(NSRange)range; - (NSString *)selectionRangeString; - (NSArray *)lineRectsAndText; - (CGPoint)accessibilityClickPoint; - (void)accessibilityModifySelection:(WebCore::TextGranularity)granularity increase:(BOOL)increase; - (NSRange)_accessibilitySelectedTextRange; - (void)_accessibilitySetSelectedTextRange:(NSRange)range; - (BOOL)accessibilityReplaceRange:(NSRange)range withText:(NSString *)string; - (BOOL)accessibilityInsertText:(NSString *)text; - (void)accessibilitySetPostedNotificationCallback:(AXPostedNotificationCallback)function withContext:(void*)context; - (CGFloat)_accessibilityMinValue; - (CGFloat)_accessibilityMaxValue; - (void)_accessibilitySetValue:(NSString *)value; - (void)_accessibilitySetFocus:(BOOL)focus; - (void)_accessibilityActivate; - (UIAccessibilityTraits)_axSelectedTrait; - (UIAccessibilityTraits)_axTextAreaTrait; - (UIAccessibilityTraits)_axSearchFieldTrait; - (NSString *)accessibilityCurrentState; - (NSUInteger)accessibilityRowCount; - (NSUInteger)accessibilityColumnCount; - (NSUInteger)accessibilityARIARowCount; - (NSUInteger)accessibilityARIAColumnCount; - (NSUInteger)accessibilityARIARowIndex; - (NSUInteger)accessibilityARIAColumnIndex; - (BOOL)accessibilityARIAIsBusy; - (BOOL)accessibilityARIALiveRegionIsAtomic; - (NSString *)accessibilityARIALiveRegionStatus; - (NSString *)accessibilityARIARelevantStatus; - (NSString *)accessibilityInvalidStatus; - (UIAccessibilityTraits)_axContainedByFieldsetTrait; - (id)_accessibilityFieldsetAncestor; - (BOOL)_accessibilityHasTouchEventListener; - (NSString *)accessibilityExpandedTextValue; - (NSString *)accessibilitySortDirection; - (BOOL)accessibilityIsExpanded; - (NSUInteger)accessibilityBlockquoteLevel; - (NSArray *)accessibilityFindMatchingObjects:(NSDictionary *)parameters; - (NSArray *)accessibilitySpeechHint; - (BOOL)_accessibilityIsStrongPasswordField; - (CGRect)accessibilityVisibleContentRect; - (NSString *)accessibilityTextualContext; - (NSString *)accessibilityRoleDescription; - (BOOL)accessibilityHasPopup; - (NSString *)accessibilityPopupValue; - (NSString *)accessibilityColorStringValue; - (BOOL)accessibilityHasDocumentRoleAncestor; - (BOOL)accessibilityHasWebApplicationAncestor; - (BOOL)accessibilityIsInDescriptionListDefinition; - (BOOL)accessibilityIsInDescriptionListTerm; - (BOOL)_accessibilityIsInTableCell; - (BOOL)accessibilityIsAttributeSettable:(NSString *)attributeName; - (BOOL)accessibilityIsRequired; - (id)_accessibilityTableAncestor; - (id)_accessibilityLandmarkAncestor; - (id)_accessibilityListAncestor; - (id)_accessibilityPhotoDescription; - (NSArray *)accessibilityImageOverlayElements; - (NSRange)accessibilityVisibleCharacterRange; - (NSString *)_accessibilityWebRoleAsString; // TextMarker related - (NSArray *)textMarkerRange; - (NSInteger)lengthForTextMarkers:(NSArray *)textMarkers; - (NSString *)stringForTextMarkers:(NSArray *)markers; - (NSArray *)textRectsFromMarkers:(NSArray *)markers withText:(NSString *)text; - (id)startOrEndTextMarkerForTextMarkers:(NSArray*)textMarkers isStart:(BOOL)isStart; - (NSArray *)textMarkerRangeForMarkers:(NSArray *)textMarkers; - (NSInteger)positionForTextMarker:(id)marker; - (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) - (NSString *)accessibilityDOMIdentifier; - (CGPathRef)_accessibilityPath; @end @implementation NSString (JSStringRefAdditions) + (NSString *)stringWithJSStringRef:(JSStringRef)jsStringRef { if (!jsStringRef) return nil; return adoptCF(JSStringCopyCFString(kCFAllocatorDefault, jsStringRef)).bridgingAutorelease(); } - (JSRetainPtr)createJSStringRef { return adopt(JSStringCreateWithCFString((__bridge CFStringRef)self)); } @end namespace WTR { static JSRetainPtr concatenateAttributeAndValue(NSString *attribute, NSString *value) { Vector buffer([attribute length]); [attribute getCharacters:buffer.data()]; buffer.append(':'); buffer.append(' '); Vector valueBuffer([value length]); [value getCharacters:valueBuffer.data()]; buffer.appendVector(valueBuffer); return adopt(JSStringCreateWithCharacters(buffer.data(), buffer.size())); } AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element) : m_element(element) { } AccessibilityUIElement::AccessibilityUIElement(const AccessibilityUIElement& other) : JSWrappable() , m_element(other.m_element) { } AccessibilityUIElement::~AccessibilityUIElement() { } bool AccessibilityUIElement::isEqual(AccessibilityUIElement* otherElement) { if (!otherElement) return false; return platformUIElement() == otherElement->platformUIElement(); } JSRetainPtr AccessibilityUIElement::domIdentifier() const { id value = [m_element accessibilityDOMIdentifier]; if ([value isKindOfClass:[NSString class]]) return [value createJSStringRef]; return nullptr; } RefPtr AccessibilityUIElement::headerElementAtIndex(unsigned index) { NSArray *headers = [m_element accessibilityHeaderElements]; if (index < [headers count]) return AccessibilityUIElement::create([headers objectAtIndex:index]); return nullptr; } RefPtr AccessibilityUIElement::linkedElement() { id linkedElement = [m_element accessibilityLinkedElement]; if (linkedElement) return AccessibilityUIElement::create(linkedElement); return nullptr; } void AccessibilityUIElement::getLinkedUIElements(Vector >& elementVector) { } void AccessibilityUIElement::getDocumentLinks(Vector >& elementVector) { } JSValueRef AccessibilityUIElement::children() const { return makeJSArray(makeVector>([m_element accessibilityElements])); } void AccessibilityUIElement::getChildren(Vector >& elementVector) { NSInteger childCount = [m_element accessibilityElementCount]; for (NSInteger k = 0; k < childCount; ++k) elementVector.append(AccessibilityUIElement::create([m_element accessibilityElementAtIndex:k])); } void AccessibilityUIElement::getChildrenWithRange(Vector >& elementVector, unsigned location, unsigned length) { NSUInteger childCount = [m_element accessibilityElementCount]; for (NSUInteger k = location; k < childCount && k < (location+length); ++k) elementVector.append(AccessibilityUIElement::create([m_element accessibilityElementAtIndex:k])); } int AccessibilityUIElement::childrenCount() { Vector> children; getChildren(children); return children.size(); } RefPtr AccessibilityUIElement::elementAtPoint(int x, int y) { id element = [m_element accessibilityHitTest:CGPointMake(x, y)]; if (!element) return nil; return AccessibilityUIElement::create(element); } JSValueRef AccessibilityUIElement::elementsForRange(unsigned location, unsigned length) { NSArray *elementsForRange = [m_element elementsForRange:NSMakeRange(location, length)]; return makeJSArray(makeVector>(elementsForRange)); } unsigned AccessibilityUIElement::indexOfChild(AccessibilityUIElement* element) { return 0; } RefPtr AccessibilityUIElement::childAtIndex(unsigned index) { Vector > children; getChildrenWithRange(children, index, 1); if (children.size() == 1) return children[0]; return nullptr; } RefPtr AccessibilityUIElement::linkedUIElementAtIndex(unsigned index) { return nullptr; } JSValueRef AccessibilityUIElement::detailsElements() const { NSArray *elements = [m_element accessibilityDetailsElements]; if ([elements isKindOfClass:NSArray.class]) return makeJSArray(makeVector>(elements)); return { }; } JSValueRef AccessibilityUIElement::errorMessageElements() const { NSArray *elements = [m_element accessibilityErrorMessageElements]; if ([elements isKindOfClass:NSArray.class]) return makeJSArray(makeVector>(elements)); return { }; } RefPtr AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index) { return nullptr; } RefPtr AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index) { return nullptr; } RefPtr AccessibilityUIElement::ariaControlsElementAtIndex(unsigned index) { return nullptr; } RefPtr AccessibilityUIElement::ariaDetailsElementAtIndex(unsigned index) { return nil; } RefPtr AccessibilityUIElement::ariaErrorMessageElementAtIndex(unsigned index) { NSArray *elements = [m_element accessibilityErrorMessageElements]; if (![elements isKindOfClass:NSArray.class]) return nullptr; if (index < elements.count) return create([elements objectAtIndex:index]); return nullptr; } RefPtr AccessibilityUIElement::disclosedRowAtIndex(unsigned index) { return nullptr; } RefPtr AccessibilityUIElement::rowAtIndex(unsigned index) { return nullptr; } RefPtr AccessibilityUIElement::selectedChildAtIndex(unsigned index) const { return nullptr; } unsigned AccessibilityUIElement::selectedChildrenCount() const { return 0; } RefPtr AccessibilityUIElement::selectedRowAtIndex(unsigned index) { return nullptr; } RefPtr AccessibilityUIElement::titleUIElement() { id titleElement = [m_element accessibilityTitleElement]; if (titleElement) return AccessibilityUIElement::create(titleElement); return nullptr; } RefPtr AccessibilityUIElement::parentElement() { return nil; } RefPtr AccessibilityUIElement::disclosedByRow() { return nullptr; } JSRetainPtr AccessibilityUIElement::attributesOfLinkedUIElements() { return createJSString(); } JSRetainPtr AccessibilityUIElement::attributesOfDocumentLinks() { return createJSString(); } JSRetainPtr AccessibilityUIElement::attributesOfChildren() { return createJSString(); } JSRetainPtr AccessibilityUIElement::allAttributes() { return createJSString(); } JSRetainPtr AccessibilityUIElement::stringDescriptionOfAttributeValue(JSStringRef attribute) { if (JSStringIsEqualToUTF8CString(attribute, "AXVisibleCharacterRange")) return [NSStringFromRange([m_element accessibilityVisibleCharacterRange]) createJSStringRef]; return createJSString(); } JSRetainPtr AccessibilityUIElement::stringAttributeValue(JSStringRef attribute) { if (JSStringIsEqualToUTF8CString(attribute, "AXPlaceholderValue")) return [[m_element accessibilityPlaceholderValue] createJSStringRef]; if (JSStringIsEqualToUTF8CString(attribute, "AXRoleDescription")) return [[m_element accessibilityRoleDescription] createJSStringRef]; if (JSStringIsEqualToUTF8CString(attribute, "AXColorStringDescription")) return [[m_element accessibilityColorStringValue] createJSStringRef]; if (JSStringIsEqualToUTF8CString(attribute, "AXARIACurrent")) return [[m_element accessibilityCurrentState] createJSStringRef]; if (JSStringIsEqualToUTF8CString(attribute, "AXExpandedTextValue")) return [[m_element accessibilityExpandedTextValue] createJSStringRef]; if (JSStringIsEqualToUTF8CString(attribute, "AXInvalid")) return [[m_element accessibilityInvalidStatus] createJSStringRef]; if (JSStringIsEqualToUTF8CString(attribute, "AXSortDirection")) return [[m_element accessibilitySortDirection] createJSStringRef]; if (JSStringIsEqualToUTF8CString(attribute, "AXVisibleContentRect")) { CGRect screenRect = [m_element accessibilityVisibleContentRect]; NSString *rectStr = [NSString stringWithFormat:@"{%.2f, %.2f, %.2f, %.2f}", screenRect.origin.x, screenRect.origin.y, screenRect.size.width, screenRect.size.height]; return [rectStr createJSStringRef]; } if (JSStringIsEqualToUTF8CString(attribute, "AXTextualContext")) return [[m_element accessibilityTextualContext] createJSStringRef]; return createJSString(); } 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; } JSValueRef AccessibilityUIElement::uiElementArrayAttributeValue(JSStringRef attribute) const { return nullptr; } JSValueRef AccessibilityUIElement::rowHeaders() const { return nullptr; } JSValueRef AccessibilityUIElement::columnHeaders() const { return nullptr; } RefPtr AccessibilityUIElement::uiElementAttributeValue(JSStringRef attribute) const { return nullptr; } 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 [m_element accessibilityIsAttributeSettable:[NSString stringWithJSStringRef:attribute]]; } bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute) { return false; } JSRetainPtr AccessibilityUIElement::parameterizedAttributeNames() { return createJSString(); } JSRetainPtr AccessibilityUIElement::role() { return [[m_element _accessibilityWebRoleAsString] createJSStringRef]; } JSRetainPtr AccessibilityUIElement::subrole() { return createJSString(); } JSRetainPtr AccessibilityUIElement::roleDescription() { return concatenateAttributeAndValue(@"AXRoleDescription", [m_element accessibilityRoleDescription]); } JSRetainPtr AccessibilityUIElement::computedRoleString() { return createJSString(); } JSRetainPtr AccessibilityUIElement::title() { return createJSString(); } JSRetainPtr AccessibilityUIElement::description() { return concatenateAttributeAndValue(@"AXLabel", [m_element accessibilityLabel]); } JSRetainPtr AccessibilityUIElement::liveRegionRelevant() const { return [[m_element accessibilityARIARelevantStatus] createJSStringRef]; } JSRetainPtr AccessibilityUIElement::liveRegionStatus() const { return [[m_element accessibilityARIALiveRegionStatus] createJSStringRef]; } JSRetainPtr AccessibilityUIElement::orientation() const { return createJSString(); } JSRetainPtr AccessibilityUIElement::stringValue() { return concatenateAttributeAndValue(@"AXValue", [m_element accessibilityValue]); } JSRetainPtr AccessibilityUIElement::language() { return createJSString(); } JSRetainPtr AccessibilityUIElement::helpText() const { return concatenateAttributeAndValue(@"AXHint", [m_element accessibilityHint]); } 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() { return [m_element accessibilityClickPoint].x; } double AccessibilityUIElement::clickPointY() { return [m_element accessibilityClickPoint].y; } JSRetainPtr AccessibilityUIElement::lineRectsAndText() const { return [[[m_element lineRectsAndText] componentsJoinedByString:@"|"] createJSStringRef]; } double AccessibilityUIElement::intValue() const { return [[m_element accessibilityValue] integerValue]; } double AccessibilityUIElement::minValue() { return [m_element _accessibilityMinValue]; } double AccessibilityUIElement::maxValue() { return [m_element _accessibilityMaxValue]; } JSRetainPtr AccessibilityUIElement::valueDescription() { return createJSString(); } int AccessibilityUIElement::insertionPointLineNumber() { return -1; } bool AccessibilityUIElement::isPressActionSupported() { return false; } bool AccessibilityUIElement::isIncrementActionSupported() { return false; } bool AccessibilityUIElement::isDecrementActionSupported() { return false; } bool AccessibilityUIElement::isAtomicLiveRegion() const { return [m_element accessibilityARIALiveRegionIsAtomic]; } bool AccessibilityUIElement::isBusy() const { return [m_element accessibilityARIAIsBusy]; } bool AccessibilityUIElement::isEnabled() { return false; } bool AccessibilityUIElement::isRequired() const { return [m_element accessibilityIsRequired]; } RefPtr AccessibilityUIElement::focusedElement() const { if (id focusedUIElement = [m_element accessibilityFocusedUIElement]) return AccessibilityUIElement::create(focusedUIElement); return nullptr; } bool AccessibilityUIElement::isFocused() const { return false; } bool AccessibilityUIElement::isSelected() const { UIAccessibilityTraits traits = [m_element accessibilityTraits]; return (traits & [m_element _axSelectedTrait]) == [m_element _axSelectedTrait]; } bool AccessibilityUIElement::isSelectedOptionActive() const { return false; } bool AccessibilityUIElement::isIndeterminate() const { return false; } bool AccessibilityUIElement::isExpanded() const { return [m_element accessibilityIsExpanded]; } bool AccessibilityUIElement::isChecked() const { return false; } JSRetainPtr AccessibilityUIElement::currentStateValue() const { id value = [m_element accessibilityCurrentState]; if ([value isKindOfClass:[NSString class]]) return [value createJSStringRef]; return nullptr; } JSRetainPtr AccessibilityUIElement::sortDirection() const { id value = [m_element accessibilitySortDirection]; if ([value isKindOfClass:[NSString class]]) return [value createJSStringRef]; return nullptr; } int AccessibilityUIElement::hierarchicalLevel() const { return 0; } JSRetainPtr AccessibilityUIElement::classList() const { return nullptr; } JSRetainPtr AccessibilityUIElement::speakAs() { return [[[m_element accessibilitySpeechHint] componentsJoinedByString:@", "] createJSStringRef]; } bool AccessibilityUIElement::ariaIsGrabbed() const { return false; } JSRetainPtr AccessibilityUIElement::ariaDropEffects() const { return createJSString(); } // parameterized attributes int AccessibilityUIElement::lineForIndex(int index) { return -1; } JSRetainPtr AccessibilityUIElement::rangeForLine(int line) { return nullptr; } JSRetainPtr AccessibilityUIElement::rangeForPosition(int x, int y) { return nullptr; } JSRetainPtr AccessibilityUIElement::boundsForRange(unsigned location, unsigned length) { return createJSString(); } JSRetainPtr AccessibilityUIElement::stringForRange(unsigned location, unsigned length) { NSString *stringForRange = [m_element stringForRange:NSMakeRange(location, length)]; return [stringForRange createJSStringRef]; } JSRetainPtr AccessibilityUIElement::attributedStringForRange(unsigned location, unsigned length) { NSAttributedString *stringForRange = [m_element attributedStringForRange:NSMakeRange(location, length)]; return [[stringForRange description] createJSStringRef]; } JSRetainPtr AccessibilityUIElement::attributedStringForElement() { NSAttributedString *string = [m_element attributedStringForElement]; if (![string isKindOfClass:[NSAttributedString class]]) return nullptr; return [[string description] createJSStringRef]; } bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned location, unsigned length) { return false; } unsigned AccessibilityUIElement::uiElementCountForSearchPredicate(JSContextRef context, AccessibilityUIElement *startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly, bool immediateDescendantsOnly) { return 0; } RefPtr 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 results = [m_element accessibilityFindMatchingObjects:parameterizedAttribute]; if (![results isKindOfClass:[NSArray class]]) return nullptr; for (id element in results) { if ([element isAccessibilityElement]) return AccessibilityUIElement::create(element); } if (id firstResult = [results firstObject]) return AccessibilityUIElement::create(firstResult); return nullptr; } JSRetainPtr AccessibilityUIElement::selectTextWithCriteria(JSContextRef, JSStringRef ambiguityResolution, JSValueRef searchStrings, JSStringRef replacementString, JSStringRef activity) { return nullptr; } JSRetainPtr AccessibilityUIElement::attributesOfColumnHeaders() { return createJSString(); } JSRetainPtr AccessibilityUIElement::attributesOfRowHeaders() { return createJSString(); } JSRetainPtr AccessibilityUIElement::attributesOfColumns() { return createJSString(); } JSRetainPtr AccessibilityUIElement::attributesOfRows() { return createJSString(); } JSRetainPtr AccessibilityUIElement::attributesOfVisibleCells() { return createJSString(); } JSRetainPtr AccessibilityUIElement::attributesOfHeader() { return createJSString(); } JSRetainPtr AccessibilityUIElement::traits() { return concatenateAttributeAndValue(@"AXTraits", [NSString stringWithFormat:@"%qu", [m_element accessibilityTraits]]); } JSRetainPtr AccessibilityUIElement::identifier() { return concatenateAttributeAndValue(@"AXIdentifier", [m_element accessibilityIdentifier]); } bool AccessibilityUIElement::hasContainedByFieldsetTrait() { UIAccessibilityTraits traits = [m_element accessibilityTraits]; return (traits & [m_element _axContainedByFieldsetTrait]) == [m_element _axContainedByFieldsetTrait]; } RefPtr AccessibilityUIElement::fieldsetAncestorElement() { id ancestorElement = [m_element _accessibilityFieldsetAncestor]; if (ancestorElement) return AccessibilityUIElement::create(ancestorElement); return nullptr; } 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]; } int AccessibilityUIElement::rowCount() { return [m_element accessibilityRowCount]; } int AccessibilityUIElement::columnCount() { return [m_element accessibilityColumnCount]; } bool AccessibilityUIElement::isInCell() const { return [m_element _accessibilityIsInTableCell]; } bool AccessibilityUIElement::isInTable() const { return [m_element _accessibilityTableAncestor] != nullptr; } bool AccessibilityUIElement::isInLandmark() const { return [m_element _accessibilityLandmarkAncestor] != nullptr; } bool AccessibilityUIElement::isInList() const { return [m_element _accessibilityListAncestor] != nullptr; } int AccessibilityUIElement::indexInTable() { return -1; } JSRetainPtr 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 AccessibilityUIElement::columnIndexRange() { NSRange range = [m_element accessibilityColumnRange]; NSMutableString* rangeDescription = [NSMutableString stringWithFormat:@"{%lu, %lu}", (unsigned long)range.location, (unsigned long)range.length]; return [rangeDescription createJSStringRef]; } RefPtr AccessibilityUIElement::cellForColumnAndRow(unsigned col, unsigned row) { return AccessibilityUIElement::create([m_element accessibilityElementForRow:row andColumn:col]); } RefPtr AccessibilityUIElement::horizontalScrollbar() const { return nullptr; } RefPtr AccessibilityUIElement::verticalScrollbar() const { return nullptr; } void AccessibilityUIElement::scrollToMakeVisible() { } void AccessibilityUIElement::scrollToGlobalPoint(int x, int y) { } void AccessibilityUIElement::scrollToMakeVisibleWithSubFocus(int x, int y, int width, int height) { } JSRetainPtr AccessibilityUIElement::selectedTextRange() { NSRange range = [m_element _accessibilitySelectedTextRange]; NSMutableString *rangeDescription = [NSMutableString stringWithFormat:@"{%lu, %lu}", static_cast(range.location), static_cast(range.length)]; return [rangeDescription createJSStringRef]; } bool AccessibilityUIElement::setSelectedTextMarkerRange(AccessibilityTextMarkerRange*) { return false; } bool AccessibilityUIElement::setSelectedTextRange(unsigned location, unsigned length) { [m_element _accessibilitySetSelectedTextRange:NSMakeRange(location, length)]; return true; } void AccessibilityUIElement::increment() { [m_element accessibilityIncrement]; } void AccessibilityUIElement::decrement() { [m_element accessibilityDecrement]; } void AccessibilityUIElement::showMenu() { } void AccessibilityUIElement::press() { [m_element _accessibilityActivate]; } void AccessibilityUIElement::dismiss() { [m_element accessibilityPerformEscape]; } void AccessibilityUIElement::setSelectedChild(AccessibilityUIElement* element) const { } void AccessibilityUIElement::setSelectedChildAtIndex(unsigned index) const { } void AccessibilityUIElement::removeSelectionAtIndex(unsigned index) const { } void AccessibilityUIElement::clearSelectedChildren() const { } JSRetainPtr AccessibilityUIElement::accessibilityValue() const { return createJSString(); } JSRetainPtr AccessibilityUIElement::documentEncoding() { return createJSString(); } JSRetainPtr AccessibilityUIElement::documentURI() { return createJSString(); } void AccessibilityUIElement::assistiveTechnologySimulatedFocus() { [m_element accessibilityElementDidBecomeFocused]; } 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]; } void AccessibilityUIElement::increaseTextSelection() { [m_element accessibilityModifySelection:WebCore::TextGranularity::CharacterGranularity increase:YES]; } void AccessibilityUIElement::decreaseTextSelection() { [m_element accessibilityModifySelection:WebCore::TextGranularity::CharacterGranularity increase:NO]; } JSRetainPtr AccessibilityUIElement::stringForSelection() { NSString *stringForRange = [m_element selectionRangeString]; return [stringForRange createJSStringRef]; } 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; } JSRetainPtr AccessibilityUIElement::url() { NSURL *url = [m_element accessibilityURL]; return [[url absoluteString] createJSStringRef]; } bool AccessibilityUIElement::addNotificationListener(JSValueRef 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; } bool 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; return true; } bool AccessibilityUIElement::isFocusable() const { return false; } bool AccessibilityUIElement::isSelectable() const { return false; } bool AccessibilityUIElement::isMultiSelectable() const { return false; } bool AccessibilityUIElement::isVisible() const { return false; } bool AccessibilityUIElement::isOffScreen() const { return false; } JSRetainPtr AccessibilityUIElement::embeddedImageDescription() const { return concatenateAttributeAndValue(@"AXEmbeddedImageDescription", [m_element _accessibilityPhotoDescription]); } JSValueRef AccessibilityUIElement::imageOverlayElements() const { return makeJSArray(makeVector>([m_element accessibilityImageOverlayElements])); } bool AccessibilityUIElement::isCollapsed() const { return false; } bool AccessibilityUIElement::isIgnored() const { bool isAccessibilityElement = [m_element isAccessibilityElement]; return !isAccessibilityElement; } bool AccessibilityUIElement::isSingleLine() const { return false; } bool AccessibilityUIElement::isMultiLine() const { return false; } bool AccessibilityUIElement::hasPopup() const { return [m_element accessibilityHasPopup]; } JSRetainPtr AccessibilityUIElement::popupValue() const { return [[m_element accessibilityPopupValue] createJSStringRef]; } bool AccessibilityUIElement::hasDocumentRoleAncestor() const { return [m_element accessibilityHasDocumentRoleAncestor]; } bool AccessibilityUIElement::hasWebApplicationAncestor() const { return [m_element accessibilityHasWebApplicationAncestor]; } bool AccessibilityUIElement::isInDescriptionListDetail() const { // The names are inconsistent here (isInDescriptionListDetail vs. isInDescriptionListDefinition) // because the iOS interface requires the latter form. return [m_element accessibilityIsInDescriptionListDefinition]; } bool AccessibilityUIElement::isInDescriptionListTerm() const { return [m_element accessibilityIsInDescriptionListTerm]; } void AccessibilityUIElement::takeFocus() { [m_element _accessibilitySetFocus:YES]; } void AccessibilityUIElement::takeSelection() { } void AccessibilityUIElement::addSelection() { } void AccessibilityUIElement::removeSelection() { } // Text markers RefPtr 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::create(textMarkerRange); } RefPtr AccessibilityUIElement::misspellingTextMarkerRange(AccessibilityTextMarkerRange* start, bool forward) { id misspellingRange = [m_element misspellingTextMarkerRange:start->platformTextMarkerRange() forward:forward]; return AccessibilityTextMarkerRange::create(misspellingRange); } RefPtr AccessibilityUIElement::textMarkerRangeForElement(AccessibilityUIElement* element) { id textMarkerRange = [element->platformUIElement() textMarkerRange]; return AccessibilityTextMarkerRange::create(textMarkerRange); } int AccessibilityUIElement::textMarkerRangeLength(AccessibilityTextMarkerRange* range) { return [m_element lengthForTextMarkers:range->platformTextMarkerRange()]; } RefPtr AccessibilityUIElement::previousTextMarker(AccessibilityTextMarker* textMarker) { id previousMarker = [m_element previousMarkerForMarker:textMarker->platformTextMarker()]; return AccessibilityTextMarker::create(previousMarker); } RefPtr AccessibilityUIElement::nextTextMarker(AccessibilityTextMarker* textMarker) { id nextMarker = [m_element nextMarkerForMarker:textMarker->platformTextMarker()]; return AccessibilityTextMarker::create(nextMarker); } JSRetainPtr AccessibilityUIElement::stringForTextMarkerRange(AccessibilityTextMarkerRange* markerRange) { id textMarkers = markerRange->platformTextMarkerRange(); if (![textMarkers isKindOfClass:[NSArray class]]) return createJSString(); return [[m_element stringForTextMarkers:textMarkers] createJSStringRef]; } JSRetainPtr AccessibilityUIElement::rectsForTextMarkerRange(AccessibilityTextMarkerRange* markerRange, JSStringRef text) { id textMarkers = markerRange->platformTextMarkerRange(); if (![textMarkers isKindOfClass:[NSArray class]]) return createJSString(); return [[[m_element textRectsFromMarkers:textMarkers withText:[NSString stringWithJSStringRef:text]] componentsJoinedByString:@","] createJSStringRef]; } RefPtr AccessibilityUIElement::textMarkerRangeForMarkers(AccessibilityTextMarker* startMarker, AccessibilityTextMarker* endMarker) { NSArray *textMarkers = @[startMarker->platformTextMarker(), endMarker->platformTextMarker()]; id textMarkerRange = [m_element textMarkerRangeForMarkers:textMarkers]; return AccessibilityTextMarkerRange::create(textMarkerRange); } RefPtr AccessibilityUIElement::startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range) { id textMarkers = range->platformTextMarkerRange(); id textMarker = [m_element startOrEndTextMarkerForTextMarkers:textMarkers isStart:YES]; return AccessibilityTextMarker::create(textMarker); } RefPtr AccessibilityUIElement::endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range) { id textMarkers = range->platformTextMarkerRange(); id textMarker = [m_element startOrEndTextMarkerForTextMarkers:textMarkers isStart:NO]; return AccessibilityTextMarker::create(textMarker); } RefPtr AccessibilityUIElement::endTextMarkerForBounds(int x, int y, int width, int height) { return nullptr; } RefPtr AccessibilityUIElement::startTextMarkerForBounds(int x, int y, int width, int height) { return nullptr; } bool AccessibilityUIElement::replaceTextInRange(JSStringRef string, int location, int length) { return [m_element accessibilityReplaceRange:NSMakeRange(location, length) withText:[NSString stringWithJSStringRef:string]]; } bool AccessibilityUIElement::insertText(JSStringRef text) { return [m_element accessibilityInsertText:[NSString stringWithJSStringRef:text]]; } RefPtr AccessibilityUIElement::textMarkerForPoint(int x, int y) { return nullptr; } RefPtr AccessibilityUIElement::accessibilityElementForTextMarker(AccessibilityTextMarker* marker) { id obj = [m_element accessibilityObjectForTextMarker:marker->platformTextMarker()]; if (obj) return AccessibilityUIElement::create(obj); return nullptr; } JSRetainPtr AccessibilityUIElement::attributedStringForTextMarkerRange(AccessibilityTextMarkerRange* markerRange) { return nullptr; } JSRetainPtr AccessibilityUIElement::attributedStringForTextMarkerRangeWithOptions(AccessibilityTextMarkerRange* markerRange, bool) { return nullptr; } bool AccessibilityUIElement::attributedStringForTextMarkerRangeContainsAttribute(JSStringRef attribute, AccessibilityTextMarkerRange* range) { return false; } int AccessibilityUIElement::indexForTextMarker(AccessibilityTextMarker* marker) { return [m_element positionForTextMarker:(__bridge id)marker->platformTextMarker()]; } bool AccessibilityUIElement::isTextMarkerValid(AccessibilityTextMarker* textMarker) { return false; } RefPtr AccessibilityUIElement::textMarkerForIndex(int textIndex) { return nullptr; } RefPtr AccessibilityUIElement::startTextMarker() { return nullptr; } RefPtr AccessibilityUIElement::endTextMarker() { return nullptr; } RefPtr AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker) { return nullptr; } RefPtr AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker) { return nullptr; } RefPtr AccessibilityUIElement::previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker* textMarker) { return nullptr; } RefPtr AccessibilityUIElement::nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker* textMarker) { return nullptr; } RefPtr AccessibilityUIElement::paragraphTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker) { return nullptr; } RefPtr AccessibilityUIElement::nextParagraphEndTextMarkerForTextMarker(AccessibilityTextMarker* textMarker) { return nullptr; } RefPtr AccessibilityUIElement::previousParagraphStartTextMarkerForTextMarker(AccessibilityTextMarker* textMarker) { return nullptr; } RefPtr AccessibilityUIElement::sentenceTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker) { return nullptr; } RefPtr AccessibilityUIElement::nextSentenceEndTextMarkerForTextMarker(AccessibilityTextMarker* textMarker) { return nullptr; } RefPtr AccessibilityUIElement::previousSentenceStartTextMarkerForTextMarker(AccessibilityTextMarker* textMarker) { return nullptr; } RefPtr 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::create(textMarkerRange); } JSRetainPtr AccessibilityUIElement::mathPostscriptsDescription() const { return nullptr; } JSRetainPtr AccessibilityUIElement::mathPrescriptsDescription() const { return nullptr; } 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 AccessibilityUIElement::pathDescription() const { NSMutableString *result = [NSMutableString stringWithString:@"\nStart Path\n"]; CGPathRef pathRef = [m_element _accessibilityPath]; CGPathApply(pathRef, result, _CGPathEnumerationIteration); return [result createJSStringRef]; } JSRetainPtr AccessibilityUIElement::supportedActions() const { return nullptr; } } // namespace WTR