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