1/*
2 * Copyright (C) 2008, 2009, 2010, 2011 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 *
8 * 1.  Redistributions of source code must retain the above copyright
9 *     notice, this list of conditions and the following disclaimer.
10 * 2.  Redistributions in binary form must reproduce the above copyright
11 *     notice, this list of conditions and the following disclaimer in the
12 *     documentation and/or other materials provided with the distribution.
13 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 *     its contributors may be used to endorse or promote products derived
15 *     from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#import "config.h"
30#import "WebAccessibilityObjectWrapperMac.h"
31
32#if HAVE(ACCESSIBILITY)
33
34#import "AXObjectCache.h"
35#import "AccessibilityARIAGridRow.h"
36#import "AccessibilityList.h"
37#import "AccessibilityListBox.h"
38#import "AccessibilityRenderObject.h"
39#import "AccessibilityScrollView.h"
40#import "AccessibilitySpinButton.h"
41#import "AccessibilityTable.h"
42#import "AccessibilityTableCell.h"
43#import "AccessibilityTableColumn.h"
44#import "AccessibilityTableRow.h"
45#import "Chrome.h"
46#import "ChromeClient.h"
47#import "ColorMac.h"
48#import "ContextMenuController.h"
49#import "Editor.h"
50#import "Font.h"
51#import "Frame.h"
52#import "FrameLoaderClient.h"
53#import "FrameSelection.h"
54#import "HTMLAnchorElement.h"
55#import "HTMLAreaElement.h"
56#import "HTMLFrameOwnerElement.h"
57#import "HTMLImageElement.h"
58#import "HTMLInputElement.h"
59#import "HTMLNames.h"
60#import "HTMLTextAreaElement.h"
61#import "LocalizedStrings.h"
62#import "Page.h"
63#import "RenderTextControl.h"
64#import "RenderView.h"
65#import "RenderWidget.h"
66#import "ScrollView.h"
67#import "SimpleFontData.h"
68#import "TextCheckerClient.h"
69#import "TextCheckingHelper.h"
70#import "TextIterator.h"
71#import "VisibleUnits.h"
72#import "WebCoreFrameView.h"
73#import "WebCoreObjCExtras.h"
74#import "WebCoreSystemInterface.h"
75#import "htmlediting.h"
76#import <wtf/ObjcRuntimeExtras.h>
77
78using namespace WebCore;
79using namespace HTMLNames;
80using namespace std;
81
82// Cell Tables
83#ifndef NSAccessibilitySelectedCellsAttribute
84#define NSAccessibilitySelectedCellsAttribute @"AXSelectedCells"
85#endif
86
87#ifndef NSAccessibilityVisibleCellsAttribute
88#define NSAccessibilityVisibleCellsAttribute @"AXVisibleCells"
89#endif
90
91#ifndef NSAccessibilityRowHeaderUIElementsAttribute
92#define NSAccessibilityRowHeaderUIElementsAttribute @"AXRowHeaderUIElements"
93#endif
94
95#ifndef NSAccessibilityRowIndexRangeAttribute
96#define NSAccessibilityRowIndexRangeAttribute @"AXRowIndexRange"
97#endif
98
99#ifndef NSAccessibilityColumnIndexRangeAttribute
100#define NSAccessibilityColumnIndexRangeAttribute @"AXColumnIndexRange"
101#endif
102
103#ifndef NSAccessibilityCellForColumnAndRowParameterizedAttribute
104#define NSAccessibilityCellForColumnAndRowParameterizedAttribute @"AXCellForColumnAndRow"
105#endif
106
107#ifndef NSAccessibilityCellRole
108#define NSAccessibilityCellRole @"AXCell"
109#endif
110
111// Lists
112#ifndef NSAccessibilityContentListSubrole
113#define NSAccessibilityContentListSubrole @"AXContentList"
114#endif
115
116#ifndef NSAccessibilityDefinitionListSubrole
117#define NSAccessibilityDefinitionListSubrole @"AXDefinitionList"
118#endif
119
120#ifndef NSAccessibilityDescriptionListSubrole
121#define NSAccessibilityDescriptionListSubrole @"AXDescriptionList"
122#endif
123
124// Miscellaneous
125#ifndef NSAccessibilityBlockQuoteLevelAttribute
126#define NSAccessibilityBlockQuoteLevelAttribute @"AXBlockQuoteLevel"
127#endif
128
129#ifndef NSAccessibilityAccessKeyAttribute
130#define NSAccessibilityAccessKeyAttribute @"AXAccessKey"
131#endif
132
133#ifndef NSAccessibilityLanguageAttribute
134#define NSAccessibilityLanguageAttribute @"AXLanguage"
135#endif
136
137#ifndef NSAccessibilityRequiredAttribute
138#define NSAccessibilityRequiredAttribute @"AXRequired"
139#endif
140
141#ifndef NSAccessibilityInvalidAttribute
142#define NSAccessibilityInvalidAttribute @"AXInvalid"
143#endif
144
145#ifndef NSAccessibilityOwnsAttribute
146#define NSAccessibilityOwnsAttribute @"AXOwns"
147#endif
148
149#ifndef NSAccessibilityGrabbedAttribute
150#define NSAccessibilityGrabbedAttribute @"AXGrabbed"
151#endif
152
153#ifndef NSAccessibilityDropEffectsAttribute
154#define NSAccessibilityDropEffectsAttribute @"AXDropEffects"
155#endif
156
157#ifndef NSAccessibilityARIALiveAttribute
158#define NSAccessibilityARIALiveAttribute @"AXARIALive"
159#endif
160
161#ifndef NSAccessibilityARIAAtomicAttribute
162#define NSAccessibilityARIAAtomicAttribute @"AXARIAAtomic"
163#endif
164
165#ifndef NSAccessibilityARIARelevantAttribute
166#define NSAccessibilityARIARelevantAttribute @"AXARIARelevant"
167#endif
168
169#ifndef NSAccessibilityARIABusyAttribute
170#define NSAccessibilityARIABusyAttribute @"AXARIABusy"
171#endif
172
173#ifndef NSAccessibilityARIAPosInSetAttribute
174#define NSAccessibilityARIAPosInSetAttribute @"AXARIAPosInSet"
175#endif
176
177#ifndef NSAccessibilityARIASetSizeAttribute
178#define NSAccessibilityARIASetSizeAttribute @"AXARIASetSize"
179#endif
180
181#ifndef NSAccessibilityLoadingProgressAttribute
182#define NSAccessibilityLoadingProgressAttribute @"AXLoadingProgress"
183#endif
184
185#ifndef NSAccessibilityHasPopupAttribute
186#define NSAccessibilityHasPopupAttribute @"AXHasPopup"
187#endif
188
189#ifndef NSAccessibilityPlaceholderValueAttribute
190#define NSAccessibilityPlaceholderValueAttribute @"AXPlaceholderValue"
191#endif
192
193// Search
194#ifndef NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute
195#define NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute @"AXUIElementsForSearchPredicate"
196#endif
197
198// Text
199#ifndef NSAccessibilityEndTextMarkerForBoundsParameterizedAttribute
200#define NSAccessibilityEndTextMarkerForBoundsParameterizedAttribute @"AXEndTextMarkerForBounds"
201#endif
202
203#ifndef NSAccessibilityStartTextMarkerForBoundsParameterizedAttribute
204#define NSAccessibilityStartTextMarkerForBoundsParameterizedAttribute @"AXStartTextMarkerForBounds"
205#endif
206
207// Search Keys
208#ifndef NSAccessibilityAnyTypeSearchKey
209#define NSAccessibilityAnyTypeSearchKey @"AXAnyTypeSearchKey"
210#endif
211
212#ifndef NSAccessibilityBlockquoteSameLevelSearchKey
213#define NSAccessibilityBlockquoteSameLevelSearchKey @"AXBlockquoteSameLevelSearchKey"
214#endif
215
216#ifndef NSAccessibilityBlockquoteSearchKey
217#define NSAccessibilityBlockquoteSearchKey @"AXBlockquoteSearchKey"
218#endif
219
220#ifndef NSAccessibilityBoldFontSearchKey
221#define NSAccessibilityBoldFontSearchKey @"AXBoldFontSearchKey"
222#endif
223
224#ifndef NSAccessibilityButtonSearchKey
225#define NSAccessibilityButtonSearchKey @"AXButtonSearchKey"
226#endif
227
228#ifndef NSAccessibilityCheckBoxSearchKey
229#define NSAccessibilityCheckBoxSearchKey @"AXCheckBoxSearchKey"
230#endif
231
232#ifndef NSAccessibilityControlSearchKey
233#define NSAccessibilityControlSearchKey @"AXControlSearchKey"
234#endif
235
236#ifndef NSAccessibilityDifferentTypeSearchKey
237#define NSAccessibilityDifferentTypeSearchKey @"AXDifferentTypeSearchKey"
238#endif
239
240#ifndef NSAccessibilityFontChangeSearchKey
241#define NSAccessibilityFontChangeSearchKey @"AXFontChangeSearchKey"
242#endif
243
244#ifndef NSAccessibilityFontColorChangeSearchKey
245#define NSAccessibilityFontColorChangeSearchKey @"AXFontColorChangeSearchKey"
246#endif
247
248#ifndef NSAccessibilityFrameSearchKey
249#define NSAccessibilityFrameSearchKey @"AXFrameSearchKey"
250#endif
251
252#ifndef NSAccessibilityGraphicSearchKey
253#define NSAccessibilityGraphicSearchKey @"AXGraphicSearchKey"
254#endif
255
256#ifndef NSAccessibilityHeadingLevel1SearchKey
257#define NSAccessibilityHeadingLevel1SearchKey @"AXHeadingLevel1SearchKey"
258#endif
259
260#ifndef NSAccessibilityHeadingLevel2SearchKey
261#define NSAccessibilityHeadingLevel2SearchKey @"AXHeadingLevel2SearchKey"
262#endif
263
264#ifndef NSAccessibilityHeadingLevel3SearchKey
265#define NSAccessibilityHeadingLevel3SearchKey @"AXHeadingLevel3SearchKey"
266#endif
267
268#ifndef NSAccessibilityHeadingLevel4SearchKey
269#define NSAccessibilityHeadingLevel4SearchKey @"AXHeadingLevel4SearchKey"
270#endif
271
272#ifndef NSAccessibilityHeadingLevel5SearchKey
273#define NSAccessibilityHeadingLevel5SearchKey @"AXHeadingLevel5SearchKey"
274#endif
275
276#ifndef NSAccessibilityHeadingLevel6SearchKey
277#define NSAccessibilityHeadingLevel6SearchKey @"AXHeadingLevel6SearchKey"
278#endif
279
280#ifndef NSAccessibilityHeadingSameLevelSearchKey
281#define NSAccessibilityHeadingSameLevelSearchKey @"AXHeadingSameLevelSearchKey"
282#endif
283
284#ifndef NSAccessibilityHeadingSearchKey
285#define NSAccessibilityHeadingSearchKey @"AXHeadingSearchKey"
286#endif
287
288#ifndef NSAccessibilityHighlightedSearchKey
289#define NSAccessibilityHighlightedSearchKey @"AXHighlightedSearchKey"
290#endif
291
292#ifndef NSAccessibilityItalicFontSearchKey
293#define NSAccessibilityItalicFontSearchKey @"AXItalicFontSearchKey"
294#endif
295
296#ifndef NSAccessibilityLandmarkSearchKey
297#define NSAccessibilityLandmarkSearchKey @"AXLandmarkSearchKey"
298#endif
299
300#ifndef NSAccessibilityLinkSearchKey
301#define NSAccessibilityLinkSearchKey @"AXLinkSearchKey"
302#endif
303
304#ifndef NSAccessibilityListSearchKey
305#define NSAccessibilityListSearchKey @"AXListSearchKey"
306#endif
307
308#ifndef NSAccessibilityLiveRegionSearchKey
309#define NSAccessibilityLiveRegionSearchKey @"AXLiveRegionSearchKey"
310#endif
311
312#ifndef NSAccessibilityMisspelledWordSearchKey
313#define NSAccessibilityMisspelledWordSearchKey @"AXMisspelledWordSearchKey"
314#endif
315
316#ifndef NSAccessibilityPlainTextSearchKey
317#define NSAccessibilityPlainTextSearchKey @"AXPlainTextSearchKey"
318#endif
319
320#ifndef NSAccessibilityRadioGroupSearchKey
321#define NSAccessibilityRadioGroupSearchKey @"AXRadioGroupSearchKey"
322#endif
323
324#ifndef NSAccessibilitySameTypeSearchKey
325#define NSAccessibilitySameTypeSearchKey @"AXSameTypeSearchKey"
326#endif
327
328#ifndef NSAccessibilityStaticTextSearchKey
329#define NSAccessibilityStaticTextSearchKey @"AXStaticTextSearchKey"
330#endif
331
332#ifndef NSAccessibilityStyleChangeSearchKey
333#define NSAccessibilityStyleChangeSearchKey @"AXStyleChangeSearchKey"
334#endif
335
336#ifndef NSAccessibilityTableSameLevelSearchKey
337#define NSAccessibilityTableSameLevelSearchKey @"AXTableSameLevelSearchKey"
338#endif
339
340#ifndef NSAccessibilityTableSearchKey
341#define NSAccessibilityTableSearchKey @"AXTableSearchKey"
342#endif
343
344#ifndef NSAccessibilityTextFieldSearchKey
345#define NSAccessibilityTextFieldSearchKey @"AXTextFieldSearchKey"
346#endif
347
348#ifndef NSAccessibilityUnderlineSearchKey
349#define NSAccessibilityUnderlineSearchKey @"AXUnderlineSearchKey"
350#endif
351
352#ifndef NSAccessibilityUnvisitedLinkSearchKey
353#define NSAccessibilityUnvisitedLinkSearchKey @"AXUnvisitedLinkSearchKey"
354#endif
355
356#ifndef NSAccessibilityVisitedLinkSearchKey
357#define NSAccessibilityVisitedLinkSearchKey @"AXVisitedLinkSearchKey"
358#endif
359
360#define NSAccessibilityTextMarkerIsValidParameterizedAttribute @"AXTextMarkerIsValid"
361#define NSAccessibilityIndexForTextMarkerParameterizedAttribute @"AXIndexForTextMarker"
362#define NSAccessibilityTextMarkerForIndexParameterizedAttribute @"AXTextMarkerForIndex"
363
364#ifndef NSAccessibilityScrollToVisibleAction
365#define NSAccessibilityScrollToVisibleAction @"AXScrollToVisible"
366#endif
367
368#ifndef NSAccessibilityPathAttribute
369#define NSAccessibilityPathAttribute @"AXPath"
370#endif
371
372// Math attributes
373#define NSAccessibilityMathRootRadicandAttribute @"AXMathRootRadicand"
374#define NSAccessibilityMathRootIndexAttribute @"AXMathRootIndex"
375#define NSAccessibilityMathFractionDenominatorAttribute @"AXMathFractionDenominator"
376#define NSAccessibilityMathFractionNumeratorAttribute @"AXMathFractionNumerator"
377#define NSAccessibilityMathBaseAttribute @"AXMathBase"
378#define NSAccessibilityMathSubscriptAttribute @"AXMathSubscript"
379#define NSAccessibilityMathSuperscriptAttribute @"AXMathSuperscript"
380#define NSAccessibilityMathUnderAttribute @"AXMathUnder"
381#define NSAccessibilityMathOverAttribute @"AXMathOver"
382#define NSAccessibilityMathFencedOpenAttribute @"AXMathFencedOpen"
383#define NSAccessibilityMathFencedCloseAttribute @"AXMathFencedClose"
384#define NSAccessibilityMathLineThicknessAttribute @"AXMathLineThickness"
385#define NSAccessibilityMathPrescriptsAttribute @"AXMathPrescripts"
386#define NSAccessibilityMathPostscriptsAttribute @"AXMathPostscripts"
387
388@implementation WebAccessibilityObjectWrapper
389
390- (void)unregisterUniqueIdForUIElement
391{
392    wkUnregisterUniqueIdForElement(self);
393}
394
395- (void)detach
396{
397    // Send unregisterUniqueIdForUIElement unconditionally because if it is
398    // ever accidentally not done (via other bugs in our AX implementation) you
399    // end up with a crash like <rdar://problem/4273149>.  It is safe and not
400    // expensive to send even if the object is not registered.
401    [self unregisterUniqueIdForUIElement];
402    [super detach];
403}
404
405- (id)attachmentView
406{
407    ASSERT(m_object->isAttachment());
408    Widget* widget = m_object->widgetForAttachmentView();
409    if (!widget)
410        return nil;
411    return NSAccessibilityUnignoredDescendant(widget->platformWidget());
412}
413
414#pragma mark SystemInterface wrappers
415
416static inline BOOL AXObjectIsTextMarker(id obj)
417{
418    return obj != nil && CFGetTypeID(obj) == wkGetAXTextMarkerTypeID();
419}
420
421static inline BOOL AXObjectIsTextMarkerRange(id obj)
422{
423    return obj != nil && CFGetTypeID(obj) == wkGetAXTextMarkerRangeTypeID();
424}
425
426static id AXTextMarkerRange(id startMarker, id endMarker)
427{
428    ASSERT(startMarker != nil);
429    ASSERT(endMarker != nil);
430    ASSERT(CFGetTypeID(startMarker) == wkGetAXTextMarkerTypeID());
431    ASSERT(CFGetTypeID(endMarker) == wkGetAXTextMarkerTypeID());
432    return HardAutorelease(wkCreateAXTextMarkerRange((CFTypeRef)startMarker, (CFTypeRef)endMarker));
433}
434
435static id AXTextMarkerRangeStart(id range)
436{
437    ASSERT(range != nil);
438    ASSERT(CFGetTypeID(range) == wkGetAXTextMarkerRangeTypeID());
439    return HardAutorelease(wkCopyAXTextMarkerRangeStart(range));
440}
441
442static id AXTextMarkerRangeEnd(id range)
443{
444    ASSERT(range != nil);
445    ASSERT(CFGetTypeID(range) == wkGetAXTextMarkerRangeTypeID());
446    return HardAutorelease(wkCopyAXTextMarkerRangeEnd(range));
447}
448
449#pragma mark Other helpers
450
451- (IntRect)screenToContents:(const IntRect&)rect
452{
453    Document* document = m_object->document();
454    if (!document)
455        return IntRect();
456
457    FrameView* frameView = document->view();
458    if (!frameView)
459        return IntRect();
460
461    IntPoint startPoint = frameView->screenToContents(rect.minXMaxYCorner());
462    IntPoint endPoint = frameView->screenToContents(rect.maxXMinYCorner());
463    return IntRect(startPoint.x(), startPoint.y(), endPoint.x() - startPoint.x(), endPoint.y() - startPoint.y());
464}
465
466#pragma mark Search helpers
467
468typedef HashMap<String, AccessibilitySearchKey> AccessibilitySearchKeyMap;
469
470struct SearchKeyEntry {
471    String key;
472    AccessibilitySearchKey value;
473};
474
475static AccessibilitySearchKeyMap* createAccessibilitySearchKeyMap()
476{
477    const SearchKeyEntry searchKeys[] = {
478        { NSAccessibilityAnyTypeSearchKey, AnyTypeSearchKey },
479        { NSAccessibilityBlockquoteSameLevelSearchKey, BlockquoteSameLevelSearchKey },
480        { NSAccessibilityBlockquoteSearchKey, BlockquoteSearchKey },
481        { NSAccessibilityBoldFontSearchKey, BoldFontSearchKey },
482        { NSAccessibilityButtonSearchKey, ButtonSearchKey },
483        { NSAccessibilityCheckBoxSearchKey, CheckBoxSearchKey },
484        { NSAccessibilityControlSearchKey, ControlSearchKey },
485        { NSAccessibilityDifferentTypeSearchKey, DifferentTypeSearchKey },
486        { NSAccessibilityFontChangeSearchKey, FontChangeSearchKey },
487        { NSAccessibilityFontColorChangeSearchKey, FontColorChangeSearchKey },
488        { NSAccessibilityFrameSearchKey, FrameSearchKey },
489        { NSAccessibilityGraphicSearchKey, GraphicSearchKey },
490        { NSAccessibilityHeadingLevel1SearchKey, HeadingLevel1SearchKey },
491        { NSAccessibilityHeadingLevel2SearchKey, HeadingLevel2SearchKey },
492        { NSAccessibilityHeadingLevel3SearchKey, HeadingLevel3SearchKey },
493        { NSAccessibilityHeadingLevel4SearchKey, HeadingLevel4SearchKey },
494        { NSAccessibilityHeadingLevel5SearchKey, HeadingLevel5SearchKey },
495        { NSAccessibilityHeadingLevel6SearchKey, HeadingLevel6SearchKey },
496        { NSAccessibilityHeadingSameLevelSearchKey, HeadingSameLevelSearchKey },
497        { NSAccessibilityHeadingSearchKey, HeadingSearchKey },
498        { NSAccessibilityHighlightedSearchKey, HighlightedSearchKey },
499        { NSAccessibilityItalicFontSearchKey, ItalicFontSearchKey },
500        { NSAccessibilityLandmarkSearchKey, LandmarkSearchKey },
501        { NSAccessibilityLinkSearchKey, LinkSearchKey },
502        { NSAccessibilityListSearchKey, ListSearchKey },
503        { NSAccessibilityLiveRegionSearchKey, LiveRegionSearchKey },
504        { NSAccessibilityMisspelledWordSearchKey, MisspelledWordSearchKey },
505        { NSAccessibilityPlainTextSearchKey, PlainTextSearchKey },
506        { NSAccessibilityRadioGroupSearchKey, RadioGroupSearchKey },
507        { NSAccessibilitySameTypeSearchKey, SameTypeSearchKey },
508        { NSAccessibilityStaticTextSearchKey, StaticTextSearchKey },
509        { NSAccessibilityStyleChangeSearchKey, StyleChangeSearchKey },
510        { NSAccessibilityTableSameLevelSearchKey, TableSameLevelSearchKey },
511        { NSAccessibilityTableSearchKey, TableSearchKey },
512        { NSAccessibilityTextFieldSearchKey, TextFieldSearchKey },
513        { NSAccessibilityUnderlineSearchKey, UnderlineSearchKey },
514        { NSAccessibilityUnvisitedLinkSearchKey, UnvisitedLinkSearchKey },
515        { NSAccessibilityVisitedLinkSearchKey, VisitedLinkSearchKey }
516    };
517
518    AccessibilitySearchKeyMap* searchKeyMap = new AccessibilitySearchKeyMap;
519    for (size_t i = 0; i < WTF_ARRAY_LENGTH(searchKeys); i++)
520        searchKeyMap->set(searchKeys[i].key, searchKeys[i].value);
521
522    return searchKeyMap;
523}
524
525static AccessibilitySearchKey accessibilitySearchKeyForString(const String& value)
526{
527    if (value.isEmpty())
528        return AnyTypeSearchKey;
529
530    static const AccessibilitySearchKeyMap* searchKeyMap = createAccessibilitySearchKeyMap();
531
532    AccessibilitySearchKey searchKey = searchKeyMap->get(value);
533
534    return searchKey ? searchKey : AnyTypeSearchKey;
535}
536
537#pragma mark Text Marker helpers
538
539static id textMarkerForVisiblePosition(AXObjectCache* cache, const VisiblePosition& visiblePos)
540{
541    ASSERT(cache);
542
543    TextMarkerData textMarkerData;
544    cache->textMarkerDataForVisiblePosition(textMarkerData, visiblePos);
545    if (!textMarkerData.axID)
546        return nil;
547
548    return HardAutorelease(wkCreateAXTextMarker(&textMarkerData, sizeof(textMarkerData)));
549}
550
551- (id)textMarkerForVisiblePosition:(const VisiblePosition &)visiblePos
552{
553    return textMarkerForVisiblePosition(m_object->axObjectCache(), visiblePos);
554}
555
556static VisiblePosition visiblePositionForTextMarker(AXObjectCache* cache, CFTypeRef textMarker)
557{
558    ASSERT(cache);
559
560    if (!textMarker)
561        return VisiblePosition();
562    TextMarkerData textMarkerData;
563    if (!wkGetBytesFromAXTextMarker(textMarker, &textMarkerData, sizeof(textMarkerData)))
564        return VisiblePosition();
565
566    return cache->visiblePositionForTextMarkerData(textMarkerData);
567}
568
569- (VisiblePosition)visiblePositionForTextMarker:(id)textMarker
570{
571    return visiblePositionForTextMarker(m_object->axObjectCache(), textMarker);
572}
573
574static VisiblePosition visiblePositionForStartOfTextMarkerRange(AXObjectCache *cache, id textMarkerRange)
575{
576    return visiblePositionForTextMarker(cache, AXTextMarkerRangeStart(textMarkerRange));
577}
578
579static VisiblePosition visiblePositionForEndOfTextMarkerRange(AXObjectCache *cache, id textMarkerRange)
580{
581    return visiblePositionForTextMarker(cache, AXTextMarkerRangeEnd(textMarkerRange));
582}
583
584static id textMarkerRangeFromMarkers(id textMarker1, id textMarker2)
585{
586    if (!textMarker1 || !textMarker2)
587        return nil;
588
589    return AXTextMarkerRange(textMarker1, textMarker2);
590}
591
592// When modifying attributed strings, the range can come from a source which may provide faulty information (e.g. the spell checker).
593// To protect against such cases the range should be validated before adding or removing attributes.
594static BOOL AXAttributedStringRangeIsValid(NSAttributedString* attrString, NSRange range)
595{
596    return (range.location < [attrString length] && NSMaxRange(range) <= [attrString length]);
597}
598
599static void AXAttributeStringSetFont(NSMutableAttributedString* attrString, NSString* attribute, NSFont* font, NSRange range)
600{
601    if (!AXAttributedStringRangeIsValid(attrString, range))
602        return;
603
604    if (font) {
605        NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
606                              [font fontName]                             , NSAccessibilityFontNameKey,
607                              [font familyName]                           , NSAccessibilityFontFamilyKey,
608                              [font displayName]                          , NSAccessibilityVisibleNameKey,
609                              [NSNumber numberWithFloat:[font pointSize]] , NSAccessibilityFontSizeKey,
610                              nil];
611
612        [attrString addAttribute:attribute value:dict range:range];
613    } else
614        [attrString removeAttribute:attribute range:range];
615
616}
617
618static CGColorRef CreateCGColorIfDifferent(NSColor* nsColor, CGColorRef existingColor)
619{
620    // get color information assuming NSDeviceRGBColorSpace
621    NSColor* rgbColor = [nsColor colorUsingColorSpaceName:NSDeviceRGBColorSpace];
622    if (rgbColor == nil)
623        rgbColor = [NSColor blackColor];
624    CGFloat components[4];
625    [rgbColor getRed:&components[0] green:&components[1] blue:&components[2] alpha:&components[3]];
626
627    // create a new CGColorRef to return
628    CGColorSpaceRef cgColorSpace = CGColorSpaceCreateDeviceRGB();
629    CGColorRef cgColor = CGColorCreate(cgColorSpace, components);
630    CGColorSpaceRelease(cgColorSpace);
631
632    // check for match with existing color
633    if (existingColor && CGColorEqualToColor(cgColor, existingColor)) {
634        CGColorRelease(cgColor);
635        cgColor = 0;
636    }
637
638    return cgColor;
639}
640
641static void AXAttributeStringSetColor(NSMutableAttributedString* attrString, NSString* attribute, NSColor* color, NSRange range)
642{
643    if (!AXAttributedStringRangeIsValid(attrString, range))
644        return;
645
646    if (color) {
647        CGColorRef existingColor = (CGColorRef) [attrString attribute:attribute atIndex:range.location effectiveRange:nil];
648        CGColorRef cgColor = CreateCGColorIfDifferent(color, existingColor);
649        if (cgColor) {
650            [attrString addAttribute:attribute value:(id)cgColor range:range];
651            CGColorRelease(cgColor);
652        }
653    } else
654        [attrString removeAttribute:attribute range:range];
655}
656
657static void AXAttributeStringSetNumber(NSMutableAttributedString* attrString, NSString* attribute, NSNumber* number, NSRange range)
658{
659    if (!AXAttributedStringRangeIsValid(attrString, range))
660        return;
661
662    if (number)
663        [attrString addAttribute:attribute value:number range:range];
664    else
665        [attrString removeAttribute:attribute range:range];
666}
667
668static void AXAttributeStringSetStyle(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
669{
670    RenderStyle* style = renderer->style();
671
672    // set basic font info
673    AXAttributeStringSetFont(attrString, NSAccessibilityFontTextAttribute, style->font().primaryFont()->getNSFont(), range);
674
675    // set basic colors
676    AXAttributeStringSetColor(attrString, NSAccessibilityForegroundColorTextAttribute, nsColor(style->visitedDependentColor(CSSPropertyColor)), range);
677    AXAttributeStringSetColor(attrString, NSAccessibilityBackgroundColorTextAttribute, nsColor(style->visitedDependentColor(CSSPropertyBackgroundColor)), range);
678
679    // set super/sub scripting
680    EVerticalAlign alignment = style->verticalAlign();
681    if (alignment == SUB)
682        AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, [NSNumber numberWithInt:(-1)], range);
683    else if (alignment == SUPER)
684        AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, [NSNumber numberWithInt:1], range);
685    else
686        [attrString removeAttribute:NSAccessibilitySuperscriptTextAttribute range:range];
687
688    // set shadow
689    if (style->textShadow())
690        AXAttributeStringSetNumber(attrString, NSAccessibilityShadowTextAttribute, [NSNumber numberWithBool:YES], range);
691    else
692        [attrString removeAttribute:NSAccessibilityShadowTextAttribute range:range];
693
694    // set underline and strikethrough
695    int decor = style->textDecorationsInEffect();
696    if ((decor & TextDecorationUnderline) == 0) {
697        [attrString removeAttribute:NSAccessibilityUnderlineTextAttribute range:range];
698        [attrString removeAttribute:NSAccessibilityUnderlineColorTextAttribute range:range];
699    }
700
701    if ((decor & TextDecorationLineThrough) == 0) {
702        [attrString removeAttribute:NSAccessibilityStrikethroughTextAttribute range:range];
703        [attrString removeAttribute:NSAccessibilityStrikethroughColorTextAttribute range:range];
704    }
705
706    if ((decor & (TextDecorationUnderline | TextDecorationLineThrough)) != 0) {
707        // find colors using quirk mode approach (strict mode would use current
708        // color for all but the root line box, which would use getTextDecorationColors)
709        Color underline, overline, linethrough;
710        renderer->getTextDecorationColors(decor, underline, overline, linethrough);
711
712        if ((decor & TextDecorationUnderline) != 0) {
713            AXAttributeStringSetNumber(attrString, NSAccessibilityUnderlineTextAttribute, [NSNumber numberWithBool:YES], range);
714            AXAttributeStringSetColor(attrString, NSAccessibilityUnderlineColorTextAttribute, nsColor(underline), range);
715        }
716
717        if ((decor & TextDecorationLineThrough) != 0) {
718            AXAttributeStringSetNumber(attrString, NSAccessibilityStrikethroughTextAttribute, [NSNumber numberWithBool:YES], range);
719            AXAttributeStringSetColor(attrString, NSAccessibilityStrikethroughColorTextAttribute, nsColor(linethrough), range);
720        }
721    }
722
723    // Indicate background highlighting.
724    for (Node* node = renderer->node(); node; node = node->parentNode()) {
725        if (node->hasTagName(markTag))
726            AXAttributeStringSetNumber(attrString, @"AXHighlight", [NSNumber numberWithBool:YES], range);
727    }
728}
729
730static void AXAttributeStringSetBlockquoteLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
731{
732    if (!AXAttributedStringRangeIsValid(attrString, range))
733        return;
734
735    AccessibilityObject* obj = renderer->document()->axObjectCache()->getOrCreate(renderer);
736    int quoteLevel = obj->blockquoteLevel();
737
738    if (quoteLevel)
739        [attrString addAttribute:NSAccessibilityBlockQuoteLevelAttribute value:[NSNumber numberWithInt:quoteLevel] range:range];
740    else
741        [attrString removeAttribute:NSAccessibilityBlockQuoteLevelAttribute range:range];
742}
743
744static void AXAttributeStringSetSpelling(NSMutableAttributedString* attrString, Node* node, const UChar* chars, int charLength, NSRange range)
745{
746    if (unifiedTextCheckerEnabled(node->document()->frame())) {
747        // Check the spelling directly since document->markersForNode() does not store the misspelled marking when the cursor is in a word.
748        TextCheckerClient* checker = node->document()->frame()->editor().textChecker();
749
750        // checkTextOfParagraph is the only spelling/grammar checker implemented in WK1 and WK2
751        Vector<TextCheckingResult> results;
752        checkTextOfParagraph(checker, chars, charLength, TextCheckingTypeSpelling, results);
753
754        size_t size = results.size();
755        NSNumber* trueValue = [NSNumber numberWithBool:YES];
756        for (unsigned i = 0; i < size; i++) {
757            const TextCheckingResult& result = results[i];
758            AXAttributeStringSetNumber(attrString, NSAccessibilityMisspelledTextAttribute, trueValue, NSMakeRange(result.location + range.location, result.length));
759#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
760            AXAttributeStringSetNumber(attrString, NSAccessibilityMarkedMisspelledTextAttribute, trueValue, NSMakeRange(result.location + range.location, result.length));
761#endif
762        }
763        return;
764    }
765
766    int currentPosition = 0;
767    while (charLength > 0) {
768        const UChar* charData = chars + currentPosition;
769        TextCheckerClient* checker = node->document()->frame()->editor().textChecker();
770
771        int misspellingLocation = -1;
772        int misspellingLength = 0;
773        checker->checkSpellingOfString(charData, charLength, &misspellingLocation, &misspellingLength);
774        if (misspellingLocation == -1 || !misspellingLength)
775            break;
776
777        NSRange spellRange = NSMakeRange(range.location + currentPosition + misspellingLocation, misspellingLength);
778        AXAttributeStringSetNumber(attrString, NSAccessibilityMisspelledTextAttribute, [NSNumber numberWithBool:YES], spellRange);
779#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
780        AXAttributeStringSetNumber(attrString, NSAccessibilityMarkedMisspelledTextAttribute, [NSNumber numberWithBool:YES], spellRange);
781#endif
782        charLength -= (misspellingLocation + misspellingLength);
783        currentPosition += (misspellingLocation + misspellingLength);
784    }
785}
786
787static void AXAttributeStringSetHeadingLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
788{
789    if (!renderer)
790        return;
791
792    if (!AXAttributedStringRangeIsValid(attrString, range))
793        return;
794
795    // Sometimes there are objects between the text and the heading.
796    // In those cases the parent hierarchy should be queried to see if there is a heading level.
797    int parentHeadingLevel = 0;
798    AccessibilityObject* parentObject = renderer->document()->axObjectCache()->getOrCreate(renderer->parent());
799    for (; parentObject; parentObject = parentObject->parentObject()) {
800        parentHeadingLevel = parentObject->headingLevel();
801        if (parentHeadingLevel)
802            break;
803    }
804
805    if (parentHeadingLevel)
806        [attrString addAttribute:@"AXHeadingLevel" value:[NSNumber numberWithInt:parentHeadingLevel] range:range];
807    else
808        [attrString removeAttribute:@"AXHeadingLevel" range:range];
809}
810
811static void AXAttributeStringSetElement(NSMutableAttributedString* attrString, NSString* attribute, AccessibilityObject* object, NSRange range)
812{
813    if (!AXAttributedStringRangeIsValid(attrString, range))
814        return;
815
816    if (object && object->isAccessibilityRenderObject()) {
817        // make a serializable AX object
818
819        RenderObject* renderer = static_cast<AccessibilityRenderObject*>(object)->renderer();
820        if (!renderer)
821            return;
822
823        Document* doc = renderer->document();
824        if (!doc)
825            return;
826
827        AXObjectCache* cache = doc->axObjectCache();
828        if (!cache)
829            return;
830
831        AXUIElementRef axElement = wkCreateAXUIElementRef(object->wrapper());
832        if (axElement) {
833            [attrString addAttribute:attribute value:(id)axElement range:range];
834            CFRelease(axElement);
835        }
836    } else
837        [attrString removeAttribute:attribute range:range];
838}
839
840static void AXAttributedStringAppendText(NSMutableAttributedString* attrString, Node* node, const UChar* chars, int length)
841{
842    // skip invisible text
843    if (!node->renderer())
844        return;
845
846    // easier to calculate the range before appending the string
847    NSRange attrStringRange = NSMakeRange([attrString length], length);
848
849    // append the string from this node
850    [[attrString mutableString] appendString:[NSString stringWithCharacters:chars length:length]];
851
852    // add new attributes and remove irrelevant inherited ones
853    // NOTE: color attributes are handled specially because -[NSMutableAttributedString addAttribute: value: range:] does not merge
854    // identical colors.  Workaround is to not replace an existing color attribute if it matches what we are adding.  This also means
855    // we cannot just pre-remove all inherited attributes on the appended string, so we have to remove the irrelevant ones individually.
856
857    // remove inherited attachment from prior AXAttributedStringAppendReplaced
858    [attrString removeAttribute:NSAccessibilityAttachmentTextAttribute range:attrStringRange];
859#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
860    [attrString removeAttribute:NSAccessibilityMarkedMisspelledTextAttribute range:attrStringRange];
861#endif
862    [attrString removeAttribute:NSAccessibilityMisspelledTextAttribute range:attrStringRange];
863
864    // set new attributes
865    AXAttributeStringSetStyle(attrString, node->renderer(), attrStringRange);
866    AXAttributeStringSetHeadingLevel(attrString, node->renderer(), attrStringRange);
867    AXAttributeStringSetBlockquoteLevel(attrString, node->renderer(), attrStringRange);
868    AXAttributeStringSetElement(attrString, NSAccessibilityLinkTextAttribute, AccessibilityObject::anchorElementForNode(node), attrStringRange);
869
870    // do spelling last because it tends to break up the range
871    AXAttributeStringSetSpelling(attrString, node, chars, length, attrStringRange);
872}
873
874static NSString* nsStringForReplacedNode(Node* replacedNode)
875{
876    // we should always be given a rendered node and a replaced node, but be safe
877    // replaced nodes are either attachments (widgets) or images
878    if (!replacedNode || !isRendererReplacedElement(replacedNode->renderer()) || replacedNode->isTextNode()) {
879        ASSERT_NOT_REACHED();
880        return nil;
881    }
882
883    // create an AX object, but skip it if it is not supposed to be seen
884    RefPtr<AccessibilityObject> obj = replacedNode->renderer()->document()->axObjectCache()->getOrCreate(replacedNode->renderer());
885    if (obj->accessibilityIsIgnored())
886        return nil;
887
888    // use the attachmentCharacter to represent the replaced node
889    const UniChar attachmentChar = NSAttachmentCharacter;
890    return [NSString stringWithCharacters:&attachmentChar length:1];
891}
892
893- (NSAttributedString*)doAXAttributedStringForTextMarkerRange:(id)textMarkerRange
894{
895    if (!m_object)
896        return nil;
897
898    // extract the start and end VisiblePosition
899    VisiblePosition startVisiblePosition = visiblePositionForStartOfTextMarkerRange(m_object->axObjectCache(), textMarkerRange);
900    if (startVisiblePosition.isNull())
901        return nil;
902
903    VisiblePosition endVisiblePosition = visiblePositionForEndOfTextMarkerRange(m_object->axObjectCache(), textMarkerRange);
904    if (endVisiblePosition.isNull())
905        return nil;
906
907    VisiblePositionRange visiblePositionRange(startVisiblePosition, endVisiblePosition);
908    // iterate over the range to build the AX attributed string
909    NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] init];
910    TextIterator it(makeRange(startVisiblePosition, endVisiblePosition).get());
911    while (!it.atEnd()) {
912        // locate the node and starting offset for this range
913        int exception = 0;
914        Node* node = it.range()->startContainer(exception);
915        ASSERT(node == it.range()->endContainer(exception));
916        int offset = it.range()->startOffset(exception);
917
918        // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
919        if (it.length() != 0) {
920            // Add the text of the list marker item if necessary.
921            String listMarkerText = m_object->listMarkerTextForNodeAndPosition(node, VisiblePosition(it.range()->startPosition()));
922            if (!listMarkerText.isEmpty())
923                AXAttributedStringAppendText(attrString, node, listMarkerText.characters(), listMarkerText.length());
924
925            AXAttributedStringAppendText(attrString, node, it.characters(), it.length());
926        } else {
927            Node* replacedNode = node->childNode(offset);
928            NSString *attachmentString = nsStringForReplacedNode(replacedNode);
929            if (attachmentString) {
930                NSRange attrStringRange = NSMakeRange([attrString length], [attachmentString length]);
931
932                // append the placeholder string
933                [[attrString mutableString] appendString:attachmentString];
934
935                // remove all inherited attributes
936                [attrString setAttributes:nil range:attrStringRange];
937
938                // add the attachment attribute
939                AccessibilityObject* obj = replacedNode->renderer()->document()->axObjectCache()->getOrCreate(replacedNode->renderer());
940                AXAttributeStringSetElement(attrString, NSAccessibilityAttachmentTextAttribute, obj, attrStringRange);
941            }
942        }
943        it.advance();
944    }
945
946    return [attrString autorelease];
947}
948
949static id textMarkerRangeFromVisiblePositions(AXObjectCache *cache, VisiblePosition startPosition, VisiblePosition endPosition)
950{
951    id startTextMarker = textMarkerForVisiblePosition(cache, startPosition);
952    id endTextMarker = textMarkerForVisiblePosition(cache, endPosition);
953    return textMarkerRangeFromMarkers(startTextMarker, endTextMarker);
954}
955
956- (id)textMarkerRangeFromVisiblePositions:(VisiblePosition)startPosition endPosition:(VisiblePosition)endPosition
957{
958    return textMarkerRangeFromVisiblePositions(m_object->axObjectCache(), startPosition, endPosition);
959}
960
961- (NSArray*)accessibilityActionNames
962{
963    if (![self updateObjectBackingStore])
964        return nil;
965
966    // All elements should get ShowMenu and ScrollToVisible.
967    // But certain earlier VoiceOver versions do not support scroll to visible, and it confuses them to see it in the list.
968#if __MAC_OS_X_VERSION_MIN_REQUIRED < 1090
969    static NSArray *defaultElementActions = [[NSArray alloc] initWithObjects:NSAccessibilityShowMenuAction, nil];
970#else
971    static NSArray *defaultElementActions = [[NSArray alloc] initWithObjects:NSAccessibilityShowMenuAction, NSAccessibilityScrollToVisibleAction, nil];
972#endif
973
974    // Action elements allow Press.
975    // The order is important to VoiceOver, which expects the 'default' action to be the first action. In this case the default action should be press.
976#if __MAC_OS_X_VERSION_MIN_REQUIRED < 1090
977    static NSArray *actionElementActions = [[NSArray alloc] initWithObjects:NSAccessibilityPressAction, NSAccessibilityShowMenuAction, nil];
978#else
979    static NSArray *actionElementActions = [[NSArray alloc] initWithObjects:NSAccessibilityPressAction, NSAccessibilityShowMenuAction, NSAccessibilityScrollToVisibleAction, nil];
980#endif
981
982    // Menu elements allow Press and Cancel.
983    static NSArray *menuElementActions = [[actionElementActions arrayByAddingObject:NSAccessibilityCancelAction] retain];
984
985    // Slider elements allow Increment/Decrement.
986    static NSArray *sliderActions = [[defaultElementActions arrayByAddingObjectsFromArray:[NSArray arrayWithObjects:NSAccessibilityIncrementAction, NSAccessibilityDecrementAction, nil]] retain];
987
988    NSArray *actions;
989    if (m_object->actionElement() || m_object->isButton())
990        actions = actionElementActions;
991    else if (m_object->isMenuRelated())
992        actions = menuElementActions;
993    else if (m_object->isSlider())
994        actions = sliderActions;
995    else if (m_object->isAttachment())
996        actions = [[self attachmentView] accessibilityActionNames];
997    else
998        actions = defaultElementActions;
999
1000    return actions;
1001}
1002
1003- (NSArray*)additionalAccessibilityAttributeNames
1004{
1005    if (!m_object)
1006        return nil;
1007
1008    NSMutableArray *additional = [NSMutableArray array];
1009    if (m_object->supportsARIAOwns())
1010        [additional addObject:NSAccessibilityOwnsAttribute];
1011
1012    if (m_object->supportsARIAExpanded())
1013        [additional addObject:NSAccessibilityExpandedAttribute];
1014
1015    if (m_object->isScrollbar())
1016        [additional addObject:NSAccessibilityOrientationAttribute];
1017
1018    if (m_object->supportsARIADragging())
1019        [additional addObject:NSAccessibilityGrabbedAttribute];
1020
1021    if (m_object->supportsARIADropping())
1022        [additional addObject:NSAccessibilityDropEffectsAttribute];
1023
1024    if (m_object->isAccessibilityTable() && static_cast<AccessibilityTable*>(m_object)->supportsSelectedRows())
1025        [additional addObject:NSAccessibilitySelectedRowsAttribute];
1026
1027    if (m_object->supportsARIALiveRegion()) {
1028        [additional addObject:NSAccessibilityARIALiveAttribute];
1029        [additional addObject:NSAccessibilityARIARelevantAttribute];
1030    }
1031
1032    if (m_object->supportsARIASetSize())
1033        [additional addObject:NSAccessibilityARIASetSizeAttribute];
1034    if (m_object->supportsARIAPosInSet())
1035        [additional addObject:NSAccessibilityARIAPosInSetAttribute];
1036
1037    if (m_object->sortDirection() != SortDirectionNone)
1038        [additional addObject:NSAccessibilitySortDirectionAttribute];
1039
1040    // If an object is a child of a live region, then add these
1041    if (m_object->isInsideARIALiveRegion())
1042        [additional addObject:NSAccessibilityARIAAtomicAttribute];
1043    // All objects should expose the ARIA busy attribute (ARIA 1.1 with ISSUE-538).
1044    [additional addObject:NSAccessibilityARIABusyAttribute];
1045
1046    // Popup buttons on the Mac expose the value attribute.
1047    if (m_object->isPopUpButton()) {
1048        [additional addObject:NSAccessibilityValueAttribute];
1049    }
1050
1051    if (m_object->supportsRequiredAttribute()) {
1052        [additional addObject:NSAccessibilityRequiredAttribute];
1053    }
1054
1055    if (m_object->ariaHasPopup())
1056        [additional addObject:NSAccessibilityHasPopupAttribute];
1057
1058    if (m_object->isMathRoot()) {
1059        // The index of a square root is always known, so there's no object associated with it.
1060        if (!m_object->isMathSquareRoot())
1061            [additional addObject:NSAccessibilityMathRootIndexAttribute];
1062        [additional addObject:NSAccessibilityMathRootRadicandAttribute];
1063    } else if (m_object->isMathFraction()) {
1064        [additional addObject:NSAccessibilityMathFractionNumeratorAttribute];
1065        [additional addObject:NSAccessibilityMathFractionDenominatorAttribute];
1066        [additional addObject:NSAccessibilityMathLineThicknessAttribute];
1067    } else if (m_object->isMathSubscriptSuperscript()) {
1068        [additional addObject:NSAccessibilityMathBaseAttribute];
1069        [additional addObject:NSAccessibilityMathSubscriptAttribute];
1070        [additional addObject:NSAccessibilityMathSuperscriptAttribute];
1071    } else if (m_object->isMathUnderOver()) {
1072        [additional addObject:NSAccessibilityMathBaseAttribute];
1073        [additional addObject:NSAccessibilityMathUnderAttribute];
1074        [additional addObject:NSAccessibilityMathOverAttribute];
1075    } else if (m_object->isMathFenced()) {
1076        [additional addObject:NSAccessibilityMathFencedOpenAttribute];
1077        [additional addObject:NSAccessibilityMathFencedCloseAttribute];
1078    } else if (m_object->isMathMultiscript()) {
1079        [additional addObject:NSAccessibilityMathBaseAttribute];
1080        [additional addObject:NSAccessibilityMathPrescriptsAttribute];
1081        [additional addObject:NSAccessibilityMathPostscriptsAttribute];
1082    }
1083
1084    if (m_object->supportsPath())
1085        [additional addObject:NSAccessibilityPathAttribute];
1086
1087    return additional;
1088}
1089
1090- (NSArray*)accessibilityAttributeNames
1091{
1092    if (![self updateObjectBackingStore])
1093        return nil;
1094
1095    if (m_object->isAttachment())
1096        return [[self attachmentView] accessibilityAttributeNames];
1097
1098    static NSArray* attributes = nil;
1099    static NSArray* anchorAttrs = nil;
1100    static NSArray* webAreaAttrs = nil;
1101    static NSArray* textAttrs = nil;
1102    static NSArray* listAttrs = nil;
1103    static NSArray* listBoxAttrs = nil;
1104    static NSArray* rangeAttrs = nil;
1105    static NSArray* commonMenuAttrs = nil;
1106    static NSArray* menuAttrs = nil;
1107    static NSArray* menuBarAttrs = nil;
1108    static NSArray* menuItemAttrs = nil;
1109    static NSArray* menuButtonAttrs = nil;
1110    static NSArray* controlAttrs = nil;
1111    static NSArray* tableAttrs = nil;
1112    static NSArray* tableRowAttrs = nil;
1113    static NSArray* tableColAttrs = nil;
1114    static NSArray* tableCellAttrs = nil;
1115    static NSArray* groupAttrs = nil;
1116    static NSArray* inputImageAttrs = nil;
1117    static NSArray* passwordFieldAttrs = nil;
1118    static NSArray* tabListAttrs = nil;
1119    static NSArray* comboBoxAttrs = nil;
1120    static NSArray* outlineAttrs = nil;
1121    static NSArray* outlineRowAttrs = nil;
1122    static NSArray* buttonAttrs = nil;
1123    static NSArray* scrollViewAttrs = nil;
1124    static NSArray* incrementorAttrs = nil;
1125    NSMutableArray* tempArray;
1126    if (attributes == nil) {
1127        attributes = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute,
1128                      NSAccessibilitySubroleAttribute,
1129                      NSAccessibilityRoleDescriptionAttribute,
1130                      NSAccessibilityChildrenAttribute,
1131                      NSAccessibilityHelpAttribute,
1132                      NSAccessibilityParentAttribute,
1133                      NSAccessibilityPositionAttribute,
1134                      NSAccessibilitySizeAttribute,
1135                      NSAccessibilityTitleAttribute,
1136                      NSAccessibilityDescriptionAttribute,
1137                      NSAccessibilityValueAttribute,
1138                      NSAccessibilityFocusedAttribute,
1139                      NSAccessibilityEnabledAttribute,
1140                      NSAccessibilityWindowAttribute,
1141                      @"AXSelectedTextMarkerRange",
1142                      @"AXStartTextMarker",
1143                      @"AXEndTextMarker",
1144                      @"AXVisited",
1145                      NSAccessibilityLinkedUIElementsAttribute,
1146                      NSAccessibilitySelectedAttribute,
1147                      NSAccessibilityBlockQuoteLevelAttribute,
1148                      NSAccessibilityTopLevelUIElementAttribute,
1149                      nil];
1150    }
1151    if (commonMenuAttrs == nil) {
1152        commonMenuAttrs = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute,
1153                           NSAccessibilityRoleDescriptionAttribute,
1154                           NSAccessibilityChildrenAttribute,
1155                           NSAccessibilityParentAttribute,
1156                           NSAccessibilityEnabledAttribute,
1157                           NSAccessibilityPositionAttribute,
1158                           NSAccessibilitySizeAttribute,
1159                           nil];
1160    }
1161    if (anchorAttrs == nil) {
1162        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1163        [tempArray addObject:NSAccessibilityURLAttribute];
1164        [tempArray addObject:NSAccessibilityAccessKeyAttribute];
1165        anchorAttrs = [[NSArray alloc] initWithArray:tempArray];
1166        [tempArray release];
1167    }
1168    if (webAreaAttrs == nil) {
1169        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1170        [tempArray addObject:@"AXLinkUIElements"];
1171        [tempArray addObject:@"AXLoaded"];
1172        [tempArray addObject:@"AXLayoutCount"];
1173        [tempArray addObject:NSAccessibilityLoadingProgressAttribute];
1174        [tempArray addObject:NSAccessibilityURLAttribute];
1175        webAreaAttrs = [[NSArray alloc] initWithArray:tempArray];
1176        [tempArray release];
1177    }
1178    if (textAttrs == nil) {
1179        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1180        [tempArray addObject:NSAccessibilityNumberOfCharactersAttribute];
1181        [tempArray addObject:NSAccessibilitySelectedTextAttribute];
1182        [tempArray addObject:NSAccessibilitySelectedTextRangeAttribute];
1183        [tempArray addObject:NSAccessibilityVisibleCharacterRangeAttribute];
1184        [tempArray addObject:NSAccessibilityInsertionPointLineNumberAttribute];
1185        [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1186        [tempArray addObject:NSAccessibilityAccessKeyAttribute];
1187        [tempArray addObject:NSAccessibilityRequiredAttribute];
1188        [tempArray addObject:NSAccessibilityInvalidAttribute];
1189        [tempArray addObject:NSAccessibilityPlaceholderValueAttribute];
1190        textAttrs = [[NSArray alloc] initWithArray:tempArray];
1191        [tempArray release];
1192    }
1193    if (listAttrs == nil) {
1194        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1195        [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
1196        [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
1197        [tempArray addObject:NSAccessibilityOrientationAttribute];
1198        [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1199        listAttrs = [[NSArray alloc] initWithArray:tempArray];
1200        [tempArray release];
1201    }
1202    if (listBoxAttrs == nil) {
1203        tempArray = [[NSMutableArray alloc] initWithArray:listAttrs];
1204        [tempArray addObject:NSAccessibilityAccessKeyAttribute];
1205        [tempArray addObject:NSAccessibilityRequiredAttribute];
1206        [tempArray addObject:NSAccessibilityInvalidAttribute];
1207        listBoxAttrs = [[NSArray alloc] initWithArray:tempArray];
1208        [tempArray release];
1209    }
1210    if (rangeAttrs == nil) {
1211        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1212        [tempArray addObject:NSAccessibilityMinValueAttribute];
1213        [tempArray addObject:NSAccessibilityMaxValueAttribute];
1214        [tempArray addObject:NSAccessibilityOrientationAttribute];
1215        [tempArray addObject:NSAccessibilityValueDescriptionAttribute];
1216        [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1217        rangeAttrs = [[NSArray alloc] initWithArray:tempArray];
1218        [tempArray release];
1219    }
1220    if (menuBarAttrs == nil) {
1221        tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
1222        [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
1223        [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
1224        [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1225        menuBarAttrs = [[NSArray alloc] initWithArray:tempArray];
1226        [tempArray release];
1227    }
1228    if (menuAttrs == nil) {
1229        tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
1230        [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
1231        [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
1232        [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1233        menuAttrs = [[NSArray alloc] initWithArray:tempArray];
1234        [tempArray release];
1235    }
1236    if (menuItemAttrs == nil) {
1237        tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
1238        [tempArray addObject:NSAccessibilityTitleAttribute];
1239        [tempArray addObject:NSAccessibilityHelpAttribute];
1240        [tempArray addObject:NSAccessibilitySelectedAttribute];
1241        [tempArray addObject:(NSString*)kAXMenuItemCmdCharAttribute];
1242        [tempArray addObject:(NSString*)kAXMenuItemCmdVirtualKeyAttribute];
1243        [tempArray addObject:(NSString*)kAXMenuItemCmdGlyphAttribute];
1244        [tempArray addObject:(NSString*)kAXMenuItemCmdModifiersAttribute];
1245        [tempArray addObject:(NSString*)kAXMenuItemMarkCharAttribute];
1246        [tempArray addObject:(NSString*)kAXMenuItemPrimaryUIElementAttribute];
1247        [tempArray addObject:NSAccessibilityServesAsTitleForUIElementsAttribute];
1248        menuItemAttrs = [[NSArray alloc] initWithArray:tempArray];
1249        [tempArray release];
1250    }
1251    if (menuButtonAttrs == nil) {
1252        menuButtonAttrs = [[NSArray alloc] initWithObjects:NSAccessibilityRoleAttribute,
1253                           NSAccessibilityRoleDescriptionAttribute,
1254                           NSAccessibilityParentAttribute,
1255                           NSAccessibilityPositionAttribute,
1256                           NSAccessibilitySizeAttribute,
1257                           NSAccessibilityWindowAttribute,
1258                           NSAccessibilityEnabledAttribute,
1259                           NSAccessibilityFocusedAttribute,
1260                           NSAccessibilityTitleAttribute,
1261                           NSAccessibilityChildrenAttribute, nil];
1262    }
1263    if (controlAttrs == nil) {
1264        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1265        [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1266        [tempArray addObject:NSAccessibilityAccessKeyAttribute];
1267        [tempArray addObject:NSAccessibilityRequiredAttribute];
1268        [tempArray addObject:NSAccessibilityInvalidAttribute];
1269        controlAttrs = [[NSArray alloc] initWithArray:tempArray];
1270        [tempArray release];
1271    }
1272    if (incrementorAttrs == nil) {
1273        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1274        [tempArray addObject:NSAccessibilityIncrementButtonAttribute];
1275        [tempArray addObject:NSAccessibilityDecrementButtonAttribute];
1276        incrementorAttrs = [[NSArray alloc] initWithArray:tempArray];
1277        [tempArray release];
1278    }
1279    if (buttonAttrs == nil) {
1280        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1281        // Buttons should not expose AXValue.
1282        [tempArray removeObject:NSAccessibilityValueAttribute];
1283        [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1284        [tempArray addObject:NSAccessibilityAccessKeyAttribute];
1285        buttonAttrs = [[NSArray alloc] initWithArray:tempArray];
1286        [tempArray release];
1287    }
1288    if (comboBoxAttrs == nil) {
1289        tempArray = [[NSMutableArray alloc] initWithArray:controlAttrs];
1290        [tempArray addObject:NSAccessibilityExpandedAttribute];
1291        comboBoxAttrs = [[NSArray alloc] initWithArray:tempArray];
1292        [tempArray release];
1293    }
1294    if (tableAttrs == nil) {
1295        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1296        [tempArray addObject:NSAccessibilityRowsAttribute];
1297        [tempArray addObject:NSAccessibilityVisibleRowsAttribute];
1298        [tempArray addObject:NSAccessibilityColumnsAttribute];
1299        [tempArray addObject:NSAccessibilityVisibleColumnsAttribute];
1300        [tempArray addObject:NSAccessibilityVisibleCellsAttribute];
1301        [tempArray addObject:(NSString *)kAXColumnHeaderUIElementsAttribute];
1302        [tempArray addObject:NSAccessibilityRowHeaderUIElementsAttribute];
1303        [tempArray addObject:NSAccessibilityHeaderAttribute];
1304        tableAttrs = [[NSArray alloc] initWithArray:tempArray];
1305        [tempArray release];
1306    }
1307    if (tableRowAttrs == nil) {
1308        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1309        [tempArray addObject:NSAccessibilityIndexAttribute];
1310        tableRowAttrs = [[NSArray alloc] initWithArray:tempArray];
1311        [tempArray release];
1312    }
1313    if (tableColAttrs == nil) {
1314        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1315        [tempArray addObject:NSAccessibilityIndexAttribute];
1316        [tempArray addObject:NSAccessibilityHeaderAttribute];
1317        [tempArray addObject:NSAccessibilityRowsAttribute];
1318        [tempArray addObject:NSAccessibilityVisibleRowsAttribute];
1319        tableColAttrs = [[NSArray alloc] initWithArray:tempArray];
1320        [tempArray release];
1321    }
1322    if (tableCellAttrs == nil) {
1323        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1324        [tempArray addObject:NSAccessibilityRowIndexRangeAttribute];
1325        [tempArray addObject:NSAccessibilityColumnIndexRangeAttribute];
1326        tableCellAttrs = [[NSArray alloc] initWithArray:tempArray];
1327        [tempArray release];
1328    }
1329    if (groupAttrs == nil) {
1330        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1331        [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1332        groupAttrs = [[NSArray alloc] initWithArray:tempArray];
1333        [tempArray release];
1334    }
1335    if (inputImageAttrs == nil) {
1336        tempArray = [[NSMutableArray alloc] initWithArray:buttonAttrs];
1337        [tempArray addObject:NSAccessibilityURLAttribute];
1338        inputImageAttrs = [[NSArray alloc] initWithArray:tempArray];
1339        [tempArray release];
1340    }
1341    if (passwordFieldAttrs == nil) {
1342        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1343        [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1344        [tempArray addObject:NSAccessibilityRequiredAttribute];
1345        [tempArray addObject:NSAccessibilityInvalidAttribute];
1346        [tempArray addObject:NSAccessibilityPlaceholderValueAttribute];
1347        passwordFieldAttrs = [[NSArray alloc] initWithArray:tempArray];
1348        [tempArray release];
1349    }
1350    if (tabListAttrs == nil) {
1351        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1352        [tempArray addObject:NSAccessibilityTabsAttribute];
1353        [tempArray addObject:NSAccessibilityContentsAttribute];
1354        tabListAttrs = [[NSArray alloc] initWithArray:tempArray];
1355        [tempArray release];
1356    }
1357    if (outlineAttrs == nil) {
1358        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1359        [tempArray addObject:NSAccessibilitySelectedRowsAttribute];
1360        [tempArray addObject:NSAccessibilityRowsAttribute];
1361        [tempArray addObject:NSAccessibilityColumnsAttribute];
1362        outlineAttrs = [[NSArray alloc] initWithArray:tempArray];
1363        [tempArray release];
1364    }
1365    if (outlineRowAttrs == nil) {
1366        tempArray = [[NSMutableArray alloc] initWithArray:tableRowAttrs];
1367        [tempArray addObject:NSAccessibilityDisclosingAttribute];
1368        [tempArray addObject:NSAccessibilityDisclosedByRowAttribute];
1369        [tempArray addObject:NSAccessibilityDisclosureLevelAttribute];
1370        [tempArray addObject:NSAccessibilityDisclosedRowsAttribute];
1371        outlineRowAttrs = [[NSArray alloc] initWithArray:tempArray];
1372        [tempArray release];
1373    }
1374    if (scrollViewAttrs == nil) {
1375        tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1376        [tempArray addObject:NSAccessibilityContentsAttribute];
1377        [tempArray addObject:NSAccessibilityHorizontalScrollBarAttribute];
1378        [tempArray addObject:NSAccessibilityVerticalScrollBarAttribute];
1379        scrollViewAttrs = [[NSArray alloc] initWithArray:tempArray];
1380        [tempArray release];
1381    }
1382
1383    NSArray *objectAttributes = attributes;
1384
1385    if (m_object->isPasswordField())
1386        objectAttributes = passwordFieldAttrs;
1387
1388    else if (m_object->isWebArea())
1389        objectAttributes = webAreaAttrs;
1390
1391    else if (m_object->isTextControl())
1392        objectAttributes = textAttrs;
1393
1394    else if (m_object->isAnchor() || m_object->isImage() || m_object->isLink())
1395        objectAttributes = anchorAttrs;
1396
1397    else if (m_object->isAccessibilityTable())
1398        objectAttributes = tableAttrs;
1399    else if (m_object->isTableColumn())
1400        objectAttributes = tableColAttrs;
1401    else if (m_object->isTableCell())
1402        objectAttributes = tableCellAttrs;
1403    else if (m_object->isTableRow()) {
1404        // An ARIA table row can be collapsed and expanded, so it needs the extra attributes.
1405        if (m_object->isARIATreeGridRow())
1406            objectAttributes = outlineRowAttrs;
1407        else
1408            objectAttributes = tableRowAttrs;
1409    }
1410
1411    else if (m_object->isTree())
1412        objectAttributes = outlineAttrs;
1413    else if (m_object->isTreeItem())
1414        objectAttributes = outlineRowAttrs;
1415
1416    else if (m_object->isListBox())
1417        objectAttributes = listBoxAttrs;
1418    else if (m_object->isList())
1419        objectAttributes = listAttrs;
1420
1421    else if (m_object->isComboBox())
1422        objectAttributes = comboBoxAttrs;
1423
1424    else if (m_object->isProgressIndicator() || m_object->isSlider())
1425        objectAttributes = rangeAttrs;
1426
1427    // These are processed in order because an input image is a button, and a button is a control.
1428    else if (m_object->isInputImage())
1429        objectAttributes = inputImageAttrs;
1430    else if (m_object->isButton())
1431        objectAttributes = buttonAttrs;
1432    else if (m_object->isControl())
1433        objectAttributes = controlAttrs;
1434
1435    else if (m_object->isGroup() || m_object->isListItem())
1436        objectAttributes = groupAttrs;
1437    else if (m_object->isTabList())
1438        objectAttributes = tabListAttrs;
1439    else if (m_object->isScrollView())
1440        objectAttributes = scrollViewAttrs;
1441    else if (m_object->isSpinButton())
1442        objectAttributes = incrementorAttrs;
1443
1444    else if (m_object->isMenu())
1445        objectAttributes = menuAttrs;
1446    else if (m_object->isMenuBar())
1447        objectAttributes = menuBarAttrs;
1448    else if (m_object->isMenuButton())
1449        objectAttributes = menuButtonAttrs;
1450    else if (m_object->isMenuItem())
1451        objectAttributes = menuItemAttrs;
1452
1453    NSArray *additionalAttributes = [self additionalAccessibilityAttributeNames];
1454    if ([additionalAttributes count])
1455        objectAttributes = [objectAttributes arrayByAddingObjectsFromArray:additionalAttributes];
1456
1457    return objectAttributes;
1458}
1459
1460- (VisiblePositionRange)visiblePositionRangeForTextMarkerRange:(id)textMarkerRange
1461{
1462    if (!textMarkerRange)
1463        return VisiblePositionRange();
1464    AXObjectCache* cache = m_object->axObjectCache();
1465    return VisiblePositionRange(visiblePositionForStartOfTextMarkerRange(cache, textMarkerRange), visiblePositionForEndOfTextMarkerRange(cache, textMarkerRange));
1466}
1467
1468- (NSArray*)renderWidgetChildren
1469{
1470    Widget* widget = m_object->widget();
1471    if (!widget)
1472        return nil;
1473    return [(widget->platformWidget()) accessibilityAttributeValue: NSAccessibilityChildrenAttribute];
1474}
1475
1476- (id)remoteAccessibilityParentObject
1477{
1478    if (!m_object)
1479        return nil;
1480
1481    Document* document = m_object->document();
1482    if (!document)
1483        return nil;
1484
1485    Frame* frame = document->frame();
1486    if (!frame)
1487        return nil;
1488
1489    return frame->loader()->client()->accessibilityRemoteObject();
1490}
1491
1492static void convertToVector(NSArray* array, AccessibilityObject::AccessibilityChildrenVector& vector)
1493{
1494    unsigned length = [array count];
1495    vector.reserveInitialCapacity(length);
1496    for (unsigned i = 0; i < length; ++i) {
1497        AccessibilityObject* obj = [[array objectAtIndex:i] accessibilityObject];
1498        if (obj)
1499            vector.append(obj);
1500    }
1501}
1502
1503static NSMutableArray* convertToNSArray(const AccessibilityObject::AccessibilityChildrenVector& vector)
1504{
1505    unsigned length = vector.size();
1506    NSMutableArray* array = [NSMutableArray arrayWithCapacity: length];
1507    for (unsigned i = 0; i < length; ++i) {
1508        WebAccessibilityObjectWrapper* wrapper = vector[i]->wrapper();
1509        ASSERT(wrapper);
1510        if (wrapper) {
1511            // we want to return the attachment view instead of the object representing the attachment.
1512            // otherwise, we get palindrome errors in the AX hierarchy
1513            if (vector[i]->isAttachment() && [wrapper attachmentView])
1514                [array addObject:[wrapper attachmentView]];
1515            else
1516                [array addObject:wrapper];
1517        }
1518    }
1519    return array;
1520}
1521
1522- (id)textMarkerRangeForSelection
1523{
1524    VisibleSelection selection = m_object->selection();
1525    if (selection.isNone())
1526        return nil;
1527    return [self textMarkerRangeFromVisiblePositions:selection.visibleStart() endPosition:selection.visibleEnd()];
1528}
1529
1530- (CGPoint)convertPointToScreenSpace:(FloatPoint &)point
1531{
1532    FrameView* frameView = m_object->documentFrameView();
1533
1534    // WebKit1 code path... platformWidget() exists.
1535    if (frameView && frameView->platformWidget()) {
1536
1537        NSPoint nsPoint = (NSPoint)point;
1538        NSView* view = frameView->documentView();
1539        nsPoint = [[view window] convertBaseToScreen:[view convertPoint:nsPoint toView:nil]];
1540        return CGPointMake(nsPoint.x, nsPoint.y);
1541
1542    } else {
1543
1544        // Find the appropriate scroll view to use to convert the contents to the window.
1545        ScrollView* scrollView = 0;
1546        AccessibilityObject* parent = 0;
1547        for (parent = m_object->parentObject(); parent; parent = parent->parentObject()) {
1548            if (parent->isAccessibilityScrollView()) {
1549                scrollView = toAccessibilityScrollView(parent)->scrollView();
1550                break;
1551            }
1552        }
1553
1554        IntPoint intPoint = flooredIntPoint(point);
1555        if (scrollView)
1556            intPoint = scrollView->contentsToRootView(intPoint);
1557
1558        Page* page = m_object->page();
1559
1560        // If we have an empty chrome client (like SVG) then we should use the page
1561        // of the scroll view parent to help us get to the screen rect.
1562        if (parent && page && page->chrome().client()->isEmptyChromeClient())
1563            page = parent->page();
1564
1565        if (page) {
1566            IntRect rect = IntRect(intPoint, IntSize(0, 0));
1567            intPoint = page->chrome().rootViewToScreen(rect).location();
1568        }
1569
1570        return intPoint;
1571    }
1572}
1573
1574static void WebTransformCGPathToNSBezierPath(void *info, const CGPathElement *element)
1575{
1576    NSBezierPath *bezierPath = (NSBezierPath *)info;
1577    switch (element->type) {
1578    case kCGPathElementMoveToPoint:
1579        [bezierPath moveToPoint:NSPointFromCGPoint(element->points[0])];
1580        break;
1581    case kCGPathElementAddLineToPoint:
1582        [bezierPath lineToPoint:NSPointFromCGPoint(element->points[0])];
1583        break;
1584    case kCGPathElementAddCurveToPoint:
1585        [bezierPath curveToPoint:NSPointFromCGPoint(element->points[0]) controlPoint1:NSPointFromCGPoint(element->points[1]) controlPoint2:NSPointFromCGPoint(element->points[2])];
1586        break;
1587    case kCGPathElementCloseSubpath:
1588        [bezierPath closePath];
1589        break;
1590    default:
1591        break;
1592    }
1593}
1594
1595- (NSBezierPath *)bezierPathFromPath:(CGPathRef)path
1596{
1597    NSBezierPath *bezierPath = [NSBezierPath bezierPath];
1598    CGPathApply(path, bezierPath, WebTransformCGPathToNSBezierPath);
1599    return bezierPath;
1600}
1601
1602- (NSBezierPath *)path
1603{
1604    Path path = m_object->elementPath();
1605    if (path.isEmpty())
1606        return NULL;
1607
1608    CGPathRef transformedPath = [self convertPathToScreenSpace:path];
1609    return [self bezierPathFromPath:transformedPath];
1610}
1611
1612- (NSValue *)position
1613{
1614    IntRect rect = pixelSnappedIntRect(m_object->elementRect());
1615
1616    // The Cocoa accessibility API wants the lower-left corner.
1617    FloatPoint floatPoint = FloatPoint(rect.x(), rect.maxY());
1618
1619    CGPoint cgPoint = [self convertPointToScreenSpace:floatPoint];
1620
1621    return [NSValue valueWithPoint:NSMakePoint(cgPoint.x, cgPoint.y)];
1622}
1623
1624typedef HashMap<int, NSString*> AccessibilityRoleMap;
1625
1626static const AccessibilityRoleMap& createAccessibilityRoleMap()
1627{
1628    struct RoleEntry {
1629        AccessibilityRole value;
1630        NSString* string;
1631    };
1632
1633    static const RoleEntry roles[] = {
1634        { UnknownRole, NSAccessibilityUnknownRole },
1635        { ButtonRole, NSAccessibilityButtonRole },
1636        { RadioButtonRole, NSAccessibilityRadioButtonRole },
1637        { CheckBoxRole, NSAccessibilityCheckBoxRole },
1638        { SliderRole, NSAccessibilitySliderRole },
1639        { TabGroupRole, NSAccessibilityTabGroupRole },
1640        { TextFieldRole, NSAccessibilityTextFieldRole },
1641        { StaticTextRole, NSAccessibilityStaticTextRole },
1642        { TextAreaRole, NSAccessibilityTextAreaRole },
1643        { ScrollAreaRole, NSAccessibilityScrollAreaRole },
1644        { PopUpButtonRole, NSAccessibilityPopUpButtonRole },
1645        { MenuButtonRole, NSAccessibilityMenuButtonRole },
1646        { TableRole, NSAccessibilityTableRole },
1647        { ApplicationRole, NSAccessibilityApplicationRole },
1648        { GroupRole, NSAccessibilityGroupRole },
1649        { RadioGroupRole, NSAccessibilityRadioGroupRole },
1650        { ListRole, NSAccessibilityListRole },
1651        { DirectoryRole, NSAccessibilityListRole },
1652        { ScrollBarRole, NSAccessibilityScrollBarRole },
1653        { ValueIndicatorRole, NSAccessibilityValueIndicatorRole },
1654        { ImageRole, NSAccessibilityImageRole },
1655        { MenuBarRole, NSAccessibilityMenuBarRole },
1656        { MenuRole, NSAccessibilityMenuRole },
1657        { MenuItemRole, NSAccessibilityMenuItemRole },
1658        { ColumnRole, NSAccessibilityColumnRole },
1659        { RowRole, NSAccessibilityRowRole },
1660        { ToolbarRole, NSAccessibilityToolbarRole },
1661        { BusyIndicatorRole, NSAccessibilityBusyIndicatorRole },
1662        { ProgressIndicatorRole, NSAccessibilityProgressIndicatorRole },
1663        { WindowRole, NSAccessibilityWindowRole },
1664        { DrawerRole, NSAccessibilityDrawerRole },
1665        { SystemWideRole, NSAccessibilitySystemWideRole },
1666        { OutlineRole, NSAccessibilityOutlineRole },
1667        { IncrementorRole, NSAccessibilityIncrementorRole },
1668        { BrowserRole, NSAccessibilityBrowserRole },
1669        { ComboBoxRole, NSAccessibilityComboBoxRole },
1670        { SplitGroupRole, NSAccessibilitySplitGroupRole },
1671        { SplitterRole, NSAccessibilitySplitterRole },
1672        { ColorWellRole, NSAccessibilityColorWellRole },
1673        { GrowAreaRole, NSAccessibilityGrowAreaRole },
1674        { SheetRole, NSAccessibilitySheetRole },
1675        { HelpTagRole, NSAccessibilityHelpTagRole },
1676        { MatteRole, NSAccessibilityMatteRole },
1677        { RulerRole, NSAccessibilityRulerRole },
1678        { RulerMarkerRole, NSAccessibilityRulerMarkerRole },
1679        { LinkRole, NSAccessibilityLinkRole },
1680        { DisclosureTriangleRole, NSAccessibilityDisclosureTriangleRole },
1681        { GridRole, NSAccessibilityGridRole },
1682        { WebCoreLinkRole, NSAccessibilityLinkRole },
1683        { ImageMapLinkRole, NSAccessibilityLinkRole },
1684        { ImageMapRole, @"AXImageMap" },
1685        { ListMarkerRole, @"AXListMarker" },
1686        { WebAreaRole, @"AXWebArea" },
1687        { SeamlessWebAreaRole, NSAccessibilityGroupRole },
1688        { HeadingRole, @"AXHeading" },
1689        { ListBoxRole, NSAccessibilityListRole },
1690        { ListBoxOptionRole, NSAccessibilityStaticTextRole },
1691        { CellRole, NSAccessibilityCellRole },
1692        { TableHeaderContainerRole, NSAccessibilityGroupRole },
1693        { RowHeaderRole, NSAccessibilityGroupRole },
1694        { DefinitionRole, NSAccessibilityGroupRole },
1695        { DescriptionListDetailRole, NSAccessibilityGroupRole },
1696        { DescriptionListTermRole, NSAccessibilityGroupRole },
1697        { DescriptionListRole, NSAccessibilityListRole },
1698        { SliderThumbRole, NSAccessibilityValueIndicatorRole },
1699        { LandmarkApplicationRole, NSAccessibilityGroupRole },
1700        { LandmarkBannerRole, NSAccessibilityGroupRole },
1701        { LandmarkComplementaryRole, NSAccessibilityGroupRole },
1702        { LandmarkContentInfoRole, NSAccessibilityGroupRole },
1703        { LandmarkMainRole, NSAccessibilityGroupRole },
1704        { LandmarkNavigationRole, NSAccessibilityGroupRole },
1705        { LandmarkSearchRole, NSAccessibilityGroupRole },
1706        { ApplicationAlertRole, NSAccessibilityGroupRole },
1707        { ApplicationAlertDialogRole, NSAccessibilityGroupRole },
1708        { ApplicationDialogRole, NSAccessibilityGroupRole },
1709        { ApplicationLogRole, NSAccessibilityGroupRole },
1710        { ApplicationMarqueeRole, NSAccessibilityGroupRole },
1711        { ApplicationStatusRole, NSAccessibilityGroupRole },
1712        { ApplicationTimerRole, NSAccessibilityGroupRole },
1713        { DocumentRole, NSAccessibilityGroupRole },
1714        { DocumentArticleRole, NSAccessibilityGroupRole },
1715        { DocumentMathRole, NSAccessibilityGroupRole },
1716        { DocumentNoteRole, NSAccessibilityGroupRole },
1717        { DocumentRegionRole, NSAccessibilityGroupRole },
1718        { UserInterfaceTooltipRole, NSAccessibilityGroupRole },
1719        { TabRole, NSAccessibilityRadioButtonRole },
1720        { TabListRole, NSAccessibilityTabGroupRole },
1721        { TabPanelRole, NSAccessibilityGroupRole },
1722        { TreeRole, NSAccessibilityOutlineRole },
1723        { TreeItemRole, NSAccessibilityRowRole },
1724        { ListItemRole, NSAccessibilityGroupRole },
1725        { ParagraphRole, NSAccessibilityGroupRole },
1726        { LabelRole, NSAccessibilityGroupRole },
1727        { DivRole, NSAccessibilityGroupRole },
1728        { FormRole, NSAccessibilityGroupRole },
1729        { SpinButtonRole, NSAccessibilityIncrementorRole },
1730        { FooterRole, NSAccessibilityGroupRole },
1731        { ToggleButtonRole, NSAccessibilityButtonRole },
1732        { CanvasRole, NSAccessibilityImageRole },
1733        { SVGRootRole, NSAccessibilityGroupRole },
1734        { LegendRole, NSAccessibilityGroupRole },
1735        { MathElementRole, NSAccessibilityGroupRole },
1736        { AudioRole, NSAccessibilityGroupRole },
1737        { VideoRole, NSAccessibilityGroupRole }
1738    };
1739    AccessibilityRoleMap& roleMap = *new AccessibilityRoleMap;
1740
1741    const unsigned numRoles = sizeof(roles) / sizeof(roles[0]);
1742    for (unsigned i = 0; i < numRoles; ++i)
1743        roleMap.set(roles[i].value, roles[i].string);
1744    return roleMap;
1745}
1746
1747static NSString* roleValueToNSString(AccessibilityRole value)
1748{
1749    ASSERT(value);
1750    static const AccessibilityRoleMap& roleMap = createAccessibilityRoleMap();
1751    return roleMap.get(value);
1752}
1753
1754- (NSString*)role
1755{
1756    if (m_object->isAttachment())
1757        return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleAttribute];
1758    AccessibilityRole role = m_object->roleValue();
1759    if (role == CanvasRole && m_object->canvasHasFallbackContent())
1760        role = GroupRole;
1761    NSString* string = roleValueToNSString(role);
1762    if (string != nil)
1763        return string;
1764    return NSAccessibilityUnknownRole;
1765}
1766
1767- (NSString*)subrole
1768{
1769    if (m_object->isPasswordField())
1770        return NSAccessibilitySecureTextFieldSubrole;
1771    if (m_object->isSearchField())
1772        return NSAccessibilitySearchFieldSubrole;
1773
1774    if (m_object->isAttachment()) {
1775        NSView* attachView = [self attachmentView];
1776        if ([[attachView accessibilityAttributeNames] containsObject:NSAccessibilitySubroleAttribute]) {
1777            return [attachView accessibilityAttributeValue:NSAccessibilitySubroleAttribute];
1778        }
1779    }
1780
1781    if (m_object->isSpinButtonPart()) {
1782        if (toAccessibilitySpinButtonPart(m_object)->isIncrementor())
1783            return NSAccessibilityIncrementArrowSubrole;
1784
1785        return NSAccessibilityDecrementArrowSubrole;
1786    }
1787
1788    if (m_object->isFileUploadButton())
1789        return @"AXFileUploadButton";
1790
1791    if (m_object->isTreeItem())
1792        return NSAccessibilityOutlineRowSubrole;
1793
1794    if (m_object->isList()) {
1795        AccessibilityList* listObject = toAccessibilityList(m_object);
1796        if (listObject->isUnorderedList() || listObject->isOrderedList())
1797            return NSAccessibilityContentListSubrole;
1798        if (listObject->isDescriptionList()) {
1799#if __MAC_OS_X_VERSION_MIN_REQUIRED < 1090
1800            return NSAccessibilityDefinitionListSubrole;
1801#else
1802            return NSAccessibilityDescriptionListSubrole;
1803#endif
1804        }
1805    }
1806
1807    // ARIA content subroles.
1808    switch (m_object->roleValue()) {
1809        case LandmarkApplicationRole:
1810            return @"AXLandmarkApplication";
1811        case LandmarkBannerRole:
1812            return @"AXLandmarkBanner";
1813        case LandmarkComplementaryRole:
1814            return @"AXLandmarkComplementary";
1815            // Footer roles should appear as content info types.
1816        case FooterRole:
1817        case LandmarkContentInfoRole:
1818            return @"AXLandmarkContentInfo";
1819        case LandmarkMainRole:
1820            return @"AXLandmarkMain";
1821        case LandmarkNavigationRole:
1822            return @"AXLandmarkNavigation";
1823        case LandmarkSearchRole:
1824            return @"AXLandmarkSearch";
1825        case ApplicationAlertRole:
1826            return @"AXApplicationAlert";
1827        case ApplicationAlertDialogRole:
1828            return @"AXApplicationAlertDialog";
1829        case ApplicationDialogRole:
1830            return @"AXApplicationDialog";
1831        case ApplicationLogRole:
1832            return @"AXApplicationLog";
1833        case ApplicationMarqueeRole:
1834            return @"AXApplicationMarquee";
1835        case ApplicationStatusRole:
1836            return @"AXApplicationStatus";
1837        case ApplicationTimerRole:
1838            return @"AXApplicationTimer";
1839        case DocumentRole:
1840            return @"AXDocument";
1841        case DocumentArticleRole:
1842            return @"AXDocumentArticle";
1843        case DocumentMathRole:
1844            return @"AXDocumentMath";
1845        case DocumentNoteRole:
1846            return @"AXDocumentNote";
1847        case DocumentRegionRole:
1848            return @"AXDocumentRegion";
1849        case UserInterfaceTooltipRole:
1850            return @"AXUserInterfaceTooltip";
1851        case TabPanelRole:
1852            return @"AXTabPanel";
1853        case DefinitionRole:
1854            return @"AXDefinition";
1855        case DescriptionListTermRole:
1856            return @"AXTerm";
1857        case DescriptionListDetailRole:
1858            return @"AXDescription";
1859            // Default doesn't return anything, so roles defined below can be chosen.
1860        default:
1861            break;
1862    }
1863
1864    if (m_object->roleValue() == MathElementRole) {
1865        if (m_object->isMathFraction())
1866            return @"AXMathFraction";
1867        if (m_object->isMathFenced())
1868            return @"AXMathFenced";
1869        if (m_object->isMathSubscriptSuperscript())
1870            return @"AXMathSubscriptSuperscript";
1871        if (m_object->isMathRow())
1872            return @"AXMathRow";
1873        if (m_object->isMathUnderOver())
1874            return @"AXMathUnderOver";
1875        if (m_object->isMathSquareRoot())
1876            return @"AXMathSquareRoot";
1877        if (m_object->isMathRoot())
1878            return @"AXMathRoot";
1879        if (m_object->isMathText())
1880            return @"AXMathText";
1881        if (m_object->isMathNumber())
1882            return @"AXMathNumber";
1883        if (m_object->isMathIdentifier())
1884            return @"AXMathIdentifier";
1885        if (m_object->isMathTable())
1886            return @"AXMathTable";
1887        if (m_object->isMathTableRow())
1888            return @"AXMathTableRow";
1889        if (m_object->isMathTableCell())
1890            return @"AXMathTableCell";
1891        if (m_object->isMathFenceOperator())
1892            return @"AXMathFenceOperator";
1893        if (m_object->isMathSeparatorOperator())
1894            return @"AXMathSeparatorOperator";
1895        if (m_object->isMathOperator())
1896            return @"AXMathOperator";
1897        if (m_object->isMathMultiscript())
1898            return @"AXMathMultiscript";
1899    }
1900
1901    if (m_object->roleValue() == VideoRole)
1902        return @"AXVideo";
1903    if (m_object->roleValue() == AudioRole)
1904        return @"AXAudio";
1905
1906    if (m_object->isMediaTimeline())
1907        return NSAccessibilityTimelineSubrole;
1908
1909    return nil;
1910}
1911
1912- (NSString*)roleDescription
1913{
1914    if (!m_object)
1915        return nil;
1916
1917    // attachments have the AXImage role, but a different subrole
1918    if (m_object->isAttachment())
1919        return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleDescriptionAttribute];
1920
1921    NSString* axRole = [self role];
1922
1923    if ([axRole isEqualToString:NSAccessibilityGroupRole]) {
1924
1925        NSString *ariaLandmarkRoleDescription = [self ariaLandmarkRoleDescription];
1926        if (ariaLandmarkRoleDescription)
1927            return ariaLandmarkRoleDescription;
1928
1929        switch (m_object->roleValue()) {
1930        case AudioRole:
1931            return localizedMediaControlElementString("AudioElement");
1932        case DefinitionRole:
1933            return AXDefinitionText();
1934        case DescriptionListTermRole:
1935            return AXDescriptionListTermText();
1936        case DescriptionListDetailRole:
1937            return AXDescriptionListDetailText();
1938        case FooterRole:
1939            return AXFooterRoleDescriptionText();
1940        case VideoRole:
1941            return localizedMediaControlElementString("VideoElement");
1942        default:
1943            return NSAccessibilityRoleDescription(NSAccessibilityGroupRole, [self subrole]);
1944        }
1945    }
1946
1947    if ([axRole isEqualToString:@"AXWebArea"])
1948        return AXWebAreaText();
1949
1950    if ([axRole isEqualToString:@"AXLink"])
1951        return AXLinkText();
1952
1953    if ([axRole isEqualToString:@"AXListMarker"])
1954        return AXListMarkerText();
1955
1956    if ([axRole isEqualToString:@"AXImageMap"])
1957        return AXImageMapText();
1958
1959    if ([axRole isEqualToString:@"AXHeading"])
1960        return AXHeadingText();
1961
1962    if (m_object->isFileUploadButton())
1963        return AXFileUploadButtonText();
1964
1965    // Only returning for DL (not UL or OL) because description changed with HTML5 from 'definition list' to
1966    // superset 'description list' and does not return the same values in AX API on some OS versions.
1967    if (m_object->isList()) {
1968        AccessibilityList* listObject = toAccessibilityList(m_object);
1969        if (listObject->isDescriptionList())
1970            return AXDescriptionListText();
1971    }
1972
1973    // AppKit also returns AXTab for the role description for a tab item.
1974    if (m_object->isTabItem())
1975        return NSAccessibilityRoleDescription(@"AXTab", nil);
1976
1977    // We should try the system default role description for all other roles.
1978    // If we get the same string back, then as a last resort, return unknown.
1979    NSString* defaultRoleDescription = NSAccessibilityRoleDescription(axRole, [self subrole]);
1980
1981    // On earlier Mac versions (Lion), using a non-standard subrole would result in a role description
1982    // being returned that looked like AXRole:AXSubrole. To make all platforms have the same role descriptions
1983    // we should fallback on a role description ignoring the subrole in these cases.
1984    if ([defaultRoleDescription isEqualToString:[NSString stringWithFormat:@"%@:%@", axRole, [self subrole]]])
1985        defaultRoleDescription = NSAccessibilityRoleDescription(axRole, nil);
1986
1987    if (![defaultRoleDescription isEqualToString:axRole])
1988        return defaultRoleDescription;
1989
1990    return NSAccessibilityRoleDescription(NSAccessibilityUnknownRole, nil);
1991}
1992
1993- (id)scrollViewParent
1994{
1995    if (!m_object || !m_object->isAccessibilityScrollView())
1996        return nil;
1997
1998    // If this scroll view provides it's parent object (because it's a sub-frame), then
1999    // we should not find the remoteAccessibilityParent.
2000    if (m_object->parentObject())
2001        return nil;
2002
2003    AccessibilityScrollView* scrollView = toAccessibilityScrollView(m_object);
2004    ScrollView* scroll = scrollView->scrollView();
2005    if (!scroll)
2006        return nil;
2007
2008    if (scroll->platformWidget())
2009        return NSAccessibilityUnignoredAncestor(scroll->platformWidget());
2010
2011    return [self remoteAccessibilityParentObject];
2012}
2013
2014// FIXME: Different kinds of elements are putting the title tag to use in different
2015// AX fields. This should be rectified, but in the initial patch I want to achieve
2016// parity with existing behavior.
2017- (BOOL)titleTagShouldBeUsedInDescriptionField
2018{
2019    return (m_object->isLink() && !m_object->isImageMapLink()) || m_object->isImage();
2020}
2021
2022// This should be the "visible" text that's actually on the screen if possible.
2023// If there's alternative text, that can override the title.
2024- (NSString *)accessibilityTitle
2025{
2026    // Static text objects should not have a title. Its content is communicated in its AXValue.
2027    if (m_object->roleValue() == StaticTextRole)
2028        return [NSString string];
2029
2030    // A file upload button presents a challenge because it has button text and a value, but the
2031    // API doesn't support this paradigm.
2032    // The compromise is to return the button type in the role description and the value of the file path in the title
2033    if (m_object->isFileUploadButton())
2034        return m_object->stringValue();
2035
2036    Vector<AccessibilityText> textOrder;
2037    m_object->accessibilityText(textOrder);
2038
2039    unsigned length = textOrder.size();
2040    for (unsigned k = 0; k < length; k++) {
2041        const AccessibilityText& text = textOrder[k];
2042
2043        // If we have alternative text, then we should not expose a title.
2044        if (text.textSource == AlternativeText)
2045            break;
2046
2047        // Once we encounter visible text, or the text from our children that should be used foremost.
2048        if (text.textSource == VisibleText || text.textSource == ChildrenText)
2049            return text.text;
2050
2051        // If there's an element that labels this object and it's not exposed, then we should use
2052        // that text as our title.
2053        if (text.textSource == LabelByElementText && !m_object->exposesTitleUIElement())
2054            return text.text;
2055
2056        // FIXME: The title tag is used in certain cases for the title. This usage should
2057        // probably be in the description field since it's not "visible".
2058        if (text.textSource == TitleTagText && ![self titleTagShouldBeUsedInDescriptionField])
2059            return text.text;
2060    }
2061
2062    return [NSString string];
2063}
2064
2065- (NSString *)accessibilityDescription
2066{
2067    // Static text objects should not have a description. Its content is communicated in its AXValue.
2068    // One exception is the media control labels that have a value and a description. Those are set programatically.
2069    if (m_object->roleValue() == StaticTextRole && !m_object->isMediaControlLabel())
2070        return [NSString string];
2071
2072    Vector<AccessibilityText> textOrder;
2073    m_object->accessibilityText(textOrder);
2074
2075    unsigned length = textOrder.size();
2076    for (unsigned k = 0; k < length; k++) {
2077        const AccessibilityText& text = textOrder[k];
2078
2079        if (text.textSource == AlternativeText)
2080            return text.text;
2081
2082        if (text.textSource == TitleTagText && [self titleTagShouldBeUsedInDescriptionField])
2083            return text.text;
2084    }
2085
2086    return [NSString string];
2087}
2088
2089- (NSString *)accessibilityHelpText
2090{
2091    Vector<AccessibilityText> textOrder;
2092    m_object->accessibilityText(textOrder);
2093
2094    unsigned length = textOrder.size();
2095    bool descriptiveTextAvailable = false;
2096    for (unsigned k = 0; k < length; k++) {
2097        const AccessibilityText& text = textOrder[k];
2098
2099        if (text.textSource == HelpText || text.textSource == SummaryText)
2100            return text.text;
2101
2102        // If an element does NOT have other descriptive text the title tag should be used as its descriptive text.
2103        // But, if those ARE available, then the title tag should be used for help text instead.
2104        switch (text.textSource) {
2105            case AlternativeText:
2106            case VisibleText:
2107            case ChildrenText:
2108            case LabelByElementText:
2109                descriptiveTextAvailable = true;
2110            default:
2111                break;
2112        }
2113
2114        if (text.textSource == TitleTagText && descriptiveTextAvailable)
2115            return text.text;
2116    }
2117
2118    return [NSString string];
2119}
2120
2121// FIXME: split up this function in a better way.
2122// suggestions: Use a hash table that maps attribute names to function calls,
2123// or maybe pointers to member functions
2124- (id)accessibilityAttributeValue:(NSString*)attributeName
2125{
2126    if (![self updateObjectBackingStore])
2127        return nil;
2128
2129    if ([attributeName isEqualToString: NSAccessibilityRoleAttribute])
2130        return [self role];
2131
2132    if ([attributeName isEqualToString: NSAccessibilitySubroleAttribute])
2133        return [self subrole];
2134
2135    if ([attributeName isEqualToString: NSAccessibilityRoleDescriptionAttribute])
2136        return [self roleDescription];
2137
2138    if ([attributeName isEqualToString: NSAccessibilityParentAttribute]) {
2139
2140        // This will return the parent of the AXWebArea, if this is a web area.
2141        id scrollViewParent = [self scrollViewParent];
2142        if (scrollViewParent)
2143            return scrollViewParent;
2144
2145        // Tree item (changed to AXRows) can only report the tree (AXOutline) as its parent.
2146        if (m_object->isTreeItem()) {
2147            AccessibilityObject* parent = m_object->parentObjectUnignored();
2148            while (parent) {
2149                if (parent->isTree())
2150                    return parent->wrapper();
2151                parent = parent->parentObjectUnignored();
2152            }
2153        }
2154
2155        AccessibilityObject* parent = m_object->parentObjectUnignored();
2156        if (!parent)
2157            return nil;
2158
2159        // In WebKit1, the scroll view is provided by the system (the attachment view), so the parent
2160        // should be reported directly as such.
2161        if (m_object->isWebArea() && parent->isAttachment())
2162            return [parent->wrapper() attachmentView];
2163
2164        return parent->wrapper();
2165    }
2166
2167    if ([attributeName isEqualToString: NSAccessibilityChildrenAttribute]) {
2168        if (m_object->children().isEmpty()) {
2169            NSArray* children = [self renderWidgetChildren];
2170            if (children != nil)
2171                return children;
2172        }
2173
2174        // The tree's (AXOutline) children are supposed to be its rows and columns.
2175        // The ARIA spec doesn't have columns, so we just need rows.
2176        if (m_object->isTree())
2177            return [self accessibilityAttributeValue:NSAccessibilityRowsAttribute];
2178
2179        // A tree item should only expose its content as its children (not its rows)
2180        if (m_object->isTreeItem()) {
2181            AccessibilityObject::AccessibilityChildrenVector contentCopy;
2182            m_object->ariaTreeItemContent(contentCopy);
2183            return convertToNSArray(contentCopy);
2184        }
2185
2186        return convertToNSArray(m_object->children());
2187    }
2188
2189    if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) {
2190        if (m_object->isListBox()) {
2191            AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
2192            m_object->selectedChildren(selectedChildrenCopy);
2193            return convertToNSArray(selectedChildrenCopy);
2194        }
2195        return nil;
2196    }
2197
2198    if ([attributeName isEqualToString: NSAccessibilityVisibleChildrenAttribute]) {
2199        if (m_object->isListBox()) {
2200            AccessibilityObject::AccessibilityChildrenVector visibleChildrenCopy;
2201            m_object->visibleChildren(visibleChildrenCopy);
2202            return convertToNSArray(visibleChildrenCopy);
2203        }
2204        else if (m_object->isList())
2205            return [self accessibilityAttributeValue:NSAccessibilityChildrenAttribute];
2206
2207        return nil;
2208    }
2209
2210
2211    if (m_object->isWebArea()) {
2212        if ([attributeName isEqualToString:@"AXLinkUIElements"]) {
2213            AccessibilityObject::AccessibilityChildrenVector links;
2214            static_cast<AccessibilityRenderObject*>(m_object)->getDocumentLinks(links);
2215            return convertToNSArray(links);
2216        }
2217        if ([attributeName isEqualToString:@"AXLoaded"])
2218            return [NSNumber numberWithBool:m_object->isLoaded()];
2219        if ([attributeName isEqualToString:@"AXLayoutCount"])
2220            return [NSNumber numberWithInt:m_object->layoutCount()];
2221        if ([attributeName isEqualToString:NSAccessibilityLoadingProgressAttribute])
2222            return [NSNumber numberWithDouble:m_object->estimatedLoadingProgress()];
2223    }
2224
2225    if (m_object->isTextControl()) {
2226        if ([attributeName isEqualToString: NSAccessibilityNumberOfCharactersAttribute]) {
2227            int length = m_object->textLength();
2228            if (length < 0)
2229                return nil;
2230            return [NSNumber numberWithUnsignedInt:length];
2231        }
2232        if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) {
2233            String selectedText = m_object->selectedText();
2234            if (selectedText.isNull())
2235                return nil;
2236            return (NSString*)selectedText;
2237        }
2238        if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) {
2239            PlainTextRange textRange = m_object->selectedTextRange();
2240            if (textRange.isNull())
2241                return [NSValue valueWithRange:NSMakeRange(0, 0)];
2242            return [NSValue valueWithRange:NSMakeRange(textRange.start, textRange.length)];
2243        }
2244        // TODO: Get actual visible range. <rdar://problem/4712101>
2245        if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
2246            return m_object->isPasswordField() ? nil : [NSValue valueWithRange: NSMakeRange(0, m_object->textLength())];
2247        if ([attributeName isEqualToString: NSAccessibilityInsertionPointLineNumberAttribute]) {
2248            // if selectionEnd > 0, then there is selected text and this question should not be answered
2249            if (m_object->isPasswordField() || m_object->selectionEnd() > 0)
2250                return nil;
2251
2252            AccessibilityObject* focusedObject = m_object->focusedUIElement();
2253            if (focusedObject != m_object)
2254                return nil;
2255
2256            VisiblePosition focusedPosition = focusedObject->visiblePositionForIndex(focusedObject->selectionStart(), true);
2257            int lineNumber = m_object->lineForPosition(focusedPosition);
2258            if (lineNumber < 0)
2259                return nil;
2260
2261            return [NSNumber numberWithInt:lineNumber];
2262        }
2263    }
2264
2265    if ([attributeName isEqualToString: NSAccessibilityURLAttribute]) {
2266        KURL url = m_object->url();
2267        if (url.isNull())
2268            return nil;
2269        return (NSURL*)url;
2270    }
2271
2272    // Only native spin buttons have increment and decrement buttons.
2273    if (m_object->isNativeSpinButton()) {
2274        if ([attributeName isEqualToString:NSAccessibilityIncrementButtonAttribute])
2275            return toAccessibilitySpinButton(m_object)->incrementButton()->wrapper();
2276        if ([attributeName isEqualToString:NSAccessibilityDecrementButtonAttribute])
2277            return toAccessibilitySpinButton(m_object)->decrementButton()->wrapper();
2278    }
2279
2280    if ([attributeName isEqualToString: @"AXVisited"])
2281        return [NSNumber numberWithBool: m_object->isVisited()];
2282
2283    if ([attributeName isEqualToString: NSAccessibilityTitleAttribute]) {
2284        if (m_object->isAttachment()) {
2285            if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityTitleAttribute])
2286                return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityTitleAttribute];
2287        }
2288
2289        return [self accessibilityTitle];
2290    }
2291
2292    if ([attributeName isEqualToString: NSAccessibilityDescriptionAttribute]) {
2293        if (m_object->isAttachment()) {
2294            if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityDescriptionAttribute])
2295                return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityDescriptionAttribute];
2296        }
2297        return [self accessibilityDescription];
2298    }
2299
2300    if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) {
2301        if (m_object->isAttachment()) {
2302            if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityValueAttribute])
2303                return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityValueAttribute];
2304        }
2305        if (m_object->supportsRangeValue())
2306            return [NSNumber numberWithFloat:m_object->valueForRange()];
2307        if (m_object->roleValue() == SliderThumbRole)
2308            return [NSNumber numberWithFloat:m_object->parentObject()->valueForRange()];
2309        if (m_object->isHeading())
2310            return [NSNumber numberWithInt:m_object->headingLevel()];
2311
2312        if (m_object->isCheckboxOrRadio()) {
2313            switch (m_object->checkboxOrRadioValue()) {
2314                case ButtonStateOff:
2315                    return [NSNumber numberWithInt:0];
2316                case ButtonStateOn:
2317                    return [NSNumber numberWithInt:1];
2318                case ButtonStateMixed:
2319                    return [NSNumber numberWithInt:2];
2320            }
2321        }
2322
2323        // radio groups return the selected radio button as the AXValue
2324        if (m_object->isRadioGroup()) {
2325            AccessibilityObject* radioButton = m_object->selectedRadioButton();
2326            if (!radioButton)
2327                return nil;
2328            return radioButton->wrapper();
2329        }
2330
2331        if (m_object->isTabList()) {
2332            AccessibilityObject* tabItem = m_object->selectedTabItem();
2333            if (!tabItem)
2334                return nil;
2335            return tabItem->wrapper();
2336        }
2337
2338        if (m_object->isTabItem())
2339            return [NSNumber numberWithInt:m_object->isSelected()];
2340
2341        if (m_object->isColorWell()) {
2342            int r, g, b;
2343            m_object->colorValue(r, g, b);
2344            return [NSString stringWithFormat:@"rgb %7.5f %7.5f %7.5f 1", r / 255., g / 255., b / 255.];
2345        }
2346
2347        return m_object->stringValue();
2348    }
2349
2350    if ([attributeName isEqualToString:(NSString *)kAXMenuItemMarkCharAttribute]) {
2351        const unichar ch = 0x2713; // ✓ used on Mac for selected menu items.
2352        return (m_object->isChecked()) ? [NSString stringWithCharacters:&ch length:1] : nil;
2353    }
2354
2355    if ([attributeName isEqualToString: NSAccessibilityMinValueAttribute])
2356        return [NSNumber numberWithFloat:m_object->minValueForRange()];
2357
2358    if ([attributeName isEqualToString: NSAccessibilityMaxValueAttribute])
2359        return [NSNumber numberWithFloat:m_object->maxValueForRange()];
2360
2361    if ([attributeName isEqualToString: NSAccessibilityHelpAttribute])
2362        return [self accessibilityHelpText];
2363
2364    if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute])
2365        return [NSNumber numberWithBool: m_object->isFocused()];
2366
2367    if ([attributeName isEqualToString: NSAccessibilityEnabledAttribute])
2368        return [NSNumber numberWithBool: m_object->isEnabled()];
2369
2370    if ([attributeName isEqualToString: NSAccessibilitySizeAttribute]) {
2371        IntSize s = m_object->pixelSnappedSize();
2372        return [NSValue valueWithSize: NSMakeSize(s.width(), s.height())];
2373    }
2374
2375    if ([attributeName isEqualToString: NSAccessibilityPositionAttribute])
2376        return [self position];
2377    if ([attributeName isEqualToString:NSAccessibilityPathAttribute])
2378        return [self path];
2379
2380    if ([attributeName isEqualToString: NSAccessibilityWindowAttribute] ||
2381        [attributeName isEqualToString: NSAccessibilityTopLevelUIElementAttribute]) {
2382
2383        id remoteParent = [self remoteAccessibilityParentObject];
2384        if (remoteParent)
2385            return [remoteParent accessibilityAttributeValue:attributeName];
2386
2387        FrameView* fv = m_object->documentFrameView();
2388        if (fv)
2389            return [fv->platformWidget() window];
2390        return nil;
2391    }
2392
2393    if ([attributeName isEqualToString:NSAccessibilityAccessKeyAttribute]) {
2394        AtomicString accessKey = m_object->accessKey();
2395        if (accessKey.isNull())
2396            return nil;
2397        return accessKey;
2398    }
2399
2400    if ([attributeName isEqualToString:NSAccessibilityTabsAttribute]) {
2401        if (m_object->isTabList()) {
2402            AccessibilityObject::AccessibilityChildrenVector tabsChildren;
2403            m_object->tabChildren(tabsChildren);
2404            return convertToNSArray(tabsChildren);
2405        }
2406    }
2407
2408    if ([attributeName isEqualToString:NSAccessibilityContentsAttribute]) {
2409        // The contents of a tab list are all the children except the tabs.
2410        if (m_object->isTabList()) {
2411            AccessibilityObject::AccessibilityChildrenVector children = m_object->children();
2412            AccessibilityObject::AccessibilityChildrenVector tabsChildren;
2413            m_object->tabChildren(tabsChildren);
2414
2415            AccessibilityObject::AccessibilityChildrenVector contents;
2416            unsigned childrenSize = children.size();
2417            for (unsigned k = 0; k < childrenSize; ++k) {
2418                if (tabsChildren.find(children[k]) == WTF::notFound)
2419                    contents.append(children[k]);
2420            }
2421            return convertToNSArray(contents);
2422        } else if (m_object->isScrollView()) {
2423            AccessibilityObject::AccessibilityChildrenVector children = m_object->children();
2424
2425            // A scrollView's contents are everything except the scroll bars.
2426            AccessibilityObject::AccessibilityChildrenVector contents;
2427            unsigned childrenSize = children.size();
2428            for (unsigned k = 0; k < childrenSize; ++k) {
2429                if (!children[k]->isScrollbar())
2430                    contents.append(children[k]);
2431            }
2432            return convertToNSArray(contents);
2433        }
2434    }
2435
2436    if (m_object->isAccessibilityTable()) {
2437        // TODO: distinguish between visible and non-visible rows
2438        if ([attributeName isEqualToString:NSAccessibilityRowsAttribute] ||
2439            [attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute]) {
2440            return convertToNSArray(static_cast<AccessibilityTable*>(m_object)->rows());
2441        }
2442        // TODO: distinguish between visible and non-visible columns
2443        if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute] ||
2444            [attributeName isEqualToString:NSAccessibilityVisibleColumnsAttribute]) {
2445            return convertToNSArray(static_cast<AccessibilityTable*>(m_object)->columns());
2446        }
2447
2448        if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
2449            AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
2450            m_object->selectedChildren(selectedChildrenCopy);
2451            return convertToNSArray(selectedChildrenCopy);
2452        }
2453
2454        // HTML tables don't support these
2455        if ([attributeName isEqualToString:NSAccessibilitySelectedColumnsAttribute] ||
2456            [attributeName isEqualToString:NSAccessibilitySelectedCellsAttribute])
2457            return nil;
2458
2459        if ([attributeName isEqualToString:(NSString *)kAXColumnHeaderUIElementsAttribute]) {
2460            AccessibilityObject::AccessibilityChildrenVector columnHeaders;
2461            static_cast<AccessibilityTable*>(m_object)->columnHeaders(columnHeaders);
2462            return convertToNSArray(columnHeaders);
2463        }
2464
2465        if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) {
2466            AccessibilityObject* headerContainer = static_cast<AccessibilityTable*>(m_object)->headerContainer();
2467            if (headerContainer)
2468                return headerContainer->wrapper();
2469            return nil;
2470        }
2471
2472        if ([attributeName isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute]) {
2473            AccessibilityObject::AccessibilityChildrenVector rowHeaders;
2474            static_cast<AccessibilityTable*>(m_object)->rowHeaders(rowHeaders);
2475            return convertToNSArray(rowHeaders);
2476        }
2477
2478        if ([attributeName isEqualToString:NSAccessibilityVisibleCellsAttribute]) {
2479            AccessibilityObject::AccessibilityChildrenVector cells;
2480            static_cast<AccessibilityTable*>(m_object)->cells(cells);
2481            return convertToNSArray(cells);
2482        }
2483    }
2484
2485    if (m_object->isTableColumn()) {
2486        if ([attributeName isEqualToString:NSAccessibilityIndexAttribute])
2487            return [NSNumber numberWithInt:static_cast<AccessibilityTableColumn*>(m_object)->columnIndex()];
2488
2489        // rows attribute for a column is the list of all the elements in that column at each row
2490        if ([attributeName isEqualToString:NSAccessibilityRowsAttribute] ||
2491            [attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute]) {
2492            return convertToNSArray(static_cast<AccessibilityTableColumn*>(m_object)->children());
2493        }
2494        if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) {
2495            AccessibilityObject* header = static_cast<AccessibilityTableColumn*>(m_object)->headerObject();
2496            if (!header)
2497                return nil;
2498            return header->wrapper();
2499        }
2500    }
2501
2502    if (m_object->isTableCell()) {
2503        if ([attributeName isEqualToString:NSAccessibilityRowIndexRangeAttribute]) {
2504            pair<unsigned, unsigned> rowRange;
2505            static_cast<AccessibilityTableCell*>(m_object)->rowIndexRange(rowRange);
2506            return [NSValue valueWithRange:NSMakeRange(rowRange.first, rowRange.second)];
2507        }
2508        if ([attributeName isEqualToString:NSAccessibilityColumnIndexRangeAttribute]) {
2509            pair<unsigned, unsigned> columnRange;
2510            static_cast<AccessibilityTableCell*>(m_object)->columnIndexRange(columnRange);
2511            return [NSValue valueWithRange:NSMakeRange(columnRange.first, columnRange.second)];
2512        }
2513    }
2514
2515    if (m_object->isTree()) {
2516        if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
2517            AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
2518            m_object->selectedChildren(selectedChildrenCopy);
2519            return convertToNSArray(selectedChildrenCopy);
2520        }
2521        if ([attributeName isEqualToString:NSAccessibilityRowsAttribute]) {
2522            AccessibilityObject::AccessibilityChildrenVector rowsCopy;
2523            m_object->ariaTreeRows(rowsCopy);
2524            return convertToNSArray(rowsCopy);
2525        }
2526
2527        // TreeRoles do not support columns, but Mac AX expects to be able to ask about columns at the least.
2528        if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute])
2529            return [NSArray array];
2530    }
2531
2532    if ([attributeName isEqualToString:NSAccessibilityIndexAttribute]) {
2533        if (m_object->isTreeItem()) {
2534            AccessibilityObject* parent = m_object->parentObject();
2535            for (; parent && !parent->isTree(); parent = parent->parentObject())
2536            { }
2537
2538            if (!parent)
2539                return nil;
2540
2541            // Find the index of this item by iterating the parents.
2542            AccessibilityObject::AccessibilityChildrenVector rowsCopy;
2543            parent->ariaTreeRows(rowsCopy);
2544            size_t count = rowsCopy.size();
2545            for (size_t k = 0; k < count; ++k)
2546                if (rowsCopy[k]->wrapper() == self)
2547                    return [NSNumber numberWithUnsignedInt:k];
2548
2549            return nil;
2550        }
2551        if (m_object->isTableRow()) {
2552            if ([attributeName isEqualToString:NSAccessibilityIndexAttribute])
2553                return [NSNumber numberWithInt:static_cast<AccessibilityTableRow*>(m_object)->rowIndex()];
2554        }
2555    }
2556
2557    // The rows that are considered inside this row.
2558    if ([attributeName isEqualToString:NSAccessibilityDisclosedRowsAttribute]) {
2559        if (m_object->isTreeItem()) {
2560            AccessibilityObject::AccessibilityChildrenVector rowsCopy;
2561            m_object->ariaTreeItemDisclosedRows(rowsCopy);
2562            return convertToNSArray(rowsCopy);
2563        } else if (m_object->isARIATreeGridRow()) {
2564            AccessibilityObject::AccessibilityChildrenVector rowsCopy;
2565            static_cast<AccessibilityARIAGridRow*>(m_object)->disclosedRows(rowsCopy);
2566            return convertToNSArray(rowsCopy);
2567        }
2568    }
2569
2570    // The row that contains this row. It should be the same as the first parent that is a treeitem.
2571    if ([attributeName isEqualToString:NSAccessibilityDisclosedByRowAttribute]) {
2572        if (m_object->isTreeItem()) {
2573            AccessibilityObject* parent = m_object->parentObject();
2574            while (parent) {
2575                if (parent->isTreeItem())
2576                    return parent->wrapper();
2577                // If the parent is the tree itself, then this value == nil.
2578                if (parent->isTree())
2579                    return nil;
2580                parent = parent->parentObject();
2581            }
2582            return nil;
2583        } else if (m_object->isARIATreeGridRow()) {
2584            AccessibilityObject* row = static_cast<AccessibilityARIAGridRow*>(m_object)->disclosedByRow();
2585            if (!row)
2586                return nil;
2587            return row->wrapper();
2588        }
2589    }
2590
2591    if ([attributeName isEqualToString:NSAccessibilityDisclosureLevelAttribute]) {
2592        // Convert from 1-based level (from aria-level spec) to 0-based level (Mac)
2593        int level = m_object->hierarchicalLevel();
2594        if (level > 0)
2595            level -= 1;
2596        return [NSNumber numberWithInt:level];
2597    }
2598    if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute])
2599        return [NSNumber numberWithBool:m_object->isExpanded()];
2600
2601    if ((m_object->isListBox() || m_object->isList()) && [attributeName isEqualToString:NSAccessibilityOrientationAttribute])
2602        return NSAccessibilityVerticalOrientationValue;
2603
2604    if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"])
2605        return [self textMarkerRangeForSelection];
2606
2607    if (m_object->renderer()) {
2608        if ([attributeName isEqualToString: @"AXStartTextMarker"])
2609            return [self textMarkerForVisiblePosition:startOfDocument(m_object->renderer()->document())];
2610        if ([attributeName isEqualToString: @"AXEndTextMarker"])
2611            return [self textMarkerForVisiblePosition:endOfDocument(m_object->renderer()->document())];
2612    }
2613
2614    if ([attributeName isEqualToString:NSAccessibilityBlockQuoteLevelAttribute])
2615        return [NSNumber numberWithInt:m_object->blockquoteLevel()];
2616    if ([attributeName isEqualToString:@"AXTableLevel"])
2617        return [NSNumber numberWithInt:m_object->tableLevel()];
2618
2619    if ([attributeName isEqualToString: NSAccessibilityLinkedUIElementsAttribute]) {
2620        AccessibilityObject::AccessibilityChildrenVector linkedUIElements;
2621        m_object->linkedUIElements(linkedUIElements);
2622        if (linkedUIElements.size() == 0)
2623            return nil;
2624        return convertToNSArray(linkedUIElements);
2625    }
2626
2627    if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute])
2628        return [NSNumber numberWithBool:m_object->isSelected()];
2629
2630    if ([attributeName isEqualToString: NSAccessibilityServesAsTitleForUIElementsAttribute] && m_object->isMenuButton()) {
2631        AccessibilityObject* uiElement = static_cast<AccessibilityRenderObject*>(m_object)->menuForMenuButton();
2632        if (uiElement)
2633            return [NSArray arrayWithObject:uiElement->wrapper()];
2634    }
2635
2636    if ([attributeName isEqualToString:NSAccessibilityTitleUIElementAttribute]) {
2637        if (!m_object->exposesTitleUIElement())
2638            return nil;
2639
2640        AccessibilityObject* obj = m_object->titleUIElement();
2641        if (obj)
2642            return obj->wrapper();
2643        return nil;
2644    }
2645
2646    if ([attributeName isEqualToString:NSAccessibilityValueDescriptionAttribute])
2647        return m_object->valueDescription();
2648
2649    if ([attributeName isEqualToString:NSAccessibilityOrientationAttribute]) {
2650        AccessibilityOrientation elementOrientation = m_object->orientation();
2651        if (elementOrientation == AccessibilityOrientationVertical)
2652            return NSAccessibilityVerticalOrientationValue;
2653        if (elementOrientation == AccessibilityOrientationHorizontal)
2654            return NSAccessibilityHorizontalOrientationValue;
2655        return nil;
2656    }
2657
2658    if ([attributeName isEqualToString:NSAccessibilityHorizontalScrollBarAttribute]) {
2659        AccessibilityObject* scrollBar = m_object->scrollBar(AccessibilityOrientationHorizontal);
2660        if (scrollBar)
2661            return scrollBar->wrapper();
2662        return nil;
2663    }
2664    if ([attributeName isEqualToString:NSAccessibilityVerticalScrollBarAttribute]) {
2665        AccessibilityObject* scrollBar = m_object->scrollBar(AccessibilityOrientationVertical);
2666        if (scrollBar)
2667            return scrollBar->wrapper();
2668        return nil;
2669    }
2670
2671    if ([attributeName isEqualToString:NSAccessibilitySortDirectionAttribute]) {
2672        switch (m_object->sortDirection()) {
2673            case SortDirectionAscending:
2674                return NSAccessibilityAscendingSortDirectionValue;
2675            case SortDirectionDescending:
2676                return NSAccessibilityDescendingSortDirectionValue;
2677            default:
2678                return NSAccessibilityUnknownSortDirectionValue;
2679        }
2680    }
2681
2682    if ([attributeName isEqualToString:NSAccessibilityLanguageAttribute])
2683        return m_object->language();
2684
2685    if ([attributeName isEqualToString:NSAccessibilityExpandedAttribute])
2686        return [NSNumber numberWithBool:m_object->isExpanded()];
2687
2688    if ([attributeName isEqualToString:NSAccessibilityRequiredAttribute])
2689        return [NSNumber numberWithBool:m_object->isRequired()];
2690
2691    if ([attributeName isEqualToString:NSAccessibilityInvalidAttribute])
2692        return m_object->invalidStatus();
2693
2694    if ([attributeName isEqualToString:NSAccessibilityOwnsAttribute]) {
2695        AccessibilityObject::AccessibilityChildrenVector ariaOwns;
2696        m_object->ariaOwnsElements(ariaOwns);
2697        return convertToNSArray(ariaOwns);
2698    }
2699
2700    if ([attributeName isEqualToString:NSAccessibilityARIAPosInSetAttribute])
2701        return [NSNumber numberWithInt:m_object->ariaPosInSet()];
2702    if ([attributeName isEqualToString:NSAccessibilityARIASetSizeAttribute])
2703        return [NSNumber numberWithInt:m_object->ariaSetSize()];
2704
2705    if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute])
2706        return [NSNumber numberWithBool:m_object->isARIAGrabbed()];
2707
2708    if ([attributeName isEqualToString:NSAccessibilityDropEffectsAttribute]) {
2709        Vector<String> dropEffects;
2710        m_object->determineARIADropEffects(dropEffects);
2711        size_t length = dropEffects.size();
2712
2713        NSMutableArray* dropEffectsArray = [NSMutableArray arrayWithCapacity:length];
2714        for (size_t i = 0; i < length; ++i)
2715            [dropEffectsArray addObject:dropEffects[i]];
2716        return dropEffectsArray;
2717    }
2718
2719    if ([attributeName isEqualToString:NSAccessibilityPlaceholderValueAttribute])
2720        return m_object->placeholderValue();
2721
2722    if ([attributeName isEqualToString:NSAccessibilityHasPopupAttribute])
2723        return [NSNumber numberWithBool:m_object->ariaHasPopup()];
2724
2725    // ARIA Live region attributes.
2726    if ([attributeName isEqualToString:NSAccessibilityARIALiveAttribute])
2727        return m_object->ariaLiveRegionStatus();
2728    if ([attributeName isEqualToString:NSAccessibilityARIARelevantAttribute])
2729        return m_object->ariaLiveRegionRelevant();
2730    if ([attributeName isEqualToString:NSAccessibilityARIAAtomicAttribute])
2731        return [NSNumber numberWithBool:m_object->ariaLiveRegionAtomic()];
2732    if ([attributeName isEqualToString:NSAccessibilityARIABusyAttribute])
2733        return [NSNumber numberWithBool:m_object->ariaLiveRegionBusy()];
2734
2735    // MathML Attributes.
2736    if (m_object->isMathElement()) {
2737        if ([attributeName isEqualToString:NSAccessibilityMathRootIndexAttribute])
2738            return (m_object->mathRootIndexObject()) ? m_object->mathRootIndexObject()->wrapper() : 0;
2739        if ([attributeName isEqualToString:NSAccessibilityMathRootRadicandAttribute])
2740            return (m_object->mathRadicandObject()) ? m_object->mathRadicandObject()->wrapper() : 0;
2741        if ([attributeName isEqualToString:NSAccessibilityMathFractionNumeratorAttribute])
2742            return (m_object->mathNumeratorObject()) ? m_object->mathNumeratorObject()->wrapper() : 0;
2743        if ([attributeName isEqualToString:NSAccessibilityMathFractionDenominatorAttribute])
2744            return (m_object->mathDenominatorObject()) ? m_object->mathDenominatorObject()->wrapper() : 0;
2745        if ([attributeName isEqualToString:NSAccessibilityMathBaseAttribute])
2746            return (m_object->mathBaseObject()) ? m_object->mathBaseObject()->wrapper() : 0;
2747        if ([attributeName isEqualToString:NSAccessibilityMathSubscriptAttribute])
2748            return (m_object->mathSubscriptObject()) ? m_object->mathSubscriptObject()->wrapper() : 0;
2749        if ([attributeName isEqualToString:NSAccessibilityMathSuperscriptAttribute])
2750            return (m_object->mathSuperscriptObject()) ? m_object->mathSuperscriptObject()->wrapper() : 0;
2751        if ([attributeName isEqualToString:NSAccessibilityMathUnderAttribute])
2752            return (m_object->mathUnderObject()) ? m_object->mathUnderObject()->wrapper() : 0;
2753        if ([attributeName isEqualToString:NSAccessibilityMathOverAttribute])
2754            return (m_object->mathOverObject()) ? m_object->mathOverObject()->wrapper() : 0;
2755        if ([attributeName isEqualToString:NSAccessibilityMathFencedOpenAttribute])
2756            return m_object->mathFencedOpenString();
2757        if ([attributeName isEqualToString:NSAccessibilityMathFencedCloseAttribute])
2758            return m_object->mathFencedCloseString();
2759        if ([attributeName isEqualToString:NSAccessibilityMathLineThicknessAttribute])
2760            return [NSNumber numberWithInteger:m_object->mathLineThickness()];
2761        if ([attributeName isEqualToString:NSAccessibilityMathPostscriptsAttribute])
2762            return [self accessibilityMathPostscriptPairs];
2763        if ([attributeName isEqualToString:NSAccessibilityMathPrescriptsAttribute])
2764            return [self accessibilityMathPrescriptPairs];
2765    }
2766
2767    // this is used only by DumpRenderTree for testing
2768    if ([attributeName isEqualToString:@"AXClickPoint"])
2769        return [NSValue valueWithPoint:m_object->clickPoint()];
2770
2771    // This is used by DRT to verify CSS3 speech works.
2772    if ([attributeName isEqualToString:@"AXDRTSpeechAttribute"]) {
2773        ESpeak speakProperty = m_object->speakProperty();
2774        switch (speakProperty) {
2775            case SpeakNone:
2776                return @"none";
2777            case SpeakSpellOut:
2778                return @"spell-out";
2779            case SpeakDigits:
2780                return @"digits";
2781            case SpeakLiteralPunctuation:
2782                return @"literal-punctuation";
2783            case SpeakNoPunctuation:
2784                return @"no-punctuation";
2785            default:
2786            case SpeakNormal:
2787                return @"normal";
2788        }
2789    }
2790
2791    // Used by DRT to find an accessible node by its element id.
2792    if ([attributeName isEqualToString:@"AXDRTElementIdAttribute"])
2793        return m_object->getAttribute(idAttr);
2794
2795    return nil;
2796}
2797
2798- (NSString *)accessibilityPlatformMathSubscriptKey
2799{
2800    return NSAccessibilityMathSubscriptAttribute;
2801}
2802
2803- (NSString *)accessibilityPlatformMathSuperscriptKey
2804{
2805    return NSAccessibilityMathSuperscriptAttribute;
2806}
2807
2808- (id)accessibilityFocusedUIElement
2809{
2810    if (![self updateObjectBackingStore])
2811        return nil;
2812
2813    RefPtr<AccessibilityObject> focusedObj = m_object->focusedUIElement();
2814
2815    if (!focusedObj)
2816        return nil;
2817
2818    return focusedObj->wrapper();
2819}
2820
2821- (id)accessibilityHitTest:(NSPoint)point
2822{
2823    if (![self updateObjectBackingStore])
2824        return nil;
2825
2826    m_object->updateChildrenIfNecessary();
2827    RefPtr<AccessibilityObject> axObject = m_object->accessibilityHitTest(IntPoint(point));
2828    if (axObject)
2829        return NSAccessibilityUnignoredAncestor(axObject->wrapper());
2830    return NSAccessibilityUnignoredAncestor(self);
2831}
2832
2833- (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName
2834{
2835    if (![self updateObjectBackingStore])
2836        return nil;
2837
2838    if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"])
2839        return YES;
2840
2841    if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute])
2842        return m_object->canSetFocusAttribute();
2843
2844    if ([attributeName isEqualToString: NSAccessibilityValueAttribute])
2845        return m_object->canSetValueAttribute();
2846
2847    if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute])
2848        return m_object->canSetSelectedAttribute();
2849
2850    if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute])
2851        return m_object->canSetSelectedChildrenAttribute();
2852
2853    if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute])
2854        return m_object->canSetExpandedAttribute();
2855
2856    if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute])
2857        return YES;
2858
2859    if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute] ||
2860        [attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute] ||
2861        [attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
2862        return m_object->canSetTextRangeAttributes();
2863
2864    if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute])
2865        return YES;
2866
2867    return NO;
2868}
2869
2870// accessibilityShouldUseUniqueId is an AppKit method we override so that
2871// objects will be given a unique ID, and therefore allow AppKit to know when they
2872// become obsolete (e.g. when the user navigates to a new web page, making this one
2873// unrendered but not deallocated because it is in the back/forward cache).
2874// It is important to call NSAccessibilityUnregisterUniqueIdForUIElement in the
2875// appropriate place (e.g. dealloc) to remove these non-retained references from
2876// AppKit's id mapping tables. We do this in detach by calling unregisterUniqueIdForUIElement.
2877//
2878// Registering an object is also required for observing notifications. Only registered objects can be observed.
2879- (BOOL)accessibilityIsIgnored
2880{
2881    if (![self updateObjectBackingStore])
2882        return YES;
2883
2884    if (m_object->isAttachment())
2885        return [[self attachmentView] accessibilityIsIgnored];
2886    return m_object->accessibilityIsIgnored();
2887}
2888
2889- (NSArray* )accessibilityParameterizedAttributeNames
2890{
2891    if (![self updateObjectBackingStore])
2892        return nil;
2893
2894    if (m_object->isAttachment())
2895        return nil;
2896
2897    static NSArray* paramAttrs = nil;
2898    static NSArray* textParamAttrs = nil;
2899    static NSArray* tableParamAttrs = nil;
2900    static NSArray* webAreaParamAttrs = nil;
2901    if (paramAttrs == nil) {
2902        paramAttrs = [[NSArray alloc] initWithObjects:
2903                      @"AXUIElementForTextMarker",
2904                      @"AXTextMarkerRangeForUIElement",
2905                      @"AXLineForTextMarker",
2906                      @"AXTextMarkerRangeForLine",
2907                      @"AXStringForTextMarkerRange",
2908                      @"AXTextMarkerForPosition",
2909                      @"AXBoundsForTextMarkerRange",
2910                      @"AXAttributedStringForTextMarkerRange",
2911                      @"AXTextMarkerRangeForUnorderedTextMarkers",
2912                      @"AXNextTextMarkerForTextMarker",
2913                      @"AXPreviousTextMarkerForTextMarker",
2914                      @"AXLeftWordTextMarkerRangeForTextMarker",
2915                      @"AXRightWordTextMarkerRangeForTextMarker",
2916                      @"AXLeftLineTextMarkerRangeForTextMarker",
2917                      @"AXRightLineTextMarkerRangeForTextMarker",
2918                      @"AXSentenceTextMarkerRangeForTextMarker",
2919                      @"AXParagraphTextMarkerRangeForTextMarker",
2920                      @"AXNextWordEndTextMarkerForTextMarker",
2921                      @"AXPreviousWordStartTextMarkerForTextMarker",
2922                      @"AXNextLineEndTextMarkerForTextMarker",
2923                      @"AXPreviousLineStartTextMarkerForTextMarker",
2924                      @"AXNextSentenceEndTextMarkerForTextMarker",
2925                      @"AXPreviousSentenceStartTextMarkerForTextMarker",
2926                      @"AXNextParagraphEndTextMarkerForTextMarker",
2927                      @"AXPreviousParagraphStartTextMarkerForTextMarker",
2928                      @"AXStyleTextMarkerRangeForTextMarker",
2929                      @"AXLengthForTextMarkerRange",
2930                      NSAccessibilityBoundsForRangeParameterizedAttribute,
2931                      NSAccessibilityStringForRangeParameterizedAttribute,
2932                      NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute,
2933                      NSAccessibilityEndTextMarkerForBoundsParameterizedAttribute,
2934                      NSAccessibilityStartTextMarkerForBoundsParameterizedAttribute,
2935                      nil];
2936    }
2937
2938    if (textParamAttrs == nil) {
2939        NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs];
2940        [tempArray addObject:(NSString*)kAXLineForIndexParameterizedAttribute];
2941        [tempArray addObject:(NSString*)kAXRangeForLineParameterizedAttribute];
2942        [tempArray addObject:(NSString*)kAXStringForRangeParameterizedAttribute];
2943        [tempArray addObject:(NSString*)kAXRangeForPositionParameterizedAttribute];
2944        [tempArray addObject:(NSString*)kAXRangeForIndexParameterizedAttribute];
2945        [tempArray addObject:(NSString*)kAXBoundsForRangeParameterizedAttribute];
2946        [tempArray addObject:(NSString*)kAXRTFForRangeParameterizedAttribute];
2947        [tempArray addObject:(NSString*)kAXAttributedStringForRangeParameterizedAttribute];
2948        [tempArray addObject:(NSString*)kAXStyleRangeForIndexParameterizedAttribute];
2949        textParamAttrs = [[NSArray alloc] initWithArray:tempArray];
2950        [tempArray release];
2951    }
2952    if (tableParamAttrs == nil) {
2953        NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs];
2954        [tempArray addObject:NSAccessibilityCellForColumnAndRowParameterizedAttribute];
2955        tableParamAttrs = [[NSArray alloc] initWithArray:tempArray];
2956        [tempArray release];
2957    }
2958    if (!webAreaParamAttrs) {
2959        NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs];
2960        [tempArray addObject:NSAccessibilityTextMarkerForIndexParameterizedAttribute];
2961        [tempArray addObject:NSAccessibilityTextMarkerIsValidParameterizedAttribute];
2962        [tempArray addObject:NSAccessibilityIndexForTextMarkerParameterizedAttribute];
2963        webAreaParamAttrs = [[NSArray alloc] initWithArray:tempArray];
2964        [tempArray release];
2965    }
2966
2967    if (m_object->isPasswordField())
2968        return [NSArray array];
2969
2970    if (!m_object->isAccessibilityRenderObject())
2971        return paramAttrs;
2972
2973    if (m_object->isTextControl())
2974        return textParamAttrs;
2975
2976    if (m_object->isAccessibilityTable())
2977        return tableParamAttrs;
2978
2979    if (m_object->isMenuRelated())
2980        return nil;
2981
2982    if (m_object->isWebArea())
2983        return webAreaParamAttrs;
2984
2985    return paramAttrs;
2986}
2987
2988- (void)accessibilityPerformPressAction
2989{
2990    if (![self updateObjectBackingStore])
2991        return;
2992
2993    if (m_object->isAttachment())
2994        [[self attachmentView] accessibilityPerformAction:NSAccessibilityPressAction];
2995    else
2996        m_object->press();
2997}
2998
2999- (void)accessibilityPerformIncrementAction
3000{
3001    if (![self updateObjectBackingStore])
3002        return;
3003
3004    if (m_object->isAttachment())
3005        [[self attachmentView] accessibilityPerformAction:NSAccessibilityIncrementAction];
3006    else
3007        m_object->increment();
3008}
3009
3010- (void)accessibilityPerformDecrementAction
3011{
3012    if (![self updateObjectBackingStore])
3013        return;
3014
3015    if (m_object->isAttachment())
3016        [[self attachmentView] accessibilityPerformAction:NSAccessibilityDecrementAction];
3017    else
3018        m_object->decrement();
3019}
3020
3021- (void)accessibilityPerformShowMenuAction
3022{
3023    if (m_object->roleValue() == ComboBoxRole)
3024        m_object->setIsExpanded(true);
3025    else {
3026        // This needs to be performed in an iteration of the run loop that did not start from an AX call.
3027        // If it's the same run loop iteration, the menu open notification won't be sent
3028        [self performSelector:@selector(accessibilityShowContextMenu) withObject:nil afterDelay:0.0];
3029    }
3030}
3031
3032- (void)accessibilityShowContextMenu
3033{
3034    Page* page = m_object->page();
3035    if (!page)
3036        return;
3037
3038    IntRect rect = pixelSnappedIntRect(m_object->elementRect());
3039    FrameView* frameView = m_object->documentFrameView();
3040
3041    // On WK2, we need to account for the scroll position.
3042    // On WK1, this isn't necessary, it's taken care of by the attachment views.
3043    if (frameView && !frameView->platformWidget()) {
3044        // Find the appropriate scroll view to use to convert the contents to the window.
3045        for (AccessibilityObject* parent = m_object->parentObject(); parent; parent = parent->parentObject()) {
3046            if (parent->isAccessibilityScrollView()) {
3047                ScrollView* scrollView = toAccessibilityScrollView(parent)->scrollView();
3048                rect = scrollView->contentsToRootView(rect);
3049                break;
3050            }
3051        }
3052    }
3053
3054    page->contextMenuController()->showContextMenuAt(page->mainFrame(), rect.center());
3055}
3056
3057- (void)accessibilityScrollToVisible
3058{
3059    m_object->scrollToMakeVisible();
3060}
3061
3062- (void)accessibilityPerformAction:(NSString*)action
3063{
3064    if (![self updateObjectBackingStore])
3065        return;
3066
3067    if ([action isEqualToString:NSAccessibilityPressAction])
3068        [self accessibilityPerformPressAction];
3069
3070    else if ([action isEqualToString:NSAccessibilityShowMenuAction])
3071        [self accessibilityPerformShowMenuAction];
3072
3073    else if ([action isEqualToString:NSAccessibilityIncrementAction])
3074        [self accessibilityPerformIncrementAction];
3075
3076    else if ([action isEqualToString:NSAccessibilityDecrementAction])
3077        [self accessibilityPerformDecrementAction];
3078
3079    else if ([action isEqualToString:NSAccessibilityScrollToVisibleAction])
3080        [self accessibilityScrollToVisible];
3081}
3082
3083- (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attributeName
3084{
3085    if (![self updateObjectBackingStore])
3086        return;
3087
3088    id textMarkerRange = nil;
3089    NSNumber*               number = nil;
3090    NSString*               string = nil;
3091    NSRange                 range = {0, 0};
3092    NSArray*                array = nil;
3093
3094    // decode the parameter
3095    if (AXObjectIsTextMarkerRange(value))
3096        textMarkerRange = value;
3097
3098    else if ([value isKindOfClass:[NSNumber self]])
3099        number = value;
3100
3101    else if ([value isKindOfClass:[NSString self]])
3102        string = value;
3103
3104    else if ([value isKindOfClass:[NSValue self]])
3105        range = [value rangeValue];
3106
3107    else if ([value isKindOfClass:[NSArray self]])
3108        array = value;
3109
3110    // handle the command
3111    if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"]) {
3112        ASSERT(textMarkerRange);
3113        m_object->setSelectedVisiblePositionRange([self visiblePositionRangeForTextMarkerRange:textMarkerRange]);
3114    } else if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute]) {
3115        ASSERT(number);
3116
3117        bool focus = [number boolValue];
3118
3119        // If focus is just set without making the view the first responder, then keyboard focus won't move to the right place.
3120        if (focus && m_object->isWebArea() && !m_object->document()->frame()->selection()->isFocusedAndActive()) {
3121            FrameView* frameView = m_object->documentFrameView();
3122            Page* page = m_object->page();
3123            if (page && frameView) {
3124                ChromeClient* client = page->chrome().client();
3125                client->focus();
3126                if (frameView->platformWidget())
3127                    client->makeFirstResponder(frameView->platformWidget());
3128                else
3129                    client->makeFirstResponder();
3130            }
3131        }
3132
3133        m_object->setFocused(focus);
3134    } else if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) {
3135        if (number && m_object->canSetNumericValue())
3136            m_object->setValue([number floatValue]);
3137        else if (string)
3138            m_object->setValue(string);
3139    } else if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute]) {
3140        if (!number)
3141            return;
3142        m_object->setSelected([number boolValue]);
3143    } else if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) {
3144        if (!array || m_object->roleValue() != ListBoxRole)
3145            return;
3146        AccessibilityObject::AccessibilityChildrenVector selectedChildren;
3147        convertToVector(array, selectedChildren);
3148        static_cast<AccessibilityListBox*>(m_object)->setSelectedChildren(selectedChildren);
3149    } else if (m_object->isTextControl()) {
3150        if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) {
3151            m_object->setSelectedText(string);
3152        } else if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) {
3153            m_object->setSelectedTextRange(PlainTextRange(range.location, range.length));
3154        } else if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute]) {
3155            m_object->makeRangeVisible(PlainTextRange(range.location, range.length));
3156        }
3157    } else if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute])
3158        m_object->setIsExpanded([number boolValue]);
3159    else if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
3160        AccessibilityObject::AccessibilityChildrenVector selectedRows;
3161        convertToVector(array, selectedRows);
3162        if (m_object->isTree() || m_object->isAccessibilityTable())
3163            m_object->setSelectedRows(selectedRows);
3164    } else if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute])
3165        m_object->setARIAGrabbed([number boolValue]);
3166}
3167
3168static RenderObject* rendererForView(NSView* view)
3169{
3170    if (![view conformsToProtocol:@protocol(WebCoreFrameView)])
3171        return 0;
3172
3173    NSView<WebCoreFrameView>* frameView = (NSView<WebCoreFrameView>*)view;
3174    Frame* frame = [frameView _web_frame];
3175    if (!frame)
3176        return 0;
3177
3178    Node* node = frame->document()->ownerElement();
3179    if (!node)
3180        return 0;
3181
3182    return node->renderer();
3183}
3184
3185- (id)_accessibilityParentForSubview:(NSView*)subview
3186{
3187    RenderObject* renderer = rendererForView(subview);
3188    if (!renderer)
3189        return nil;
3190
3191    AccessibilityObject* obj = renderer->document()->axObjectCache()->getOrCreate(renderer);
3192    if (obj)
3193        return obj->parentObjectUnignored()->wrapper();
3194    return nil;
3195}
3196
3197- (NSString*)accessibilityActionDescription:(NSString*)action
3198{
3199    // we have no custom actions
3200    return NSAccessibilityActionDescription(action);
3201}
3202
3203// The CFAttributedStringType representation of the text associated with this accessibility
3204// object that is specified by the given range.
3205- (NSAttributedString*)doAXAttributedStringForRange:(NSRange)range
3206{
3207    PlainTextRange textRange = PlainTextRange(range.location, range.length);
3208    VisiblePositionRange visiblePosRange = m_object->visiblePositionRangeForRange(textRange);
3209    return [self doAXAttributedStringForTextMarkerRange:[self textMarkerRangeFromVisiblePositions:visiblePosRange.start endPosition:visiblePosRange.end]];
3210}
3211
3212- (NSRange)_convertToNSRange:(Range*)range
3213{
3214    NSRange result = NSMakeRange(NSNotFound, 0);
3215    if (!range || !range->startContainer())
3216        return result;
3217
3218    Document* document = m_object->document();
3219    if (!document)
3220        return result;
3221
3222    size_t location;
3223    size_t length;
3224    TextIterator::getLocationAndLengthFromRange(document->documentElement(), range, location, length);
3225    result.location = location;
3226    result.length = length;
3227
3228    return result;
3229}
3230
3231- (NSInteger)_indexForTextMarker:(id)marker
3232{
3233    if (!marker)
3234        return NSNotFound;
3235
3236    VisibleSelection selection([self visiblePositionForTextMarker:marker]);
3237    return [self _convertToNSRange:selection.toNormalizedRange().get()].location;
3238}
3239
3240- (id)_textMarkerForIndex:(NSInteger)textIndex
3241{
3242    Document* document = m_object->document();
3243    if (!document)
3244        return nil;
3245
3246    PassRefPtr<Range> textRange = TextIterator::rangeFromLocationAndLength(document->documentElement(), textIndex, 0);
3247    if (!textRange || !textRange->boundaryPointsValid())
3248        return nil;
3249
3250    VisiblePosition position(textRange->startPosition());
3251    return [self textMarkerForVisiblePosition:position];
3252}
3253
3254// The RTF representation of the text associated with this accessibility object that is
3255// specified by the given range.
3256- (NSData*)doAXRTFForRange:(NSRange)range
3257{
3258    NSAttributedString* attrString = [self doAXAttributedStringForRange:range];
3259    return [attrString RTFFromRange: NSMakeRange(0, [attrString length]) documentAttributes: nil];
3260}
3261
3262- (id)accessibilityAttributeValue:(NSString*)attribute forParameter:(id)parameter
3263{
3264    id textMarker = nil;
3265    id textMarkerRange = nil;
3266    NSNumber* number = nil;
3267    NSArray* array = nil;
3268    NSDictionary* dictionary = nil;
3269    RefPtr<AccessibilityObject> uiElement = 0;
3270    NSPoint point = NSZeroPoint;
3271    bool pointSet = false;
3272    NSRange range = {0, 0};
3273    bool rangeSet = false;
3274    NSRect rect = NSZeroRect;
3275    bool rectSet = false;
3276
3277    // basic parameter validation
3278    if (!m_object || !attribute || !parameter)
3279        return nil;
3280
3281    if (![self updateObjectBackingStore])
3282        return nil;
3283
3284    // common parameter type check/casting.  Nil checks in handlers catch wrong type case.
3285    // NOTE: This assumes nil is not a valid parameter, because it is indistinguishable from
3286    // a parameter of the wrong type.
3287    if (AXObjectIsTextMarker(parameter))
3288        textMarker = parameter;
3289
3290    else if (AXObjectIsTextMarkerRange(parameter))
3291        textMarkerRange = parameter;
3292
3293    else if ([parameter isKindOfClass:[WebAccessibilityObjectWrapper self]])
3294        uiElement = [(WebAccessibilityObjectWrapper*)parameter accessibilityObject];
3295
3296    else if ([parameter isKindOfClass:[NSNumber self]])
3297        number = parameter;
3298
3299    else if ([parameter isKindOfClass:[NSArray self]])
3300        array = parameter;
3301
3302    else if ([parameter isKindOfClass:[NSDictionary self]])
3303        dictionary = parameter;
3304
3305    else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSPoint)) == 0) {
3306        pointSet = true;
3307        point = [(NSValue*)parameter pointValue];
3308
3309    } else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSRange)) == 0) {
3310        rangeSet = true;
3311        range = [(NSValue*)parameter rangeValue];
3312    } else if ([parameter isKindOfClass:[NSValue self]] && strcmp([(NSValue*)parameter objCType], @encode(NSRect)) == 0) {
3313        rectSet = true;
3314        rect = [(NSValue*)parameter rectValue];
3315    } else {
3316        // Attribute type is not supported. Allow super to handle.
3317        return [super accessibilityAttributeValue:attribute forParameter:parameter];
3318    }
3319
3320    // dispatch
3321    if ([attribute isEqualToString:NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute]) {
3322        AccessibilityObject* startObject = 0;
3323        if ([[dictionary objectForKey:@"AXStartElement"] isKindOfClass:[WebAccessibilityObjectWrapper self]])
3324            startObject = [(WebAccessibilityObjectWrapper*)[dictionary objectForKey:@"AXStartElement"] accessibilityObject];
3325
3326        AccessibilitySearchDirection searchDirection = SearchDirectionNext;
3327        if ([[dictionary objectForKey:@"AXDirection"] isKindOfClass:[NSString self]])
3328            searchDirection = ([(NSString*)[dictionary objectForKey:@"AXDirection"] isEqualToString:@"AXDirectionNext"]) ? SearchDirectionNext : SearchDirectionPrevious;
3329
3330        String searchText;
3331        if ([[dictionary objectForKey:@"AXSearchText"] isKindOfClass:[NSString self]])
3332            searchText = (CFStringRef)[dictionary objectForKey:@"AXSearchText"];
3333
3334        unsigned resultsLimit = 0;
3335        if ([[dictionary objectForKey:@"AXResultsLimit"] isKindOfClass:[NSNumber self]])
3336            resultsLimit = [(NSNumber*)[dictionary objectForKey:@"AXResultsLimit"] unsignedIntValue];
3337
3338        BOOL visibleOnly = NO;
3339        if ([[dictionary objectForKey:@"AXVisibleOnly"] isKindOfClass:[NSNumber self]])
3340            visibleOnly = [(NSNumber*)[dictionary objectForKey:@"AXVisibleOnly"] boolValue];
3341
3342        AccessibilitySearchCriteria criteria = AccessibilitySearchCriteria(startObject, searchDirection, &searchText, resultsLimit, visibleOnly);
3343
3344        id searchKeyEntry = [dictionary objectForKey:@"AXSearchKey"];
3345        if ([searchKeyEntry isKindOfClass:[NSString class]])
3346            criteria.searchKeys.append(accessibilitySearchKeyForString((CFStringRef)searchKeyEntry));
3347        else if ([searchKeyEntry isKindOfClass:[NSArray class]]) {
3348            size_t length = static_cast<size_t>([(NSArray *)searchKeyEntry count]);
3349            criteria.searchKeys.reserveInitialCapacity(length);
3350            for (size_t i = 0; i < length; ++i) {
3351                id searchKey = [(NSArray *)searchKeyEntry objectAtIndex:i];
3352                if ([searchKey isKindOfClass:[NSString class]])
3353                    criteria.searchKeys.append(accessibilitySearchKeyForString((CFStringRef)searchKey));
3354            }
3355        }
3356
3357        AccessibilityObject::AccessibilityChildrenVector results;
3358        m_object->findMatchingObjects(&criteria, results);
3359
3360        return convertToNSArray(results);
3361    }
3362
3363    if ([attribute isEqualToString:NSAccessibilityEndTextMarkerForBoundsParameterizedAttribute]) {
3364        IntRect webCoreRect = [self screenToContents:enclosingIntRect(rect)];
3365        return [self textMarkerForVisiblePosition:m_object->visiblePositionForBounds(webCoreRect, LastVisiblePositionForBounds)];
3366    }
3367    if ([attribute isEqualToString:NSAccessibilityStartTextMarkerForBoundsParameterizedAttribute]) {
3368        IntRect webCoreRect = [self screenToContents:enclosingIntRect(rect)];
3369        return [self textMarkerForVisiblePosition:m_object->visiblePositionForBounds(webCoreRect, FirstVisiblePositionForBounds)];
3370    }
3371
3372    if ([attribute isEqualToString:NSAccessibilityTextMarkerIsValidParameterizedAttribute]) {
3373        VisiblePosition pos = [self visiblePositionForTextMarker:textMarker];
3374        return [NSNumber numberWithBool:!pos.isNull()];
3375    }
3376    if ([attribute isEqualToString:NSAccessibilityIndexForTextMarkerParameterizedAttribute]) {
3377        return [NSNumber numberWithInteger:[self _indexForTextMarker:textMarker]];
3378    }
3379    if ([attribute isEqualToString:NSAccessibilityTextMarkerForIndexParameterizedAttribute]) {
3380        return [self _textMarkerForIndex:[number integerValue]];
3381    }
3382
3383    if ([attribute isEqualToString:@"AXUIElementForTextMarker"]) {
3384        VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
3385        AccessibilityObject* axObject = m_object->accessibilityObjectForPosition(visiblePos);
3386        if (!axObject)
3387            return nil;
3388        return axObject->wrapper();
3389    }
3390
3391    if ([attribute isEqualToString:@"AXTextMarkerRangeForUIElement"]) {
3392        VisiblePositionRange vpRange = uiElement.get()->visiblePositionRange();
3393        return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
3394    }
3395
3396    if ([attribute isEqualToString:@"AXLineForTextMarker"]) {
3397        VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
3398        return [NSNumber numberWithUnsignedInt:m_object->lineForPosition(visiblePos)];
3399    }
3400
3401    if ([attribute isEqualToString:@"AXTextMarkerRangeForLine"]) {
3402        VisiblePositionRange vpRange = m_object->visiblePositionRangeForLine([number intValue]);
3403        return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
3404    }
3405
3406    if ([attribute isEqualToString:@"AXStringForTextMarkerRange"]) {
3407        VisiblePositionRange visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange];
3408        return m_object->stringForVisiblePositionRange(visiblePosRange);
3409    }
3410
3411    if ([attribute isEqualToString:@"AXTextMarkerForPosition"]) {
3412        IntPoint webCorePoint = IntPoint(point);
3413        return pointSet ? [self textMarkerForVisiblePosition:m_object->visiblePositionForPoint(webCorePoint)] : nil;
3414    }
3415
3416    if ([attribute isEqualToString:@"AXBoundsForTextMarkerRange"]) {
3417        VisiblePositionRange visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange];
3418        NSRect rect = m_object->boundsForVisiblePositionRange(visiblePosRange);
3419        return [NSValue valueWithRect:rect];
3420    }
3421
3422    if ([attribute isEqualToString:NSAccessibilityBoundsForRangeParameterizedAttribute]) {
3423        VisiblePosition start = m_object->visiblePositionForIndex(range.location);
3424        VisiblePosition end = m_object->visiblePositionForIndex(range.location+range.length);
3425        if (start.isNull() || end.isNull())
3426            return nil;
3427        NSRect rect = m_object->boundsForVisiblePositionRange(VisiblePositionRange(start, end));
3428        return [NSValue valueWithRect:rect];
3429    }
3430
3431    if ([attribute isEqualToString:NSAccessibilityStringForRangeParameterizedAttribute]) {
3432        VisiblePosition start = m_object->visiblePositionForIndex(range.location);
3433        VisiblePosition end = m_object->visiblePositionForIndex(range.location+range.length);
3434        if (start.isNull() || end.isNull())
3435            return nil;
3436        return m_object->stringForVisiblePositionRange(VisiblePositionRange(start, end));
3437    }
3438
3439    if ([attribute isEqualToString:@"AXAttributedStringForTextMarkerRange"])
3440        return [self doAXAttributedStringForTextMarkerRange:textMarkerRange];
3441
3442    if ([attribute isEqualToString:@"AXTextMarkerRangeForUnorderedTextMarkers"]) {
3443        if ([array count] < 2)
3444            return nil;
3445
3446        id textMarker1 = [array objectAtIndex:0];
3447        id textMarker2 = [array objectAtIndex:1];
3448        if (!AXObjectIsTextMarker(textMarker1) || !AXObjectIsTextMarker(textMarker2))
3449            return nil;
3450
3451        VisiblePosition visiblePos1 = [self visiblePositionForTextMarker:(textMarker1)];
3452        VisiblePosition visiblePos2 = [self visiblePositionForTextMarker:(textMarker2)];
3453        VisiblePositionRange vpRange = m_object->visiblePositionRangeForUnorderedPositions(visiblePos1, visiblePos2);
3454        return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
3455    }
3456
3457    if ([attribute isEqualToString:@"AXNextTextMarkerForTextMarker"]) {
3458        VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
3459        return [self textMarkerForVisiblePosition:m_object->nextVisiblePosition(visiblePos)];
3460    }
3461
3462    if ([attribute isEqualToString:@"AXPreviousTextMarkerForTextMarker"]) {
3463        VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
3464        return [self textMarkerForVisiblePosition:m_object->previousVisiblePosition(visiblePos)];
3465    }
3466
3467    if ([attribute isEqualToString:@"AXLeftWordTextMarkerRangeForTextMarker"]) {
3468        VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
3469        VisiblePositionRange vpRange = m_object->positionOfLeftWord(visiblePos);
3470        return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
3471    }
3472
3473    if ([attribute isEqualToString:@"AXRightWordTextMarkerRangeForTextMarker"]) {
3474        VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
3475        VisiblePositionRange vpRange = m_object->positionOfRightWord(visiblePos);
3476        return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
3477    }
3478
3479    if ([attribute isEqualToString:@"AXLeftLineTextMarkerRangeForTextMarker"]) {
3480        VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
3481        VisiblePositionRange vpRange = m_object->leftLineVisiblePositionRange(visiblePos);
3482        return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
3483    }
3484
3485    if ([attribute isEqualToString:@"AXRightLineTextMarkerRangeForTextMarker"]) {
3486        VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
3487        VisiblePositionRange vpRange = m_object->rightLineVisiblePositionRange(visiblePos);
3488        return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
3489    }
3490
3491    if ([attribute isEqualToString:@"AXSentenceTextMarkerRangeForTextMarker"]) {
3492        VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
3493        VisiblePositionRange vpRange = m_object->sentenceForPosition(visiblePos);
3494        return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
3495    }
3496
3497    if ([attribute isEqualToString:@"AXParagraphTextMarkerRangeForTextMarker"]) {
3498        VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
3499        VisiblePositionRange vpRange = m_object->paragraphForPosition(visiblePos);
3500        return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
3501    }
3502
3503    if ([attribute isEqualToString:@"AXNextWordEndTextMarkerForTextMarker"]) {
3504        VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
3505        return [self textMarkerForVisiblePosition:m_object->nextWordEnd(visiblePos)];
3506    }
3507
3508    if ([attribute isEqualToString:@"AXPreviousWordStartTextMarkerForTextMarker"]) {
3509        VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
3510        return [self textMarkerForVisiblePosition:m_object->previousWordStart(visiblePos)];
3511    }
3512
3513    if ([attribute isEqualToString:@"AXNextLineEndTextMarkerForTextMarker"]) {
3514        VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
3515        return [self textMarkerForVisiblePosition:m_object->nextLineEndPosition(visiblePos)];
3516    }
3517
3518    if ([attribute isEqualToString:@"AXPreviousLineStartTextMarkerForTextMarker"]) {
3519        VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
3520        return [self textMarkerForVisiblePosition:m_object->previousLineStartPosition(visiblePos)];
3521    }
3522
3523    if ([attribute isEqualToString:@"AXNextSentenceEndTextMarkerForTextMarker"]) {
3524        VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
3525        return [self textMarkerForVisiblePosition:m_object->nextSentenceEndPosition(visiblePos)];
3526    }
3527
3528    if ([attribute isEqualToString:@"AXPreviousSentenceStartTextMarkerForTextMarker"]) {
3529        VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
3530        return [self textMarkerForVisiblePosition:m_object->previousSentenceStartPosition(visiblePos)];
3531    }
3532
3533    if ([attribute isEqualToString:@"AXNextParagraphEndTextMarkerForTextMarker"]) {
3534        VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
3535        return [self textMarkerForVisiblePosition:m_object->nextParagraphEndPosition(visiblePos)];
3536    }
3537
3538    if ([attribute isEqualToString:@"AXPreviousParagraphStartTextMarkerForTextMarker"]) {
3539        VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
3540        return [self textMarkerForVisiblePosition:m_object->previousParagraphStartPosition(visiblePos)];
3541    }
3542
3543    if ([attribute isEqualToString:@"AXStyleTextMarkerRangeForTextMarker"]) {
3544        VisiblePosition visiblePos = [self visiblePositionForTextMarker:(textMarker)];
3545        VisiblePositionRange vpRange = m_object->styleRangeForPosition(visiblePos);
3546        return [self textMarkerRangeFromVisiblePositions:vpRange.start endPosition:vpRange.end];
3547    }
3548
3549    if ([attribute isEqualToString:@"AXLengthForTextMarkerRange"]) {
3550        VisiblePositionRange visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange];
3551        int length = m_object->lengthForVisiblePositionRange(visiblePosRange);
3552        if (length < 0)
3553            return nil;
3554        return [NSNumber numberWithInt:length];
3555    }
3556
3557    // Used only by DumpRenderTree (so far).
3558    if ([attribute isEqualToString:@"AXStartTextMarkerForTextMarkerRange"]) {
3559        VisiblePositionRange visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange];
3560        return [self textMarkerForVisiblePosition:visiblePosRange.start];
3561    }
3562
3563    if ([attribute isEqualToString:@"AXEndTextMarkerForTextMarkerRange"]) {
3564        VisiblePositionRange visiblePosRange = [self visiblePositionRangeForTextMarkerRange:textMarkerRange];
3565        return [self textMarkerForVisiblePosition:visiblePosRange.end];
3566    }
3567
3568    if (m_object->isAccessibilityTable()) {
3569        if ([attribute isEqualToString:NSAccessibilityCellForColumnAndRowParameterizedAttribute]) {
3570            if (array == nil || [array count] != 2)
3571                return nil;
3572            AccessibilityTableCell* cell = static_cast<AccessibilityTable*>(m_object)->cellForColumnAndRow([[array objectAtIndex:0] unsignedIntValue], [[array objectAtIndex:1] unsignedIntValue]);
3573            if (!cell)
3574                return nil;
3575
3576            return cell->wrapper();
3577        }
3578    }
3579
3580    if (m_object->isTextControl()) {
3581        if ([attribute isEqualToString: (NSString *)kAXLineForIndexParameterizedAttribute]) {
3582            int lineNumber = m_object->doAXLineForIndex([number intValue]);
3583            if (lineNumber < 0)
3584                return nil;
3585            return [NSNumber numberWithUnsignedInt:lineNumber];
3586        }
3587
3588        if ([attribute isEqualToString: (NSString *)kAXRangeForLineParameterizedAttribute]) {
3589            PlainTextRange textRange = m_object->doAXRangeForLine([number intValue]);
3590            return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
3591        }
3592
3593        if ([attribute isEqualToString: (NSString*)kAXStringForRangeParameterizedAttribute]) {
3594            PlainTextRange plainTextRange = PlainTextRange(range.location, range.length);
3595            return rangeSet ? (id)(m_object->doAXStringForRange(plainTextRange)) : nil;
3596        }
3597
3598        if ([attribute isEqualToString: (NSString*)kAXRangeForPositionParameterizedAttribute]) {
3599            if (!pointSet)
3600                return nil;
3601            IntPoint webCorePoint = IntPoint(point);
3602            PlainTextRange textRange = m_object->doAXRangeForPosition(webCorePoint);
3603            return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
3604        }
3605
3606        if ([attribute isEqualToString: (NSString*)kAXRangeForIndexParameterizedAttribute]) {
3607            PlainTextRange textRange = m_object->doAXRangeForIndex([number intValue]);
3608            return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
3609        }
3610
3611        if ([attribute isEqualToString: (NSString*)kAXBoundsForRangeParameterizedAttribute]) {
3612            if (!rangeSet)
3613                return nil;
3614            PlainTextRange plainTextRange = PlainTextRange(range.location, range.length);
3615            NSRect rect = m_object->doAXBoundsForRange(plainTextRange);
3616            return [NSValue valueWithRect:rect];
3617        }
3618
3619        if ([attribute isEqualToString: (NSString*)kAXRTFForRangeParameterizedAttribute])
3620            return rangeSet ? [self doAXRTFForRange:range] : nil;
3621
3622        if ([attribute isEqualToString: (NSString*)kAXAttributedStringForRangeParameterizedAttribute])
3623            return rangeSet ? [self doAXAttributedStringForRange:range] : nil;
3624
3625        if ([attribute isEqualToString: (NSString*)kAXStyleRangeForIndexParameterizedAttribute]) {
3626            PlainTextRange textRange = m_object->doAXStyleRangeForIndex([number intValue]);
3627            return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
3628        }
3629    }
3630
3631    // There are some parameters that super handles that are not explicitly returned by the list of the element's attributes.
3632    // In that case it must be passed to super.
3633    return [super accessibilityAttributeValue:attribute forParameter:parameter];
3634}
3635
3636- (BOOL)accessibilitySupportsOverriddenAttributes
3637{
3638    return YES;
3639}
3640
3641- (BOOL)accessibilityShouldUseUniqueId
3642{
3643    // All AX object wrappers should use unique ID's because it's faster within AppKit to look them up.
3644    return YES;
3645}
3646
3647// API that AppKit uses for faster access
3648- (NSUInteger)accessibilityIndexOfChild:(id)child
3649{
3650    if (![self updateObjectBackingStore])
3651        return NSNotFound;
3652
3653    // Tree objects return their rows as their children. We can use the original method
3654    // here, because we won't gain any speed up.
3655    if (m_object->isTree())
3656        return [super accessibilityIndexOfChild:child];
3657
3658    const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children();
3659
3660    if (children.isEmpty())
3661        return [[self renderWidgetChildren] indexOfObject:child];
3662
3663    unsigned count = children.size();
3664    for (unsigned k = 0; k < count; ++k) {
3665        WebAccessibilityObjectWrapper* wrapper = children[k]->wrapper();
3666        if (wrapper == child || (children[k]->isAttachment() && [wrapper attachmentView] == child))
3667            return k;
3668    }
3669
3670    return NSNotFound;
3671}
3672
3673- (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute
3674{
3675    if (![self updateObjectBackingStore])
3676        return 0;
3677
3678    if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
3679        // Tree items object returns a different set of children than those that are in children()
3680        // because an AXOutline (the mac role is becomes) has some odd stipulations.
3681        if (m_object->isTree() || m_object->isTreeItem())
3682            return [[self accessibilityAttributeValue:NSAccessibilityChildrenAttribute] count];
3683
3684        const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children();
3685        if (children.isEmpty())
3686            return [[self renderWidgetChildren] count];
3687
3688        return children.size();
3689    }
3690
3691    return [super accessibilityArrayAttributeCount:attribute];
3692}
3693
3694- (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount
3695{
3696    if (![self updateObjectBackingStore])
3697        return nil;
3698
3699    if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
3700        if (m_object->children().isEmpty()) {
3701            NSArray *children = [self renderWidgetChildren];
3702            if (!children)
3703                return nil;
3704
3705            NSUInteger childCount = [children count];
3706            if (index >= childCount)
3707                return nil;
3708
3709            NSUInteger arrayLength = min(childCount - index, maxCount);
3710            return [children subarrayWithRange:NSMakeRange(index, arrayLength)];
3711        } else if (m_object->isTree()) {
3712            // Tree objects return their rows as their children. We can use the original method in this case.
3713            return [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount];
3714        }
3715
3716        const AccessibilityObject::AccessibilityChildrenVector& children = m_object->children();
3717        unsigned childCount = children.size();
3718        if (index >= childCount)
3719            return nil;
3720
3721        unsigned available = min(childCount - index, maxCount);
3722
3723        NSMutableArray *subarray = [NSMutableArray arrayWithCapacity:available];
3724        for (unsigned added = 0; added < available; ++index, ++added) {
3725            WebAccessibilityObjectWrapper* wrapper = children[index]->wrapper();
3726            if (wrapper) {
3727                // The attachment view should be returned, otherwise AX palindrome errors occur.
3728                if (children[index]->isAttachment() && [wrapper attachmentView])
3729                    [subarray addObject:[wrapper attachmentView]];
3730                else
3731                    [subarray addObject:wrapper];
3732            }
3733        }
3734
3735        return subarray;
3736    }
3737
3738    return [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount];
3739}
3740
3741@end
3742
3743#endif // HAVE(ACCESSIBILITY)
3744