Add "VisibleOnly" key to search predicate
[WebKit-https.git] / Tools / WebKitTestRunner / InjectedBundle / mac / AccessibilityUIElementMac.mm
1 /*
2  * Copyright (C) 2011 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 "AccessibilityCommonMac.h"
28 #import "AccessibilityNotificationHandler.h"
29 #import "AccessibilityUIElement.h"
30 #import "InjectedBundle.h"
31 #import "InjectedBundlePage.h"
32
33 #import <AppKit/NSAccessibility.h>
34 #import <Foundation/Foundation.h>
35 #import <JavaScriptCore/JSRetainPtr.h>
36 #import <JavaScriptCore/JSStringRef.h>
37 #import <JavaScriptCore/JSStringRefCF.h>
38 #import <JavaScriptCore/JSObjectRef.h>
39 #import <WebKit2/WKBundleFrame.h>
40 #import <wtf/RetainPtr.h>
41 #import <wtf/Vector.h>
42
43
44 #ifndef NSAccessibilityOwnsAttribute
45 #define NSAccessibilityOwnsAttribute @"AXOwns"
46 #endif
47
48 #ifndef NSAccessibilityGrabbedAttribute
49 #define NSAccessibilityGrabbedAttribute @"AXGrabbed"
50 #endif
51
52 #ifndef NSAccessibilityDropEffectsAttribute
53 #define NSAccessibilityDropEffectsAttribute @"AXDropEffects"
54 #endif
55
56 #ifndef NSAccessibilityPathAttribute
57 #define NSAccessibilityPathAttribute @"AXPath"
58 #endif
59
60 typedef void (*AXPostedNotificationCallback)(id element, NSString* notification, void* context);
61
62 @interface NSObject (WebKitAccessibilityAdditions)
63 - (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount;
64 - (NSUInteger)accessibilityIndexOfChild:(id)child;
65 - (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute;
66 @end
67
68 namespace WTR {
69
70 AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element)
71     : m_element(element)
72     , m_notificationHandler(0)
73 {
74     // FIXME: ap@webkit.org says ObjC objects need to be CFRetained/CFRelease to be GC-compliant on the mac.
75     [m_element retain];
76 }
77
78 AccessibilityUIElement::AccessibilityUIElement(const AccessibilityUIElement& other)
79     : JSWrappable()
80     , m_element(other.m_element)
81     , m_notificationHandler(0)
82 {
83     [m_element retain];
84 }
85
86 AccessibilityUIElement::~AccessibilityUIElement()
87 {
88     // The notification handler should be nil because removeNotificationListener() should have been called in the test.
89     ASSERT(!m_notificationHandler);
90     [m_element release];
91 }
92
93 bool AccessibilityUIElement::isEqual(AccessibilityUIElement* otherElement)
94 {
95     if (!otherElement)
96         return false;
97     return platformUIElement() == otherElement->platformUIElement();
98 }
99     
100 static NSString* descriptionOfValue(id valueObject, id focusedAccessibilityObject)
101 {
102     if (!valueObject)
103         return NULL;
104
105     if ([valueObject isKindOfClass:[NSArray class]])
106         return [NSString stringWithFormat:@"<array of size %lu>", static_cast<unsigned long>([(NSArray*)valueObject count])];
107
108     if ([valueObject isKindOfClass:[NSNumber class]])
109         return [(NSNumber*)valueObject stringValue];
110
111     if ([valueObject isKindOfClass:[NSValue class]]) {
112         NSString* type = [NSString stringWithCString:[valueObject objCType] encoding:NSASCIIStringEncoding];
113         NSValue* value = (NSValue*)valueObject;
114         if ([type rangeOfString:@"NSRect"].length > 0)
115             return [NSString stringWithFormat:@"NSRect: %@", NSStringFromRect([value rectValue])];
116         if ([type rangeOfString:@"NSPoint"].length > 0)
117             return [NSString stringWithFormat:@"NSPoint: %@", NSStringFromPoint([value pointValue])];
118         if ([type rangeOfString:@"NSSize"].length > 0)
119             return [NSString stringWithFormat:@"NSSize: %@", NSStringFromSize([value sizeValue])];
120         if ([type rangeOfString:@"NSRange"].length > 0)
121             return [NSString stringWithFormat:@"NSRange: %@", NSStringFromRange([value rangeValue])];
122     }
123
124     // Strip absolute URL paths
125     NSString* description = [valueObject description];
126     NSRange range = [description rangeOfString:@"LayoutTests"];
127     if (range.length)
128         return [description substringFromIndex:range.location];
129
130     // Strip pointer locations
131     if ([description rangeOfString:@"0x"].length) {
132         NSString* role = [focusedAccessibilityObject accessibilityAttributeValue:NSAccessibilityRoleAttribute];
133         NSString* title = [focusedAccessibilityObject accessibilityAttributeValue:NSAccessibilityTitleAttribute];
134         if ([title length])
135             return [NSString stringWithFormat:@"<%@: '%@'>", role, title];
136         return [NSString stringWithFormat:@"<%@>", role];
137     }
138     
139     return [valueObject description];
140 }
141
142 static NSString* attributesOfElement(id accessibilityObject)
143 {
144     NSArray* supportedAttributes = [accessibilityObject accessibilityAttributeNames];
145
146     NSMutableString* attributesString = [NSMutableString string];
147     for (NSUInteger i = 0; i < [supportedAttributes count]; ++i) {
148         NSString* attribute = [supportedAttributes objectAtIndex:i];
149         
150         // Right now, position provides useless and screen-specific information, so we do not
151         // want to include it for the sake of universally passing tests.
152         if ([attribute isEqualToString:@"AXPosition"])
153             continue;
154         
155         // accessibilityAttributeValue: can throw an if an attribute is not returned.
156         // For DumpRenderTree's purpose, we should ignore those exceptions
157         BEGIN_AX_OBJC_EXCEPTIONS
158         id valueObject = [accessibilityObject accessibilityAttributeValue:attribute];
159         NSString* value = descriptionOfValue(valueObject, accessibilityObject);
160         [attributesString appendFormat:@"%@: %@\n", attribute, value];
161         END_AX_OBJC_EXCEPTIONS
162     }
163     
164     return attributesString;
165 }
166
167 static JSStringRef concatenateAttributeAndValue(NSString* attribute, NSString* value)
168 {
169     Vector<UniChar> buffer([attribute length]);
170     [attribute getCharacters:buffer.data()];
171     buffer.append(':');
172     buffer.append(' ');
173
174     Vector<UniChar> valueBuffer([value length]);
175     [value getCharacters:valueBuffer.data()];
176     buffer.appendVector(valueBuffer);
177
178     return JSStringCreateWithCharacters(buffer.data(), buffer.size());
179 }
180
181 static void convertNSArrayToVector(NSArray* array, Vector<RefPtr<AccessibilityUIElement> >& elementVector)
182 {
183     NSUInteger count = [array count];
184     for (NSUInteger i = 0; i < count; ++i)
185         elementVector.append(AccessibilityUIElement::create([array objectAtIndex:i]));
186 }
187
188 static JSStringRef descriptionOfElements(Vector<RefPtr<AccessibilityUIElement> >& elementVector)
189 {
190     NSMutableString* allElementString = [NSMutableString string];
191     size_t size = elementVector.size();
192     for (size_t i = 0; i < size; ++i) {
193         RefPtr<AccessibilityUIElement> uiElement = elementVector[i];
194         NSString* attributes = attributesOfElement(uiElement->platformUIElement());
195         [allElementString appendFormat:@"%@\n------------\n", attributes];
196     }
197     
198     return [allElementString createJSStringRef];
199 }
200
201 void AccessibilityUIElement::getLinkedUIElements(Vector<RefPtr<AccessibilityUIElement> >& elementVector)
202 {
203     BEGIN_AX_OBJC_EXCEPTIONS
204     NSArray* linkedElements = [m_element accessibilityAttributeValue:NSAccessibilityLinkedUIElementsAttribute];
205     convertNSArrayToVector(linkedElements, elementVector);
206     END_AX_OBJC_EXCEPTIONS
207 }
208
209 void AccessibilityUIElement::getDocumentLinks(Vector<RefPtr<AccessibilityUIElement> >& elementVector)
210 {
211     BEGIN_AX_OBJC_EXCEPTIONS
212     NSArray* linkElements = [m_element accessibilityAttributeValue:@"AXLinkUIElements"];
213     convertNSArrayToVector(linkElements, elementVector);
214     END_AX_OBJC_EXCEPTIONS
215 }
216
217 void AccessibilityUIElement::getChildren(Vector<RefPtr<AccessibilityUIElement> >& elementVector)
218 {
219     BEGIN_AX_OBJC_EXCEPTIONS
220     NSArray* children = [m_element accessibilityAttributeValue:NSAccessibilityChildrenAttribute];
221     convertNSArrayToVector(children, elementVector);
222     END_AX_OBJC_EXCEPTIONS
223 }
224
225 void AccessibilityUIElement::getChildrenWithRange(Vector<RefPtr<AccessibilityUIElement> >& elementVector, unsigned location, unsigned length)
226 {
227     BEGIN_AX_OBJC_EXCEPTIONS
228     NSArray* children = [m_element accessibilityArrayAttributeValues:NSAccessibilityChildrenAttribute index:location maxCount:length];
229     convertNSArrayToVector(children, elementVector);
230     END_AX_OBJC_EXCEPTIONS
231 }
232
233 int AccessibilityUIElement::childrenCount()
234 {
235     Vector<RefPtr<AccessibilityUIElement> > children;
236     getChildren(children);
237     
238     return children.size();
239 }
240
241 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::elementAtPoint(int x, int y)
242 {
243     id element = [m_element accessibilityHitTest:NSMakePoint(x, y)];
244     if (!element)
245         return nil;
246     
247     return AccessibilityUIElement::create(element);
248 }
249
250 unsigned AccessibilityUIElement::indexOfChild(AccessibilityUIElement* element)
251 {
252     return [m_element accessibilityIndexOfChild:element->platformUIElement()];
253 }
254
255 PassRefPtr<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 0;
263 }
264
265 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::linkedUIElementAtIndex(unsigned index)
266 {
267     BEGIN_AX_OBJC_EXCEPTIONS
268     NSArray* objects = [m_element accessibilityAttributeValue:NSAccessibilityLinkedUIElementsAttribute];
269     if (index < [objects count])
270         return AccessibilityUIElement::create([objects objectAtIndex:index]);
271     END_AX_OBJC_EXCEPTIONS
272     
273     return 0;
274 }
275
276 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index)
277 {
278     BEGIN_AX_OBJC_EXCEPTIONS
279     NSArray* objects = [m_element accessibilityAttributeValue:NSAccessibilityOwnsAttribute];
280     if (index < [objects count])
281         return AccessibilityUIElement::create([objects objectAtIndex:index]);
282     END_AX_OBJC_EXCEPTIONS
283     
284     return 0;
285 }
286
287 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index)
288 {
289     BEGIN_AX_OBJC_EXCEPTIONS
290     NSArray* objects = [m_element accessibilityAttributeValue:NSAccessibilityLinkedUIElementsAttribute];
291     if (index < [objects count])
292         return AccessibilityUIElement::create([objects objectAtIndex:index]);
293     END_AX_OBJC_EXCEPTIONS
294     
295     return 0;
296 }
297
298 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::disclosedRowAtIndex(unsigned index)
299 {
300     BEGIN_AX_OBJC_EXCEPTIONS
301     NSArray* rows = [m_element accessibilityAttributeValue:NSAccessibilityDisclosedRowsAttribute];
302     if (index < [rows count])
303         return AccessibilityUIElement::create([rows objectAtIndex:index]);
304     END_AX_OBJC_EXCEPTIONS
305
306     return 0;
307 }
308     
309 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::rowAtIndex(unsigned index)
310 {
311     BEGIN_AX_OBJC_EXCEPTIONS
312     NSArray* rows = [m_element accessibilityAttributeValue:NSAccessibilityRowsAttribute];
313     if (index < [rows count])
314         return AccessibilityUIElement::create([rows objectAtIndex:index]);
315     END_AX_OBJC_EXCEPTIONS
316     
317     return 0;
318 }
319
320 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::selectedChildAtIndex(unsigned index) const
321 {
322     BEGIN_AX_OBJC_EXCEPTIONS
323     NSArray* array = [m_element accessibilityAttributeValue:NSAccessibilitySelectedChildrenAttribute];
324     if (index < [array count])
325         return AccessibilityUIElement::create([array objectAtIndex:index]);
326     END_AX_OBJC_EXCEPTIONS
327     
328     return 0;
329 }
330
331 unsigned AccessibilityUIElement::selectedChildrenCount() const
332 {
333     BEGIN_AX_OBJC_EXCEPTIONS
334     return [m_element accessibilityArrayAttributeCount:NSAccessibilitySelectedChildrenAttribute];
335     END_AX_OBJC_EXCEPTIONS
336
337     return 0;
338 }
339
340 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::selectedRowAtIndex(unsigned index)
341 {
342     BEGIN_AX_OBJC_EXCEPTIONS
343     NSArray* rows = [m_element accessibilityAttributeValue:NSAccessibilitySelectedRowsAttribute];
344     if (index < [rows count])
345         return AccessibilityUIElement::create([rows objectAtIndex:index]);
346     END_AX_OBJC_EXCEPTIONS
347     
348     return 0;
349 }
350
351 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::titleUIElement()
352 {
353     BEGIN_AX_OBJC_EXCEPTIONS
354     id accessibilityObject = [m_element accessibilityAttributeValue:NSAccessibilityTitleUIElementAttribute];
355     if (accessibilityObject)
356         return AccessibilityUIElement::create(accessibilityObject);
357     END_AX_OBJC_EXCEPTIONS
358     
359     return 0;
360 }
361
362 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::parentElement()
363 {
364     BEGIN_AX_OBJC_EXCEPTIONS
365     id accessibilityObject = [m_element accessibilityAttributeValue:NSAccessibilityParentAttribute];
366     if (accessibilityObject)
367         return AccessibilityUIElement::create(accessibilityObject);
368     END_AX_OBJC_EXCEPTIONS
369     
370     return 0;
371 }
372
373 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::disclosedByRow()
374 {
375     BEGIN_AX_OBJC_EXCEPTIONS
376     id accessibilityObject = [m_element accessibilityAttributeValue:NSAccessibilityDisclosedByRowAttribute];
377     if (accessibilityObject)
378         return AccessibilityUIElement::create(accessibilityObject);
379     END_AX_OBJC_EXCEPTIONS
380     
381     return 0;
382 }
383
384 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfLinkedUIElements()
385 {
386     Vector<RefPtr<AccessibilityUIElement> > linkedElements;
387     getLinkedUIElements(linkedElements);
388     return descriptionOfElements(linkedElements);
389 }
390
391 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfDocumentLinks()
392 {
393     Vector<RefPtr<AccessibilityUIElement> > linkElements;
394     getDocumentLinks(linkElements);
395     return descriptionOfElements(linkElements);
396 }
397
398 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfChildren()
399 {
400     Vector<RefPtr<AccessibilityUIElement> > children;
401     getChildren(children);
402     return descriptionOfElements(children);
403 }
404
405 JSRetainPtr<JSStringRef> AccessibilityUIElement::allAttributes()
406 {
407     NSString* attributes = attributesOfElement(m_element);
408     return [attributes createJSStringRef];
409 }
410
411 JSRetainPtr<JSStringRef> AccessibilityUIElement::stringAttributeValue(JSStringRef attribute)
412 {
413     BEGIN_AX_OBJC_EXCEPTIONS
414     id value = [m_element accessibilityAttributeValue:[NSString stringWithJSStringRef:attribute]];
415     if ([value isKindOfClass:[NSString class]])
416         return [value createJSStringRef];
417     END_AX_OBJC_EXCEPTIONS
418
419     return 0;
420 }
421
422 double AccessibilityUIElement::numberAttributeValue(JSStringRef attribute)
423 {
424     BEGIN_AX_OBJC_EXCEPTIONS
425     id value = [m_element accessibilityAttributeValue:[NSString stringWithJSStringRef:attribute]];
426     if ([value isKindOfClass:[NSNumber class]])
427         return [value doubleValue];
428     END_AX_OBJC_EXCEPTIONS
429     
430     return 0;
431 }
432
433 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementAttributeValue(JSStringRef attribute) const
434 {
435     BEGIN_AX_OBJC_EXCEPTIONS
436     id uiElement = [m_element accessibilityAttributeValue:[NSString stringWithJSStringRef:attribute]];
437     return AccessibilityUIElement::create(uiElement);
438     END_AX_OBJC_EXCEPTIONS
439     
440     return 0;
441 }
442     
443 bool AccessibilityUIElement::boolAttributeValue(JSStringRef attribute)
444 {
445     BEGIN_AX_OBJC_EXCEPTIONS
446     id value = [m_element accessibilityAttributeValue:[NSString stringWithJSStringRef:attribute]];
447     if ([value isKindOfClass:[NSNumber class]])
448         return [value boolValue];
449     END_AX_OBJC_EXCEPTIONS
450     
451     return false;
452 }
453
454 bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute)
455 {
456     BEGIN_AX_OBJC_EXCEPTIONS
457     return [m_element accessibilityIsAttributeSettable:[NSString stringWithJSStringRef:attribute]];
458     END_AX_OBJC_EXCEPTIONS
459     
460     return false;
461 }
462
463 bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute)
464 {
465     BEGIN_AX_OBJC_EXCEPTIONS
466     return [[m_element accessibilityAttributeNames] containsObject:[NSString stringWithJSStringRef:attribute]];
467     END_AX_OBJC_EXCEPTIONS
468     
469     return false;
470 }
471
472 JSRetainPtr<JSStringRef> AccessibilityUIElement::parameterizedAttributeNames()
473 {
474     NSArray* supportedParameterizedAttributes = [m_element accessibilityParameterizedAttributeNames];
475     
476     NSMutableString* attributesString = [NSMutableString string];
477     for (NSUInteger i = 0; i < [supportedParameterizedAttributes count]; ++i) {
478         [attributesString appendFormat:@"%@\n", [supportedParameterizedAttributes objectAtIndex:i]];
479     }
480     
481     return [attributesString createJSStringRef];
482 }
483
484 JSRetainPtr<JSStringRef> AccessibilityUIElement::role()
485 {
486     BEGIN_AX_OBJC_EXCEPTIONS
487     NSString *role = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityRoleAttribute], m_element);
488     return concatenateAttributeAndValue(@"AXRole", role);
489     END_AX_OBJC_EXCEPTIONS
490     
491     return 0;
492 }
493
494 JSRetainPtr<JSStringRef> AccessibilityUIElement::subrole()
495 {
496     BEGIN_AX_OBJC_EXCEPTIONS
497     NSString* role = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilitySubroleAttribute], m_element);
498     return concatenateAttributeAndValue(@"AXSubrole", role);
499     END_AX_OBJC_EXCEPTIONS
500
501     return 0;
502 }
503
504 JSRetainPtr<JSStringRef> AccessibilityUIElement::roleDescription()
505 {
506     BEGIN_AX_OBJC_EXCEPTIONS
507     NSString* role = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityRoleDescriptionAttribute], m_element);
508     return concatenateAttributeAndValue(@"AXRoleDescription", role);
509     END_AX_OBJC_EXCEPTIONS
510     
511     return 0;
512 }
513
514 JSRetainPtr<JSStringRef> AccessibilityUIElement::title()
515 {
516     BEGIN_AX_OBJC_EXCEPTIONS
517     NSString* title = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityTitleAttribute], m_element);
518     return concatenateAttributeAndValue(@"AXTitle", title);
519     END_AX_OBJC_EXCEPTIONS
520
521     return 0;
522 }
523
524 JSRetainPtr<JSStringRef> AccessibilityUIElement::description()
525 {
526     BEGIN_AX_OBJC_EXCEPTIONS
527     id description = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityDescriptionAttribute], m_element);
528     return concatenateAttributeAndValue(@"AXDescription", description);
529     END_AX_OBJC_EXCEPTIONS
530
531     return 0;
532 }
533
534 JSRetainPtr<JSStringRef> AccessibilityUIElement::orientation() const
535 {
536     BEGIN_AX_OBJC_EXCEPTIONS
537     id description = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityOrientationAttribute], m_element);
538     return concatenateAttributeAndValue(@"AXOrientation", description);    
539     END_AX_OBJC_EXCEPTIONS
540
541     return 0;
542 }
543
544 JSRetainPtr<JSStringRef> AccessibilityUIElement::stringValue()
545 {
546     BEGIN_AX_OBJC_EXCEPTIONS
547     id description = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityValueAttribute], m_element);
548     return concatenateAttributeAndValue(@"AXValue", description);
549     END_AX_OBJC_EXCEPTIONS
550
551     return 0;
552 }
553
554 JSRetainPtr<JSStringRef> AccessibilityUIElement::language()
555 {
556     BEGIN_AX_OBJC_EXCEPTIONS
557     id description = descriptionOfValue([m_element accessibilityAttributeValue:@"AXLanguage"], m_element);
558     return concatenateAttributeAndValue(@"AXLanguage", description);
559     END_AX_OBJC_EXCEPTIONS
560
561     return 0;
562 }
563
564 JSRetainPtr<JSStringRef> AccessibilityUIElement::helpText() const
565 {
566     BEGIN_AX_OBJC_EXCEPTIONS
567     id description = descriptionOfValue([m_element accessibilityAttributeValue:NSAccessibilityHelpAttribute], m_element);
568     return concatenateAttributeAndValue(@"AXHelp", description);
569     END_AX_OBJC_EXCEPTIONS
570     
571     return 0;
572 }
573
574 double AccessibilityUIElement::x()
575 {
576     BEGIN_AX_OBJC_EXCEPTIONS
577     NSValue* positionValue = [m_element accessibilityAttributeValue:NSAccessibilityPositionAttribute];
578     return static_cast<double>([positionValue pointValue].x);    
579     END_AX_OBJC_EXCEPTIONS
580     
581     return 0.0f;
582 }
583
584 double AccessibilityUIElement::y()
585 {
586     BEGIN_AX_OBJC_EXCEPTIONS
587     NSValue* positionValue = [m_element accessibilityAttributeValue:NSAccessibilityPositionAttribute];
588     return static_cast<double>([positionValue pointValue].y);    
589     END_AX_OBJC_EXCEPTIONS
590     
591     return 0.0f;
592 }
593
594 double AccessibilityUIElement::width()
595 {
596     BEGIN_AX_OBJC_EXCEPTIONS
597     NSValue* sizeValue = [m_element accessibilityAttributeValue:NSAccessibilitySizeAttribute];
598     return static_cast<double>([sizeValue sizeValue].width);
599     END_AX_OBJC_EXCEPTIONS
600     
601     return 0.0f;
602 }
603
604 double AccessibilityUIElement::height()
605 {
606     BEGIN_AX_OBJC_EXCEPTIONS
607     NSValue* sizeValue = [m_element accessibilityAttributeValue:NSAccessibilitySizeAttribute];
608     return static_cast<double>([sizeValue sizeValue].height);
609     END_AX_OBJC_EXCEPTIONS
610     
611     return 0.0f;
612 }
613
614 double AccessibilityUIElement::clickPointX()
615 {
616     BEGIN_AX_OBJC_EXCEPTIONS
617     NSValue* positionValue = [m_element accessibilityAttributeValue:@"AXClickPoint"];
618     return static_cast<double>([positionValue pointValue].x);        
619     END_AX_OBJC_EXCEPTIONS
620     
621     return 0.0f;
622 }
623
624 double AccessibilityUIElement::clickPointY()
625 {
626     BEGIN_AX_OBJC_EXCEPTIONS
627     NSValue* positionValue = [m_element accessibilityAttributeValue:@"AXClickPoint"];
628     return static_cast<double>([positionValue pointValue].y);
629     END_AX_OBJC_EXCEPTIONS
630     
631     return 0.0f;
632 }
633
634 double AccessibilityUIElement::intValue() const
635 {
636     BEGIN_AX_OBJC_EXCEPTIONS
637     id value = [m_element accessibilityAttributeValue:NSAccessibilityValueAttribute];
638     if ([value isKindOfClass:[NSNumber class]])
639         return [(NSNumber*)value doubleValue]; 
640     END_AX_OBJC_EXCEPTIONS
641
642     return 0.0f;
643 }
644
645 double AccessibilityUIElement::minValue()
646 {
647     BEGIN_AX_OBJC_EXCEPTIONS
648     id value = [m_element accessibilityAttributeValue:NSAccessibilityMinValueAttribute];
649     if ([value isKindOfClass:[NSNumber class]])
650         return [(NSNumber*)value doubleValue]; 
651     END_AX_OBJC_EXCEPTIONS
652
653     return 0.0f;
654 }
655
656 double AccessibilityUIElement::maxValue()
657 {
658     BEGIN_AX_OBJC_EXCEPTIONS
659     id value = [m_element accessibilityAttributeValue:NSAccessibilityMaxValueAttribute];
660     if ([value isKindOfClass:[NSNumber class]])
661         return [(NSNumber*)value doubleValue]; 
662     END_AX_OBJC_EXCEPTIONS
663
664     return 0.0;
665 }
666
667 JSRetainPtr<JSStringRef> AccessibilityUIElement::valueDescription()
668 {
669     BEGIN_AX_OBJC_EXCEPTIONS
670     NSString* valueDescription = [m_element accessibilityAttributeValue:NSAccessibilityValueDescriptionAttribute];
671     if ([valueDescription isKindOfClass:[NSString class]])
672          return [valueDescription createJSStringRef];
673
674     END_AX_OBJC_EXCEPTIONS
675     return 0;
676 }
677
678 int AccessibilityUIElement::insertionPointLineNumber()
679 {
680     BEGIN_AX_OBJC_EXCEPTIONS
681     id value = [m_element accessibilityAttributeValue:NSAccessibilityInsertionPointLineNumberAttribute];
682     if ([value isKindOfClass:[NSNumber class]])
683         return [(NSNumber *)value intValue]; 
684     END_AX_OBJC_EXCEPTIONS
685     
686     return -1;
687 }
688
689 bool AccessibilityUIElement::isPressActionSupported()
690 {
691     BEGIN_AX_OBJC_EXCEPTIONS
692     NSArray* actions = [m_element accessibilityActionNames];
693     return [actions containsObject:NSAccessibilityPressAction];
694     END_AX_OBJC_EXCEPTIONS
695     
696     return false;
697 }
698
699 bool AccessibilityUIElement::isIncrementActionSupported()
700 {
701     BEGIN_AX_OBJC_EXCEPTIONS
702     NSArray* actions = [m_element accessibilityActionNames];
703     return [actions containsObject:NSAccessibilityIncrementAction];
704     END_AX_OBJC_EXCEPTIONS
705     
706     return false;
707 }
708
709 bool AccessibilityUIElement::isDecrementActionSupported()
710 {
711     BEGIN_AX_OBJC_EXCEPTIONS
712     NSArray* actions = [m_element accessibilityActionNames];
713     return [actions containsObject:NSAccessibilityDecrementAction];
714     END_AX_OBJC_EXCEPTIONS
715     
716     return false;
717 }
718
719 bool AccessibilityUIElement::isEnabled()
720 {
721     BEGIN_AX_OBJC_EXCEPTIONS
722     id value = [m_element accessibilityAttributeValue:NSAccessibilityEnabledAttribute];
723     if ([value isKindOfClass:[NSNumber class]])
724         return [value boolValue];
725     END_AX_OBJC_EXCEPTIONS
726     
727     return false;
728 }
729
730 bool AccessibilityUIElement::isRequired() const
731 {
732     BEGIN_AX_OBJC_EXCEPTIONS
733     id value = [m_element accessibilityAttributeValue:@"AXRequired"];
734     if ([value isKindOfClass:[NSNumber class]])
735         return [value boolValue];
736     END_AX_OBJC_EXCEPTIONS
737     
738     return false;
739 }
740
741 bool AccessibilityUIElement::isFocused() const
742 {
743     // FIXME: implement
744     return false;
745 }
746
747 bool AccessibilityUIElement::isSelected() const
748 {
749     BEGIN_AX_OBJC_EXCEPTIONS
750     id value = [m_element accessibilityAttributeValue:NSAccessibilitySelectedAttribute];
751     if ([value isKindOfClass:[NSNumber class]])
752         return [value boolValue];
753     END_AX_OBJC_EXCEPTIONS
754     
755     return false;
756 }
757
758 bool AccessibilityUIElement::isExpanded() const
759 {
760     BEGIN_AX_OBJC_EXCEPTIONS
761     id value = [m_element accessibilityAttributeValue:NSAccessibilityExpandedAttribute];
762     if ([value isKindOfClass:[NSNumber class]])
763         return [value boolValue];
764     END_AX_OBJC_EXCEPTIONS
765     
766     return false;
767 }
768
769 bool AccessibilityUIElement::isChecked() const
770 {
771     // On the Mac, intValue()==1 if a a checkable control is checked.
772     return intValue() == 1;
773 }
774
775 int AccessibilityUIElement::hierarchicalLevel() const
776 {
777     BEGIN_AX_OBJC_EXCEPTIONS
778     id value = [m_element accessibilityAttributeValue:NSAccessibilityDisclosureLevelAttribute];
779     if ([value isKindOfClass:[NSNumber class]])
780         return [value intValue];
781     END_AX_OBJC_EXCEPTIONS
782
783     return 0;
784 }
785
786 JSRetainPtr<JSStringRef> AccessibilityUIElement::speak()
787 {
788     BEGIN_AX_OBJC_EXCEPTIONS
789     id value = [m_element accessibilityAttributeValue:@"AXDRTSpeechAttribute"];
790     if ([value isKindOfClass:[NSString class]])
791         return [value createJSStringRef];
792     END_AX_OBJC_EXCEPTIONS
793         
794     return 0;
795 }
796
797 bool AccessibilityUIElement::ariaIsGrabbed() const
798 {
799     BEGIN_AX_OBJC_EXCEPTIONS
800     id value = [m_element accessibilityAttributeValue:NSAccessibilityGrabbedAttribute];
801     if ([value isKindOfClass:[NSNumber class]])
802         return [value boolValue];
803     END_AX_OBJC_EXCEPTIONS
804
805     return false;
806 }
807
808 JSRetainPtr<JSStringRef> AccessibilityUIElement::ariaDropEffects() const
809 {
810     BEGIN_AX_OBJC_EXCEPTIONS
811     id value = [m_element accessibilityAttributeValue:NSAccessibilityDropEffectsAttribute];
812     if (![value isKindOfClass:[NSArray class]])
813         return 0;
814
815     NSMutableString* dropEffects = [NSMutableString string];
816     NSInteger length = [value count];
817     for (NSInteger k = 0; k < length; ++k) {
818         [dropEffects appendString:[value objectAtIndex:k]];
819         if (k < length - 1)
820             [dropEffects appendString:@","];
821     }
822     
823     return [dropEffects createJSStringRef];
824     END_AX_OBJC_EXCEPTIONS
825     
826     return 0;
827 }
828
829 // parameterized attributes
830 int AccessibilityUIElement::lineForIndex(int index)
831 {
832     BEGIN_AX_OBJC_EXCEPTIONS
833     id value = [m_element accessibilityAttributeValue:NSAccessibilityLineForIndexParameterizedAttribute forParameter:[NSNumber numberWithInt:index]];
834     if ([value isKindOfClass:[NSNumber class]])
835         return [(NSNumber *)value intValue]; 
836     END_AX_OBJC_EXCEPTIONS
837
838     return -1;
839 }
840
841 JSRetainPtr<JSStringRef> AccessibilityUIElement::rangeForLine(int line)
842 {
843     BEGIN_AX_OBJC_EXCEPTIONS
844     id value = [m_element accessibilityAttributeValue:NSAccessibilityRangeForLineParameterizedAttribute forParameter:[NSNumber numberWithInt:line]];
845     if ([value isKindOfClass:[NSValue class]])
846         return [NSStringFromRange([value rangeValue]) createJSStringRef];
847     END_AX_OBJC_EXCEPTIONS
848     
849     return 0;
850 }
851
852 JSRetainPtr<JSStringRef> AccessibilityUIElement::rangeForPosition(int x, int y)
853 {
854     BEGIN_AX_OBJC_EXCEPTIONS
855     id value = [m_element accessibilityAttributeValue:NSAccessibilityRangeForPositionParameterizedAttribute forParameter:[NSValue valueWithPoint:NSMakePoint(x, y)]];
856     if ([value isKindOfClass:[NSValue class]])
857         return [NSStringFromRange([value rangeValue]) createJSStringRef];
858     END_AX_OBJC_EXCEPTIONS
859
860     return 0;
861 }
862
863 JSRetainPtr<JSStringRef> AccessibilityUIElement::boundsForRange(unsigned location, unsigned length)
864 {
865     NSRange range = NSMakeRange(location, length);
866     BEGIN_AX_OBJC_EXCEPTIONS
867     id value = [m_element accessibilityAttributeValue:NSAccessibilityBoundsForRangeParameterizedAttribute forParameter:[NSValue valueWithRange:range]];
868     NSRect rect = NSMakeRect(0,0,0,0);
869     if ([value isKindOfClass:[NSValue class]])
870         rect = [value rectValue]; 
871     
872     // don't return position information because it is platform dependent
873     NSMutableString* boundsDescription = [NSMutableString stringWithFormat:@"{{%f, %f}, {%f, %f}}",-1.0f,-1.0f,rect.size.width,rect.size.height];
874     return [boundsDescription createJSStringRef];
875     END_AX_OBJC_EXCEPTIONS
876     
877     return 0;
878 }
879
880 JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForRange(unsigned location, unsigned length)
881 {
882     NSRange range = NSMakeRange(location, length);
883     BEGIN_AX_OBJC_EXCEPTIONS
884     id string = [m_element accessibilityAttributeValue:NSAccessibilityStringForRangeParameterizedAttribute forParameter:[NSValue valueWithRange:range]];
885     if (![string isKindOfClass:[NSString class]])
886         return 0;
887     
888     return [string createJSStringRef];
889     END_AX_OBJC_EXCEPTIONS
890     
891     return 0;
892 }
893
894 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributedStringForRange(unsigned location, unsigned length)
895 {
896     NSRange range = NSMakeRange(location, length);
897     BEGIN_AX_OBJC_EXCEPTIONS
898     NSAttributedString* string = [m_element accessibilityAttributeValue:NSAccessibilityAttributedStringForRangeParameterizedAttribute forParameter:[NSValue valueWithRange:range]];
899     if (![string isKindOfClass:[NSAttributedString class]])
900         return 0;
901     
902     NSString* stringWithAttrs = [string description];
903     return [stringWithAttrs createJSStringRef];
904     END_AX_OBJC_EXCEPTIONS
905     
906     return 0;
907 }
908
909 bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned location, unsigned length)
910 {
911     NSRange range = NSMakeRange(location, length);
912     BEGIN_AX_OBJC_EXCEPTIONS
913     NSAttributedString* string = [m_element accessibilityAttributeValue:NSAccessibilityAttributedStringForRangeParameterizedAttribute forParameter:[NSValue valueWithRange:range]];
914     if (![string isKindOfClass:[NSAttributedString class]])
915         return false;
916
917     NSDictionary* attrs = [string attributesAtIndex:0 effectiveRange:nil];
918     if([[attrs objectForKey:NSAccessibilityMisspelledTextAttribute] boolValue])
919         return true;    
920     END_AX_OBJC_EXCEPTIONS
921     
922     return false;
923 }
924
925 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementForSearchPredicate(JSContextRef context, AccessibilityUIElement* startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly)
926 {
927     BEGIN_AX_OBJC_EXCEPTIONS
928     NSMutableDictionary* parameter = [NSMutableDictionary dictionary];
929     [parameter setObject:(isDirectionNext) ? @"AXDirectionNext" : @"AXDirectionPrevious" forKey:@"AXDirection"];
930     if (visibleOnly)
931         [parameter setObject:[NSNumber numberWithBool:YES] forKey:@"AXVisibleOnly"];
932     [parameter setObject:[NSNumber numberWithInt:1] forKey:@"AXResultsLimit"];
933     if (startElement && startElement->platformUIElement())
934         [parameter setObject:(id)startElement->platformUIElement() forKey:@"AXStartElement"];
935     if (searchKey) {
936         if (JSValueIsString(context, searchKey)) {
937             NSString *searchKeyParameter = nil;
938             JSStringRef singleSearchKey = JSValueToStringCopy(context, searchKey, 0);
939             if (singleSearchKey) {
940                 searchKeyParameter = [NSString stringWithJSStringRef:singleSearchKey];
941                 JSStringRelease(singleSearchKey);
942                 if (searchKeyParameter)
943                     [parameter setObject:searchKeyParameter forKey:@"AXSearchKey"];
944             }
945         }
946         else if (JSValueIsObject(context, searchKey)) {
947             NSMutableArray *searchKeyParameter = nil;
948             JSObjectRef array = const_cast<JSObjectRef>(searchKey);
949             unsigned arrayLength = 0;
950             JSRetainPtr<JSStringRef> arrayLengthString(Adopt, JSStringCreateWithUTF8CString("length"));
951             JSValueRef arrayLengthValue = JSObjectGetProperty(context, array, arrayLengthString.get(), 0);
952             if (arrayLengthValue && JSValueIsNumber(context, arrayLengthValue))
953                 arrayLength = static_cast<unsigned>(JSValueToNumber(context, arrayLengthValue, 0));
954             
955             for (unsigned i = 0; i < arrayLength; ++i) {
956                 JSValueRef exception = 0;
957                 JSValueRef value = JSObjectGetPropertyAtIndex(context, array, i, &exception);
958                 if (exception)
959                     break;
960                 JSStringRef singleSearchKey = JSValueToStringCopy(context, value, &exception);
961                 if (exception)
962                     break;
963                 if (singleSearchKey) {
964                     if (!searchKeyParameter)
965                         searchKeyParameter = [NSMutableArray array];
966                     [searchKeyParameter addObject:[NSString stringWithJSStringRef:singleSearchKey]];
967                     JSStringRelease(singleSearchKey);
968                 }
969             }
970             if (searchKeyParameter)
971                 [parameter setObject:searchKeyParameter forKey:@"AXSearchKey"];
972         }
973     }
974     if (searchText && JSStringGetLength(searchText))
975         [parameter setObject:[NSString stringWithJSStringRef:searchText] forKey:@"AXSearchText"];
976     
977     id uiElement = [[m_element accessibilityAttributeValue:@"AXUIElementsForSearchPredicate" forParameter:parameter] lastObject];
978     return AccessibilityUIElement::create(uiElement);
979     END_AX_OBJC_EXCEPTIONS
980     
981     return 0;
982 }
983
984 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfColumnHeaders()
985 {
986     // not yet defined in AppKit... odd
987     BEGIN_AX_OBJC_EXCEPTIONS
988     NSArray* columnHeadersArray = [m_element accessibilityAttributeValue:@"AXColumnHeaderUIElements"];
989     Vector<RefPtr<AccessibilityUIElement> > columnHeadersVector;
990     convertNSArrayToVector(columnHeadersArray, columnHeadersVector);
991     return descriptionOfElements(columnHeadersVector);
992     END_AX_OBJC_EXCEPTIONS
993     
994     return 0;
995 }
996
997 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfRowHeaders()
998 {
999     BEGIN_AX_OBJC_EXCEPTIONS
1000     NSArray* rowHeadersArray = [m_element accessibilityAttributeValue:@"AXRowHeaderUIElements"];
1001     Vector<RefPtr<AccessibilityUIElement> > rowHeadersVector;
1002     convertNSArrayToVector(rowHeadersArray, rowHeadersVector);
1003     return descriptionOfElements(rowHeadersVector);
1004     END_AX_OBJC_EXCEPTIONS
1005     
1006     return 0;
1007 }
1008
1009 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfColumns()
1010 {
1011     BEGIN_AX_OBJC_EXCEPTIONS
1012     NSArray* columnsArray = [m_element accessibilityAttributeValue:NSAccessibilityColumnsAttribute];
1013     Vector<RefPtr<AccessibilityUIElement> > columnsVector;
1014     convertNSArrayToVector(columnsArray, columnsVector);
1015     return descriptionOfElements(columnsVector);
1016     END_AX_OBJC_EXCEPTIONS
1017     
1018     return 0;
1019 }
1020
1021 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfRows()
1022 {
1023     BEGIN_AX_OBJC_EXCEPTIONS
1024     NSArray* rowsArray = [m_element accessibilityAttributeValue:NSAccessibilityRowsAttribute];
1025     Vector<RefPtr<AccessibilityUIElement> > rowsVector;
1026     convertNSArrayToVector(rowsArray, rowsVector);
1027     return descriptionOfElements(rowsVector);
1028     END_AX_OBJC_EXCEPTIONS
1029     
1030     return 0;
1031 }
1032
1033 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfVisibleCells()
1034 {
1035     BEGIN_AX_OBJC_EXCEPTIONS
1036     NSArray* cellsArray = [m_element accessibilityAttributeValue:@"AXVisibleCells"];
1037     Vector<RefPtr<AccessibilityUIElement> > cellsVector;
1038     convertNSArrayToVector(cellsArray, cellsVector);
1039     return descriptionOfElements(cellsVector);
1040     END_AX_OBJC_EXCEPTIONS
1041     
1042     return 0;
1043 }
1044
1045 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfHeader()
1046 {
1047     BEGIN_AX_OBJC_EXCEPTIONS
1048     id headerObject = [m_element accessibilityAttributeValue:NSAccessibilityHeaderAttribute];
1049     if (!headerObject)
1050         return [@"" createJSStringRef];
1051     
1052     Vector<RefPtr<AccessibilityUIElement> > headerVector;
1053     headerVector.append(AccessibilityUIElement::create(headerObject));
1054     return descriptionOfElements(headerVector);
1055     END_AX_OBJC_EXCEPTIONS
1056     
1057     return 0;
1058 }
1059
1060 int AccessibilityUIElement::rowCount()
1061 {
1062     BEGIN_AX_OBJC_EXCEPTIONS
1063     return [m_element accessibilityArrayAttributeCount:NSAccessibilityRowsAttribute];
1064     END_AX_OBJC_EXCEPTIONS
1065     
1066     return 0;
1067 }
1068
1069 int AccessibilityUIElement::columnCount()
1070 {
1071     BEGIN_AX_OBJC_EXCEPTIONS
1072     return [m_element accessibilityArrayAttributeCount:NSAccessibilityColumnsAttribute];
1073     END_AX_OBJC_EXCEPTIONS
1074     
1075     return 0;
1076 }
1077
1078 int AccessibilityUIElement::indexInTable()
1079 {
1080     BEGIN_AX_OBJC_EXCEPTIONS
1081     NSNumber* indexNumber = [m_element accessibilityAttributeValue:NSAccessibilityIndexAttribute];
1082     if (indexNumber)
1083         return [indexNumber intValue];
1084     END_AX_OBJC_EXCEPTIONS
1085
1086     return -1;
1087 }
1088
1089 JSRetainPtr<JSStringRef> AccessibilityUIElement::rowIndexRange()
1090 {
1091     NSRange range = NSMakeRange(0, 0);
1092     BEGIN_AX_OBJC_EXCEPTIONS
1093     NSValue* indexRange = [m_element accessibilityAttributeValue:@"AXRowIndexRange"];
1094     if (indexRange)
1095         range = [indexRange rangeValue];
1096     NSMutableString* rangeDescription = [NSMutableString stringWithFormat:@"{%lu, %lu}", static_cast<unsigned long>(range.location), static_cast<unsigned long>(range.length)];
1097     return [rangeDescription createJSStringRef];
1098     END_AX_OBJC_EXCEPTIONS
1099     
1100     return 0;
1101 }
1102
1103 JSRetainPtr<JSStringRef> AccessibilityUIElement::columnIndexRange()
1104 {
1105     NSRange range = NSMakeRange(0, 0);
1106     BEGIN_AX_OBJC_EXCEPTIONS
1107     NSNumber* indexRange = [m_element accessibilityAttributeValue:@"AXColumnIndexRange"];
1108     if (indexRange)
1109         range = [indexRange rangeValue];
1110     NSMutableString* rangeDescription = [NSMutableString stringWithFormat:@"{%lu, %lu}", static_cast<unsigned long>(range.location), static_cast<unsigned long>(range.length)];
1111     return [rangeDescription createJSStringRef];
1112     END_AX_OBJC_EXCEPTIONS
1113     
1114     return 0;
1115 }
1116
1117 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::cellForColumnAndRow(unsigned col, unsigned row)
1118 {
1119     NSArray *colRowArray = [NSArray arrayWithObjects:[NSNumber numberWithUnsignedInt:col], [NSNumber numberWithUnsignedInt:row], nil];
1120     BEGIN_AX_OBJC_EXCEPTIONS
1121     return AccessibilityUIElement::create([m_element accessibilityAttributeValue:@"AXCellForColumnAndRow" forParameter:colRowArray]);
1122     END_AX_OBJC_EXCEPTIONS    
1123
1124     return 0;
1125 }
1126
1127 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::horizontalScrollbar() const
1128 {
1129     BEGIN_AX_OBJC_EXCEPTIONS
1130     return AccessibilityUIElement::create([m_element accessibilityAttributeValue:NSAccessibilityHorizontalScrollBarAttribute]);
1131     END_AX_OBJC_EXCEPTIONS    
1132     
1133     return 0;
1134 }
1135
1136 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::verticalScrollbar() const
1137 {
1138     BEGIN_AX_OBJC_EXCEPTIONS
1139     return AccessibilityUIElement::create([m_element accessibilityAttributeValue:NSAccessibilityVerticalScrollBarAttribute]);
1140     END_AX_OBJC_EXCEPTIONS        
1141
1142     return 0;
1143 }
1144
1145 void AccessibilityUIElement::scrollToMakeVisible()
1146 {
1147     BEGIN_AX_OBJC_EXCEPTIONS
1148     [m_element accessibilityPerformAction:@"AXScrollToVisible"];
1149     END_AX_OBJC_EXCEPTIONS
1150 }
1151     
1152 JSRetainPtr<JSStringRef> AccessibilityUIElement::selectedTextRange()
1153 {
1154     NSRange range = NSMakeRange(NSNotFound, 0);
1155     BEGIN_AX_OBJC_EXCEPTIONS
1156     NSValue *indexRange = [m_element accessibilityAttributeValue:NSAccessibilitySelectedTextRangeAttribute];
1157     if (indexRange)
1158         range = [indexRange rangeValue];
1159     NSMutableString* rangeDescription = [NSMutableString stringWithFormat:@"{%lu, %lu}", static_cast<unsigned long>(range.location), static_cast<unsigned long>(range.length)];
1160     return [rangeDescription createJSStringRef];
1161     END_AX_OBJC_EXCEPTIONS
1162     
1163     return 0;
1164 }
1165
1166 void AccessibilityUIElement::setSelectedTextRange(unsigned location, unsigned length)
1167 {
1168     NSRange textRange = NSMakeRange(location, length);
1169     NSValue *textRangeValue = [NSValue valueWithRange:textRange];
1170     BEGIN_AX_OBJC_EXCEPTIONS
1171     [m_element accessibilitySetValue:textRangeValue forAttribute:NSAccessibilitySelectedTextRangeAttribute];
1172     END_AX_OBJC_EXCEPTIONS
1173 }
1174
1175 void AccessibilityUIElement::increment()
1176 {
1177     BEGIN_AX_OBJC_EXCEPTIONS
1178     [m_element accessibilityPerformAction:NSAccessibilityIncrementAction];
1179     END_AX_OBJC_EXCEPTIONS
1180 }
1181
1182 void AccessibilityUIElement::decrement()
1183 {
1184     BEGIN_AX_OBJC_EXCEPTIONS
1185     [m_element accessibilityPerformAction:NSAccessibilityDecrementAction];
1186     END_AX_OBJC_EXCEPTIONS
1187 }
1188
1189 void AccessibilityUIElement::showMenu()
1190 {
1191     BEGIN_AX_OBJC_EXCEPTIONS
1192     [m_element accessibilityPerformAction:NSAccessibilityShowMenuAction];
1193     END_AX_OBJC_EXCEPTIONS
1194 }
1195
1196 void AccessibilityUIElement::press()
1197 {
1198     BEGIN_AX_OBJC_EXCEPTIONS
1199     [m_element accessibilityPerformAction:NSAccessibilityPressAction];
1200     END_AX_OBJC_EXCEPTIONS
1201 }
1202
1203 void AccessibilityUIElement::setSelectedChild(AccessibilityUIElement* element) const
1204 {
1205     BEGIN_AX_OBJC_EXCEPTIONS
1206     NSArray* array = [NSArray arrayWithObject:element->platformUIElement()];
1207     [m_element accessibilitySetValue:array forAttribute:NSAccessibilitySelectedChildrenAttribute];
1208     END_AX_OBJC_EXCEPTIONS    
1209 }
1210
1211 JSRetainPtr<JSStringRef> AccessibilityUIElement::accessibilityValue() const
1212 {
1213     // FIXME: implement
1214     return JSStringCreateWithCharacters(0, 0);
1215 }
1216
1217 JSRetainPtr<JSStringRef> AccessibilityUIElement::documentEncoding()
1218 {
1219     return JSStringCreateWithCharacters(0, 0);
1220 }
1221
1222 JSRetainPtr<JSStringRef> AccessibilityUIElement::documentURI()
1223 {
1224     return JSStringCreateWithCharacters(0, 0);
1225 }
1226
1227 JSRetainPtr<JSStringRef> AccessibilityUIElement::url()
1228 {
1229     BEGIN_AX_OBJC_EXCEPTIONS
1230     NSURL *url = [m_element accessibilityAttributeValue:NSAccessibilityURLAttribute];
1231     return [[url absoluteString] createJSStringRef];    
1232     END_AX_OBJC_EXCEPTIONS
1233     
1234     return nil;
1235 }
1236
1237 bool AccessibilityUIElement::addNotificationListener(JSValueRef functionCallback)
1238 {
1239     if (!functionCallback)
1240         return false;
1241  
1242     // Mac programmers should not be adding more than one notification listener per element.
1243     // Other platforms may be different.
1244     if (m_notificationHandler)
1245         return false;
1246     m_notificationHandler = [[AccessibilityNotificationHandler alloc] init];
1247     [m_notificationHandler setPlatformElement:platformUIElement()];
1248     [m_notificationHandler setCallback:functionCallback];
1249     [m_notificationHandler startObserving];
1250
1251     return true;
1252 }
1253
1254 bool AccessibilityUIElement::removeNotificationListener()
1255 {
1256     // Mac programmers should not be trying to remove a listener that's already removed.
1257     ASSERT(m_notificationHandler);
1258
1259     [m_notificationHandler release];
1260     m_notificationHandler = nil;
1261     
1262     return true;
1263 }
1264
1265 bool AccessibilityUIElement::isFocusable() const
1266 {
1267     bool result = false;
1268     BEGIN_AX_OBJC_EXCEPTIONS
1269     result = [m_element accessibilityIsAttributeSettable:NSAccessibilityFocusedAttribute];
1270     END_AX_OBJC_EXCEPTIONS
1271     
1272     return result;
1273 }
1274
1275 bool AccessibilityUIElement::isSelectable() const
1276 {
1277     // FIXME: implement
1278     return false;
1279 }
1280
1281 bool AccessibilityUIElement::isMultiSelectable() const
1282 {
1283     // FIXME: implement
1284     return false;
1285 }
1286
1287 bool AccessibilityUIElement::isVisible() const
1288 {
1289     // FIXME: implement
1290     return false;
1291 }
1292
1293 bool AccessibilityUIElement::isOffScreen() const
1294 {
1295     // FIXME: implement
1296     return false;
1297 }
1298
1299 bool AccessibilityUIElement::isCollapsed() const
1300 {
1301     // FIXME: implement
1302     return false;
1303 }
1304
1305 bool AccessibilityUIElement::isIgnored() const
1306 {
1307     BOOL result = NO;
1308     BEGIN_AX_OBJC_EXCEPTIONS
1309     result = [m_element accessibilityIsIgnored];
1310     END_AX_OBJC_EXCEPTIONS
1311     return result;
1312 }
1313
1314 bool AccessibilityUIElement::hasPopup() const
1315 {
1316     BEGIN_AX_OBJC_EXCEPTIONS
1317     id value = [m_element accessibilityAttributeValue:@"AXHasPopup"];
1318     if ([value isKindOfClass:[NSNumber class]])
1319         return [value boolValue];
1320     END_AX_OBJC_EXCEPTIONS
1321
1322     return false;
1323 }
1324
1325 void AccessibilityUIElement::takeFocus()
1326 {
1327     // FIXME: implement
1328 }
1329
1330 void AccessibilityUIElement::takeSelection()
1331 {
1332     // FIXME: implement
1333 }
1334
1335 void AccessibilityUIElement::addSelection()
1336 {
1337     // FIXME: implement
1338 }
1339
1340 void AccessibilityUIElement::removeSelection()
1341 {
1342     // FIXME: implement
1343 }
1344
1345 // Text markers
1346 PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeForElement(AccessibilityUIElement* element)
1347 {
1348     BEGIN_AX_OBJC_EXCEPTIONS
1349     id textMarkerRange = [m_element accessibilityAttributeValue:@"AXTextMarkerRangeForUIElement" forParameter:element->platformUIElement()];
1350     return AccessibilityTextMarkerRange::create(textMarkerRange);
1351     END_AX_OBJC_EXCEPTIONS
1352     
1353     return 0;
1354 }
1355
1356 int AccessibilityUIElement::textMarkerRangeLength(AccessibilityTextMarkerRange* range)
1357 {
1358     BEGIN_AX_OBJC_EXCEPTIONS
1359     NSNumber* lengthValue = [m_element accessibilityAttributeValue:@"AXLengthForTextMarkerRange" forParameter:(id)range->platformTextMarkerRange()];
1360     return [lengthValue intValue];
1361     END_AX_OBJC_EXCEPTIONS
1362     
1363     return 0;
1364 }
1365
1366 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousTextMarker(AccessibilityTextMarker* textMarker)
1367 {
1368     BEGIN_AX_OBJC_EXCEPTIONS
1369     id previousMarker = [m_element accessibilityAttributeValue:@"AXPreviousTextMarkerForTextMarker" forParameter:(id)textMarker->platformTextMarker()];
1370     return AccessibilityTextMarker::create(previousMarker);
1371     END_AX_OBJC_EXCEPTIONS
1372     
1373     return 0;
1374 }
1375
1376 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextTextMarker(AccessibilityTextMarker* textMarker)
1377 {
1378     BEGIN_AX_OBJC_EXCEPTIONS
1379     id nextMarker = [m_element accessibilityAttributeValue:@"AXNextTextMarkerForTextMarker" forParameter:(id)textMarker->platformTextMarker()];
1380     return AccessibilityTextMarker::create(nextMarker);
1381     END_AX_OBJC_EXCEPTIONS
1382     
1383     return 0;
1384 }
1385
1386 JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForTextMarkerRange(AccessibilityTextMarkerRange* markerRange)
1387 {
1388     BEGIN_AX_OBJC_EXCEPTIONS
1389     id textString = [m_element accessibilityAttributeValue:@"AXStringForTextMarkerRange" forParameter:(id)markerRange->platformTextMarkerRange()];
1390     return [textString createJSStringRef];
1391     END_AX_OBJC_EXCEPTIONS
1392     
1393     return 0;
1394 }
1395
1396 PassRefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeForMarkers(AccessibilityTextMarker* startMarker, AccessibilityTextMarker* endMarker)
1397 {
1398     BEGIN_AX_OBJC_EXCEPTIONS
1399     NSArray* textMarkers = [NSArray arrayWithObjects:(id)startMarker->platformTextMarker(), (id)endMarker->platformTextMarker(), nil];
1400     id textMarkerRange = [m_element accessibilityAttributeValue:@"AXTextMarkerRangeForUnorderedTextMarkers" forParameter:textMarkers];
1401     return AccessibilityTextMarkerRange::create(textMarkerRange);
1402     END_AX_OBJC_EXCEPTIONS
1403     
1404     return 0;
1405 }
1406
1407 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range)
1408 {
1409     BEGIN_AX_OBJC_EXCEPTIONS
1410     id textMarker = [m_element accessibilityAttributeValue:@"AXStartTextMarkerForTextMarkerRange" forParameter:(id)range->platformTextMarkerRange()];
1411     return AccessibilityTextMarker::create(textMarker);
1412     END_AX_OBJC_EXCEPTIONS
1413     
1414     return 0;    
1415 }
1416
1417 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range)
1418 {
1419     BEGIN_AX_OBJC_EXCEPTIONS
1420     id textMarker = [m_element accessibilityAttributeValue:@"AXEndTextMarkerForTextMarkerRange" forParameter:(id)range->platformTextMarkerRange()];
1421     return AccessibilityTextMarker::create(textMarker);
1422     END_AX_OBJC_EXCEPTIONS
1423     
1424     return 0;    
1425 }
1426
1427 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForPoint(int x, int y)
1428 {
1429     BEGIN_AX_OBJC_EXCEPTIONS
1430     id textMarker = [m_element accessibilityAttributeValue:@"AXTextMarkerForPosition" forParameter:[NSValue valueWithPoint:NSMakePoint(x, y)]];
1431     return AccessibilityTextMarker::create(textMarker);
1432     END_AX_OBJC_EXCEPTIONS
1433     
1434     return 0;    
1435 }
1436
1437 PassRefPtr<AccessibilityUIElement> AccessibilityUIElement::accessibilityElementForTextMarker(AccessibilityTextMarker* marker)
1438 {
1439     BEGIN_AX_OBJC_EXCEPTIONS
1440     id uiElement = [m_element accessibilityAttributeValue:@"AXUIElementForTextMarker" forParameter:(id)marker->platformTextMarker()];
1441     return AccessibilityUIElement::create(uiElement);
1442     END_AX_OBJC_EXCEPTIONS
1443     
1444     return 0;  
1445 }
1446     
1447 bool AccessibilityUIElement::attributedStringForTextMarkerRangeContainsAttribute(JSStringRef attribute, AccessibilityTextMarkerRange* range)
1448 {
1449     BEGIN_AX_OBJC_EXCEPTIONS
1450     NSAttributedString* string = [m_element accessibilityAttributeValue:@"AXAttributedStringForTextMarkerRange" forParameter:(id)range->platformTextMarkerRange()];
1451     if (![string isKindOfClass:[NSAttributedString class]])
1452         return false;
1453     
1454     NSDictionary* attrs = [string attributesAtIndex:0 effectiveRange:nil];
1455     if ([attrs objectForKey:[NSString stringWithJSStringRef:attribute]])
1456         return true;    
1457     END_AX_OBJC_EXCEPTIONS
1458     
1459     return false;
1460 }
1461     
1462 int AccessibilityUIElement::indexForTextMarker(AccessibilityTextMarker* marker)
1463 {
1464     BEGIN_AX_OBJC_EXCEPTIONS
1465     NSNumber* indexNumber = [m_element accessibilityAttributeValue:@"AXIndexForTextMarker" forParameter:(id)marker->platformTextMarker()];
1466     return [indexNumber intValue];
1467     END_AX_OBJC_EXCEPTIONS
1468     
1469     return -1;
1470 }
1471
1472 bool AccessibilityUIElement::isTextMarkerValid(AccessibilityTextMarker* textMarker)
1473 {
1474     BEGIN_AX_OBJC_EXCEPTIONS
1475     NSNumber* validNumber = [m_element accessibilityAttributeValue:@"AXTextMarkerIsValid" forParameter:(id)textMarker->platformTextMarker()];
1476     return [validNumber boolValue];
1477     END_AX_OBJC_EXCEPTIONS
1478     
1479     return false;
1480 }
1481
1482 PassRefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForIndex(int textIndex)
1483 {
1484     BEGIN_AX_OBJC_EXCEPTIONS
1485     id textMarker = [m_element accessibilityAttributeValue:@"AXTextMarkerForIndex" forParameter:[NSNumber numberWithInteger:textIndex]];
1486     return AccessibilityTextMarker::create(textMarker);
1487     END_AX_OBJC_EXCEPTIONS
1488     
1489     return 0;                                                                          
1490 }
1491
1492 static NSString *_convertMathMultiscriptPairsToString(NSArray *pairs)
1493 {
1494     __block NSMutableString *result = [NSMutableString string];
1495     [pairs enumerateObjectsUsingBlock:^(id pair, NSUInteger index, BOOL *stop) {
1496         for (NSString *key in pair)
1497             [result appendFormat:@"\t%lu. %@ = %@\n", (unsigned long)index, key, [[pair objectForKey:key] accessibilityAttributeValue:NSAccessibilitySubroleAttribute]];
1498     }];
1499     
1500     return result;
1501 }
1502     
1503 JSRetainPtr<JSStringRef> AccessibilityUIElement::mathPostscriptsDescription() const
1504 {
1505     BEGIN_AX_OBJC_EXCEPTIONS
1506     NSArray *pairs = [m_element accessibilityAttributeValue:@"AXMathPostscripts"];
1507     return [_convertMathMultiscriptPairsToString(pairs) createJSStringRef];
1508     END_AX_OBJC_EXCEPTIONS
1509     
1510     return 0;
1511 }
1512
1513 JSRetainPtr<JSStringRef> AccessibilityUIElement::mathPrescriptsDescription() const
1514 {
1515     BEGIN_AX_OBJC_EXCEPTIONS
1516     NSArray *pairs = [m_element accessibilityAttributeValue:@"AXMathPrescripts"];
1517     return [_convertMathMultiscriptPairsToString(pairs) createJSStringRef];
1518     END_AX_OBJC_EXCEPTIONS
1519     
1520     return 0;
1521 }
1522     
1523 JSRetainPtr<JSStringRef> AccessibilityUIElement::pathDescription() const
1524 {
1525     BEGIN_AX_OBJC_EXCEPTIONS
1526     NSMutableString *result = [NSMutableString stringWithString:@"\nStart Path\n"];
1527     NSBezierPath *bezierPath = [m_element accessibilityAttributeValue:NSAccessibilityPathAttribute];
1528     
1529     NSUInteger elementCount = [bezierPath elementCount];
1530     NSPoint points[3];
1531     for (NSUInteger i = 0; i < elementCount; i++) {
1532         switch ([bezierPath elementAtIndex:i associatedPoints:points]) {
1533         case NSMoveToBezierPathElement:
1534             [result appendString:@"\tMove to point\n"];
1535             break;
1536             
1537         case NSLineToBezierPathElement:
1538             [result appendString:@"\tLine to\n"];
1539             break;
1540             
1541         case NSCurveToBezierPathElement:
1542             [result appendString:@"\tCurve to\n"];
1543             break;
1544             
1545         case NSClosePathBezierPathElement:
1546             [result appendString:@"\tClose\n"];
1547             break;
1548         }
1549     }
1550     
1551     return [result createJSStringRef];
1552     END_AX_OBJC_EXCEPTIONS
1553     
1554     return 0;
1555 }
1556     
1557 JSRetainPtr<JSStringRef> AccessibilityUIElement::supportedActions() const
1558 {
1559     BEGIN_AX_OBJC_EXCEPTIONS
1560     NSArray *names = [m_element accessibilityActionNames];
1561     return [[names componentsJoinedByString:@","] createJSStringRef];
1562     END_AX_OBJC_EXCEPTIONS
1563     
1564     return 0;
1565 }
1566
1567 } // namespace WTR
1568