AX: Implement bounds/position and index related text marker functions using TextIterator
[WebKit-https.git] / Source / WebCore / accessibility / ios / WebAccessibilityObjectWrapperIOS.mm
1 /*
2  * Copyright (C) 2008, 2015 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 "WebAccessibilityObjectWrapperIOS.h"
28
29 #if HAVE(ACCESSIBILITY) && PLATFORM(IOS)
30
31 #import "AccessibilityRenderObject.h"
32 #import "AccessibilityScrollView.h"
33 #import "AccessibilityTable.h"
34 #import "AccessibilityTableCell.h"
35 #import "Chrome.h"
36 #import "ChromeClient.h"
37 #import "FontCascade.h"
38 #import "Frame.h"
39 #import "FrameSelection.h"
40 #import "FrameView.h"
41 #import "HitTestResult.h"
42 #import "HTMLFrameOwnerElement.h"
43 #import "HTMLInputElement.h"
44 #import "HTMLNames.h"
45 #import "IntRect.h"
46 #import "IntSize.h"
47 #import "LocalizedStrings.h"
48 #import "Page.h"
49 #import "Range.h"
50 #import "RenderView.h"
51 #import "RuntimeApplicationChecks.h"
52 #import "SVGNames.h"
53 #import "SVGElement.h"
54 #import "TextIterator.h"
55 #import "WAKScrollView.h"
56 #import "WAKView.h"
57 #import "WAKWindow.h"
58 #import "WebCoreThread.h"
59 #import "VisibleUnits.h"
60
61 #import <CoreText/CoreText.h>
62
63 @interface NSObject (AccessibilityPrivate)
64 - (void)_accessibilityUnregister;
65 - (NSString *)accessibilityLabel;
66 - (NSString *)accessibilityValue;
67 - (BOOL)isAccessibilityElement;
68 - (NSInteger)accessibilityElementCount;
69 - (id)accessibilityElementAtIndex:(NSInteger)index;
70 - (NSInteger)indexOfAccessibilityElement:(id)element;
71 @end
72
73 @interface WebAccessibilityObjectWrapper (AccessibilityPrivate)
74 - (id)_accessibilityWebDocumentView;
75 - (id)accessibilityContainer;
76 - (void)setAccessibilityLabel:(NSString *)label;
77 - (void)setAccessibilityValue:(NSString *)value;
78 - (BOOL)containsUnnaturallySegmentedChildren;
79 - (NSInteger)positionForTextMarker:(id)marker;
80 @end
81
82 @interface WAKView (iOSAccessibility)
83 - (BOOL)accessibilityIsIgnored;
84 @end
85
86 using namespace WebCore;
87 using namespace HTMLNames;
88
89 typedef NS_ENUM(NSInteger, UIAccessibilityScrollDirection) {
90     UIAccessibilityScrollDirectionRight = 1,
91     UIAccessibilityScrollDirectionLeft,
92     UIAccessibilityScrollDirectionUp,
93     UIAccessibilityScrollDirectionDown,
94     UIAccessibilityScrollDirectionNext,
95     UIAccessibilityScrollDirectionPrevious
96 };
97
98 // These are tokens accessibility uses to denote attributes. 
99 static NSString * const UIAccessibilityTokenBlockquoteLevel = @"UIAccessibilityTokenBlockquoteLevel";
100 static NSString * const UIAccessibilityTokenHeadingLevel = @"UIAccessibilityTokenHeadingLevel";
101 static NSString * const UIAccessibilityTokenFontName = @"UIAccessibilityTokenFontName";
102 static NSString * const UIAccessibilityTokenFontFamily = @"UIAccessibilityTokenFontFamily";
103 static NSString * const UIAccessibilityTokenFontSize = @"UIAccessibilityTokenFontSize";
104 static NSString * const UIAccessibilityTokenBold = @"UIAccessibilityTokenBold";
105 static NSString * const UIAccessibilityTokenItalic = @"UIAccessibilityTokenItalic";
106 static NSString * const UIAccessibilityTokenUnderline = @"UIAccessibilityTokenUnderline";
107 static NSString * const UIAccessibilityTokenLanguage = @"UIAccessibilityTokenLanguage";
108
109 static AccessibilityObjectWrapper* AccessibilityUnignoredAncestor(AccessibilityObjectWrapper *wrapper)
110 {
111     while (wrapper && ![wrapper isAccessibilityElement]) {
112         AccessibilityObject* object = [wrapper accessibilityObject];
113         if (!object)
114             break;
115         
116         if ([wrapper isAttachment] && ![[wrapper attachmentView] accessibilityIsIgnored])
117             break;
118             
119         AccessibilityObject* parentObject = object->parentObjectUnignored();
120         if (!parentObject)
121             break;
122
123         wrapper = parentObject->wrapper();
124     }
125     return wrapper;
126 }
127
128 #pragma mark Accessibility Text Marker
129
130 @interface WebAccessibilityTextMarker : NSObject
131 {
132     AXObjectCache* _cache;
133     TextMarkerData _textMarkerData;
134 }
135
136 + (WebAccessibilityTextMarker *)textMarkerWithVisiblePosition:(VisiblePosition&)visiblePos cache:(AXObjectCache*)cache;
137 + (WebAccessibilityTextMarker *)textMarkerWithCharacterOffset:(CharacterOffset&)characterOffset cache:(AXObjectCache*)cache;
138 + (WebAccessibilityTextMarker *)startOrEndTextMarkerForRange:(const RefPtr<Range>)range isStart:(BOOL)isStart cache:(AXObjectCache*)cache;
139
140 @end
141
142 @implementation WebAccessibilityTextMarker
143
144 - (id)initWithTextMarker:(TextMarkerData *)data cache:(AXObjectCache*)cache
145 {
146     if (!(self = [super init]))
147         return nil;
148     
149     _cache = cache;
150     memcpy(&_textMarkerData, data, sizeof(TextMarkerData));
151     return self;
152 }
153
154 - (id)initWithData:(NSData *)data cache:(AXObjectCache*)cache
155 {
156     if (!(self = [super init]))
157         return nil;
158     
159     _cache = cache;
160     [data getBytes:&_textMarkerData length:sizeof(TextMarkerData)];
161     
162     return self;
163 }
164
165 // This is needed for external clients to be able to create a text marker without having a pointer to the cache.
166 - (id)initWithData:(NSData *)data accessibilityObject:(AccessibilityObjectWrapper *)wrapper
167 {
168     WebCore::AccessibilityObject* axObject = [wrapper accessibilityObject]; 
169     if (!axObject)
170         return nil;
171     
172     return [self initWithData:data cache:axObject->axObjectCache()];
173 }
174
175 + (WebAccessibilityTextMarker *)textMarkerWithVisiblePosition:(VisiblePosition&)visiblePos cache:(AXObjectCache*)cache
176 {
177     TextMarkerData textMarkerData;
178     cache->textMarkerDataForVisiblePosition(textMarkerData, visiblePos);
179     
180     return [[[WebAccessibilityTextMarker alloc] initWithTextMarker:&textMarkerData cache:cache] autorelease];
181 }
182
183 + (WebAccessibilityTextMarker *)textMarkerWithCharacterOffset:(CharacterOffset&)characterOffset cache:(AXObjectCache*)cache
184 {
185     if (!cache)
186         return nil;
187     
188     if (characterOffset.isNull())
189         return nil;
190     
191     TextMarkerData textMarkerData;
192     cache->textMarkerDataForCharacterOffset(textMarkerData, characterOffset);
193     if (!textMarkerData.axID && !textMarkerData.ignored)
194         return nil;
195     return [[[WebAccessibilityTextMarker alloc] initWithTextMarker:&textMarkerData cache:cache] autorelease];
196 }
197
198 + (WebAccessibilityTextMarker *)startOrEndTextMarkerForRange:(const RefPtr<Range>)range isStart:(BOOL)isStart cache:(AXObjectCache*)cache
199 {
200     if (!cache)
201         return nil;
202     
203     TextMarkerData textMarkerData;
204     cache->startOrEndTextMarkerDataForRange(textMarkerData, range, isStart);
205     if (!textMarkerData.axID)
206         return nil;
207     return [[[WebAccessibilityTextMarker alloc] initWithTextMarker:&textMarkerData cache:cache] autorelease];
208 }
209
210 - (NSData *)dataRepresentation
211 {
212     return [NSData dataWithBytes:&_textMarkerData length:sizeof(TextMarkerData)];
213 }
214
215 - (VisiblePosition)visiblePosition
216 {
217     return _cache->visiblePositionForTextMarkerData(_textMarkerData);
218 }
219
220 - (CharacterOffset)characterOffset
221 {
222     return _cache->characterOffsetForTextMarkerData(_textMarkerData);
223 }
224
225 - (BOOL)isIgnored
226 {
227     return _textMarkerData.ignored;
228 }
229
230 - (AccessibilityObject*)accessibilityObject
231 {
232     if (_textMarkerData.ignored)
233         return nullptr;
234     return _cache->accessibilityObjectForTextMarkerData(_textMarkerData);
235 }
236
237 - (NSString *)description
238 {
239     return [NSString stringWithFormat:@"[AXTextMarker %p] = node: %p offset: %d", self, _textMarkerData.node, _textMarkerData.offset];
240 }
241
242 @end
243
244 @implementation WebAccessibilityObjectWrapper
245
246 - (id)initWithAccessibilityObject:(AccessibilityObject*)axObject
247 {
248     self = [super initWithAccessibilityObject:axObject];
249     if (!self)
250         return nil;
251     
252     // Initialize to a sentinel value.
253     m_accessibilityTraitsFromAncestor = ULLONG_MAX;
254     m_isAccessibilityElement = -1;
255     
256     return self;
257 }
258
259 - (void)detach
260 {
261     // rdar://8798960 Make sure the object is gone early, so that anything _accessibilityUnregister 
262     // does can't call back into the render tree.
263     m_object = nullptr;
264
265     if ([self respondsToSelector:@selector(_accessibilityUnregister)])
266         [self _accessibilityUnregister];
267 }
268
269 - (void)dealloc
270 {
271     // We should have been detached before deallocated.
272     ASSERT(!m_object);
273     [super dealloc];
274 }
275
276 - (BOOL)_prepareAccessibilityCall
277 {
278     // rdar://7980318 if we start a call, then block in WebThreadLock(), then we're dealloced on another, thread, we could
279     // crash, so we should retain ourself for the duration of usage here.
280     [[self retain] autorelease];
281
282     WebThreadLock();
283     
284     // If we came back from our thread lock and we were detached, we will no longer have an m_object.
285     if (!m_object)
286         return NO;
287     
288     m_object->updateBackingStore();
289     if (!m_object)
290         return NO;
291     
292     return YES;
293 }
294
295 // These are here so that we don't have to import AXRuntime.
296 // The methods will be swizzled when the accessibility bundle is loaded.
297
298 - (uint64_t)_axLinkTrait { return (1 << 0); }
299 - (uint64_t)_axVisitedTrait { return (1 << 1); }
300 - (uint64_t)_axHeaderTrait { return (1 << 2); }
301 - (uint64_t)_axContainedByListTrait { return (1 << 3); }
302 - (uint64_t)_axContainedByTableTrait { return (1 << 4); }
303 - (uint64_t)_axContainedByLandmarkTrait { return (1 << 5); }
304 - (uint64_t)_axWebContentTrait { return (1 << 6); }
305 - (uint64_t)_axSecureTextFieldTrait { return (1 << 7); }
306 - (uint64_t)_axTextEntryTrait { return (1 << 8); }
307 - (uint64_t)_axHasTextCursorTrait { return (1 << 9); }
308 - (uint64_t)_axTextOperationsAvailableTrait { return (1 << 10); }
309 - (uint64_t)_axImageTrait { return (1 << 11); }
310 - (uint64_t)_axTabButtonTrait { return (1 << 12); }
311 - (uint64_t)_axButtonTrait { return (1 << 13); }
312 - (uint64_t)_axToggleTrait { return (1 << 14); }
313 - (uint64_t)_axPopupButtonTrait { return (1 << 15); }
314 - (uint64_t)_axStaticTextTrait { return (1 << 16); }
315 - (uint64_t)_axAdjustableTrait { return (1 << 17); }
316 - (uint64_t)_axMenuItemTrait { return (1 << 18); }
317 - (uint64_t)_axSelectedTrait { return (1 << 19); }
318 - (uint64_t)_axNotEnabledTrait { return (1 << 20); }
319 - (uint64_t)_axRadioButtonTrait { return (1 << 21); }
320 - (uint64_t)_axContainedByFieldsetTrait { return (1 << 22); }
321 - (uint64_t)_axSearchFieldTrait { return (1 << 23); }
322 - (uint64_t)_axTextAreaTrait { return (1 << 24); }
323
324 - (BOOL)accessibilityCanFuzzyHitTest
325 {
326     if (![self _prepareAccessibilityCall])
327         return false;
328     
329     AccessibilityRole role = m_object->roleValue();
330     // Elements that can be returned when performing fuzzy hit testing.
331     switch (role) {
332     case ButtonRole:
333     case CheckBoxRole:
334     case ComboBoxRole:
335     case DisclosureTriangleRole:
336     case HeadingRole:
337     case ImageMapLinkRole:
338     case ImageRole:
339     case LinkRole:
340     case ListBoxRole:
341     case ListBoxOptionRole:
342     case MenuButtonRole:
343     case MenuItemRole:
344     case MenuItemCheckboxRole:
345     case MenuItemRadioRole:
346     case PopUpButtonRole:
347     case RadioButtonRole:
348     case ScrollBarRole:
349     case SearchFieldRole:
350     case SliderRole:
351     case StaticTextRole:
352     case SwitchRole:
353     case TabRole:
354     case TextFieldRole:
355     case ToggleButtonRole:
356         return !m_object->accessibilityIsIgnored();
357     default:
358         return false;
359     }
360 }
361
362 - (AccessibilityObjectWrapper *)accessibilityPostProcessHitTest:(CGPoint)point
363 {
364     UNUSED_PARAM(point);
365     // The UIKit accessibility wrapper will override this and perform the post process hit test.
366     return nil;
367 }
368
369 - (id)accessibilityHitTest:(CGPoint)point
370 {
371     if (![self _prepareAccessibilityCall])
372         return nil;
373     
374     // Try a fuzzy hit test first to find an accessible element.
375     RefPtr<AccessibilityObject> axObject;
376     {
377         AXAttributeCacheEnabler enableCache(m_object->axObjectCache());
378         axObject = m_object->accessibilityHitTest(IntPoint(point));
379     }
380
381     if (!axObject)
382         return nil;
383     
384     // If this is a good accessible object to return, no extra work is required.
385     if ([axObject->wrapper() accessibilityCanFuzzyHitTest])
386         return AccessibilityUnignoredAncestor(axObject->wrapper());
387     
388     // Check to see if we can post-process this hit test to find a better candidate.
389     AccessibilityObjectWrapper* wrapper = [axObject->wrapper() accessibilityPostProcessHitTest:point];
390     if (wrapper)
391         return AccessibilityUnignoredAncestor(wrapper);
392     
393     // Fall back to default behavior.
394     return AccessibilityUnignoredAncestor(axObject->wrapper());    
395 }
396
397 - (void)enableAttributeCaching
398 {
399     if (AXObjectCache* cache = m_object->axObjectCache())
400         cache->startCachingComputedObjectAttributesUntilTreeMutates();
401 }
402
403 - (void)disableAttributeCaching
404 {
405     if (AXObjectCache* cache = m_object->axObjectCache())
406         cache->stopCachingComputedObjectAttributes();
407 }
408
409 - (NSInteger)accessibilityElementCount
410 {
411     if (![self _prepareAccessibilityCall])
412         return 0;
413
414     if ([self isAttachment]) {
415         if (id attachmentView = [self attachmentView])
416             return [attachmentView accessibilityElementCount];
417     }
418     
419     return m_object->children().size();
420 }
421
422 - (id)accessibilityElementAtIndex:(NSInteger)index
423 {
424     if (![self _prepareAccessibilityCall])
425         return nil;
426
427     if ([self isAttachment]) {
428         if (id attachmentView = [self attachmentView])
429             return [attachmentView accessibilityElementAtIndex:index];
430     }
431     
432     const auto& children = m_object->children();
433     size_t elementIndex = static_cast<size_t>(index);
434     if (elementIndex >= children.size())
435         return nil;
436     
437     AccessibilityObjectWrapper* wrapper = children[elementIndex]->wrapper();
438     if (children[elementIndex]->isAttachment()) {
439         if (id attachmentView = [wrapper attachmentView])
440             return attachmentView;
441     }
442
443     return wrapper;
444 }
445
446 - (NSInteger)indexOfAccessibilityElement:(id)element
447 {
448     if (![self _prepareAccessibilityCall])
449         return NSNotFound;
450     
451     if ([self isAttachment]) {
452         if (id attachmentView = [self attachmentView])
453             return [attachmentView indexOfAccessibilityElement:element];
454     }
455     
456     const auto& children = m_object->children();
457     unsigned count = children.size();
458     for (unsigned k = 0; k < count; ++k) {
459         AccessibilityObjectWrapper* wrapper = children[k]->wrapper();
460         if (wrapper == element || (children[k]->isAttachment() && [wrapper attachmentView] == element))
461             return k;
462     }
463     
464     return NSNotFound;
465 }
466
467 - (CGPathRef)_accessibilityPath
468 {
469     if (![self _prepareAccessibilityCall])
470         return NULL;
471
472     if (!m_object->supportsPath())
473         return NULL;
474     
475     Path path = m_object->elementPath();
476     if (path.isEmpty())
477         return NULL;
478     
479     return [self convertPathToScreenSpace:path];
480 }
481
482 - (BOOL)accessibilityHasPopup
483 {
484     if (![self _prepareAccessibilityCall])
485         return NO;
486     
487     return m_object->ariaHasPopup();
488 }
489
490 - (NSString *)accessibilityLanguage
491 {
492     if (![self _prepareAccessibilityCall])
493         return nil;
494     
495     return m_object->language();
496 }
497
498 - (BOOL)_accessibilityIsLandmarkRole:(AccessibilityRole)role
499 {
500     switch (role) {
501     case DocumentRegionRole:
502     case LandmarkApplicationRole:
503     case LandmarkBannerRole:
504     case LandmarkComplementaryRole:
505     case LandmarkContentInfoRole:
506     case LandmarkMainRole:
507     case LandmarkNavigationRole:
508     case LandmarkSearchRole:
509         return YES;
510     default:
511         return NO;
512     }    
513 }
514
515 - (AccessibilityObjectWrapper*)_accessibilityListAncestor
516 {
517     for (AccessibilityObject* parent = m_object->parentObject(); parent != nil; parent = parent->parentObject()) {
518         AccessibilityRole role = parent->roleValue();
519         if (role == ListRole || role == ListBoxRole)
520             return parent->wrapper();
521     }
522     
523     return nil;
524 }
525
526 - (AccessibilityObjectWrapper*)_accessibilityLandmarkAncestor
527 {
528     for (AccessibilityObject* parent = m_object->parentObject(); parent != nil; parent = parent->parentObject()) {
529         if ([self _accessibilityIsLandmarkRole:parent->roleValue()])
530             return parent->wrapper();
531     }
532
533     return nil;
534 }
535
536 - (AccessibilityObjectWrapper*)_accessibilityTableAncestor
537 {
538     for (AccessibilityObject* parent = m_object->parentObject(); parent != nil; parent = parent->parentObject()) {
539         if (parent->roleValue() == TableRole || parent->roleValue() == GridRole)
540             return parent->wrapper();   
541     }
542     
543     return nil;
544 }
545
546 - (AccessibilityObjectWrapper*)_accessibilityFieldsetAncestor
547 {
548     for (AccessibilityObject* parent = m_object->parentObject(); parent != nil; parent = parent->parentObject()) {
549         if (parent->isFieldset())
550             return parent->wrapper();
551     }
552     
553     return nil;
554 }
555
556 - (uint64_t)_accessibilityTraitsFromAncestors
557 {
558     uint64_t traits = 0;
559     AccessibilityRole role = m_object->roleValue();
560     
561     // Trait information also needs to be gathered from the parents above the object.
562     // The parentObject is needed instead of the unignoredParentObject, because a table might be ignored, but information still needs to be gathered from it.    
563     for (AccessibilityObject* parent = m_object->parentObject(); parent != nil; parent = parent->parentObject()) {
564         AccessibilityRole parentRole = parent->roleValue();
565         if (parentRole == WebAreaRole)
566             break;
567         
568         switch (parentRole) {
569             case LinkRole:
570             case WebCoreLinkRole:
571                 traits |= [self _axLinkTrait];
572                 if (parent->isVisited())
573                     traits |= [self _axVisitedTrait];
574                 break;
575             case HeadingRole:
576             {
577                 traits |= [self _axHeaderTrait];
578                 // If this object has the header trait, we should set the value
579                 // to the heading level. If it was a static text element, we need to store
580                 // the value as the label, because the heading level needs to the value.
581                 AccessibilityObjectWrapper* wrapper = parent->wrapper();
582                 if (role == StaticTextRole) 
583                     [self setAccessibilityLabel:m_object->stringValue()];                
584                 [self setAccessibilityValue:[wrapper accessibilityValue]];
585                 break;
586             }
587             case ListBoxRole:
588             case ListRole:
589                 traits |= [self _axContainedByListTrait];
590                 break;
591             case GridRole:
592             case TableRole:
593                 traits |= [self _axContainedByTableTrait];
594                 break;
595             default:
596                 if ([self _accessibilityIsLandmarkRole:parentRole])
597                     traits |= [self _axContainedByLandmarkTrait];
598                 break;
599         }
600         
601         // If this object has fieldset parent, we should add containedByFieldsetTrait to it.
602         if (parent->isFieldset())
603             traits |= [self _axContainedByFieldsetTrait];
604     }
605     
606     return traits;
607 }
608
609 - (uint64_t)_accessibilityTextEntryTraits
610 {
611     uint64_t traits = [self _axTextEntryTrait];
612     if (m_object->isFocused())
613         traits |= ([self _axHasTextCursorTrait] | [self _axTextOperationsAvailableTrait]);
614     if (m_object->isPasswordField())
615         traits |= [self _axSecureTextFieldTrait];
616     if (m_object->roleValue() == SearchFieldRole)
617         traits |= [self _axSearchFieldTrait];
618     if (m_object->roleValue() == TextAreaRole)
619         traits |= [self _axTextAreaTrait];
620     return traits;
621 }
622
623 - (uint64_t)accessibilityTraits
624 {
625     if (![self _prepareAccessibilityCall])
626         return 0;
627     
628     AccessibilityRole role = m_object->roleValue();
629     uint64_t traits = [self _axWebContentTrait];
630     switch (role) {
631         case LinkRole:
632         case WebCoreLinkRole:
633             traits |= [self _axLinkTrait];
634             if (m_object->isVisited())
635                 traits |= [self _axVisitedTrait];
636             break;
637         case TextFieldRole:
638         case SearchFieldRole:
639         case TextAreaRole:
640             traits |= [self _accessibilityTextEntryTraits];
641             break;
642         case ImageRole:
643             traits |= [self _axImageTrait];
644             break;
645         case TabRole:
646             traits |= [self _axTabButtonTrait];
647             break;
648         case ButtonRole:
649             traits |= [self _axButtonTrait];
650             if (m_object->isPressed())
651                 traits |= [self _axToggleTrait];
652             break;
653         case PopUpButtonRole:
654             traits |= [self _axPopupButtonTrait];
655             break;
656         case RadioButtonRole:
657             traits |= [self _axRadioButtonTrait] | [self _axToggleTrait];
658             break;
659         case ToggleButtonRole:
660         case CheckBoxRole:
661         case SwitchRole:
662             traits |= ([self _axButtonTrait] | [self _axToggleTrait]);
663             break;
664         case HeadingRole:
665             traits |= [self _axHeaderTrait];
666             break;
667         case StaticTextRole:
668             traits |= [self _axStaticTextTrait];
669             break;
670         case SliderRole:
671             traits |= [self _axAdjustableTrait];
672             break;
673         case MenuButtonRole:
674         case MenuItemRole:
675         case MenuItemCheckboxRole:
676         case MenuItemRadioRole:
677             traits |= [self _axMenuItemTrait];
678             break;
679         default:
680             break;
681     }
682
683     if (m_object->isSelected())
684         traits |= [self _axSelectedTrait];
685
686     if (!m_object->isEnabled())
687         traits |= [self _axNotEnabledTrait];
688     
689     if (m_accessibilityTraitsFromAncestor == ULLONG_MAX)
690         m_accessibilityTraitsFromAncestor = [self _accessibilityTraitsFromAncestors];
691     
692     traits |= m_accessibilityTraitsFromAncestor;
693
694     return traits;
695 }
696
697 - (BOOL)isSVGGroupElement
698 {
699     // If an SVG group element has a title, it should be an accessible element on iOS.
700     Node* node = m_object->node();
701     if (node && node->hasTagName(SVGNames::gTag) && [[self accessibilityLabel] length] > 0)
702         return YES;
703     
704     return NO;
705 }
706
707 - (BOOL)determineIsAccessibilityElement
708 {
709     if (!m_object)
710         return false;
711     
712     // Honor when something explicitly makes this an element (super will contain that logic) 
713     if ([super isAccessibilityElement])
714         return YES;
715     
716     m_object->updateBackingStore();
717     
718     switch (m_object->roleValue()) {
719         case TextFieldRole:
720         case TextAreaRole:
721         case ButtonRole:
722         case ToggleButtonRole:
723         case PopUpButtonRole:
724         case CheckBoxRole:
725         case RadioButtonRole:
726         case SliderRole:
727         case MenuButtonRole:
728         case ValueIndicatorRole:
729         case ImageRole:
730         case ImageMapLinkRole:
731         case ProgressIndicatorRole:
732         case MenuItemRole:
733         case MenuItemCheckboxRole:
734         case MenuItemRadioRole:
735         case IncrementorRole:
736         case ComboBoxRole:
737         case DisclosureTriangleRole:
738         case ImageMapRole:
739         case ListMarkerRole:
740         case ListBoxOptionRole:
741         case TabRole:
742         case DocumentMathRole:
743         case HorizontalRuleRole:
744         case SliderThumbRole:
745         case SwitchRole:
746         case SearchFieldRole:
747         case SpinButtonRole:
748             return true;
749         case StaticTextRole:
750         {
751             // Many text elements only contain a space.
752             if (![[[self accessibilityLabel] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length])
753                 return false;
754
755             // Text elements that are just pieces of links or headers should not be exposed.
756             if ([AccessibilityUnignoredAncestor([self accessibilityContainer]) containsUnnaturallySegmentedChildren])
757                 return false;
758             return true;
759         }
760             
761         // Don't expose headers as elements; instead expose their children as elements, with the header trait (unless they have no children)
762         case HeadingRole:
763             if (![self accessibilityElementCount])
764                 return true;
765             return false;
766             
767         // Links can sometimes be elements (when they only contain static text or don't contain anything).
768         // They should not be elements when containing text and other types.
769         case WebCoreLinkRole:
770         case LinkRole:
771             if ([self containsUnnaturallySegmentedChildren] || ![self accessibilityElementCount])
772                 return true;
773             return false;
774         case GroupRole:
775             if ([self isSVGGroupElement])
776                 return true;
777             FALLTHROUGH;
778         // All other elements are ignored on the iphone.
779         case AnnotationRole:
780         case ApplicationRole:
781         case ApplicationAlertRole:
782         case ApplicationAlertDialogRole:
783         case ApplicationDialogRole:
784         case ApplicationLogRole:
785         case ApplicationMarqueeRole:
786         case ApplicationStatusRole:
787         case ApplicationTimerRole:
788         case AudioRole:
789         case BlockquoteRole:
790         case BrowserRole:
791         case BusyIndicatorRole:
792         case CanvasRole:
793         case CaptionRole:
794         case CellRole:
795         case ColorWellRole:
796         case ColumnRole:
797         case ColumnHeaderRole:
798         case DefinitionRole:
799         case DescriptionListRole:
800         case DescriptionListTermRole:
801         case DescriptionListDetailRole:
802         case DetailsRole:
803         case DirectoryRole:
804         case DivRole:
805         case DocumentRole:
806         case DocumentArticleRole:
807         case DocumentNoteRole:
808         case DocumentRegionRole:
809         case DrawerRole:
810         case EditableTextRole:
811         case FooterRole:
812         case FormRole:
813         case GridRole:
814         case GridCellRole:
815         case GrowAreaRole:
816         case HelpTagRole:
817         case IgnoredRole:
818         case InlineRole:
819         case LabelRole:
820         case LandmarkApplicationRole:
821         case LandmarkBannerRole:
822         case LandmarkComplementaryRole:
823         case LandmarkContentInfoRole:
824         case LandmarkMainRole:
825         case LandmarkNavigationRole:
826         case LandmarkSearchRole:
827         case LegendRole:
828         case ListRole:
829         case ListBoxRole:
830         case ListItemRole:
831         case MathElementRole:
832         case MatteRole:
833         case MenuRole:
834         case MenuBarRole:
835         case MenuListPopupRole:
836         case MenuListOptionRole:
837         case OutlineRole:
838         case ParagraphRole:
839         case PreRole:
840         case PresentationalRole:
841         case RadioGroupRole:
842         case RowHeaderRole:
843         case RowRole:
844         case RubyBaseRole:
845         case RubyBlockRole:
846         case RubyInlineRole:
847         case RubyRunRole:
848         case RubyTextRole:
849         case RulerRole:
850         case RulerMarkerRole:
851         case ScrollAreaRole:
852         case ScrollBarRole:
853         case SheetRole:
854         case SpinButtonPartRole:
855         case SplitGroupRole:
856         case SplitterRole:
857         case SummaryRole:
858         case SystemWideRole:
859         case SVGRootRole:
860         case SVGTextPathRole:
861         case SVGTextRole:
862         case SVGTSpanRole:
863         case TabGroupRole:
864         case TabListRole:
865         case TabPanelRole:
866         case TableRole:
867         case TableHeaderContainerRole:
868         case TreeRole:
869         case TreeItemRole:
870         case TreeGridRole:
871         case ToolbarRole:
872         case UnknownRole:
873         case UserInterfaceTooltipRole:
874         case VideoRole:
875         case WebAreaRole:
876         case WindowRole:
877         case RowGroupRole:
878             return false;
879     }
880     
881     ASSERT_NOT_REACHED();
882     return false;
883 }
884
885 - (BOOL)isAccessibilityElement
886 {
887     if (![self _prepareAccessibilityCall])
888         return NO;
889     
890     if (m_isAccessibilityElement == -1)
891         m_isAccessibilityElement = [self determineIsAccessibilityElement];
892     
893     return m_isAccessibilityElement;
894 }
895
896 - (BOOL)stringValueShouldBeUsedInLabel
897 {
898     if (m_object->isTextControl())
899         return NO;
900     if (m_object->roleValue() == PopUpButtonRole)
901         return NO;
902     if (m_object->isFileUploadButton())
903         return NO;
904
905     return YES;
906 }
907
908 - (BOOL)fileUploadButtonReturnsValueInTitle
909 {
910     return NO;
911 }
912
913 static void appendStringToResult(NSMutableString *result, NSString *string)
914 {
915     ASSERT(result);
916     if (![string length])
917         return;
918     if ([result length])
919         [result appendString:@", "];
920     [result appendString:string];
921 }
922
923 - (BOOL)_accessibilityValueIsAutofilled
924 {
925     if (![self _prepareAccessibilityCall])
926         return NO;
927
928     return m_object->isValueAutofilled();
929 }
930
931 - (CGFloat)_accessibilityMinValue
932 {
933     return m_object->minValueForRange();
934 }
935
936 - (CGFloat)_accessibilityMaxValue
937 {
938     return m_object->maxValueForRange();
939 }
940
941 - (NSString *)accessibilityRoleDescription
942 {
943     return m_object->roleDescription();
944 }
945
946 - (NSString *)accessibilityLabel
947 {
948     if (![self _prepareAccessibilityCall])
949         return nil;
950
951     // check if the label was overriden
952     NSString *label = [super accessibilityLabel];
953     if (label)
954         return label;
955
956     // iOS doesn't distinguish between a title and description field,
957     // so concatentation will yield the best result.
958     NSString *axTitle = [self baseAccessibilityTitle];
959     NSString *axDescription = [self baseAccessibilityDescription];
960     NSString *landmarkDescription = [self ariaLandmarkRoleDescription];
961     
962     NSMutableString *result = [NSMutableString string];
963     if (m_object->roleValue() == HorizontalRuleRole)
964         appendStringToResult(result, AXHorizontalRuleDescriptionText());
965         
966     appendStringToResult(result, axTitle);
967     appendStringToResult(result, axDescription);
968     if ([self stringValueShouldBeUsedInLabel]) {
969         NSString *valueLabel = m_object->stringValue();
970         valueLabel = [valueLabel stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
971         appendStringToResult(result, valueLabel);
972     }
973     appendStringToResult(result, landmarkDescription);
974     
975     return [result length] ? result : nil;
976 }
977
978 - (AccessibilityTableCell*)tableCellParent
979 {
980     // Find if this element is in a table cell.
981     AccessibilityObject* cell = nullptr;
982     for (cell = m_object; cell && !cell->isTableCell(); cell = cell->parentObject()) 
983     { }
984     
985     if (!cell)
986         return nil;
987
988     return static_cast<AccessibilityTableCell*>(cell);
989 }
990
991 - (AccessibilityTable*)tableParent
992 {
993     // Find if the parent table for the table cell.
994     AccessibilityObject* parentTable = nullptr;
995     for (parentTable = m_object; parentTable && !(is<AccessibilityTable>(*parentTable) && downcast<AccessibilityTable>(*parentTable).isExposableThroughAccessibility()); parentTable = parentTable->parentObject())
996     { }
997     
998     if (!parentTable)
999         return nil;
1000     
1001     return static_cast<AccessibilityTable*>(parentTable);
1002 }
1003
1004 - (id)accessibilityTitleElement
1005 {
1006     if (![self _prepareAccessibilityCall])
1007         return nil;
1008
1009     AccessibilityObject* titleElement = m_object->titleUIElement();
1010     if (titleElement)
1011         return titleElement->wrapper();
1012
1013     return nil;
1014 }
1015
1016 // Meant to return row or column headers (or other things as the future permits).
1017 - (NSArray *)accessibilityHeaderElements
1018 {
1019     if (![self _prepareAccessibilityCall])
1020         return nil;
1021
1022     AccessibilityTableCell* tableCell = [self tableCellParent];
1023     if (!tableCell)
1024         return nil;
1025     
1026     AccessibilityTable* table = [self tableParent];
1027     if (!table)
1028         return nil;
1029     
1030     // Get the row and column range, so we can use them to find the headers.
1031     std::pair<unsigned, unsigned> rowRange;
1032     std::pair<unsigned, unsigned> columnRange;
1033     tableCell->rowIndexRange(rowRange);
1034     tableCell->columnIndexRange(columnRange);
1035     
1036     AccessibilityObject::AccessibilityChildrenVector rowHeaders;
1037     AccessibilityObject::AccessibilityChildrenVector columnHeaders;
1038     table->rowHeaders(rowHeaders);
1039     table->columnHeaders(columnHeaders);
1040     
1041     NSMutableArray *headers = [NSMutableArray array];
1042     
1043     unsigned columnRangeIndex = static_cast<unsigned>(columnRange.first);
1044     if (columnRangeIndex < columnHeaders.size()) {
1045         RefPtr<AccessibilityObject> columnHeader = columnHeaders[columnRange.first];
1046         AccessibilityObjectWrapper* wrapper = columnHeader->wrapper();
1047         if (wrapper)
1048             [headers addObject:wrapper];
1049     }
1050
1051     unsigned rowRangeIndex = static_cast<unsigned>(rowRange.first);
1052     if (rowRangeIndex < rowHeaders.size()) {
1053         RefPtr<AccessibilityObject> rowHeader = rowHeaders[rowRange.first];
1054         AccessibilityObjectWrapper* wrapper = rowHeader->wrapper();
1055         if (wrapper)
1056             [headers addObject:wrapper];
1057     }
1058         
1059     return headers;
1060 }
1061
1062 - (id)accessibilityElementForRow:(NSInteger)row andColumn:(NSInteger)column
1063 {
1064     if (![self _prepareAccessibilityCall])
1065         return nil;
1066
1067     AccessibilityTable* table = [self tableParent];
1068     if (!table)
1069         return nil;
1070
1071     AccessibilityTableCell* cell = table->cellForColumnAndRow(column, row);
1072     if (!cell)
1073         return nil;
1074     return cell->wrapper();
1075 }
1076
1077 - (NSUInteger)accessibilityRowCount
1078 {
1079     if (![self _prepareAccessibilityCall])
1080         return 0;
1081     AccessibilityTable *table = [self tableParent];
1082     if (!table)
1083         return 0;
1084     
1085     return table->rowCount();
1086 }
1087
1088 - (NSUInteger)accessibilityColumnCount
1089 {
1090     if (![self _prepareAccessibilityCall])
1091         return 0;
1092     AccessibilityTable *table = [self tableParent];
1093     if (!table)
1094         return 0;
1095     
1096     return table->columnCount();
1097 }
1098
1099 - (NSUInteger)accessibilityARIARowCount
1100 {
1101     if (![self _prepareAccessibilityCall])
1102         return 0;
1103     AccessibilityTable *table = [self tableParent];
1104     if (!table)
1105         return 0;
1106     
1107     NSInteger rowCount = table->ariaRowCount();
1108     return rowCount > 0 ? rowCount : 0;
1109 }
1110
1111 - (NSUInteger)accessibilityARIAColumnCount
1112 {
1113     if (![self _prepareAccessibilityCall])
1114         return 0;
1115     AccessibilityTable *table = [self tableParent];
1116     if (!table)
1117         return 0;
1118     
1119     NSInteger colCount = table->ariaColumnCount();
1120     return colCount > 0 ? colCount : 0;
1121 }
1122
1123 - (NSUInteger)accessibilityARIARowIndex
1124 {
1125     if (![self _prepareAccessibilityCall])
1126         return NSNotFound;
1127     AccessibilityTableCell* tableCell = [self tableCellParent];
1128     if (!tableCell)
1129         return NSNotFound;
1130     
1131     NSInteger rowIndex = tableCell->ariaRowIndex();
1132     return rowIndex > 0 ? rowIndex : NSNotFound;
1133 }
1134
1135 - (NSUInteger)accessibilityARIAColumnIndex
1136 {
1137     if (![self _prepareAccessibilityCall])
1138         return NSNotFound;
1139     AccessibilityTableCell* tableCell = [self tableCellParent];
1140     if (!tableCell)
1141         return NSNotFound;
1142     
1143     NSInteger columnIndex = tableCell->ariaColumnIndex();
1144     return columnIndex > 0 ? columnIndex : NSNotFound;
1145 }
1146
1147 - (NSRange)accessibilityRowRange
1148 {
1149     if (![self _prepareAccessibilityCall])
1150         return NSMakeRange(NSNotFound, 0);
1151
1152     if (m_object->isRadioButton()) {
1153         AccessibilityObject::AccessibilityChildrenVector radioButtonSiblings;
1154         m_object->linkedUIElements(radioButtonSiblings);
1155         if (radioButtonSiblings.size() <= 1)
1156             return NSMakeRange(NSNotFound, 0);
1157         
1158         return NSMakeRange(radioButtonSiblings.find(m_object), radioButtonSiblings.size());
1159     }
1160     
1161     AccessibilityTableCell* tableCell = [self tableCellParent];
1162     if (!tableCell)
1163         return NSMakeRange(NSNotFound, 0);
1164     
1165     std::pair<unsigned, unsigned> rowRange;
1166     tableCell->rowIndexRange(rowRange);
1167     return NSMakeRange(rowRange.first, rowRange.second);
1168 }
1169
1170 - (NSRange)accessibilityColumnRange
1171 {
1172     if (![self _prepareAccessibilityCall])
1173         return NSMakeRange(NSNotFound, 0);
1174
1175     AccessibilityTableCell* tableCell = [self tableCellParent];
1176     if (!tableCell)
1177         return NSMakeRange(NSNotFound, 0);
1178     
1179     std::pair<unsigned, unsigned> columnRange;
1180     tableCell->columnIndexRange(columnRange);
1181     return NSMakeRange(columnRange.first, columnRange.second);
1182 }
1183
1184 - (NSString *)accessibilityPlaceholderValue
1185 {
1186     if (![self _prepareAccessibilityCall])
1187         return nil;
1188
1189     return m_object->placeholderValue();
1190 }
1191
1192 - (NSString *)accessibilityValue
1193 {
1194     if (![self _prepareAccessibilityCall])
1195         return nil;
1196     
1197     // check if the value was overriden
1198     NSString *value = [super accessibilityValue];
1199     if (value)
1200         return value;
1201     
1202     if (m_object->isCheckboxOrRadio()) {
1203         switch (m_object->checkboxOrRadioValue()) {
1204         case ButtonStateOff:
1205             return [NSString stringWithFormat:@"%d", 0];
1206         case ButtonStateOn:
1207             return [NSString stringWithFormat:@"%d", 1];
1208         case ButtonStateMixed:
1209             return [NSString stringWithFormat:@"%d", 2];
1210         }
1211         ASSERT_NOT_REACHED();
1212         return [NSString stringWithFormat:@"%d", 0];
1213     }
1214     
1215     if (m_object->isButton() && m_object->isPressed())
1216         return [NSString stringWithFormat:@"%d", 1];
1217
1218     // rdar://8131388 WebKit should expose the same info as UIKit for its password fields.
1219     if (m_object->isPasswordField()) {
1220         int passwordLength = m_object->accessibilityPasswordFieldLength();
1221         NSMutableString* string = [NSMutableString string];
1222         for (int k = 0; k < passwordLength; ++k)
1223             [string appendString:@"•"];
1224         return string;
1225     }
1226     
1227     // A text control should return its text data as the axValue (per iPhone AX API).
1228     if (![self stringValueShouldBeUsedInLabel])
1229         return m_object->stringValue();
1230     
1231     if (m_object->isProgressIndicator() || m_object->isSlider()) {
1232         // Prefer a valueDescription if provided by the author (through aria-valuetext).
1233         String valueDescription = m_object->valueDescription();
1234         if (!valueDescription.isEmpty())
1235             return valueDescription;
1236
1237         return [NSString stringWithFormat:@"%.2f", m_object->valueForRange()];
1238     }
1239
1240     if (m_object->isHeading())
1241         return [NSString stringWithFormat:@"%d", m_object->headingLevel()];
1242     
1243     return nil;
1244 }
1245
1246 - (BOOL)accessibilityIsComboBox
1247 {
1248     if (![self _prepareAccessibilityCall])
1249         return NO;
1250
1251     return m_object->roleValue() == ComboBoxRole;
1252 }
1253
1254 - (NSString *)accessibilityHint
1255 {
1256     if (![self _prepareAccessibilityCall])
1257         return nil;
1258
1259     return [self baseAccessibilityHelpText];
1260 }
1261
1262 - (NSURL *)accessibilityURL
1263 {
1264     if (![self _prepareAccessibilityCall])
1265         return nil;
1266     
1267     URL url = m_object->url();
1268     if (url.isNull())
1269         return nil;
1270     return (NSURL*)url;
1271 }
1272
1273 - (CGPoint)_accessibilityConvertPointToViewSpace:(CGPoint)point
1274 {
1275     if (![self _prepareAccessibilityCall])
1276         return point;
1277     
1278     FloatPoint floatPoint = FloatPoint(point);
1279     return [self convertPointToScreenSpace:floatPoint];
1280 }
1281
1282 - (BOOL)_accessibilityScrollToVisible
1283 {
1284     if (![self _prepareAccessibilityCall])
1285         return NO;
1286     
1287     m_object->scrollToMakeVisible();
1288     return YES;
1289 }
1290
1291
1292 - (BOOL)accessibilityScroll:(UIAccessibilityScrollDirection)direction
1293 {
1294     if (![self _prepareAccessibilityCall])
1295         return NO;
1296     
1297     AccessibilityObject::ScrollByPageDirection scrollDirection;
1298     switch (direction) {
1299     case UIAccessibilityScrollDirectionRight:
1300         scrollDirection = AccessibilityObject::ScrollByPageDirection::Right;
1301         break;
1302     case UIAccessibilityScrollDirectionLeft:
1303         scrollDirection = AccessibilityObject::ScrollByPageDirection::Left;
1304         break;
1305     case UIAccessibilityScrollDirectionUp:
1306         scrollDirection = AccessibilityObject::ScrollByPageDirection::Up;
1307         break;
1308     case UIAccessibilityScrollDirectionDown:
1309         scrollDirection = AccessibilityObject::ScrollByPageDirection::Down;
1310         break;
1311     default:
1312         return NO;
1313     }
1314
1315     BOOL result = m_object->scrollByPage(scrollDirection);
1316     
1317     if (result) {
1318         [self postScrollStatusChangeNotification];
1319
1320         CGPoint scrollPos = [self _accessibilityScrollPosition];
1321         NSString *testString = [NSString stringWithFormat:@"AXScroll [position: %.2f %.2f]", scrollPos.x, scrollPos.y];
1322         [self accessibilityPostedNotification:@"AXScrollByPage" userInfo:@{ @"status" : testString }];
1323     }
1324     
1325     // This means that this object handled the scroll and no other ancestor should attempt scrolling.
1326     return result;
1327 }
1328
1329 - (CGPoint)convertPointToScreenSpace:(FloatPoint &)point
1330 {
1331     if (!m_object)
1332         return CGPointZero;
1333     
1334     CGPoint cgPoint = CGPointMake(point.x(), point.y());
1335     
1336     FrameView* frameView = m_object->documentFrameView();
1337     WAKView* documentView = frameView ? frameView->documentView() : nullptr;
1338     if (documentView) {
1339         cgPoint = [documentView convertPoint:cgPoint toView:nil];
1340
1341         // we need the web document view to give us our final screen coordinates
1342         // because that can take account of the scroller
1343         id webDocument = [self _accessibilityWebDocumentView];
1344         if (webDocument)
1345             cgPoint = [webDocument convertPoint:cgPoint toView:nil];
1346     }
1347     else {
1348         // Find the appropriate scroll view to use to convert the contents to the window.
1349         ScrollView* scrollView = nullptr;
1350         AccessibilityObject* parent = nullptr;
1351         for (parent = m_object->parentObject(); parent; parent = parent->parentObject()) {
1352             if (is<AccessibilityScrollView>(*parent)) {
1353                 scrollView = downcast<AccessibilityScrollView>(*parent).scrollView();
1354                 break;
1355             }
1356         }
1357         
1358         IntPoint intPoint = flooredIntPoint(point);
1359         if (scrollView)
1360             intPoint = scrollView->contentsToRootView(intPoint);
1361         
1362         Page* page = m_object->page();
1363         
1364         // If we have an empty chrome client (like SVG) then we should use the page
1365         // of the scroll view parent to help us get to the screen rect.
1366         if (parent && page && page->chrome().client().isEmptyChromeClient())
1367             page = parent->page();
1368         
1369         if (page) {
1370             IntRect rect = IntRect(intPoint, IntSize(0, 0));
1371             intPoint = page->chrome().rootViewToAccessibilityScreen(rect).location();
1372         }
1373         
1374         cgPoint = (CGPoint)intPoint;
1375     }
1376     
1377     return cgPoint;
1378 }
1379
1380 - (CGRect)convertRectToScreenSpace:(IntRect &)rect
1381 {
1382     if (!m_object)
1383         return CGRectZero;
1384     
1385     CGSize size = CGSizeMake(rect.size().width(), rect.size().height());
1386     CGPoint point = CGPointMake(rect.x(), rect.y());
1387     
1388     CGRect frame = CGRectMake(point.x, point.y, size.width, size.height);
1389     
1390     FrameView* frameView = m_object->documentFrameView();
1391     WAKView* documentView = frameView ? frameView->documentView() : nil;
1392     if (documentView) {
1393         frame = [documentView convertRect:frame toView:nil];
1394         
1395         // we need the web document view to give us our final screen coordinates
1396         // because that can take account of the scroller
1397         id webDocument = [self _accessibilityWebDocumentView];
1398         if (webDocument)
1399             frame = [webDocument convertRect:frame toView:nil];
1400         
1401     } else {
1402         // Find the appropriate scroll view to use to convert the contents to the window.
1403         ScrollView* scrollView = nullptr;
1404         AccessibilityObject* parent = nullptr;
1405         for (parent = m_object->parentObject(); parent; parent = parent->parentObject()) {
1406             if (is<AccessibilityScrollView>(*parent)) {
1407                 scrollView = downcast<AccessibilityScrollView>(*parent).scrollView();
1408                 break;
1409             }
1410         }
1411         
1412         if (scrollView)
1413             rect = scrollView->contentsToRootView(rect);
1414         
1415         Page* page = m_object->page();
1416         
1417         // If we have an empty chrome client (like SVG) then we should use the page
1418         // of the scroll view parent to help us get to the screen rect.
1419         if (parent && page && page->chrome().client().isEmptyChromeClient())
1420             page = parent->page();
1421         
1422         if (page)
1423             rect = page->chrome().rootViewToAccessibilityScreen(rect);
1424         
1425         frame = (CGRect)rect;
1426     }
1427     
1428     return frame;
1429 }
1430
1431 // Used by UIKit accessibility bundle to help determine distance during a hit-test.
1432 - (CGRect)accessibilityElementRect
1433 {
1434     if (![self _prepareAccessibilityCall])
1435         return CGRectZero;
1436     
1437     LayoutRect rect = m_object->elementRect();
1438     return CGRectMake(rect.x(), rect.y(), rect.width(), rect.height());
1439 }
1440
1441 // The "center point" is where VoiceOver will "press" an object. This may not be the actual
1442 // center of the accessibilityFrame
1443 - (CGPoint)accessibilityActivationPoint
1444 {
1445     if (![self _prepareAccessibilityCall])
1446         return CGPointZero;
1447     
1448     IntRect rect = snappedIntRect(m_object->boundingBoxRect());
1449     CGRect cgRect = [self convertRectToScreenSpace:rect];
1450     return CGPointMake(CGRectGetMidX(cgRect), CGRectGetMidY(cgRect));
1451 }
1452
1453 - (CGRect)accessibilityFrame
1454 {
1455     if (![self _prepareAccessibilityCall])
1456         return CGRectZero;
1457     
1458     IntRect rect = snappedIntRect(m_object->elementRect());
1459     return [self convertRectToScreenSpace:rect];
1460 }
1461
1462 // Checks whether a link contains only static text and images (and has been divided unnaturally by <spans> and other nefarious mechanisms).
1463 - (BOOL)containsUnnaturallySegmentedChildren
1464 {
1465     if (!m_object)
1466         return NO;
1467     
1468     AccessibilityRole role = m_object->roleValue();
1469     if (role != LinkRole && role != WebCoreLinkRole)
1470         return NO;
1471     
1472     const auto& children = m_object->children();
1473     unsigned childrenSize = children.size();
1474
1475     // If there's only one child, then it doesn't have segmented children. 
1476     if (childrenSize == 1)
1477         return NO;
1478     
1479     for (unsigned i = 0; i < childrenSize; ++i) {
1480         AccessibilityRole role = children[i]->roleValue();
1481         if (role != StaticTextRole && role != ImageRole && role != GroupRole)
1482             return NO;
1483     }
1484     
1485     return YES;
1486 }
1487
1488 - (id)accessibilityContainer
1489 {
1490     if (![self _prepareAccessibilityCall])
1491         return nil;
1492
1493     AXAttributeCacheEnabler enableCache(m_object->axObjectCache());
1494     
1495     // As long as there's a parent wrapper, that's the correct chain to climb.
1496     AccessibilityObject* parent = m_object->parentObjectUnignored(); 
1497     if (parent)
1498         return parent->wrapper();
1499
1500     // Mock objects can have their parents detached but still exist in the cache.
1501     if (m_object->isDetachedFromParent())
1502         return nil;
1503     
1504     // The only object without a parent wrapper at this point should be a scroll view.
1505     ASSERT(m_object->isAccessibilityScrollView());
1506     
1507     // Verify this is the top document. If not, we might need to go through the platform widget.
1508     FrameView* frameView = m_object->documentFrameView();
1509     Document* document = m_object->document();
1510     if (document && frameView && document != &document->topDocument())
1511         return frameView->platformWidget();
1512     
1513     // The top scroll view's parent is the web document view.
1514     return [self _accessibilityWebDocumentView];
1515 }
1516
1517 - (id)accessibilityFocusedUIElement
1518 {
1519     if (![self _prepareAccessibilityCall])
1520         return nil;
1521     
1522     AccessibilityObject* focusedObj = m_object->focusedUIElement();
1523     
1524     if (!focusedObj)
1525         return nil;
1526     
1527     return focusedObj->wrapper();
1528 }
1529
1530 - (id)_accessibilityWebDocumentView
1531 {
1532     if (![self _prepareAccessibilityCall])
1533         return nil;
1534
1535     // This method performs the crucial task of connecting to the UIWebDocumentView.
1536     // This is needed to correctly calculate the screen position of the AX object.
1537     static Class webViewClass = nil;
1538     if (!webViewClass)
1539         webViewClass = NSClassFromString(@"WebView");
1540
1541     if (!webViewClass)
1542         return nil;
1543     
1544     FrameView* frameView = m_object->documentFrameView();
1545
1546     if (!frameView)
1547         return nil;
1548     
1549     // If this is the top level frame, the UIWebDocumentView should be returned.
1550     id parentView = frameView->documentView();
1551     while (parentView && ![parentView isKindOfClass:webViewClass])
1552         parentView = [parentView superview];
1553     
1554     // The parentView should have an accessibilityContainer, if the UIKit accessibility bundle was loaded. 
1555     // The exception is DRT, which tests accessibility without the entire system turning accessibility on. Hence,
1556     // this check should be valid for everything except DRT.
1557     ASSERT([parentView accessibilityContainer] || IOSApplication::isDumpRenderTree());
1558     
1559     return [parentView accessibilityContainer];
1560 }
1561
1562 - (NSArray *)_accessibilityNextElementsWithCount:(UInt32)count
1563 {    
1564     if (![self _prepareAccessibilityCall])
1565         return nil;
1566     
1567     return [[self _accessibilityWebDocumentView] _accessibilityNextElementsWithCount:count];
1568 }
1569
1570 - (NSArray *)_accessibilityPreviousElementsWithCount:(UInt32)count
1571 {
1572     if (![self _prepareAccessibilityCall])
1573         return nil;
1574     
1575     return [[self _accessibilityWebDocumentView] _accessibilityPreviousElementsWithCount:count];
1576 }
1577
1578 - (BOOL)accessibilityCanSetValue
1579 {
1580     if (![self _prepareAccessibilityCall])
1581         return NO;
1582     
1583     return m_object->canSetValueAttribute();
1584 }
1585
1586 - (BOOL)accessibilityRequired
1587 {
1588     if (![self _prepareAccessibilityCall])
1589         return NO;
1590
1591     return m_object->isRequired();
1592 }
1593
1594 - (NSArray *)accessibilityFlowToElements
1595 {
1596     if (![self _prepareAccessibilityCall])
1597         return nil;
1598     
1599     AccessibilityObject::AccessibilityChildrenVector children;
1600     m_object->ariaFlowToElements(children);
1601     
1602     unsigned length = children.size();
1603     NSMutableArray* array = [NSMutableArray arrayWithCapacity:length];
1604     for (unsigned i = 0; i < length; ++i) {
1605         AccessibilityObjectWrapper* wrapper = children[i]->wrapper();
1606         ASSERT(wrapper);
1607         if (!wrapper)
1608             continue;
1609
1610         if (children[i]->isAttachment() && [wrapper attachmentView])
1611             [array addObject:[wrapper attachmentView]];
1612         else
1613             [array addObject:wrapper];
1614     }
1615     return array;
1616 }
1617
1618 - (id)accessibilityLinkedElement
1619 {
1620     if (![self _prepareAccessibilityCall])
1621         return nil;
1622     
1623     // If this static text inside of a link, it should use its parent's linked element.
1624     AccessibilityObject* element = m_object;
1625     if (m_object->roleValue() == StaticTextRole && m_object->parentObjectUnignored()->isLink())
1626         element = m_object->parentObjectUnignored();
1627     
1628     AccessibilityObject::AccessibilityChildrenVector children;
1629     element->linkedUIElements(children);
1630     if (children.size() == 0)
1631         return nil;
1632     
1633     return children[0]->wrapper();
1634 }
1635
1636
1637 - (BOOL)isAttachment
1638 {
1639     if (!m_object)
1640         return NO;
1641     
1642     return m_object->isAttachment();
1643 }
1644
1645 - (void)_accessibilityActivate
1646 {
1647     if (![self _prepareAccessibilityCall])
1648         return;
1649
1650     m_object->press();
1651 }
1652
1653 - (id)attachmentView
1654 {
1655     if (![self _prepareAccessibilityCall])
1656         return nil;
1657
1658     ASSERT([self isAttachment]);
1659     Widget* widget = m_object->widgetForAttachmentView();
1660     if (!widget)
1661         return nil;
1662     return widget->platformWidget();    
1663 }
1664
1665 static RenderObject* rendererForView(WAKView* view)
1666 {
1667     if (![view conformsToProtocol:@protocol(WebCoreFrameView)])
1668         return nil;
1669     
1670     WAKView<WebCoreFrameView>* frameView = (WAKView<WebCoreFrameView>*)view;
1671     Frame* frame = [frameView _web_frame];
1672     if (!frame)
1673         return nil;
1674     
1675     Node* node = frame->document()->ownerElement();
1676     if (!node)
1677         return nil;
1678     
1679     return node->renderer();
1680 }
1681
1682 - (id)_accessibilityParentForSubview:(id)subview
1683 {   
1684     RenderObject* renderer = rendererForView(subview);
1685     if (!renderer)
1686         return nil;
1687     
1688     AccessibilityObject* obj = renderer->document().axObjectCache()->getOrCreate(renderer);
1689     if (obj)
1690         return obj->parentObjectUnignored()->wrapper();
1691     return nil;
1692 }
1693
1694 - (void)postFocusChangeNotification
1695 {
1696     // The UIKit accessibility wrapper will override and post appropriate notification.
1697 }
1698
1699 - (void)postSelectedTextChangeNotification
1700 {
1701     // The UIKit accessibility wrapper will override and post appropriate notification.    
1702 }
1703
1704 - (void)postLayoutChangeNotification
1705 {
1706     // The UIKit accessibility wrapper will override and post appropriate notification.        
1707 }
1708
1709 - (void)postLiveRegionChangeNotification
1710 {
1711     // The UIKit accessibility wrapper will override and post appropriate notification.    
1712 }
1713
1714 - (void)postLiveRegionCreatedNotification
1715 {
1716     // The UIKit accessibility wrapper will override and post appropriate notification.    
1717 }
1718
1719 - (void)postLoadCompleteNotification
1720 {
1721     // The UIKit accessibility wrapper will override and post appropriate notification.    
1722 }
1723
1724 - (void)postChildrenChangedNotification
1725 {
1726     // The UIKit accessibility wrapper will override and post appropriate notification.    
1727 }
1728
1729 - (void)postInvalidStatusChangedNotification
1730 {
1731     // The UIKit accessibility wrapper will override and post appropriate notification.        
1732 }
1733
1734 - (void)postValueChangedNotification
1735 {
1736     // The UIKit accessibility wrapper will override and post appropriate notification.
1737 }
1738
1739 - (void)postExpandedChangedNotification
1740 {
1741     // The UIKit accessibility wrapper will override and post appropriate notification.
1742 }
1743
1744 - (void)postScrollStatusChangeNotification
1745 {
1746     // The UIKit accessibility wrapper will override and post appropriate notification.
1747 }
1748
1749 // These will be used by the UIKit wrapper to calculate an appropriate description of scroll status.
1750 - (CGPoint)_accessibilityScrollPosition
1751 {
1752     if (![self _prepareAccessibilityCall])
1753         return CGPointZero;
1754     
1755     return m_object->scrollPosition();
1756 }
1757
1758 - (CGSize)_accessibilityScrollSize
1759 {
1760     if (![self _prepareAccessibilityCall])
1761         return CGSizeZero;
1762     
1763     return m_object->scrollContentsSize();
1764 }
1765
1766 - (CGRect)_accessibilityScrollVisibleRect
1767 {
1768     if (![self _prepareAccessibilityCall])
1769         return CGRectZero;
1770     
1771     return m_object->scrollVisibleContentRect();
1772 }
1773
1774 - (void)accessibilityElementDidBecomeFocused
1775 {
1776     if (![self _prepareAccessibilityCall])
1777         return;
1778     
1779     // The focused VoiceOver element might be the text inside a link.
1780     // In those cases we should focus on the link itself.
1781     for (AccessibilityObject* object = m_object; object != nil; object = object->parentObject()) {
1782         if (object->roleValue() == WebAreaRole)
1783             break;
1784
1785         if (object->canSetFocusAttribute()) {
1786             object->setFocused(true);
1787             break;
1788         }
1789     }
1790 }
1791
1792 - (void)accessibilityModifySelection:(TextGranularity)granularity increase:(BOOL)increase
1793 {
1794     if (![self _prepareAccessibilityCall])
1795         return;
1796     
1797     FrameSelection& frameSelection = m_object->document()->frame()->selection();
1798     VisibleSelection selection = m_object->selection();
1799     VisiblePositionRange range = m_object->visiblePositionRange();
1800     
1801     // Before a selection with length exists, the cursor position needs to move to the right starting place.
1802     // That should be the beginning of this element (range.start). However, if the cursor is already within the 
1803     // range of this element (the cursor is represented by selection), then the cursor does not need to move.
1804     if (frameSelection.isNone() && (selection.visibleStart() < range.start || selection.visibleEnd() > range.end))
1805         frameSelection.moveTo(range.start, UserTriggered);
1806     
1807     frameSelection.modify(FrameSelection::AlterationExtend, (increase) ? DirectionRight : DirectionLeft, granularity, UserTriggered);
1808 }
1809
1810 - (void)accessibilityIncreaseSelection:(TextGranularity)granularity
1811 {
1812     [self accessibilityModifySelection:granularity increase:YES];
1813 }
1814
1815 - (void)accessibilityDecreaseSelection:(TextGranularity)granularity
1816 {
1817     [self accessibilityModifySelection:granularity increase:NO];
1818 }
1819
1820 - (void)accessibilityMoveSelectionToMarker:(WebAccessibilityTextMarker *)marker
1821 {
1822     if (![self _prepareAccessibilityCall])
1823         return;
1824     
1825     VisiblePosition visiblePosition = [marker visiblePosition];
1826     if (visiblePosition.isNull())
1827         return;
1828
1829     FrameSelection& frameSelection = m_object->document()->frame()->selection();
1830     frameSelection.moveTo(visiblePosition, UserTriggered);
1831 }
1832
1833 - (void)accessibilityIncrement
1834 {
1835     if (![self _prepareAccessibilityCall])
1836         return;
1837
1838     m_object->increment();
1839 }
1840
1841 - (void)accessibilityDecrement
1842 {
1843     if (![self _prepareAccessibilityCall])
1844         return;
1845
1846     m_object->decrement();
1847 }
1848
1849 #pragma mark Accessibility Text Marker Handlers
1850
1851 - (BOOL)_addAccessibilityObject:(AccessibilityObject*)axObject toTextMarkerArray:(NSMutableArray *)array
1852 {
1853     if (!axObject)
1854         return NO;
1855     
1856     AccessibilityObjectWrapper* wrapper = axObject->wrapper();
1857     if (!wrapper)
1858         return NO;
1859
1860     // Don't add the same object twice, but since this has already been added, we should return
1861     // YES because we want to inform that it's in the array
1862     if ([array containsObject:wrapper])
1863         return YES;
1864     
1865     // Explicity set that this is now an element (in case other logic tries to override).
1866     [wrapper setValue:[NSNumber numberWithBool:YES] forKey:@"isAccessibilityElement"];    
1867     [array addObject:wrapper];
1868     return YES;
1869 }
1870
1871 - (void)_accessibilitySetValue:(NSString *)string
1872 {
1873     if (![self _prepareAccessibilityCall])
1874         return;
1875     m_object->setValue(string);
1876 }
1877
1878 - (NSString *)stringForTextMarkers:(NSArray *)markers
1879 {
1880     if (![self _prepareAccessibilityCall])
1881         return nil;
1882     
1883     RefPtr<Range> range = [self rangeForTextMarkers:markers];
1884     if (!range)
1885         return nil;
1886     
1887     return m_object->stringForRange(range);
1888 }
1889
1890 static int blockquoteLevel(RenderObject* renderer)
1891 {
1892     if (!renderer)
1893         return 0;
1894     
1895     int result = 0;
1896     for (Node* node = renderer->node(); node; node = node->parentNode()) {
1897         if (node->hasTagName(blockquoteTag))
1898             result += 1;
1899     }
1900     
1901     return result;
1902 }
1903
1904 static void AXAttributeStringSetLanguage(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
1905 {
1906     if (!renderer)
1907         return;
1908     
1909     AccessibilityObject* axObject = renderer->document().axObjectCache()->getOrCreate(renderer);
1910     NSString *language = axObject->language();
1911     if ([language length])
1912         [attrString addAttribute:UIAccessibilityTokenLanguage value:language range:range];
1913     else
1914         [attrString removeAttribute:UIAccessibilityTokenLanguage range:range];
1915 }
1916
1917 static void AXAttributeStringSetBlockquoteLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
1918 {
1919     int quoteLevel = blockquoteLevel(renderer);
1920     
1921     if (quoteLevel)
1922         [attrString addAttribute:UIAccessibilityTokenBlockquoteLevel value:[NSNumber numberWithInt:quoteLevel] range:range];
1923     else
1924         [attrString removeAttribute:UIAccessibilityTokenBlockquoteLevel range:range];
1925 }
1926
1927 static void AXAttributeStringSetHeadingLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
1928 {
1929     if (!renderer)
1930         return;
1931     
1932     AccessibilityObject* parentObject = renderer->document().axObjectCache()->getOrCreate(renderer->parent());
1933     int parentHeadingLevel = parentObject->headingLevel();
1934     
1935     if (parentHeadingLevel)
1936         [attrString addAttribute:UIAccessibilityTokenHeadingLevel value:[NSNumber numberWithInt:parentHeadingLevel] range:range];
1937     else
1938         [attrString removeAttribute:UIAccessibilityTokenHeadingLevel range:range];
1939 }
1940
1941 static void AXAttributeStringSetFont(NSMutableAttributedString* attrString, CTFontRef font, NSRange range)
1942 {
1943     if (!font)
1944         return;
1945     
1946     RetainPtr<CFStringRef> fullName = adoptCF(CTFontCopyFullName(font));
1947     RetainPtr<CFStringRef> familyName = adoptCF(CTFontCopyFamilyName(font));
1948
1949     NSNumber* size = [NSNumber numberWithFloat:CTFontGetSize(font)];
1950     CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(font);
1951     NSNumber* bold = [NSNumber numberWithBool:(traits & kCTFontTraitBold)];
1952     if (fullName)
1953         [attrString addAttribute:UIAccessibilityTokenFontName value:(NSString*)fullName.get() range:range];
1954     if (familyName)
1955         [attrString addAttribute:UIAccessibilityTokenFontFamily value:(NSString*)familyName.get() range:range];
1956     if ([size boolValue])
1957         [attrString addAttribute:UIAccessibilityTokenFontSize value:size range:range];
1958     if ([bold boolValue] || (traits & kCTFontTraitBold))
1959         [attrString addAttribute:UIAccessibilityTokenBold value:[NSNumber numberWithBool:YES] range:range];
1960     if (traits & kCTFontTraitItalic)
1961         [attrString addAttribute:UIAccessibilityTokenItalic value:[NSNumber numberWithBool:YES] range:range];
1962
1963 }
1964
1965 static void AXAttributeStringSetNumber(NSMutableAttributedString* attrString, NSString* attribute, NSNumber* number, NSRange range)
1966 {
1967     if (number)
1968         [attrString addAttribute:attribute value:number range:range];
1969     else
1970         [attrString removeAttribute:attribute range:range];
1971 }
1972
1973 static void AXAttributeStringSetStyle(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
1974 {
1975     RenderStyle& style = renderer->style();
1976     
1977     // set basic font info
1978     AXAttributeStringSetFont(attrString, style.fontCascade().primaryFont().getCTFont(), range);
1979                 
1980     int decor = style.textDecorationsInEffect();
1981     if ((decor & (TextDecorationUnderline | TextDecorationLineThrough)) != 0) {
1982         Color underlineColor, overlineColor, linethroughColor;
1983         TextDecorationStyle underlineStyle, overlineStyle, linethroughStyle;
1984         renderer->getTextDecorationColorsAndStyles(decor, underlineColor, overlineColor, linethroughColor, underlineStyle, overlineStyle, linethroughStyle);
1985         
1986         if (decor & TextDecorationUnderline)
1987             AXAttributeStringSetNumber(attrString, UIAccessibilityTokenUnderline, [NSNumber numberWithBool:YES], range);
1988     }
1989 }
1990
1991 static void AXAttributedStringAppendText(NSMutableAttributedString* attrString, Node* node, NSString *text)
1992 {
1993     // skip invisible text
1994     if (!node->renderer())
1995         return;
1996     
1997     // easier to calculate the range before appending the string
1998     NSRange attrStringRange = NSMakeRange([attrString length], [text length]);
1999     
2000     // append the string from this node
2001     [[attrString mutableString] appendString:text];
2002     
2003     // set new attributes
2004     AXAttributeStringSetStyle(attrString, node->renderer(), attrStringRange);
2005     AXAttributeStringSetHeadingLevel(attrString, node->renderer(), attrStringRange);
2006     AXAttributeStringSetBlockquoteLevel(attrString, node->renderer(), attrStringRange);    
2007     AXAttributeStringSetLanguage(attrString, node->renderer(), attrStringRange);
2008 }
2009
2010
2011 // This method is intended to return an array of strings and accessibility elements that 
2012 // represent the objects on one line of rendered web content. The array of markers sent
2013 // in should be ordered and contain only a start and end marker.
2014 - (NSArray *)arrayOfTextForTextMarkers:(NSArray *)markers attributed:(BOOL)attributed
2015 {
2016     if (![self _prepareAccessibilityCall])
2017         return nil;
2018
2019     if ([markers count] != 2)
2020         return nil;
2021     
2022     WebAccessibilityTextMarker* startMarker = [markers objectAtIndex:0];
2023     WebAccessibilityTextMarker* endMarker = [markers objectAtIndex:1];
2024     if (![startMarker isKindOfClass:[WebAccessibilityTextMarker class]] || ![endMarker isKindOfClass:[WebAccessibilityTextMarker class]])
2025         return nil;
2026     
2027     // extract the start and end VisiblePosition
2028     VisiblePosition startVisiblePosition = [startMarker visiblePosition];
2029     if (startVisiblePosition.isNull())
2030         return nil;
2031     
2032     VisiblePosition endVisiblePosition = [endMarker visiblePosition];
2033     if (endVisiblePosition.isNull())
2034         return nil;
2035     
2036     // iterate over the range to build the AX attributed string
2037     NSMutableArray* array = [[NSMutableArray alloc] init];
2038     TextIterator it(makeRange(startVisiblePosition, endVisiblePosition).get());
2039     for (; !it.atEnd(); it.advance()) {
2040         // locate the node and starting offset for this range
2041         Node& node = it.range()->startContainer();
2042         ASSERT(&node == &it.range()->endContainer());
2043         int offset = it.range()->startOffset();
2044         
2045         // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
2046         if (it.text().length() != 0) {
2047             if (!attributed) {
2048                 // First check if this is represented by a link.
2049                 AccessibilityObject* linkObject = AccessibilityObject::anchorElementForNode(&node);
2050                 if ([self _addAccessibilityObject:linkObject toTextMarkerArray:array])
2051                     continue;
2052                 
2053                 // Next check if this region is represented by a heading.
2054                 AccessibilityObject* headingObject = AccessibilityObject::headingElementForNode(&node);
2055                 if ([self _addAccessibilityObject:headingObject toTextMarkerArray:array])
2056                     continue;
2057                 
2058                 String listMarkerText = m_object->listMarkerTextForNodeAndPosition(&node, VisiblePosition(it.range()->startPosition()));
2059                 
2060                 if (!listMarkerText.isEmpty()) 
2061                     [array addObject:listMarkerText];
2062                 // There was not an element representation, so just return the text.
2063                 [array addObject:it.text().createNSString().get()];
2064             }
2065             else
2066             {
2067                 String listMarkerText = m_object->listMarkerTextForNodeAndPosition(&node, VisiblePosition(it.range()->startPosition()));
2068
2069                 if (!listMarkerText.isEmpty()) {
2070                     NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] init];
2071                     AXAttributedStringAppendText(attrString, &node, listMarkerText);
2072                     [array addObject:attrString];
2073                     [attrString release];
2074                 }
2075                 
2076                 NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] init];
2077                 AXAttributedStringAppendText(attrString, &node, it.text().createNSStringWithoutCopying().get());
2078                 [array addObject:attrString];
2079                 [attrString release];
2080             }
2081         } else {
2082             Node* replacedNode = node.traverseToChildAt(offset);
2083             if (replacedNode) {
2084                 AccessibilityObject* obj = m_object->axObjectCache()->getOrCreate(replacedNode->renderer());
2085                 if (obj && !obj->accessibilityIsIgnored())
2086                     [self _addAccessibilityObject:obj toTextMarkerArray:array];
2087             }
2088         }
2089     }
2090     
2091     return [array autorelease];
2092 }
2093
2094 - (NSRange)_convertToNSRange:(Range *)range
2095 {
2096     if (!range)
2097         return NSMakeRange(NSNotFound, 0);
2098     
2099     Document* document = m_object->document();
2100     Element* selectionRoot = document->frame()->selection().selection().rootEditableElement();
2101     Element* scope = selectionRoot ? selectionRoot : document->documentElement();
2102     
2103     // Mouse events may cause TSM to attempt to create an NSRange for a portion of the view
2104     // that is not inside the current editable region.  These checks ensure we don't produce
2105     // potentially invalid data when responding to such requests.
2106     if (&range->startContainer() != scope && !range->startContainer().isDescendantOf(scope))
2107         return NSMakeRange(NSNotFound, 0);
2108     if (&range->endContainer() != scope && !range->endContainer().isDescendantOf(scope))
2109         return NSMakeRange(NSNotFound, 0);
2110     
2111     RefPtr<Range> testRange = Range::create(scope->document(), scope, 0, &range->startContainer(), range->startOffset());
2112     ASSERT(&testRange->startContainer() == scope);
2113     int startPosition = TextIterator::rangeLength(testRange.get());
2114     
2115     ExceptionCode ec;
2116     testRange->setEnd(&range->endContainer(), range->endOffset(), ec);
2117     ASSERT(&testRange->startContainer() == scope);
2118     int endPosition = TextIterator::rangeLength(testRange.get());
2119     return NSMakeRange(startPosition, endPosition - startPosition);
2120 }
2121
2122 - (RefPtr<Range>)_convertToDOMRange:(NSRange)nsrange
2123 {
2124     if (nsrange.location > INT_MAX)
2125         return nullptr;
2126     if (nsrange.length > INT_MAX || nsrange.location + nsrange.length > INT_MAX)
2127         nsrange.length = INT_MAX - nsrange.location;
2128         
2129     // our critical assumption is that we are only called by input methods that
2130     // concentrate on a given area containing the selection
2131     // We have to do this because of text fields and textareas. The DOM for those is not
2132     // directly in the document DOM, so serialization is problematic. Our solution is
2133     // to use the root editable element of the selection start as the positional base.
2134     // That fits with AppKit's idea of an input context.
2135     Document* document = m_object->document();
2136     Element* selectionRoot = document->frame()->selection().selection().rootEditableElement();
2137     Element* scope = selectionRoot ? selectionRoot : document->documentElement();
2138     return TextIterator::rangeFromLocationAndLength(scope, nsrange.location, nsrange.length);
2139 }
2140
2141 // This method is intended to take a text marker representing a VisiblePosition and convert it
2142 // into a normalized location within the document.
2143 - (NSInteger)positionForTextMarker:(WebAccessibilityTextMarker *)marker
2144 {
2145     if (![self _prepareAccessibilityCall])
2146         return NSNotFound;
2147
2148     if (!marker)
2149         return NSNotFound;    
2150
2151     if (AXObjectCache* cache = m_object->axObjectCache()) {
2152         CharacterOffset characterOffset = [marker characterOffset];
2153         // Create a collapsed range from the CharacterOffset object.
2154         RefPtr<Range> range = cache->rangeForUnorderedCharacterOffsets(characterOffset, characterOffset);
2155         NSRange nsRange = [self _convertToNSRange:range.get()];
2156         return nsRange.location;
2157     }
2158     return NSNotFound;
2159 }
2160
2161 - (NSArray *)textMarkerRange
2162 {
2163     if (![self _prepareAccessibilityCall])
2164         return nil;
2165     
2166     RefPtr<Range> range = m_object->elementRange();
2167     return [self textMarkersForRange:range];
2168 }
2169
2170 // A method to get the normalized text cursor range of an element. Used in DumpRenderTree.
2171 - (NSRange)elementTextRange
2172 {
2173     if (![self _prepareAccessibilityCall])
2174         return NSMakeRange(NSNotFound, 0);
2175
2176     NSArray *markers = [self textMarkerRange];
2177     if ([markers count] != 2)
2178         return NSMakeRange(NSNotFound, 0);
2179     
2180     WebAccessibilityTextMarker *startMarker = [markers objectAtIndex:0];
2181     WebAccessibilityTextMarker *endMarker = [markers objectAtIndex:1];
2182     
2183     NSInteger startPosition = [self positionForTextMarker:startMarker];
2184     NSInteger endPosition = [self positionForTextMarker:endMarker];
2185     
2186     return NSMakeRange(startPosition, endPosition - startPosition);
2187 }
2188
2189 - (AccessibilityObjectWrapper *)accessibilityObjectForTextMarker:(WebAccessibilityTextMarker *)marker
2190 {
2191     if (![self _prepareAccessibilityCall])
2192         return nil;
2193
2194     if (!marker)
2195         return nil;
2196     
2197     AccessibilityObject* obj = [marker accessibilityObject];
2198     if (!obj)
2199         return nil;
2200     
2201     return AccessibilityUnignoredAncestor(obj->wrapper());
2202 }
2203
2204 - (NSArray *)textMarkerRangeForSelection
2205 {
2206     if (![self _prepareAccessibilityCall])
2207         return nil;
2208     
2209     VisibleSelection selection = m_object->selection();
2210     if (selection.isNone())
2211         return nil;
2212     
2213     AXObjectCache* cache = m_object->axObjectCache();
2214     if (!cache)
2215         return nil;
2216     
2217     RefPtr<Range> range = selection.toNormalizedRange();
2218     CharacterOffset start = cache->startOrEndCharacterOffsetForRange(range, true);
2219     CharacterOffset end = cache->startOrEndCharacterOffsetForRange(range, false);
2220
2221     WebAccessibilityTextMarker* startMarker = [WebAccessibilityTextMarker textMarkerWithCharacterOffset:start cache:cache];
2222     WebAccessibilityTextMarker* endMarker = [WebAccessibilityTextMarker textMarkerWithCharacterOffset:end cache:cache];
2223     if (!startMarker || !endMarker)
2224         return nil;
2225     
2226     return [NSArray arrayWithObjects:startMarker, endMarker, nil];
2227 }
2228
2229 - (WebAccessibilityTextMarker *)textMarkerForPosition:(NSInteger)position
2230 {
2231     if (![self _prepareAccessibilityCall])
2232         return nil;
2233
2234     RefPtr<Range> range = [self _convertToDOMRange:NSMakeRange(position, 0)];
2235     if (!range)
2236         return nil;
2237
2238     AXObjectCache* cache = m_object->axObjectCache();
2239     if (!cache)
2240         return nil;
2241     
2242     CharacterOffset characterOffset = cache->startOrEndCharacterOffsetForRange(range, true);
2243     return [WebAccessibilityTextMarker textMarkerWithCharacterOffset:characterOffset cache:cache];
2244 }
2245
2246 - (id)_stringForRange:(NSRange)range attributed:(BOOL)attributed
2247 {
2248     if (![self _prepareAccessibilityCall])
2249         return nil;
2250     
2251     WebAccessibilityTextMarker* startMarker = [self textMarkerForPosition:range.location];
2252     WebAccessibilityTextMarker* endMarker = [self textMarkerForPosition:NSMaxRange(range)];
2253     
2254     // Clients don't always know the exact range, rather than force them to compute it,
2255     // allow clients to overshoot and use the max text marker range.
2256     if (!startMarker || !endMarker) {
2257         NSArray *markers = [self textMarkerRange];
2258         if ([markers count] != 2)
2259             return nil;
2260         if (!startMarker)
2261             startMarker = [markers objectAtIndex:0];
2262         if (!endMarker)
2263             endMarker = [markers objectAtIndex:1];
2264     }
2265     
2266     NSArray* array = [self arrayOfTextForTextMarkers:[NSArray arrayWithObjects:startMarker, endMarker, nil] attributed:attributed];
2267     Class returnClass = attributed ? [NSMutableAttributedString class] : [NSMutableString class];
2268     id returnValue = [[(NSString *)[returnClass alloc] init] autorelease];
2269     
2270     NSInteger count = [array count];
2271     for (NSInteger k = 0; k < count; ++k) {
2272         id object = [array objectAtIndex:k];
2273
2274         if (![object isKindOfClass:returnClass])
2275             continue;
2276         
2277         if (attributed)
2278             [(NSMutableAttributedString *)returnValue appendAttributedString:object];
2279         else
2280             [(NSMutableString *)returnValue appendString:object];
2281     }
2282     return returnValue;
2283 }
2284
2285
2286 // A convenience method for getting the text of a NSRange. Currently used only by DRT.
2287 - (NSString *)stringForRange:(NSRange)range
2288 {
2289     return [self _stringForRange:range attributed:NO];
2290 }
2291
2292 - (NSAttributedString *)attributedStringForRange:(NSRange)range
2293 {
2294     return [self _stringForRange:range attributed:YES];
2295 }
2296
2297 - (NSRange)_accessibilitySelectedTextRange
2298 {
2299     if (![self _prepareAccessibilityCall] || !m_object->isTextControl())
2300         return NSMakeRange(NSNotFound, 0);
2301     
2302     PlainTextRange textRange = m_object->selectedTextRange();
2303     if (textRange.isNull())
2304         return NSMakeRange(NSNotFound, 0);
2305     return NSMakeRange(textRange.start, textRange.length);    
2306 }
2307
2308 - (void)_accessibilitySetSelectedTextRange:(NSRange)range
2309 {
2310     if (![self _prepareAccessibilityCall] || !m_object->isTextControl())
2311         return;
2312     
2313     m_object->setSelectedTextRange(PlainTextRange(range.location, range.length));
2314 }
2315
2316 // A convenience method for getting the accessibility objects of a NSRange. Currently used only by DRT.
2317 - (NSArray *)elementsForRange:(NSRange)range
2318 {
2319     if (![self _prepareAccessibilityCall])
2320         return nil;
2321     
2322     WebAccessibilityTextMarker* startMarker = [self textMarkerForPosition:range.location];
2323     WebAccessibilityTextMarker* endMarker = [self textMarkerForPosition:NSMaxRange(range)];
2324     if (!startMarker || !endMarker)
2325         return nil;
2326     
2327     NSArray* array = [self arrayOfTextForTextMarkers:[NSArray arrayWithObjects:startMarker, endMarker, nil] attributed:NO];
2328     NSMutableArray* elements = [NSMutableArray array];
2329     for (id element in array) {
2330         if (![element isKindOfClass:[AccessibilityObjectWrapper class]])
2331             continue;
2332         [elements addObject:element];
2333     }
2334     return elements;
2335 }
2336
2337 - (NSString *)selectionRangeString
2338 {
2339     NSArray *markers = [self textMarkerRangeForSelection];
2340     return [self stringForTextMarkers:markers];
2341 }
2342
2343 - (WebAccessibilityTextMarker *)selectedTextMarker
2344 {
2345     if (![self _prepareAccessibilityCall])
2346         return nil;
2347     
2348     VisibleSelection selection = m_object->selection();
2349     VisiblePosition position = selection.visibleStart();
2350     
2351     // if there's no selection, start at the top of the document
2352     if (position.isNull())
2353         position = startOfDocument(m_object->document());
2354     
2355     return [WebAccessibilityTextMarker textMarkerWithVisiblePosition:position cache:m_object->axObjectCache()];
2356 }
2357
2358 // This method is intended to return the marker at the end of the line starting at
2359 // the marker that is passed into the method.
2360 - (WebAccessibilityTextMarker *)lineEndMarkerForMarker:(WebAccessibilityTextMarker *)marker
2361 {
2362     if (![self _prepareAccessibilityCall])
2363         return nil;
2364
2365     if (!marker)
2366         return nil;
2367     
2368     VisiblePosition start = [marker visiblePosition];
2369     VisiblePosition lineEnd = m_object->nextLineEndPosition(start);
2370     
2371     return [WebAccessibilityTextMarker textMarkerWithVisiblePosition:lineEnd cache:m_object->axObjectCache()];
2372 }
2373
2374 // This method is intended to return the marker at the start of the line starting at
2375 // the marker that is passed into the method.
2376 - (WebAccessibilityTextMarker *)lineStartMarkerForMarker:(WebAccessibilityTextMarker *)marker
2377 {
2378     if (![self _prepareAccessibilityCall])
2379         return nil;
2380
2381     if (!marker)
2382         return nil;
2383     
2384     VisiblePosition start = [marker visiblePosition];
2385     VisiblePosition lineStart = m_object->previousLineStartPosition(start);
2386     
2387     return [WebAccessibilityTextMarker textMarkerWithVisiblePosition:lineStart cache:m_object->axObjectCache()];
2388 }
2389
2390 - (WebAccessibilityTextMarker *)nextMarkerForMarker:(WebAccessibilityTextMarker *)marker
2391 {
2392     if (![self _prepareAccessibilityCall])
2393         return nil;
2394
2395     if (!marker)
2396         return nil;
2397     
2398     CharacterOffset start = [marker characterOffset];
2399     return [self nextMarkerForCharacterOffset:start];
2400 }
2401
2402 - (WebAccessibilityTextMarker *)previousMarkerForMarker:(WebAccessibilityTextMarker *)marker
2403 {
2404     if (![self _prepareAccessibilityCall])
2405         return nil;
2406
2407     if (!marker)
2408         return nil;
2409     
2410     CharacterOffset start = [marker characterOffset];
2411     return [self previousMarkerForCharacterOffset:start];
2412 }
2413
2414 // This method is intended to return the bounds of a text marker range in screen coordinates.
2415 - (CGRect)frameForTextMarkers:(NSArray *)array
2416 {
2417     if (![self _prepareAccessibilityCall])
2418         return CGRectZero;
2419
2420     AXObjectCache* cache = m_object->axObjectCache();
2421     if (!cache)
2422         return CGRectZero;
2423     RefPtr<Range> range = [self rangeForTextMarkers:array];
2424     if (!range)
2425         return CGRectZero;
2426     
2427     IntRect rect = m_object->boundsForRange(range);
2428     return [self convertRectToScreenSpace:rect];
2429 }
2430
2431 - (WebAccessibilityTextMarker *)textMarkerForPoint:(CGPoint)point
2432 {
2433     if (![self _prepareAccessibilityCall])
2434         return nil;
2435     
2436     AXObjectCache* cache = m_object->axObjectCache();
2437     if (!cache)
2438         return nil;
2439     CharacterOffset characterOffset = cache->characterOffsetForPoint(IntPoint(point), m_object);
2440     return [WebAccessibilityTextMarker textMarkerWithCharacterOffset:characterOffset cache:cache];
2441 }
2442
2443 - (WebAccessibilityTextMarker *)nextMarkerForCharacterOffset:(CharacterOffset&)characterOffset
2444 {
2445     AXObjectCache* cache = m_object->axObjectCache();
2446     if (!cache)
2447         return nil;
2448     
2449     TextMarkerData textMarkerData;
2450     cache->textMarkerDataForNextCharacterOffset(textMarkerData, characterOffset);
2451     if (!textMarkerData.axID)
2452         return nil;
2453     return [[[WebAccessibilityTextMarker alloc] initWithTextMarker:&textMarkerData cache:cache] autorelease];
2454 }
2455
2456 - (WebAccessibilityTextMarker *)previousMarkerForCharacterOffset:(CharacterOffset&)characterOffset
2457 {
2458     AXObjectCache* cache = m_object->axObjectCache();
2459     if (!cache)
2460         return nil;
2461     
2462     TextMarkerData textMarkerData;
2463     cache->textMarkerDataForPreviousCharacterOffset(textMarkerData, characterOffset);
2464     if (!textMarkerData.axID)
2465         return nil;
2466     return [[[WebAccessibilityTextMarker alloc] initWithTextMarker:&textMarkerData cache:cache] autorelease];
2467 }
2468
2469 - (RefPtr<Range>)rangeForTextMarkers:(NSArray *)textMarkers
2470 {
2471     if ([textMarkers count] != 2)
2472         return nullptr;
2473     
2474     WebAccessibilityTextMarker *startMarker = [textMarkers objectAtIndex:0];
2475     WebAccessibilityTextMarker *endMarker = [textMarkers objectAtIndex:1];
2476     
2477     if (![startMarker isKindOfClass:[WebAccessibilityTextMarker class]] || ![endMarker isKindOfClass:[WebAccessibilityTextMarker class]])
2478         return nullptr;
2479     
2480     AXObjectCache* cache = m_object->axObjectCache();
2481     if (!cache)
2482         return nullptr;
2483     
2484     CharacterOffset startCharacterOffset = [startMarker characterOffset];
2485     CharacterOffset endCharacterOffset = [endMarker characterOffset];
2486     return cache->rangeForUnorderedCharacterOffsets(startCharacterOffset, endCharacterOffset);
2487 }
2488
2489 - (NSInteger)lengthForTextMarkers:(NSArray *)textMarkers
2490 {
2491     if (![self _prepareAccessibilityCall])
2492         return 0;
2493     
2494     RefPtr<Range> range = [self rangeForTextMarkers:textMarkers];
2495     int length = AXObjectCache::lengthForRange(range.get());
2496     return length < 0 ? 0 : length;
2497 }
2498
2499 - (WebAccessibilityTextMarker *)startOrEndTextMarkerForTextMarkers:(NSArray *)textMarkers isStart:(BOOL)isStart
2500 {
2501     if (![self _prepareAccessibilityCall])
2502         return nil;
2503     
2504     RefPtr<Range> range = [self rangeForTextMarkers:textMarkers];
2505     if (!range)
2506         return nil;
2507     
2508     return [WebAccessibilityTextMarker startOrEndTextMarkerForRange:range isStart:isStart cache:m_object->axObjectCache()];
2509 }
2510
2511 - (NSArray *)textMarkerRangeForMarkers:(NSArray *)textMarkers
2512 {
2513     if (![self _prepareAccessibilityCall])
2514         return nil;
2515     
2516     RefPtr<Range> range = [self rangeForTextMarkers:textMarkers];
2517     return [self textMarkersForRange:range];
2518 }
2519
2520 - (NSArray *)textMarkersForRange:(RefPtr<Range>)range
2521 {
2522     if (!range)
2523         return nil;
2524     
2525     WebAccessibilityTextMarker* start = [WebAccessibilityTextMarker startOrEndTextMarkerForRange:range isStart:YES cache:m_object->axObjectCache()];
2526     WebAccessibilityTextMarker* end = [WebAccessibilityTextMarker startOrEndTextMarkerForRange:range isStart:NO cache:m_object->axObjectCache()];
2527     if (!start || !end)
2528         return nil;
2529     return [NSArray arrayWithObjects:start, end, nil];
2530 }
2531
2532 - (NSString *)accessibilityIdentifier
2533 {
2534     if (![self _prepareAccessibilityCall])
2535         return nil;
2536     
2537     return m_object->getAttribute(HTMLNames::idAttr);
2538 }
2539
2540 - (NSString *)accessibilitySpeechHint
2541 {
2542     if (![self _prepareAccessibilityCall])
2543         return nil;
2544
2545     switch (m_object->speakProperty()) {
2546     default:
2547     case SpeakNormal:
2548         return @"normal";
2549     case SpeakNone:
2550         return @"none";
2551     case SpeakSpellOut:
2552         return @"spell-out";
2553     case SpeakDigits:
2554         return @"digits";
2555     case SpeakLiteralPunctuation:
2556         return @"literal-punctuation";
2557     case SpeakNoPunctuation:
2558         return @"no-punctuation";
2559     }
2560     
2561     return nil;
2562 }
2563
2564 - (BOOL)accessibilityARIAIsBusy
2565 {
2566     if (![self _prepareAccessibilityCall])
2567         return NO;
2568
2569     return m_object->ariaLiveRegionBusy();
2570 }
2571
2572 - (NSString *)accessibilityARIALiveRegionStatus
2573 {
2574     if (![self _prepareAccessibilityCall])
2575         return nil;
2576
2577     return m_object->ariaLiveRegionStatus();
2578 }
2579
2580 - (NSString *)accessibilityARIARelevantStatus
2581 {
2582     if (![self _prepareAccessibilityCall])
2583         return nil;
2584     
2585     return m_object->ariaLiveRegionRelevant();
2586 }
2587
2588 - (BOOL)accessibilityARIALiveRegionIsAtomic
2589 {
2590     if (![self _prepareAccessibilityCall])
2591         return NO;
2592     
2593     return m_object->ariaLiveRegionAtomic();
2594 }
2595
2596 - (BOOL)accessibilitySupportsARIAPressed
2597 {
2598     if (![self _prepareAccessibilityCall])
2599         return NO;
2600     
2601     return m_object->supportsARIAPressed();
2602 }
2603
2604 - (BOOL)accessibilityIsPressed
2605 {
2606     if (![self _prepareAccessibilityCall])
2607         return NO;
2608     
2609     return m_object->isPressed();
2610 }
2611
2612 - (BOOL)accessibilitySupportsARIAExpanded
2613 {
2614     if (![self _prepareAccessibilityCall])
2615         return NO;
2616     
2617     return m_object->supportsExpanded();
2618 }
2619
2620 - (BOOL)accessibilityIsExpanded
2621 {
2622     if (![self _prepareAccessibilityCall])
2623         return NO;
2624
2625     return m_object->isExpanded();
2626 }
2627
2628 - (NSString *)accessibilityInvalidStatus
2629 {
2630     if (![self _prepareAccessibilityCall])
2631         return nil;
2632     
2633     return m_object->invalidStatus();
2634 }
2635
2636 - (NSString *)accessibilityARIACurrentStatus
2637 {
2638     if (![self _prepareAccessibilityCall])
2639         return nil;
2640     
2641     switch (m_object->ariaCurrentState()) {
2642     case ARIACurrentFalse:
2643         return @"false";
2644     case ARIACurrentPage:
2645         return @"page";
2646     case ARIACurrentStep:
2647         return @"step";
2648     case ARIACurrentLocation:
2649         return @"location";
2650     case ARIACurrentTime:
2651         return @"time";
2652     case ARIACurrentDate:
2653         return @"date";
2654     default:
2655     case ARIACurrentTrue:
2656         return @"true";
2657     }
2658 }
2659
2660 - (WebAccessibilityObjectWrapper *)accessibilityMathRootIndexObject
2661 {
2662     if (![self _prepareAccessibilityCall])
2663         return nil;
2664
2665     return m_object->mathRootIndexObject() ? m_object->mathRootIndexObject()->wrapper() : 0;
2666 }
2667
2668 - (WebAccessibilityObjectWrapper *)accessibilityMathRadicandObject
2669 {
2670     if (![self _prepareAccessibilityCall])
2671         return nil;
2672
2673     return m_object->mathRadicandObject() ? m_object->mathRadicandObject()->wrapper() : 0;
2674 }
2675
2676 - (WebAccessibilityObjectWrapper *)accessibilityMathNumeratorObject
2677 {
2678     if (![self _prepareAccessibilityCall])
2679         return nil;
2680
2681     return m_object->mathNumeratorObject() ? m_object->mathNumeratorObject()->wrapper() : 0;
2682 }
2683
2684 - (WebAccessibilityObjectWrapper *)accessibilityMathDenominatorObject
2685 {
2686     if (![self _prepareAccessibilityCall])
2687         return nil;
2688
2689     return m_object->mathDenominatorObject() ? m_object->mathDenominatorObject()->wrapper() : 0;
2690 }
2691
2692 - (WebAccessibilityObjectWrapper *)accessibilityMathBaseObject
2693 {
2694     if (![self _prepareAccessibilityCall])
2695         return nil;
2696
2697     return m_object->mathBaseObject() ? m_object->mathBaseObject()->wrapper() : 0;
2698 }
2699
2700 - (WebAccessibilityObjectWrapper *)accessibilityMathSubscriptObject
2701 {
2702     if (![self _prepareAccessibilityCall])
2703         return nil;
2704
2705     return m_object->mathSubscriptObject() ? m_object->mathSubscriptObject()->wrapper() : 0;
2706 }
2707
2708 - (WebAccessibilityObjectWrapper *)accessibilityMathSuperscriptObject
2709 {
2710     if (![self _prepareAccessibilityCall])
2711         return nil;
2712
2713     return m_object->mathSuperscriptObject() ? m_object->mathSuperscriptObject()->wrapper() : 0;
2714 }
2715
2716 - (WebAccessibilityObjectWrapper *)accessibilityMathUnderObject
2717 {
2718     if (![self _prepareAccessibilityCall])
2719         return nil;
2720
2721     return m_object->mathUnderObject() ? m_object->mathUnderObject()->wrapper() : 0;
2722 }
2723
2724 - (WebAccessibilityObjectWrapper *)accessibilityMathOverObject
2725 {
2726     if (![self _prepareAccessibilityCall])
2727         return nil;
2728
2729     return m_object->mathOverObject() ? m_object->mathOverObject()->wrapper() : 0;
2730 }
2731
2732 - (NSString *)accessibilityPlatformMathSubscriptKey
2733 {
2734     return @"AXMSubscriptObject";
2735 }
2736
2737 - (NSString *)accessibilityPlatformMathSuperscriptKey
2738 {
2739     return @"AXMSuperscriptObject";
2740 }
2741
2742 - (NSArray *)accessibilityMathPostscripts
2743 {
2744     if (![self _prepareAccessibilityCall])
2745         return nil;
2746     
2747     return [self accessibilityMathPostscriptPairs];
2748 }
2749
2750 - (NSArray *)accessibilityMathPrescripts
2751 {
2752     if (![self _prepareAccessibilityCall])
2753         return nil;
2754     
2755     return [self accessibilityMathPrescriptPairs];
2756 }
2757
2758 - (NSString *)accessibilityMathFencedOpenString
2759 {
2760     if (![self _prepareAccessibilityCall])
2761         return nil;
2762
2763     return m_object->mathFencedOpenString();
2764 }
2765
2766 - (NSString *)accessibilityMathFencedCloseString
2767 {
2768     if (![self _prepareAccessibilityCall])
2769         return nil;
2770
2771     return m_object->mathFencedCloseString();
2772 }
2773
2774 - (BOOL)accessibilityIsMathTopObject
2775 {
2776     if (![self _prepareAccessibilityCall])
2777         return NO;
2778
2779     return m_object->roleValue() == DocumentMathRole;
2780 }
2781
2782 - (NSInteger)accessibilityMathLineThickness
2783 {
2784     if (![self _prepareAccessibilityCall])
2785         return 0;
2786
2787     return m_object->mathLineThickness();
2788 }
2789
2790 - (NSString *)accessibilityMathType
2791 {
2792     if (![self _prepareAccessibilityCall])
2793         return nil;
2794
2795     if (m_object->roleValue() == MathElementRole) {
2796         if (m_object->isMathFraction())
2797             return @"AXMathFraction";
2798         if (m_object->isMathFenced())
2799             return @"AXMathFenced";
2800         if (m_object->isMathSubscriptSuperscript())
2801             return @"AXMathSubscriptSuperscript";
2802         if (m_object->isMathRow())
2803             return @"AXMathRow";
2804         if (m_object->isMathUnderOver())
2805             return @"AXMathUnderOver";
2806         if (m_object->isMathSquareRoot())
2807             return @"AXMathSquareRoot";
2808         if (m_object->isMathRoot())
2809             return @"AXMathRoot";
2810         if (m_object->isMathText())
2811             return @"AXMathText";
2812         if (m_object->isMathNumber())
2813             return @"AXMathNumber";
2814         if (m_object->isMathIdentifier())
2815             return @"AXMathIdentifier";
2816         if (m_object->isMathTable())
2817             return @"AXMathTable";
2818         if (m_object->isMathTableRow())
2819             return @"AXMathTableRow";
2820         if (m_object->isMathTableCell())
2821             return @"AXMathTableCell";
2822         if (m_object->isMathFenceOperator())
2823             return @"AXMathFenceOperator";
2824         if (m_object->isMathSeparatorOperator())
2825             return @"AXMathSeparatorOperator";
2826         if (m_object->isMathOperator())
2827             return @"AXMathOperator";
2828         if (m_object->isMathMultiscript())
2829             return @"AXMathMultiscript";
2830     }
2831     
2832     return nil;
2833 }
2834
2835 - (CGPoint)accessibilityClickPoint
2836 {
2837     return m_object->clickPoint();
2838 }
2839
2840 #ifndef NDEBUG
2841 - (NSString *)description
2842 {
2843     CGRect frame = [self accessibilityFrame];
2844     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];
2845 }
2846 #endif
2847
2848 @end
2849
2850 #endif // HAVE(ACCESSIBILITY) && PLATFORM(IOS)