bb54e2c3b1a7792576d50e53b0cc20b34f395f76
[WebKit-https.git] / Source / WebCore / accessibility / ios / WebAccessibilityObjectWrapperIOS.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 COMPUTER, 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 COMPUTER, 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 "WebAccessibilityObjectWrapperIOS.h"
28
29 #if HAVE(ACCESSIBILITY) && PLATFORM(IOS)
30
31 #import "AccessibilityRenderObject.h"
32 #import "AccessibilityTable.h"
33 #import "AccessibilityTableCell.h"
34 #import "Font.h"
35 #import "Frame.h"
36 #import "FrameSelection.h"
37 #import "FrameView.h"
38 #import "HitTestResult.h"
39 #import "HTMLFrameOwnerElement.h"
40 #import "HTMLInputElement.h"
41 #import "HTMLNames.h"
42 #import "IntRect.h"
43 #import "IntSize.h"
44 #import "Range.h"
45 #import "RenderView.h"
46 #import "RuntimeApplicationChecksIOS.h"
47 #import "SVGNames.h"
48 #import "TextIterator.h"
49 #import "WAKScrollView.h"
50 #import "WAKView.h"
51 #import "WAKWindow.h"
52 #import "WebCoreThread.h"
53 #import "VisibleUnits.h"
54
55 #import <GraphicsServices/GraphicsServices.h>
56
57 @interface NSObject (AccessibilityPrivate)
58 - (void)_accessibilityUnregister;
59 - (NSString *)accessibilityLabel;
60 - (NSString *)accessibilityValue;
61 - (BOOL)isAccessibilityElement;
62 - (NSInteger)accessibilityElementCount;
63 - (id)accessibilityElementAtIndex:(NSInteger)index;
64 - (NSInteger)indexOfAccessibilityElement:(id)element;
65 @end
66
67 @interface WebAccessibilityObjectWrapper (AccessibilityPrivate)
68 - (id)_accessibilityWebDocumentView;
69 - (id)accessibilityContainer;
70 - (void)setAccessibilityLabel:(NSString *)label;
71 - (void)setAccessibilityValue:(NSString *)value;
72 - (BOOL)containsUnnaturallySegmentedChildren;
73 - (NSInteger)positionForTextMarker:(id)marker;
74 @end
75
76 @interface WAKView (iOSAccessibility)
77 - (BOOL)accessibilityIsIgnored;
78 @end
79
80 using namespace WebCore;
81 using namespace HTMLNames;
82
83 // These are tokens accessibility uses to denote attributes. 
84 static NSString * const UIAccessibilityTokenBlockquoteLevel = @"UIAccessibilityTokenBlockquoteLevel";
85 static NSString * const UIAccessibilityTokenHeadingLevel = @"UIAccessibilityTokenHeadingLevel";
86 static NSString * const UIAccessibilityTokenFontName = @"UIAccessibilityTokenFontName";
87 static NSString * const UIAccessibilityTokenFontFamily = @"UIAccessibilityTokenFontFamily";
88 static NSString * const UIAccessibilityTokenFontSize = @"UIAccessibilityTokenFontSize";
89 static NSString * const UIAccessibilityTokenBold = @"UIAccessibilityTokenBold";
90 static NSString * const UIAccessibilityTokenItalic = @"UIAccessibilityTokenItalic";
91 static NSString * const UIAccessibilityTokenUnderline = @"UIAccessibilityTokenUnderline";
92
93 static AccessibilityObjectWrapper* AccessibilityUnignoredAncestor(AccessibilityObjectWrapper *wrapper)
94 {
95     while (wrapper && ![wrapper isAccessibilityElement]) {
96         AccessibilityObject* object = [wrapper accessibilityObject];
97         if (!object)
98             break;
99         
100         if ([wrapper isAttachment] && ![[wrapper attachmentView] accessibilityIsIgnored])
101             break;
102             
103         AccessibilityObject* parentObject = object->parentObjectUnignored();
104         if (!parentObject)
105             break;
106
107         wrapper = parentObject->wrapper();
108     }
109     return wrapper;
110 }
111
112 #pragma mark Accessibility Text Marker
113
114 @interface WebAccessibilityTextMarker : NSObject
115 {
116     AXObjectCache* _cache;
117     TextMarkerData _textMarkerData;
118 }
119
120 + (WebAccessibilityTextMarker *)textMarkerWithVisiblePosition:(VisiblePosition&)visiblePos cache:(AXObjectCache*)cache;
121
122 @end
123
124 @implementation WebAccessibilityTextMarker
125
126 - (id)initWithTextMarker:(TextMarkerData *)data cache:(AXObjectCache*)cache
127 {
128     if (!(self = [super init]))
129         return nil;
130     
131     _cache = cache;
132     memcpy(&_textMarkerData, data, sizeof(TextMarkerData));
133     return self;
134 }
135
136 - (id)initWithData:(NSData *)data cache:(AXObjectCache*)cache
137 {
138     if (!(self = [super init]))
139         return nil;
140     
141     _cache = cache;
142     [data getBytes:&_textMarkerData length:sizeof(TextMarkerData)];
143     
144     return self;
145 }
146
147 // This is needed for external clients to be able to create a text marker without having a pointer to the cache.
148 - (id)initWithData:(NSData *)data accessibilityObject:(AccessibilityObjectWrapper *)wrapper
149 {
150     WebCore::AccessibilityObject* axObject = [wrapper accessibilityObject]; 
151     if (!axObject)
152         return nil;
153     
154     return [self initWithData:data cache:axObject->axObjectCache()];
155 }
156
157 + (WebAccessibilityTextMarker *)textMarkerWithVisiblePosition:(VisiblePosition&)visiblePos cache:(AXObjectCache*)cache
158 {
159     TextMarkerData textMarkerData;
160     cache->textMarkerDataForVisiblePosition(textMarkerData, visiblePos);
161     
162     return [[[WebAccessibilityTextMarker alloc] initWithTextMarker:&textMarkerData cache:cache] autorelease];
163 }
164
165 - (NSData *)dataRepresentation
166 {
167     return [NSData dataWithBytes:&_textMarkerData length:sizeof(TextMarkerData)];
168 }
169
170 - (VisiblePosition)visiblePosition
171 {
172     return _cache->visiblePositionForTextMarkerData(_textMarkerData);
173 }
174
175 - (NSString *)description
176 {
177     return [NSString stringWithFormat:@"[AXTextMarker %p] = node: %p offset: %d", self, _textMarkerData.node, _textMarkerData.offset];
178 }
179
180 @end
181
182 @implementation WebAccessibilityObjectWrapper
183
184 - (id)initWithAccessibilityObject:(AccessibilityObject*)axObject
185 {
186     self = [super initWithAccessibilityObject:axObject];
187     if (!self)
188         return nil;
189     
190     // Initialize to a sentinel value.
191     m_accessibilityTraitsFromAncestor = ULLONG_MAX;
192     m_isAccessibilityElement = -1;
193     
194     return self;
195 }
196
197 - (void)detach
198 {
199     // rdar://8798960 Make sure the object is gone early, so that anything _accessibilityUnregister 
200     // does can't call back into the render tree.
201     m_object = 0;
202
203     if ([self respondsToSelector:@selector(_accessibilityUnregister)])
204         [self _accessibilityUnregister];
205 }
206
207 - (void)dealloc
208 {
209     // We should have been detached before deallocated.
210     ASSERT(!m_object);
211     [super dealloc];
212 }
213
214 - (BOOL)_prepareAccessibilityCall
215 {
216     // rdar://7980318 if we start a call, then block in WebThreadLock(), then we're dealloced on another, thread, we could
217     // crash, so we should retain ourself for the duration of usage here.
218     [[self retain] autorelease];
219
220     WebThreadLock();
221     
222     // If we came back from our thread lock and we were detached, we will no longer have an m_object.
223     if (!m_object)
224         return NO;
225     
226     m_object->updateBackingStore();
227     if (!m_object)
228         return NO;
229     
230     return YES;
231 }
232
233 // These are here so that we don't have to import AXRuntime.
234 // The methods will be swizzled when the accessibility bundle is loaded.
235
236 - (uint64_t)_axLinkTrait { return (1 << 0); }
237 - (uint64_t)_axVisitedTrait { return (1 << 1); }
238 - (uint64_t)_axHeaderTrait { return (1 << 2); }
239 - (uint64_t)_axContainedByListTrait { return (1 << 3); }
240 - (uint64_t)_axContainedByTableTrait { return (1 << 4); }
241 - (uint64_t)_axContainedByLandmarkTrait { return (1 << 5); }
242 - (uint64_t)_axWebContentTrait { return (1 << 6); }
243 - (uint64_t)_axSecureTextFieldTrait { return (1 << 7); }
244 - (uint64_t)_axTextEntryTrait { return (1 << 8); }
245 - (uint64_t)_axHasTextCursorTrait { return (1 << 9); }
246 - (uint64_t)_axTextOperationsAvailableTrait { return (1 << 10); }
247 - (uint64_t)_axImageTrait { return (1 << 11); }
248 - (uint64_t)_axTabButtonTrait { return (1 << 12); }
249 - (uint64_t)_axButtonTrait { return (1 << 13); }
250 - (uint64_t)_axToggleTrait { return (1 << 14); }
251 - (uint64_t)_axPopupButtonTrait { return (1 << 15); }
252 - (uint64_t)_axStaticTextTrait { return (1 << 16); }
253 - (uint64_t)_axAdjustableTrait { return (1 << 17); }
254 - (uint64_t)_axMenuItemTrait { return (1 << 18); }
255 - (uint64_t)_axSelectedTrait { return (1 << 19); }
256 - (uint64_t)_axNotEnabledTrait { return (1 << 20); }
257 - (uint64_t)_axRadioButtonTrait { return (1 << 21); }
258
259 - (BOOL)accessibilityCanFuzzyHitTest
260 {
261     if (![self _prepareAccessibilityCall])
262         return nil;
263     
264     AccessibilityRole role = m_object->roleValue();
265     // Elements that can be returned when performing fuzzy hit testing.
266     switch (role) {
267     case ButtonRole:
268     case CheckBoxRole:
269     case ComboBoxRole:
270     case DisclosureTriangleRole:
271     case HeadingRole:
272     case ImageMapLinkRole:
273     case ImageRole:
274     case LinkRole:
275     case ListBoxRole:
276     case ListBoxOptionRole:
277     case MenuButtonRole:
278     case MenuItemRole:
279     case MenuItemCheckboxRole:
280     case MenuItemRadioRole:
281     case PopUpButtonRole:
282     case RadioButtonRole:
283     case ScrollBarRole:
284     case SliderRole:
285     case StaticTextRole:
286     case TabRole:
287     case TextFieldRole:
288         return !m_object->accessibilityIsIgnored();
289     default:
290         return false;
291     }
292 }
293
294 - (AccessibilityObjectWrapper *)accessibilityPostProcessHitTest:(CGPoint)point
295 {
296     UNUSED_PARAM(point);
297     // The UIKit accessibility wrapper will override this and perform the post process hit test.
298     return nil;
299 }
300
301 - (id)accessibilityHitTest:(CGPoint)point
302 {
303     if (![self _prepareAccessibilityCall])
304         return nil;
305     
306     // Try a fuzzy hit test first to find an accessible element.
307     RefPtr<AccessibilityObject> axObject;
308     {
309         AXAttributeCacheEnabler enableCache(m_object->axObjectCache());
310         axObject = m_object->accessibilityHitTest(IntPoint(point));
311     }
312
313     if (!axObject)
314         return nil;
315     
316     // If this is a good accessible object to return, no extra work is required.
317     if ([axObject->wrapper() accessibilityCanFuzzyHitTest])
318         return AccessibilityUnignoredAncestor(axObject->wrapper());
319     
320     // Check to see if we can post-process this hit test to find a better candidate.
321     AccessibilityObjectWrapper* wrapper = [axObject->wrapper() accessibilityPostProcessHitTest:point];
322     if (wrapper)
323         return AccessibilityUnignoredAncestor(wrapper);
324     
325     // Fall back to default behavior.
326     return AccessibilityUnignoredAncestor(axObject->wrapper());    
327 }
328
329 - (NSInteger)accessibilityElementCount
330 {
331     if (![self _prepareAccessibilityCall])
332         return nil;
333
334     AXAttributeCacheEnabler enableCache(m_object->axObjectCache());
335     if ([self isAttachment])
336         return [[self attachmentView] accessibilityElementCount];
337     
338     return m_object->children().size();
339 }
340
341 - (id)accessibilityElementAtIndex:(NSInteger)index
342 {
343     if (![self _prepareAccessibilityCall])
344         return nil;
345
346     AXAttributeCacheEnabler enableCache(m_object->axObjectCache());
347     if ([self isAttachment])
348         return [[self attachmentView] accessibilityElementAtIndex:index];
349     
350     AccessibilityObject::AccessibilityChildrenVector children = m_object->children();
351     if (static_cast<unsigned>(index) >= children.size())
352         return nil;
353     
354     AccessibilityObjectWrapper* wrapper = children[index]->wrapper();
355     if (children[index]->isAttachment())
356         return [wrapper attachmentView];
357
358     return wrapper;
359 }
360
361 - (NSInteger)indexOfAccessibilityElement:(id)element
362 {
363     if (![self _prepareAccessibilityCall])
364         return NSNotFound;
365     
366     AXAttributeCacheEnabler enableCache(m_object->axObjectCache());
367     if ([self isAttachment])
368         return [[self attachmentView] indexOfAccessibilityElement:element];
369     
370     AccessibilityObject::AccessibilityChildrenVector children = m_object->children();
371     unsigned count = children.size();
372     for (unsigned k = 0; k < count; ++k) {
373         AccessibilityObjectWrapper* wrapper = children[k]->wrapper();
374         if (wrapper == element || (children[k]->isAttachment() && [wrapper attachmentView] == element))
375             return k;
376     }
377     
378     return NSNotFound;
379 }
380
381 - (CGPathRef)_accessibilityPath
382 {
383     if (![self _prepareAccessibilityCall])
384         return NULL;
385
386     if (!m_object->supportsPath())
387         return NULL;
388     
389     Path path = m_object->elementPath();
390     if (path.isEmpty())
391         return NULL;
392     
393     return [self convertPathToScreenSpace:path];
394 }
395
396 - (NSString *)accessibilityLanguage
397 {
398     if (![self _prepareAccessibilityCall])
399         return nil;
400     
401     return m_object->language();
402 }
403
404 - (BOOL)_accessibilityIsLandmarkRole:(AccessibilityRole)role
405 {
406     switch (role) {
407         case LandmarkApplicationRole:
408         case LandmarkBannerRole:
409         case LandmarkComplementaryRole:
410         case LandmarkContentInfoRole:
411         case LandmarkMainRole:
412         case LandmarkNavigationRole:
413         case LandmarkSearchRole:
414             return YES;
415         default:
416             return NO;
417     }    
418 }
419
420 - (AccessibilityObjectWrapper*)_accessibilityListAncestor
421 {
422     for (AccessibilityObject* parent = m_object->parentObject(); parent != nil; parent = parent->parentObject()) {
423         AccessibilityRole role = parent->roleValue();
424         if (role == ListRole || role == ListBoxRole)
425             return parent->wrapper();
426     }
427     
428     return nil;
429 }
430
431 - (AccessibilityObjectWrapper*)_accessibilityLandmarkAncestor
432 {
433     for (AccessibilityObject* parent = m_object->parentObject(); parent != nil; parent = parent->parentObject()) {
434         if ([self _accessibilityIsLandmarkRole:parent->roleValue()])
435             return parent->wrapper();
436     }
437
438     return nil;
439 }
440
441 - (AccessibilityObjectWrapper*)_accessibilityTableAncestor
442 {
443     for (AccessibilityObject* parent = m_object->parentObject(); parent != nil; parent = parent->parentObject()) {
444         if (parent->roleValue() == TableRole)
445             return parent->wrapper();   
446     }
447     
448     return nil;
449 }
450
451 - (uint64_t)_accessibilityTraitsFromAncestors
452 {
453     uint64_t traits = 0;
454     AccessibilityRole role = m_object->roleValue();
455     
456     // Trait information also needs to be gathered from the parents above the object.
457     // The parentObject is needed instead of the unignoredParentObject, because a table might be ignored, but information still needs to be gathered from it.    
458     for (AccessibilityObject* parent = m_object->parentObject(); parent != nil; parent = parent->parentObject()) {
459         AccessibilityRole parentRole = parent->roleValue();
460         if (parentRole == WebAreaRole)
461             break;
462         
463         switch (parentRole) {
464             case LinkRole:
465             case WebCoreLinkRole:
466                 traits |= [self _axLinkTrait];
467                 if (parent->isVisited())
468                     traits |= [self _axVisitedTrait];
469                 break;
470             case HeadingRole:
471             {
472                 traits |= [self _axHeaderTrait];
473                 // If this object has the header trait, we should set the value
474                 // to the heading level. If it was a static text element, we need to store
475                 // the value as the label, because the heading level needs to the value.
476                 AccessibilityObjectWrapper* wrapper = parent->wrapper();
477                 if (role == StaticTextRole) 
478                     [self setAccessibilityLabel:m_object->stringValue()];                
479                 [self setAccessibilityValue:[wrapper accessibilityValue]];
480                 break;
481             }
482             case ListBoxRole:
483             case ListRole:
484                 traits |= [self _axContainedByListTrait];
485                 break;
486             case TableRole:
487                 traits |= [self _axContainedByTableTrait];
488                 break;
489             default:
490                 if ([self _accessibilityIsLandmarkRole:parentRole])
491                     traits |= [self _axContainedByLandmarkTrait];
492                 break;
493         }
494     }
495     
496     return traits;
497 }
498
499 - (uint64_t)accessibilityTraits
500 {
501     if (![self _prepareAccessibilityCall])
502         return 0;
503     
504     AccessibilityRole role = m_object->roleValue();
505     uint64_t traits = [self _axWebContentTrait];
506     switch (role) {
507         case LinkRole:
508         case WebCoreLinkRole:
509             traits |= [self _axLinkTrait];
510             if (m_object->isVisited())
511                 traits |= [self _axVisitedTrait];
512             break;
513         // TextFieldRole is intended to fall through to TextAreaRole, in order to pick up the text entry and text cursor traits.
514         case TextFieldRole:
515             if (m_object->isPasswordField())
516                 traits |= [self _axSecureTextFieldTrait];
517         case TextAreaRole:
518             traits |= [self _axTextEntryTrait];            
519             if (m_object->isFocused())
520                 traits |= ([self _axHasTextCursorTrait] | [self _axTextOperationsAvailableTrait]);
521             break;
522         case ImageRole:
523             traits |= [self _axImageTrait];
524             break;
525         case TabRole:
526             traits |= [self _axTabButtonTrait];
527             break;
528         case ButtonRole:
529             traits |= [self _axButtonTrait];
530             if (m_object->isPressed())
531                 traits |= [self _axToggleTrait];
532             break;
533         case PopUpButtonRole:
534             traits |= [self _axPopupButtonTrait];
535             break;
536         case RadioButtonRole:
537             traits |= [self _axRadioButtonTrait] | [self _axToggleTrait];
538             break;
539         case CheckBoxRole:
540             traits |= ([self _axButtonTrait] | [self _axToggleTrait]);
541             break;
542         case HeadingRole:
543             traits |= [self _axHeaderTrait];
544             break;
545         case StaticTextRole:
546             traits |= [self _axStaticTextTrait];
547             break;
548         case SliderRole:
549             traits |= [self _axAdjustableTrait];
550             break;
551         case MenuButtonRole:
552         case MenuItemRole:
553         case MenuItemCheckboxRole:
554         case MenuItemRadioRole:
555             traits |= [self _axMenuItemTrait];
556             break;
557         default:
558             break;
559     }
560
561     if (m_object->isSelected())
562         traits |= [self _axSelectedTrait];
563
564     if (!m_object->isEnabled())
565         traits |= [self _axNotEnabledTrait];
566     
567     if (m_accessibilityTraitsFromAncestor == ULLONG_MAX)
568         m_accessibilityTraitsFromAncestor = [self _accessibilityTraitsFromAncestors];
569     
570     traits |= m_accessibilityTraitsFromAncestor;
571
572     return traits;
573 }
574
575 - (BOOL)isSVGGroupElement
576 {
577     // If an SVG group element has a title, it should be an accessible element on iOS.
578 #if ENABLE(SVG)
579     Node* node = m_object->node();
580     if (node && node->hasTagName(SVGNames::gTag) && [[self accessibilityLabel] length] > 0)
581         return YES;
582 #endif
583     
584     return NO;
585 }
586
587 - (BOOL)determineIsAccessibilityElement
588 {
589     if (!m_object)
590         return false;
591     
592     // Honor when something explicitly makes this an element (super will contain that logic) 
593     if ([super isAccessibilityElement])
594         return YES;
595     
596     m_object->updateBackingStore();
597     
598     switch (m_object->roleValue()) {
599         case TextFieldRole:
600         case TextAreaRole:
601         case ButtonRole:
602         case PopUpButtonRole:
603         case CheckBoxRole:
604         case RadioButtonRole:
605         case SliderRole:
606         case MenuButtonRole:
607         case ValueIndicatorRole:
608         case ImageRole:
609         case ProgressIndicatorRole:
610         case MenuItemRole:
611         case IncrementorRole:
612         case ComboBoxRole:
613         case DisclosureTriangleRole:
614         case ImageMapRole:
615         case ListMarkerRole:
616         case ListBoxOptionRole:
617         case TabRole:
618         case DocumentMathRole:
619             return true;
620         case StaticTextRole:
621         {
622             // Many text elements only contain a space.
623             if (![[[self accessibilityLabel] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length])
624                 return false;
625
626             // Text elements that are just pieces of links or headers should not be exposed.
627             if ([AccessibilityUnignoredAncestor([self accessibilityContainer]) containsUnnaturallySegmentedChildren])
628                 return false;
629             return true;
630         }
631             
632         // Don't expose headers as elements; instead expose their children as elements, with the header trait (unless they have no children)
633         case HeadingRole:
634             if (![self accessibilityElementCount])
635                 return true;
636             return false;
637             
638         // Links can sometimes be elements (when they only contain static text or don't contain anything).
639         // They should not be elements when containing text and other types.
640         case WebCoreLinkRole:
641         case LinkRole:
642             if ([self containsUnnaturallySegmentedChildren] || ![self accessibilityElementCount])
643                 return true;
644             return false;
645         case GroupRole:
646             if ([self isSVGGroupElement])
647                 return true;
648         // All other elements are ignored on the iphone.
649         default:
650         case UnknownRole:
651         case TabGroupRole:
652         case ScrollAreaRole:
653         case TableRole:
654         case ApplicationRole:
655         case RadioGroupRole:
656         case ListRole:
657         case ListBoxRole:
658         case ScrollBarRole:
659         case MenuBarRole:
660         case MenuRole:
661         case ColumnRole:
662         case RowRole:
663         case ToolbarRole:
664         case BusyIndicatorRole:
665         case WindowRole:
666         case DrawerRole:
667         case SystemWideRole:
668         case OutlineRole:
669         case BrowserRole:
670         case SplitGroupRole:
671         case SplitterRole:
672         case ColorWellRole:
673         case GrowAreaRole:
674         case SheetRole:
675         case HelpTagRole:
676         case MatteRole:
677         case RulerRole:
678         case RulerMarkerRole:
679         case GridRole:
680         case WebAreaRole:
681             return false;
682     }
683 }
684
685 - (BOOL)isAccessibilityElement
686 {
687     if (![self _prepareAccessibilityCall])
688         return NO;
689     
690     if (m_isAccessibilityElement == -1)
691         m_isAccessibilityElement = [self determineIsAccessibilityElement];
692     
693     return m_isAccessibilityElement;
694 }
695
696 - (BOOL)stringValueShouldBeUsedInLabel
697 {
698     if (m_object->isTextControl())
699         return NO;
700     if (m_object->roleValue() == PopUpButtonRole)
701         return NO;
702     if (m_object->isFileUploadButton())
703         return NO;
704
705     return YES;
706 }
707
708 - (BOOL)fileUploadButtonReturnsValueInTitle
709 {
710     return NO;
711 }
712
713 static void appendStringToResult(NSMutableString *result, NSString *string)
714 {
715     ASSERT(result);
716     if (![string length])
717         return;
718     if ([result length])
719         [result appendString:@", "];
720     [result appendString:string];
721 }
722
723 - (CGFloat)_accessibilityMinValue
724 {
725     return m_object->minValueForRange();
726 }
727
728 - (CGFloat)_accessibilityMaxValue
729 {
730     return m_object->maxValueForRange();
731 }
732
733 - (NSString *)accessibilityLabel
734 {
735     if (![self _prepareAccessibilityCall])
736         return nil;
737
738     // check if the label was overriden
739     NSString *label = [super accessibilityLabel];
740     if (label)
741         return label;
742
743     // iOS doesn't distinguish between a title and description field,
744     // so concatentation will yield the best result.
745     NSString *axTitle = [self accessibilityTitle];
746     NSString *axDescription = [self accessibilityDescription];
747     NSString *landmarkDescription = [self ariaLandmarkRoleDescription];
748
749     NSMutableString *result = [NSMutableString string];
750
751     appendStringToResult(result, axTitle);
752     appendStringToResult(result, axDescription);
753     if ([self stringValueShouldBeUsedInLabel]) {
754         NSString *valueLabel = m_object->stringValue();
755         valueLabel = [valueLabel stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
756         appendStringToResult(result, valueLabel);
757     }
758     appendStringToResult(result, landmarkDescription);
759     
760     return [result length] ? result : nil;
761 }
762
763 - (AccessibilityTableCell*)tableCellParent
764 {
765     // Find if this element is in a table cell.
766     AccessibilityObject* cell = 0;
767     for (cell = m_object; cell && !cell->isTableCell(); cell = cell->parentObject()) 
768     { }
769     
770     if (!cell)
771         return 0;
772
773     return static_cast<AccessibilityTableCell*>(cell);
774 }
775
776 - (AccessibilityTable*)tableParent
777 {
778     // Find if the parent table for the table cell.
779     AccessibilityObject* parentTable = 0;
780     for (parentTable = m_object; parentTable && !parentTable->isDataTable(); parentTable = parentTable->parentObject()) 
781     { }
782     
783     if (!parentTable)
784         return 0;
785     
786     return static_cast<AccessibilityTable*>(parentTable);
787 }
788
789 - (id)accessibilityTitleElement
790 {
791     if (![self _prepareAccessibilityCall])
792         return nil;
793
794     AccessibilityObject* titleElement = m_object->titleUIElement();
795     if (titleElement)
796         return titleElement->wrapper();
797
798     return nil;
799 }
800
801 // Meant to return row or column headers (or other things as the future permits).
802 - (NSArray *)accessibilityHeaderElements
803 {
804     if (![self _prepareAccessibilityCall])
805         return nil;
806
807     AccessibilityTableCell* tableCell = [self tableCellParent];
808     if (!tableCell)
809         return nil;
810     
811     AccessibilityTable* table = [self tableParent];
812     if (!table)
813         return nil;
814     
815     // Get the row and column range, so we can use them to find the headers.
816     pair<unsigned, unsigned> rowRange;
817     pair<unsigned, unsigned> columnRange;
818     tableCell->rowIndexRange(rowRange);
819     tableCell->columnIndexRange(columnRange);
820     
821     AccessibilityObject::AccessibilityChildrenVector rowHeaders;
822     AccessibilityObject::AccessibilityChildrenVector columnHeaders;
823     table->rowHeaders(rowHeaders);
824     table->columnHeaders(columnHeaders);
825     
826     NSMutableArray *headers = [NSMutableArray array];
827     
828     unsigned columnRangeIndex = static_cast<unsigned>(columnRange.first);
829     if (columnRangeIndex < columnHeaders.size()) {
830         RefPtr<AccessibilityObject> columnHeader = columnHeaders[columnRange.first];
831         AccessibilityObjectWrapper* wrapper = columnHeader->wrapper();
832         if (wrapper)
833             [headers addObject:wrapper];
834     }
835
836     unsigned rowRangeIndex = static_cast<unsigned>(rowRange.first);
837     if (rowRangeIndex < rowHeaders.size()) {
838         RefPtr<AccessibilityObject> rowHeader = rowHeaders[rowRange.first];
839         AccessibilityObjectWrapper* wrapper = rowHeader->wrapper();
840         if (wrapper)
841             [headers addObject:wrapper];
842     }
843         
844     return headers;
845 }
846
847 - (id)accessibilityElementForRow:(NSInteger)row andColumn:(NSInteger)column
848 {
849     if (![self _prepareAccessibilityCall])
850         return nil;
851
852     AccessibilityTable* table = [self tableParent];
853     if (!table)
854         return nil;
855
856     AccessibilityTableCell* cell = table->cellForColumnAndRow(column, row);
857     if (!cell)
858         return nil;
859     return cell->wrapper();
860 }
861
862 - (NSRange)accessibilityRowRange
863 {
864     if (![self _prepareAccessibilityCall])
865         return NSMakeRange(NSNotFound, 0);
866
867     if (m_object->isRadioButton()) {
868         AccessibilityObject::AccessibilityChildrenVector radioButtonSiblings;
869         m_object->linkedUIElements(radioButtonSiblings);
870         if (radioButtonSiblings.size() <= 1)
871             return NSMakeRange(NSNotFound, 0);
872         
873         return NSMakeRange(radioButtonSiblings.find(m_object), radioButtonSiblings.size());
874     }
875     
876     AccessibilityTableCell* tableCell = [self tableCellParent];
877     if (!tableCell)
878         return NSMakeRange(NSNotFound, 0);
879     
880     pair<unsigned, unsigned> rowRange;
881     tableCell->rowIndexRange(rowRange);
882     return NSMakeRange(rowRange.first, rowRange.second);
883 }
884
885 - (NSRange)accessibilityColumnRange
886 {
887     if (![self _prepareAccessibilityCall])
888         return NSMakeRange(NSNotFound, 0);
889
890     AccessibilityTableCell* tableCell = [self tableCellParent];
891     if (!tableCell)
892         return NSMakeRange(NSNotFound, 0);
893     
894     pair<unsigned, unsigned> columnRange;
895     tableCell->columnIndexRange(columnRange);
896     return NSMakeRange(columnRange.first, columnRange.second);
897 }
898
899 - (NSString *)accessibilityPlaceholderValue
900 {
901     if (![self _prepareAccessibilityCall])
902         return nil;
903
904     return m_object->placeholderValue();
905 }
906
907 - (NSString *)accessibilityValue
908 {
909     if (![self _prepareAccessibilityCall])
910         return nil;
911     
912     // check if the value was overriden
913     NSString *value = [super accessibilityValue];
914     if (value)
915         return value;
916     
917     if (m_object->isCheckboxOrRadio()) {
918         switch (m_object->checkboxOrRadioValue()) {
919         case ButtonStateOff:
920             return [NSString stringWithFormat:@"%d", 0];
921         case ButtonStateOn:
922             return [NSString stringWithFormat:@"%d", 1];
923         case ButtonStateMixed:
924             return [NSString stringWithFormat:@"%d", 2];
925         }
926         ASSERT_NOT_REACHED();
927         return [NSString stringWithFormat:@"%d", 0];
928     }
929     
930     if (m_object->isButton() && m_object->isPressed())
931         return [NSString stringWithFormat:@"%d", 1];
932
933     // rdar://8131388 WebKit should expose the same info as UIKit for its password fields.
934     if (m_object->isPasswordField()) {
935         int passwordLength = m_object->accessibilityPasswordFieldLength();
936         NSMutableString* string = [NSMutableString string];
937         for (int k = 0; k < passwordLength; ++k)
938             [string appendString:@"•"];
939         return string;
940     }
941     
942     // A text control should return its text data as the axValue (per iPhone AX API).
943     if (![self stringValueShouldBeUsedInLabel])
944         return m_object->stringValue();
945     
946     if (m_object->isProgressIndicator() || m_object->isSlider()) {
947         // Prefer a valueDescription if provided by the author (through aria-valuetext).
948         String valueDescription = m_object->valueDescription();
949         if (!valueDescription.isEmpty())
950             return valueDescription;
951
952         return [NSString stringWithFormat:@"%.2f", m_object->valueForRange()];
953     }
954
955     if (m_object->isHeading())
956         return [NSString stringWithFormat:@"%d", m_object->headingLevel()];
957     
958     return nil;
959 }
960
961 - (BOOL)accessibilityIsComboBox
962 {
963     if (![self _prepareAccessibilityCall])
964         return NO;
965
966     return m_object->roleValue() == ComboBoxRole;
967 }
968
969 - (NSString *)accessibilityHint
970 {
971     if (![self _prepareAccessibilityCall])
972         return nil;
973
974     return [self accessibilityHelpText];
975 }
976
977 - (NSURL *)accessibilityURL
978 {
979     if (![self _prepareAccessibilityCall])
980         return nil;
981     
982     URL url = m_object->url();
983     if (url.isNull())
984         return nil;
985     return (NSURL*)url;
986 }
987
988 - (CGPoint)convertPointToScreenSpace:(FloatPoint &)point
989 {
990     if (!m_object)
991         return CGPointZero;
992     
993     CGPoint cgPoint = CGPointMake(point.x(), point.y());
994     
995     FrameView* frameView = m_object->documentFrameView();
996     if (frameView) {
997         WAKView* view = frameView->documentView();
998         cgPoint = [view convertPoint:cgPoint toView:nil];
999     }
1000     
1001     // we need the web document view to give us our final screen coordinates
1002     // because that can take account of the scroller
1003     id webDocument = [self _accessibilityWebDocumentView];
1004     if (webDocument)
1005         cgPoint = [webDocument convertPoint:cgPoint toView:nil];
1006     
1007     return cgPoint;
1008 }
1009
1010 - (CGRect)convertRectToScreenSpace:(IntRect &)rect
1011 {
1012     if (!m_object)
1013         return CGRectZero;
1014     
1015     CGSize size = CGSizeMake(rect.size().width(), rect.size().height());
1016     CGPoint point = CGPointMake(rect.x(), rect.y());
1017     
1018     CGRect frame = CGRectMake(point.x, point.y, size.width, size.height);
1019     
1020     FrameView* frameView = m_object->documentFrameView();
1021     if (frameView) {
1022         WAKView* view = frameView->documentView();
1023         frame = [view convertRect:frame toView:nil];
1024     }
1025     
1026     // we need the web document view to give us our final screen coordinates
1027     // because that can take account of the scroller
1028     id webDocument = [self _accessibilityWebDocumentView];
1029     if (webDocument)
1030         frame = [webDocument convertRect:frame toView:nil];
1031     
1032     return frame;
1033 }
1034
1035 // Used by UIKit accessibility bundle to help determine distance during a hit-test.
1036 - (CGRect)accessibilityElementRect
1037 {
1038     if (![self _prepareAccessibilityCall])
1039         return CGRectZero;
1040     
1041     LayoutRect rect = m_object->elementRect();
1042     return CGRectMake(rect.x(), rect.y(), rect.width(), rect.height());
1043 }
1044
1045 // The "center point" is where VoiceOver will "press" an object. This may not be the actual
1046 // center of the accessibilityFrame
1047 - (CGPoint)accessibilityActivationPoint
1048 {
1049     if (![self _prepareAccessibilityCall])
1050         return CGPointZero;
1051     
1052     IntRect rect = pixelSnappedIntRect(m_object->boundingBoxRect());
1053     CGRect cgRect = [self convertRectToScreenSpace:rect];
1054     return CGPointMake(CGRectGetMidX(cgRect), CGRectGetMidY(cgRect));
1055 }
1056
1057 - (CGRect)accessibilityFrame
1058 {
1059     if (![self _prepareAccessibilityCall])
1060         return CGRectZero;
1061     
1062     IntRect rect = pixelSnappedIntRect(m_object->elementRect());
1063     return [self convertRectToScreenSpace:rect];
1064 }
1065
1066 // Checks whether a link contains only static text and images (and has been divided unnaturally by <spans> and other nefarious mechanisms).
1067 - (BOOL)containsUnnaturallySegmentedChildren
1068 {
1069     if (!m_object)
1070         return NO;
1071     
1072     AccessibilityRole role = m_object->roleValue();
1073     if (role != LinkRole && role != WebCoreLinkRole)
1074         return NO;
1075     
1076     AccessibilityObject::AccessibilityChildrenVector children = m_object->children();
1077     unsigned childrenSize = children.size();
1078
1079     // If there's only one child, then it doesn't have segmented children. 
1080     if (childrenSize == 1)
1081         return NO;
1082     
1083     for (unsigned i = 0; i < childrenSize; ++i) {
1084         AccessibilityRole role = children[i]->roleValue();
1085         if (role != StaticTextRole && role != ImageRole && role != GroupRole)
1086             return NO;
1087     }
1088     
1089     return YES;
1090 }
1091
1092 - (id)accessibilityContainer
1093 {
1094     if (![self _prepareAccessibilityCall])
1095         return nil;
1096
1097     AXAttributeCacheEnabler enableCache(m_object->axObjectCache());
1098     
1099     // As long as there's a parent wrapper, that's the correct chain to climb.
1100     AccessibilityObject* parent = m_object->parentObjectUnignored(); 
1101     if (parent)
1102         return parent->wrapper();
1103
1104     // The only object without a parent wrapper should be a scroll view.
1105     ASSERT(m_object->isAccessibilityScrollView());
1106     
1107     // Verify this is the top document. If not, we might need to go through the platform widget.
1108     FrameView* frameView = m_object->documentFrameView();
1109     Document* document = m_object->document();
1110     if (document && frameView && document != document->topDocument())
1111         return frameView->platformWidget();
1112     
1113     // The top scroll view's parent is the web document view.
1114     return [self _accessibilityWebDocumentView];
1115 }
1116
1117 - (id)accessibilityFocusedUIElement
1118 {
1119     if (![self _prepareAccessibilityCall])
1120         return nil;
1121     
1122     AccessibilityObject* focusedObj = m_object->focusedUIElement();
1123     
1124     if (!focusedObj)
1125         return nil;
1126     
1127     return focusedObj->wrapper();
1128 }
1129
1130 - (id)_accessibilityWebDocumentView
1131 {
1132     if (![self _prepareAccessibilityCall])
1133         return nil;
1134
1135     // This method performs the crucial task of connecting to the UIWebDocumentView.
1136     // This is needed to correctly calculate the screen position of the AX object.
1137     static Class webViewClass = nil;
1138     if (!webViewClass)
1139         webViewClass = NSClassFromString(@"WebView");
1140
1141     if (!webViewClass)
1142         return nil;
1143     
1144     FrameView* frameView = m_object->documentFrameView();
1145
1146     if (!frameView)
1147         return nil;
1148     
1149     // If this is the top level frame, the UIWebDocumentView should be returned.
1150     id parentView = frameView->documentView();
1151     while (parentView && ![parentView isKindOfClass:webViewClass])
1152         parentView = [parentView superview];
1153     
1154     // The parentView should have an accessibilityContainer, if the UIKit accessibility bundle was loaded. 
1155     // The exception is DRT, which tests accessibility without the entire system turning accessibility on. Hence,
1156     // this check should be valid for everything except DRT.
1157     ASSERT([parentView accessibilityContainer] || applicationIsDumpRenderTree());
1158     
1159     return [parentView accessibilityContainer];
1160 }
1161
1162 - (NSArray *)_accessibilityNextElementsWithCount:(UInt32)count
1163 {    
1164     if (![self _prepareAccessibilityCall])
1165         return nil;
1166     
1167     return [[self _accessibilityWebDocumentView] _accessibilityNextElementsWithCount:count];
1168 }
1169
1170 - (NSArray *)_accessibilityPreviousElementsWithCount:(UInt32)count
1171 {
1172     if (![self _prepareAccessibilityCall])
1173         return nil;
1174     
1175     return [[self _accessibilityWebDocumentView] _accessibilityPreviousElementsWithCount:count];
1176 }
1177
1178 - (BOOL)accessibilityRequired
1179 {
1180     if (![self _prepareAccessibilityCall])
1181         return NO;
1182
1183     return m_object->isRequired();
1184 }
1185
1186 - (NSArray *)accessibilityFlowToElements
1187 {
1188     if (![self _prepareAccessibilityCall])
1189         return nil;
1190     
1191     AccessibilityObject::AccessibilityChildrenVector children;
1192     m_object->ariaFlowToElements(children);
1193     
1194     unsigned length = children.size();
1195     NSMutableArray* array = [NSMutableArray arrayWithCapacity:length];
1196     for (unsigned i = 0; i < length; ++i) {
1197         AccessibilityObjectWrapper* wrapper = children[i]->wrapper();
1198         ASSERT(wrapper);
1199         if (!wrapper)
1200             continue;
1201
1202         if (children[i]->isAttachment() && [wrapper attachmentView])
1203             [array addObject:[wrapper attachmentView]];
1204         else
1205             [array addObject:wrapper];
1206     }
1207     return array;
1208 }
1209
1210 - (id)accessibilityLinkedElement
1211 {
1212     if (![self _prepareAccessibilityCall])
1213         return nil;
1214     
1215     // If this static text inside of a link, it should use its parent's linked element.
1216     AccessibilityObject* element = m_object;
1217     if (m_object->roleValue() == StaticTextRole && m_object->parentObjectUnignored()->isLink())
1218         element = m_object->parentObjectUnignored();
1219     
1220     AccessibilityObject::AccessibilityChildrenVector children;
1221     element->linkedUIElements(children);
1222     if (children.size() == 0)
1223         return nil;
1224     
1225     return children[0]->wrapper();
1226 }
1227
1228
1229 - (BOOL)isAttachment
1230 {
1231     if (!m_object)
1232         return NO;
1233     
1234     return m_object->isAttachment();
1235 }
1236
1237 - (void)_accessibilityActivate
1238 {
1239     if (![self _prepareAccessibilityCall])
1240         return;
1241
1242     m_object->press();
1243 }
1244
1245 - (id)attachmentView
1246 {
1247     if (![self _prepareAccessibilityCall])
1248         return nil;
1249
1250     ASSERT([self isAttachment]);
1251     Widget* widget = m_object->widgetForAttachmentView();
1252     if (!widget)
1253         return nil;
1254     return widget->platformWidget();    
1255 }
1256
1257 static RenderObject* rendererForView(WAKView* view)
1258 {
1259     if (![view conformsToProtocol:@protocol(WebCoreFrameView)])
1260         return 0;
1261     
1262     WAKView<WebCoreFrameView>* frameView = (WAKView<WebCoreFrameView>*)view;
1263     Frame* frame = [frameView _web_frame];
1264     if (!frame)
1265         return 0;
1266     
1267     Node* node = frame->document()->ownerElement();
1268     if (!node)
1269         return 0;
1270     
1271     return node->renderer();
1272 }
1273
1274 - (id)_accessibilityParentForSubview:(id)subview
1275 {   
1276     RenderObject* renderer = rendererForView(subview);
1277     if (!renderer)
1278         return nil;
1279     
1280     AccessibilityObject* obj = renderer->document().axObjectCache()->getOrCreate(renderer);
1281     if (obj)
1282         return obj->parentObjectUnignored()->wrapper();
1283     return nil;
1284 }
1285
1286 - (void)postFocusChangeNotification
1287 {
1288     // The UIKit accessibility wrapper will override and post appropriate notification.
1289 }
1290
1291 - (void)postSelectedTextChangeNotification
1292 {
1293     // The UIKit accessibility wrapper will override and post appropriate notification.    
1294 }
1295
1296 - (void)postLayoutChangeNotification
1297 {
1298     // The UIKit accessibility wrapper will override and post appropriate notification.        
1299 }
1300
1301 - (void)postLiveRegionChangeNotification
1302 {
1303     // The UIKit accessibility wrapper will override and post appropriate notification.    
1304 }
1305
1306 - (void)postLoadCompleteNotification
1307 {
1308     // The UIKit accessibility wrapper will override and post appropriate notification.    
1309 }
1310
1311 - (void)postChildrenChangedNotification
1312 {
1313     // The UIKit accessibility wrapper will override and post appropriate notification.    
1314 }
1315
1316 - (void)postInvalidStatusChangedNotification
1317 {
1318     // The UIKit accessibility wrapper will override and post appropriate notification.        
1319 }
1320
1321 - (void)accessibilityElementDidBecomeFocused
1322 {
1323     if (![self _prepareAccessibilityCall])
1324         return;
1325     
1326     // The focused VoiceOver element might be the text inside a link.
1327     // In those cases we should focus on the link itself.
1328     for (AccessibilityObject* object = m_object; object != nil; object = object->parentObject()) {
1329         if (object->roleValue() == WebAreaRole)
1330             break;
1331
1332         if (object->canSetFocusAttribute()) {
1333             object->setFocused(true);
1334             break;
1335         }
1336     }
1337 }
1338
1339 - (void)accessibilityModifySelection:(TextGranularity)granularity increase:(BOOL)increase
1340 {
1341     if (![self _prepareAccessibilityCall])
1342         return;
1343     
1344     FrameSelection& frameSelection = m_object->document()->frame()->selection();
1345     VisibleSelection selection = m_object->selection();
1346     VisiblePositionRange range = m_object->visiblePositionRange();
1347     
1348     // Before a selection with length exists, the cursor position needs to move to the right starting place.
1349     // That should be the beginning of this element (range.start). However, if the cursor is already within the 
1350     // range of this element (the cursor is represented by selection), then the cursor does not need to move.
1351     if (frameSelection.isNone() && (selection.visibleStart() < range.start || selection.visibleEnd() > range.end))
1352         frameSelection.moveTo(range.start, UserTriggered);
1353     
1354     frameSelection.modify(FrameSelection::AlterationExtend, (increase) ? DirectionRight : DirectionLeft, granularity, UserTriggered);
1355 }
1356
1357 - (void)accessibilityIncreaseSelection:(TextGranularity)granularity
1358 {
1359     [self accessibilityModifySelection:granularity increase:YES];
1360 }
1361
1362 - (void)accessibilityDecreaseSelection:(TextGranularity)granularity
1363 {
1364     [self accessibilityModifySelection:granularity increase:NO];
1365 }
1366
1367 - (void)accessibilityMoveSelectionToMarker:(WebAccessibilityTextMarker *)marker
1368 {
1369     if (![self _prepareAccessibilityCall])
1370         return;
1371     
1372     VisiblePosition visiblePosition = [marker visiblePosition];
1373     if (visiblePosition.isNull())
1374         return;
1375
1376     FrameSelection& frameSelection = m_object->document()->frame()->selection();
1377     frameSelection.moveTo(visiblePosition, UserTriggered);
1378 }
1379
1380 - (void)accessibilityIncrement
1381 {
1382     if (![self _prepareAccessibilityCall])
1383         return;
1384
1385     m_object->increment();
1386 }
1387
1388 - (void)accessibilityDecrement
1389 {
1390     if (![self _prepareAccessibilityCall])
1391         return;
1392
1393     m_object->decrement();
1394 }
1395
1396 #pragma mark Accessibility Text Marker Handlers
1397
1398 - (BOOL)_addAccessibilityObject:(AccessibilityObject*)axObject toTextMarkerArray:(NSMutableArray *)array
1399 {
1400     if (!axObject)
1401         return NO;
1402     
1403     AccessibilityObjectWrapper* wrapper = axObject->wrapper();
1404     if (!wrapper)
1405         return NO;
1406
1407     // Don't add the same object twice, but since this has already been added, we should return
1408     // YES because we want to inform that it's in the array
1409     if ([array containsObject:wrapper])
1410         return YES;
1411     
1412     // Explicity set that this is now an element (in case other logic tries to override).
1413     [wrapper setValue:[NSNumber numberWithBool:YES] forKey:@"isAccessibilityElement"];    
1414     [array addObject:wrapper];
1415     return YES;
1416 }
1417
1418 - (NSString *)stringForTextMarkers:(NSArray *)markers
1419 {
1420     if (![self _prepareAccessibilityCall])
1421         return nil;
1422     
1423     if ([markers count] != 2)
1424         return nil;
1425     
1426     WebAccessibilityTextMarker* startMarker = [markers objectAtIndex:0];
1427     WebAccessibilityTextMarker* endMarker = [markers objectAtIndex:1];
1428     if (![startMarker isKindOfClass:[WebAccessibilityTextMarker class]] || ![endMarker isKindOfClass:[WebAccessibilityTextMarker class]])
1429         return nil;
1430     
1431     // extract the start and end VisiblePosition
1432     VisiblePosition startVisiblePosition = [startMarker visiblePosition];
1433     if (startVisiblePosition.isNull())
1434         return nil;
1435     
1436     VisiblePosition endVisiblePosition = [endMarker visiblePosition];
1437     if (endVisiblePosition.isNull())
1438         return nil;
1439
1440     VisiblePositionRange visiblePosRange = VisiblePositionRange(startVisiblePosition, endVisiblePosition);
1441     return m_object->stringForVisiblePositionRange(visiblePosRange);
1442 }
1443
1444 static int blockquoteLevel(RenderObject* renderer)
1445 {
1446     if (!renderer)
1447         return 0;
1448     
1449     int result = 0;
1450     for (Node* node = renderer->node(); node; node = node->parentNode()) {
1451         if (node->hasTagName(blockquoteTag))
1452             result += 1;
1453     }
1454     
1455     return result;
1456 }
1457
1458 static void AXAttributeStringSetBlockquoteLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
1459 {
1460     int quoteLevel = blockquoteLevel(renderer);
1461     
1462     if (quoteLevel)
1463         [attrString addAttribute:UIAccessibilityTokenBlockquoteLevel value:[NSNumber numberWithInt:quoteLevel] range:range];
1464     else
1465         [attrString removeAttribute:UIAccessibilityTokenBlockquoteLevel range:range];
1466 }
1467
1468 static void AXAttributeStringSetHeadingLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
1469 {
1470     if (!renderer)
1471         return;
1472     
1473     AccessibilityObject* parentObject = renderer->document().axObjectCache()->getOrCreate(renderer->parent());
1474     int parentHeadingLevel = parentObject->headingLevel();
1475     
1476     if (parentHeadingLevel)
1477         [attrString addAttribute:UIAccessibilityTokenHeadingLevel value:[NSNumber numberWithInt:parentHeadingLevel] range:range];
1478     else
1479         [attrString removeAttribute:UIAccessibilityTokenHeadingLevel range:range];
1480 }
1481
1482 static void AXAttributeStringSetFont(NSMutableAttributedString* attrString, GSFontRef font, NSRange range)
1483 {
1484     if (!font)
1485         return;
1486     
1487     const char* nameCStr = GSFontGetFullName(font);
1488     const char* familyCStr = GSFontGetFamilyName(font);
1489     NSNumber* size = [NSNumber numberWithFloat:GSFontGetSize(font)];
1490     NSNumber* bold = [NSNumber numberWithBool:GSFontIsBold(font)];
1491     GSFontTraitMask traits = GSFontGetTraits(font);
1492     if (nameCStr)
1493         [attrString addAttribute:UIAccessibilityTokenFontName value:[NSString stringWithUTF8String:nameCStr] range:range];
1494     if (familyCStr)
1495         [attrString addAttribute:UIAccessibilityTokenFontFamily value:[NSString stringWithUTF8String:familyCStr] range:range];
1496     if ([size boolValue])
1497         [attrString addAttribute:UIAccessibilityTokenFontSize value:size range:range];
1498     if ([bold boolValue] || (traits & GSBoldFontMask))
1499         [attrString addAttribute:UIAccessibilityTokenBold value:[NSNumber numberWithBool:YES] range:range];
1500     if (traits & GSItalicFontMask)
1501         [attrString addAttribute:UIAccessibilityTokenItalic value:[NSNumber numberWithBool:YES] range:range];
1502
1503 }
1504
1505 static void AXAttributeStringSetNumber(NSMutableAttributedString* attrString, NSString* attribute, NSNumber* number, NSRange range)
1506 {
1507     if (number)
1508         [attrString addAttribute:attribute value:number range:range];
1509     else
1510         [attrString removeAttribute:attribute range:range];
1511 }
1512
1513 static void AXAttributeStringSetStyle(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
1514 {
1515     RenderStyle* style = renderer->style();
1516     
1517     // set basic font info
1518     AXAttributeStringSetFont(attrString, style->font().primaryFont()->getGSFont(), range);
1519                 
1520     int decor = style->textDecorationsInEffect();
1521     if ((decor & (TextDecorationUnderline | TextDecorationLineThrough)) != 0) {
1522         // find colors using quirk mode approach (strict mode would use current
1523         // color for all but the root line box, which would use getTextDecorationColors)
1524         Color underline, overline, linethrough;
1525         renderer->getTextDecorationColors(decor, underline, overline, linethrough);
1526         
1527         if (decor & TextDecorationUnderline)
1528             AXAttributeStringSetNumber(attrString, UIAccessibilityTokenUnderline, [NSNumber numberWithBool:YES], range);
1529     }
1530 }
1531
1532 static void AXAttributedStringAppendText(NSMutableAttributedString* attrString, Node* node, const UChar* chars, int length)
1533 {
1534     // skip invisible text
1535     if (!node->renderer())
1536         return;
1537     
1538     // easier to calculate the range before appending the string
1539     NSRange attrStringRange = NSMakeRange([attrString length], length);
1540     
1541     // append the string from this node
1542     [[attrString mutableString] appendString:[NSString stringWithCharacters:chars length:length]];
1543     
1544     // set new attributes
1545     AXAttributeStringSetStyle(attrString, node->renderer(), attrStringRange);
1546     AXAttributeStringSetHeadingLevel(attrString, node->renderer(), attrStringRange);
1547     AXAttributeStringSetBlockquoteLevel(attrString, node->renderer(), attrStringRange);    
1548 }
1549
1550
1551 // This method is intended to return an array of strings and accessibility elements that 
1552 // represent the objects on one line of rendered web content. The array of markers sent
1553 // in should be ordered and contain only a start and end marker.
1554 - (NSArray *)arrayOfTextForTextMarkers:(NSArray *)markers attributed:(BOOL)attributed
1555 {
1556     if (![self _prepareAccessibilityCall])
1557         return nil;
1558
1559     if ([markers count] != 2)
1560         return nil;
1561     
1562     WebAccessibilityTextMarker* startMarker = [markers objectAtIndex:0];
1563     WebAccessibilityTextMarker* endMarker = [markers objectAtIndex:1];
1564     if (![startMarker isKindOfClass:[WebAccessibilityTextMarker class]] || ![endMarker isKindOfClass:[WebAccessibilityTextMarker class]])
1565         return nil;
1566     
1567     // extract the start and end VisiblePosition
1568     VisiblePosition startVisiblePosition = [startMarker visiblePosition];
1569     if (startVisiblePosition.isNull())
1570         return nil;
1571     
1572     VisiblePosition endVisiblePosition = [endMarker visiblePosition];
1573     if (endVisiblePosition.isNull())
1574         return nil;
1575     
1576     // iterate over the range to build the AX attributed string
1577     NSMutableArray* array = [[NSMutableArray alloc] init];
1578     TextIterator it(makeRange(startVisiblePosition, endVisiblePosition).get());
1579     for (; !it.atEnd(); it.advance()) {
1580         // locate the node and starting offset for this range
1581         int exception = 0;
1582         Node* node = it.range()->startContainer(exception);
1583         ASSERT(node == it.range()->endContainer(exception));
1584         int offset = it.range()->startOffset(exception);
1585         
1586         // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
1587         if (it.length() != 0) {
1588             if (!attributed) {
1589                 // First check if this is represented by a link.
1590                 AccessibilityObject* linkObject = AccessibilityObject::anchorElementForNode(node);
1591                 if ([self _addAccessibilityObject:linkObject toTextMarkerArray:array])
1592                     continue;
1593                 
1594                 // Next check if this region is represented by a heading.
1595                 AccessibilityObject* headingObject = AccessibilityObject::headingElementForNode(node);
1596                 if ([self _addAccessibilityObject:headingObject toTextMarkerArray:array])
1597                     continue;
1598                 
1599                 String listMarkerText = m_object->listMarkerTextForNodeAndPosition(node, VisiblePosition(it.range()->startPosition())); 
1600                 
1601                 if (!listMarkerText.isEmpty()) 
1602                     [array addObject:[NSString stringWithCharacters:listMarkerText.characters() length:listMarkerText.length()]];
1603                 // There was not an element representation, so just return the text.
1604                 [array addObject:[NSString stringWithCharacters:it.characters() length:it.length()]];
1605             }
1606             else
1607             {
1608                 String listMarkerText = m_object->listMarkerTextForNodeAndPosition(node, VisiblePosition(it.range()->startPosition())); 
1609
1610                 if (!listMarkerText.isEmpty()) {
1611                     NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] init];
1612                     AXAttributedStringAppendText(attrString, node, listMarkerText.characters(), listMarkerText.length());
1613                     [array addObject:attrString];
1614                     [attrString release];
1615                 }
1616                 
1617                 NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] init];
1618                 AXAttributedStringAppendText(attrString, node, it.characters(), it.length());
1619                 [array addObject:attrString];
1620                 [attrString release];
1621             }
1622         } else {
1623             Node* replacedNode = node->childNode(offset);
1624             if (replacedNode) {
1625                 AccessibilityObject* obj = m_object->axObjectCache()->getOrCreate(replacedNode->renderer());
1626                 if (obj && !obj->accessibilityIsIgnored())
1627                     [self _addAccessibilityObject:obj toTextMarkerArray:array];
1628             }
1629         }
1630     }
1631     
1632     return [array autorelease];
1633 }
1634
1635 - (NSRange)_convertToNSRange:(Range *)range
1636 {
1637     if (!range || !range->startContainer())
1638         return NSMakeRange(NSNotFound, 0);
1639     
1640     Document* document = m_object->document();
1641     FrameSelection& frameSelection = document->frame()->selection();
1642     
1643     Element* selectionRoot = frameSelection.rootEditableElement();
1644     Element* scope = selectionRoot ? selectionRoot : document->documentElement();
1645     
1646     // Mouse events may cause TSM to attempt to create an NSRange for a portion of the view
1647     // that is not inside the current editable region.  These checks ensure we don't produce
1648     // potentially invalid data when responding to such requests.
1649     if (range->startContainer() != scope && !range->startContainer()->isDescendantOf(scope))
1650         return NSMakeRange(NSNotFound, 0);
1651     if (range->endContainer() != scope && !range->endContainer()->isDescendantOf(scope))
1652         return NSMakeRange(NSNotFound, 0);
1653     
1654     RefPtr<Range> testRange = Range::create(&scope->document(), scope, 0, range->startContainer(), range->startOffset());
1655     ASSERT(testRange->startContainer() == scope);
1656     int startPosition = TextIterator::rangeLength(testRange.get());
1657     
1658     ExceptionCode ec;
1659     testRange->setEnd(range->endContainer(), range->endOffset(), ec);
1660     ASSERT(testRange->startContainer() == scope);
1661     int endPosition = TextIterator::rangeLength(testRange.get());
1662     return NSMakeRange(startPosition, endPosition - startPosition);
1663 }
1664
1665 - (PassRefPtr<Range>)_convertToDOMRange:(NSRange)nsrange
1666 {
1667     if (nsrange.location > INT_MAX)
1668         return 0;
1669     if (nsrange.length > INT_MAX || nsrange.location + nsrange.length > INT_MAX)
1670         nsrange.length = INT_MAX - nsrange.location;
1671         
1672     // our critical assumption is that we are only called by input methods that
1673     // concentrate on a given area containing the selection
1674     // We have to do this because of text fields and textareas. The DOM for those is not
1675     // directly in the document DOM, so serialization is problematic. Our solution is
1676     // to use the root editable element of the selection start as the positional base.
1677     // That fits with AppKit's idea of an input context.
1678     Document* document = m_object->document();
1679     FrameSelection& frameSelection = document->frame()->selection();
1680     Element* selectionRoot = frameSelection.rootEditableElement();
1681     Element* scope = selectionRoot ? selectionRoot : document->documentElement();
1682     return TextIterator::rangeFromLocationAndLength(scope, nsrange.location, nsrange.length);
1683 }
1684
1685 // This method is intended to take a text marker representing a VisiblePosition and convert it
1686 // into a normalized location within the document.
1687 - (NSInteger)positionForTextMarker:(WebAccessibilityTextMarker *)marker
1688 {
1689     if (![self _prepareAccessibilityCall])
1690         return NSNotFound;
1691
1692     if (!marker)
1693         return NSNotFound;    
1694
1695     VisibleSelection selection([marker visiblePosition]);
1696     RefPtr<Range> range = selection.toNormalizedRange();
1697     NSRange nsRange = [self _convertToNSRange:range.get()];
1698     return nsRange.location;
1699 }
1700
1701 - (NSArray *)textMarkerRange
1702 {
1703     if (![self _prepareAccessibilityCall])
1704         return nil;
1705     
1706     VisiblePositionRange range = m_object->visiblePositionRange();
1707     VisiblePosition startPosition = range.start;
1708     VisiblePosition endPosition = range.end;
1709     WebAccessibilityTextMarker* start = [WebAccessibilityTextMarker textMarkerWithVisiblePosition:startPosition cache:m_object->axObjectCache()];
1710     WebAccessibilityTextMarker* end = [WebAccessibilityTextMarker textMarkerWithVisiblePosition:endPosition cache:m_object->axObjectCache()];
1711     
1712     return [NSArray arrayWithObjects:start, end, nil];
1713 }
1714
1715 // A method to get the normalized text cursor range of an element. Used in DumpRenderTree.
1716 - (NSRange)elementTextRange
1717 {
1718     if (![self _prepareAccessibilityCall])
1719         return NSMakeRange(NSNotFound, 0);
1720
1721     NSArray *markers = [self textMarkerRange];
1722     if ([markers count] != 2)
1723         return NSMakeRange(NSNotFound, 0);
1724     
1725     WebAccessibilityTextMarker *startMarker = [markers objectAtIndex:0];
1726     WebAccessibilityTextMarker *endMarker = [markers objectAtIndex:1];
1727     
1728     NSInteger startPosition = [self positionForTextMarker:startMarker];
1729     NSInteger endPosition = [self positionForTextMarker:endMarker];
1730     
1731     return NSMakeRange(startPosition, endPosition - startPosition);
1732 }
1733
1734 - (AccessibilityObjectWrapper *)accessibilityObjectForTextMarker:(WebAccessibilityTextMarker *)marker
1735 {
1736     if (![self _prepareAccessibilityCall])
1737         return nil;
1738
1739     if (!marker)
1740         return nil;
1741     
1742     VisiblePosition visiblePosition = [marker visiblePosition];
1743     AccessibilityObject* obj = m_object->accessibilityObjectForPosition(visiblePosition);
1744     if (!obj)
1745         return nil;
1746     
1747     return AccessibilityUnignoredAncestor(obj->wrapper());
1748 }
1749
1750 - (NSArray *)textMarkerRangeForSelection
1751 {
1752     if (![self _prepareAccessibilityCall])
1753         return nil;
1754     
1755     VisibleSelection selection = m_object->selection();
1756     if (selection.isNone())
1757         return nil;
1758     VisiblePosition startPosition = selection.visibleStart();
1759     VisiblePosition endPosition = selection.visibleEnd();
1760
1761     WebAccessibilityTextMarker* startMarker = [WebAccessibilityTextMarker textMarkerWithVisiblePosition:startPosition cache:m_object->axObjectCache()];
1762     WebAccessibilityTextMarker* endMarker = [WebAccessibilityTextMarker textMarkerWithVisiblePosition:endPosition cache:m_object->axObjectCache()];
1763     if (!startMarker || !endMarker)
1764         return nil;
1765     
1766     return [NSArray arrayWithObjects:startMarker, endMarker, nil];
1767 }
1768
1769 - (WebAccessibilityTextMarker *)textMarkerForPosition:(NSInteger)position
1770 {
1771     if (![self _prepareAccessibilityCall])
1772         return nil;
1773
1774     PassRefPtr<Range> range = [self _convertToDOMRange:NSMakeRange(position, 0)];
1775     if (!range)
1776         return nil;
1777     
1778     VisibleSelection selection = VisibleSelection(range.get(), DOWNSTREAM);
1779
1780     VisiblePosition visiblePosition = selection.visibleStart();
1781     return [WebAccessibilityTextMarker textMarkerWithVisiblePosition:visiblePosition cache:m_object->axObjectCache()];
1782 }
1783
1784 - (id)_stringForRange:(NSRange)range attributed:(BOOL)attributed
1785 {
1786     if (![self _prepareAccessibilityCall])
1787         return nil;
1788     
1789     WebAccessibilityTextMarker* startMarker = [self textMarkerForPosition:range.location];
1790     WebAccessibilityTextMarker* endMarker = [self textMarkerForPosition:NSMaxRange(range)];
1791     
1792     // Clients don't always know the exact range, rather than force them to compute it,
1793     // allow clients to overshoot and use the max text marker range.
1794     if (!startMarker || !endMarker) {
1795         NSArray *markers = [self textMarkerRange];
1796         if ([markers count] != 2)
1797             return nil;
1798         if (!startMarker)
1799             startMarker = [markers objectAtIndex:0];
1800         if (!endMarker)
1801             endMarker = [markers objectAtIndex:1];
1802     }
1803     
1804     NSArray* array = [self arrayOfTextForTextMarkers:[NSArray arrayWithObjects:startMarker, endMarker, nil] attributed:attributed];
1805     Class returnClass = attributed ? [NSMutableAttributedString class] : [NSMutableString class];
1806     id returnValue = [[[returnClass alloc] init] autorelease];
1807     
1808     NSInteger count = [array count];
1809     for (NSInteger k = 0; k < count; ++k) {
1810         id object = [array objectAtIndex:k];
1811
1812         if (![object isKindOfClass:returnClass])
1813             continue;
1814         
1815         if (attributed)
1816             [(NSMutableAttributedString *)returnValue appendAttributedString:object];
1817         else
1818             [(NSMutableString *)returnValue appendString:object];
1819     }
1820     return returnValue;
1821 }
1822
1823
1824 // A convenience method for getting the text of a NSRange. Currently used only by DRT.
1825 - (NSString *)stringForRange:(NSRange)range
1826 {
1827     return [self _stringForRange:range attributed:NO];
1828 }
1829
1830 - (NSAttributedString *)attributedStringForRange:(NSRange)range
1831 {
1832     return [self _stringForRange:range attributed:YES];
1833 }
1834
1835 // A convenience method for getting the accessibility objects of a NSRange. Currently used only by DRT.
1836 - (NSArray *)elementsForRange:(NSRange)range
1837 {
1838     if (![self _prepareAccessibilityCall])
1839         return nil;
1840     
1841     WebAccessibilityTextMarker* startMarker = [self textMarkerForPosition:range.location];
1842     WebAccessibilityTextMarker* endMarker = [self textMarkerForPosition:NSMaxRange(range)];
1843     if (!startMarker || !endMarker)
1844         return nil;
1845     
1846     NSArray* array = [self arrayOfTextForTextMarkers:[NSArray arrayWithObjects:startMarker, endMarker, nil] attributed:NO];
1847     NSMutableArray* elements = [NSMutableArray array];
1848     for (id element in array) {
1849         if (![element isKindOfClass:[AccessibilityObjectWrapper class]])
1850             continue;
1851         [elements addObject:element];
1852     }
1853     return elements;
1854 }
1855
1856 - (NSString *)selectionRangeString
1857 {
1858     NSArray *markers = [self textMarkerRangeForSelection];
1859     return [self stringForTextMarkers:markers];
1860 }
1861
1862 - (WebAccessibilityTextMarker *)selectedTextMarker
1863 {
1864     if (![self _prepareAccessibilityCall])
1865         return nil;
1866     
1867     VisibleSelection selection = m_object->selection();
1868     VisiblePosition position = selection.visibleStart();
1869     
1870     // if there's no selection, start at the top of the document
1871     if (position.isNull())
1872         position = startOfDocument(m_object->document());
1873     
1874     return [WebAccessibilityTextMarker textMarkerWithVisiblePosition:position cache:m_object->axObjectCache()];
1875 }
1876
1877 // This method is intended to return the marker at the end of the line starting at
1878 // the marker that is passed into the method.
1879 - (WebAccessibilityTextMarker *)lineEndMarkerForMarker:(WebAccessibilityTextMarker *)marker
1880 {
1881     if (![self _prepareAccessibilityCall])
1882         return nil;
1883
1884     if (!marker)
1885         return nil;
1886     
1887     VisiblePosition start = [marker visiblePosition];
1888     VisiblePosition lineEnd = m_object->nextLineEndPosition(start);
1889     
1890     return [WebAccessibilityTextMarker textMarkerWithVisiblePosition:lineEnd cache:m_object->axObjectCache()];
1891 }
1892
1893 // This method is intended to return the marker at the start of the line starting at
1894 // the marker that is passed into the method.
1895 - (WebAccessibilityTextMarker *)lineStartMarkerForMarker:(WebAccessibilityTextMarker *)marker
1896 {
1897     if (![self _prepareAccessibilityCall])
1898         return nil;
1899
1900     if (!marker)
1901         return nil;
1902     
1903     VisiblePosition start = [marker visiblePosition];
1904     VisiblePosition lineStart = m_object->previousLineStartPosition(start);
1905     
1906     return [WebAccessibilityTextMarker textMarkerWithVisiblePosition:lineStart cache:m_object->axObjectCache()];
1907 }
1908
1909 - (WebAccessibilityTextMarker *)nextMarkerForMarker:(WebAccessibilityTextMarker *)marker
1910 {
1911     if (![self _prepareAccessibilityCall])
1912         return nil;
1913
1914     if (!marker)
1915         return nil;
1916     
1917     VisiblePosition start = [marker visiblePosition];
1918     VisiblePosition nextMarker = m_object->nextVisiblePosition(start);
1919     
1920     return [WebAccessibilityTextMarker textMarkerWithVisiblePosition:nextMarker cache:m_object->axObjectCache()];
1921 }
1922
1923 // This method is intended to return the marker at the start of the line starting at
1924 // the marker that is passed into the method.
1925 - (WebAccessibilityTextMarker *)previousMarkerForMarker:(WebAccessibilityTextMarker *)marker
1926 {
1927     if (![self _prepareAccessibilityCall])
1928         return nil;
1929
1930     if (!marker)
1931         return nil;
1932     
1933     VisiblePosition start = [marker visiblePosition];
1934     VisiblePosition previousMarker = m_object->previousVisiblePosition(start);
1935     
1936     return [WebAccessibilityTextMarker textMarkerWithVisiblePosition:previousMarker cache:m_object->axObjectCache()];
1937 }
1938
1939 // This method is intended to return the bounds of a text marker range in screen coordinates.
1940 - (CGRect)frameForTextMarkers:(NSArray *)array
1941 {
1942     if (![self _prepareAccessibilityCall])
1943         return CGRectZero;
1944
1945     if ([array count] != 2)
1946         return CGRectZero;
1947     
1948     WebAccessibilityTextMarker* startMarker = [array objectAtIndex:0];
1949     WebAccessibilityTextMarker* endMarker = [array objectAtIndex:1];
1950     if (![startMarker isKindOfClass:[WebAccessibilityTextMarker class]] || ![endMarker isKindOfClass:[WebAccessibilityTextMarker class]])
1951         return CGRectZero;
1952
1953     IntRect rect = m_object->boundsForVisiblePositionRange(VisiblePositionRange([startMarker visiblePosition], [endMarker visiblePosition]));
1954     return [self convertRectToScreenSpace:rect];
1955 }
1956
1957 - (WebAccessibilityTextMarker *)textMarkerForPoint:(CGPoint)point
1958 {
1959     if (![self _prepareAccessibilityCall])
1960         return nil;
1961     
1962     VisiblePosition pos = m_object->visiblePositionForPoint(IntPoint(point));
1963     return [WebAccessibilityTextMarker textMarkerWithVisiblePosition:pos cache:m_object->axObjectCache()];
1964 }
1965
1966 - (NSString *)accessibilityIdentifier
1967 {
1968     if (![self _prepareAccessibilityCall])
1969         return nil;
1970     
1971     return m_object->getAttribute(HTMLNames::idAttr);
1972 }
1973
1974 - (NSString *)accessibilitySpeechHint
1975 {
1976     if (![self _prepareAccessibilityCall])
1977         return nil;
1978
1979     switch (m_object->speakProperty()) {
1980     default:
1981     case SpeakNormal:
1982         return @"normal";
1983     case SpeakNone:
1984         return @"none";
1985     case SpeakSpellOut:
1986         return @"spell-out";
1987     case SpeakDigits:
1988         return @"digits";
1989     case SpeakLiteralPunctuation:
1990         return @"literal-punctuation";
1991     case SpeakNoPunctuation:
1992         return @"no-punctuation";
1993     }
1994     
1995     return nil;
1996 }
1997
1998 - (BOOL)accessibilityARIAIsBusy
1999 {
2000     if (![self _prepareAccessibilityCall])
2001         return nil;
2002
2003     return m_object->ariaLiveRegionBusy();
2004 }
2005
2006 - (NSString *)accessibilityARIALiveRegionStatus
2007 {
2008     if (![self _prepareAccessibilityCall])
2009         return nil;
2010
2011     return m_object->ariaLiveRegionStatus();
2012 }
2013
2014 - (NSString *)accessibilityARIARelevantStatus
2015 {
2016     if (![self _prepareAccessibilityCall])
2017         return nil;
2018     
2019     return m_object->ariaLiveRegionRelevant();
2020 }
2021
2022 - (BOOL)accessibilityARIALiveRegionIsAtomic
2023 {
2024     if (![self _prepareAccessibilityCall])
2025         return nil;
2026     
2027     return m_object->ariaLiveRegionAtomic();
2028 }
2029
2030 - (NSString *)accessibilityInvalidStatus
2031 {
2032     if (![self _prepareAccessibilityCall])
2033         return nil;
2034     
2035     return m_object->invalidStatus();
2036 }
2037
2038 - (WebAccessibilityObjectWrapper *)accessibilityMathRootIndexObject
2039 {
2040     if (![self _prepareAccessibilityCall])
2041         return nil;
2042
2043     return m_object->mathRootIndexObject() ? m_object->mathRootIndexObject()->wrapper() : 0;
2044 }
2045
2046 - (WebAccessibilityObjectWrapper *)accessibilityMathRadicandObject
2047 {
2048     if (![self _prepareAccessibilityCall])
2049         return nil;
2050
2051     return m_object->mathRadicandObject() ? m_object->mathRadicandObject()->wrapper() : 0;
2052 }
2053
2054 - (WebAccessibilityObjectWrapper *)accessibilityMathNumeratorObject
2055 {
2056     if (![self _prepareAccessibilityCall])
2057         return nil;
2058
2059     return m_object->mathNumeratorObject() ? m_object->mathNumeratorObject()->wrapper() : 0;
2060 }
2061
2062 - (WebAccessibilityObjectWrapper *)accessibilityMathDenominatorObject
2063 {
2064     if (![self _prepareAccessibilityCall])
2065         return nil;
2066
2067     return m_object->mathDenominatorObject() ? m_object->mathDenominatorObject()->wrapper() : 0;
2068 }
2069
2070 - (WebAccessibilityObjectWrapper *)accessibilityMathBaseObject
2071 {
2072     if (![self _prepareAccessibilityCall])
2073         return nil;
2074
2075     return m_object->mathBaseObject() ? m_object->mathBaseObject()->wrapper() : 0;
2076 }
2077
2078 - (WebAccessibilityObjectWrapper *)accessibilityMathSubscriptObject
2079 {
2080     if (![self _prepareAccessibilityCall])
2081         return nil;
2082
2083     return m_object->mathSubscriptObject() ? m_object->mathSubscriptObject()->wrapper() : 0;
2084 }
2085
2086 - (WebAccessibilityObjectWrapper *)accessibilityMathSuperscriptObject
2087 {
2088     if (![self _prepareAccessibilityCall])
2089         return nil;
2090
2091     return m_object->mathSuperscriptObject() ? m_object->mathSuperscriptObject()->wrapper() : 0;
2092 }
2093
2094 - (WebAccessibilityObjectWrapper *)accessibilityMathUnderObject
2095 {
2096     if (![self _prepareAccessibilityCall])
2097         return nil;
2098
2099     return m_object->mathUnderObject() ? m_object->mathUnderObject()->wrapper() : 0;
2100 }
2101
2102 - (WebAccessibilityObjectWrapper *)accessibilityMathOverObject
2103 {
2104     if (![self _prepareAccessibilityCall])
2105         return nil;
2106
2107     return m_object->mathOverObject() ? m_object->mathOverObject()->wrapper() : 0;
2108 }
2109
2110 - (NSString *)accessibilityPlatformMathSubscriptKey
2111 {
2112     return @"AXMSubscriptObject";
2113 }
2114
2115 - (NSString *)accessibilityPlatformMathSuperscriptKey
2116 {
2117     return @"AXMSuperscriptObject";
2118 }
2119
2120 - (NSArray *)accessibilityMathPostscripts
2121 {
2122     if (![self _prepareAccessibilityCall])
2123         return nil;
2124     
2125     return [self accessibilityMathPostscriptPairs];
2126 }
2127
2128 - (NSArray *)accessibilityMathPrescripts
2129 {
2130     if (![self _prepareAccessibilityCall])
2131         return nil;
2132     
2133     return [self accessibilityMathPrescriptPairs];
2134 }
2135
2136 - (NSString *)accessibilityMathFencedOpenString
2137 {
2138     if (![self _prepareAccessibilityCall])
2139         return nil;
2140
2141     return m_object->mathFencedOpenString();
2142 }
2143
2144 - (NSString *)accessibilityMathFencedCloseString
2145 {
2146     if (![self _prepareAccessibilityCall])
2147         return nil;
2148
2149     return m_object->mathFencedCloseString();
2150 }
2151
2152 - (BOOL)accessibilityIsMathTopObject
2153 {
2154     if (![self _prepareAccessibilityCall])
2155         return NO;
2156
2157     return m_object->roleValue() == DocumentMathRole;
2158 }
2159
2160 - (NSInteger)accessibilityMathLineThickness
2161 {
2162     if (![self _prepareAccessibilityCall])
2163         return 0;
2164
2165     return m_object->mathLineThickness();
2166 }
2167
2168 - (NSString *)accessibilityMathType
2169 {
2170     if (![self _prepareAccessibilityCall])
2171         return nil;
2172
2173     if (m_object->roleValue() == MathElementRole) {
2174         if (m_object->isMathFraction())
2175             return @"AXMathFraction";
2176         if (m_object->isMathFenced())
2177             return @"AXMathFenced";
2178         if (m_object->isMathSubscriptSuperscript())
2179             return @"AXMathSubscriptSuperscript";
2180         if (m_object->isMathRow())
2181             return @"AXMathRow";
2182         if (m_object->isMathUnderOver())
2183             return @"AXMathUnderOver";
2184         if (m_object->isMathSquareRoot())
2185             return @"AXMathSquareRoot";
2186         if (m_object->isMathRoot())
2187             return @"AXMathRoot";
2188         if (m_object->isMathText())
2189             return @"AXMathText";
2190         if (m_object->isMathNumber())
2191             return @"AXMathNumber";
2192         if (m_object->isMathIdentifier())
2193             return @"AXMathIdentifier";
2194         if (m_object->isMathTable())
2195             return @"AXMathTable";
2196         if (m_object->isMathTableRow())
2197             return @"AXMathTableRow";
2198         if (m_object->isMathTableCell())
2199             return @"AXMathTableCell";
2200         if (m_object->isMathFenceOperator())
2201             return @"AXMathFenceOperator";
2202         if (m_object->isMathSeparatorOperator())
2203             return @"AXMathSeparatorOperator";
2204         if (m_object->isMathOperator())
2205             return @"AXMathOperator";
2206         if (m_object->isMathMultiscript())
2207             return @"AXMathMultiscript";
2208     }
2209     
2210     return nil;
2211 }
2212
2213 - (CGPoint)accessibilityClickPoint
2214 {
2215     return m_object->clickPoint();
2216 }
2217
2218 // These are used by DRT so that it can know when notifications are sent.
2219 // Since they are static, only one callback can be installed at a time (that's all DRT should need).
2220 typedef void (*AXPostedNotificationCallback)(id element, NSString* notification, void* context);
2221 static AXPostedNotificationCallback AXNotificationCallback = 0;
2222 static void* AXPostedNotificationContext = 0;
2223
2224 - (void)accessibilitySetPostedNotificationCallback:(AXPostedNotificationCallback)function withContext:(void*)context
2225 {
2226     AXNotificationCallback = function;
2227     AXPostedNotificationContext = context;
2228 }
2229
2230 - (void)accessibilityPostedNotification:(NSString *)notificationName
2231 {
2232     if (AXNotificationCallback && notificationName)
2233         AXNotificationCallback(self, notificationName, AXPostedNotificationContext);
2234 }
2235
2236 #ifndef NDEBUG
2237 - (NSString *)description
2238 {
2239     CGRect frame = [self accessibilityFrame];
2240     return [NSString stringWithFormat:@"Role: (%d) - Text: %@: Value: %@ -- Frame: %f %f %f %f", m_object ? m_object->roleValue() : 0, [self accessibilityLabel], [self accessibilityValue], frame.origin.x, frame.origin.y, frame.size.width, frame.size.height];
2241 }
2242 #endif
2243
2244 @end
2245
2246 #endif // HAVE(ACCESSIBILITY) && PLATFORM(IOS)