d40c97e47d7fb9106c79b118f9a5196921f6d7a8
[WebKit-https.git] / Source / WebCore / accessibility / ios / WebAccessibilityObjectWrapperIOS.mm
1 /*
2  * Copyright (C) 2008, 2015 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "WebAccessibilityObjectWrapperIOS.h"
28
29 #if HAVE(ACCESSIBILITY) && PLATFORM(IOS)
30
31 #import "AccessibilityRenderObject.h"
32 #import "AccessibilityScrollView.h"
33 #import "AccessibilityTable.h"
34 #import "AccessibilityTableCell.h"
35 #import "Chrome.h"
36 #import "ChromeClient.h"
37 #import "FontCascade.h"
38 #import "Frame.h"
39 #import "FrameSelection.h"
40 #import "FrameView.h"
41 #import "HitTestResult.h"
42 #import "HTMLFrameOwnerElement.h"
43 #import "HTMLInputElement.h"
44 #import "HTMLNames.h"
45 #import "IntRect.h"
46 #import "IntSize.h"
47 #import "LocalizedStrings.h"
48 #import "Page.h"
49 #import "Range.h"
50 #import "RenderView.h"
51 #import "RuntimeApplicationChecksIOS.h"
52 #import "SVGNames.h"
53 #import "SVGElement.h"
54 #import "TextIterator.h"
55 #import "WAKScrollView.h"
56 #import "WAKView.h"
57 #import "WAKWindow.h"
58 #import "WebCoreThread.h"
59 #import "VisibleUnits.h"
60
61 #import <CoreText/CoreText.h>
62
63 @interface NSObject (AccessibilityPrivate)
64 - (void)_accessibilityUnregister;
65 - (NSString *)accessibilityLabel;
66 - (NSString *)accessibilityValue;
67 - (BOOL)isAccessibilityElement;
68 - (NSInteger)accessibilityElementCount;
69 - (id)accessibilityElementAtIndex:(NSInteger)index;
70 - (NSInteger)indexOfAccessibilityElement:(id)element;
71 @end
72
73 @interface WebAccessibilityObjectWrapper (AccessibilityPrivate)
74 - (id)_accessibilityWebDocumentView;
75 - (id)accessibilityContainer;
76 - (void)setAccessibilityLabel:(NSString *)label;
77 - (void)setAccessibilityValue:(NSString *)value;
78 - (BOOL)containsUnnaturallySegmentedChildren;
79 - (NSInteger)positionForTextMarker:(id)marker;
80 @end
81
82 @interface WAKView (iOSAccessibility)
83 - (BOOL)accessibilityIsIgnored;
84 @end
85
86 using namespace WebCore;
87 using namespace HTMLNames;
88
89 typedef NS_ENUM(NSInteger, UIAccessibilityScrollDirection) {
90     UIAccessibilityScrollDirectionRight = 1,
91     UIAccessibilityScrollDirectionLeft,
92     UIAccessibilityScrollDirectionUp,
93     UIAccessibilityScrollDirectionDown,
94     UIAccessibilityScrollDirectionNext,
95     UIAccessibilityScrollDirectionPrevious
96 };
97
98 // These are tokens accessibility uses to denote attributes. 
99 static NSString * const UIAccessibilityTokenBlockquoteLevel = @"UIAccessibilityTokenBlockquoteLevel";
100 static NSString * const UIAccessibilityTokenHeadingLevel = @"UIAccessibilityTokenHeadingLevel";
101 static NSString * const UIAccessibilityTokenFontName = @"UIAccessibilityTokenFontName";
102 static NSString * const UIAccessibilityTokenFontFamily = @"UIAccessibilityTokenFontFamily";
103 static NSString * const UIAccessibilityTokenFontSize = @"UIAccessibilityTokenFontSize";
104 static NSString * const UIAccessibilityTokenBold = @"UIAccessibilityTokenBold";
105 static NSString * const UIAccessibilityTokenItalic = @"UIAccessibilityTokenItalic";
106 static NSString * const UIAccessibilityTokenUnderline = @"UIAccessibilityTokenUnderline";
107 static NSString * const UIAccessibilityTokenLanguage = @"UIAccessibilityTokenLanguage";
108
109 static AccessibilityObjectWrapper* AccessibilityUnignoredAncestor(AccessibilityObjectWrapper *wrapper)
110 {
111     while (wrapper && ![wrapper isAccessibilityElement]) {
112         AccessibilityObject* object = [wrapper accessibilityObject];
113         if (!object)
114             break;
115         
116         if ([wrapper isAttachment] && ![[wrapper attachmentView] accessibilityIsIgnored])
117             break;
118             
119         AccessibilityObject* parentObject = object->parentObjectUnignored();
120         if (!parentObject)
121             break;
122
123         wrapper = parentObject->wrapper();
124     }
125     return wrapper;
126 }
127
128 #pragma mark Accessibility Text Marker
129
130 @interface WebAccessibilityTextMarker : NSObject
131 {
132     AXObjectCache* _cache;
133     TextMarkerData _textMarkerData;
134 }
135
136 + (WebAccessibilityTextMarker *)textMarkerWithVisiblePosition:(VisiblePosition&)visiblePos cache:(AXObjectCache*)cache;
137 + (WebAccessibilityTextMarker *)textMarkerWithCharacterOffset:(CharacterOffset&)characterOffset cache:(AXObjectCache*)cache;
138 + (WebAccessibilityTextMarker *)startOrEndTextMarkerForRange:(const RefPtr<Range>)range isStart:(BOOL)isStart cache:(AXObjectCache*)cache;
139
140 @end
141
142 @implementation WebAccessibilityTextMarker
143
144 - (id)initWithTextMarker:(TextMarkerData *)data cache:(AXObjectCache*)cache
145 {
146     if (!(self = [super init]))
147         return nil;
148     
149     _cache = cache;
150     memcpy(&_textMarkerData, data, sizeof(TextMarkerData));
151     return self;
152 }
153
154 - (id)initWithData:(NSData *)data cache:(AXObjectCache*)cache
155 {
156     if (!(self = [super init]))
157         return nil;
158     
159     _cache = cache;
160     [data getBytes:&_textMarkerData length:sizeof(TextMarkerData)];
161     
162     return self;
163 }
164
165 // This is needed for external clients to be able to create a text marker without having a pointer to the cache.
166 - (id)initWithData:(NSData *)data accessibilityObject:(AccessibilityObjectWrapper *)wrapper
167 {
168     WebCore::AccessibilityObject* axObject = [wrapper accessibilityObject]; 
169     if (!axObject)
170         return nil;
171     
172     return [self initWithData:data cache:axObject->axObjectCache()];
173 }
174
175 + (WebAccessibilityTextMarker *)textMarkerWithVisiblePosition:(VisiblePosition&)visiblePos cache:(AXObjectCache*)cache
176 {
177     TextMarkerData textMarkerData;
178     cache->textMarkerDataForVisiblePosition(textMarkerData, visiblePos);
179     
180     return [[[WebAccessibilityTextMarker alloc] initWithTextMarker:&textMarkerData cache:cache] autorelease];
181 }
182
183 + (WebAccessibilityTextMarker *)textMarkerWithCharacterOffset:(CharacterOffset&)characterOffset cache:(AXObjectCache*)cache
184 {
185     if (!cache)
186         return nil;
187     
188     if (characterOffset.isNull())
189         return nil;
190     
191     TextMarkerData textMarkerData;
192     cache->textMarkerDataForCharacterOffset(textMarkerData, *characterOffset.node, characterOffset.offset, false);
193     if (!textMarkerData.axID && !textMarkerData.ignored)
194         return nil;
195     return [[[WebAccessibilityTextMarker alloc] initWithTextMarker:&textMarkerData cache:cache] autorelease];
196 }
197
198 + (WebAccessibilityTextMarker *)startOrEndTextMarkerForRange:(const RefPtr<Range>)range isStart:(BOOL)isStart cache:(AXObjectCache*)cache
199 {
200     if (!cache)
201         return nil;
202     
203     TextMarkerData textMarkerData;
204     cache->startOrEndTextMarkerDataForRange(textMarkerData, range, isStart);
205     if (!textMarkerData.axID)
206         return nil;
207     return [[[WebAccessibilityTextMarker alloc] initWithTextMarker:&textMarkerData cache:cache] autorelease];
208 }
209
210 - (NSData *)dataRepresentation
211 {
212     return [NSData dataWithBytes:&_textMarkerData length:sizeof(TextMarkerData)];
213 }
214
215 - (VisiblePosition)visiblePosition
216 {
217     return _cache->visiblePositionForTextMarkerData(_textMarkerData);
218 }
219
220 - (CharacterOffset)characterOffset
221 {
222     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 TabGroupRole:
861         case TabListRole:
862         case TabPanelRole:
863         case TableRole:
864         case TableHeaderContainerRole:
865         case TreeRole:
866         case TreeItemRole:
867         case TreeGridRole:
868         case ToolbarRole:
869         case UnknownRole:
870         case UserInterfaceTooltipRole:
871         case VideoRole:
872         case WebAreaRole:
873         case WindowRole:
874         case RowGroupRole:
875             return false;
876     }
877     
878     ASSERT_NOT_REACHED();
879     return false;
880 }
881
882 - (BOOL)isAccessibilityElement
883 {
884     if (![self _prepareAccessibilityCall])
885         return NO;
886     
887     if (m_isAccessibilityElement == -1)
888         m_isAccessibilityElement = [self determineIsAccessibilityElement];
889     
890     return m_isAccessibilityElement;
891 }
892
893 - (BOOL)stringValueShouldBeUsedInLabel
894 {
895     if (m_object->isTextControl())
896         return NO;
897     if (m_object->roleValue() == PopUpButtonRole)
898         return NO;
899     if (m_object->isFileUploadButton())
900         return NO;
901
902     return YES;
903 }
904
905 - (BOOL)fileUploadButtonReturnsValueInTitle
906 {
907     return NO;
908 }
909
910 static void appendStringToResult(NSMutableString *result, NSString *string)
911 {
912     ASSERT(result);
913     if (![string length])
914         return;
915     if ([result length])
916         [result appendString:@", "];
917     [result appendString:string];
918 }
919
920 - (BOOL)_accessibilityValueIsAutofilled
921 {
922     if (![self _prepareAccessibilityCall])
923         return NO;
924
925     return m_object->isValueAutofilled();
926 }
927
928 - (CGFloat)_accessibilityMinValue
929 {
930     return m_object->minValueForRange();
931 }
932
933 - (CGFloat)_accessibilityMaxValue
934 {
935     return m_object->maxValueForRange();
936 }
937
938 - (NSString *)accessibilityRoleDescription
939 {
940     return m_object->roleDescription();
941 }
942
943 - (NSString *)accessibilityLabel
944 {
945     if (![self _prepareAccessibilityCall])
946         return nil;
947
948     // check if the label was overriden
949     NSString *label = [super accessibilityLabel];
950     if (label)
951         return label;
952
953     // iOS doesn't distinguish between a title and description field,
954     // so concatentation will yield the best result.
955     NSString *axTitle = [self baseAccessibilityTitle];
956     NSString *axDescription = [self baseAccessibilityDescription];
957     NSString *landmarkDescription = [self ariaLandmarkRoleDescription];
958     
959     NSMutableString *result = [NSMutableString string];
960     if (m_object->roleValue() == HorizontalRuleRole)
961         appendStringToResult(result, AXHorizontalRuleDescriptionText());
962         
963     appendStringToResult(result, axTitle);
964     appendStringToResult(result, axDescription);
965     if ([self stringValueShouldBeUsedInLabel]) {
966         NSString *valueLabel = m_object->stringValue();
967         valueLabel = [valueLabel stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
968         appendStringToResult(result, valueLabel);
969     }
970     appendStringToResult(result, landmarkDescription);
971     
972     return [result length] ? result : nil;
973 }
974
975 - (AccessibilityTableCell*)tableCellParent
976 {
977     // Find if this element is in a table cell.
978     AccessibilityObject* cell = nullptr;
979     for (cell = m_object; cell && !cell->isTableCell(); cell = cell->parentObject()) 
980     { }
981     
982     if (!cell)
983         return nil;
984
985     return static_cast<AccessibilityTableCell*>(cell);
986 }
987
988 - (AccessibilityTable*)tableParent
989 {
990     // Find if the parent table for the table cell.
991     AccessibilityObject* parentTable = nullptr;
992     for (parentTable = m_object; parentTable && !(is<AccessibilityTable>(*parentTable) && downcast<AccessibilityTable>(*parentTable).isExposableThroughAccessibility()); parentTable = parentTable->parentObject())
993     { }
994     
995     if (!parentTable)
996         return nil;
997     
998     return static_cast<AccessibilityTable*>(parentTable);
999 }
1000
1001 - (id)accessibilityTitleElement
1002 {
1003     if (![self _prepareAccessibilityCall])
1004         return nil;
1005
1006     AccessibilityObject* titleElement = m_object->titleUIElement();
1007     if (titleElement)
1008         return titleElement->wrapper();
1009
1010     return nil;
1011 }
1012
1013 // Meant to return row or column headers (or other things as the future permits).
1014 - (NSArray *)accessibilityHeaderElements
1015 {
1016     if (![self _prepareAccessibilityCall])
1017         return nil;
1018
1019     AccessibilityTableCell* tableCell = [self tableCellParent];
1020     if (!tableCell)
1021         return nil;
1022     
1023     AccessibilityTable* table = [self tableParent];
1024     if (!table)
1025         return nil;
1026     
1027     // Get the row and column range, so we can use them to find the headers.
1028     std::pair<unsigned, unsigned> rowRange;
1029     std::pair<unsigned, unsigned> columnRange;
1030     tableCell->rowIndexRange(rowRange);
1031     tableCell->columnIndexRange(columnRange);
1032     
1033     AccessibilityObject::AccessibilityChildrenVector rowHeaders;
1034     AccessibilityObject::AccessibilityChildrenVector columnHeaders;
1035     table->rowHeaders(rowHeaders);
1036     table->columnHeaders(columnHeaders);
1037     
1038     NSMutableArray *headers = [NSMutableArray array];
1039     
1040     unsigned columnRangeIndex = static_cast<unsigned>(columnRange.first);
1041     if (columnRangeIndex < columnHeaders.size()) {
1042         RefPtr<AccessibilityObject> columnHeader = columnHeaders[columnRange.first];
1043         AccessibilityObjectWrapper* wrapper = columnHeader->wrapper();
1044         if (wrapper)
1045             [headers addObject:wrapper];
1046     }
1047
1048     unsigned rowRangeIndex = static_cast<unsigned>(rowRange.first);
1049     if (rowRangeIndex < rowHeaders.size()) {
1050         RefPtr<AccessibilityObject> rowHeader = rowHeaders[rowRange.first];
1051         AccessibilityObjectWrapper* wrapper = rowHeader->wrapper();
1052         if (wrapper)
1053             [headers addObject:wrapper];
1054     }
1055         
1056     return headers;
1057 }
1058
1059 - (id)accessibilityElementForRow:(NSInteger)row andColumn:(NSInteger)column
1060 {
1061     if (![self _prepareAccessibilityCall])
1062         return nil;
1063
1064     AccessibilityTable* table = [self tableParent];
1065     if (!table)
1066         return nil;
1067
1068     AccessibilityTableCell* cell = table->cellForColumnAndRow(column, row);
1069     if (!cell)
1070         return nil;
1071     return cell->wrapper();
1072 }
1073
1074 - (NSUInteger)accessibilityRowCount
1075 {
1076     if (![self _prepareAccessibilityCall])
1077         return 0;
1078     AccessibilityTable *table = [self tableParent];
1079     if (!table)
1080         return 0;
1081     
1082     return table->rowCount();
1083 }
1084
1085 - (NSUInteger)accessibilityColumnCount
1086 {
1087     if (![self _prepareAccessibilityCall])
1088         return 0;
1089     AccessibilityTable *table = [self tableParent];
1090     if (!table)
1091         return 0;
1092     
1093     return table->columnCount();
1094 }
1095
1096 - (NSUInteger)accessibilityARIARowCount
1097 {
1098     if (![self _prepareAccessibilityCall])
1099         return 0;
1100     AccessibilityTable *table = [self tableParent];
1101     if (!table)
1102         return 0;
1103     
1104     NSInteger rowCount = table->ariaRowCount();
1105     return rowCount > 0 ? rowCount : 0;
1106 }
1107
1108 - (NSUInteger)accessibilityARIAColumnCount
1109 {
1110     if (![self _prepareAccessibilityCall])
1111         return 0;
1112     AccessibilityTable *table = [self tableParent];
1113     if (!table)
1114         return 0;
1115     
1116     NSInteger colCount = table->ariaColumnCount();
1117     return colCount > 0 ? colCount : 0;
1118 }
1119
1120 - (NSUInteger)accessibilityARIARowIndex
1121 {
1122     if (![self _prepareAccessibilityCall])
1123         return NSNotFound;
1124     AccessibilityTableCell* tableCell = [self tableCellParent];
1125     if (!tableCell)
1126         return NSNotFound;
1127     
1128     NSInteger rowIndex = tableCell->ariaRowIndex();
1129     return rowIndex > 0 ? rowIndex : NSNotFound;
1130 }
1131
1132 - (NSUInteger)accessibilityARIAColumnIndex
1133 {
1134     if (![self _prepareAccessibilityCall])
1135         return NSNotFound;
1136     AccessibilityTableCell* tableCell = [self tableCellParent];
1137     if (!tableCell)
1138         return NSNotFound;
1139     
1140     NSInteger columnIndex = tableCell->ariaColumnIndex();
1141     return columnIndex > 0 ? columnIndex : NSNotFound;
1142 }
1143
1144 - (NSRange)accessibilityRowRange
1145 {
1146     if (![self _prepareAccessibilityCall])
1147         return NSMakeRange(NSNotFound, 0);
1148
1149     if (m_object->isRadioButton()) {
1150         AccessibilityObject::AccessibilityChildrenVector radioButtonSiblings;
1151         m_object->linkedUIElements(radioButtonSiblings);
1152         if (radioButtonSiblings.size() <= 1)
1153             return NSMakeRange(NSNotFound, 0);
1154         
1155         return NSMakeRange(radioButtonSiblings.find(m_object), radioButtonSiblings.size());
1156     }
1157     
1158     AccessibilityTableCell* tableCell = [self tableCellParent];
1159     if (!tableCell)
1160         return NSMakeRange(NSNotFound, 0);
1161     
1162     std::pair<unsigned, unsigned> rowRange;
1163     tableCell->rowIndexRange(rowRange);
1164     return NSMakeRange(rowRange.first, rowRange.second);
1165 }
1166
1167 - (NSRange)accessibilityColumnRange
1168 {
1169     if (![self _prepareAccessibilityCall])
1170         return NSMakeRange(NSNotFound, 0);
1171
1172     AccessibilityTableCell* tableCell = [self tableCellParent];
1173     if (!tableCell)
1174         return NSMakeRange(NSNotFound, 0);
1175     
1176     std::pair<unsigned, unsigned> columnRange;
1177     tableCell->columnIndexRange(columnRange);
1178     return NSMakeRange(columnRange.first, columnRange.second);
1179 }
1180
1181 - (NSString *)accessibilityPlaceholderValue
1182 {
1183     if (![self _prepareAccessibilityCall])
1184         return nil;
1185
1186     return m_object->placeholderValue();
1187 }
1188
1189 - (NSString *)accessibilityValue
1190 {
1191     if (![self _prepareAccessibilityCall])
1192         return nil;
1193     
1194     // check if the value was overriden
1195     NSString *value = [super accessibilityValue];
1196     if (value)
1197         return value;
1198     
1199     if (m_object->isCheckboxOrRadio()) {
1200         switch (m_object->checkboxOrRadioValue()) {
1201         case ButtonStateOff:
1202             return [NSString stringWithFormat:@"%d", 0];
1203         case ButtonStateOn:
1204             return [NSString stringWithFormat:@"%d", 1];
1205         case ButtonStateMixed:
1206             return [NSString stringWithFormat:@"%d", 2];
1207         }
1208         ASSERT_NOT_REACHED();
1209         return [NSString stringWithFormat:@"%d", 0];
1210     }
1211     
1212     if (m_object->isButton() && m_object->isPressed())
1213         return [NSString stringWithFormat:@"%d", 1];
1214
1215     // rdar://8131388 WebKit should expose the same info as UIKit for its password fields.
1216     if (m_object->isPasswordField()) {
1217         int passwordLength = m_object->accessibilityPasswordFieldLength();
1218         NSMutableString* string = [NSMutableString string];
1219         for (int k = 0; k < passwordLength; ++k)
1220             [string appendString:@"•"];
1221         return string;
1222     }
1223     
1224     // A text control should return its text data as the axValue (per iPhone AX API).
1225     if (![self stringValueShouldBeUsedInLabel])
1226         return m_object->stringValue();
1227     
1228     if (m_object->isProgressIndicator() || m_object->isSlider()) {
1229         // Prefer a valueDescription if provided by the author (through aria-valuetext).
1230         String valueDescription = m_object->valueDescription();
1231         if (!valueDescription.isEmpty())
1232             return valueDescription;
1233
1234         return [NSString stringWithFormat:@"%.2f", m_object->valueForRange()];
1235     }
1236
1237     if (m_object->isHeading())
1238         return [NSString stringWithFormat:@"%d", m_object->headingLevel()];
1239     
1240     return nil;
1241 }
1242
1243 - (BOOL)accessibilityIsComboBox
1244 {
1245     if (![self _prepareAccessibilityCall])
1246         return NO;
1247
1248     return m_object->roleValue() == ComboBoxRole;
1249 }
1250
1251 - (NSString *)accessibilityHint
1252 {
1253     if (![self _prepareAccessibilityCall])
1254         return nil;
1255
1256     return [self baseAccessibilityHelpText];
1257 }
1258
1259 - (NSURL *)accessibilityURL
1260 {
1261     if (![self _prepareAccessibilityCall])
1262         return nil;
1263     
1264     URL url = m_object->url();
1265     if (url.isNull())
1266         return nil;
1267     return (NSURL*)url;
1268 }
1269
1270 - (CGPoint)_accessibilityConvertPointToViewSpace:(CGPoint)point
1271 {
1272     if (![self _prepareAccessibilityCall])
1273         return point;
1274     
1275     FloatPoint floatPoint = FloatPoint(point);
1276     return [self convertPointToScreenSpace:floatPoint];
1277 }
1278
1279 - (BOOL)_accessibilityScrollToVisible
1280 {
1281     if (![self _prepareAccessibilityCall])
1282         return NO;
1283     
1284     m_object->scrollToMakeVisible();
1285     return YES;
1286 }
1287
1288
1289 - (BOOL)accessibilityScroll:(UIAccessibilityScrollDirection)direction
1290 {
1291     if (![self _prepareAccessibilityCall])
1292         return NO;
1293     
1294     AccessibilityObject::ScrollByPageDirection scrollDirection;
1295     switch (direction) {
1296     case UIAccessibilityScrollDirectionRight:
1297         scrollDirection = AccessibilityObject::ScrollByPageDirection::Right;
1298         break;
1299     case UIAccessibilityScrollDirectionLeft:
1300         scrollDirection = AccessibilityObject::ScrollByPageDirection::Left;
1301         break;
1302     case UIAccessibilityScrollDirectionUp:
1303         scrollDirection = AccessibilityObject::ScrollByPageDirection::Up;
1304         break;
1305     case UIAccessibilityScrollDirectionDown:
1306         scrollDirection = AccessibilityObject::ScrollByPageDirection::Down;
1307         break;
1308     default:
1309         return NO;
1310     }
1311
1312     BOOL result = m_object->scrollByPage(scrollDirection);
1313     
1314     if (result) {
1315         [self postScrollStatusChangeNotification];
1316
1317         CGPoint scrollPos = [self _accessibilityScrollPosition];
1318         NSString *testString = [NSString stringWithFormat:@"AXScroll [position: %.2f %.2f]", scrollPos.x, scrollPos.y];
1319         [self accessibilityPostedNotification:@"AXScrollByPage" userInfo:@{ @"status" : testString }];
1320     }
1321     
1322     // This means that this object handled the scroll and no other ancestor should attempt scrolling.
1323     return result;
1324 }
1325
1326 - (CGPoint)convertPointToScreenSpace:(FloatPoint &)point
1327 {
1328     if (!m_object)
1329         return CGPointZero;
1330     
1331     CGPoint cgPoint = CGPointMake(point.x(), point.y());
1332     
1333     FrameView* frameView = m_object->documentFrameView();
1334     WAKView* documentView = frameView ? frameView->documentView() : nullptr;
1335     if (documentView) {
1336         cgPoint = [documentView convertPoint:cgPoint toView:nil];
1337
1338         // we need the web document view to give us our final screen coordinates
1339         // because that can take account of the scroller
1340         id webDocument = [self _accessibilityWebDocumentView];
1341         if (webDocument)
1342             cgPoint = [webDocument convertPoint:cgPoint toView:nil];
1343     }
1344     else {
1345         // Find the appropriate scroll view to use to convert the contents to the window.
1346         ScrollView* scrollView = nullptr;
1347         AccessibilityObject* parent = nullptr;
1348         for (parent = m_object->parentObject(); parent; parent = parent->parentObject()) {
1349             if (is<AccessibilityScrollView>(*parent)) {
1350                 scrollView = downcast<AccessibilityScrollView>(*parent).scrollView();
1351                 break;
1352             }
1353         }
1354         
1355         IntPoint intPoint = flooredIntPoint(point);
1356         if (scrollView)
1357             intPoint = scrollView->contentsToRootView(intPoint);
1358         
1359         Page* page = m_object->page();
1360         
1361         // If we have an empty chrome client (like SVG) then we should use the page
1362         // of the scroll view parent to help us get to the screen rect.
1363         if (parent && page && page->chrome().client().isEmptyChromeClient())
1364             page = parent->page();
1365         
1366         if (page) {
1367             IntRect rect = IntRect(intPoint, IntSize(0, 0));
1368             intPoint = page->chrome().rootViewToAccessibilityScreen(rect).location();
1369         }
1370         
1371         cgPoint = (CGPoint)intPoint;
1372     }
1373     
1374     return cgPoint;
1375 }
1376
1377 - (CGRect)convertRectToScreenSpace:(IntRect &)rect
1378 {
1379     if (!m_object)
1380         return CGRectZero;
1381     
1382     CGSize size = CGSizeMake(rect.size().width(), rect.size().height());
1383     CGPoint point = CGPointMake(rect.x(), rect.y());
1384     
1385     CGRect frame = CGRectMake(point.x, point.y, size.width, size.height);
1386     
1387     FrameView* frameView = m_object->documentFrameView();
1388     WAKView* documentView = frameView ? frameView->documentView() : nil;
1389     if (documentView) {
1390         frame = [documentView convertRect:frame toView:nil];
1391         
1392         // we need the web document view to give us our final screen coordinates
1393         // because that can take account of the scroller
1394         id webDocument = [self _accessibilityWebDocumentView];
1395         if (webDocument)
1396             frame = [webDocument convertRect:frame toView:nil];
1397         
1398     } else {
1399         // Find the appropriate scroll view to use to convert the contents to the window.
1400         ScrollView* scrollView = nullptr;
1401         AccessibilityObject* parent = nullptr;
1402         for (parent = m_object->parentObject(); parent; parent = parent->parentObject()) {
1403             if (is<AccessibilityScrollView>(*parent)) {
1404                 scrollView = downcast<AccessibilityScrollView>(*parent).scrollView();
1405                 break;
1406             }
1407         }
1408         
1409         if (scrollView)
1410             rect = scrollView->contentsToRootView(rect);
1411         
1412         Page* page = m_object->page();
1413         
1414         // If we have an empty chrome client (like SVG) then we should use the page
1415         // of the scroll view parent to help us get to the screen rect.
1416         if (parent && page && page->chrome().client().isEmptyChromeClient())
1417             page = parent->page();
1418         
1419         if (page)
1420             rect = page->chrome().rootViewToAccessibilityScreen(rect);
1421         
1422         frame = (CGRect)rect;
1423     }
1424     
1425     return frame;
1426 }
1427
1428 // Used by UIKit accessibility bundle to help determine distance during a hit-test.
1429 - (CGRect)accessibilityElementRect
1430 {
1431     if (![self _prepareAccessibilityCall])
1432         return CGRectZero;
1433     
1434     LayoutRect rect = m_object->elementRect();
1435     return CGRectMake(rect.x(), rect.y(), rect.width(), rect.height());
1436 }
1437
1438 // The "center point" is where VoiceOver will "press" an object. This may not be the actual
1439 // center of the accessibilityFrame
1440 - (CGPoint)accessibilityActivationPoint
1441 {
1442     if (![self _prepareAccessibilityCall])
1443         return CGPointZero;
1444     
1445     IntRect rect = snappedIntRect(m_object->boundingBoxRect());
1446     CGRect cgRect = [self convertRectToScreenSpace:rect];
1447     return CGPointMake(CGRectGetMidX(cgRect), CGRectGetMidY(cgRect));
1448 }
1449
1450 - (CGRect)accessibilityFrame
1451 {
1452     if (![self _prepareAccessibilityCall])
1453         return CGRectZero;
1454     
1455     IntRect rect = snappedIntRect(m_object->elementRect());
1456     return [self convertRectToScreenSpace:rect];
1457 }
1458
1459 // Checks whether a link contains only static text and images (and has been divided unnaturally by <spans> and other nefarious mechanisms).
1460 - (BOOL)containsUnnaturallySegmentedChildren
1461 {
1462     if (!m_object)
1463         return NO;
1464     
1465     AccessibilityRole role = m_object->roleValue();
1466     if (role != LinkRole && role != WebCoreLinkRole)
1467         return NO;
1468     
1469     const auto& children = m_object->children();
1470     unsigned childrenSize = children.size();
1471
1472     // If there's only one child, then it doesn't have segmented children. 
1473     if (childrenSize == 1)
1474         return NO;
1475     
1476     for (unsigned i = 0; i < childrenSize; ++i) {
1477         AccessibilityRole role = children[i]->roleValue();
1478         if (role != StaticTextRole && role != ImageRole && role != GroupRole)
1479             return NO;
1480     }
1481     
1482     return YES;
1483 }
1484
1485 - (id)accessibilityContainer
1486 {
1487     if (![self _prepareAccessibilityCall])
1488         return nil;
1489
1490     AXAttributeCacheEnabler enableCache(m_object->axObjectCache());
1491     
1492     // As long as there's a parent wrapper, that's the correct chain to climb.
1493     AccessibilityObject* parent = m_object->parentObjectUnignored(); 
1494     if (parent)
1495         return parent->wrapper();
1496
1497     // Mock objects can have their parents detached but still exist in the cache.
1498     if (m_object->isDetachedFromParent())
1499         return nil;
1500     
1501     // The only object without a parent wrapper at this point should be a scroll view.
1502     ASSERT(m_object->isAccessibilityScrollView());
1503     
1504     // Verify this is the top document. If not, we might need to go through the platform widget.
1505     FrameView* frameView = m_object->documentFrameView();
1506     Document* document = m_object->document();
1507     if (document && frameView && document != &document->topDocument())
1508         return frameView->platformWidget();
1509     
1510     // The top scroll view's parent is the web document view.
1511     return [self _accessibilityWebDocumentView];
1512 }
1513
1514 - (id)accessibilityFocusedUIElement
1515 {
1516     if (![self _prepareAccessibilityCall])
1517         return nil;
1518     
1519     AccessibilityObject* focusedObj = m_object->focusedUIElement();
1520     
1521     if (!focusedObj)
1522         return nil;
1523     
1524     return focusedObj->wrapper();
1525 }
1526
1527 - (id)_accessibilityWebDocumentView
1528 {
1529     if (![self _prepareAccessibilityCall])
1530         return nil;
1531
1532     // This method performs the crucial task of connecting to the UIWebDocumentView.
1533     // This is needed to correctly calculate the screen position of the AX object.
1534     static Class webViewClass = nil;
1535     if (!webViewClass)
1536         webViewClass = NSClassFromString(@"WebView");
1537
1538     if (!webViewClass)
1539         return nil;
1540     
1541     FrameView* frameView = m_object->documentFrameView();
1542
1543     if (!frameView)
1544         return nil;
1545     
1546     // If this is the top level frame, the UIWebDocumentView should be returned.
1547     id parentView = frameView->documentView();
1548     while (parentView && ![parentView isKindOfClass:webViewClass])
1549         parentView = [parentView superview];
1550     
1551     // The parentView should have an accessibilityContainer, if the UIKit accessibility bundle was loaded. 
1552     // The exception is DRT, which tests accessibility without the entire system turning accessibility on. Hence,
1553     // this check should be valid for everything except DRT.
1554     ASSERT([parentView accessibilityContainer] || applicationIsDumpRenderTree());
1555     
1556     return [parentView accessibilityContainer];
1557 }
1558
1559 - (NSArray *)_accessibilityNextElementsWithCount:(UInt32)count
1560 {    
1561     if (![self _prepareAccessibilityCall])
1562         return nil;
1563     
1564     return [[self _accessibilityWebDocumentView] _accessibilityNextElementsWithCount:count];
1565 }
1566
1567 - (NSArray *)_accessibilityPreviousElementsWithCount:(UInt32)count
1568 {
1569     if (![self _prepareAccessibilityCall])
1570         return nil;
1571     
1572     return [[self _accessibilityWebDocumentView] _accessibilityPreviousElementsWithCount:count];
1573 }
1574
1575 - (BOOL)accessibilityCanSetValue
1576 {
1577     if (![self _prepareAccessibilityCall])
1578         return NO;
1579     
1580     return m_object->canSetValueAttribute();
1581 }
1582
1583 - (BOOL)accessibilityRequired
1584 {
1585     if (![self _prepareAccessibilityCall])
1586         return NO;
1587
1588     return m_object->isRequired();
1589 }
1590
1591 - (NSArray *)accessibilityFlowToElements
1592 {
1593     if (![self _prepareAccessibilityCall])
1594         return nil;
1595     
1596     AccessibilityObject::AccessibilityChildrenVector children;
1597     m_object->ariaFlowToElements(children);
1598     
1599     unsigned length = children.size();
1600     NSMutableArray* array = [NSMutableArray arrayWithCapacity:length];
1601     for (unsigned i = 0; i < length; ++i) {
1602         AccessibilityObjectWrapper* wrapper = children[i]->wrapper();
1603         ASSERT(wrapper);
1604         if (!wrapper)
1605             continue;
1606
1607         if (children[i]->isAttachment() && [wrapper attachmentView])
1608             [array addObject:[wrapper attachmentView]];
1609         else
1610             [array addObject:wrapper];
1611     }
1612     return array;
1613 }
1614
1615 - (id)accessibilityLinkedElement
1616 {
1617     if (![self _prepareAccessibilityCall])
1618         return nil;
1619     
1620     // If this static text inside of a link, it should use its parent's linked element.
1621     AccessibilityObject* element = m_object;
1622     if (m_object->roleValue() == StaticTextRole && m_object->parentObjectUnignored()->isLink())
1623         element = m_object->parentObjectUnignored();
1624     
1625     AccessibilityObject::AccessibilityChildrenVector children;
1626     element->linkedUIElements(children);
1627     if (children.size() == 0)
1628         return nil;
1629     
1630     return children[0]->wrapper();
1631 }
1632
1633
1634 - (BOOL)isAttachment
1635 {
1636     if (!m_object)
1637         return NO;
1638     
1639     return m_object->isAttachment();
1640 }
1641
1642 - (void)_accessibilityActivate
1643 {
1644     if (![self _prepareAccessibilityCall])
1645         return;
1646
1647     m_object->press();
1648 }
1649
1650 - (id)attachmentView
1651 {
1652     if (![self _prepareAccessibilityCall])
1653         return nil;
1654
1655     ASSERT([self isAttachment]);
1656     Widget* widget = m_object->widgetForAttachmentView();
1657     if (!widget)
1658         return nil;
1659     return widget->platformWidget();    
1660 }
1661
1662 static RenderObject* rendererForView(WAKView* view)
1663 {
1664     if (![view conformsToProtocol:@protocol(WebCoreFrameView)])
1665         return nil;
1666     
1667     WAKView<WebCoreFrameView>* frameView = (WAKView<WebCoreFrameView>*)view;
1668     Frame* frame = [frameView _web_frame];
1669     if (!frame)
1670         return nil;
1671     
1672     Node* node = frame->document()->ownerElement();
1673     if (!node)
1674         return nil;
1675     
1676     return node->renderer();
1677 }
1678
1679 - (id)_accessibilityParentForSubview:(id)subview
1680 {   
1681     RenderObject* renderer = rendererForView(subview);
1682     if (!renderer)
1683         return nil;
1684     
1685     AccessibilityObject* obj = renderer->document().axObjectCache()->getOrCreate(renderer);
1686     if (obj)
1687         return obj->parentObjectUnignored()->wrapper();
1688     return nil;
1689 }
1690
1691 - (void)postFocusChangeNotification
1692 {
1693     // The UIKit accessibility wrapper will override and post appropriate notification.
1694 }
1695
1696 - (void)postSelectedTextChangeNotification
1697 {
1698     // The UIKit accessibility wrapper will override and post appropriate notification.    
1699 }
1700
1701 - (void)postLayoutChangeNotification
1702 {
1703     // The UIKit accessibility wrapper will override and post appropriate notification.        
1704 }
1705
1706 - (void)postLiveRegionChangeNotification
1707 {
1708     // The UIKit accessibility wrapper will override and post appropriate notification.    
1709 }
1710
1711 - (void)postLiveRegionCreatedNotification
1712 {
1713     // The UIKit accessibility wrapper will override and post appropriate notification.    
1714 }
1715
1716 - (void)postLoadCompleteNotification
1717 {
1718     // The UIKit accessibility wrapper will override and post appropriate notification.    
1719 }
1720
1721 - (void)postChildrenChangedNotification
1722 {
1723     // The UIKit accessibility wrapper will override and post appropriate notification.    
1724 }
1725
1726 - (void)postInvalidStatusChangedNotification
1727 {
1728     // The UIKit accessibility wrapper will override and post appropriate notification.        
1729 }
1730
1731 - (void)postValueChangedNotification
1732 {
1733     // The UIKit accessibility wrapper will override and post appropriate notification.
1734 }
1735
1736 - (void)postExpandedChangedNotification
1737 {
1738     // The UIKit accessibility wrapper will override and post appropriate notification.
1739 }
1740
1741 - (void)postScrollStatusChangeNotification
1742 {
1743     // The UIKit accessibility wrapper will override and post appropriate notification.
1744 }
1745
1746 // These will be used by the UIKit wrapper to calculate an appropriate description of scroll status.
1747 - (CGPoint)_accessibilityScrollPosition
1748 {
1749     if (![self _prepareAccessibilityCall])
1750         return CGPointZero;
1751     
1752     return m_object->scrollPosition();
1753 }
1754
1755 - (CGSize)_accessibilityScrollSize
1756 {
1757     if (![self _prepareAccessibilityCall])
1758         return CGSizeZero;
1759     
1760     return m_object->scrollContentsSize();
1761 }
1762
1763 - (CGRect)_accessibilityScrollVisibleRect
1764 {
1765     if (![self _prepareAccessibilityCall])
1766         return CGRectZero;
1767     
1768     return m_object->scrollVisibleContentRect();
1769 }
1770
1771 - (void)accessibilityElementDidBecomeFocused
1772 {
1773     if (![self _prepareAccessibilityCall])
1774         return;
1775     
1776     // The focused VoiceOver element might be the text inside a link.
1777     // In those cases we should focus on the link itself.
1778     for (AccessibilityObject* object = m_object; object != nil; object = object->parentObject()) {
1779         if (object->roleValue() == WebAreaRole)
1780             break;
1781
1782         if (object->canSetFocusAttribute()) {
1783             object->setFocused(true);
1784             break;
1785         }
1786     }
1787 }
1788
1789 - (void)accessibilityModifySelection:(TextGranularity)granularity increase:(BOOL)increase
1790 {
1791     if (![self _prepareAccessibilityCall])
1792         return;
1793     
1794     FrameSelection& frameSelection = m_object->document()->frame()->selection();
1795     VisibleSelection selection = m_object->selection();
1796     VisiblePositionRange range = m_object->visiblePositionRange();
1797     
1798     // Before a selection with length exists, the cursor position needs to move to the right starting place.
1799     // That should be the beginning of this element (range.start). However, if the cursor is already within the 
1800     // range of this element (the cursor is represented by selection), then the cursor does not need to move.
1801     if (frameSelection.isNone() && (selection.visibleStart() < range.start || selection.visibleEnd() > range.end))
1802         frameSelection.moveTo(range.start, UserTriggered);
1803     
1804     frameSelection.modify(FrameSelection::AlterationExtend, (increase) ? DirectionRight : DirectionLeft, granularity, UserTriggered);
1805 }
1806
1807 - (void)accessibilityIncreaseSelection:(TextGranularity)granularity
1808 {
1809     [self accessibilityModifySelection:granularity increase:YES];
1810 }
1811
1812 - (void)accessibilityDecreaseSelection:(TextGranularity)granularity
1813 {
1814     [self accessibilityModifySelection:granularity increase:NO];
1815 }
1816
1817 - (void)accessibilityMoveSelectionToMarker:(WebAccessibilityTextMarker *)marker
1818 {
1819     if (![self _prepareAccessibilityCall])
1820         return;
1821     
1822     VisiblePosition visiblePosition = [marker visiblePosition];
1823     if (visiblePosition.isNull())
1824         return;
1825
1826     FrameSelection& frameSelection = m_object->document()->frame()->selection();
1827     frameSelection.moveTo(visiblePosition, UserTriggered);
1828 }
1829
1830 - (void)accessibilityIncrement
1831 {
1832     if (![self _prepareAccessibilityCall])
1833         return;
1834
1835     m_object->increment();
1836 }
1837
1838 - (void)accessibilityDecrement
1839 {
1840     if (![self _prepareAccessibilityCall])
1841         return;
1842
1843     m_object->decrement();
1844 }
1845
1846 #pragma mark Accessibility Text Marker Handlers
1847
1848 - (BOOL)_addAccessibilityObject:(AccessibilityObject*)axObject toTextMarkerArray:(NSMutableArray *)array
1849 {
1850     if (!axObject)
1851         return NO;
1852     
1853     AccessibilityObjectWrapper* wrapper = axObject->wrapper();
1854     if (!wrapper)
1855         return NO;
1856
1857     // Don't add the same object twice, but since this has already been added, we should return
1858     // YES because we want to inform that it's in the array
1859     if ([array containsObject:wrapper])
1860         return YES;
1861     
1862     // Explicity set that this is now an element (in case other logic tries to override).
1863     [wrapper setValue:[NSNumber numberWithBool:YES] forKey:@"isAccessibilityElement"];    
1864     [array addObject:wrapper];
1865     return YES;
1866 }
1867
1868 - (void)_accessibilitySetValue:(NSString *)string
1869 {
1870     if (![self _prepareAccessibilityCall])
1871         return;
1872     m_object->setValue(string);
1873 }
1874
1875 - (NSString *)stringForTextMarkers:(NSArray *)markers
1876 {
1877     if (![self _prepareAccessibilityCall])
1878         return nil;
1879     
1880     RefPtr<Range> range = [self rangeForTextMarkers:markers];
1881     if (!range)
1882         return nil;
1883     
1884     return m_object->stringForRange(range);
1885 }
1886
1887 static int blockquoteLevel(RenderObject* renderer)
1888 {
1889     if (!renderer)
1890         return 0;
1891     
1892     int result = 0;
1893     for (Node* node = renderer->node(); node; node = node->parentNode()) {
1894         if (node->hasTagName(blockquoteTag))
1895             result += 1;
1896     }
1897     
1898     return result;
1899 }
1900
1901 static void AXAttributeStringSetLanguage(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
1902 {
1903     if (!renderer)
1904         return;
1905     
1906     AccessibilityObject* axObject = renderer->document().axObjectCache()->getOrCreate(renderer);
1907     NSString *language = axObject->language();
1908     if ([language length])
1909         [attrString addAttribute:UIAccessibilityTokenLanguage value:language range:range];
1910     else
1911         [attrString removeAttribute:UIAccessibilityTokenLanguage range:range];
1912 }
1913
1914 static void AXAttributeStringSetBlockquoteLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
1915 {
1916     int quoteLevel = blockquoteLevel(renderer);
1917     
1918     if (quoteLevel)
1919         [attrString addAttribute:UIAccessibilityTokenBlockquoteLevel value:[NSNumber numberWithInt:quoteLevel] range:range];
1920     else
1921         [attrString removeAttribute:UIAccessibilityTokenBlockquoteLevel range:range];
1922 }
1923
1924 static void AXAttributeStringSetHeadingLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
1925 {
1926     if (!renderer)
1927         return;
1928     
1929     AccessibilityObject* parentObject = renderer->document().axObjectCache()->getOrCreate(renderer->parent());
1930     int parentHeadingLevel = parentObject->headingLevel();
1931     
1932     if (parentHeadingLevel)
1933         [attrString addAttribute:UIAccessibilityTokenHeadingLevel value:[NSNumber numberWithInt:parentHeadingLevel] range:range];
1934     else
1935         [attrString removeAttribute:UIAccessibilityTokenHeadingLevel range:range];
1936 }
1937
1938 static void AXAttributeStringSetFont(NSMutableAttributedString* attrString, CTFontRef font, NSRange range)
1939 {
1940     if (!font)
1941         return;
1942     
1943     RetainPtr<CFStringRef> fullName = adoptCF(CTFontCopyFullName(font));
1944     RetainPtr<CFStringRef> familyName = adoptCF(CTFontCopyFamilyName(font));
1945
1946     NSNumber* size = [NSNumber numberWithFloat:CTFontGetSize(font)];
1947     CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(font);
1948     NSNumber* bold = [NSNumber numberWithBool:(traits & kCTFontTraitBold)];
1949     if (fullName)
1950         [attrString addAttribute:UIAccessibilityTokenFontName value:(NSString*)fullName.get() range:range];
1951     if (familyName)
1952         [attrString addAttribute:UIAccessibilityTokenFontFamily value:(NSString*)familyName.get() range:range];
1953     if ([size boolValue])
1954         [attrString addAttribute:UIAccessibilityTokenFontSize value:size range:range];
1955     if ([bold boolValue] || (traits & kCTFontTraitBold))
1956         [attrString addAttribute:UIAccessibilityTokenBold value:[NSNumber numberWithBool:YES] range:range];
1957     if (traits & kCTFontTraitItalic)
1958         [attrString addAttribute:UIAccessibilityTokenItalic value:[NSNumber numberWithBool:YES] range:range];
1959
1960 }
1961
1962 static void AXAttributeStringSetNumber(NSMutableAttributedString* attrString, NSString* attribute, NSNumber* number, NSRange range)
1963 {
1964     if (number)
1965         [attrString addAttribute:attribute value:number range:range];
1966     else
1967         [attrString removeAttribute:attribute range:range];
1968 }
1969
1970 static void AXAttributeStringSetStyle(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
1971 {
1972     RenderStyle& style = renderer->style();
1973     
1974     // set basic font info
1975     AXAttributeStringSetFont(attrString, style.fontCascade().primaryFont().getCTFont(), range);
1976                 
1977     int decor = style.textDecorationsInEffect();
1978     if ((decor & (TextDecorationUnderline | TextDecorationLineThrough)) != 0) {
1979         Color underlineColor, overlineColor, linethroughColor;
1980         TextDecorationStyle underlineStyle, overlineStyle, linethroughStyle;
1981         renderer->getTextDecorationColorsAndStyles(decor, underlineColor, overlineColor, linethroughColor, underlineStyle, overlineStyle, linethroughStyle);
1982         
1983         if (decor & TextDecorationUnderline)
1984             AXAttributeStringSetNumber(attrString, UIAccessibilityTokenUnderline, [NSNumber numberWithBool:YES], range);
1985     }
1986 }
1987
1988 static void AXAttributedStringAppendText(NSMutableAttributedString* attrString, Node* node, NSString *text)
1989 {
1990     // skip invisible text
1991     if (!node->renderer())
1992         return;
1993     
1994     // easier to calculate the range before appending the string
1995     NSRange attrStringRange = NSMakeRange([attrString length], [text length]);
1996     
1997     // append the string from this node
1998     [[attrString mutableString] appendString:text];
1999     
2000     // set new attributes
2001     AXAttributeStringSetStyle(attrString, node->renderer(), attrStringRange);
2002     AXAttributeStringSetHeadingLevel(attrString, node->renderer(), attrStringRange);
2003     AXAttributeStringSetBlockquoteLevel(attrString, node->renderer(), attrStringRange);    
2004     AXAttributeStringSetLanguage(attrString, node->renderer(), attrStringRange);
2005 }
2006
2007
2008 // This method is intended to return an array of strings and accessibility elements that 
2009 // represent the objects on one line of rendered web content. The array of markers sent
2010 // in should be ordered and contain only a start and end marker.
2011 - (NSArray *)arrayOfTextForTextMarkers:(NSArray *)markers attributed:(BOOL)attributed
2012 {
2013     if (![self _prepareAccessibilityCall])
2014         return nil;
2015
2016     if ([markers count] != 2)
2017         return nil;
2018     
2019     WebAccessibilityTextMarker* startMarker = [markers objectAtIndex:0];
2020     WebAccessibilityTextMarker* endMarker = [markers objectAtIndex:1];
2021     if (![startMarker isKindOfClass:[WebAccessibilityTextMarker class]] || ![endMarker isKindOfClass:[WebAccessibilityTextMarker class]])
2022         return nil;
2023     
2024     // extract the start and end VisiblePosition
2025     VisiblePosition startVisiblePosition = [startMarker visiblePosition];
2026     if (startVisiblePosition.isNull())
2027         return nil;
2028     
2029     VisiblePosition endVisiblePosition = [endMarker visiblePosition];
2030     if (endVisiblePosition.isNull())
2031         return nil;
2032     
2033     // iterate over the range to build the AX attributed string
2034     NSMutableArray* array = [[NSMutableArray alloc] init];
2035     TextIterator it(makeRange(startVisiblePosition, endVisiblePosition).get());
2036     for (; !it.atEnd(); it.advance()) {
2037         // locate the node and starting offset for this range
2038         Node& node = it.range()->startContainer();
2039         ASSERT(&node == &it.range()->endContainer());
2040         int offset = it.range()->startOffset();
2041         
2042         // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
2043         if (it.text().length() != 0) {
2044             if (!attributed) {
2045                 // First check if this is represented by a link.
2046                 AccessibilityObject* linkObject = AccessibilityObject::anchorElementForNode(&node);
2047                 if ([self _addAccessibilityObject:linkObject toTextMarkerArray:array])
2048                     continue;
2049                 
2050                 // Next check if this region is represented by a heading.
2051                 AccessibilityObject* headingObject = AccessibilityObject::headingElementForNode(&node);
2052                 if ([self _addAccessibilityObject:headingObject toTextMarkerArray:array])
2053                     continue;
2054                 
2055                 String listMarkerText = m_object->listMarkerTextForNodeAndPosition(&node, VisiblePosition(it.range()->startPosition()));
2056                 
2057                 if (!listMarkerText.isEmpty()) 
2058                     [array addObject:listMarkerText];
2059                 // There was not an element representation, so just return the text.
2060                 [array addObject:it.text().createNSString().get()];
2061             }
2062             else
2063             {
2064                 String listMarkerText = m_object->listMarkerTextForNodeAndPosition(&node, VisiblePosition(it.range()->startPosition()));
2065
2066                 if (!listMarkerText.isEmpty()) {
2067                     NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] init];
2068                     AXAttributedStringAppendText(attrString, &node, listMarkerText);
2069                     [array addObject:attrString];
2070                     [attrString release];
2071                 }
2072                 
2073                 NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] init];
2074                 AXAttributedStringAppendText(attrString, &node, it.text().createNSStringWithoutCopying().get());
2075                 [array addObject:attrString];
2076                 [attrString release];
2077             }
2078         } else {
2079             Node* replacedNode = node.traverseToChildAt(offset);
2080             if (replacedNode) {
2081                 AccessibilityObject* obj = m_object->axObjectCache()->getOrCreate(replacedNode->renderer());
2082                 if (obj && !obj->accessibilityIsIgnored())
2083                     [self _addAccessibilityObject:obj toTextMarkerArray:array];
2084             }
2085         }
2086     }
2087     
2088     return [array autorelease];
2089 }
2090
2091 - (NSRange)_convertToNSRange:(Range *)range
2092 {
2093     if (!range)
2094         return NSMakeRange(NSNotFound, 0);
2095     
2096     Document* document = m_object->document();
2097     Element* selectionRoot = document->frame()->selection().selection().rootEditableElement();
2098     Element* scope = selectionRoot ? selectionRoot : document->documentElement();
2099     
2100     // Mouse events may cause TSM to attempt to create an NSRange for a portion of the view
2101     // that is not inside the current editable region.  These checks ensure we don't produce
2102     // potentially invalid data when responding to such requests.
2103     if (&range->startContainer() != scope && !range->startContainer().isDescendantOf(scope))
2104         return NSMakeRange(NSNotFound, 0);
2105     if (&range->endContainer() != scope && !range->endContainer().isDescendantOf(scope))
2106         return NSMakeRange(NSNotFound, 0);
2107     
2108     RefPtr<Range> testRange = Range::create(scope->document(), scope, 0, &range->startContainer(), range->startOffset());
2109     ASSERT(&testRange->startContainer() == scope);
2110     int startPosition = TextIterator::rangeLength(testRange.get());
2111     
2112     ExceptionCode ec;
2113     testRange->setEnd(&range->endContainer(), range->endOffset(), ec);
2114     ASSERT(&testRange->startContainer() == scope);
2115     int endPosition = TextIterator::rangeLength(testRange.get());
2116     return NSMakeRange(startPosition, endPosition - startPosition);
2117 }
2118
2119 - (RefPtr<Range>)_convertToDOMRange:(NSRange)nsrange
2120 {
2121     if (nsrange.location > INT_MAX)
2122         return nullptr;
2123     if (nsrange.length > INT_MAX || nsrange.location + nsrange.length > INT_MAX)
2124         nsrange.length = INT_MAX - nsrange.location;
2125         
2126     // our critical assumption is that we are only called by input methods that
2127     // concentrate on a given area containing the selection
2128     // We have to do this because of text fields and textareas. The DOM for those is not
2129     // directly in the document DOM, so serialization is problematic. Our solution is
2130     // to use the root editable element of the selection start as the positional base.
2131     // That fits with AppKit's idea of an input context.
2132     Document* document = m_object->document();
2133     Element* selectionRoot = document->frame()->selection().selection().rootEditableElement();
2134     Element* scope = selectionRoot ? selectionRoot : document->documentElement();
2135     return TextIterator::rangeFromLocationAndLength(scope, nsrange.location, nsrange.length);
2136 }
2137
2138 // This method is intended to take a text marker representing a VisiblePosition and convert it
2139 // into a normalized location within the document.
2140 - (NSInteger)positionForTextMarker:(WebAccessibilityTextMarker *)marker
2141 {
2142     if (![self _prepareAccessibilityCall])
2143         return NSNotFound;
2144
2145     if (!marker)
2146         return NSNotFound;    
2147
2148     VisibleSelection selection([marker visiblePosition]);
2149     RefPtr<Range> range = selection.toNormalizedRange();
2150     NSRange nsRange = [self _convertToNSRange:range.get()];
2151     return nsRange.location;
2152 }
2153
2154 - (NSArray *)textMarkerRange
2155 {
2156     if (![self _prepareAccessibilityCall])
2157         return nil;
2158     
2159     RefPtr<Range> range = m_object->elementRange();
2160     return [self textMarkersForRange:range];
2161 }
2162
2163 // A method to get the normalized text cursor range of an element. Used in DumpRenderTree.
2164 - (NSRange)elementTextRange
2165 {
2166     if (![self _prepareAccessibilityCall])
2167         return NSMakeRange(NSNotFound, 0);
2168
2169     NSArray *markers = [self textMarkerRange];
2170     if ([markers count] != 2)
2171         return NSMakeRange(NSNotFound, 0);
2172     
2173     WebAccessibilityTextMarker *startMarker = [markers objectAtIndex:0];
2174     WebAccessibilityTextMarker *endMarker = [markers objectAtIndex:1];
2175     
2176     NSInteger startPosition = [self positionForTextMarker:startMarker];
2177     NSInteger endPosition = [self positionForTextMarker:endMarker];
2178     
2179     return NSMakeRange(startPosition, endPosition - startPosition);
2180 }
2181
2182 - (AccessibilityObjectWrapper *)accessibilityObjectForTextMarker:(WebAccessibilityTextMarker *)marker
2183 {
2184     if (![self _prepareAccessibilityCall])
2185         return nil;
2186
2187     if (!marker)
2188         return nil;
2189     
2190     AccessibilityObject* obj = [marker accessibilityObject];
2191     if (!obj)
2192         return nil;
2193     
2194     return AccessibilityUnignoredAncestor(obj->wrapper());
2195 }
2196
2197 - (NSArray *)textMarkerRangeForSelection
2198 {
2199     if (![self _prepareAccessibilityCall])
2200         return nil;
2201     
2202     VisibleSelection selection = m_object->selection();
2203     if (selection.isNone())
2204         return nil;
2205     VisiblePosition startPosition = selection.visibleStart();
2206     VisiblePosition endPosition = selection.visibleEnd();
2207
2208     WebAccessibilityTextMarker* startMarker = [WebAccessibilityTextMarker textMarkerWithVisiblePosition:startPosition cache:m_object->axObjectCache()];
2209     WebAccessibilityTextMarker* endMarker = [WebAccessibilityTextMarker textMarkerWithVisiblePosition:endPosition cache:m_object->axObjectCache()];
2210     if (!startMarker || !endMarker)
2211         return nil;
2212     
2213     return [NSArray arrayWithObjects:startMarker, endMarker, nil];
2214 }
2215
2216 - (WebAccessibilityTextMarker *)textMarkerForPosition:(NSInteger)position
2217 {
2218     if (![self _prepareAccessibilityCall])
2219         return nil;
2220
2221     RefPtr<Range> range = [self _convertToDOMRange:NSMakeRange(position, 0)];
2222     if (!range)
2223         return nil;
2224     
2225     VisibleSelection selection = VisibleSelection(*range, DOWNSTREAM);
2226
2227     VisiblePosition visiblePosition = selection.visibleStart();
2228     return [WebAccessibilityTextMarker textMarkerWithVisiblePosition:visiblePosition cache:m_object->axObjectCache()];
2229 }
2230
2231 - (id)_stringForRange:(NSRange)range attributed:(BOOL)attributed
2232 {
2233     if (![self _prepareAccessibilityCall])
2234         return nil;
2235     
2236     WebAccessibilityTextMarker* startMarker = [self textMarkerForPosition:range.location];
2237     WebAccessibilityTextMarker* endMarker = [self textMarkerForPosition:NSMaxRange(range)];
2238     
2239     // Clients don't always know the exact range, rather than force them to compute it,
2240     // allow clients to overshoot and use the max text marker range.
2241     if (!startMarker || !endMarker) {
2242         NSArray *markers = [self textMarkerRange];
2243         if ([markers count] != 2)
2244             return nil;
2245         if (!startMarker)
2246             startMarker = [markers objectAtIndex:0];
2247         if (!endMarker)
2248             endMarker = [markers objectAtIndex:1];
2249     }
2250     
2251     NSArray* array = [self arrayOfTextForTextMarkers:[NSArray arrayWithObjects:startMarker, endMarker, nil] attributed:attributed];
2252     Class returnClass = attributed ? [NSMutableAttributedString class] : [NSMutableString class];
2253     id returnValue = [[(NSString *)[returnClass alloc] init] autorelease];
2254     
2255     NSInteger count = [array count];
2256     for (NSInteger k = 0; k < count; ++k) {
2257         id object = [array objectAtIndex:k];
2258
2259         if (![object isKindOfClass:returnClass])
2260             continue;
2261         
2262         if (attributed)
2263             [(NSMutableAttributedString *)returnValue appendAttributedString:object];
2264         else
2265             [(NSMutableString *)returnValue appendString:object];
2266     }
2267     return returnValue;
2268 }
2269
2270
2271 // A convenience method for getting the text of a NSRange. Currently used only by DRT.
2272 - (NSString *)stringForRange:(NSRange)range
2273 {
2274     return [self _stringForRange:range attributed:NO];
2275 }
2276
2277 - (NSAttributedString *)attributedStringForRange:(NSRange)range
2278 {
2279     return [self _stringForRange:range attributed:YES];
2280 }
2281
2282 - (NSRange)_accessibilitySelectedTextRange
2283 {
2284     if (![self _prepareAccessibilityCall] || !m_object->isTextControl())
2285         return NSMakeRange(NSNotFound, 0);
2286     
2287     PlainTextRange textRange = m_object->selectedTextRange();
2288     if (textRange.isNull())
2289         return NSMakeRange(NSNotFound, 0);
2290     return NSMakeRange(textRange.start, textRange.length);    
2291 }
2292
2293 - (void)_accessibilitySetSelectedTextRange:(NSRange)range
2294 {
2295     if (![self _prepareAccessibilityCall] || !m_object->isTextControl())
2296         return;
2297     
2298     m_object->setSelectedTextRange(PlainTextRange(range.location, range.length));
2299 }
2300
2301 // A convenience method for getting the accessibility objects of a NSRange. Currently used only by DRT.
2302 - (NSArray *)elementsForRange:(NSRange)range
2303 {
2304     if (![self _prepareAccessibilityCall])
2305         return nil;
2306     
2307     WebAccessibilityTextMarker* startMarker = [self textMarkerForPosition:range.location];
2308     WebAccessibilityTextMarker* endMarker = [self textMarkerForPosition:NSMaxRange(range)];
2309     if (!startMarker || !endMarker)
2310         return nil;
2311     
2312     NSArray* array = [self arrayOfTextForTextMarkers:[NSArray arrayWithObjects:startMarker, endMarker, nil] attributed:NO];
2313     NSMutableArray* elements = [NSMutableArray array];
2314     for (id element in array) {
2315         if (![element isKindOfClass:[AccessibilityObjectWrapper class]])
2316             continue;
2317         [elements addObject:element];
2318     }
2319     return elements;
2320 }
2321
2322 - (NSString *)selectionRangeString
2323 {
2324     NSArray *markers = [self textMarkerRangeForSelection];
2325     return [self stringForTextMarkers:markers];
2326 }
2327
2328 - (WebAccessibilityTextMarker *)selectedTextMarker
2329 {
2330     if (![self _prepareAccessibilityCall])
2331         return nil;
2332     
2333     VisibleSelection selection = m_object->selection();
2334     VisiblePosition position = selection.visibleStart();
2335     
2336     // if there's no selection, start at the top of the document
2337     if (position.isNull())
2338         position = startOfDocument(m_object->document());
2339     
2340     return [WebAccessibilityTextMarker textMarkerWithVisiblePosition:position cache:m_object->axObjectCache()];
2341 }
2342
2343 // This method is intended to return the marker at the end of the line starting at
2344 // the marker that is passed into the method.
2345 - (WebAccessibilityTextMarker *)lineEndMarkerForMarker:(WebAccessibilityTextMarker *)marker
2346 {
2347     if (![self _prepareAccessibilityCall])
2348         return nil;
2349
2350     if (!marker)
2351         return nil;
2352     
2353     VisiblePosition start = [marker visiblePosition];
2354     VisiblePosition lineEnd = m_object->nextLineEndPosition(start);
2355     
2356     return [WebAccessibilityTextMarker textMarkerWithVisiblePosition:lineEnd cache:m_object->axObjectCache()];
2357 }
2358
2359 // This method is intended to return the marker at the start of the line starting at
2360 // the marker that is passed into the method.
2361 - (WebAccessibilityTextMarker *)lineStartMarkerForMarker:(WebAccessibilityTextMarker *)marker
2362 {
2363     if (![self _prepareAccessibilityCall])
2364         return nil;
2365
2366     if (!marker)
2367         return nil;
2368     
2369     VisiblePosition start = [marker visiblePosition];
2370     VisiblePosition lineStart = m_object->previousLineStartPosition(start);
2371     
2372     return [WebAccessibilityTextMarker textMarkerWithVisiblePosition:lineStart cache:m_object->axObjectCache()];
2373 }
2374
2375 - (WebAccessibilityTextMarker *)nextMarkerForMarker:(WebAccessibilityTextMarker *)marker
2376 {
2377     if (![self _prepareAccessibilityCall])
2378         return nil;
2379
2380     if (!marker)
2381         return nil;
2382     
2383     CharacterOffset start = [marker characterOffset];
2384     return [self nextMarkerForCharacterOffset:start];
2385 }
2386
2387 - (WebAccessibilityTextMarker *)previousMarkerForMarker:(WebAccessibilityTextMarker *)marker
2388 {
2389     if (![self _prepareAccessibilityCall])
2390         return nil;
2391
2392     if (!marker)
2393         return nil;
2394     
2395     CharacterOffset start = [marker characterOffset];
2396     return [self previousMarkerForCharacterOffset:start];
2397 }
2398
2399 // This method is intended to return the bounds of a text marker range in screen coordinates.
2400 - (CGRect)frameForTextMarkers:(NSArray *)array
2401 {
2402     if (![self _prepareAccessibilityCall])
2403         return CGRectZero;
2404
2405     if ([array count] != 2)
2406         return CGRectZero;
2407     
2408     WebAccessibilityTextMarker* startMarker = [array objectAtIndex:0];
2409     WebAccessibilityTextMarker* endMarker = [array objectAtIndex:1];
2410     if (![startMarker isKindOfClass:[WebAccessibilityTextMarker class]] || ![endMarker isKindOfClass:[WebAccessibilityTextMarker class]])
2411         return CGRectZero;
2412
2413     IntRect rect = m_object->boundsForVisiblePositionRange(VisiblePositionRange([startMarker visiblePosition], [endMarker visiblePosition]));
2414     return [self convertRectToScreenSpace:rect];
2415 }
2416
2417 - (WebAccessibilityTextMarker *)textMarkerForPoint:(CGPoint)point
2418 {
2419     if (![self _prepareAccessibilityCall])
2420         return nil;
2421     
2422     VisiblePosition pos = m_object->visiblePositionForPoint(IntPoint(point));
2423     return [WebAccessibilityTextMarker textMarkerWithVisiblePosition:pos cache:m_object->axObjectCache()];
2424 }
2425
2426 - (WebAccessibilityTextMarker *)nextMarkerForCharacterOffset:(CharacterOffset&)characterOffset
2427 {
2428     characterOffset.offset = characterOffset.offset + 1;
2429     WebAccessibilityTextMarker *textMarker = [WebAccessibilityTextMarker textMarkerWithCharacterOffset:characterOffset cache:m_object->axObjectCache()];
2430     if (textMarker && textMarker.isIgnored)
2431         textMarker = [self nextMarkerForCharacterOffset:characterOffset];
2432     return textMarker;
2433 }
2434
2435 - (WebAccessibilityTextMarker *)previousMarkerForCharacterOffset:(CharacterOffset&)characterOffset
2436 {
2437     characterOffset.offset = characterOffset.offset - 1;
2438     WebAccessibilityTextMarker *textMarker = [WebAccessibilityTextMarker textMarkerWithCharacterOffset:characterOffset cache:m_object->axObjectCache()];
2439     if (textMarker && textMarker.isIgnored)
2440         textMarker = [self previousMarkerForCharacterOffset:characterOffset];
2441     return textMarker;
2442 }
2443
2444 - (RefPtr<Range>)rangeForTextMarkers:(NSArray *)textMarkers
2445 {
2446     if ([textMarkers count] != 2)
2447         return nullptr;
2448     
2449     WebAccessibilityTextMarker *startMarker = [textMarkers objectAtIndex:0];
2450     WebAccessibilityTextMarker *endMarker = [textMarkers objectAtIndex:1];
2451     
2452     if (![startMarker isKindOfClass:[WebAccessibilityTextMarker class]] || ![endMarker isKindOfClass:[WebAccessibilityTextMarker class]])
2453         return nullptr;
2454     
2455     AXObjectCache* cache = m_object->axObjectCache();
2456     if (!cache)
2457         return nullptr;
2458     
2459     CharacterOffset startCharacterOffset = [startMarker characterOffset];
2460     CharacterOffset endCharacterOffset = [endMarker characterOffset];
2461     return cache->rangeForUnorderedCharacterOffsets(startCharacterOffset, endCharacterOffset);
2462 }
2463
2464 - (NSInteger)lengthForTextMarkers:(NSArray *)textMarkers
2465 {
2466     if (![self _prepareAccessibilityCall])
2467         return 0;
2468     
2469     RefPtr<Range> range = [self rangeForTextMarkers:textMarkers];
2470     int length = AXObjectCache::lengthForRange(range.get());
2471     return length < 0 ? 0 : length;
2472 }
2473
2474 - (WebAccessibilityTextMarker *)startOrEndTextMarkerForTextMarkers:(NSArray *)textMarkers isStart:(BOOL)isStart
2475 {
2476     if (![self _prepareAccessibilityCall])
2477         return nil;
2478     
2479     RefPtr<Range> range = [self rangeForTextMarkers:textMarkers];
2480     if (!range)
2481         return nil;
2482     
2483     return [WebAccessibilityTextMarker startOrEndTextMarkerForRange:range isStart:isStart cache:m_object->axObjectCache()];
2484 }
2485
2486 - (NSArray *)textMarkerRangeForMarkers:(NSArray *)textMarkers
2487 {
2488     if (![self _prepareAccessibilityCall])
2489         return nil;
2490     
2491     RefPtr<Range> range = [self rangeForTextMarkers:textMarkers];
2492     return [self textMarkersForRange:range];
2493 }
2494
2495 - (NSArray *)textMarkersForRange:(RefPtr<Range>)range
2496 {
2497     if (!range)
2498         return nil;
2499     
2500     WebAccessibilityTextMarker* start = [WebAccessibilityTextMarker startOrEndTextMarkerForRange:range isStart:YES cache:m_object->axObjectCache()];
2501     WebAccessibilityTextMarker* end = [WebAccessibilityTextMarker startOrEndTextMarkerForRange:range isStart:NO cache:m_object->axObjectCache()];
2502     if (!start || !end)
2503         return nil;
2504     return [NSArray arrayWithObjects:start, end, nil];
2505 }
2506
2507 - (NSString *)accessibilityIdentifier
2508 {
2509     if (![self _prepareAccessibilityCall])
2510         return nil;
2511     
2512     return m_object->getAttribute(HTMLNames::idAttr);
2513 }
2514
2515 - (NSString *)accessibilitySpeechHint
2516 {
2517     if (![self _prepareAccessibilityCall])
2518         return nil;
2519
2520     switch (m_object->speakProperty()) {
2521     default:
2522     case SpeakNormal:
2523         return @"normal";
2524     case SpeakNone:
2525         return @"none";
2526     case SpeakSpellOut:
2527         return @"spell-out";
2528     case SpeakDigits:
2529         return @"digits";
2530     case SpeakLiteralPunctuation:
2531         return @"literal-punctuation";
2532     case SpeakNoPunctuation:
2533         return @"no-punctuation";
2534     }
2535     
2536     return nil;
2537 }
2538
2539 - (BOOL)accessibilityARIAIsBusy
2540 {
2541     if (![self _prepareAccessibilityCall])
2542         return NO;
2543
2544     return m_object->ariaLiveRegionBusy();
2545 }
2546
2547 - (NSString *)accessibilityARIALiveRegionStatus
2548 {
2549     if (![self _prepareAccessibilityCall])
2550         return nil;
2551
2552     return m_object->ariaLiveRegionStatus();
2553 }
2554
2555 - (NSString *)accessibilityARIARelevantStatus
2556 {
2557     if (![self _prepareAccessibilityCall])
2558         return nil;
2559     
2560     return m_object->ariaLiveRegionRelevant();
2561 }
2562
2563 - (BOOL)accessibilityARIALiveRegionIsAtomic
2564 {
2565     if (![self _prepareAccessibilityCall])
2566         return NO;
2567     
2568     return m_object->ariaLiveRegionAtomic();
2569 }
2570
2571 - (BOOL)accessibilitySupportsARIAPressed
2572 {
2573     if (![self _prepareAccessibilityCall])
2574         return NO;
2575     
2576     return m_object->supportsARIAPressed();
2577 }
2578
2579 - (BOOL)accessibilityIsPressed
2580 {
2581     if (![self _prepareAccessibilityCall])
2582         return NO;
2583     
2584     return m_object->isPressed();
2585 }
2586
2587 - (BOOL)accessibilitySupportsARIAExpanded
2588 {
2589     if (![self _prepareAccessibilityCall])
2590         return NO;
2591     
2592     return m_object->supportsExpanded();
2593 }
2594
2595 - (BOOL)accessibilityIsExpanded
2596 {
2597     if (![self _prepareAccessibilityCall])
2598         return NO;
2599
2600     return m_object->isExpanded();
2601 }
2602
2603 - (NSString *)accessibilityInvalidStatus
2604 {
2605     if (![self _prepareAccessibilityCall])
2606         return nil;
2607     
2608     return m_object->invalidStatus();
2609 }
2610
2611 - (NSString *)accessibilityARIACurrentStatus
2612 {
2613     if (![self _prepareAccessibilityCall])
2614         return nil;
2615     
2616     switch (m_object->ariaCurrentState()) {
2617     case ARIACurrentFalse:
2618         return @"false";
2619     case ARIACurrentPage:
2620         return @"page";
2621     case ARIACurrentStep:
2622         return @"step";
2623     case ARIACurrentLocation:
2624         return @"location";
2625     case ARIACurrentTime:
2626         return @"time";
2627     case ARIACurrentDate:
2628         return @"date";
2629     default:
2630     case ARIACurrentTrue:
2631         return @"true";
2632     }
2633 }
2634
2635 - (WebAccessibilityObjectWrapper *)accessibilityMathRootIndexObject
2636 {
2637     if (![self _prepareAccessibilityCall])
2638         return nil;
2639
2640     return m_object->mathRootIndexObject() ? m_object->mathRootIndexObject()->wrapper() : 0;
2641 }
2642
2643 - (WebAccessibilityObjectWrapper *)accessibilityMathRadicandObject
2644 {
2645     if (![self _prepareAccessibilityCall])
2646         return nil;
2647
2648     return m_object->mathRadicandObject() ? m_object->mathRadicandObject()->wrapper() : 0;
2649 }
2650
2651 - (WebAccessibilityObjectWrapper *)accessibilityMathNumeratorObject
2652 {
2653     if (![self _prepareAccessibilityCall])
2654         return nil;
2655
2656     return m_object->mathNumeratorObject() ? m_object->mathNumeratorObject()->wrapper() : 0;
2657 }
2658
2659 - (WebAccessibilityObjectWrapper *)accessibilityMathDenominatorObject
2660 {
2661     if (![self _prepareAccessibilityCall])
2662         return nil;
2663
2664     return m_object->mathDenominatorObject() ? m_object->mathDenominatorObject()->wrapper() : 0;
2665 }
2666
2667 - (WebAccessibilityObjectWrapper *)accessibilityMathBaseObject
2668 {
2669     if (![self _prepareAccessibilityCall])
2670         return nil;
2671
2672     return m_object->mathBaseObject() ? m_object->mathBaseObject()->wrapper() : 0;
2673 }
2674
2675 - (WebAccessibilityObjectWrapper *)accessibilityMathSubscriptObject
2676 {
2677     if (![self _prepareAccessibilityCall])
2678         return nil;
2679
2680     return m_object->mathSubscriptObject() ? m_object->mathSubscriptObject()->wrapper() : 0;
2681 }
2682
2683 - (WebAccessibilityObjectWrapper *)accessibilityMathSuperscriptObject
2684 {
2685     if (![self _prepareAccessibilityCall])
2686         return nil;
2687
2688     return m_object->mathSuperscriptObject() ? m_object->mathSuperscriptObject()->wrapper() : 0;
2689 }
2690
2691 - (WebAccessibilityObjectWrapper *)accessibilityMathUnderObject
2692 {
2693     if (![self _prepareAccessibilityCall])
2694         return nil;
2695
2696     return m_object->mathUnderObject() ? m_object->mathUnderObject()->wrapper() : 0;
2697 }
2698
2699 - (WebAccessibilityObjectWrapper *)accessibilityMathOverObject
2700 {
2701     if (![self _prepareAccessibilityCall])
2702         return nil;
2703
2704     return m_object->mathOverObject() ? m_object->mathOverObject()->wrapper() : 0;
2705 }
2706
2707 - (NSString *)accessibilityPlatformMathSubscriptKey
2708 {
2709     return @"AXMSubscriptObject";
2710 }
2711
2712 - (NSString *)accessibilityPlatformMathSuperscriptKey
2713 {
2714     return @"AXMSuperscriptObject";
2715 }
2716
2717 - (NSArray *)accessibilityMathPostscripts
2718 {
2719     if (![self _prepareAccessibilityCall])
2720         return nil;
2721     
2722     return [self accessibilityMathPostscriptPairs];
2723 }
2724
2725 - (NSArray *)accessibilityMathPrescripts
2726 {
2727     if (![self _prepareAccessibilityCall])
2728         return nil;
2729     
2730     return [self accessibilityMathPrescriptPairs];
2731 }
2732
2733 - (NSString *)accessibilityMathFencedOpenString
2734 {
2735     if (![self _prepareAccessibilityCall])
2736         return nil;
2737
2738     return m_object->mathFencedOpenString();
2739 }
2740
2741 - (NSString *)accessibilityMathFencedCloseString
2742 {
2743     if (![self _prepareAccessibilityCall])
2744         return nil;
2745
2746     return m_object->mathFencedCloseString();
2747 }
2748
2749 - (BOOL)accessibilityIsMathTopObject
2750 {
2751     if (![self _prepareAccessibilityCall])
2752         return NO;
2753
2754     return m_object->roleValue() == DocumentMathRole;
2755 }
2756
2757 - (NSInteger)accessibilityMathLineThickness
2758 {
2759     if (![self _prepareAccessibilityCall])
2760         return 0;
2761
2762     return m_object->mathLineThickness();
2763 }
2764
2765 - (NSString *)accessibilityMathType
2766 {
2767     if (![self _prepareAccessibilityCall])
2768         return nil;
2769
2770     if (m_object->roleValue() == MathElementRole) {
2771         if (m_object->isMathFraction())
2772             return @"AXMathFraction";
2773         if (m_object->isMathFenced())
2774             return @"AXMathFenced";
2775         if (m_object->isMathSubscriptSuperscript())
2776             return @"AXMathSubscriptSuperscript";
2777         if (m_object->isMathRow())
2778             return @"AXMathRow";
2779         if (m_object->isMathUnderOver())
2780             return @"AXMathUnderOver";
2781         if (m_object->isMathSquareRoot())
2782             return @"AXMathSquareRoot";
2783         if (m_object->isMathRoot())
2784             return @"AXMathRoot";
2785         if (m_object->isMathText())
2786             return @"AXMathText";
2787         if (m_object->isMathNumber())
2788             return @"AXMathNumber";
2789         if (m_object->isMathIdentifier())
2790             return @"AXMathIdentifier";
2791         if (m_object->isMathTable())
2792             return @"AXMathTable";
2793         if (m_object->isMathTableRow())
2794             return @"AXMathTableRow";
2795         if (m_object->isMathTableCell())
2796             return @"AXMathTableCell";
2797         if (m_object->isMathFenceOperator())
2798             return @"AXMathFenceOperator";
2799         if (m_object->isMathSeparatorOperator())
2800             return @"AXMathSeparatorOperator";
2801         if (m_object->isMathOperator())
2802             return @"AXMathOperator";
2803         if (m_object->isMathMultiscript())
2804             return @"AXMathMultiscript";
2805     }
2806     
2807     return nil;
2808 }
2809
2810 - (CGPoint)accessibilityClickPoint
2811 {
2812     return m_object->clickPoint();
2813 }
2814
2815 #ifndef NDEBUG
2816 - (NSString *)description
2817 {
2818     CGRect frame = [self accessibilityFrame];
2819     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];
2820 }
2821 #endif
2822
2823 @end
2824
2825 #endif // HAVE(ACCESSIBILITY) && PLATFORM(IOS)