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