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