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