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