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