Hitpoint for link which spans two lines in web content is incorrect
[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     IntPoint point = m_object->clickPoint();
1604     return [self _accessibilityConvertPointToViewSpace:point];
1605 }
1606
1607 - (CGRect)accessibilityFrame
1608 {
1609     if (![self _prepareAccessibilityCall])
1610         return CGRectZero;
1611     
1612     auto rect = FloatRect(snappedIntRect(m_object->elementRect()));
1613     return [self convertRectToSpace:rect space:AccessibilityConversionSpace::Screen];
1614 }
1615
1616 // Checks whether a link contains only static text and images (and has been divided unnaturally by <spans> and other nefarious mechanisms).
1617 - (BOOL)containsUnnaturallySegmentedChildren
1618 {
1619     if (!m_object)
1620         return NO;
1621     
1622     AccessibilityRole role = m_object->roleValue();
1623     if (role != AccessibilityRole::Link && role != AccessibilityRole::WebCoreLink)
1624         return NO;
1625     
1626     const auto& children = m_object->children();
1627     unsigned childrenSize = children.size();
1628
1629     // If there's only one child, then it doesn't have segmented children. 
1630     if (childrenSize == 1)
1631         return NO;
1632     
1633     for (unsigned i = 0; i < childrenSize; ++i) {
1634         AccessibilityRole role = children[i]->roleValue();
1635         if (role != AccessibilityRole::StaticText && role != AccessibilityRole::Image && role != AccessibilityRole::Group && role != AccessibilityRole::TextGroup)
1636             return NO;
1637     }
1638     
1639     return YES;
1640 }
1641
1642 - (id)accessibilityContainer
1643 {
1644     if (![self _prepareAccessibilityCall])
1645         return nil;
1646
1647     AXAttributeCacheEnabler enableCache(m_object->axObjectCache());
1648     
1649     // As long as there's a parent wrapper, that's the correct chain to climb.
1650     AccessibilityObject* parent = m_object->parentObjectUnignored(); 
1651     if (parent)
1652         return parent->wrapper();
1653
1654     // Mock objects can have their parents detached but still exist in the cache.
1655     if (m_object->isDetachedFromParent())
1656         return nil;
1657     
1658     // The only object without a parent wrapper at this point should be a scroll view.
1659     ASSERT(m_object->isAccessibilityScrollView());
1660     
1661     // Verify this is the top document. If not, we might need to go through the platform widget.
1662     FrameView* frameView = m_object->documentFrameView();
1663     Document* document = m_object->document();
1664     if (document && frameView && document != &document->topDocument())
1665         return frameView->platformWidget();
1666     
1667     // The top scroll view's parent is the web document view.
1668     return [self _accessibilityWebDocumentView];
1669 }
1670
1671 - (id)accessibilityFocusedUIElement
1672 {
1673     if (![self _prepareAccessibilityCall])
1674         return nil;
1675     
1676     AccessibilityObject* focusedObj = downcast<AccessibilityObject>(m_object->focusedUIElement());
1677     
1678     if (!focusedObj)
1679         return nil;
1680     
1681     return focusedObj->wrapper();
1682 }
1683
1684 - (id)_accessibilityWebDocumentView
1685 {
1686     if (![self _prepareAccessibilityCall])
1687         return nil;
1688
1689     // This method performs the crucial task of connecting to the UIWebDocumentView.
1690     // This is needed to correctly calculate the screen position of the AX object.
1691     static Class webViewClass = nil;
1692     if (!webViewClass)
1693         webViewClass = NSClassFromString(@"WebView");
1694
1695     if (!webViewClass)
1696         return nil;
1697     
1698     FrameView* frameView = m_object->documentFrameView();
1699
1700     if (!frameView)
1701         return nil;
1702     
1703     // If this is the top level frame, the UIWebDocumentView should be returned.
1704     id parentView = frameView->documentView();
1705     while (parentView && ![parentView isKindOfClass:webViewClass])
1706         parentView = [parentView superview];
1707     
1708     // The parentView should have an accessibilityContainer, if the UIKit accessibility bundle was loaded. 
1709     // The exception is DRT, which tests accessibility without the entire system turning accessibility on. Hence,
1710     // this check should be valid for everything except DRT.
1711     ASSERT([parentView accessibilityContainer] || IOSApplication::isDumpRenderTree());
1712     
1713     return [parentView accessibilityContainer];
1714 }
1715
1716 - (NSArray *)_accessibilityNextElementsWithCount:(UInt32)count
1717 {    
1718     if (![self _prepareAccessibilityCall])
1719         return nil;
1720     
1721     return [[self _accessibilityWebDocumentView] _accessibilityNextElementsWithCount:count];
1722 }
1723
1724 - (NSArray *)_accessibilityPreviousElementsWithCount:(UInt32)count
1725 {
1726     if (![self _prepareAccessibilityCall])
1727         return nil;
1728     
1729     return [[self _accessibilityWebDocumentView] _accessibilityPreviousElementsWithCount:count];
1730 }
1731
1732 - (BOOL)accessibilityCanSetValue
1733 {
1734     if (![self _prepareAccessibilityCall])
1735         return NO;
1736     
1737     return m_object->canSetValueAttribute();
1738 }
1739
1740 - (NSString *)accessibilityLinkRelationshipType
1741 {
1742     if (![self _prepareAccessibilityCall])
1743         return nil;
1744     
1745     return m_object->linkRelValue();
1746 }
1747
1748 - (BOOL)accessibilityRequired
1749 {
1750     if (![self _prepareAccessibilityCall])
1751         return NO;
1752
1753     return m_object->isRequired();
1754 }
1755
1756 - (NSArray *)accessibilityFlowToElements
1757 {
1758     if (![self _prepareAccessibilityCall])
1759         return nil;
1760     
1761     AccessibilityObject::AccessibilityChildrenVector children;
1762     m_object->ariaFlowToElements(children);
1763     
1764     unsigned length = children.size();
1765     NSMutableArray* array = [NSMutableArray arrayWithCapacity:length];
1766     for (unsigned i = 0; i < length; ++i) {
1767         AccessibilityObjectWrapper* wrapper = children[i]->wrapper();
1768         ASSERT(wrapper);
1769         if (!wrapper)
1770             continue;
1771
1772         if (children[i]->isAttachment() && [wrapper attachmentView])
1773             [array addObject:[wrapper attachmentView]];
1774         else
1775             [array addObject:wrapper];
1776     }
1777     return array;
1778 }
1779
1780 - (id)accessibilityLinkedElement
1781 {
1782     if (![self _prepareAccessibilityCall])
1783         return nil;
1784     
1785     // If this static text inside of a link, it should use its parent's linked element.
1786     AccessibilityObject* element = m_object;
1787     if (m_object->roleValue() == AccessibilityRole::StaticText && m_object->parentObjectUnignored()->isLink())
1788         element = m_object->parentObjectUnignored();
1789     
1790     AccessibilityObject::AccessibilityChildrenVector children;
1791     element->linkedUIElements(children);
1792     if (children.size() == 0)
1793         return nil;
1794     
1795     return children[0]->wrapper();
1796 }
1797
1798
1799 - (BOOL)isAttachment
1800 {
1801     if (!m_object)
1802         return NO;
1803     
1804     return m_object->isAttachment();
1805 }
1806
1807 - (NSString *)accessibilityTextualContext
1808 {
1809     if (![self _prepareAccessibilityCall])
1810         return nil;
1811
1812     if (m_object->node() && m_object->node()->hasTagName(codeTag))
1813         return UIAccessibilityTextualContextSourceCode;
1814     
1815     return nil;
1816 }
1817
1818 - (BOOL)_accessibilityActivate
1819 {
1820     if (![self _prepareAccessibilityCall])
1821         return NO;
1822
1823     return m_object->press();
1824 }
1825
1826 - (id)attachmentView
1827 {
1828     if (![self _prepareAccessibilityCall])
1829         return nil;
1830
1831     ASSERT([self isAttachment]);
1832     Widget* widget = m_object->widgetForAttachmentView();
1833     if (!widget)
1834         return nil;
1835     return widget->platformWidget();    
1836 }
1837
1838 static RenderObject* rendererForView(WAKView* view)
1839 {
1840     if (![view conformsToProtocol:@protocol(WebCoreFrameView)])
1841         return nil;
1842     
1843     WAKView<WebCoreFrameView>* frameView = (WAKView<WebCoreFrameView>*)view;
1844     Frame* frame = [frameView _web_frame];
1845     if (!frame)
1846         return nil;
1847     
1848     Node* node = frame->document()->ownerElement();
1849     if (!node)
1850         return nil;
1851     
1852     return node->renderer();
1853 }
1854
1855 - (id)_accessibilityParentForSubview:(id)subview
1856 {   
1857     RenderObject* renderer = rendererForView(subview);
1858     if (!renderer)
1859         return nil;
1860     
1861     AccessibilityObject* obj = renderer->document().axObjectCache()->getOrCreate(renderer);
1862     if (obj)
1863         return obj->parentObjectUnignored()->wrapper();
1864     return nil;
1865 }
1866
1867 - (void)postFocusChangeNotification
1868 {
1869     // The UIKit accessibility wrapper will override and post appropriate notification.
1870 }
1871
1872 - (void)postSelectedTextChangeNotification
1873 {
1874     // The UIKit accessibility wrapper will override and post appropriate notification.    
1875 }
1876
1877 - (void)postLayoutChangeNotification
1878 {
1879     // The UIKit accessibility wrapper will override and post appropriate notification.        
1880 }
1881
1882 - (void)postLiveRegionChangeNotification
1883 {
1884     // The UIKit accessibility wrapper will override and post appropriate notification.    
1885 }
1886
1887 - (void)postLiveRegionCreatedNotification
1888 {
1889     // The UIKit accessibility wrapper will override and post appropriate notification.    
1890 }
1891
1892 - (void)postLoadCompleteNotification
1893 {
1894     // The UIKit accessibility wrapper will override and post appropriate notification.    
1895 }
1896
1897 - (void)postChildrenChangedNotification
1898 {
1899     // The UIKit accessibility wrapper will override and post appropriate notification.    
1900 }
1901
1902 - (void)postInvalidStatusChangedNotification
1903 {
1904     // The UIKit accessibility wrapper will override and post appropriate notification.        
1905 }
1906
1907 - (void)postValueChangedNotification
1908 {
1909     // The UIKit accessibility wrapper will override and post appropriate notification.
1910 }
1911
1912 - (void)postExpandedChangedNotification
1913 {
1914     // The UIKit accessibility wrapper will override and post appropriate notification.
1915 }
1916
1917 - (void)postScrollStatusChangeNotification
1918 {
1919     // The UIKit accessibility wrapper will override and post appropriate notification.
1920 }
1921
1922 // These will be used by the UIKit wrapper to calculate an appropriate description of scroll status.
1923 - (CGPoint)_accessibilityScrollPosition
1924 {
1925     if (![self _prepareAccessibilityCall])
1926         return CGPointZero;
1927     
1928     return m_object->scrollPosition();
1929 }
1930
1931 - (CGSize)_accessibilityScrollSize
1932 {
1933     if (![self _prepareAccessibilityCall])
1934         return CGSizeZero;
1935     
1936     return m_object->scrollContentsSize();
1937 }
1938
1939 - (CGRect)_accessibilityScrollVisibleRect
1940 {
1941     if (![self _prepareAccessibilityCall])
1942         return CGRectZero;
1943     
1944     return m_object->scrollVisibleContentRect();
1945 }
1946
1947 - (AccessibilityObject*)detailParentForSummaryObject:(AccessibilityObject*)object
1948 {
1949     // Use this to check if an object is the child of a summary object.
1950     // And return the summary's parent, which is the expandable details object.
1951     if (const AccessibilityObject* summary = AccessibilityObject::matchedParent(*object, true, [] (const AccessibilityObject& object) {
1952         return object.hasTagName(summaryTag);
1953     }))
1954         return summary->parentObject();
1955     return nil;
1956 }
1957
1958 - (AccessibilityObject*)detailParentForObject:(AccessibilityObject*)object
1959 {
1960     // Use this to check if an object is inside a details object.
1961     if (const AccessibilityObject* details = AccessibilityObject::matchedParent(*object, true, [] (const AccessibilityObject& object) {
1962         return object.hasTagName(detailsTag);
1963     }))
1964         return const_cast<AccessibilityObject*>(details);
1965     return nil;
1966 }
1967
1968 - (AccessibilityObject*)treeItemParentForObject:(AccessibilityObject*)object
1969 {
1970     // Use this to check if an object is inside a treeitem object.
1971     if (const AccessibilityObject* parent = AccessibilityObject::matchedParent(*object, true, [] (const AccessibilityObject& object) {
1972         return object.roleValue() == AccessibilityRole::TreeItem;
1973     }))
1974         return const_cast<AccessibilityObject*>(parent);
1975     return nil;
1976 }
1977
1978 - (NSArray<WebAccessibilityObjectWrapper *> *)accessibilityFindMatchingObjects:(NSDictionary *)parameters
1979 {
1980     AccessibilitySearchCriteria criteria = accessibilitySearchCriteriaForSearchPredicateParameterizedAttribute(parameters);
1981     AccessibilityObject::AccessibilityChildrenVector results;
1982     m_object->findMatchingObjects(&criteria, results);
1983     return (NSArray *)convertToNSArray(results);
1984 }
1985
1986 - (void)accessibilityModifySelection:(TextGranularity)granularity increase:(BOOL)increase
1987 {
1988     if (![self _prepareAccessibilityCall])
1989         return;
1990     
1991     FrameSelection& frameSelection = m_object->document()->frame()->selection();
1992     VisibleSelection selection = m_object->selection();
1993     VisiblePositionRange range = m_object->visiblePositionRange();
1994     
1995     // Before a selection with length exists, the cursor position needs to move to the right starting place.
1996     // That should be the beginning of this element (range.start). However, if the cursor is already within the 
1997     // range of this element (the cursor is represented by selection), then the cursor does not need to move.
1998     if (frameSelection.isNone() && (selection.visibleStart() < range.start || selection.visibleEnd() > range.end))
1999         frameSelection.moveTo(range.start, UserTriggered);
2000     
2001     frameSelection.modify(FrameSelection::AlterationExtend, (increase) ? DirectionRight : DirectionLeft, granularity, UserTriggered);
2002 }
2003
2004 - (void)accessibilityIncreaseSelection:(TextGranularity)granularity
2005 {
2006     [self accessibilityModifySelection:granularity increase:YES];
2007 }
2008
2009 - (void)_accessibilitySetFocus:(BOOL)focus
2010 {
2011     [self baseAccessibilitySetFocus:focus];
2012 }
2013
2014 - (void)accessibilityDecreaseSelection:(TextGranularity)granularity
2015 {
2016     [self accessibilityModifySelection:granularity increase:NO];
2017 }
2018
2019 - (void)accessibilityMoveSelectionToMarker:(WebAccessibilityTextMarker *)marker
2020 {
2021     if (![self _prepareAccessibilityCall])
2022         return;
2023     
2024     VisiblePosition visiblePosition = [marker visiblePosition];
2025     if (visiblePosition.isNull())
2026         return;
2027
2028     FrameSelection& frameSelection = m_object->document()->frame()->selection();
2029     frameSelection.moveTo(visiblePosition, UserTriggered);
2030 }
2031
2032 - (void)accessibilityIncrement
2033 {
2034     if (![self _prepareAccessibilityCall])
2035         return;
2036
2037     m_object->increment();
2038 }
2039
2040 - (void)accessibilityDecrement
2041 {
2042     if (![self _prepareAccessibilityCall])
2043         return;
2044
2045     m_object->decrement();
2046 }
2047
2048 #pragma mark Accessibility Text Marker Handlers
2049
2050 - (BOOL)_addAccessibilityObject:(AccessibilityObject*)axObject toTextMarkerArray:(NSMutableArray *)array
2051 {
2052     if (!axObject)
2053         return NO;
2054     
2055     AccessibilityObjectWrapper* wrapper = axObject->wrapper();
2056     if (!wrapper)
2057         return NO;
2058
2059     // Don't add the same object twice, but since this has already been added, we should return
2060     // YES because we want to inform that it's in the array
2061     if ([array containsObject:wrapper])
2062         return YES;
2063     
2064     // Explicitly set that this is now an element (in case other logic tries to override).
2065     [wrapper setValue:@YES forKey:@"isAccessibilityElement"];    
2066     [array addObject:wrapper];
2067     return YES;
2068 }
2069
2070 - (void)_accessibilitySetValue:(NSString *)string
2071 {
2072     if (![self _prepareAccessibilityCall])
2073         return;
2074     m_object->setValue(string);
2075 }
2076
2077 - (NSString *)stringForTextMarkers:(NSArray *)markers
2078 {
2079     if (![self _prepareAccessibilityCall])
2080         return nil;
2081     
2082     RefPtr<Range> range = [self rangeForTextMarkers:markers];
2083     if (!range)
2084         return nil;
2085     
2086     return m_object->stringForRange(range);
2087 }
2088
2089 static int blockquoteLevel(RenderObject* renderer)
2090 {
2091     if (!renderer)
2092         return 0;
2093     
2094     int result = 0;
2095     for (Node* node = renderer->node(); node; node = node->parentNode()) {
2096         if (node->hasTagName(blockquoteTag))
2097             result += 1;
2098     }
2099     
2100     return result;
2101 }
2102
2103 static void AXAttributeStringSetLanguage(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
2104 {
2105     if (!renderer)
2106         return;
2107     
2108     AccessibilityObject* axObject = renderer->document().axObjectCache()->getOrCreate(renderer);
2109     NSString *language = axObject->language();
2110     if ([language length])
2111         [attrString addAttribute:UIAccessibilityTokenLanguage value:language range:range];
2112     else
2113         [attrString removeAttribute:UIAccessibilityTokenLanguage range:range];
2114 }
2115
2116 static void AXAttributeStringSetBlockquoteLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
2117 {
2118     int quoteLevel = blockquoteLevel(renderer);
2119     
2120     if (quoteLevel)
2121         [attrString addAttribute:UIAccessibilityTokenBlockquoteLevel value:[NSNumber numberWithInt:quoteLevel] range:range];
2122     else
2123         [attrString removeAttribute:UIAccessibilityTokenBlockquoteLevel range:range];
2124 }
2125
2126 static void AXAttributeStringSetHeadingLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
2127 {
2128     if (!renderer)
2129         return;
2130     
2131     AccessibilityObject* parentObject = renderer->document().axObjectCache()->getOrCreate(renderer->parent());
2132     int parentHeadingLevel = parentObject->headingLevel();
2133     
2134     if (parentHeadingLevel)
2135         [attrString addAttribute:UIAccessibilityTokenHeadingLevel value:[NSNumber numberWithInt:parentHeadingLevel] range:range];
2136     else
2137         [attrString removeAttribute:UIAccessibilityTokenHeadingLevel range:range];
2138 }
2139
2140 static void AXAttributeStringSetFont(NSMutableAttributedString* attrString, CTFontRef font, NSRange range)
2141 {
2142     if (!font)
2143         return;
2144     
2145     RetainPtr<CFStringRef> fullName = adoptCF(CTFontCopyFullName(font));
2146     RetainPtr<CFStringRef> familyName = adoptCF(CTFontCopyFamilyName(font));
2147
2148     NSNumber* size = [NSNumber numberWithFloat:CTFontGetSize(font)];
2149     CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(font);
2150     NSNumber* bold = [NSNumber numberWithBool:(traits & kCTFontTraitBold)];
2151     if (fullName)
2152         [attrString addAttribute:UIAccessibilityTokenFontName value:(NSString*)fullName.get() range:range];
2153     if (familyName)
2154         [attrString addAttribute:UIAccessibilityTokenFontFamily value:(NSString*)familyName.get() range:range];
2155     if ([size boolValue])
2156         [attrString addAttribute:UIAccessibilityTokenFontSize value:size range:range];
2157     if ([bold boolValue] || (traits & kCTFontTraitBold))
2158         [attrString addAttribute:UIAccessibilityTokenBold value:@YES range:range];
2159     if (traits & kCTFontTraitItalic)
2160         [attrString addAttribute:UIAccessibilityTokenItalic value:@YES range:range];
2161
2162 }
2163
2164 static void AXAttributeStringSetNumber(NSMutableAttributedString* attrString, NSString* attribute, NSNumber* number, NSRange range)
2165 {
2166     if (number)
2167         [attrString addAttribute:attribute value:number range:range];
2168     else
2169         [attrString removeAttribute:attribute range:range];
2170 }
2171
2172 static void AXAttributeStringSetStyle(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
2173 {
2174     auto& style = renderer->style();
2175     
2176     // set basic font info
2177     AXAttributeStringSetFont(attrString, style.fontCascade().primaryFont().getCTFont(), range);
2178                 
2179     auto decor = style.textDecorationsInEffect();
2180     if (decor & TextDecoration::Underline)
2181         AXAttributeStringSetNumber(attrString, UIAccessibilityTokenUnderline, @YES, range);
2182
2183     // Add code context if this node is within a <code> block.
2184     AccessibilityObject* axObject = renderer->document().axObjectCache()->getOrCreate(renderer);
2185     auto matchFunc = [] (const AccessibilityObject& object) {
2186         return object.node() && object.node()->hasTagName(codeTag);
2187     };
2188     
2189     if (const AccessibilityObject* parent = AccessibilityObject::matchedParent(*axObject, true, WTFMove(matchFunc)))
2190         [attrString addAttribute:UIAccessibilityTextAttributeContext value:UIAccessibilityTextualContextSourceCode range:range];
2191 }
2192
2193 static void AXAttributedStringAppendText(NSMutableAttributedString* attrString, Node* node, NSString *text)
2194 {
2195     // skip invisible text
2196     if (!node->renderer())
2197         return;
2198     
2199     // easier to calculate the range before appending the string
2200     NSRange attrStringRange = NSMakeRange([attrString length], [text length]);
2201     
2202     // append the string from this node
2203     [[attrString mutableString] appendString:text];
2204     
2205     // set new attributes
2206     AXAttributeStringSetStyle(attrString, node->renderer(), attrStringRange);
2207     AXAttributeStringSetHeadingLevel(attrString, node->renderer(), attrStringRange);
2208     AXAttributeStringSetBlockquoteLevel(attrString, node->renderer(), attrStringRange);    
2209     AXAttributeStringSetLanguage(attrString, node->renderer(), attrStringRange);
2210 }
2211
2212
2213 // This method is intended to return an array of strings and accessibility elements that 
2214 // represent the objects on one line of rendered web content. The array of markers sent
2215 // in should be ordered and contain only a start and end marker.
2216 - (NSArray *)arrayOfTextForTextMarkers:(NSArray *)markers attributed:(BOOL)attributed
2217 {
2218     if (![self _prepareAccessibilityCall])
2219         return nil;
2220
2221     if ([markers count] != 2)
2222         return nil;
2223     
2224     WebAccessibilityTextMarker* startMarker = [markers objectAtIndex:0];
2225     WebAccessibilityTextMarker* endMarker = [markers objectAtIndex:1];
2226     if (![startMarker isKindOfClass:[WebAccessibilityTextMarker class]] || ![endMarker isKindOfClass:[WebAccessibilityTextMarker class]])
2227         return nil;
2228     
2229     // extract the start and end VisiblePosition
2230     VisiblePosition startVisiblePosition = [startMarker visiblePosition];
2231     if (startVisiblePosition.isNull())
2232         return nil;
2233     
2234     VisiblePosition endVisiblePosition = [endMarker visiblePosition];
2235     if (endVisiblePosition.isNull())
2236         return nil;
2237     
2238     // iterate over the range to build the AX attributed string
2239     NSMutableArray* array = [[NSMutableArray alloc] init];
2240     TextIterator it(makeRange(startVisiblePosition, endVisiblePosition).get());
2241     for (; !it.atEnd(); it.advance()) {
2242         // locate the node and starting offset for this range
2243         Node& node = it.range()->startContainer();
2244         ASSERT(&node == &it.range()->endContainer());
2245         int offset = it.range()->startOffset();
2246         
2247         // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
2248         if (it.text().length() != 0) {
2249             if (!attributed) {
2250                 // First check if this is represented by a link.
2251                 AccessibilityObject* linkObject = AccessibilityObject::anchorElementForNode(&node);
2252                 if ([self _addAccessibilityObject:linkObject toTextMarkerArray:array])
2253                     continue;
2254                 
2255                 // Next check if this region is represented by a heading.
2256                 AccessibilityObject* headingObject = AccessibilityObject::headingElementForNode(&node);
2257                 if ([self _addAccessibilityObject:headingObject toTextMarkerArray:array])
2258                     continue;
2259                 
2260                 String listMarkerText = m_object->listMarkerTextForNodeAndPosition(&node, VisiblePosition(it.range()->startPosition()));
2261                 
2262                 if (!listMarkerText.isEmpty()) 
2263                     [array addObject:listMarkerText];
2264                 // There was not an element representation, so just return the text.
2265                 [array addObject:it.text().createNSString().get()];
2266             }
2267             else
2268             {
2269                 String listMarkerText = m_object->listMarkerTextForNodeAndPosition(&node, VisiblePosition(it.range()->startPosition()));
2270
2271                 if (!listMarkerText.isEmpty()) {
2272                     NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] init];
2273                     AXAttributedStringAppendText(attrString, &node, listMarkerText);
2274                     [array addObject:attrString];
2275                     [attrString release];
2276                 }
2277                 
2278                 NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] init];
2279                 AXAttributedStringAppendText(attrString, &node, it.text().createNSStringWithoutCopying().get());
2280                 [array addObject:attrString];
2281                 [attrString release];
2282             }
2283         } else {
2284             Node* replacedNode = node.traverseToChildAt(offset);
2285             if (replacedNode) {
2286                 AccessibilityObject* obj = m_object->axObjectCache()->getOrCreate(replacedNode->renderer());
2287                 if (obj && !obj->accessibilityIsIgnored())
2288                     [self _addAccessibilityObject:obj toTextMarkerArray:array];
2289             }
2290         }
2291     }
2292     
2293     return [array autorelease];
2294 }
2295
2296 - (NSRange)_convertToNSRange:(Range *)range
2297 {
2298     if (!range)
2299         return NSMakeRange(NSNotFound, 0);
2300
2301     Document* document = m_object->document();
2302     Element* selectionRoot = document->frame()->selection().selection().rootEditableElement();
2303     Element* scope = selectionRoot ? selectionRoot : document->documentElement();
2304
2305     // Mouse events may cause TSM to attempt to create an NSRange for a portion of the view
2306     // that is not inside the current editable region.  These checks ensure we don't produce
2307     // potentially invalid data when responding to such requests.
2308     if (&range->startContainer() != scope && !range->startContainer().isDescendantOf(scope))
2309         return NSMakeRange(NSNotFound, 0);
2310     if (&range->endContainer() != scope && !range->endContainer().isDescendantOf(scope))
2311         return NSMakeRange(NSNotFound, 0);
2312
2313     auto testRange = Range::create(scope->document(), scope, 0, &range->startContainer(), range->startOffset());
2314     ASSERT(&testRange->startContainer() == scope);
2315     int startPosition = TextIterator::rangeLength(testRange.ptr());
2316     testRange->setEnd(range->endContainer(), range->endOffset());
2317     ASSERT(&testRange->startContainer() == scope);
2318     int endPosition = TextIterator::rangeLength(testRange.ptr());
2319     return NSMakeRange(startPosition, endPosition - startPosition);
2320 }
2321
2322 - (RefPtr<Range>)_convertToDOMRange:(NSRange)nsrange
2323 {
2324     if (nsrange.location > INT_MAX)
2325         return nullptr;
2326     if (nsrange.length > INT_MAX || nsrange.location + nsrange.length > INT_MAX)
2327         nsrange.length = INT_MAX - nsrange.location;
2328         
2329     // our critical assumption is that we are only called by input methods that
2330     // concentrate on a given area containing the selection
2331     // We have to do this because of text fields and textareas. The DOM for those is not
2332     // directly in the document DOM, so serialization is problematic. Our solution is
2333     // to use the root editable element of the selection start as the positional base.
2334     // That fits with AppKit's idea of an input context.
2335     Document* document = m_object->document();
2336     Element* selectionRoot = document->frame()->selection().selection().rootEditableElement();
2337     Element* scope = selectionRoot ? selectionRoot : document->documentElement();
2338     return TextIterator::rangeFromLocationAndLength(scope, nsrange.location, nsrange.length);
2339 }
2340
2341 // This method is intended to take a text marker representing a VisiblePosition and convert it
2342 // into a normalized location within the document.
2343 - (NSInteger)positionForTextMarker:(WebAccessibilityTextMarker *)marker
2344 {
2345     if (![self _prepareAccessibilityCall])
2346         return NSNotFound;
2347
2348     if (!marker)
2349         return NSNotFound;    
2350
2351     if (AXObjectCache* cache = m_object->axObjectCache()) {
2352         CharacterOffset characterOffset = [marker characterOffset];
2353         // Create a collapsed range from the CharacterOffset object.
2354         RefPtr<Range> range = cache->rangeForUnorderedCharacterOffsets(characterOffset, characterOffset);
2355         NSRange nsRange = [self _convertToNSRange:range.get()];
2356         return nsRange.location;
2357     }
2358     return NSNotFound;
2359 }
2360
2361 - (NSArray *)textMarkerRange
2362 {
2363     if (![self _prepareAccessibilityCall])
2364         return nil;
2365     
2366     RefPtr<Range> range = m_object->elementRange();
2367     return [self textMarkersForRange:range];
2368 }
2369
2370 // A method to get the normalized text cursor range of an element. Used in DumpRenderTree.
2371 - (NSRange)elementTextRange
2372 {
2373     if (![self _prepareAccessibilityCall])
2374         return NSMakeRange(NSNotFound, 0);
2375
2376     NSArray *markers = [self textMarkerRange];
2377     if ([markers count] != 2)
2378         return NSMakeRange(NSNotFound, 0);
2379     
2380     WebAccessibilityTextMarker *startMarker = [markers objectAtIndex:0];
2381     WebAccessibilityTextMarker *endMarker = [markers objectAtIndex:1];
2382     
2383     NSInteger startPosition = [self positionForTextMarker:startMarker];
2384     NSInteger endPosition = [self positionForTextMarker:endMarker];
2385     
2386     return NSMakeRange(startPosition, endPosition - startPosition);
2387 }
2388
2389 - (AccessibilityObjectWrapper *)accessibilityObjectForTextMarker:(WebAccessibilityTextMarker *)marker
2390 {
2391     if (![self _prepareAccessibilityCall])
2392         return nil;
2393
2394     if (!marker)
2395         return nil;
2396     
2397     AccessibilityObject* obj = [marker accessibilityObject];
2398     if (!obj)
2399         return nil;
2400     
2401     return AccessibilityUnignoredAncestor(obj->wrapper());
2402 }
2403
2404 - (NSArray *)textMarkerRangeForSelection
2405 {
2406     if (![self _prepareAccessibilityCall])
2407         return nil;
2408     
2409     VisibleSelection selection = m_object->selection();
2410     if (selection.isNone())
2411         return nil;
2412     
2413     AXObjectCache* cache = m_object->axObjectCache();
2414     if (!cache)
2415         return nil;
2416     
2417     RefPtr<Range> range = selection.toNormalizedRange();
2418     if (!range)
2419         return nil;
2420
2421     CharacterOffset start = cache->startOrEndCharacterOffsetForRange(range, true);
2422     CharacterOffset end = cache->startOrEndCharacterOffsetForRange(range, false);
2423
2424     WebAccessibilityTextMarker* startMarker = [WebAccessibilityTextMarker textMarkerWithCharacterOffset:start cache:cache];
2425     WebAccessibilityTextMarker* endMarker = [WebAccessibilityTextMarker textMarkerWithCharacterOffset:end cache:cache];
2426     if (!startMarker || !endMarker)
2427         return nil;
2428     
2429     return [NSArray arrayWithObjects:startMarker, endMarker, nil];
2430 }
2431
2432 - (WebAccessibilityTextMarker *)textMarkerForPosition:(NSInteger)position
2433 {
2434     if (![self _prepareAccessibilityCall])
2435         return nil;
2436
2437     RefPtr<Range> range = [self _convertToDOMRange:NSMakeRange(position, 0)];
2438     if (!range)
2439         return nil;
2440
2441     AXObjectCache* cache = m_object->axObjectCache();
2442     if (!cache)
2443         return nil;
2444     
2445     CharacterOffset characterOffset = cache->startOrEndCharacterOffsetForRange(range, true);
2446     return [WebAccessibilityTextMarker textMarkerWithCharacterOffset:characterOffset cache:cache];
2447 }
2448
2449 - (id)_stringFromStartMarker:(WebAccessibilityTextMarker*)startMarker toEndMarker:(WebAccessibilityTextMarker*)endMarker attributed:(BOOL)attributed
2450 {
2451     if (!startMarker || !endMarker)
2452         return nil;
2453     
2454     NSArray* array = [self arrayOfTextForTextMarkers:[NSArray arrayWithObjects:startMarker, endMarker, nil] attributed:attributed];
2455     Class returnClass = attributed ? [NSMutableAttributedString class] : [NSMutableString class];
2456     id returnValue = [[(NSString *)[returnClass alloc] init] autorelease];
2457     
2458     const unichar attachmentChar = NSAttachmentCharacter;
2459     NSInteger count = [array count];
2460     for (NSInteger k = 0; k < count; ++k) {
2461         id object = [array objectAtIndex:k];
2462
2463         if (attributed && [object isKindOfClass:[WebAccessibilityObjectWrapper class]])
2464             object = [[[NSMutableAttributedString alloc] initWithString:[NSString stringWithCharacters:&attachmentChar length:1] attributes:@{ UIAccessibilityTokenAttachment : object }] autorelease];
2465         
2466         if (![object isKindOfClass:returnClass])
2467             continue;
2468         
2469         if (attributed)
2470             [(NSMutableAttributedString *)returnValue appendAttributedString:object];
2471         else
2472             [(NSMutableString *)returnValue appendString:object];
2473     }
2474     return returnValue;
2475 }
2476
2477 - (id)_stringForRange:(NSRange)range attributed:(BOOL)attributed
2478 {
2479     if (![self _prepareAccessibilityCall])
2480         return nil;
2481     
2482     WebAccessibilityTextMarker* startMarker = [self textMarkerForPosition:range.location];
2483     WebAccessibilityTextMarker* endMarker = [self textMarkerForPosition:NSMaxRange(range)];
2484     
2485     // Clients don't always know the exact range, rather than force them to compute it,
2486     // allow clients to overshoot and use the max text marker range.
2487     if (!startMarker || !endMarker) {
2488         NSArray *markers = [self textMarkerRange];
2489         if ([markers count] != 2)
2490             return nil;
2491         if (!startMarker)
2492             startMarker = [markers objectAtIndex:0];
2493         if (!endMarker)
2494             endMarker = [markers objectAtIndex:1];
2495     }
2496     
2497     return [self _stringFromStartMarker:startMarker toEndMarker:endMarker attributed:attributed];
2498 }
2499
2500
2501 // A convenience method for getting the text of a NSRange. Currently used only by DRT.
2502 - (NSString *)stringForRange:(NSRange)range
2503 {
2504     return [self _stringForRange:range attributed:NO];
2505 }
2506
2507 - (NSAttributedString *)attributedStringForRange:(NSRange)range
2508 {
2509     return [self _stringForRange:range attributed:YES];
2510 }
2511
2512 - (NSAttributedString *)attributedStringForElement
2513 {
2514     if (![self _prepareAccessibilityCall])
2515         return nil;
2516     
2517     NSArray *markers = [self textMarkerRange];
2518     if ([markers count] != 2)
2519         return nil;
2520     
2521     return [self _stringFromStartMarker:markers.firstObject toEndMarker:markers.lastObject attributed:YES];
2522 }
2523
2524 - (NSRange)_accessibilitySelectedTextRange
2525 {
2526     if (![self _prepareAccessibilityCall] || !m_object->isTextControl())
2527         return NSMakeRange(NSNotFound, 0);
2528     
2529     PlainTextRange textRange = m_object->selectedTextRange();
2530     if (textRange.isNull())
2531         return NSMakeRange(NSNotFound, 0);
2532     return NSMakeRange(textRange.start, textRange.length);    
2533 }
2534
2535 - (void)_accessibilitySetSelectedTextRange:(NSRange)range
2536 {
2537     if (![self _prepareAccessibilityCall] || !m_object->isTextControl())
2538         return;
2539     
2540     m_object->setSelectedTextRange(PlainTextRange(range.location, range.length));
2541 }
2542
2543 // A convenience method for getting the accessibility objects of a NSRange. Currently used only by DRT.
2544 - (NSArray *)elementsForRange:(NSRange)range
2545 {
2546     if (![self _prepareAccessibilityCall])
2547         return nil;
2548     
2549     WebAccessibilityTextMarker* startMarker = [self textMarkerForPosition:range.location];
2550     WebAccessibilityTextMarker* endMarker = [self textMarkerForPosition:NSMaxRange(range)];
2551     if (!startMarker || !endMarker)
2552         return nil;
2553     
2554     NSArray* array = [self arrayOfTextForTextMarkers:[NSArray arrayWithObjects:startMarker, endMarker, nil] attributed:NO];
2555     NSMutableArray* elements = [NSMutableArray array];
2556     for (id element in array) {
2557         if (![element isKindOfClass:[AccessibilityObjectWrapper class]])
2558             continue;
2559         [elements addObject:element];
2560     }
2561     return elements;
2562 }
2563
2564 - (NSString *)selectionRangeString
2565 {
2566     NSArray *markers = [self textMarkerRangeForSelection];
2567     return [self stringForTextMarkers:markers];
2568 }
2569
2570 - (WebAccessibilityTextMarker *)selectedTextMarker
2571 {
2572     if (![self _prepareAccessibilityCall])
2573         return nil;
2574     
2575     VisibleSelection selection = m_object->selection();
2576     VisiblePosition position = selection.visibleStart();
2577     
2578     // if there's no selection, start at the top of the document
2579     if (position.isNull())
2580         position = startOfDocument(m_object->document());
2581     
2582     return [WebAccessibilityTextMarker textMarkerWithVisiblePosition:position cache:m_object->axObjectCache()];
2583 }
2584
2585 // This method is intended to return the marker at the end of the line starting at
2586 // the marker that is passed into the method.
2587 - (WebAccessibilityTextMarker *)lineEndMarkerForMarker:(WebAccessibilityTextMarker *)marker
2588 {
2589     if (![self _prepareAccessibilityCall])
2590         return nil;
2591
2592     if (!marker)
2593         return nil;
2594     
2595     VisiblePosition start = [marker visiblePosition];
2596     VisiblePosition lineEnd = m_object->nextLineEndPosition(start);
2597     
2598     return [WebAccessibilityTextMarker textMarkerWithVisiblePosition:lineEnd cache:m_object->axObjectCache()];
2599 }
2600
2601 // This method is intended to return the marker at the start of the line starting at
2602 // the marker that is passed into the method.
2603 - (WebAccessibilityTextMarker *)lineStartMarkerForMarker:(WebAccessibilityTextMarker *)marker
2604 {
2605     if (![self _prepareAccessibilityCall])
2606         return nil;
2607
2608     if (!marker)
2609         return nil;
2610     
2611     VisiblePosition start = [marker visiblePosition];
2612     VisiblePosition lineStart = m_object->previousLineStartPosition(start);
2613     
2614     return [WebAccessibilityTextMarker textMarkerWithVisiblePosition:lineStart cache:m_object->axObjectCache()];
2615 }
2616
2617 - (WebAccessibilityTextMarker *)nextMarkerForMarker:(WebAccessibilityTextMarker *)marker
2618 {
2619     if (![self _prepareAccessibilityCall])
2620         return nil;
2621
2622     if (!marker)
2623         return nil;
2624     
2625     CharacterOffset start = [marker characterOffset];
2626     return [self nextMarkerForCharacterOffset:start];
2627 }
2628
2629 - (WebAccessibilityTextMarker *)previousMarkerForMarker:(WebAccessibilityTextMarker *)marker
2630 {
2631     if (![self _prepareAccessibilityCall])
2632         return nil;
2633
2634     if (!marker)
2635         return nil;
2636     
2637     CharacterOffset start = [marker characterOffset];
2638     return [self previousMarkerForCharacterOffset:start];
2639 }
2640
2641 // This method is intended to return the bounds of a text marker range in screen coordinates.
2642 - (CGRect)frameForTextMarkers:(NSArray *)array
2643 {
2644     if (![self _prepareAccessibilityCall])
2645         return CGRectZero;
2646
2647     AXObjectCache* cache = m_object->axObjectCache();
2648     if (!cache)
2649         return CGRectZero;
2650     RefPtr<Range> range = [self rangeForTextMarkers:array];
2651     if (!range)
2652         return CGRectZero;
2653     
2654     auto rect = FloatRect(m_object->boundsForRange(range));
2655     return [self convertRectToSpace:rect space:AccessibilityConversionSpace::Screen];
2656 }
2657
2658 - (RefPtr<Range>)rangeFromMarkers:(NSArray *)markers withText:(NSString *)text
2659 {
2660     RefPtr<Range> originalRange = [self rangeForTextMarkers:markers];
2661     if (!originalRange)
2662         return nil;
2663     
2664     AXObjectCache* cache = m_object->axObjectCache();
2665     if (!cache)
2666         return nil;
2667     
2668     return cache->rangeMatchesTextNearRange(originalRange, text);
2669 }
2670
2671 // This is only used in the layout test.
2672 - (NSArray *)textMarkerRangeFromMarkers:(NSArray *)markers withText:(NSString *)text
2673 {
2674     return [self textMarkersForRange:[self rangeFromMarkers:markers withText:text]];
2675 }
2676
2677 - (NSArray *)textRectsFromMarkers:(NSArray *)markers withText:(NSString *)text
2678 {
2679     if (![self _prepareAccessibilityCall])
2680         return nil;
2681     
2682     RefPtr<Range> range = [self rangeFromMarkers:markers withText:text];
2683     if (!range || range->collapsed())
2684         return nil;
2685     
2686     Vector<WebCore::SelectionRect> selectionRects;
2687     range->collectSelectionRectsWithoutUnionInteriorLines(selectionRects);
2688     return [self rectsForSelectionRects:selectionRects];
2689 }
2690
2691 - (NSArray *)rectsForSelectionRects:(const Vector<WebCore::SelectionRect>&)selectionRects
2692 {
2693     unsigned size = selectionRects.size();
2694     if (!size)
2695         return nil;
2696     
2697     NSMutableArray *rects = [NSMutableArray arrayWithCapacity:size];
2698     for (unsigned i = 0; i < size; i++) {
2699         const WebCore::SelectionRect& coreRect = selectionRects[i];
2700         auto selectionRect = FloatRect(coreRect.rect());
2701         CGRect rect = [self convertRectToSpace:selectionRect space:AccessibilityConversionSpace::Screen];
2702         [rects addObject:[NSValue valueWithRect:rect]];
2703     }
2704     
2705     return rects;
2706 }
2707
2708 - (WebAccessibilityTextMarker *)textMarkerForPoint:(CGPoint)point
2709 {
2710     if (![self _prepareAccessibilityCall])
2711         return nil;
2712     
2713     AXObjectCache* cache = m_object->axObjectCache();
2714     if (!cache)
2715         return nil;
2716     CharacterOffset characterOffset = cache->characterOffsetForPoint(IntPoint(point), m_object);
2717     return [WebAccessibilityTextMarker textMarkerWithCharacterOffset:characterOffset cache:cache];
2718 }
2719
2720 - (WebAccessibilityTextMarker *)nextMarkerForCharacterOffset:(CharacterOffset&)characterOffset
2721 {
2722     AXObjectCache* cache = m_object->axObjectCache();
2723     if (!cache)
2724         return nil;
2725     
2726     TextMarkerData textMarkerData;
2727     cache->textMarkerDataForNextCharacterOffset(textMarkerData, characterOffset);
2728     if (!textMarkerData.axID)
2729         return nil;
2730     return [[[WebAccessibilityTextMarker alloc] initWithTextMarker:&textMarkerData cache:cache] autorelease];
2731 }
2732
2733 - (WebAccessibilityTextMarker *)previousMarkerForCharacterOffset:(CharacterOffset&)characterOffset
2734 {
2735     AXObjectCache* cache = m_object->axObjectCache();
2736     if (!cache)
2737         return nil;
2738     
2739     TextMarkerData textMarkerData;
2740     cache->textMarkerDataForPreviousCharacterOffset(textMarkerData, characterOffset);
2741     if (!textMarkerData.axID)
2742         return nil;
2743     return [[[WebAccessibilityTextMarker alloc] initWithTextMarker:&textMarkerData cache:cache] autorelease];
2744 }
2745
2746 - (RefPtr<Range>)rangeForTextMarkers:(NSArray *)textMarkers
2747 {
2748     if ([textMarkers count] != 2)
2749         return nullptr;
2750     
2751     WebAccessibilityTextMarker *startMarker = [textMarkers objectAtIndex:0];
2752     WebAccessibilityTextMarker *endMarker = [textMarkers objectAtIndex:1];
2753     
2754     if (![startMarker isKindOfClass:[WebAccessibilityTextMarker class]] || ![endMarker isKindOfClass:[WebAccessibilityTextMarker class]])
2755         return nullptr;
2756     
2757     AXObjectCache* cache = m_object->axObjectCache();
2758     if (!cache)
2759         return nullptr;
2760     
2761     CharacterOffset startCharacterOffset = [startMarker characterOffset];
2762     CharacterOffset endCharacterOffset = [endMarker characterOffset];
2763     return cache->rangeForUnorderedCharacterOffsets(startCharacterOffset, endCharacterOffset);
2764 }
2765
2766 - (NSInteger)lengthForTextMarkers:(NSArray *)textMarkers
2767 {
2768     if (![self _prepareAccessibilityCall])
2769         return 0;
2770     
2771     RefPtr<Range> range = [self rangeForTextMarkers:textMarkers];
2772     int length = AXObjectCache::lengthForRange(range.get());
2773     return length < 0 ? 0 : length;
2774 }
2775
2776 - (WebAccessibilityTextMarker *)startOrEndTextMarkerForTextMarkers:(NSArray *)textMarkers isStart:(BOOL)isStart
2777 {
2778     if (![self _prepareAccessibilityCall])
2779         return nil;
2780     
2781     RefPtr<Range> range = [self rangeForTextMarkers:textMarkers];
2782     if (!range)
2783         return nil;
2784     
2785     return [WebAccessibilityTextMarker startOrEndTextMarkerForRange:range isStart:isStart cache:m_object->axObjectCache()];
2786 }
2787
2788 - (NSArray *)textMarkerRangeForMarkers:(NSArray *)textMarkers
2789 {
2790     if (![self _prepareAccessibilityCall])
2791         return nil;
2792     
2793     RefPtr<Range> range = [self rangeForTextMarkers:textMarkers];
2794     return [self textMarkersForRange:range];
2795 }
2796
2797 - (NSArray *)textMarkersForRange:(RefPtr<Range>)range
2798 {
2799     if (!range)
2800         return nil;
2801     
2802     WebAccessibilityTextMarker* start = [WebAccessibilityTextMarker startOrEndTextMarkerForRange:range isStart:YES cache:m_object->axObjectCache()];
2803     WebAccessibilityTextMarker* end = [WebAccessibilityTextMarker startOrEndTextMarkerForRange:range isStart:NO cache:m_object->axObjectCache()];
2804     if (!start || !end)
2805         return nil;
2806     return [NSArray arrayWithObjects:start, end, nil];
2807 }
2808
2809 - (NSString *)accessibilityExpandedTextValue
2810 {
2811     if (![self _prepareAccessibilityCall])
2812         return nil;
2813     return m_object->expandedTextValue();
2814 }
2815
2816 - (NSString *)accessibilityIdentifier
2817 {
2818     if (![self _prepareAccessibilityCall])
2819         return nil;
2820     
2821     return m_object->getAttribute(HTMLNames::idAttr);
2822 }
2823
2824 - (NSArray<NSString *> *)accessibilitySpeechHint
2825 {
2826     if (![self _prepareAccessibilityCall])
2827         return nil;
2828
2829     return [self baseAccessibilitySpeechHint];
2830 }
2831
2832 - (BOOL)accessibilityARIAIsBusy
2833 {
2834     if (![self _prepareAccessibilityCall])
2835         return NO;
2836
2837     return m_object->isBusy();
2838 }
2839
2840 - (NSString *)accessibilityARIALiveRegionStatus
2841 {
2842     if (![self _prepareAccessibilityCall])
2843         return nil;
2844
2845     return m_object->liveRegionStatus();
2846 }
2847
2848 - (NSString *)accessibilityARIARelevantStatus
2849 {
2850     if (![self _prepareAccessibilityCall])
2851         return nil;
2852     
2853     return m_object->liveRegionRelevant();
2854 }
2855
2856 - (BOOL)accessibilityARIALiveRegionIsAtomic
2857 {
2858     if (![self _prepareAccessibilityCall])
2859         return NO;
2860     
2861     return m_object->liveRegionAtomic();
2862 }
2863
2864 - (BOOL)accessibilitySupportsARIAPressed
2865 {
2866     if (![self _prepareAccessibilityCall])
2867         return NO;
2868     
2869     return m_object->supportsPressed();
2870 }
2871
2872 - (BOOL)accessibilityIsPressed
2873 {
2874     if (![self _prepareAccessibilityCall])
2875         return NO;
2876     
2877     return m_object->isPressed();
2878 }
2879
2880 - (BOOL)accessibilitySupportsARIAExpanded
2881 {
2882     if (![self _prepareAccessibilityCall])
2883         return NO;
2884     
2885     // Since details element is ignored on iOS, we should expose the expanded status on its
2886     // summary's accessible children.
2887     if (AccessibilityObject* detailParent = [self detailParentForSummaryObject:m_object])
2888         return detailParent->supportsExpanded();
2889     
2890     if (AccessibilityObject* treeItemParent = [self treeItemParentForObject:m_object])
2891         return treeItemParent->supportsExpanded();
2892     
2893     return m_object->supportsExpanded();
2894 }
2895
2896 - (BOOL)accessibilityIsExpanded
2897 {
2898     if (![self _prepareAccessibilityCall])
2899         return NO;
2900
2901     // Since details element is ignored on iOS, we should expose the expanded status on its
2902     // summary's accessible children.
2903     if (AccessibilityObject* detailParent = [self detailParentForSummaryObject:m_object])
2904         return detailParent->isExpanded();
2905     
2906     if (AccessibilityObject* treeItemParent = [self treeItemParentForObject:m_object])
2907         return treeItemParent->isExpanded();
2908     
2909     return m_object->isExpanded();
2910 }
2911
2912 - (BOOL)accessibilityIsShowingValidationMessage
2913 {
2914     if (![self _prepareAccessibilityCall])
2915         return NO;
2916     
2917     return m_object->isShowingValidationMessage();
2918 }
2919
2920 - (NSString *)accessibilityInvalidStatus
2921 {
2922     if (![self _prepareAccessibilityCall])
2923         return nil;
2924     
2925     return m_object->invalidStatus();
2926 }
2927
2928 - (NSString *)accessibilityARIACurrentStatus
2929 {
2930     if (![self _prepareAccessibilityCall])
2931         return nil;
2932     
2933     switch (m_object->currentState()) {
2934     case AccessibilityCurrentState::False:
2935         return @"false";
2936     case AccessibilityCurrentState::Page:
2937         return @"page";
2938     case AccessibilityCurrentState::Step:
2939         return @"step";
2940     case AccessibilityCurrentState::Location:
2941         return @"location";
2942     case AccessibilityCurrentState::Time:
2943         return @"time";
2944     case AccessibilityCurrentState::Date:
2945         return @"date";
2946     case AccessibilityCurrentState::True:
2947         return @"true";
2948     }
2949 }
2950
2951 - (NSString *)accessibilitySortDirection
2952 {
2953     if (![self _prepareAccessibilityCall])
2954         return nil;
2955     
2956     switch (m_object->sortDirection()) {
2957     case AccessibilitySortDirection::Ascending:
2958         return @"ascending";
2959     case AccessibilitySortDirection::Descending:
2960         return @"descending";
2961     case AccessibilitySortDirection::Other:
2962         return @"other";
2963     case AccessibilitySortDirection::Invalid:
2964     case AccessibilitySortDirection::None:
2965         return nil;
2966     }
2967 }
2968
2969 - (WebAccessibilityObjectWrapper *)accessibilityMathRootIndexObject
2970 {
2971     if (![self _prepareAccessibilityCall])
2972         return nil;
2973
2974     return m_object->mathRootIndexObject() ? m_object->mathRootIndexObject()->wrapper() : 0;
2975 }
2976
2977 - (WebAccessibilityObjectWrapper *)accessibilityMathRadicandObject
2978 {
2979     if (![self _prepareAccessibilityCall])
2980         return nil;
2981
2982     return m_object->mathRadicandObject() ? m_object->mathRadicandObject()->wrapper() : 0;
2983 }
2984
2985 - (WebAccessibilityObjectWrapper *)accessibilityMathNumeratorObject
2986 {
2987     if (![self _prepareAccessibilityCall])
2988         return nil;
2989
2990     return m_object->mathNumeratorObject() ? m_object->mathNumeratorObject()->wrapper() : 0;
2991 }
2992
2993 - (WebAccessibilityObjectWrapper *)accessibilityMathDenominatorObject
2994 {
2995     if (![self _prepareAccessibilityCall])
2996         return nil;
2997
2998     return m_object->mathDenominatorObject() ? m_object->mathDenominatorObject()->wrapper() : 0;
2999 }
3000
3001 - (WebAccessibilityObjectWrapper *)accessibilityMathBaseObject
3002 {
3003     if (![self _prepareAccessibilityCall])
3004         return nil;
3005
3006     return m_object->mathBaseObject() ? m_object->mathBaseObject()->wrapper() : 0;
3007 }
3008
3009 - (WebAccessibilityObjectWrapper *)accessibilityMathSubscriptObject
3010 {
3011     if (![self _prepareAccessibilityCall])
3012         return nil;
3013
3014     return m_object->mathSubscriptObject() ? m_object->mathSubscriptObject()->wrapper() : 0;
3015 }
3016
3017 - (WebAccessibilityObjectWrapper *)accessibilityMathSuperscriptObject
3018 {
3019     if (![self _prepareAccessibilityCall])
3020         return nil;
3021
3022     return m_object->mathSuperscriptObject() ? m_object->mathSuperscriptObject()->wrapper() : 0;
3023 }
3024
3025 - (WebAccessibilityObjectWrapper *)accessibilityMathUnderObject
3026 {
3027     if (![self _prepareAccessibilityCall])
3028         return nil;
3029
3030     return m_object->mathUnderObject() ? m_object->mathUnderObject()->wrapper() : 0;
3031 }
3032
3033 - (WebAccessibilityObjectWrapper *)accessibilityMathOverObject
3034 {
3035     if (![self _prepareAccessibilityCall])
3036         return nil;
3037
3038     return m_object->mathOverObject() ? m_object->mathOverObject()->wrapper() : 0;
3039 }
3040
3041 - (NSString *)accessibilityPlatformMathSubscriptKey
3042 {
3043     return @"AXMSubscriptObject";
3044 }
3045
3046 - (NSString *)accessibilityPlatformMathSuperscriptKey
3047 {
3048     return @"AXMSuperscriptObject";
3049 }
3050
3051 - (NSArray *)accessibilityMathPostscripts
3052 {
3053     if (![self _prepareAccessibilityCall])
3054         return nil;
3055     
3056     return [self accessibilityMathPostscriptPairs];
3057 }
3058
3059 - (NSArray *)accessibilityMathPrescripts
3060 {
3061     if (![self _prepareAccessibilityCall])
3062         return nil;
3063     
3064     return [self accessibilityMathPrescriptPairs];
3065 }
3066
3067 - (NSString *)accessibilityMathFencedOpenString
3068 {
3069     if (![self _prepareAccessibilityCall])
3070         return nil;
3071
3072     return m_object->mathFencedOpenString();
3073 }
3074
3075 - (NSString *)accessibilityMathFencedCloseString
3076 {
3077     if (![self _prepareAccessibilityCall])
3078         return nil;
3079
3080     return m_object->mathFencedCloseString();
3081 }
3082
3083 - (BOOL)accessibilityIsMathTopObject
3084 {
3085     if (![self _prepareAccessibilityCall])
3086         return NO;
3087
3088     return m_object->roleValue() == AccessibilityRole::DocumentMath;
3089 }
3090
3091 - (NSInteger)accessibilityMathLineThickness
3092 {
3093     if (![self _prepareAccessibilityCall])
3094         return 0;
3095
3096     return m_object->mathLineThickness();
3097 }
3098
3099 - (NSString *)accessibilityMathType
3100 {
3101     if (![self _prepareAccessibilityCall])
3102         return nil;
3103
3104     if (m_object->roleValue() == AccessibilityRole::MathElement) {
3105         if (m_object->isMathFraction())
3106             return @"AXMathFraction";
3107         if (m_object->isMathFenced())
3108             return @"AXMathFenced";
3109         if (m_object->isMathSubscriptSuperscript())
3110             return @"AXMathSubscriptSuperscript";
3111         if (m_object->isMathRow())
3112             return @"AXMathRow";
3113         if (m_object->isMathUnderOver())
3114             return @"AXMathUnderOver";
3115         if (m_object->isMathSquareRoot())
3116             return @"AXMathSquareRoot";
3117         if (m_object->isMathRoot())
3118             return @"AXMathRoot";
3119         if (m_object->isMathText())
3120             return @"AXMathText";
3121         if (m_object->isMathNumber())
3122             return @"AXMathNumber";
3123         if (m_object->isMathIdentifier())
3124             return @"AXMathIdentifier";
3125         if (m_object->isMathTable())
3126             return @"AXMathTable";
3127         if (m_object->isMathTableRow())
3128             return @"AXMathTableRow";
3129         if (m_object->isMathTableCell())
3130             return @"AXMathTableCell";
3131         if (m_object->isMathFenceOperator())
3132             return @"AXMathFenceOperator";
3133         if (m_object->isMathSeparatorOperator())
3134             return @"AXMathSeparatorOperator";
3135         if (m_object->isMathOperator())
3136             return @"AXMathOperator";
3137         if (m_object->isMathMultiscript())
3138             return @"AXMathMultiscript";
3139     }
3140     
3141     return nil;
3142 }
3143
3144 - (CGPoint)accessibilityClickPoint
3145 {
3146     return m_object->clickPoint();
3147 }
3148
3149 - (NSString *)description
3150 {
3151     return [NSString stringWithFormat:@"%@: %@", [self class], [self accessibilityLabel]];
3152 }
3153
3154 @end
3155
3156 #endif // HAVE(ACCESSIBILITY) && PLATFORM(IOS_FAMILY)