AX: Implement updated CSS3 Speech for 'speak' and 'speak-as' properties
[WebKit-https.git] / Tools / WebKitTestRunner / InjectedBundle / ios / AccessibilityUIElementIOS.mm
1 /*
2  * Copyright (C) 2014 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "AccessibilityCommonMac.h"
28 #import "AccessibilityNotificationHandler.h"
29 #import "AccessibilityUIElement.h"
30 #import "InjectedBundle.h"
31 #import "InjectedBundlePage.h"
32 #import <Foundation/Foundation.h>
33 #import <JavaScriptCore/JSRetainPtr.h>
34 #import <JavaScriptCore/JSStringRef.h>
35 #import <JavaScriptCore/JSStringRefCF.h>
36 #import <UIKit/UIKit.h>
37 #import <WebCore/TextGranularity.h>
38 #import <WebKit/WKBundleFrame.h>
39 #import <wtf/RetainPtr.h>
40 #import <wtf/Vector.h>
41
42 typedef void (*AXPostedNotificationCallback)(id element, NSString* notification, void* context);
43
44 @interface NSObject (UIAccessibilityHidden)
45 - (id)accessibilityHitTest:(CGPoint)point;
46 - (id)accessibilityLinkedElement;
47 - (NSRange)accessibilityColumnRange;
48 - (NSRange)accessibilityRowRange;
49 - (id)accessibilityElementForRow:(NSInteger)row andColumn:(NSInteger)column;
50 - (NSURL *)accessibilityURL;
51 - (NSArray *)accessibilityHeaderElements;
52 - (NSString *)accessibilityPlaceholderValue;
53 - (NSString *)stringForRange:(NSRange)range;
54 - (NSAttributedString *)attributedStringForRange:(NSRange)range;
55 - (NSArray *)elementsForRange:(NSRange)range;
56 - (NSString *)selectionRangeString;
57 - (CGPoint)accessibilityClickPoint;
58 - (void)accessibilityModifySelection:(WebCore::TextGranularity)granularity increase:(BOOL)increase;
59 - (void)accessibilitySetPostedNotificationCallback:(AXPostedNotificationCallback)function withContext:(void*)context;
60 - (CGFloat)_accessibilityMinValue;
61 - (CGFloat)_accessibilityMaxValue;
62 - (void)_accessibilitySetValue:(NSString *)value;
63 - (void)_accessibilityActivate;
64 - (UIAccessibilityTraits)_axSelectedTrait;
65 - (UIAccessibilityTraits)_axTextAreaTrait;
66 - (UIAccessibilityTraits)_axSearchFieldTrait;
67 - (NSString *)accessibilityARIACurrentStatus;
68 - (NSUInteger)accessibilityRowCount;
69 - (NSUInteger)accessibilityColumnCount;
70 - (NSUInteger)accessibilityARIARowCount;
71 - (NSUInteger)accessibilityARIAColumnCount;
72 - (NSUInteger)accessibilityARIARowIndex;
73 - (NSUInteger)accessibilityARIAColumnIndex;
74 - (UIAccessibilityTraits)_axContainedByFieldsetTrait;
75 - (id)_accessibilityFieldsetAncestor;
76 - (BOOL)_accessibilityHasTouchEventListener;
77 - (NSString *)accessibilityExpandedTextValue;
78 - (NSString *)accessibilitySortDirection;
79 - (BOOL)accessibilityIsExpanded;
80 - (NSUInteger)accessibilityBlockquoteLevel;
81 - (NSArray *)accessibilityFindMatchingObjects:(NSDictionary *)parameters;
82 - (NSArray<NSString *> *)accessibilitySpeechHint;
83
84 // TextMarker related
85 - (NSArray *)textMarkerRange;
86 - (NSInteger)lengthForTextMarkers:(NSArray *)textMarkers;
87 - (NSString *)stringForTextMarkers:(NSArray *)markers;
88 - (id)startOrEndTextMarkerForTextMarkers:(NSArray*)textMarkers isStart:(BOOL)isStart;
89 - (NSArray *)textMarkerRangeForMarkers:(NSArray *)textMarkers;
90 - (id)nextMarkerForMarker:(id)marker;
91 - (id)previousMarkerForMarker:(id)marker;
92 - (id)accessibilityObjectForTextMarker:(id)marker;
93 - (id)lineStartMarkerForMarker:(id)marker;
94 - (id)lineEndMarkerForMarker:(id)marker;
95 - (NSArray *)textMarkerRangeFromMarkers:(NSArray *)markers withText:(NSString *)text;
96 @end
97
98 @interface NSObject (WebAccessibilityObjectWrapperPrivate)
99 - (CGPathRef)_accessibilityPath;
100 @end
101
102 @implementation NSString (JSStringRefAdditions)
103
104 + (NSString *)stringWithJSStringRef:(JSStringRef)jsStringRef
105 {
106     if (!jsStringRef)
107         return nil;
108     
109     CFStringRef cfString = JSStringCopyCFString(kCFAllocatorDefault, jsStringRef);
110     return [(NSString *)cfString autorelease];
111 }
112
113 - (JSStringRef)createJSStringRef
114 {
115     return JSStringCreateWithCFString((CFStringRef)self);
116 }
117
118 @end
119
120 namespace WTR {
121
122 static void convertNSArrayToVector(NSArray* array, Vector<RefPtr<AccessibilityUIElement> >& elementVector)
123 {
124     NSUInteger count = [array count];
125     for (NSUInteger i = 0; i < count; ++i)
126         elementVector.append(AccessibilityUIElement::create([array objectAtIndex:i]));
127 }    
128
129 static JSStringRef concatenateAttributeAndValue(NSString* attribute, NSString* value)
130 {
131     Vector<UniChar> buffer([attribute length]);
132     [attribute getCharacters:buffer.data()];
133     buffer.append(':');
134     buffer.append(' ');
135     
136     Vector<UniChar> valueBuffer([value length]);
137     [value getCharacters:valueBuffer.data()];
138     buffer.appendVector(valueBuffer);
139     
140     return JSStringCreateWithCharacters(buffer.data(), buffer.size());
141 }
142     
143 AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element)
144     : m_element(element)
145     , m_notificationHandler(0)
146 {
147     // FIXME: ap@webkit.org says ObjC objects need to be CFRetained/CFRelease to be GC-compliant on the mac.
148     [m_element retain];
149 }
150
151 AccessibilityUIElement::AccessibilityUIElement(const AccessibilityUIElement& other)
152     : JSWrappable()
153     , m_element(other.m_element)
154     , m_notificationHandler(0)
155 {
156     [m_element retain];
157 }
158
159 AccessibilityUIElement::~AccessibilityUIElement()
160 {
161     [m_element release];
162 }
163
164 bool AccessibilityUIElement::isEqual(AccessibilityUIElement* otherElement)
165 {
166     if (!otherElement)
167         return false;
168     return platformUIElement() == otherElement->platformUIElement();
169 }
170
171 RefPtr<AccessibilityUIElement> AccessibilityUIElement::headerElementAtIndex(unsigned index)
172 {
173     NSArray *headers = [m_element accessibilityHeaderElements];
174     if (index < [headers count])
175         return AccessibilityUIElement::create([headers objectAtIndex:index]);
176     
177     return nullptr;
178 }
179
180 RefPtr<AccessibilityUIElement> AccessibilityUIElement::linkedElement()
181 {
182     id linkedElement = [m_element accessibilityLinkedElement];
183     if (linkedElement)
184         return AccessibilityUIElement::create(linkedElement);
185     
186     return nullptr;
187 }
188
189 void AccessibilityUIElement::getLinkedUIElements(Vector<RefPtr<AccessibilityUIElement> >& elementVector)
190 {
191 }
192
193 void AccessibilityUIElement::getDocumentLinks(Vector<RefPtr<AccessibilityUIElement> >& elementVector)
194 {
195 }
196
197 void AccessibilityUIElement::getChildren(Vector<RefPtr<AccessibilityUIElement> >& elementVector)
198 {
199     NSInteger childCount = [m_element accessibilityElementCount];
200     for (NSInteger k = 0; k < childCount; ++k)
201         elementVector.append(AccessibilityUIElement::create([m_element accessibilityElementAtIndex:k]));
202 }
203
204 void AccessibilityUIElement::getChildrenWithRange(Vector<RefPtr<AccessibilityUIElement> >& elementVector, unsigned location, unsigned length)
205 {
206     NSUInteger childCount = [m_element accessibilityElementCount];
207     for (NSUInteger k = location; k < childCount && k < (location+length); ++k)
208         elementVector.append(AccessibilityUIElement::create([m_element accessibilityElementAtIndex:k]));
209 }
210
211 int AccessibilityUIElement::childrenCount()
212 {
213     Vector<RefPtr<AccessibilityUIElement>> children;
214     getChildren(children);
215
216     return children.size();
217 }
218
219 RefPtr<AccessibilityUIElement> AccessibilityUIElement::elementAtPoint(int x, int y)
220 {
221     id element = [m_element accessibilityHitTest:CGPointMake(x, y)];
222     if (!element)
223         return nil;
224     
225     return AccessibilityUIElement::create(element);
226 }
227     
228 static JSValueRef convertElementsToObjectArray(JSContextRef context, Vector<RefPtr<AccessibilityUIElement>>& elements)
229 {
230     JSValueRef arrayResult = JSObjectMakeArray(context, 0, nullptr, nullptr);
231     JSObjectRef arrayObj = JSValueToObject(context, arrayResult, nullptr);
232     size_t elementCount = elements.size();
233     for (size_t i = 0; i < elementCount; ++i)
234         JSObjectSetPropertyAtIndex(context, arrayObj, i, JSObjectMake(context, elements[i]->wrapperClass(), elements[i].get()), nullptr);
235     
236     return arrayResult;
237 }
238
239 JSValueRef AccessibilityUIElement::elementsForRange(unsigned location, unsigned length)
240 {
241     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
242     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
243
244     NSArray *elementsForRange = [m_element elementsForRange:NSMakeRange(location, length)];
245     Vector<RefPtr<AccessibilityUIElement>> elements;
246     convertNSArrayToVector(elementsForRange, elements);
247     return convertElementsToObjectArray(context, elements);
248 }
249
250 unsigned AccessibilityUIElement::indexOfChild(AccessibilityUIElement* element)
251 {
252     return 0;
253 }
254
255 RefPtr<AccessibilityUIElement> AccessibilityUIElement::childAtIndex(unsigned index)
256 {
257     Vector<RefPtr<AccessibilityUIElement> > children;
258     getChildrenWithRange(children, index, 1);
259
260     if (children.size() == 1)
261         return children[0];
262     return nullptr;
263 }
264
265 RefPtr<AccessibilityUIElement> AccessibilityUIElement::linkedUIElementAtIndex(unsigned index)
266 {
267     return nullptr;
268 }
269
270 RefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index)
271 {
272     return nullptr;
273 }
274
275 RefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index)
276 {
277     return 0;
278 }
279
280 RefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaControlsElementAtIndex(unsigned index)
281 {
282     return 0;
283 }
284
285 RefPtr<AccessibilityUIElement> AccessibilityUIElement::disclosedRowAtIndex(unsigned index)
286 {
287     return 0;
288 }
289
290 RefPtr<AccessibilityUIElement> AccessibilityUIElement::rowAtIndex(unsigned index)
291 {
292     return 0;
293 }
294
295 RefPtr<AccessibilityUIElement> AccessibilityUIElement::selectedChildAtIndex(unsigned index) const
296 {
297     return nullptr;
298 }
299
300 unsigned AccessibilityUIElement::selectedChildrenCount() const
301 {
302     return 0;
303 }
304
305 RefPtr<AccessibilityUIElement> AccessibilityUIElement::selectedRowAtIndex(unsigned index)
306 {
307     return nullptr;
308 }
309
310 RefPtr<AccessibilityUIElement> AccessibilityUIElement::titleUIElement()
311 {
312     return nullptr;
313 }
314
315 RefPtr<AccessibilityUIElement> AccessibilityUIElement::parentElement()
316 {
317     return nil;
318 }
319
320 RefPtr<AccessibilityUIElement> AccessibilityUIElement::disclosedByRow()
321 {
322     return nullptr;
323 }
324
325 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfLinkedUIElements()
326 {
327     return JSStringCreateWithCharacters(0, 0);
328 }
329
330 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfDocumentLinks()
331 {
332     return JSStringCreateWithCharacters(0, 0);
333 }
334
335 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfChildren()
336 {
337     return JSStringCreateWithCharacters(0, 0);
338 }
339
340 JSRetainPtr<JSStringRef> AccessibilityUIElement::allAttributes()
341 {
342     return JSStringCreateWithCharacters(0, 0);
343 }
344
345 JSRetainPtr<JSStringRef> AccessibilityUIElement::stringAttributeValue(JSStringRef attribute)
346 {
347     if (JSStringIsEqualToUTF8CString(attribute, "AXPlaceholderValue"))
348         return [[m_element accessibilityPlaceholderValue] createJSStringRef];
349     
350     if (JSStringIsEqualToUTF8CString(attribute, "AXARIACurrent"))
351         return [[m_element accessibilityARIACurrentStatus] createJSStringRef];
352
353     if (JSStringIsEqualToUTF8CString(attribute, "AXExpandedTextValue"))
354         return [[m_element accessibilityExpandedTextValue] createJSStringRef];
355     
356     if (JSStringIsEqualToUTF8CString(attribute, "AXSortDirection"))
357         return [[m_element accessibilitySortDirection] createJSStringRef];
358
359     return JSStringCreateWithCharacters(0, 0);
360 }
361
362 double AccessibilityUIElement::numberAttributeValue(JSStringRef attribute)
363 {
364     // Support test for table related attributes.
365     if (JSStringIsEqualToUTF8CString(attribute, "AXARIAColumnCount"))
366         return [m_element accessibilityARIAColumnCount];
367     if (JSStringIsEqualToUTF8CString(attribute, "AXARIARowCount"))
368         return [m_element accessibilityARIARowCount];
369     if (JSStringIsEqualToUTF8CString(attribute, "AXARIAColumnIndex"))
370         return [m_element accessibilityARIAColumnIndex];
371     if (JSStringIsEqualToUTF8CString(attribute, "AXARIARowIndex"))
372         return [m_element accessibilityARIARowIndex];
373     if (JSStringIsEqualToUTF8CString(attribute, "AXBlockquoteLevel"))
374         return [m_element accessibilityBlockquoteLevel];
375     
376     return 0;
377 }
378
379 JSValueRef AccessibilityUIElement::uiElementArrayAttributeValue(JSStringRef attribute) const
380 {
381     return nullptr;
382 }
383
384 JSValueRef AccessibilityUIElement::rowHeaders() const
385 {
386     return nullptr;
387 }
388
389 JSValueRef AccessibilityUIElement::columnHeaders() const
390 {
391     return nullptr;
392 }
393
394 RefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementAttributeValue(JSStringRef attribute) const
395 {
396     return nullptr;
397 }
398
399 bool AccessibilityUIElement::boolAttributeValue(JSStringRef attribute)
400 {
401     if (JSStringIsEqualToUTF8CString(attribute, "AXHasTouchEventListener"))
402         return [m_element _accessibilityHasTouchEventListener];
403     return false;
404 }
405
406 bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute)
407 {
408     return false;
409 }
410
411 bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute)
412 {
413     return false;
414 }
415
416 JSRetainPtr<JSStringRef> AccessibilityUIElement::parameterizedAttributeNames()
417 {
418     return JSStringCreateWithCharacters(0, 0);
419 }
420
421 JSRetainPtr<JSStringRef> AccessibilityUIElement::role()
422 {
423     return JSStringCreateWithCharacters(0, 0);
424 }
425
426 JSRetainPtr<JSStringRef> AccessibilityUIElement::subrole()
427 {
428     return JSStringCreateWithCharacters(0, 0);
429 }
430
431 JSRetainPtr<JSStringRef> AccessibilityUIElement::roleDescription()
432 {
433     return JSStringCreateWithCharacters(0, 0);
434 }
435
436 JSRetainPtr<JSStringRef> AccessibilityUIElement::computedRoleString()
437 {
438     // FIXME: implement
439     return JSStringCreateWithCharacters(0, 0);
440 }
441
442 JSRetainPtr<JSStringRef> AccessibilityUIElement::title()
443 {
444     return JSStringCreateWithCharacters(0, 0);
445 }
446
447 JSRetainPtr<JSStringRef> AccessibilityUIElement::description()
448 {
449     return concatenateAttributeAndValue(@"AXLabel", [m_element accessibilityLabel]);
450 }
451
452 JSRetainPtr<JSStringRef> AccessibilityUIElement::orientation() const
453 {
454     return JSStringCreateWithCharacters(0, 0);
455 }
456
457 JSRetainPtr<JSStringRef> AccessibilityUIElement::stringValue()
458 {
459     return concatenateAttributeAndValue(@"AXValue", [m_element accessibilityValue]);
460 }
461
462 JSRetainPtr<JSStringRef> AccessibilityUIElement::language()
463 {
464     return JSStringCreateWithCharacters(0, 0);
465 }
466
467 JSRetainPtr<JSStringRef> AccessibilityUIElement::helpText() const
468 {
469     return concatenateAttributeAndValue(@"AXHint", [m_element accessibilityHint]);
470 }
471
472 double AccessibilityUIElement::x()
473 {
474     CGRect frame = [m_element accessibilityFrame];
475     return frame.origin.x;
476 }
477
478 double AccessibilityUIElement::y()
479 {
480     CGRect frame = [m_element accessibilityFrame];
481     return frame.origin.y;
482 }
483
484 double AccessibilityUIElement::width()
485 {
486     CGRect frame = [m_element accessibilityFrame];
487     return frame.size.width;
488 }
489
490 double AccessibilityUIElement::height()
491 {
492     CGRect frame = [m_element accessibilityFrame];
493     return frame.size.height;
494 }
495
496 double AccessibilityUIElement::clickPointX()
497 {
498     return [m_element accessibilityClickPoint].x;
499 }
500
501 double AccessibilityUIElement::clickPointY()
502 {
503     return [m_element accessibilityClickPoint].y;
504 }
505
506 double AccessibilityUIElement::intValue() const
507 {
508     return 0;
509 }
510
511 double AccessibilityUIElement::minValue()
512 {
513     return [m_element _accessibilityMinValue];
514 }
515
516 double AccessibilityUIElement::maxValue()
517 {
518     return [m_element _accessibilityMaxValue];
519 }
520
521
522 JSRetainPtr<JSStringRef> AccessibilityUIElement::valueDescription()
523 {
524     return JSStringCreateWithCharacters(0, 0);
525 }
526
527 int AccessibilityUIElement::insertionPointLineNumber()
528 {
529     return -1;
530 }
531
532 bool AccessibilityUIElement::isPressActionSupported()
533 {
534     return false;
535 }
536
537 bool AccessibilityUIElement::isIncrementActionSupported()
538 {
539     return false;
540 }
541
542 bool AccessibilityUIElement::isDecrementActionSupported()
543 {
544     return false;
545 }
546
547 bool AccessibilityUIElement::isEnabled()
548 {
549     return false;
550 }
551
552 bool AccessibilityUIElement::isRequired() const
553 {
554     return false;
555 }
556
557 bool AccessibilityUIElement::isFocused() const
558 {
559     // FIXME: implement
560     return false;
561 }
562
563 bool AccessibilityUIElement::isSelected() const
564 {
565     UIAccessibilityTraits traits = [m_element accessibilityTraits];
566     return (traits & [m_element _axSelectedTrait]) == [m_element _axSelectedTrait];
567 }
568
569 bool AccessibilityUIElement::isSelectedOptionActive() const
570 {
571     // FIXME: implement
572     return false;
573 }
574
575 bool AccessibilityUIElement::isIndeterminate() const
576 {
577     // FIXME: implement
578     return false;
579 }
580
581 bool AccessibilityUIElement::isExpanded() const
582 {
583     return [m_element accessibilityIsExpanded];
584 }
585
586 bool AccessibilityUIElement::isChecked() const
587 {
588     return false;
589 }
590
591 int AccessibilityUIElement::hierarchicalLevel() const
592 {
593     return 0;
594 }
595
596 JSRetainPtr<JSStringRef> AccessibilityUIElement::classList() const
597 {
598     return nullptr;
599 }
600
601 JSRetainPtr<JSStringRef> AccessibilityUIElement::speakAs()
602 {
603     return [[[m_element accessibilitySpeechHint] componentsJoinedByString:@", "] createJSStringRef];
604 }
605
606 bool AccessibilityUIElement::ariaIsGrabbed() const
607 {
608     return false;
609 }
610
611 JSRetainPtr<JSStringRef> AccessibilityUIElement::ariaDropEffects() const
612 {
613     return JSStringCreateWithCharacters(0, 0);
614 }
615
616 // parameterized attributes
617 int AccessibilityUIElement::lineForIndex(int index)
618 {
619     return -1;
620 }
621
622 JSRetainPtr<JSStringRef> AccessibilityUIElement::rangeForLine(int line)
623 {
624     return nullptr;
625 }
626
627 JSRetainPtr<JSStringRef> AccessibilityUIElement::rangeForPosition(int x, int y)
628 {
629     return nullptr;
630 }
631
632 JSRetainPtr<JSStringRef> AccessibilityUIElement::boundsForRange(unsigned location, unsigned length)
633 {
634     return JSStringCreateWithCharacters(0, 0);
635 }
636
637 JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForRange(unsigned location, unsigned length)
638 {
639     NSString *stringForRange = [m_element stringForRange:NSMakeRange(location, length)];
640     if (!stringForRange)
641         return nullptr;
642     
643     return [stringForRange createJSStringRef];
644 }
645
646 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributedStringForRange(unsigned location, unsigned length)
647 {
648     NSAttributedString *stringForRange = [m_element attributedStringForRange:NSMakeRange(location, length)];
649     if (!stringForRange)
650         return nullptr;
651     
652     return [[stringForRange description] createJSStringRef];
653 }
654
655 bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned location, unsigned length)
656 {
657     return false;
658 }
659
660 unsigned AccessibilityUIElement::uiElementCountForSearchPredicate(JSContextRef context, AccessibilityUIElement *startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly, bool immediateDescendantsOnly)
661 {
662     return 0;
663 }
664
665 RefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementForSearchPredicate(JSContextRef context, AccessibilityUIElement *startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly, bool immediateDescendantsOnly)
666 {
667     NSDictionary *parameterizedAttribute = searchPredicateParameterizedAttributeForSearchCriteria(context, startElement, isDirectionNext, 5, searchKey, searchText, visibleOnly, immediateDescendantsOnly);
668     id value = [m_element accessibilityFindMatchingObjects:parameterizedAttribute];
669     if (![value isKindOfClass:[NSArray class]])
670         return nullptr;
671     for (id element in value) {
672         if ([element isAccessibilityElement])
673             return AccessibilityUIElement::create(element);
674     }
675     return AccessibilityUIElement::create([value firstObject]);
676 }
677
678 JSRetainPtr<JSStringRef> AccessibilityUIElement::selectTextWithCriteria(JSContextRef, JSStringRef ambiguityResolution, JSValueRef searchStrings, JSStringRef replacementString, JSStringRef activity)
679 {
680     return nullptr;
681 }
682
683 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfColumnHeaders()
684 {
685     return JSStringCreateWithCharacters(0, 0);
686 }
687
688 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfRowHeaders()
689 {
690     return JSStringCreateWithCharacters(0, 0);
691 }
692
693 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfColumns()
694 {
695     return JSStringCreateWithCharacters(0, 0);
696 }
697
698 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfRows()
699 {
700     return JSStringCreateWithCharacters(0, 0);
701 }
702
703 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfVisibleCells()
704 {
705     return JSStringCreateWithCharacters(0, 0);
706 }
707
708 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfHeader()
709 {
710     return JSStringCreateWithCharacters(0, 0);
711 }
712
713 JSRetainPtr<JSStringRef> AccessibilityUIElement::traits()
714 {
715     return concatenateAttributeAndValue(@"AXTraits", [NSString stringWithFormat:@"%qu", [m_element accessibilityTraits]]);
716 }
717
718 JSRetainPtr<JSStringRef> AccessibilityUIElement::identifier()
719 {
720     return concatenateAttributeAndValue(@"AXIdentifier", [m_element accessibilityIdentifier]);
721 }
722
723 bool AccessibilityUIElement::hasContainedByFieldsetTrait()
724 {
725     UIAccessibilityTraits traits = [m_element accessibilityTraits];
726     return (traits & [m_element _axContainedByFieldsetTrait]) == [m_element _axContainedByFieldsetTrait];
727 }
728
729 RefPtr<AccessibilityUIElement> AccessibilityUIElement::fieldsetAncestorElement()
730 {
731     id ancestorElement = [m_element _accessibilityFieldsetAncestor];
732     if (ancestorElement)
733         return AccessibilityUIElement::create(ancestorElement);
734     
735     return nullptr;
736 }
737
738 bool AccessibilityUIElement::isTextArea() const
739 {
740     return ([m_element accessibilityTraits] & [m_element _axTextAreaTrait]) == [m_element _axTextAreaTrait];
741 }
742
743 bool AccessibilityUIElement::isSearchField() const
744 {
745     return ([m_element accessibilityTraits] & [m_element _axSearchFieldTrait]) == [m_element _axSearchFieldTrait];
746 }
747     
748 int AccessibilityUIElement::rowCount()
749 {
750     return [m_element accessibilityRowCount];
751 }
752
753 int AccessibilityUIElement::columnCount()
754 {
755     return [m_element accessibilityColumnCount];
756 }
757
758 int AccessibilityUIElement::indexInTable()
759 {
760     return -1;
761 }
762
763 JSRetainPtr<JSStringRef> AccessibilityUIElement::rowIndexRange()
764 {
765     NSRange range = [m_element accessibilityRowRange];
766     NSMutableString* rangeDescription = [NSMutableString stringWithFormat:@"{%lu, %lu}", (unsigned long)range.location, (unsigned long)range.length];
767     return [rangeDescription createJSStringRef];
768 }
769
770 JSRetainPtr<JSStringRef> AccessibilityUIElement::columnIndexRange()
771 {
772     NSRange range = [m_element accessibilityColumnRange];
773     NSMutableString* rangeDescription = [NSMutableString stringWithFormat:@"{%lu, %lu}", (unsigned long)range.location, (unsigned long)range.length];
774     return [rangeDescription createJSStringRef];
775 }
776
777 RefPtr<AccessibilityUIElement> AccessibilityUIElement::cellForColumnAndRow(unsigned col, unsigned row)
778 {
779     return AccessibilityUIElement::create([m_element accessibilityElementForRow:row andColumn:col]);
780 }
781
782 RefPtr<AccessibilityUIElement> AccessibilityUIElement::horizontalScrollbar() const
783 {
784     return nullptr;
785 }
786
787 RefPtr<AccessibilityUIElement> AccessibilityUIElement::verticalScrollbar() const
788 {
789     return nullptr;
790 }
791
792 void AccessibilityUIElement::scrollToMakeVisible()
793 {
794 }
795     
796 void AccessibilityUIElement::scrollToGlobalPoint(int x, int y)
797 {
798 }
799     
800 void AccessibilityUIElement::scrollToMakeVisibleWithSubFocus(int x, int y, int width, int height)
801 {
802 }
803
804 JSRetainPtr<JSStringRef> AccessibilityUIElement::selectedTextRange()
805 {
806     return JSStringCreateWithCharacters(0, 0);
807 }
808
809 bool AccessibilityUIElement::setSelectedVisibleTextRange(AccessibilityTextMarkerRange*)
810 {
811     return false;
812 }
813
814 bool AccessibilityUIElement::setSelectedTextRange(unsigned location, unsigned length)
815 {
816     return false;
817 }
818
819 void AccessibilityUIElement::increment()
820 {
821     [m_element accessibilityIncrement];
822 }
823
824 void AccessibilityUIElement::decrement()
825 {
826     [m_element accessibilityDecrement];
827 }
828
829 void AccessibilityUIElement::showMenu()
830 {
831 }
832
833 void AccessibilityUIElement::press()
834 {
835     [m_element _accessibilityActivate];
836 }
837
838 void AccessibilityUIElement::setSelectedChild(AccessibilityUIElement* element) const
839 {
840 }
841
842 void AccessibilityUIElement::setSelectedChildAtIndex(unsigned index) const
843 {
844 }
845
846 void AccessibilityUIElement::removeSelectionAtIndex(unsigned index) const
847 {
848 }
849
850 void AccessibilityUIElement::clearSelectedChildren() const
851 {
852     // FIXME: implement
853 }
854
855 JSRetainPtr<JSStringRef> AccessibilityUIElement::accessibilityValue() const
856 {
857     // FIXME: implement
858     return JSStringCreateWithCharacters(0, 0);
859 }
860
861 JSRetainPtr<JSStringRef> AccessibilityUIElement::documentEncoding()
862 {
863     return JSStringCreateWithCharacters(0, 0);
864 }
865
866 JSRetainPtr<JSStringRef> AccessibilityUIElement::documentURI()
867 {
868     return JSStringCreateWithCharacters(0, 0);
869 }
870
871 void AccessibilityUIElement::assistiveTechnologySimulatedFocus()
872 {
873     [m_element accessibilityElementDidBecomeFocused];
874 }
875     
876 bool AccessibilityUIElement::scrollPageUp()
877 {
878     return [m_element accessibilityScroll:UIAccessibilityScrollDirectionUp];
879 }
880
881 bool AccessibilityUIElement::scrollPageDown()
882 {
883     return [m_element accessibilityScroll:UIAccessibilityScrollDirectionDown];
884 }
885 bool AccessibilityUIElement::scrollPageLeft()
886 {
887     return [m_element accessibilityScroll:UIAccessibilityScrollDirectionLeft];
888 }
889
890 bool AccessibilityUIElement::scrollPageRight()
891 {
892     return [m_element accessibilityScroll:UIAccessibilityScrollDirectionRight];
893 }
894
895 void AccessibilityUIElement::increaseTextSelection()
896 {
897     [m_element accessibilityModifySelection:WebCore::CharacterGranularity increase:YES];
898 }
899
900 void AccessibilityUIElement::decreaseTextSelection()
901 {
902     [m_element accessibilityModifySelection:WebCore::CharacterGranularity increase:NO];
903 }
904
905 JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForSelection()
906 {
907     NSString *stringForRange = [m_element selectionRangeString];
908     if (!stringForRange)
909         return nullptr;
910     
911     return [stringForRange createJSStringRef];
912 }
913     
914 int AccessibilityUIElement::elementTextPosition()
915 {
916     NSRange range = [[m_element valueForKey:@"elementTextRange"] rangeValue];
917     return range.location;
918 }
919
920 int AccessibilityUIElement::elementTextLength()
921 {
922     NSRange range = [[m_element valueForKey:@"elementTextRange"] rangeValue];
923     return range.length;    
924 }
925     
926 JSRetainPtr<JSStringRef> AccessibilityUIElement::url()
927 {
928     NSURL *url = [m_element accessibilityURL];
929     return [[url absoluteString] createJSStringRef];
930 }
931
932 bool AccessibilityUIElement::addNotificationListener(JSValueRef functionCallback)
933 {
934     if (!functionCallback)
935         return false;
936     
937     // iOS programmers should not be adding more than one notification listener per element.
938     // Other platforms may be different.
939     if (m_notificationHandler)
940         return false;
941     m_notificationHandler = [[AccessibilityNotificationHandler alloc] init];
942     [m_notificationHandler setPlatformElement:platformUIElement()];
943     [m_notificationHandler setCallback:functionCallback];
944     [m_notificationHandler startObserving];
945     
946     return true;
947 }
948
949 bool AccessibilityUIElement::removeNotificationListener()
950 {
951     // iOS programmers should not be trying to remove a listener that's already removed.
952     ASSERT(m_notificationHandler);
953     
954     [m_notificationHandler stopObserving];
955     [m_notificationHandler release];
956     m_notificationHandler = nil;
957     
958     return true;
959 }
960
961 bool AccessibilityUIElement::isFocusable() const
962 {
963     return false;
964 }
965
966 bool AccessibilityUIElement::isSelectable() const
967 {
968     // FIXME: implement
969     return false;
970 }
971
972 bool AccessibilityUIElement::isMultiSelectable() const
973 {
974     // FIXME: implement
975     return false;
976 }
977
978 bool AccessibilityUIElement::isVisible() const
979 {
980     // FIXME: implement
981     return false;
982 }
983
984 bool AccessibilityUIElement::isOffScreen() const
985 {
986     // FIXME: implement
987     return false;
988 }
989
990 bool AccessibilityUIElement::isCollapsed() const
991 {
992     // FIXME: implement
993     return false;
994 }
995
996 bool AccessibilityUIElement::isIgnored() const
997 {
998     bool isAccessibilityElement = [m_element isAccessibilityElement];
999     return !isAccessibilityElement;
1000 }
1001
1002 bool AccessibilityUIElement::isSingleLine() const
1003 {
1004     // FIXME: implement
1005     return false;
1006 }
1007
1008 bool AccessibilityUIElement::isMultiLine() const
1009 {
1010     // FIXME: implement
1011     return false;
1012 }
1013
1014 bool AccessibilityUIElement::hasPopup() const
1015 {
1016     return false;
1017 }
1018
1019 void AccessibilityUIElement::takeFocus()
1020 {
1021     // FIXME: implement
1022 }
1023
1024 void AccessibilityUIElement::takeSelection()
1025 {
1026     // FIXME: implement
1027 }
1028
1029 void AccessibilityUIElement::addSelection()
1030 {
1031     // FIXME: implement
1032 }
1033
1034 void AccessibilityUIElement::removeSelection()
1035 {
1036     // FIXME: implement
1037 }
1038
1039 // Text markers
1040 RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::lineTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
1041 {
1042     id startTextMarker = [m_element lineStartMarkerForMarker:(id)textMarker->platformTextMarker()];
1043     id endTextMarker = [m_element lineEndMarkerForMarker:(id)textMarker->platformTextMarker()];
1044     NSArray *textMarkers = [NSArray arrayWithObjects:startTextMarker, endTextMarker, nil];
1045     
1046     id textMarkerRange = [m_element textMarkerRangeForMarkers:textMarkers];
1047     return AccessibilityTextMarkerRange::create(textMarkerRange);
1048 }
1049
1050 RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeForElement(AccessibilityUIElement* element)
1051 {
1052     id textMarkerRange = [element->platformUIElement() textMarkerRange];
1053     return AccessibilityTextMarkerRange::create(textMarkerRange);
1054 }
1055
1056 int AccessibilityUIElement::textMarkerRangeLength(AccessibilityTextMarkerRange* range)
1057 {
1058     id textMarkers = (id)range->platformTextMarkerRange();    
1059     return [m_element lengthForTextMarkers:textMarkers];
1060 }
1061
1062 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousTextMarker(AccessibilityTextMarker* textMarker)
1063 {
1064     id previousMarker = [m_element previousMarkerForMarker:(id)textMarker->platformTextMarker()];
1065     return AccessibilityTextMarker::create(previousMarker);
1066 }
1067
1068 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextTextMarker(AccessibilityTextMarker* textMarker)
1069 {
1070     id nextMarker = [m_element nextMarkerForMarker:(id)textMarker->platformTextMarker()];
1071     return AccessibilityTextMarker::create(nextMarker);
1072 }
1073
1074 JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForTextMarkerRange(AccessibilityTextMarkerRange* markerRange)
1075 {
1076     id textMarkers = (id)markerRange->platformTextMarkerRange();
1077     if (!textMarkers || ![textMarkers isKindOfClass:[NSArray class]])
1078         return JSStringCreateWithCharacters(0, 0);
1079     return [[m_element stringForTextMarkers:textMarkers] createJSStringRef];
1080 }
1081
1082 RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeForMarkers(AccessibilityTextMarker* startMarker, AccessibilityTextMarker* endMarker)
1083 {
1084     NSArray *textMarkers = [NSArray arrayWithObjects:(id)startMarker->platformTextMarker(), (id)endMarker->platformTextMarker(), nil];
1085     id textMarkerRange = [m_element textMarkerRangeForMarkers:textMarkers];
1086     return AccessibilityTextMarkerRange::create(textMarkerRange);
1087 }
1088
1089 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range)
1090 {
1091     id textMarkers = (id)range->platformTextMarkerRange();
1092     id textMarker = [m_element startOrEndTextMarkerForTextMarkers:textMarkers isStart:YES];
1093     return AccessibilityTextMarker::create(textMarker);
1094 }
1095
1096 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range)
1097 {
1098     id textMarkers = (id)range->platformTextMarkerRange();
1099     id textMarker = [m_element startOrEndTextMarkerForTextMarkers:textMarkers isStart:NO];
1100     return AccessibilityTextMarker::create(textMarker);
1101 }
1102
1103 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarkerForBounds(int x, int y, int width, int height)
1104 {
1105     return nullptr;
1106 }
1107
1108 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarkerForBounds(int x, int y, int width, int height)
1109 {
1110     return nullptr;
1111 }
1112
1113 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForPoint(int x, int y)
1114 {
1115     return nullptr;
1116 }
1117
1118 RefPtr<AccessibilityUIElement> AccessibilityUIElement::accessibilityElementForTextMarker(AccessibilityTextMarker* marker)
1119 {
1120     id obj = [m_element accessibilityObjectForTextMarker:(id)marker->platformTextMarker()];
1121     if (obj)
1122         return AccessibilityUIElement::create(obj);
1123     return nullptr;
1124 }
1125
1126 bool AccessibilityUIElement::attributedStringForTextMarkerRangeContainsAttribute(JSStringRef attribute, AccessibilityTextMarkerRange* range)
1127 {
1128     return false;
1129 }
1130
1131 int AccessibilityUIElement::indexForTextMarker(AccessibilityTextMarker* marker)
1132 {
1133     return -1;
1134 }
1135
1136 bool AccessibilityUIElement::isTextMarkerValid(AccessibilityTextMarker* textMarker)
1137 {
1138     return false;
1139 }
1140
1141 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForIndex(int textIndex)
1142 {
1143     return nullptr;
1144 }
1145
1146 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarker()
1147 {
1148     return nullptr;
1149 }
1150
1151 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarker()
1152 {
1153     return nullptr;
1154 }
1155
1156 RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
1157 {
1158     return nullptr;
1159 }
1160
1161 RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
1162 {
1163     return nullptr;
1164 }
1165
1166 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
1167 {
1168     return nullptr;
1169 }
1170
1171 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
1172 {
1173     return nullptr;
1174 }
1175
1176 RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::paragraphTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
1177 {
1178     return nullptr;
1179 }
1180
1181 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextParagraphEndTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
1182 {
1183     return nullptr;
1184 }
1185
1186 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousParagraphStartTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
1187 {
1188     return nullptr;
1189 }
1190
1191 RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::sentenceTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
1192 {
1193     return nullptr;
1194 }
1195
1196 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextSentenceEndTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
1197 {
1198     return nullptr;
1199 }
1200
1201 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousSentenceStartTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
1202 {
1203     return nullptr;
1204 }
1205     
1206 RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeMatchesTextNearMarkers(JSStringRef text, AccessibilityTextMarker* startMarker, AccessibilityTextMarker* endMarker)
1207 {
1208     NSArray *textMarkers = nil;
1209     if (startMarker->platformTextMarker() && endMarker->platformTextMarker())
1210         textMarkers = [NSArray arrayWithObjects:(id)startMarker->platformTextMarker(), (id)endMarker->platformTextMarker(), nil];
1211     id textMarkerRange = [m_element textMarkerRangeFromMarkers:textMarkers withText:[NSString stringWithJSStringRef:text]];
1212     return AccessibilityTextMarkerRange::create(textMarkerRange);
1213 }
1214
1215 JSRetainPtr<JSStringRef> AccessibilityUIElement::mathPostscriptsDescription() const
1216 {
1217     return nullptr;
1218 }
1219
1220 JSRetainPtr<JSStringRef> AccessibilityUIElement::mathPrescriptsDescription() const
1221 {
1222     return nullptr;
1223 }
1224
1225 static void _CGPathEnumerationIteration(void *info, const CGPathElement *element)
1226 {
1227     NSMutableString *result = (NSMutableString *)info;
1228     switch (element->type) {
1229     case kCGPathElementMoveToPoint:
1230         [result appendString:@"\tMove to point\n"];
1231         break;
1232     case kCGPathElementAddLineToPoint:
1233         [result appendString:@"\tLine to\n"];
1234         break;
1235     case kCGPathElementAddQuadCurveToPoint:
1236         [result appendString:@"\tQuad curve to\n"];
1237         break;
1238     case kCGPathElementAddCurveToPoint:
1239         [result appendString:@"\tCurve to\n"];
1240         break;
1241     case kCGPathElementCloseSubpath:
1242         [result appendString:@"\tClose\n"];
1243         break;
1244     }
1245 }
1246
1247 JSRetainPtr<JSStringRef> AccessibilityUIElement::pathDescription() const
1248 {
1249     NSMutableString *result = [NSMutableString stringWithString:@"\nStart Path\n"];
1250     CGPathRef pathRef = [m_element _accessibilityPath];
1251     
1252     CGPathApply(pathRef, result, _CGPathEnumerationIteration);
1253     
1254     return [result createJSStringRef];
1255 }
1256
1257 JSRetainPtr<JSStringRef> AccessibilityUIElement::supportedActions() const
1258 {
1259     return nullptr;
1260 }
1261
1262 } // namespace WTR
1263