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