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