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