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