AX: Upstream iOS Accessibility DumpRenderTree changes
[WebKit-https.git] / Tools / DumpRenderTree / ios / AccessibilityUIElementIOS.mm
1 /*
2  * Copyright (C) 2009 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. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #import "config.h"
27 #import "DumpRenderTree.h"
28 #import "AccessibilityUIElement.h"
29
30 #import "AccessibilityCommonMac.h"
31 #import <Foundation/Foundation.h>
32 #import <JavaScriptCore/JSRetainPtr.h>
33 #import <JavaScriptCore/JSStringRef.h>
34 #import <JavaScriptCore/JSStringRefCF.h>
35 #import <WebCore/TextGranularity.h>
36 #import <WebKit/WebFrame.h>
37 #import <WebKit/WebHTMLView.h>
38 #import <WebKit/WebTypesInternal.h>
39 #import <wtf/RetainPtr.h>
40 #import <wtf/Vector.h>
41
42 #if PLATFORM(IOS)
43
44 #import <UIKit/UIKit.h>
45
46 typedef void (*AXPostedNotificationCallback)(id element, NSString* notification, void* context);
47
48 AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element)
49     : m_element(element)
50 {
51     [m_element retain];
52 }
53
54 AccessibilityUIElement::AccessibilityUIElement(const AccessibilityUIElement& other)
55     : m_element(other.m_element)
56 {
57     [m_element retain];
58 }
59
60 AccessibilityUIElement::~AccessibilityUIElement()
61 {
62     [m_element release];
63 }
64
65 @interface NSObject (UIAccessibilityHidden)
66 - (id)accessibilityHitTest:(CGPoint)point;
67 - (id)accessibilityLinkedElement;
68 - (NSRange)accessibilityColumnRange;
69 - (NSRange)accessibilityRowRange;
70 - (id)accessibilityElementForRow:(NSInteger)row andColumn:(NSInteger)column;
71 - (NSURL *)accessibilityURL;
72 - (NSArray *)accessibilityHeaderElements;
73 - (NSString *)accessibilityPlaceholderValue;
74 - (NSString *)stringForRange:(NSRange)range;
75 - (NSArray *)elementsForRange:(NSRange)range;
76 - (NSString *)selectionRangeString;
77 - (void)accessibilityModifySelection:(WebCore::TextGranularity)granularity increase:(BOOL)increase;
78 - (void)accessibilitySetPostedNotificationCallback:(AXPostedNotificationCallback)function withContext:(void*)context;
79 @end
80
81 static JSStringRef concatenateAttributeAndValue(NSString* attribute, NSString* value)
82 {
83     Vector<UniChar> buffer([attribute length]);
84     [attribute getCharacters:buffer.data()];
85     buffer.append(':');
86     buffer.append(' ');
87     
88     Vector<UniChar> valueBuffer([value length]);
89     [value getCharacters:valueBuffer.data()];
90     buffer.append(valueBuffer);
91     
92     return JSStringCreateWithCharacters(buffer.data(), buffer.size());
93 }
94
95 #pragma mark iPhone Attributes
96
97 JSStringRef AccessibilityUIElement::iphoneLabel()
98 {
99     return concatenateAttributeAndValue(@"AXLabel", [m_element accessibilityLabel]);
100 }
101
102 JSStringRef AccessibilityUIElement::iphoneHint()
103 {
104     return concatenateAttributeAndValue(@"AXHint", [m_element accessibilityHint]);
105 }
106
107 JSStringRef AccessibilityUIElement::iphoneValue()
108 {
109     return concatenateAttributeAndValue(@"AXValue", [m_element accessibilityValue]);
110 }
111
112 JSStringRef AccessibilityUIElement::iphoneIdentifier()
113 {
114     return concatenateAttributeAndValue(@"AXIdentifier", [m_element accessibilityIdentifier]);
115 }
116
117 JSStringRef AccessibilityUIElement::iphoneTraits()
118 {
119     return concatenateAttributeAndValue(@"AXTraits", [NSString stringWithFormat:@"%qu", [m_element accessibilityTraits]]);
120 }
121
122 bool AccessibilityUIElement::iphoneIsElement()
123 {
124     return [m_element isAccessibilityElement];
125 }
126
127 int AccessibilityUIElement::iphoneElementTextPosition()
128 {
129     NSRange range = [[m_element valueForKey:@"elementTextRange"] rangeValue];
130     return range.location;
131 }
132
133 int AccessibilityUIElement::iphoneElementTextLength()
134 {
135     NSRange range = [[m_element valueForKey:@"elementTextRange"] rangeValue];
136     return range.length;    
137 }
138
139 JSStringRef AccessibilityUIElement::url()
140 {
141     NSURL *url = [m_element accessibilityURL];
142     return [[url absoluteString] createJSStringRef];    
143 }
144
145 double AccessibilityUIElement::x()
146 {
147     CGRect frame = [m_element accessibilityFrame];
148     return frame.origin.x;
149 }
150
151 double AccessibilityUIElement::y()
152 {
153     CGRect frame = [m_element accessibilityFrame];
154     return frame.origin.y;
155 }
156
157 double AccessibilityUIElement::width()
158 {
159     CGRect frame = [m_element accessibilityFrame];
160     return frame.size.width;
161 }
162
163 double AccessibilityUIElement::height()
164 {
165     CGRect frame = [m_element accessibilityFrame];
166     return frame.size.height;
167 }
168
169 double AccessibilityUIElement::clickPointX()
170 {
171     CGPoint centerPoint = [m_element accessibilityActivationPoint];
172     return centerPoint.x;
173 }
174
175 double AccessibilityUIElement::clickPointY()
176 {
177     CGPoint centerPoint = [m_element accessibilityActivationPoint];
178     return centerPoint.y;
179 }
180
181 void AccessibilityUIElement::getChildren(Vector<AccessibilityUIElement>& elementVector)
182 {
183     NSInteger childCount = [m_element accessibilityElementCount];
184     for (NSInteger k = 0; k < childCount; ++k)
185         elementVector.append(AccessibilityUIElement([m_element accessibilityElementAtIndex:k]));
186 }
187
188 void AccessibilityUIElement::getChildrenWithRange(Vector<AccessibilityUIElement>& elementVector, unsigned location, unsigned length)
189 {
190     NSUInteger childCount = [m_element accessibilityElementCount];
191     for (NSUInteger k = location; k < childCount && k < (location+length); ++k)
192         elementVector.append(AccessibilityUIElement([m_element accessibilityElementAtIndex:k]));    
193 }
194
195 int AccessibilityUIElement::childrenCount()
196 {
197     Vector<AccessibilityUIElement> children;
198     getChildren(children);
199     
200     return children.size();
201 }
202
203 AccessibilityUIElement AccessibilityUIElement::elementAtPoint(int x, int y)
204 {
205     id element = [m_element accessibilityHitTest:NSMakePoint(x, y)];
206     if (!element)
207         return nil;
208     
209     return AccessibilityUIElement(element); 
210 }
211
212 unsigned AccessibilityUIElement::indexOfChild(AccessibilityUIElement* element)
213 {
214     return 0;
215 }
216
217 AccessibilityUIElement AccessibilityUIElement::getChildAtIndex(unsigned index)
218 {
219     Vector<AccessibilityUIElement> children;
220     getChildrenWithRange(children, index, 1);
221     
222     if (children.size() == 1)
223         return children[0];
224     return nil;
225 }
226
227 AccessibilityUIElement AccessibilityUIElement::headerElementAtIndex(unsigned index)
228 {
229     NSArray *headers = [m_element accessibilityHeaderElements];
230     if (index < [headers count])
231         return [headers objectAtIndex:index];
232     
233     return 0;
234 }
235
236 AccessibilityUIElement AccessibilityUIElement::linkedElement()
237 {
238     id linkedElement = [m_element accessibilityLinkedElement];
239     if (linkedElement)
240         return AccessibilityUIElement(linkedElement);
241     
242     return 0;
243 }
244
245 AccessibilityUIElement AccessibilityUIElement::linkedUIElementAtIndex(unsigned index)
246 {
247     // FIXME: implement
248     return 0;
249 }
250
251 AccessibilityUIElement AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index)
252 {
253     return 0;
254 }
255
256 AccessibilityUIElement AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index)
257 {
258     return 0;
259 }
260
261 AccessibilityUIElement AccessibilityUIElement::disclosedRowAtIndex(unsigned index)
262 {
263     return 0;
264 }
265
266 AccessibilityUIElement AccessibilityUIElement::selectedRowAtIndex(unsigned index)
267 {
268     return 0;
269 }
270
271 AccessibilityUIElement AccessibilityUIElement::rowAtIndex(unsigned index)
272 {
273     return 0;
274 }
275
276 AccessibilityUIElement AccessibilityUIElement::titleUIElement()
277 {
278     return 0;
279 }
280
281 AccessibilityUIElement AccessibilityUIElement::parentElement()
282 {
283     id accessibilityObject = [m_element accessibilityContainer];
284     if (accessibilityObject)
285         return AccessibilityUIElement(accessibilityObject);
286     
287     return nil;
288 }
289
290 AccessibilityUIElement AccessibilityUIElement::disclosedByRow()
291 {
292     return 0;
293 }
294
295 void AccessibilityUIElement::increaseTextSelection()
296 {
297     [m_element accessibilityModifySelection:WebCore::CharacterGranularity increase:YES];
298 }
299
300 void AccessibilityUIElement::decreaseTextSelection()
301 {
302     [m_element accessibilityModifySelection:WebCore::CharacterGranularity increase:NO];    
303 }
304
305 JSStringRef AccessibilityUIElement::stringForSelection() 
306
307     NSString *stringForRange = [m_element selectionRangeString];
308     if (!stringForRange)
309         return 0;
310     
311     return [stringForRange createJSStringRef];
312 }
313
314 JSStringRef AccessibilityUIElement::stringForRange(unsigned location, unsigned length) 
315
316     NSString *stringForRange = [m_element stringForRange:NSMakeRange(location, length)];
317     if (!stringForRange)
318         return 0;
319     
320     return [stringForRange createJSStringRef];
321 }
322
323 JSStringRef AccessibilityUIElement::attributedStringForRange(unsigned, unsigned)
324 {
325     return JSStringCreateWithCharacters(0, 0);
326 }
327
328 bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned, unsigned)
329 {
330     return false;
331 }
332
333
334 void AccessibilityUIElement::elementsForRange(unsigned location, unsigned length, Vector<AccessibilityUIElement>& elements)
335
336     NSArray *elementsForRange = [m_element elementsForRange:NSMakeRange(location, length)];
337     for (id object in elementsForRange) {
338         AccessibilityUIElement element = AccessibilityUIElement(object);
339         elements.append(element);
340     }
341 }
342
343 #pragma mark Unused
344
345 void AccessibilityUIElement::getLinkedUIElements(Vector<AccessibilityUIElement>& elementVector)
346 {
347 }
348
349 void AccessibilityUIElement::getDocumentLinks(Vector<AccessibilityUIElement>& elementVector)
350 {
351 }
352
353 JSStringRef AccessibilityUIElement::attributesOfLinkedUIElements()
354 {
355     return JSStringCreateWithCharacters(0, 0);
356 }
357
358 JSStringRef AccessibilityUIElement::attributesOfDocumentLinks()
359 {
360     return JSStringCreateWithCharacters(0, 0);
361 }
362
363 JSStringRef AccessibilityUIElement::attributesOfChildren()
364 {
365     return JSStringCreateWithCharacters(0, 0);
366 }
367
368 JSStringRef AccessibilityUIElement::allAttributes()
369 {
370     return JSStringCreateWithCharacters(0, 0);
371 }
372
373 JSStringRef AccessibilityUIElement::stringAttributeValue(JSStringRef attribute)
374 {
375     if (JSStringIsEqualToUTF8CString(attribute, "AXPlaceholderValue"))
376         return [[m_element accessibilityPlaceholderValue] createJSStringRef];
377     
378     return JSStringCreateWithCharacters(0, 0);
379 }
380
381 bool AccessibilityUIElement::isPressActionSupported()
382 {
383     return false;
384 }
385
386 bool AccessibilityUIElement::isIncrementActionSupported()
387 {
388     return false;
389 }
390
391 bool AccessibilityUIElement::isDecrementActionSupported()
392 {
393     return false;
394 }
395
396 bool AccessibilityUIElement::boolAttributeValue(JSStringRef attribute)
397 {
398     return false;
399 }
400
401 bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute)
402 {
403     return false;
404 }
405
406 bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute)
407 {
408     return false;
409 }
410
411 JSStringRef AccessibilityUIElement::parameterizedAttributeNames()
412 {
413     return JSStringCreateWithCharacters(0, 0);
414 }
415
416 JSStringRef AccessibilityUIElement::role()
417 {
418     return JSStringCreateWithCharacters(0, 0);
419 }
420
421 JSStringRef AccessibilityUIElement::subrole()
422 {
423     return JSStringCreateWithCharacters(0, 0);
424 }
425
426 JSStringRef AccessibilityUIElement::roleDescription()
427 {
428     return JSStringCreateWithCharacters(0, 0);
429 }
430
431 JSStringRef AccessibilityUIElement::title()
432 {
433     return JSStringCreateWithCharacters(0, 0);
434 }
435
436 JSStringRef AccessibilityUIElement::description()
437 {
438     return JSStringCreateWithCharacters(0, 0);
439 }    
440
441 JSStringRef AccessibilityUIElement::orientation() const
442 {
443     return JSStringCreateWithCharacters(0, 0);
444 }
445
446 JSStringRef AccessibilityUIElement::stringValue()
447 {
448     return JSStringCreateWithCharacters(0, 0);
449 }
450
451 JSStringRef AccessibilityUIElement::language()
452 {
453     return JSStringCreateWithCharacters(0, 0);
454 }
455
456 JSStringRef AccessibilityUIElement::helpText() const
457 {
458     return JSStringCreateWithCharacters(0, 0);
459 }
460
461 double AccessibilityUIElement::intValue() const
462 {
463     return 0.0f;
464 }
465
466 double AccessibilityUIElement::minValue()
467 {
468     return 0.0f;
469 }
470
471 double AccessibilityUIElement::maxValue()
472 {
473     return 0.0;
474 }
475
476 JSStringRef AccessibilityUIElement::valueDescription()
477 {
478     return JSStringCreateWithCharacters(0, 0);
479 }
480
481 int AccessibilityUIElement::insertionPointLineNumber()
482 {
483     return -1;
484 }
485
486 bool AccessibilityUIElement::isEnabled()
487 {
488     return false;
489 }
490
491 bool AccessibilityUIElement::isRequired() const
492 {
493     return false;
494 }
495
496 bool AccessibilityUIElement::isFocused() const
497 {
498     // FIXME: implement
499     return false;
500 }
501
502 bool AccessibilityUIElement::isSelected() const
503 {
504     UIAccessibilityTraits traits = [m_element accessibilityTraits];
505     return (traits & UIAccessibilityTraitSelected);
506 }
507
508 bool AccessibilityUIElement::isExpanded() const
509 {
510     return false;
511 }
512
513 bool AccessibilityUIElement::isChecked() const
514 {
515     return false;
516 }
517
518 int AccessibilityUIElement::hierarchicalLevel() const
519 {
520     return 0;
521 }
522
523 bool AccessibilityUIElement::ariaIsGrabbed() const
524 {
525     return false;
526 }
527
528 JSStringRef AccessibilityUIElement::ariaDropEffects() const
529 {
530     return JSStringCreateWithCharacters(0, 0);
531 }
532
533 int AccessibilityUIElement::lineForIndex(int index)
534 {
535     return -1;
536 }
537
538 JSStringRef AccessibilityUIElement::boundsForRange(unsigned location, unsigned length)
539 {
540     return JSStringCreateWithCharacters(0, 0);
541 }
542
543 JSStringRef AccessibilityUIElement::attributesOfColumnHeaders()
544 {
545     return JSStringCreateWithCharacters(0, 0);
546 }
547
548 JSStringRef AccessibilityUIElement::attributesOfRowHeaders()
549 {
550     return JSStringCreateWithCharacters(0, 0);
551 }
552
553 JSStringRef AccessibilityUIElement::attributesOfColumns()
554 {
555     return JSStringCreateWithCharacters(0, 0);
556 }
557
558 JSStringRef AccessibilityUIElement::attributesOfRows()
559 {
560     return JSStringCreateWithCharacters(0, 0);
561 }
562
563 JSStringRef AccessibilityUIElement::attributesOfVisibleCells()
564 {
565     return JSStringCreateWithCharacters(0, 0);
566 }
567
568 JSStringRef AccessibilityUIElement::attributesOfHeader()
569 {
570     return JSStringCreateWithCharacters(0, 0);
571 }
572
573 int AccessibilityUIElement::rowCount()
574 {
575     return -1;
576 }
577
578 int AccessibilityUIElement::columnCount()
579 {
580     return -1;
581 }
582
583 int AccessibilityUIElement::indexInTable()
584 {
585     return -1;
586 }
587
588 JSStringRef AccessibilityUIElement::rowIndexRange()
589 {
590     NSRange range = [m_element accessibilityRowRange];
591     NSMutableString* rangeDescription = [NSMutableString stringWithFormat:@"{%lu, %lu}", (unsigned long)range.location, (unsigned long)range.length];
592     return [rangeDescription createJSStringRef];
593 }
594
595 JSStringRef AccessibilityUIElement::columnIndexRange()
596 {
597     NSRange range = [m_element accessibilityColumnRange];
598     NSMutableString* rangeDescription = [NSMutableString stringWithFormat:@"{%lu, %lu}", (unsigned long)range.location, (unsigned long)range.length];
599     return [rangeDescription createJSStringRef];    
600 }
601
602 AccessibilityUIElement AccessibilityUIElement::cellForColumnAndRow(unsigned col, unsigned row)
603 {
604     return AccessibilityUIElement([m_element accessibilityElementForRow:row andColumn:col]);
605 }
606
607 JSStringRef AccessibilityUIElement::selectedTextRange()
608 {
609     return JSStringCreateWithCharacters(0, 0);
610 }
611
612 void AccessibilityUIElement::assistiveTechnologySimulatedFocus()
613 {
614     [m_element accessibilityElementDidBecomeFocused];
615 }
616
617 void AccessibilityUIElement::setSelectedTextRange(unsigned location, unsigned length)
618 {
619 }
620
621 void AccessibilityUIElement::increment()
622 {
623     [m_element accessibilityIncrement];
624 }
625
626 void AccessibilityUIElement::decrement()
627 {
628     [m_element accessibilityDecrement];
629 }
630
631 void AccessibilityUIElement::showMenu()
632 {
633 }
634
635 void AccessibilityUIElement::press()
636 {
637 }
638
639 JSStringRef AccessibilityUIElement::accessibilityValue() const
640 {
641     // FIXME: implement
642     return JSStringCreateWithCharacters(0, 0);
643 }
644
645 JSStringRef AccessibilityUIElement::documentEncoding()
646 {
647     return JSStringCreateWithCharacters(0, 0);
648 }
649
650 JSStringRef AccessibilityUIElement::documentURI()
651 {
652     return JSStringCreateWithCharacters(0, 0);
653 }
654
655 static void _accessibilityNotificationCallback(id element, NSString* notification, void* context)
656 {
657     if (!context)
658         return;
659     
660     JSObjectRef functionCallback = static_cast<JSObjectRef>(context);
661     
662     JSRetainPtr<JSStringRef> jsNotification(Adopt, [notification createJSStringRef]);
663     JSValueRef argument = JSValueMakeString([mainFrame globalContext], jsNotification.get());
664     JSObjectCallAsFunction([mainFrame globalContext], functionCallback, NULL, 1, &argument, NULL);
665 }
666
667 bool AccessibilityUIElement::addNotificationListener(JSObjectRef functionCallback)
668 {
669     if (!functionCallback)
670         return false;
671     
672     m_notificationFunctionCallback = functionCallback;
673     [platformUIElement() accessibilitySetPostedNotificationCallback:_accessibilityNotificationCallback withContext:reinterpret_cast<void*>(m_notificationFunctionCallback)];
674     return true;    
675 }
676
677 void AccessibilityUIElement::removeNotificationListener()
678 {
679     m_notificationFunctionCallback = 0;
680     [platformUIElement() accessibilitySetPostedNotificationCallback:nil withContext:nil];
681 }
682
683 bool AccessibilityUIElement::isFocusable() const
684 {
685     // FIXME: implement
686     return false;
687 }
688
689 bool AccessibilityUIElement::isSelectable() const
690 {
691     // FIXME: implement
692     return false;
693 }
694
695 bool AccessibilityUIElement::isMultiSelectable() const
696 {
697     // FIXME: implement
698     return false;
699 }
700
701 bool AccessibilityUIElement::isSelectedOptionActive() const
702 {
703     // FIXME: implement
704     return false;
705 }
706
707 bool AccessibilityUIElement::isVisible() const
708 {
709     // FIXME: implement
710     return false;
711 }
712
713 bool AccessibilityUIElement::isOffScreen() const
714 {
715     // FIXME: implement
716     return false;
717 }
718
719 bool AccessibilityUIElement::isCollapsed() const
720 {
721     // FIXME: implement
722     return false;
723 }
724
725 bool AccessibilityUIElement::isIgnored() const
726 {
727     // FIXME: implement
728     return false;
729 }
730
731 bool AccessibilityUIElement::hasPopup() const
732 {
733     // FIXME: implement
734     return false;
735 }
736
737 void AccessibilityUIElement::takeFocus()
738 {
739     // FIXME: implement
740 }
741
742 void AccessibilityUIElement::takeSelection()
743 {
744     // FIXME: implement
745 }
746
747 void AccessibilityUIElement::addSelection()
748 {
749     // FIXME: implement
750 }
751
752 void AccessibilityUIElement::removeSelection()
753 {
754     // FIXME: implement
755 }
756
757 AccessibilityUIElement AccessibilityUIElement::uiElementForSearchPredicate(AccessibilityUIElement* startElement, bool isDirectionNext, JSStringRef searchKey, JSStringRef searchText)
758 {
759     // FIXME: implement
760     return 0;
761 }
762
763 double AccessibilityUIElement::numberAttributeValue(JSStringRef attribute)
764 {
765     // FIXME: implement
766     return 0;
767 }
768 #endif // PLATFORM(IOS)