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