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