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