AX: WebArea claims to have a subrole, but always returns nil.
[WebKit-https.git] / Source / WebCore / accessibility / mac / WebAccessibilityObjectWrapperMac.mm
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
78 using namespace WebCore;
79 using namespace HTMLNames;
80 using 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 NSAccessibilityElementBusyAttribute
170 #define NSAccessibilityElementBusyAttribute @"AXElementBusy"
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 // Search Keys
199 #ifndef NSAccessibilityAnyTypeSearchKey
200 #define NSAccessibilityAnyTypeSearchKey @"AXAnyTypeSearchKey"
201 #endif
202
203 #ifndef NSAccessibilityBlockquoteSameLevelSearchKey
204 #define NSAccessibilityBlockquoteSameLevelSearchKey @"AXBlockquoteSameLevelSearchKey"
205 #endif
206
207 #ifndef NSAccessibilityBlockquoteSearchKey
208 #define NSAccessibilityBlockquoteSearchKey @"AXBlockquoteSearchKey"
209 #endif
210
211 #ifndef NSAccessibilityBoldFontSearchKey
212 #define NSAccessibilityBoldFontSearchKey @"AXBoldFontSearchKey"
213 #endif
214
215 #ifndef NSAccessibilityButtonSearchKey
216 #define NSAccessibilityButtonSearchKey @"AXButtonSearchKey"
217 #endif
218
219 #ifndef NSAccessibilityCheckBoxSearchKey
220 #define NSAccessibilityCheckBoxSearchKey @"AXCheckBoxSearchKey"
221 #endif
222
223 #ifndef NSAccessibilityControlSearchKey
224 #define NSAccessibilityControlSearchKey @"AXControlSearchKey"
225 #endif
226
227 #ifndef NSAccessibilityDifferentTypeSearchKey
228 #define NSAccessibilityDifferentTypeSearchKey @"AXDifferentTypeSearchKey"
229 #endif
230
231 #ifndef NSAccessibilityFontChangeSearchKey
232 #define NSAccessibilityFontChangeSearchKey @"AXFontChangeSearchKey"
233 #endif
234
235 #ifndef NSAccessibilityFontColorChangeSearchKey
236 #define NSAccessibilityFontColorChangeSearchKey @"AXFontColorChangeSearchKey"
237 #endif
238
239 #ifndef NSAccessibilityFrameSearchKey
240 #define NSAccessibilityFrameSearchKey @"AXFrameSearchKey"
241 #endif
242
243 #ifndef NSAccessibilityGraphicSearchKey
244 #define NSAccessibilityGraphicSearchKey @"AXGraphicSearchKey"
245 #endif
246
247 #ifndef NSAccessibilityHeadingLevel1SearchKey
248 #define NSAccessibilityHeadingLevel1SearchKey @"AXHeadingLevel1SearchKey"
249 #endif
250
251 #ifndef NSAccessibilityHeadingLevel2SearchKey
252 #define NSAccessibilityHeadingLevel2SearchKey @"AXHeadingLevel2SearchKey"
253 #endif
254
255 #ifndef NSAccessibilityHeadingLevel3SearchKey
256 #define NSAccessibilityHeadingLevel3SearchKey @"AXHeadingLevel3SearchKey"
257 #endif
258
259 #ifndef NSAccessibilityHeadingLevel4SearchKey
260 #define NSAccessibilityHeadingLevel4SearchKey @"AXHeadingLevel4SearchKey"
261 #endif
262
263 #ifndef NSAccessibilityHeadingLevel5SearchKey
264 #define NSAccessibilityHeadingLevel5SearchKey @"AXHeadingLevel5SearchKey"
265 #endif
266
267 #ifndef NSAccessibilityHeadingLevel6SearchKey
268 #define NSAccessibilityHeadingLevel6SearchKey @"AXHeadingLevel6SearchKey"
269 #endif
270
271 #ifndef NSAccessibilityHeadingSameLevelSearchKey
272 #define NSAccessibilityHeadingSameLevelSearchKey @"AXHeadingSameLevelSearchKey"
273 #endif
274
275 #ifndef NSAccessibilityHeadingSearchKey
276 #define NSAccessibilityHeadingSearchKey @"AXHeadingSearchKey"
277 #endif
278
279 #ifndef NSAccessibilityHighlightedSearchKey
280 #define NSAccessibilityHighlightedSearchKey @"AXHighlightedSearchKey"
281 #endif
282
283 #ifndef NSAccessibilityItalicFontSearchKey
284 #define NSAccessibilityItalicFontSearchKey @"AXItalicFontSearchKey"
285 #endif
286
287 #ifndef NSAccessibilityLandmarkSearchKey
288 #define NSAccessibilityLandmarkSearchKey @"AXLandmarkSearchKey"
289 #endif
290
291 #ifndef NSAccessibilityLinkSearchKey
292 #define NSAccessibilityLinkSearchKey @"AXLinkSearchKey"
293 #endif
294
295 #ifndef NSAccessibilityListSearchKey
296 #define NSAccessibilityListSearchKey @"AXListSearchKey"
297 #endif
298
299 #ifndef NSAccessibilityLiveRegionSearchKey
300 #define NSAccessibilityLiveRegionSearchKey @"AXLiveRegionSearchKey"
301 #endif
302
303 #ifndef NSAccessibilityMisspelledWordSearchKey
304 #define NSAccessibilityMisspelledWordSearchKey @"AXMisspelledWordSearchKey"
305 #endif
306
307 #ifndef NSAccessibilityPlainTextSearchKey
308 #define NSAccessibilityPlainTextSearchKey @"AXPlainTextSearchKey"
309 #endif
310
311 #ifndef NSAccessibilityRadioGroupSearchKey
312 #define NSAccessibilityRadioGroupSearchKey @"AXRadioGroupSearchKey"
313 #endif
314
315 #ifndef NSAccessibilitySameTypeSearchKey
316 #define NSAccessibilitySameTypeSearchKey @"AXSameTypeSearchKey"
317 #endif
318
319 #ifndef NSAccessibilityStaticTextSearchKey
320 #define NSAccessibilityStaticTextSearchKey @"AXStaticTextSearchKey"
321 #endif
322
323 #ifndef NSAccessibilityStyleChangeSearchKey
324 #define NSAccessibilityStyleChangeSearchKey @"AXStyleChangeSearchKey"
325 #endif
326
327 #ifndef NSAccessibilityTableSameLevelSearchKey
328 #define NSAccessibilityTableSameLevelSearchKey @"AXTableSameLevelSearchKey"
329 #endif
330
331 #ifndef NSAccessibilityTableSearchKey
332 #define NSAccessibilityTableSearchKey @"AXTableSearchKey"
333 #endif
334
335 #ifndef NSAccessibilityTextFieldSearchKey
336 #define NSAccessibilityTextFieldSearchKey @"AXTextFieldSearchKey"
337 #endif
338
339 #ifndef NSAccessibilityUnderlineSearchKey
340 #define NSAccessibilityUnderlineSearchKey @"AXUnderlineSearchKey"
341 #endif
342
343 #ifndef NSAccessibilityUnvisitedLinkSearchKey
344 #define NSAccessibilityUnvisitedLinkSearchKey @"AXUnvisitedLinkSearchKey"
345 #endif
346
347 #ifndef NSAccessibilityVisitedLinkSearchKey
348 #define NSAccessibilityVisitedLinkSearchKey @"AXVisitedLinkSearchKey"
349 #endif
350
351 #define NSAccessibilityTextMarkerIsValidParameterizedAttribute @"AXTextMarkerIsValid"
352 #define NSAccessibilityIndexForTextMarkerParameterizedAttribute @"AXIndexForTextMarker"
353 #define NSAccessibilityTextMarkerForIndexParameterizedAttribute @"AXTextMarkerForIndex"
354
355 #ifndef NSAccessibilityScrollToVisibleAction
356 #define NSAccessibilityScrollToVisibleAction @"AXScrollToVisible"
357 #endif
358
359 #ifndef NSAccessibilityPathAttribute
360 #define NSAccessibilityPathAttribute @"AXPath"
361 #endif
362
363 #define NSAccessibilityDOMIdentifierAttribute @"AXDOMIdentifier"
364 #define NSAccessibilityDOMClassListAttribute @"AXDOMClassList"
365
366 // Math attributes
367 #define NSAccessibilityMathRootRadicandAttribute @"AXMathRootRadicand"
368 #define NSAccessibilityMathRootIndexAttribute @"AXMathRootIndex"
369 #define NSAccessibilityMathFractionDenominatorAttribute @"AXMathFractionDenominator"
370 #define NSAccessibilityMathFractionNumeratorAttribute @"AXMathFractionNumerator"
371 #define NSAccessibilityMathBaseAttribute @"AXMathBase"
372 #define NSAccessibilityMathSubscriptAttribute @"AXMathSubscript"
373 #define NSAccessibilityMathSuperscriptAttribute @"AXMathSuperscript"
374 #define NSAccessibilityMathUnderAttribute @"AXMathUnder"
375 #define NSAccessibilityMathOverAttribute @"AXMathOver"
376 #define NSAccessibilityMathFencedOpenAttribute @"AXMathFencedOpen"
377 #define NSAccessibilityMathFencedCloseAttribute @"AXMathFencedClose"
378 #define NSAccessibilityMathLineThicknessAttribute @"AXMathLineThickness"
379 #define NSAccessibilityMathPrescriptsAttribute @"AXMathPrescripts"
380 #define NSAccessibilityMathPostscriptsAttribute @"AXMathPostscripts"
381
382 @implementation WebAccessibilityObjectWrapper
383
384 - (void)unregisterUniqueIdForUIElement
385 {
386     wkUnregisterUniqueIdForElement(self);
387 }
388
389 - (void)detach
390 {
391     // Send unregisterUniqueIdForUIElement unconditionally because if it is
392     // ever accidentally not done (via other bugs in our AX implementation) you
393     // end up with a crash like <rdar://problem/4273149>.  It is safe and not
394     // expensive to send even if the object is not registered.
395     [self unregisterUniqueIdForUIElement];
396     [super detach];
397 }
398
399 - (id)attachmentView
400 {
401     ASSERT(m_object->isAttachment());
402     Widget* widget = m_object->widgetForAttachmentView();
403     if (!widget)
404         return nil;
405     return NSAccessibilityUnignoredDescendant(widget->platformWidget());
406 }
407
408 #pragma mark SystemInterface wrappers
409
410 static inline BOOL AXObjectIsTextMarker(id obj)
411 {
412     return obj != nil && CFGetTypeID(obj) == wkGetAXTextMarkerTypeID();
413 }
414
415 static inline BOOL AXObjectIsTextMarkerRange(id obj)
416 {
417     return obj != nil && CFGetTypeID(obj) == wkGetAXTextMarkerRangeTypeID();
418 }
419
420 static id AXTextMarkerRange(id startMarker, id endMarker)
421 {
422     ASSERT(startMarker != nil);
423     ASSERT(endMarker != nil);
424     ASSERT(CFGetTypeID(startMarker) == wkGetAXTextMarkerTypeID());
425     ASSERT(CFGetTypeID(endMarker) == wkGetAXTextMarkerTypeID());
426     return CFBridgingRelease(wkCreateAXTextMarkerRange((CFTypeRef)startMarker, (CFTypeRef)endMarker));
427 }
428
429 static id AXTextMarkerRangeStart(id range)
430 {
431     ASSERT(range != nil);
432     ASSERT(CFGetTypeID(range) == wkGetAXTextMarkerRangeTypeID());
433     return CFBridgingRelease(wkCopyAXTextMarkerRangeStart(range));
434 }
435
436 static id AXTextMarkerRangeEnd(id range)
437 {
438     ASSERT(range != nil);
439     ASSERT(CFGetTypeID(range) == wkGetAXTextMarkerRangeTypeID());
440     return CFBridgingRelease(wkCopyAXTextMarkerRangeEnd(range));
441 }
442
443 #pragma mark Search helpers
444
445 typedef HashMap<String, AccessibilitySearchKey> AccessibilitySearchKeyMap;
446
447 struct SearchKeyEntry {
448     String key;
449     AccessibilitySearchKey value;
450 };
451
452 static AccessibilitySearchKeyMap* createAccessibilitySearchKeyMap()
453 {
454     const SearchKeyEntry searchKeys[] = {
455         { NSAccessibilityAnyTypeSearchKey, AnyTypeSearchKey },
456         { NSAccessibilityBlockquoteSameLevelSearchKey, BlockquoteSameLevelSearchKey },
457         { NSAccessibilityBlockquoteSearchKey, BlockquoteSearchKey },
458         { NSAccessibilityBoldFontSearchKey, BoldFontSearchKey },
459         { NSAccessibilityButtonSearchKey, ButtonSearchKey },
460         { NSAccessibilityCheckBoxSearchKey, CheckBoxSearchKey },
461         { NSAccessibilityControlSearchKey, ControlSearchKey },
462         { NSAccessibilityDifferentTypeSearchKey, DifferentTypeSearchKey },
463         { NSAccessibilityFontChangeSearchKey, FontChangeSearchKey },
464         { NSAccessibilityFontColorChangeSearchKey, FontColorChangeSearchKey },
465         { NSAccessibilityFrameSearchKey, FrameSearchKey },
466         { NSAccessibilityGraphicSearchKey, GraphicSearchKey },
467         { NSAccessibilityHeadingLevel1SearchKey, HeadingLevel1SearchKey },
468         { NSAccessibilityHeadingLevel2SearchKey, HeadingLevel2SearchKey },
469         { NSAccessibilityHeadingLevel3SearchKey, HeadingLevel3SearchKey },
470         { NSAccessibilityHeadingLevel4SearchKey, HeadingLevel4SearchKey },
471         { NSAccessibilityHeadingLevel5SearchKey, HeadingLevel5SearchKey },
472         { NSAccessibilityHeadingLevel6SearchKey, HeadingLevel6SearchKey },
473         { NSAccessibilityHeadingSameLevelSearchKey, HeadingSameLevelSearchKey },
474         { NSAccessibilityHeadingSearchKey, HeadingSearchKey },
475         { NSAccessibilityHighlightedSearchKey, HighlightedSearchKey },
476         { NSAccessibilityItalicFontSearchKey, ItalicFontSearchKey },
477         { NSAccessibilityLandmarkSearchKey, LandmarkSearchKey },
478         { NSAccessibilityLinkSearchKey, LinkSearchKey },
479         { NSAccessibilityListSearchKey, ListSearchKey },
480         { NSAccessibilityLiveRegionSearchKey, LiveRegionSearchKey },
481         { NSAccessibilityMisspelledWordSearchKey, MisspelledWordSearchKey },
482         { NSAccessibilityPlainTextSearchKey, PlainTextSearchKey },
483         { NSAccessibilityRadioGroupSearchKey, RadioGroupSearchKey },
484         { NSAccessibilitySameTypeSearchKey, SameTypeSearchKey },
485         { NSAccessibilityStaticTextSearchKey, StaticTextSearchKey },
486         { NSAccessibilityStyleChangeSearchKey, StyleChangeSearchKey },
487         { NSAccessibilityTableSameLevelSearchKey, TableSameLevelSearchKey },
488         { NSAccessibilityTableSearchKey, TableSearchKey },
489         { NSAccessibilityTextFieldSearchKey, TextFieldSearchKey },
490         { NSAccessibilityUnderlineSearchKey, UnderlineSearchKey },
491         { NSAccessibilityUnvisitedLinkSearchKey, UnvisitedLinkSearchKey },
492         { NSAccessibilityVisitedLinkSearchKey, VisitedLinkSearchKey }
493     };
494     
495     AccessibilitySearchKeyMap* searchKeyMap = new AccessibilitySearchKeyMap;
496     for (size_t i = 0; i < WTF_ARRAY_LENGTH(searchKeys); i++)
497         searchKeyMap->set(searchKeys[i].key, searchKeys[i].value);
498     
499     return searchKeyMap;
500 }
501
502 static AccessibilitySearchKey accessibilitySearchKeyForString(const String& value)
503 {
504     if (value.isEmpty())
505         return AnyTypeSearchKey;
506     
507     static const AccessibilitySearchKeyMap* searchKeyMap = createAccessibilitySearchKeyMap();
508     
509     AccessibilitySearchKey searchKey = searchKeyMap->get(value);
510     
511     return searchKey ? searchKey : AnyTypeSearchKey;
512 }
513
514 #pragma mark Text Marker helpers
515
516 static id textMarkerForVisiblePosition(AXObjectCache* cache, const VisiblePosition& visiblePos)
517 {
518     ASSERT(cache);
519     
520     TextMarkerData textMarkerData;
521     cache->textMarkerDataForVisiblePosition(textMarkerData, visiblePos);
522     if (!textMarkerData.axID)
523         return nil;
524     
525     return CFBridgingRelease(wkCreateAXTextMarker(&textMarkerData, sizeof(textMarkerData)));
526 }
527
528 - (id)textMarkerForVisiblePosition:(const VisiblePosition &)visiblePos
529 {
530     return textMarkerForVisiblePosition(m_object->axObjectCache(), visiblePos);
531 }
532
533 static VisiblePosition visiblePositionForTextMarker(AXObjectCache* cache, CFTypeRef textMarker)
534 {
535     ASSERT(cache);
536     
537     if (!textMarker)
538         return VisiblePosition();
539     TextMarkerData textMarkerData;
540     if (!wkGetBytesFromAXTextMarker(textMarker, &textMarkerData, sizeof(textMarkerData)))
541         return VisiblePosition();
542     
543     return cache->visiblePositionForTextMarkerData(textMarkerData);
544 }
545
546 - (VisiblePosition)visiblePositionForTextMarker:(id)textMarker
547 {
548     return visiblePositionForTextMarker(m_object->axObjectCache(), textMarker);
549 }
550
551 static VisiblePosition visiblePositionForStartOfTextMarkerRange(AXObjectCache *cache, id textMarkerRange)
552 {
553     return visiblePositionForTextMarker(cache, AXTextMarkerRangeStart(textMarkerRange));
554 }
555
556 static VisiblePosition visiblePositionForEndOfTextMarkerRange(AXObjectCache *cache, id textMarkerRange)
557 {
558     return visiblePositionForTextMarker(cache, AXTextMarkerRangeEnd(textMarkerRange));
559 }
560
561 static id textMarkerRangeFromMarkers(id textMarker1, id textMarker2)
562 {
563     if (!textMarker1 || !textMarker2)
564         return nil;
565     
566     return AXTextMarkerRange(textMarker1, textMarker2);
567 }
568
569 // When modifying attributed strings, the range can come from a source which may provide faulty information (e.g. the spell checker).
570 // To protect against such cases the range should be validated before adding or removing attributes.
571 static BOOL AXAttributedStringRangeIsValid(NSAttributedString* attrString, NSRange range)
572 {
573     return (range.location < [attrString length] && NSMaxRange(range) <= [attrString length]);
574 }
575
576 static void AXAttributeStringSetFont(NSMutableAttributedString* attrString, NSString* attribute, NSFont* font, NSRange range)
577 {
578     if (!AXAttributedStringRangeIsValid(attrString, range))
579         return;
580     
581     if (font) {
582         NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
583                               [font fontName]                             , NSAccessibilityFontNameKey,
584                               [font familyName]                           , NSAccessibilityFontFamilyKey,
585                               [font displayName]                          , NSAccessibilityVisibleNameKey,
586                               [NSNumber numberWithFloat:[font pointSize]] , NSAccessibilityFontSizeKey,
587                               nil];
588         
589         [attrString addAttribute:attribute value:dict range:range];
590     } else
591         [attrString removeAttribute:attribute range:range];
592     
593 }
594
595 static CGColorRef CreateCGColorIfDifferent(NSColor* nsColor, CGColorRef existingColor)
596 {
597     // get color information assuming NSDeviceRGBColorSpace
598     NSColor* rgbColor = [nsColor colorUsingColorSpaceName:NSDeviceRGBColorSpace];
599     if (rgbColor == nil)
600         rgbColor = [NSColor blackColor];
601     CGFloat components[4];
602     [rgbColor getRed:&components[0] green:&components[1] blue:&components[2] alpha:&components[3]];
603     
604     // create a new CGColorRef to return
605     CGColorSpaceRef cgColorSpace = CGColorSpaceCreateDeviceRGB();
606     CGColorRef cgColor = CGColorCreate(cgColorSpace, components);
607     CGColorSpaceRelease(cgColorSpace);
608     
609     // check for match with existing color
610     if (existingColor && CGColorEqualToColor(cgColor, existingColor)) {
611         CGColorRelease(cgColor);
612         cgColor = 0;
613     }
614     
615     return cgColor;
616 }
617
618 static void AXAttributeStringSetColor(NSMutableAttributedString* attrString, NSString* attribute, NSColor* color, NSRange range)
619 {
620     if (!AXAttributedStringRangeIsValid(attrString, range))
621         return;
622     
623     if (color) {
624         CGColorRef existingColor = (CGColorRef) [attrString attribute:attribute atIndex:range.location effectiveRange:nil];
625         CGColorRef cgColor = CreateCGColorIfDifferent(color, existingColor);
626         if (cgColor) {
627             [attrString addAttribute:attribute value:(id)cgColor range:range];
628             CGColorRelease(cgColor);
629         }
630     } else
631         [attrString removeAttribute:attribute range:range];
632 }
633
634 static void AXAttributeStringSetNumber(NSMutableAttributedString* attrString, NSString* attribute, NSNumber* number, NSRange range)
635 {
636     if (!AXAttributedStringRangeIsValid(attrString, range))
637         return;
638     
639     if (number)
640         [attrString addAttribute:attribute value:number range:range];
641     else
642         [attrString removeAttribute:attribute range:range];
643 }
644
645 static void AXAttributeStringSetStyle(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
646 {
647     RenderStyle* style = renderer->style();
648     
649     // set basic font info
650     AXAttributeStringSetFont(attrString, NSAccessibilityFontTextAttribute, style->font().primaryFont()->getNSFont(), range);
651     
652     // set basic colors
653     AXAttributeStringSetColor(attrString, NSAccessibilityForegroundColorTextAttribute, nsColor(style->visitedDependentColor(CSSPropertyColor)), range);
654     AXAttributeStringSetColor(attrString, NSAccessibilityBackgroundColorTextAttribute, nsColor(style->visitedDependentColor(CSSPropertyBackgroundColor)), range);
655     
656     // set super/sub scripting
657     EVerticalAlign alignment = style->verticalAlign();
658     if (alignment == SUB)
659         AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, [NSNumber numberWithInt:(-1)], range);
660     else if (alignment == SUPER)
661         AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, [NSNumber numberWithInt:1], range);
662     else
663         [attrString removeAttribute:NSAccessibilitySuperscriptTextAttribute range:range];
664     
665     // set shadow
666     if (style->textShadow())
667         AXAttributeStringSetNumber(attrString, NSAccessibilityShadowTextAttribute, [NSNumber numberWithBool:YES], range);
668     else
669         [attrString removeAttribute:NSAccessibilityShadowTextAttribute range:range];
670     
671     // set underline and strikethrough
672     int decor = style->textDecorationsInEffect();
673     if ((decor & TextDecorationUnderline) == 0) {
674         [attrString removeAttribute:NSAccessibilityUnderlineTextAttribute range:range];
675         [attrString removeAttribute:NSAccessibilityUnderlineColorTextAttribute range:range];
676     }
677     
678     if ((decor & TextDecorationLineThrough) == 0) {
679         [attrString removeAttribute:NSAccessibilityStrikethroughTextAttribute range:range];
680         [attrString removeAttribute:NSAccessibilityStrikethroughColorTextAttribute range:range];
681     }
682     
683     if ((decor & (TextDecorationUnderline | TextDecorationLineThrough)) != 0) {
684         // find colors using quirk mode approach (strict mode would use current
685         // color for all but the root line box, which would use getTextDecorationColors)
686         Color underline, overline, linethrough;
687         renderer->getTextDecorationColors(decor, underline, overline, linethrough);
688         
689         if ((decor & TextDecorationUnderline) != 0) {
690             AXAttributeStringSetNumber(attrString, NSAccessibilityUnderlineTextAttribute, [NSNumber numberWithBool:YES], range);
691             AXAttributeStringSetColor(attrString, NSAccessibilityUnderlineColorTextAttribute, nsColor(underline), range);
692         }
693         
694         if ((decor & TextDecorationLineThrough) != 0) {
695             AXAttributeStringSetNumber(attrString, NSAccessibilityStrikethroughTextAttribute, [NSNumber numberWithBool:YES], range);
696             AXAttributeStringSetColor(attrString, NSAccessibilityStrikethroughColorTextAttribute, nsColor(linethrough), range);
697         }
698     }
699     
700     // Indicate background highlighting.
701     for (Node* node = renderer->node(); node; node = node->parentNode()) {
702         if (node->hasTagName(markTag))
703             AXAttributeStringSetNumber(attrString, @"AXHighlight", [NSNumber numberWithBool:YES], range);
704     }
705 }
706
707 static void AXAttributeStringSetBlockquoteLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
708 {
709     if (!AXAttributedStringRangeIsValid(attrString, range))
710         return;
711     
712     AccessibilityObject* obj = renderer->document().axObjectCache()->getOrCreate(renderer);
713     int quoteLevel = obj->blockquoteLevel();
714     
715     if (quoteLevel)
716         [attrString addAttribute:NSAccessibilityBlockQuoteLevelAttribute value:[NSNumber numberWithInt:quoteLevel] range:range];
717     else
718         [attrString removeAttribute:NSAccessibilityBlockQuoteLevelAttribute range:range];
719 }
720
721 static void AXAttributeStringSetSpelling(NSMutableAttributedString* attrString, Node* node, const UChar* chars, int charLength, NSRange range)
722 {
723     if (unifiedTextCheckerEnabled(node->document().frame())) {
724         // Check the spelling directly since document->markersForNode() does not store the misspelled marking when the cursor is in a word.
725         TextCheckerClient* checker = node->document().frame()->editor().textChecker();
726         
727         // checkTextOfParagraph is the only spelling/grammar checker implemented in WK1 and WK2
728         Vector<TextCheckingResult> results;
729         checkTextOfParagraph(checker, chars, charLength, TextCheckingTypeSpelling, results);
730         
731         size_t size = results.size();
732         NSNumber* trueValue = [NSNumber numberWithBool:YES];
733         for (unsigned i = 0; i < size; i++) {
734             const TextCheckingResult& result = results[i];
735             AXAttributeStringSetNumber(attrString, NSAccessibilityMisspelledTextAttribute, trueValue, NSMakeRange(result.location + range.location, result.length));
736 #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
737             AXAttributeStringSetNumber(attrString, NSAccessibilityMarkedMisspelledTextAttribute, trueValue, NSMakeRange(result.location + range.location, result.length));
738 #endif
739         }
740         return;
741     }
742     
743     int currentPosition = 0;
744     while (charLength > 0) {
745         const UChar* charData = chars + currentPosition;
746         TextCheckerClient* checker = node->document().frame()->editor().textChecker();
747         
748         int misspellingLocation = -1;
749         int misspellingLength = 0;
750         checker->checkSpellingOfString(charData, charLength, &misspellingLocation, &misspellingLength);
751         if (misspellingLocation == -1 || !misspellingLength)
752             break;
753         
754         NSRange spellRange = NSMakeRange(range.location + currentPosition + misspellingLocation, misspellingLength);
755         AXAttributeStringSetNumber(attrString, NSAccessibilityMisspelledTextAttribute, [NSNumber numberWithBool:YES], spellRange);
756 #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
757         AXAttributeStringSetNumber(attrString, NSAccessibilityMarkedMisspelledTextAttribute, [NSNumber numberWithBool:YES], spellRange);
758 #endif
759         charLength -= (misspellingLocation + misspellingLength);
760         currentPosition += (misspellingLocation + misspellingLength);
761     }
762 }
763
764 static void AXAttributeStringSetHeadingLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
765 {
766     if (!renderer)
767         return;
768     
769     if (!AXAttributedStringRangeIsValid(attrString, range))
770         return;
771     
772     // Sometimes there are objects between the text and the heading.
773     // In those cases the parent hierarchy should be queried to see if there is a heading level.
774     int parentHeadingLevel = 0;
775     AccessibilityObject* parentObject = renderer->document().axObjectCache()->getOrCreate(renderer->parent());
776     for (; parentObject; parentObject = parentObject->parentObject()) {
777         parentHeadingLevel = parentObject->headingLevel();
778         if (parentHeadingLevel)
779             break;
780     }
781     
782     if (parentHeadingLevel)
783         [attrString addAttribute:@"AXHeadingLevel" value:[NSNumber numberWithInt:parentHeadingLevel] range:range];
784     else
785         [attrString removeAttribute:@"AXHeadingLevel" range:range];
786 }
787
788 static void AXAttributeStringSetElement(NSMutableAttributedString* attrString, NSString* attribute, AccessibilityObject* object, NSRange range)
789 {
790     if (!AXAttributedStringRangeIsValid(attrString, range))
791         return;
792     
793     if (object && object->isAccessibilityRenderObject()) {
794         // make a serializable AX object
795         
796         RenderObject* renderer = static_cast<AccessibilityRenderObject*>(object)->renderer();
797         if (!renderer)
798             return;
799         
800         AXObjectCache* cache = renderer->document().axObjectCache();
801         if (!cache)
802             return;
803         
804         AXUIElementRef axElement = wkCreateAXUIElementRef(object->wrapper());
805         if (axElement) {
806             [attrString addAttribute:attribute value:(id)axElement range:range];
807             CFRelease(axElement);
808         }
809     } else
810         [attrString removeAttribute:attribute range:range];
811 }
812
813 static void AXAttributedStringAppendText(NSMutableAttributedString* attrString, Node* node, const UChar* chars, int length)
814 {
815     // skip invisible text
816     if (!node->renderer())
817         return;
818     
819     // easier to calculate the range before appending the string
820     NSRange attrStringRange = NSMakeRange([attrString length], length);
821     
822     // append the string from this node
823     [[attrString mutableString] appendString:[NSString stringWithCharacters:chars length:length]];
824     
825     // add new attributes and remove irrelevant inherited ones
826     // NOTE: color attributes are handled specially because -[NSMutableAttributedString addAttribute: value: range:] does not merge
827     // identical colors.  Workaround is to not replace an existing color attribute if it matches what we are adding.  This also means
828     // we cannot just pre-remove all inherited attributes on the appended string, so we have to remove the irrelevant ones individually.
829     
830     // remove inherited attachment from prior AXAttributedStringAppendReplaced
831     [attrString removeAttribute:NSAccessibilityAttachmentTextAttribute range:attrStringRange];
832 #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
833     [attrString removeAttribute:NSAccessibilityMarkedMisspelledTextAttribute range:attrStringRange];
834 #endif
835     [attrString removeAttribute:NSAccessibilityMisspelledTextAttribute range:attrStringRange];
836     
837     // set new attributes
838     AXAttributeStringSetStyle(attrString, node->renderer(), attrStringRange);
839     AXAttributeStringSetHeadingLevel(attrString, node->renderer(), attrStringRange);
840     AXAttributeStringSetBlockquoteLevel(attrString, node->renderer(), attrStringRange);
841     AXAttributeStringSetElement(attrString, NSAccessibilityLinkTextAttribute, AccessibilityObject::anchorElementForNode(node), attrStringRange);
842     
843     // do spelling last because it tends to break up the range
844     AXAttributeStringSetSpelling(attrString, node, chars, length, attrStringRange);
845 }
846
847 static NSString* nsStringForReplacedNode(Node* replacedNode)
848 {
849     // we should always be given a rendered node and a replaced node, but be safe
850     // replaced nodes are either attachments (widgets) or images
851     if (!replacedNode || !replacedNode->renderer() || !replacedNode->renderer()->isReplaced() || replacedNode->isTextNode()) {
852         ASSERT_NOT_REACHED();
853         return nil;
854     }
855     
856     // create an AX object, but skip it if it is not supposed to be seen
857     RefPtr<AccessibilityObject> obj = replacedNode->renderer()->document().axObjectCache()->getOrCreate(replacedNode->renderer());
858     if (obj->accessibilityIsIgnored())
859         return nil;
860     
861     // use the attachmentCharacter to represent the replaced node
862     const UniChar attachmentChar = NSAttachmentCharacter;
863     return [NSString stringWithCharacters:&attachmentChar length:1];
864 }
865
866 - (NSAttributedString*)doAXAttributedStringForTextMarkerRange:(id)textMarkerRange
867 {
868     if (!m_object)
869         return nil;
870     
871     // extract the start and end VisiblePosition
872     VisiblePosition startVisiblePosition = visiblePositionForStartOfTextMarkerRange(m_object->axObjectCache(), textMarkerRange);
873     if (startVisiblePosition.isNull())
874         return nil;
875     
876     VisiblePosition endVisiblePosition = visiblePositionForEndOfTextMarkerRange(m_object->axObjectCache(), textMarkerRange);
877     if (endVisiblePosition.isNull())
878         return nil;
879     
880     VisiblePositionRange visiblePositionRange(startVisiblePosition, endVisiblePosition);
881     // iterate over the range to build the AX attributed string
882     NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] init];
883     TextIterator it(makeRange(startVisiblePosition, endVisiblePosition).get());
884     while (!it.atEnd()) {
885         // locate the node and starting offset for this range
886         int exception = 0;
887         Node* node = it.range()->startContainer(exception);
888         ASSERT(node == it.range()->endContainer(exception));
889         int offset = it.range()->startOffset(exception);
890         
891         // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
892         if (it.length() != 0) {
893             // Add the text of the list marker item if necessary.
894             String listMarkerText = m_object->listMarkerTextForNodeAndPosition(node, VisiblePosition(it.range()->startPosition()));
895             if (!listMarkerText.isEmpty())
896                 AXAttributedStringAppendText(attrString, node, listMarkerText.characters(), listMarkerText.length());
897             
898             AXAttributedStringAppendText(attrString, node, it.characters(), it.length());
899         } else {
900             Node* replacedNode = node->childNode(offset);
901             NSString *attachmentString = nsStringForReplacedNode(replacedNode);
902             if (attachmentString) {
903                 NSRange attrStringRange = NSMakeRange([attrString length], [attachmentString length]);
904                 
905                 // append the placeholder string
906                 [[attrString mutableString] appendString:attachmentString];
907                 
908                 // remove all inherited attributes
909                 [attrString setAttributes:nil range:attrStringRange];
910                 
911                 // add the attachment attribute
912                 AccessibilityObject* obj = replacedNode->renderer()->document().axObjectCache()->getOrCreate(replacedNode->renderer());
913                 AXAttributeStringSetElement(attrString, NSAccessibilityAttachmentTextAttribute, obj, attrStringRange);
914             }
915         }
916         it.advance();
917     }
918     
919     return [attrString autorelease];
920 }
921
922 static id textMarkerRangeFromVisiblePositions(AXObjectCache *cache, VisiblePosition startPosition, VisiblePosition endPosition)
923 {
924     id startTextMarker = textMarkerForVisiblePosition(cache, startPosition);
925     id endTextMarker = textMarkerForVisiblePosition(cache, endPosition);
926     return textMarkerRangeFromMarkers(startTextMarker, endTextMarker);
927 }
928
929 - (id)textMarkerRangeFromVisiblePositions:(VisiblePosition)startPosition endPosition:(VisiblePosition)endPosition
930 {
931     return textMarkerRangeFromVisiblePositions(m_object->axObjectCache(), startPosition, endPosition);
932 }
933
934 - (NSArray*)accessibilityActionNames
935 {
936     if (![self updateObjectBackingStore])
937         return nil;
938     
939     // All elements should get ShowMenu and ScrollToVisible.
940     // But certain earlier VoiceOver versions do not support scroll to visible, and it confuses them to see it in the list.
941 #if __MAC_OS_X_VERSION_MIN_REQUIRED < 1090
942     static NSArray *defaultElementActions = [[NSArray alloc] initWithObjects:NSAccessibilityShowMenuAction, nil];
943 #else
944     static NSArray *defaultElementActions = [[NSArray alloc] initWithObjects:NSAccessibilityShowMenuAction, NSAccessibilityScrollToVisibleAction, nil];
945 #endif
946
947     // Action elements allow Press.
948     // 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.
949 #if __MAC_OS_X_VERSION_MIN_REQUIRED < 1090
950     static NSArray *actionElementActions = [[NSArray alloc] initWithObjects:NSAccessibilityPressAction, NSAccessibilityShowMenuAction, nil];
951 #else
952     static NSArray *actionElementActions = [[NSArray alloc] initWithObjects:NSAccessibilityPressAction, NSAccessibilityShowMenuAction, NSAccessibilityScrollToVisibleAction, nil];
953 #endif
954
955     // Menu elements allow Press and Cancel.
956     static NSArray *menuElementActions = [[actionElementActions arrayByAddingObject:NSAccessibilityCancelAction] retain];
957
958     // Slider elements allow Increment/Decrement.
959     static NSArray *sliderActions = [[defaultElementActions arrayByAddingObjectsFromArray:[NSArray arrayWithObjects:NSAccessibilityIncrementAction, NSAccessibilityDecrementAction, nil]] retain];
960     
961     NSArray *actions;
962     if (m_object->actionElement() || m_object->isButton())
963         actions = actionElementActions;
964     else if (m_object->isMenuRelated())
965         actions = menuElementActions;
966     else if (m_object->isSlider())
967         actions = sliderActions;
968     else if (m_object->isAttachment())
969         actions = [[self attachmentView] accessibilityActionNames];
970     else
971         actions = defaultElementActions;
972     
973     return actions;
974 }
975
976 - (NSArray*)additionalAccessibilityAttributeNames
977 {
978     if (!m_object)
979         return nil;
980     
981     NSMutableArray *additional = [NSMutableArray array];
982     if (m_object->supportsARIAOwns())
983         [additional addObject:NSAccessibilityOwnsAttribute];
984     
985     if (m_object->supportsARIAExpanded())
986         [additional addObject:NSAccessibilityExpandedAttribute];
987     
988     if (m_object->isScrollbar())
989         [additional addObject:NSAccessibilityOrientationAttribute];
990     
991     if (m_object->supportsARIADragging())
992         [additional addObject:NSAccessibilityGrabbedAttribute];
993     
994     if (m_object->supportsARIADropping())
995         [additional addObject:NSAccessibilityDropEffectsAttribute];
996     
997     if (m_object->isAccessibilityTable() && static_cast<AccessibilityTable*>(m_object)->supportsSelectedRows())
998         [additional addObject:NSAccessibilitySelectedRowsAttribute];
999     
1000     if (m_object->supportsARIALiveRegion()) {
1001         [additional addObject:NSAccessibilityARIALiveAttribute];
1002         [additional addObject:NSAccessibilityARIARelevantAttribute];
1003     }
1004     
1005     if (m_object->supportsARIASetSize())
1006         [additional addObject:NSAccessibilityARIASetSizeAttribute];
1007     if (m_object->supportsARIAPosInSet())
1008         [additional addObject:NSAccessibilityARIAPosInSetAttribute];
1009     
1010     if (m_object->sortDirection() != SortDirectionNone)
1011         [additional addObject:NSAccessibilitySortDirectionAttribute];
1012     
1013     // If an object is a child of a live region, then add these
1014     if (m_object->isInsideARIALiveRegion())
1015         [additional addObject:NSAccessibilityARIAAtomicAttribute];
1016     // All objects should expose the ARIA busy attribute (ARIA 1.1 with ISSUE-538).
1017     [additional addObject:NSAccessibilityElementBusyAttribute];
1018     
1019     // Popup buttons on the Mac expose the value attribute.
1020     if (m_object->isPopUpButton()) {
1021         [additional addObject:NSAccessibilityValueAttribute];
1022     }
1023
1024     if (m_object->supportsRequiredAttribute()) {
1025         [additional addObject:NSAccessibilityRequiredAttribute];
1026     }
1027     
1028     if (m_object->ariaHasPopup())
1029         [additional addObject:NSAccessibilityHasPopupAttribute];
1030     
1031     if (m_object->isMathRoot()) {
1032         // The index of a square root is always known, so there's no object associated with it.
1033         if (!m_object->isMathSquareRoot())
1034             [additional addObject:NSAccessibilityMathRootIndexAttribute];
1035         [additional addObject:NSAccessibilityMathRootRadicandAttribute];
1036     } else if (m_object->isMathFraction()) {
1037         [additional addObject:NSAccessibilityMathFractionNumeratorAttribute];
1038         [additional addObject:NSAccessibilityMathFractionDenominatorAttribute];
1039         [additional addObject:NSAccessibilityMathLineThicknessAttribute];
1040     } else if (m_object->isMathSubscriptSuperscript()) {
1041         [additional addObject:NSAccessibilityMathBaseAttribute];
1042         [additional addObject:NSAccessibilityMathSubscriptAttribute];
1043         [additional addObject:NSAccessibilityMathSuperscriptAttribute];
1044     } else if (m_object->isMathUnderOver()) {
1045         [additional addObject:NSAccessibilityMathBaseAttribute];
1046         [additional addObject:NSAccessibilityMathUnderAttribute];
1047         [additional addObject:NSAccessibilityMathOverAttribute];
1048     } else if (m_object->isMathFenced()) {
1049         [additional addObject:NSAccessibilityMathFencedOpenAttribute];
1050         [additional addObject:NSAccessibilityMathFencedCloseAttribute];
1051     } else if (m_object->isMathMultiscript()) {
1052         [additional addObject:NSAccessibilityMathBaseAttribute];
1053         [additional addObject:NSAccessibilityMathPrescriptsAttribute];
1054         [additional addObject:NSAccessibilityMathPostscriptsAttribute];
1055     }
1056     
1057     if (m_object->supportsPath())
1058         [additional addObject:NSAccessibilityPathAttribute];
1059     
1060     return additional;
1061 }
1062
1063 - (NSArray*)accessibilityAttributeNames
1064 {
1065     if (![self updateObjectBackingStore])
1066         return nil;
1067     
1068     if (m_object->isAttachment())
1069         return [[self attachmentView] accessibilityAttributeNames];
1070     
1071     static NSArray* attributes = nil;
1072     static NSArray* anchorAttrs = nil;
1073     static NSArray* webAreaAttrs = nil;
1074     static NSArray* textAttrs = nil;
1075     static NSArray* listAttrs = nil;
1076     static NSArray* listBoxAttrs = nil;
1077     static NSArray* rangeAttrs = nil;
1078     static NSArray* commonMenuAttrs = nil;
1079     static NSArray* menuAttrs = nil;
1080     static NSArray* menuBarAttrs = nil;
1081     static NSArray* menuItemAttrs = nil;
1082     static NSArray* menuButtonAttrs = nil;
1083     static NSArray* controlAttrs = nil;
1084     static NSArray* tableAttrs = nil;
1085     static NSArray* tableRowAttrs = nil;
1086     static NSArray* tableColAttrs = nil;
1087     static NSArray* tableCellAttrs = nil;
1088     static NSArray* groupAttrs = nil;
1089     static NSArray* inputImageAttrs = nil;
1090     static NSArray* passwordFieldAttrs = nil;
1091     static NSArray* tabListAttrs = nil;
1092     static NSArray* comboBoxAttrs = nil;
1093     static NSArray* outlineAttrs = nil;
1094     static NSArray* outlineRowAttrs = nil;
1095     static NSArray* buttonAttrs = nil;
1096     static NSArray* scrollViewAttrs = nil;
1097     static NSArray* incrementorAttrs = nil;
1098     NSMutableArray* tempArray;
1099     if (attributes == nil) {
1100         attributes = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute,
1101                       NSAccessibilitySubroleAttribute,
1102                       NSAccessibilityRoleDescriptionAttribute,
1103                       NSAccessibilityChildrenAttribute,
1104                       NSAccessibilityHelpAttribute,
1105                       NSAccessibilityParentAttribute,
1106                       NSAccessibilityPositionAttribute,
1107                       NSAccessibilitySizeAttribute,
1108                       NSAccessibilityTitleAttribute,
1109                       NSAccessibilityDescriptionAttribute,
1110                       NSAccessibilityValueAttribute,
1111                       NSAccessibilityFocusedAttribute,
1112                       NSAccessibilityEnabledAttribute,
1113                       NSAccessibilityWindowAttribute,
1114                       @"AXSelectedTextMarkerRange",
1115                       @"AXStartTextMarker",
1116                       @"AXEndTextMarker",
1117                       @"AXVisited",
1118                       NSAccessibilityLinkedUIElementsAttribute,
1119                       NSAccessibilitySelectedAttribute,
1120                       NSAccessibilityBlockQuoteLevelAttribute,
1121                       NSAccessibilityTopLevelUIElementAttribute,
1122                       NSAccessibilityLanguageAttribute,
1123                       NSAccessibilityDOMIdentifierAttribute,
1124                       NSAccessibilityDOMClassListAttribute,
1125                       nil];
1126     }
1127     if (commonMenuAttrs == nil) {
1128         commonMenuAttrs = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute,
1129                            NSAccessibilityRoleDescriptionAttribute,
1130                            NSAccessibilityChildrenAttribute,
1131                            NSAccessibilityParentAttribute,
1132                            NSAccessibilityEnabledAttribute,
1133                            NSAccessibilityPositionAttribute,
1134                            NSAccessibilitySizeAttribute,
1135                            nil];
1136     }
1137     if (anchorAttrs == nil) {
1138         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1139         [tempArray addObject:NSAccessibilityURLAttribute];
1140         [tempArray addObject:NSAccessibilityAccessKeyAttribute];
1141         anchorAttrs = [[NSArray alloc] initWithArray:tempArray];
1142         [tempArray release];
1143     }
1144     if (webAreaAttrs == nil) {
1145         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1146         // WebAreas should not expose AXSubrole.
1147         [tempArray removeObject:NSAccessibilitySubroleAttribute];
1148         [tempArray addObject:@"AXLinkUIElements"];
1149         [tempArray addObject:@"AXLoaded"];
1150         [tempArray addObject:@"AXLayoutCount"];
1151         [tempArray addObject:NSAccessibilityLoadingProgressAttribute];
1152         [tempArray addObject:NSAccessibilityURLAttribute];
1153         webAreaAttrs = [[NSArray alloc] initWithArray:tempArray];
1154         [tempArray release];
1155     }
1156     if (textAttrs == nil) {
1157         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1158         [tempArray addObject:NSAccessibilityNumberOfCharactersAttribute];
1159         [tempArray addObject:NSAccessibilitySelectedTextAttribute];
1160         [tempArray addObject:NSAccessibilitySelectedTextRangeAttribute];
1161         [tempArray addObject:NSAccessibilityVisibleCharacterRangeAttribute];
1162         [tempArray addObject:NSAccessibilityInsertionPointLineNumberAttribute];
1163         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1164         [tempArray addObject:NSAccessibilityAccessKeyAttribute];
1165         [tempArray addObject:NSAccessibilityRequiredAttribute];
1166         [tempArray addObject:NSAccessibilityInvalidAttribute];
1167         [tempArray addObject:NSAccessibilityPlaceholderValueAttribute];
1168         textAttrs = [[NSArray alloc] initWithArray:tempArray];
1169         [tempArray release];
1170     }
1171     if (listAttrs == nil) {
1172         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1173         [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
1174         [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
1175         [tempArray addObject:NSAccessibilityOrientationAttribute];
1176         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1177         listAttrs = [[NSArray alloc] initWithArray:tempArray];
1178         [tempArray release];
1179     }
1180     if (listBoxAttrs == nil) {
1181         tempArray = [[NSMutableArray alloc] initWithArray:listAttrs];
1182         [tempArray addObject:NSAccessibilityAccessKeyAttribute];
1183         [tempArray addObject:NSAccessibilityRequiredAttribute];
1184         [tempArray addObject:NSAccessibilityInvalidAttribute];
1185         listBoxAttrs = [[NSArray alloc] initWithArray:tempArray];
1186         [tempArray release];
1187     }
1188     if (rangeAttrs == nil) {
1189         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1190         [tempArray addObject:NSAccessibilityMinValueAttribute];
1191         [tempArray addObject:NSAccessibilityMaxValueAttribute];
1192         [tempArray addObject:NSAccessibilityOrientationAttribute];
1193         [tempArray addObject:NSAccessibilityValueDescriptionAttribute];
1194         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1195         rangeAttrs = [[NSArray alloc] initWithArray:tempArray];
1196         [tempArray release];
1197     }
1198     if (menuBarAttrs == nil) {
1199         tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
1200         [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
1201         [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
1202         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1203         menuBarAttrs = [[NSArray alloc] initWithArray:tempArray];
1204         [tempArray release];
1205     }
1206     if (menuAttrs == nil) {
1207         tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
1208         [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
1209         [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
1210         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1211         menuAttrs = [[NSArray alloc] initWithArray:tempArray];
1212         [tempArray release];
1213     }
1214     if (menuItemAttrs == nil) {
1215         tempArray = [[NSMutableArray alloc] initWithArray:commonMenuAttrs];
1216         [tempArray addObject:NSAccessibilityTitleAttribute];
1217         [tempArray addObject:NSAccessibilityHelpAttribute];
1218         [tempArray addObject:NSAccessibilitySelectedAttribute];
1219         [tempArray addObject:NSAccessibilityValueAttribute];
1220         [tempArray addObject:(NSString*)kAXMenuItemCmdCharAttribute];
1221         [tempArray addObject:(NSString*)kAXMenuItemCmdVirtualKeyAttribute];
1222         [tempArray addObject:(NSString*)kAXMenuItemCmdGlyphAttribute];
1223         [tempArray addObject:(NSString*)kAXMenuItemCmdModifiersAttribute];
1224         [tempArray addObject:(NSString*)kAXMenuItemMarkCharAttribute];
1225         [tempArray addObject:(NSString*)kAXMenuItemPrimaryUIElementAttribute];
1226         [tempArray addObject:NSAccessibilityServesAsTitleForUIElementsAttribute];
1227         menuItemAttrs = [[NSArray alloc] initWithArray:tempArray];
1228         [tempArray release];
1229     }
1230     if (menuButtonAttrs == nil) {
1231         menuButtonAttrs = [[NSArray alloc] initWithObjects:NSAccessibilityRoleAttribute,
1232                            NSAccessibilityRoleDescriptionAttribute,
1233                            NSAccessibilityParentAttribute,
1234                            NSAccessibilityPositionAttribute,
1235                            NSAccessibilitySizeAttribute,
1236                            NSAccessibilityWindowAttribute,
1237                            NSAccessibilityEnabledAttribute,
1238                            NSAccessibilityFocusedAttribute,
1239                            NSAccessibilityTitleAttribute,
1240                            NSAccessibilityChildrenAttribute, nil];
1241     }
1242     if (controlAttrs == nil) {
1243         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1244         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1245         [tempArray addObject:NSAccessibilityAccessKeyAttribute];
1246         [tempArray addObject:NSAccessibilityRequiredAttribute];
1247         [tempArray addObject:NSAccessibilityInvalidAttribute];
1248         controlAttrs = [[NSArray alloc] initWithArray:tempArray];
1249         [tempArray release];
1250     }
1251     if (incrementorAttrs == nil) {
1252         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1253         [tempArray addObject:NSAccessibilityIncrementButtonAttribute];
1254         [tempArray addObject:NSAccessibilityDecrementButtonAttribute];
1255         [tempArray addObject:NSAccessibilityValueDescriptionAttribute];
1256         [tempArray addObject:NSAccessibilityMinValueAttribute];
1257         [tempArray addObject:NSAccessibilityMaxValueAttribute];
1258         incrementorAttrs = [[NSArray alloc] initWithArray:tempArray];
1259         [tempArray release];
1260     }
1261     if (buttonAttrs == nil) {
1262         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1263         // Buttons should not expose AXValue.
1264         [tempArray removeObject:NSAccessibilityValueAttribute];
1265         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1266         [tempArray addObject:NSAccessibilityAccessKeyAttribute];
1267         buttonAttrs = [[NSArray alloc] initWithArray:tempArray];
1268         [tempArray release];
1269     }
1270     if (comboBoxAttrs == nil) {
1271         tempArray = [[NSMutableArray alloc] initWithArray:controlAttrs];
1272         [tempArray addObject:NSAccessibilityExpandedAttribute];
1273         comboBoxAttrs = [[NSArray alloc] initWithArray:tempArray];
1274         [tempArray release];
1275     }
1276     if (tableAttrs == nil) {
1277         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1278         [tempArray addObject:NSAccessibilityRowsAttribute];
1279         [tempArray addObject:NSAccessibilityVisibleRowsAttribute];
1280         [tempArray addObject:NSAccessibilityColumnsAttribute];
1281         [tempArray addObject:NSAccessibilityVisibleColumnsAttribute];
1282         [tempArray addObject:NSAccessibilityVisibleCellsAttribute];
1283         [tempArray addObject:(NSString *)kAXColumnHeaderUIElementsAttribute];
1284         [tempArray addObject:NSAccessibilityRowHeaderUIElementsAttribute];
1285         [tempArray addObject:NSAccessibilityHeaderAttribute];
1286         tableAttrs = [[NSArray alloc] initWithArray:tempArray];
1287         [tempArray release];
1288     }
1289     if (tableRowAttrs == nil) {
1290         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1291         [tempArray addObject:NSAccessibilityIndexAttribute];
1292         tableRowAttrs = [[NSArray alloc] initWithArray:tempArray];
1293         [tempArray release];
1294     }
1295     if (tableColAttrs == nil) {
1296         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1297         [tempArray addObject:NSAccessibilityIndexAttribute];
1298         [tempArray addObject:NSAccessibilityHeaderAttribute];
1299         [tempArray addObject:NSAccessibilityRowsAttribute];
1300         [tempArray addObject:NSAccessibilityVisibleRowsAttribute];
1301         tableColAttrs = [[NSArray alloc] initWithArray:tempArray];
1302         [tempArray release];
1303     }
1304     if (tableCellAttrs == nil) {
1305         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1306         [tempArray addObject:NSAccessibilityRowIndexRangeAttribute];
1307         [tempArray addObject:NSAccessibilityColumnIndexRangeAttribute];
1308         tableCellAttrs = [[NSArray alloc] initWithArray:tempArray];
1309         [tempArray release];
1310     }
1311     if (groupAttrs == nil) {
1312         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1313         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1314         groupAttrs = [[NSArray alloc] initWithArray:tempArray];
1315         [tempArray release];
1316     }
1317     if (inputImageAttrs == nil) {
1318         tempArray = [[NSMutableArray alloc] initWithArray:buttonAttrs];
1319         [tempArray addObject:NSAccessibilityURLAttribute];
1320         inputImageAttrs = [[NSArray alloc] initWithArray:tempArray];
1321         [tempArray release];
1322     }
1323     if (passwordFieldAttrs == nil) {
1324         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1325         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1326         [tempArray addObject:NSAccessibilityRequiredAttribute];
1327         [tempArray addObject:NSAccessibilityInvalidAttribute];
1328         [tempArray addObject:NSAccessibilityPlaceholderValueAttribute];
1329         passwordFieldAttrs = [[NSArray alloc] initWithArray:tempArray];
1330         [tempArray release];
1331     }
1332     if (tabListAttrs == nil) {
1333         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1334         [tempArray addObject:NSAccessibilityTabsAttribute];
1335         [tempArray addObject:NSAccessibilityContentsAttribute];
1336         tabListAttrs = [[NSArray alloc] initWithArray:tempArray];
1337         [tempArray release];
1338     }
1339     if (outlineAttrs == nil) {
1340         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1341         [tempArray addObject:NSAccessibilitySelectedRowsAttribute];
1342         [tempArray addObject:NSAccessibilityRowsAttribute];
1343         [tempArray addObject:NSAccessibilityColumnsAttribute];
1344         outlineAttrs = [[NSArray alloc] initWithArray:tempArray];
1345         [tempArray release];
1346     }
1347     if (outlineRowAttrs == nil) {
1348         tempArray = [[NSMutableArray alloc] initWithArray:tableRowAttrs];
1349         [tempArray addObject:NSAccessibilityDisclosingAttribute];
1350         [tempArray addObject:NSAccessibilityDisclosedByRowAttribute];
1351         [tempArray addObject:NSAccessibilityDisclosureLevelAttribute];
1352         [tempArray addObject:NSAccessibilityDisclosedRowsAttribute];
1353         outlineRowAttrs = [[NSArray alloc] initWithArray:tempArray];
1354         [tempArray release];
1355     }
1356     if (scrollViewAttrs == nil) {
1357         tempArray = [[NSMutableArray alloc] initWithArray:attributes];
1358         [tempArray addObject:NSAccessibilityContentsAttribute];
1359         [tempArray addObject:NSAccessibilityHorizontalScrollBarAttribute];
1360         [tempArray addObject:NSAccessibilityVerticalScrollBarAttribute];
1361         scrollViewAttrs = [[NSArray alloc] initWithArray:tempArray];
1362         [tempArray release];
1363     }
1364     
1365     NSArray *objectAttributes = attributes;
1366     
1367     if (m_object->isPasswordField())
1368         objectAttributes = passwordFieldAttrs;
1369     
1370     else if (m_object->isWebArea())
1371         objectAttributes = webAreaAttrs;
1372     
1373     else if (m_object->isTextControl())
1374         objectAttributes = textAttrs;
1375     
1376     else if (m_object->isAnchor() || m_object->isImage() || m_object->isLink())
1377         objectAttributes = anchorAttrs;
1378     
1379     else if (m_object->isAccessibilityTable())
1380         objectAttributes = tableAttrs;
1381     else if (m_object->isTableColumn())
1382         objectAttributes = tableColAttrs;
1383     else if (m_object->isTableCell())
1384         objectAttributes = tableCellAttrs;
1385     else if (m_object->isTableRow()) {
1386         // An ARIA table row can be collapsed and expanded, so it needs the extra attributes.
1387         if (m_object->isARIATreeGridRow())
1388             objectAttributes = outlineRowAttrs;
1389         else
1390             objectAttributes = tableRowAttrs;
1391     }
1392     
1393     else if (m_object->isTree())
1394         objectAttributes = outlineAttrs;
1395     else if (m_object->isTreeItem())
1396         objectAttributes = outlineRowAttrs;
1397     
1398     else if (m_object->isListBox())
1399         objectAttributes = listBoxAttrs;
1400     else if (m_object->isList())
1401         objectAttributes = listAttrs;
1402     
1403     else if (m_object->isComboBox())
1404         objectAttributes = comboBoxAttrs;
1405     
1406     else if (m_object->isProgressIndicator() || m_object->isSlider())
1407         objectAttributes = rangeAttrs;
1408     
1409     // These are processed in order because an input image is a button, and a button is a control.
1410     else if (m_object->isInputImage())
1411         objectAttributes = inputImageAttrs;
1412     else if (m_object->isButton())
1413         objectAttributes = buttonAttrs;
1414     else if (m_object->isControl())
1415         objectAttributes = controlAttrs;
1416     
1417     else if (m_object->isGroup() || m_object->isListItem())
1418         objectAttributes = groupAttrs;
1419     else if (m_object->isTabList())
1420         objectAttributes = tabListAttrs;
1421     else if (m_object->isScrollView())
1422         objectAttributes = scrollViewAttrs;
1423     else if (m_object->isSpinButton())
1424         objectAttributes = incrementorAttrs;
1425     
1426     else if (m_object->isMenu())
1427         objectAttributes = menuAttrs;
1428     else if (m_object->isMenuBar())
1429         objectAttributes = menuBarAttrs;
1430     else if (m_object->isMenuButton())
1431         objectAttributes = menuButtonAttrs;
1432     else if (m_object->isMenuItem())
1433         objectAttributes = menuItemAttrs;
1434     
1435     NSArray *additionalAttributes = [self additionalAccessibilityAttributeNames];
1436     if ([additionalAttributes count])
1437         objectAttributes = [objectAttributes arrayByAddingObjectsFromArray:additionalAttributes];
1438     
1439     return objectAttributes;
1440 }
1441
1442 - (VisiblePositionRange)visiblePositionRangeForTextMarkerRange:(id)textMarkerRange
1443 {
1444     if (!textMarkerRange)
1445         return VisiblePositionRange();
1446     AXObjectCache* cache = m_object->axObjectCache();
1447     return VisiblePositionRange(visiblePositionForStartOfTextMarkerRange(cache, textMarkerRange), visiblePositionForEndOfTextMarkerRange(cache, textMarkerRange));
1448 }
1449
1450 - (NSArray*)renderWidgetChildren
1451 {
1452     Widget* widget = m_object->widget();
1453     if (!widget)
1454         return nil;
1455     return [(widget->platformWidget()) accessibilityAttributeValue: NSAccessibilityChildrenAttribute];
1456 }
1457
1458 - (id)remoteAccessibilityParentObject
1459 {
1460     if (!m_object)
1461         return nil;
1462     
1463     Document* document = m_object->document();
1464     if (!document)
1465         return nil;
1466     
1467     Frame* frame = document->frame();
1468     if (!frame)
1469         return nil;
1470     
1471     return frame->loader().client().accessibilityRemoteObject();
1472 }
1473
1474 static void convertToVector(NSArray* array, AccessibilityObject::AccessibilityChildrenVector& vector)
1475 {
1476     unsigned length = [array count];
1477     vector.reserveInitialCapacity(length);
1478     for (unsigned i = 0; i < length; ++i) {
1479         AccessibilityObject* obj = [[array objectAtIndex:i] accessibilityObject];
1480         if (obj)
1481             vector.append(obj);
1482     }
1483 }
1484
1485 static NSMutableArray* convertToNSArray(const AccessibilityObject::AccessibilityChildrenVector& vector)
1486 {
1487     unsigned length = vector.size();
1488     NSMutableArray* array = [NSMutableArray arrayWithCapacity: length];
1489     for (unsigned i = 0; i < length; ++i) {
1490         WebAccessibilityObjectWrapper* wrapper = vector[i]->wrapper();
1491         ASSERT(wrapper);
1492         if (wrapper) {
1493             // we want to return the attachment view instead of the object representing the attachment.
1494             // otherwise, we get palindrome errors in the AX hierarchy
1495             if (vector[i]->isAttachment() && [wrapper attachmentView])
1496                 [array addObject:[wrapper attachmentView]];
1497             else
1498                 [array addObject:wrapper];
1499         }
1500     }
1501     return array;
1502 }
1503
1504 static NSMutableArray *convertStringsToNSArray(const Vector<String>& vector)
1505 {
1506     size_t length = vector.size();
1507     NSMutableArray *array = [NSMutableArray arrayWithCapacity:length];
1508     for (size_t i = 0; i < length; ++i)
1509         [array addObject:vector[i]];
1510     return array;
1511 }
1512
1513 - (id)textMarkerRangeForSelection
1514 {
1515     VisibleSelection selection = m_object->selection();
1516     if (selection.isNone())
1517         return nil;
1518     return [self textMarkerRangeFromVisiblePositions:selection.visibleStart() endPosition:selection.visibleEnd()];
1519 }
1520
1521 - (CGPoint)convertPointToScreenSpace:(FloatPoint &)point
1522 {
1523     FrameView* frameView = m_object->documentFrameView();
1524     
1525     // WebKit1 code path... platformWidget() exists.
1526     if (frameView && frameView->platformWidget()) {
1527         
1528         NSPoint nsPoint = (NSPoint)point;
1529         NSView* view = frameView->documentView();
1530         nsPoint = [[view window] convertBaseToScreen:[view convertPoint:nsPoint toView:nil]];
1531         return CGPointMake(nsPoint.x, nsPoint.y);
1532
1533     } else {
1534         
1535         // Find the appropriate scroll view to use to convert the contents to the window.
1536         ScrollView* scrollView = 0;
1537         AccessibilityObject* parent = 0;
1538         for (parent = m_object->parentObject(); parent; parent = parent->parentObject()) {
1539             if (parent->isAccessibilityScrollView()) {
1540                 scrollView = toAccessibilityScrollView(parent)->scrollView();
1541                 break;
1542             }
1543         }
1544         
1545         IntPoint intPoint = flooredIntPoint(point);
1546         if (scrollView)
1547             intPoint = scrollView->contentsToRootView(intPoint);
1548         
1549         Page* page = m_object->page();
1550         
1551         // If we have an empty chrome client (like SVG) then we should use the page
1552         // of the scroll view parent to help us get to the screen rect.
1553         if (parent && page && page->chrome().client().isEmptyChromeClient())
1554             page = parent->page();
1555         
1556         if (page) {
1557             IntRect rect = IntRect(intPoint, IntSize(0, 0));            
1558             intPoint = page->chrome().rootViewToScreen(rect).location();
1559         }
1560         
1561         return intPoint;
1562     }
1563 }
1564
1565 static void WebTransformCGPathToNSBezierPath(void *info, const CGPathElement *element)
1566 {
1567     NSBezierPath *bezierPath = (NSBezierPath *)info;
1568     switch (element->type) {
1569     case kCGPathElementMoveToPoint:
1570         [bezierPath moveToPoint:NSPointFromCGPoint(element->points[0])];
1571         break;
1572     case kCGPathElementAddLineToPoint:
1573         [bezierPath lineToPoint:NSPointFromCGPoint(element->points[0])];
1574         break;
1575     case kCGPathElementAddCurveToPoint:
1576         [bezierPath curveToPoint:NSPointFromCGPoint(element->points[0]) controlPoint1:NSPointFromCGPoint(element->points[1]) controlPoint2:NSPointFromCGPoint(element->points[2])];
1577         break;
1578     case kCGPathElementCloseSubpath:
1579         [bezierPath closePath];
1580         break;
1581     default:
1582         break;
1583     }
1584 }
1585
1586 - (NSBezierPath *)bezierPathFromPath:(CGPathRef)path
1587 {
1588     NSBezierPath *bezierPath = [NSBezierPath bezierPath];
1589     CGPathApply(path, bezierPath, WebTransformCGPathToNSBezierPath);
1590     return bezierPath;
1591 }
1592
1593 - (NSBezierPath *)path
1594 {
1595     Path path = m_object->elementPath();
1596     if (path.isEmpty())
1597         return NULL;
1598     
1599     CGPathRef transformedPath = [self convertPathToScreenSpace:path];
1600     return [self bezierPathFromPath:transformedPath];
1601 }
1602
1603 - (NSValue *)position
1604 {
1605     IntRect rect = pixelSnappedIntRect(m_object->elementRect());
1606     
1607     // The Cocoa accessibility API wants the lower-left corner.
1608     FloatPoint floatPoint = FloatPoint(rect.x(), rect.maxY());
1609
1610     CGPoint cgPoint = [self convertPointToScreenSpace:floatPoint];
1611     
1612     return [NSValue valueWithPoint:NSMakePoint(cgPoint.x, cgPoint.y)];
1613 }
1614
1615 typedef HashMap<int, NSString*> AccessibilityRoleMap;
1616
1617 static const AccessibilityRoleMap& createAccessibilityRoleMap()
1618 {
1619     struct RoleEntry {
1620         AccessibilityRole value;
1621         NSString* string;
1622     };
1623     
1624     static const RoleEntry roles[] = {
1625         { UnknownRole, NSAccessibilityUnknownRole },
1626         { ButtonRole, NSAccessibilityButtonRole },
1627         { RadioButtonRole, NSAccessibilityRadioButtonRole },
1628         { CheckBoxRole, NSAccessibilityCheckBoxRole },
1629         { SliderRole, NSAccessibilitySliderRole },
1630         { TabGroupRole, NSAccessibilityTabGroupRole },
1631         { TextFieldRole, NSAccessibilityTextFieldRole },
1632         { StaticTextRole, NSAccessibilityStaticTextRole },
1633         { TextAreaRole, NSAccessibilityTextAreaRole },
1634         { ScrollAreaRole, NSAccessibilityScrollAreaRole },
1635         { PopUpButtonRole, NSAccessibilityPopUpButtonRole },
1636         { MenuButtonRole, NSAccessibilityMenuButtonRole },
1637         { TableRole, NSAccessibilityTableRole },
1638         { ApplicationRole, NSAccessibilityApplicationRole },
1639         { GroupRole, NSAccessibilityGroupRole },
1640         { RadioGroupRole, NSAccessibilityRadioGroupRole },
1641         { ListRole, NSAccessibilityListRole },
1642         { DirectoryRole, NSAccessibilityListRole },
1643         { ScrollBarRole, NSAccessibilityScrollBarRole },
1644         { ValueIndicatorRole, NSAccessibilityValueIndicatorRole },
1645         { ImageRole, NSAccessibilityImageRole },
1646         { MenuBarRole, NSAccessibilityMenuBarRole },
1647         { MenuRole, NSAccessibilityMenuRole },
1648         { MenuItemRole, NSAccessibilityMenuItemRole },
1649         { MenuItemCheckboxRole, NSAccessibilityMenuItemRole },
1650         { MenuItemRadioRole, NSAccessibilityMenuItemRole },
1651         { ColumnRole, NSAccessibilityColumnRole },
1652         { RowRole, NSAccessibilityRowRole },
1653         { ToolbarRole, NSAccessibilityToolbarRole },
1654         { BusyIndicatorRole, NSAccessibilityBusyIndicatorRole },
1655         { ProgressIndicatorRole, NSAccessibilityProgressIndicatorRole },
1656         { WindowRole, NSAccessibilityWindowRole },
1657         { DrawerRole, NSAccessibilityDrawerRole },
1658         { SystemWideRole, NSAccessibilitySystemWideRole },
1659         { OutlineRole, NSAccessibilityOutlineRole },
1660         { IncrementorRole, NSAccessibilityIncrementorRole },
1661         { BrowserRole, NSAccessibilityBrowserRole },
1662         { ComboBoxRole, NSAccessibilityComboBoxRole },
1663         { SplitGroupRole, NSAccessibilitySplitGroupRole },
1664         { SplitterRole, NSAccessibilitySplitterRole },
1665         { ColorWellRole, NSAccessibilityColorWellRole },
1666         { GrowAreaRole, NSAccessibilityGrowAreaRole },
1667         { SheetRole, NSAccessibilitySheetRole },
1668         { HelpTagRole, NSAccessibilityHelpTagRole },
1669         { MatteRole, NSAccessibilityMatteRole },
1670         { RulerRole, NSAccessibilityRulerRole },
1671         { RulerMarkerRole, NSAccessibilityRulerMarkerRole },
1672         { LinkRole, NSAccessibilityLinkRole },
1673         { DisclosureTriangleRole, NSAccessibilityDisclosureTriangleRole },
1674         { GridRole, NSAccessibilityGridRole },
1675         { WebCoreLinkRole, NSAccessibilityLinkRole },
1676         { ImageMapLinkRole, NSAccessibilityLinkRole },
1677         { ImageMapRole, @"AXImageMap" },
1678         { ListMarkerRole, @"AXListMarker" },
1679         { WebAreaRole, @"AXWebArea" },
1680         { SeamlessWebAreaRole, NSAccessibilityGroupRole },
1681         { HeadingRole, @"AXHeading" },
1682         { ListBoxRole, NSAccessibilityListRole },
1683         { ListBoxOptionRole, NSAccessibilityStaticTextRole },
1684         { CellRole, NSAccessibilityCellRole },
1685         { TableHeaderContainerRole, NSAccessibilityGroupRole },
1686         { RowHeaderRole, NSAccessibilityGroupRole },
1687         { DefinitionRole, NSAccessibilityGroupRole },
1688         { DescriptionListDetailRole, NSAccessibilityGroupRole },
1689         { DescriptionListTermRole, NSAccessibilityGroupRole },
1690         { DescriptionListRole, NSAccessibilityListRole },
1691         { SliderThumbRole, NSAccessibilityValueIndicatorRole },
1692         { LandmarkApplicationRole, NSAccessibilityGroupRole },
1693         { LandmarkBannerRole, NSAccessibilityGroupRole },
1694         { LandmarkComplementaryRole, NSAccessibilityGroupRole },
1695         { LandmarkContentInfoRole, NSAccessibilityGroupRole },
1696         { LandmarkMainRole, NSAccessibilityGroupRole },
1697         { LandmarkNavigationRole, NSAccessibilityGroupRole },
1698         { LandmarkSearchRole, NSAccessibilityGroupRole },
1699         { ApplicationAlertRole, NSAccessibilityGroupRole },
1700         { ApplicationAlertDialogRole, NSAccessibilityGroupRole },
1701         { ApplicationDialogRole, NSAccessibilityGroupRole },
1702         { ApplicationLogRole, NSAccessibilityGroupRole },
1703         { ApplicationMarqueeRole, NSAccessibilityGroupRole },
1704         { ApplicationStatusRole, NSAccessibilityGroupRole },
1705         { ApplicationTimerRole, NSAccessibilityGroupRole },
1706         { DocumentRole, NSAccessibilityGroupRole },
1707         { DocumentArticleRole, NSAccessibilityGroupRole },
1708         { DocumentMathRole, NSAccessibilityGroupRole },
1709         { DocumentNoteRole, NSAccessibilityGroupRole },
1710         { DocumentRegionRole, NSAccessibilityGroupRole },
1711         { UserInterfaceTooltipRole, NSAccessibilityGroupRole },
1712         { TabRole, NSAccessibilityRadioButtonRole },
1713         { TabListRole, NSAccessibilityTabGroupRole },
1714         { TabPanelRole, NSAccessibilityGroupRole },
1715         { TreeRole, NSAccessibilityOutlineRole },
1716         { TreeItemRole, NSAccessibilityRowRole },
1717         { ListItemRole, NSAccessibilityGroupRole },
1718         { ParagraphRole, NSAccessibilityGroupRole },
1719         { LabelRole, NSAccessibilityGroupRole },
1720         { DivRole, NSAccessibilityGroupRole },
1721         { FormRole, NSAccessibilityGroupRole },
1722         { SpinButtonRole, NSAccessibilityIncrementorRole },
1723         { FooterRole, NSAccessibilityGroupRole },
1724         { ToggleButtonRole, NSAccessibilityButtonRole },
1725         { CanvasRole, NSAccessibilityImageRole },
1726         { SVGRootRole, NSAccessibilityGroupRole },
1727         { LegendRole, NSAccessibilityGroupRole },
1728         { MathElementRole, NSAccessibilityGroupRole }
1729     };
1730     AccessibilityRoleMap& roleMap = *new AccessibilityRoleMap;
1731     
1732     const unsigned numRoles = sizeof(roles) / sizeof(roles[0]);
1733     for (unsigned i = 0; i < numRoles; ++i)
1734         roleMap.set(roles[i].value, roles[i].string);
1735     return roleMap;
1736 }
1737
1738 static NSString* roleValueToNSString(AccessibilityRole value)
1739 {
1740     ASSERT(value);
1741     static const AccessibilityRoleMap& roleMap = createAccessibilityRoleMap();
1742     return roleMap.get(value);
1743 }
1744
1745 - (NSString*)role
1746 {
1747     if (m_object->isAttachment())
1748         return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleAttribute];
1749     AccessibilityRole role = m_object->roleValue();
1750     if (role == CanvasRole && m_object->canvasHasFallbackContent())
1751         role = GroupRole;
1752     NSString* string = roleValueToNSString(role);
1753     if (string != nil)
1754         return string;
1755     return NSAccessibilityUnknownRole;
1756 }
1757
1758 - (NSString*)subrole
1759 {
1760     if (m_object->isPasswordField())
1761         return NSAccessibilitySecureTextFieldSubrole;
1762     if (m_object->isSearchField())
1763         return NSAccessibilitySearchFieldSubrole;
1764     
1765     if (m_object->isAttachment()) {
1766         NSView* attachView = [self attachmentView];
1767         if ([[attachView accessibilityAttributeNames] containsObject:NSAccessibilitySubroleAttribute]) {
1768             return [attachView accessibilityAttributeValue:NSAccessibilitySubroleAttribute];
1769         }
1770     }
1771     
1772     if (m_object->isSpinButtonPart()) {
1773         if (toAccessibilitySpinButtonPart(m_object)->isIncrementor())
1774             return NSAccessibilityIncrementArrowSubrole;
1775         
1776         return NSAccessibilityDecrementArrowSubrole;
1777     }
1778     
1779     if (m_object->isFileUploadButton())
1780         return @"AXFileUploadButton";
1781     
1782     if (m_object->isTreeItem())
1783         return NSAccessibilityOutlineRowSubrole;
1784     
1785     if (m_object->isList()) {
1786         AccessibilityList* listObject = toAccessibilityList(m_object);
1787         if (listObject->isUnorderedList() || listObject->isOrderedList())
1788             return NSAccessibilityContentListSubrole;
1789         if (listObject->isDescriptionList()) {
1790 #if __MAC_OS_X_VERSION_MIN_REQUIRED < 1090
1791             return NSAccessibilityDefinitionListSubrole;
1792 #else
1793             return NSAccessibilityDescriptionListSubrole;
1794 #endif
1795         }
1796     }
1797     
1798     // ARIA content subroles.
1799     switch (m_object->roleValue()) {
1800         case LandmarkApplicationRole:
1801             return @"AXLandmarkApplication";
1802         case LandmarkBannerRole:
1803             return @"AXLandmarkBanner";
1804         case LandmarkComplementaryRole:
1805             return @"AXLandmarkComplementary";
1806             // Footer roles should appear as content info types.
1807         case FooterRole:
1808         case LandmarkContentInfoRole:
1809             return @"AXLandmarkContentInfo";
1810         case LandmarkMainRole:
1811             return @"AXLandmarkMain";
1812         case LandmarkNavigationRole:
1813             return @"AXLandmarkNavigation";
1814         case LandmarkSearchRole:
1815             return @"AXLandmarkSearch";
1816         case ApplicationAlertRole:
1817             return @"AXApplicationAlert";
1818         case ApplicationAlertDialogRole:
1819             return @"AXApplicationAlertDialog";
1820         case ApplicationDialogRole:
1821             return @"AXApplicationDialog";
1822         case ApplicationLogRole:
1823             return @"AXApplicationLog";
1824         case ApplicationMarqueeRole:
1825             return @"AXApplicationMarquee";
1826         case ApplicationStatusRole:
1827             return @"AXApplicationStatus";
1828         case ApplicationTimerRole:
1829             return @"AXApplicationTimer";
1830         case DocumentRole:
1831             return @"AXDocument";
1832         case DocumentArticleRole:
1833             return @"AXDocumentArticle";
1834         case DocumentMathRole:
1835             return @"AXDocumentMath";
1836         case DocumentNoteRole:
1837             return @"AXDocumentNote";
1838         case DocumentRegionRole:
1839             return @"AXDocumentRegion";
1840         case UserInterfaceTooltipRole:
1841             return @"AXUserInterfaceTooltip";
1842         case TabPanelRole:
1843             return @"AXTabPanel";
1844         case DefinitionRole:
1845             return @"AXDefinition";
1846         case DescriptionListTermRole:
1847             return @"AXTerm";
1848         case DescriptionListDetailRole:
1849             return @"AXDescription";
1850             // Default doesn't return anything, so roles defined below can be chosen.
1851         default:
1852             break;
1853     }
1854     
1855     if (m_object->roleValue() == MathElementRole) {
1856         if (m_object->isMathFraction())
1857             return @"AXMathFraction";
1858         if (m_object->isMathFenced())
1859             return @"AXMathFenced";
1860         if (m_object->isMathSubscriptSuperscript())
1861             return @"AXMathSubscriptSuperscript";
1862         if (m_object->isMathRow())
1863             return @"AXMathRow";
1864         if (m_object->isMathUnderOver())
1865             return @"AXMathUnderOver";
1866         if (m_object->isMathSquareRoot())
1867             return @"AXMathSquareRoot";
1868         if (m_object->isMathRoot())
1869             return @"AXMathRoot";
1870         if (m_object->isMathText())
1871             return @"AXMathText";
1872         if (m_object->isMathNumber())
1873             return @"AXMathNumber";
1874         if (m_object->isMathIdentifier())
1875             return @"AXMathIdentifier";
1876         if (m_object->isMathTable())
1877             return @"AXMathTable";
1878         if (m_object->isMathTableRow())
1879             return @"AXMathTableRow";
1880         if (m_object->isMathTableCell())
1881             return @"AXMathTableCell";
1882         if (m_object->isMathFenceOperator())
1883             return @"AXMathFenceOperator";
1884         if (m_object->isMathSeparatorOperator())
1885             return @"AXMathSeparatorOperator";
1886         if (m_object->isMathOperator())
1887             return @"AXMathOperator";
1888         if (m_object->isMathMultiscript())
1889             return @"AXMathMultiscript";
1890     }
1891     
1892     if (m_object->isMediaTimeline())
1893         return NSAccessibilityTimelineSubrole;
1894     
1895     return nil;
1896 }
1897
1898 - (NSString*)roleDescription
1899 {
1900     if (!m_object)
1901         return nil;
1902     
1903     // attachments have the AXImage role, but a different subrole
1904     if (m_object->isAttachment())
1905         return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleDescriptionAttribute];
1906     
1907     NSString* axRole = [self role];
1908     
1909     if ([axRole isEqualToString:NSAccessibilityGroupRole]) {
1910         
1911         NSString *ariaLandmarkRoleDescription = [self ariaLandmarkRoleDescription];
1912         if (ariaLandmarkRoleDescription)
1913             return ariaLandmarkRoleDescription;
1914         
1915         switch (m_object->roleValue()) {
1916             case DefinitionRole:
1917                 return AXDefinitionText();
1918             case DescriptionListTermRole:
1919                 return AXDescriptionListTermText();
1920             case DescriptionListDetailRole:
1921                 return AXDescriptionListDetailText();
1922             case FooterRole:
1923                 return AXFooterRoleDescriptionText();
1924             default:
1925                 return NSAccessibilityRoleDescription(NSAccessibilityGroupRole, [self subrole]);
1926         }
1927     }
1928     
1929     if ([axRole isEqualToString:@"AXWebArea"])
1930         return AXWebAreaText();
1931     
1932     if ([axRole isEqualToString:@"AXLink"])
1933         return AXLinkText();
1934     
1935     if ([axRole isEqualToString:@"AXListMarker"])
1936         return AXListMarkerText();
1937     
1938     if ([axRole isEqualToString:@"AXImageMap"])
1939         return AXImageMapText();
1940     
1941     if ([axRole isEqualToString:@"AXHeading"])
1942         return AXHeadingText();
1943     
1944     if (m_object->isFileUploadButton())
1945         return AXFileUploadButtonText();
1946     
1947     // Only returning for DL (not UL or OL) because description changed with HTML5 from 'definition list' to
1948     // superset 'description list' and does not return the same values in AX API on some OS versions. 
1949     if (m_object->isList()) {
1950         AccessibilityList* listObject = toAccessibilityList(m_object);
1951         if (listObject->isDescriptionList())
1952             return AXDescriptionListText();
1953     }
1954     
1955     // AppKit also returns AXTab for the role description for a tab item.
1956     if (m_object->isTabItem())
1957         return NSAccessibilityRoleDescription(@"AXTab", nil);
1958     
1959     // We should try the system default role description for all other roles.
1960     // If we get the same string back, then as a last resort, return unknown.
1961     NSString* defaultRoleDescription = NSAccessibilityRoleDescription(axRole, [self subrole]);
1962     
1963     // On earlier Mac versions (Lion), using a non-standard subrole would result in a role description
1964     // being returned that looked like AXRole:AXSubrole. To make all platforms have the same role descriptions
1965     // we should fallback on a role description ignoring the subrole in these cases.
1966     if ([defaultRoleDescription isEqualToString:[NSString stringWithFormat:@"%@:%@", axRole, [self subrole]]])
1967         defaultRoleDescription = NSAccessibilityRoleDescription(axRole, nil);
1968     
1969     if (![defaultRoleDescription isEqualToString:axRole])
1970         return defaultRoleDescription;
1971     
1972     return NSAccessibilityRoleDescription(NSAccessibilityUnknownRole, nil);
1973 }
1974
1975 - (id)scrollViewParent
1976 {
1977     if (!m_object || !m_object->isAccessibilityScrollView())
1978         return nil;
1979     
1980     // If this scroll view provides it's parent object (because it's a sub-frame), then
1981     // we should not find the remoteAccessibilityParent.
1982     if (m_object->parentObject())
1983         return nil;
1984     
1985     AccessibilityScrollView* scrollView = toAccessibilityScrollView(m_object);
1986     ScrollView* scroll = scrollView->scrollView();
1987     if (!scroll)
1988         return nil;
1989     
1990     if (scroll->platformWidget())
1991         return NSAccessibilityUnignoredAncestor(scroll->platformWidget());
1992     
1993     return [self remoteAccessibilityParentObject];
1994 }
1995
1996 // FIXME: split up this function in a better way.
1997 // suggestions: Use a hash table that maps attribute names to function calls,
1998 // or maybe pointers to member functions
1999 - (id)accessibilityAttributeValue:(NSString*)attributeName
2000 {
2001     if (![self updateObjectBackingStore])
2002         return nil;
2003     
2004     if ([attributeName isEqualToString: NSAccessibilityRoleAttribute])
2005         return [self role];
2006     
2007     if ([attributeName isEqualToString: NSAccessibilitySubroleAttribute])
2008         return [self subrole];
2009     
2010     if ([attributeName isEqualToString: NSAccessibilityRoleDescriptionAttribute])
2011         return [self roleDescription];
2012     
2013     if ([attributeName isEqualToString: NSAccessibilityParentAttribute]) {
2014         
2015         // This will return the parent of the AXWebArea, if this is a web area.
2016         id scrollViewParent = [self scrollViewParent];
2017         if (scrollViewParent)
2018             return scrollViewParent;
2019         
2020         // Tree item (changed to AXRows) can only report the tree (AXOutline) as its parent.
2021         if (m_object->isTreeItem()) {
2022             AccessibilityObject* parent = m_object->parentObjectUnignored();
2023             while (parent) {
2024                 if (parent->isTree())
2025                     return parent->wrapper();
2026                 parent = parent->parentObjectUnignored();
2027             }
2028         }
2029         
2030         AccessibilityObject* parent = m_object->parentObjectUnignored();
2031         if (!parent)
2032             return nil;
2033         
2034         // In WebKit1, the scroll view is provided by the system (the attachment view), so the parent
2035         // should be reported directly as such.
2036         if (m_object->isWebArea() && parent->isAttachment())
2037             return [parent->wrapper() attachmentView];
2038         
2039         return parent->wrapper();
2040     }
2041     
2042     if ([attributeName isEqualToString: NSAccessibilityChildrenAttribute]) {
2043         if (m_object->children().isEmpty()) {
2044             NSArray* children = [self renderWidgetChildren];
2045             if (children != nil)
2046                 return children;
2047         }
2048         
2049         // The tree's (AXOutline) children are supposed to be its rows and columns.
2050         // The ARIA spec doesn't have columns, so we just need rows.
2051         if (m_object->isTree())
2052             return [self accessibilityAttributeValue:NSAccessibilityRowsAttribute];
2053         
2054         // A tree item should only expose its content as its children (not its rows)
2055         if (m_object->isTreeItem()) {
2056             AccessibilityObject::AccessibilityChildrenVector contentCopy;
2057             m_object->ariaTreeItemContent(contentCopy);
2058             return convertToNSArray(contentCopy);
2059         }
2060         
2061         return convertToNSArray(m_object->children());
2062     }
2063     
2064     if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) {
2065         if (m_object->isListBox()) {
2066             AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
2067             m_object->selectedChildren(selectedChildrenCopy);
2068             return convertToNSArray(selectedChildrenCopy);
2069         }
2070         return nil;
2071     }
2072     
2073     if ([attributeName isEqualToString: NSAccessibilityVisibleChildrenAttribute]) {
2074         if (m_object->isListBox()) {
2075             AccessibilityObject::AccessibilityChildrenVector visibleChildrenCopy;
2076             m_object->visibleChildren(visibleChildrenCopy);
2077             return convertToNSArray(visibleChildrenCopy);
2078         }
2079         else if (m_object->isList())
2080             return [self accessibilityAttributeValue:NSAccessibilityChildrenAttribute];
2081         
2082         return nil;
2083     }
2084     
2085     
2086     if (m_object->isWebArea()) {
2087         if ([attributeName isEqualToString:@"AXLinkUIElements"]) {
2088             AccessibilityObject::AccessibilityChildrenVector links;
2089             static_cast<AccessibilityRenderObject*>(m_object)->getDocumentLinks(links);
2090             return convertToNSArray(links);
2091         }
2092         if ([attributeName isEqualToString:@"AXLoaded"])
2093             return [NSNumber numberWithBool:m_object->isLoaded()];
2094         if ([attributeName isEqualToString:@"AXLayoutCount"])
2095             return [NSNumber numberWithInt:m_object->layoutCount()];
2096         if ([attributeName isEqualToString:NSAccessibilityLoadingProgressAttribute])
2097             return [NSNumber numberWithDouble:m_object->estimatedLoadingProgress()];
2098     }
2099     
2100     if (m_object->isTextControl()) {
2101         if ([attributeName isEqualToString: NSAccessibilityNumberOfCharactersAttribute]) {
2102             int length = m_object->textLength();
2103             if (length < 0)
2104                 return nil;
2105             return [NSNumber numberWithUnsignedInt:length];
2106         }
2107         if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) {
2108             String selectedText = m_object->selectedText();
2109             if (selectedText.isNull())
2110                 return nil;
2111             return (NSString*)selectedText;
2112         }
2113         if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) {
2114             PlainTextRange textRange = m_object->selectedTextRange();
2115             if (textRange.isNull())
2116                 return [NSValue valueWithRange:NSMakeRange(0, 0)];
2117             return [NSValue valueWithRange:NSMakeRange(textRange.start, textRange.length)];
2118         }
2119         // TODO: Get actual visible range. <rdar://problem/4712101>
2120         if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
2121             return m_object->isPasswordField() ? nil : [NSValue valueWithRange: NSMakeRange(0, m_object->textLength())];
2122         if ([attributeName isEqualToString: NSAccessibilityInsertionPointLineNumberAttribute]) {
2123             // if selectionEnd > 0, then there is selected text and this question should not be answered
2124             if (m_object->isPasswordField() || m_object->selectionEnd() > 0)
2125                 return nil;
2126             
2127             AccessibilityObject* focusedObject = m_object->focusedUIElement();
2128             if (focusedObject != m_object)
2129                 return nil;
2130             
2131             VisiblePosition focusedPosition = focusedObject->visiblePositionForIndex(focusedObject->selectionStart(), true);
2132             int lineNumber = m_object->lineForPosition(focusedPosition);
2133             if (lineNumber < 0)
2134                 return nil;
2135             
2136             return [NSNumber numberWithInt:lineNumber];
2137         }
2138     }
2139     
2140     if ([attributeName isEqualToString: NSAccessibilityURLAttribute]) {
2141         KURL url = m_object->url();
2142         if (url.isNull())
2143             return nil;
2144         return (NSURL*)url;
2145     }
2146
2147     // Only native spin buttons have increment and decrement buttons.
2148     if (m_object->isNativeSpinButton()) {
2149         if ([attributeName isEqualToString:NSAccessibilityIncrementButtonAttribute])
2150             return toAccessibilitySpinButton(m_object)->incrementButton()->wrapper();
2151         if ([attributeName isEqualToString:NSAccessibilityDecrementButtonAttribute])
2152             return toAccessibilitySpinButton(m_object)->decrementButton()->wrapper();
2153     }
2154     
2155     if ([attributeName isEqualToString: @"AXVisited"])
2156         return [NSNumber numberWithBool: m_object->isVisited()];
2157     
2158     if ([attributeName isEqualToString: NSAccessibilityTitleAttribute]) {
2159         if (m_object->isAttachment()) {
2160             if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityTitleAttribute])
2161                 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityTitleAttribute];
2162         }
2163         
2164         // Meter elements should communicate their content via AXValueDescription.
2165         if (m_object->isMeter())
2166             return [NSString string];
2167         
2168         return [self accessibilityTitle];
2169     }
2170     
2171     if ([attributeName isEqualToString: NSAccessibilityDescriptionAttribute]) {
2172         if (m_object->isAttachment()) {
2173             if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityDescriptionAttribute])
2174                 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityDescriptionAttribute];
2175         }
2176         return [self accessibilityDescription];
2177     }
2178     
2179     if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) {
2180         if (m_object->isAttachment()) {
2181             if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityValueAttribute])
2182                 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityValueAttribute];
2183         }
2184         if (m_object->supportsRangeValue())
2185             return [NSNumber numberWithFloat:m_object->valueForRange()];
2186         if (m_object->roleValue() == SliderThumbRole)
2187             return [NSNumber numberWithFloat:m_object->parentObject()->valueForRange()];
2188         if (m_object->isHeading())
2189             return [NSNumber numberWithInt:m_object->headingLevel()];
2190         
2191         if (m_object->isCheckboxOrRadio() || m_object->isMenuItem()) {
2192             switch (m_object->checkboxOrRadioValue()) {
2193                 case ButtonStateOff:
2194                     return [NSNumber numberWithInt:0];
2195                 case ButtonStateOn:
2196                     return [NSNumber numberWithInt:1];
2197                 case ButtonStateMixed:
2198                     return [NSNumber numberWithInt:2];
2199             }
2200         }
2201         
2202         // radio groups return the selected radio button as the AXValue
2203         if (m_object->isRadioGroup()) {
2204             AccessibilityObject* radioButton = m_object->selectedRadioButton();
2205             if (!radioButton)
2206                 return nil;
2207             return radioButton->wrapper();
2208         }
2209         
2210         if (m_object->isTabList()) {
2211             AccessibilityObject* tabItem = m_object->selectedTabItem();
2212             if (!tabItem)
2213                 return nil;
2214             return tabItem->wrapper();
2215         }
2216         
2217         if (m_object->isTabItem())
2218             return [NSNumber numberWithInt:m_object->isSelected()];
2219         
2220         if (m_object->isColorWell()) {
2221             int r, g, b;
2222             m_object->colorValue(r, g, b);
2223             return [NSString stringWithFormat:@"rgb %7.5f %7.5f %7.5f 1", r / 255., g / 255., b / 255.];
2224         }
2225         
2226         return m_object->stringValue();
2227     }
2228
2229     if ([attributeName isEqualToString:(NSString *)kAXMenuItemMarkCharAttribute]) {
2230         const unichar ch = 0x2713; // ✓ used on Mac for selected menu items.
2231         return (m_object->isChecked()) ? [NSString stringWithCharacters:&ch length:1] : nil;
2232     }
2233
2234     if ([attributeName isEqualToString: NSAccessibilityMinValueAttribute])
2235         return [NSNumber numberWithFloat:m_object->minValueForRange()];
2236     
2237     if ([attributeName isEqualToString: NSAccessibilityMaxValueAttribute])
2238         return [NSNumber numberWithFloat:m_object->maxValueForRange()];
2239     
2240     if ([attributeName isEqualToString: NSAccessibilityHelpAttribute])
2241         return [self accessibilityHelpText];
2242     
2243     if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute])
2244         return [NSNumber numberWithBool: m_object->isFocused()];
2245     
2246     if ([attributeName isEqualToString: NSAccessibilityEnabledAttribute])
2247         return [NSNumber numberWithBool: m_object->isEnabled()];
2248     
2249     if ([attributeName isEqualToString: NSAccessibilitySizeAttribute]) {
2250         IntSize s = m_object->pixelSnappedSize();
2251         return [NSValue valueWithSize: NSMakeSize(s.width(), s.height())];
2252     }
2253     
2254     if ([attributeName isEqualToString: NSAccessibilityPositionAttribute])
2255         return [self position];
2256     if ([attributeName isEqualToString:NSAccessibilityPathAttribute])
2257         return [self path];
2258     
2259     if ([attributeName isEqualToString: NSAccessibilityWindowAttribute] ||
2260         [attributeName isEqualToString: NSAccessibilityTopLevelUIElementAttribute]) {
2261         
2262         id remoteParent = [self remoteAccessibilityParentObject];
2263         if (remoteParent)
2264             return [remoteParent accessibilityAttributeValue:attributeName];
2265         
2266         FrameView* fv = m_object->documentFrameView();
2267         if (fv)
2268             return [fv->platformWidget() window];
2269         return nil;
2270     }
2271     
2272     if ([attributeName isEqualToString:NSAccessibilityAccessKeyAttribute]) {
2273         AtomicString accessKey = m_object->accessKey();
2274         if (accessKey.isNull())
2275             return nil;
2276         return accessKey;
2277     }
2278     
2279     if ([attributeName isEqualToString:NSAccessibilityTabsAttribute]) {
2280         if (m_object->isTabList()) {
2281             AccessibilityObject::AccessibilityChildrenVector tabsChildren;
2282             m_object->tabChildren(tabsChildren);
2283             return convertToNSArray(tabsChildren);
2284         }
2285     }
2286     
2287     if ([attributeName isEqualToString:NSAccessibilityContentsAttribute]) {
2288         // The contents of a tab list are all the children except the tabs.
2289         if (m_object->isTabList()) {
2290             AccessibilityObject::AccessibilityChildrenVector children = m_object->children();
2291             AccessibilityObject::AccessibilityChildrenVector tabsChildren;
2292             m_object->tabChildren(tabsChildren);
2293             
2294             AccessibilityObject::AccessibilityChildrenVector contents;
2295             unsigned childrenSize = children.size();
2296             for (unsigned k = 0; k < childrenSize; ++k) {
2297                 if (tabsChildren.find(children[k]) == WTF::notFound)
2298                     contents.append(children[k]);
2299             }
2300             return convertToNSArray(contents);
2301         } else if (m_object->isScrollView()) {
2302             AccessibilityObject::AccessibilityChildrenVector children = m_object->children();
2303             
2304             // A scrollView's contents are everything except the scroll bars.
2305             AccessibilityObject::AccessibilityChildrenVector contents;
2306             unsigned childrenSize = children.size();
2307             for (unsigned k = 0; k < childrenSize; ++k) {
2308                 if (!children[k]->isScrollbar())
2309                     contents.append(children[k]);
2310             }
2311             return convertToNSArray(contents);
2312         }
2313     }
2314     
2315     if (m_object->isAccessibilityTable()) {
2316         // TODO: distinguish between visible and non-visible rows
2317         if ([attributeName isEqualToString:NSAccessibilityRowsAttribute] ||
2318             [attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute]) {
2319             return convertToNSArray(static_cast<AccessibilityTable*>(m_object)->rows());
2320         }
2321         // TODO: distinguish between visible and non-visible columns
2322         if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute] ||
2323             [attributeName isEqualToString:NSAccessibilityVisibleColumnsAttribute]) {
2324             return convertToNSArray(static_cast<AccessibilityTable*>(m_object)->columns());
2325         }
2326         
2327         if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
2328             AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
2329             m_object->selectedChildren(selectedChildrenCopy);
2330             return convertToNSArray(selectedChildrenCopy);
2331         }
2332         
2333         // HTML tables don't support these
2334         if ([attributeName isEqualToString:NSAccessibilitySelectedColumnsAttribute] ||
2335             [attributeName isEqualToString:NSAccessibilitySelectedCellsAttribute])
2336             return nil;
2337         
2338         if ([attributeName isEqualToString:(NSString *)kAXColumnHeaderUIElementsAttribute]) {
2339             AccessibilityObject::AccessibilityChildrenVector columnHeaders;
2340             static_cast<AccessibilityTable*>(m_object)->columnHeaders(columnHeaders);
2341             return convertToNSArray(columnHeaders);
2342         }
2343         
2344         if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) {
2345             AccessibilityObject* headerContainer = static_cast<AccessibilityTable*>(m_object)->headerContainer();
2346             if (headerContainer)
2347                 return headerContainer->wrapper();
2348             return nil;
2349         }
2350         
2351         if ([attributeName isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute]) {
2352             AccessibilityObject::AccessibilityChildrenVector rowHeaders;
2353             static_cast<AccessibilityTable*>(m_object)->rowHeaders(rowHeaders);
2354             return convertToNSArray(rowHeaders);
2355         }
2356         
2357         if ([attributeName isEqualToString:NSAccessibilityVisibleCellsAttribute]) {
2358             AccessibilityObject::AccessibilityChildrenVector cells;
2359             static_cast<AccessibilityTable*>(m_object)->cells(cells);
2360             return convertToNSArray(cells);
2361         }
2362     }
2363     
2364     if (m_object->isTableColumn()) {
2365         if ([attributeName isEqualToString:NSAccessibilityIndexAttribute])
2366             return [NSNumber numberWithInt:static_cast<AccessibilityTableColumn*>(m_object)->columnIndex()];
2367         
2368         // rows attribute for a column is the list of all the elements in that column at each row
2369         if ([attributeName isEqualToString:NSAccessibilityRowsAttribute] ||
2370             [attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute]) {
2371             return convertToNSArray(static_cast<AccessibilityTableColumn*>(m_object)->children());
2372         }
2373         if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) {
2374             AccessibilityObject* header = static_cast<AccessibilityTableColumn*>(m_object)->headerObject();
2375             if (!header)
2376                 return nil;
2377             return header->wrapper();
2378         }
2379     }
2380     
2381     if (m_object->isTableCell()) {
2382         if ([attributeName isEqualToString:NSAccessibilityRowIndexRangeAttribute]) {
2383             pair<unsigned, unsigned> rowRange;
2384             static_cast<AccessibilityTableCell*>(m_object)->rowIndexRange(rowRange);
2385             return [NSValue valueWithRange:NSMakeRange(rowRange.first, rowRange.second)];
2386         }
2387         if ([attributeName isEqualToString:NSAccessibilityColumnIndexRangeAttribute]) {
2388             pair<unsigned, unsigned> columnRange;
2389             static_cast<AccessibilityTableCell*>(m_object)->columnIndexRange(columnRange);
2390             return [NSValue valueWithRange:NSMakeRange(columnRange.first, columnRange.second)];
2391         }
2392     }
2393     
2394     if (m_object->isTree()) {
2395         if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
2396             AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
2397             m_object->selectedChildren(selectedChildrenCopy);
2398             return convertToNSArray(selectedChildrenCopy);
2399         }
2400         if ([attributeName isEqualToString:NSAccessibilityRowsAttribute]) {
2401             AccessibilityObject::AccessibilityChildrenVector rowsCopy;
2402             m_object->ariaTreeRows(rowsCopy);
2403             return convertToNSArray(rowsCopy);
2404         }
2405         
2406         // TreeRoles do not support columns, but Mac AX expects to be able to ask about columns at the least.
2407         if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute])
2408             return [NSArray array];
2409     }
2410     
2411     if ([attributeName isEqualToString:NSAccessibilityIndexAttribute]) {
2412         if (m_object->isTreeItem()) {
2413             AccessibilityObject* parent = m_object->parentObject();
2414             for (; parent && !parent->isTree(); parent = parent->parentObject())
2415             { }
2416             
2417             if (!parent)
2418                 return nil;
2419             
2420             // Find the index of this item by iterating the parents.
2421             AccessibilityObject::AccessibilityChildrenVector rowsCopy;
2422             parent->ariaTreeRows(rowsCopy);
2423             size_t count = rowsCopy.size();
2424             for (size_t k = 0; k < count; ++k)
2425                 if (rowsCopy[k]->wrapper() == self)
2426                     return [NSNumber numberWithUnsignedInt:k];
2427             
2428             return nil;
2429         }
2430         if (m_object->isTableRow()) {
2431             if ([attributeName isEqualToString:NSAccessibilityIndexAttribute])
2432                 return [NSNumber numberWithInt:static_cast<AccessibilityTableRow*>(m_object)->rowIndex()];
2433         }
2434     }
2435     
2436     // The rows that are considered inside this row.
2437     if ([attributeName isEqualToString:NSAccessibilityDisclosedRowsAttribute]) {
2438         if (m_object->isTreeItem()) {
2439             AccessibilityObject::AccessibilityChildrenVector rowsCopy;
2440             m_object->ariaTreeItemDisclosedRows(rowsCopy);
2441             return convertToNSArray(rowsCopy);
2442         } else if (m_object->isARIATreeGridRow()) {
2443             AccessibilityObject::AccessibilityChildrenVector rowsCopy;
2444             static_cast<AccessibilityARIAGridRow*>(m_object)->disclosedRows(rowsCopy);
2445             return convertToNSArray(rowsCopy);
2446         }
2447     }
2448     
2449     // The row that contains this row. It should be the same as the first parent that is a treeitem.
2450     if ([attributeName isEqualToString:NSAccessibilityDisclosedByRowAttribute]) {
2451         if (m_object->isTreeItem()) {
2452             AccessibilityObject* parent = m_object->parentObject();
2453             while (parent) {
2454                 if (parent->isTreeItem())
2455                     return parent->wrapper();
2456                 // If the parent is the tree itself, then this value == nil.
2457                 if (parent->isTree())
2458                     return nil;
2459                 parent = parent->parentObject();
2460             }
2461             return nil;
2462         } else if (m_object->isARIATreeGridRow()) {
2463             AccessibilityObject* row = static_cast<AccessibilityARIAGridRow*>(m_object)->disclosedByRow();
2464             if (!row)
2465                 return nil;
2466             return row->wrapper();
2467         }
2468     }
2469     
2470     if ([attributeName isEqualToString:NSAccessibilityDisclosureLevelAttribute]) {
2471         // Convert from 1-based level (from aria-level spec) to 0-based level (Mac)
2472         int level = m_object->hierarchicalLevel();
2473         if (level > 0)
2474             level -= 1;
2475         return [NSNumber numberWithInt:level];
2476     }
2477     if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute])
2478         return [NSNumber numberWithBool:m_object->isExpanded()];
2479     
2480     if ((m_object->isListBox() || m_object->isList()) && [attributeName isEqualToString:NSAccessibilityOrientationAttribute])
2481         return NSAccessibilityVerticalOrientationValue;
2482     
2483     if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"])
2484         return [self textMarkerRangeForSelection];
2485     
2486     if (m_object->renderer()) {
2487         if ([attributeName isEqualToString: @"AXStartTextMarker"])
2488             return [self textMarkerForVisiblePosition:startOfDocument(&m_object->renderer()->document())];
2489         if ([attributeName isEqualToString: @"AXEndTextMarker"])
2490             return [self textMarkerForVisiblePosition:endOfDocument(&m_object->renderer()->document())];
2491     }
2492     
2493     if ([attributeName isEqualToString:NSAccessibilityBlockQuoteLevelAttribute])
2494         return [NSNumber numberWithInt:m_object->blockquoteLevel()];
2495     if ([attributeName isEqualToString:@"AXTableLevel"])
2496         return [NSNumber numberWithInt:m_object->tableLevel()];
2497     
2498     if ([attributeName isEqualToString: NSAccessibilityLinkedUIElementsAttribute]) {
2499         AccessibilityObject::AccessibilityChildrenVector linkedUIElements;
2500         m_object->linkedUIElements(linkedUIElements);
2501         if (linkedUIElements.size() == 0)
2502             return nil;
2503         return convertToNSArray(linkedUIElements);
2504     }
2505     
2506     if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute])
2507         return [NSNumber numberWithBool:m_object->isSelected()];
2508     
2509     if ([attributeName isEqualToString: NSAccessibilityServesAsTitleForUIElementsAttribute] && m_object->isMenuButton()) {
2510         AccessibilityObject* uiElement = static_cast<AccessibilityRenderObject*>(m_object)->menuForMenuButton();
2511         if (uiElement)
2512             return [NSArray arrayWithObject:uiElement->wrapper()];
2513     }
2514     
2515     if ([attributeName isEqualToString:NSAccessibilityTitleUIElementAttribute]) {
2516         if (!m_object->exposesTitleUIElement())
2517             return nil;
2518         
2519         AccessibilityObject* obj = m_object->titleUIElement();
2520         if (obj)
2521             return obj->wrapper();
2522         return nil;
2523     }
2524     
2525     if ([attributeName isEqualToString:NSAccessibilityValueDescriptionAttribute]) {
2526         if (m_object->isMeter())
2527             return [self accessibilityTitle];
2528         
2529         return m_object->valueDescription();
2530     }
2531     
2532     if ([attributeName isEqualToString:NSAccessibilityOrientationAttribute]) {
2533         AccessibilityOrientation elementOrientation = m_object->orientation();
2534         if (elementOrientation == AccessibilityOrientationVertical)
2535             return NSAccessibilityVerticalOrientationValue;
2536         if (elementOrientation == AccessibilityOrientationHorizontal)
2537             return NSAccessibilityHorizontalOrientationValue;
2538         return nil;
2539     }
2540     
2541     if ([attributeName isEqualToString:NSAccessibilityHorizontalScrollBarAttribute]) {
2542         AccessibilityObject* scrollBar = m_object->scrollBar(AccessibilityOrientationHorizontal);
2543         if (scrollBar)
2544             return scrollBar->wrapper();
2545         return nil;
2546     }
2547     if ([attributeName isEqualToString:NSAccessibilityVerticalScrollBarAttribute]) {
2548         AccessibilityObject* scrollBar = m_object->scrollBar(AccessibilityOrientationVertical);
2549         if (scrollBar)
2550             return scrollBar->wrapper();
2551         return nil;
2552     }
2553     
2554     if ([attributeName isEqualToString:NSAccessibilitySortDirectionAttribute]) {
2555         switch (m_object->sortDirection()) {
2556             case SortDirectionAscending:
2557                 return NSAccessibilityAscendingSortDirectionValue;
2558             case SortDirectionDescending:
2559                 return NSAccessibilityDescendingSortDirectionValue;
2560             default:
2561                 return NSAccessibilityUnknownSortDirectionValue;
2562         }
2563     }
2564     
2565     if ([attributeName isEqualToString:NSAccessibilityLanguageAttribute])
2566         return m_object->language();
2567     
2568     if ([attributeName isEqualToString:NSAccessibilityExpandedAttribute])
2569         return [NSNumber numberWithBool:m_object->isExpanded()];
2570     
2571     if ([attributeName isEqualToString:NSAccessibilityRequiredAttribute])
2572         return [NSNumber numberWithBool:m_object->isRequired()];
2573     
2574     if ([attributeName isEqualToString:NSAccessibilityInvalidAttribute])
2575         return m_object->invalidStatus();
2576     
2577     if ([attributeName isEqualToString:NSAccessibilityOwnsAttribute]) {
2578         AccessibilityObject::AccessibilityChildrenVector ariaOwns;
2579         m_object->ariaOwnsElements(ariaOwns);
2580         return convertToNSArray(ariaOwns);
2581     }
2582     
2583     if ([attributeName isEqualToString:NSAccessibilityARIAPosInSetAttribute])
2584         return [NSNumber numberWithInt:m_object->ariaPosInSet()];
2585     if ([attributeName isEqualToString:NSAccessibilityARIASetSizeAttribute])
2586         return [NSNumber numberWithInt:m_object->ariaSetSize()];
2587     
2588     if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute])
2589         return [NSNumber numberWithBool:m_object->isARIAGrabbed()];
2590     
2591     if ([attributeName isEqualToString:NSAccessibilityDropEffectsAttribute]) {
2592         Vector<String> dropEffects;
2593         m_object->determineARIADropEffects(dropEffects);
2594         return convertStringsToNSArray(dropEffects);
2595     }
2596     
2597     if ([attributeName isEqualToString:NSAccessibilityPlaceholderValueAttribute])
2598         return m_object->placeholderValue();
2599     
2600     if ([attributeName isEqualToString:NSAccessibilityHasPopupAttribute])
2601         return [NSNumber numberWithBool:m_object->ariaHasPopup()];
2602     
2603     // ARIA Live region attributes.
2604     if ([attributeName isEqualToString:NSAccessibilityARIALiveAttribute])
2605         return m_object->ariaLiveRegionStatus();
2606     if ([attributeName isEqualToString:NSAccessibilityARIARelevantAttribute])
2607         return m_object->ariaLiveRegionRelevant();
2608     if ([attributeName isEqualToString:NSAccessibilityARIAAtomicAttribute])
2609         return [NSNumber numberWithBool:m_object->ariaLiveRegionAtomic()];
2610     if ([attributeName isEqualToString:NSAccessibilityElementBusyAttribute])
2611         return [NSNumber numberWithBool:m_object->ariaLiveRegionBusy()];
2612     
2613     // MathML Attributes.
2614     if (m_object->isMathElement()) {
2615         if ([attributeName isEqualToString:NSAccessibilityMathRootIndexAttribute])
2616             return (m_object->mathRootIndexObject()) ? m_object->mathRootIndexObject()->wrapper() : 0;
2617         if ([attributeName isEqualToString:NSAccessibilityMathRootRadicandAttribute])
2618             return (m_object->mathRadicandObject()) ? m_object->mathRadicandObject()->wrapper() : 0;
2619         if ([attributeName isEqualToString:NSAccessibilityMathFractionNumeratorAttribute])
2620             return (m_object->mathNumeratorObject()) ? m_object->mathNumeratorObject()->wrapper() : 0;
2621         if ([attributeName isEqualToString:NSAccessibilityMathFractionDenominatorAttribute])
2622             return (m_object->mathDenominatorObject()) ? m_object->mathDenominatorObject()->wrapper() : 0;
2623         if ([attributeName isEqualToString:NSAccessibilityMathBaseAttribute])
2624             return (m_object->mathBaseObject()) ? m_object->mathBaseObject()->wrapper() : 0;
2625         if ([attributeName isEqualToString:NSAccessibilityMathSubscriptAttribute])
2626             return (m_object->mathSubscriptObject()) ? m_object->mathSubscriptObject()->wrapper() : 0;
2627         if ([attributeName isEqualToString:NSAccessibilityMathSuperscriptAttribute])
2628             return (m_object->mathSuperscriptObject()) ? m_object->mathSuperscriptObject()->wrapper() : 0;
2629         if ([attributeName isEqualToString:NSAccessibilityMathUnderAttribute])
2630             return (m_object->mathUnderObject()) ? m_object->mathUnderObject()->wrapper() : 0;
2631         if ([attributeName isEqualToString:NSAccessibilityMathOverAttribute])
2632             return (m_object->mathOverObject()) ? m_object->mathOverObject()->wrapper() : 0;
2633         if ([attributeName isEqualToString:NSAccessibilityMathFencedOpenAttribute])
2634             return m_object->mathFencedOpenString();
2635         if ([attributeName isEqualToString:NSAccessibilityMathFencedCloseAttribute])
2636             return m_object->mathFencedCloseString();
2637         if ([attributeName isEqualToString:NSAccessibilityMathLineThicknessAttribute])
2638             return [NSNumber numberWithInteger:m_object->mathLineThickness()];
2639         if ([attributeName isEqualToString:NSAccessibilityMathPostscriptsAttribute])
2640             return [self accessibilityMathPostscriptPairs];
2641         if ([attributeName isEqualToString:NSAccessibilityMathPrescriptsAttribute])
2642             return [self accessibilityMathPrescriptPairs];
2643     }
2644     
2645     if ([attributeName isEqualToString:NSAccessibilityDOMIdentifierAttribute])
2646         return m_object->identifierAttribute();
2647     if ([attributeName isEqualToString:NSAccessibilityDOMClassListAttribute]) {
2648         Vector<String> classList;
2649         m_object->classList(classList);
2650         return convertStringsToNSArray(classList);
2651     }
2652     
2653     // this is used only by DumpRenderTree for testing
2654     if ([attributeName isEqualToString:@"AXClickPoint"])
2655         return [NSValue valueWithPoint:m_object->clickPoint()];
2656     
2657     // This is used by DRT to verify CSS3 speech works.
2658     if ([attributeName isEqualToString:@"AXDRTSpeechAttribute"]) {
2659         ESpeak speakProperty = m_object->speakProperty();
2660         switch (speakProperty) {
2661             case SpeakNone:
2662                 return @"none";
2663             case SpeakSpellOut:
2664                 return @"spell-out";
2665             case SpeakDigits:
2666                 return @"digits";
2667             case SpeakLiteralPunctuation:
2668                 return @"literal-punctuation";
2669             case SpeakNoPunctuation:
2670                 return @"no-punctuation";
2671             default:
2672             case SpeakNormal:
2673                 return @"normal";
2674         }
2675     }
2676     
2677     // Used by DRT to find an accessible node by its element id.
2678     if ([attributeName isEqualToString:@"AXDRTElementIdAttribute"])
2679         return m_object->getAttribute(idAttr);
2680     
2681     return nil;
2682 }
2683
2684 - (NSString *)accessibilityPlatformMathSubscriptKey
2685 {
2686     return NSAccessibilityMathSubscriptAttribute;
2687 }
2688
2689 - (NSString *)accessibilityPlatformMathSuperscriptKey
2690 {
2691     return NSAccessibilityMathSuperscriptAttribute;
2692 }
2693
2694 - (id)accessibilityFocusedUIElement
2695 {
2696     if (![self updateObjectBackingStore])
2697         return nil;
2698     
2699     RefPtr<AccessibilityObject> focusedObj = m_object->focusedUIElement();
2700     
2701     if (!focusedObj)
2702         return nil;
2703     
2704     return focusedObj->wrapper();
2705 }
2706
2707 - (id)accessibilityHitTest:(NSPoint)point
2708 {
2709     if (![self updateObjectBackingStore])
2710         return nil;
2711     
2712     m_object->updateChildrenIfNecessary();
2713     RefPtr<AccessibilityObject> axObject = m_object->accessibilityHitTest(IntPoint(point));
2714     if (axObject)
2715         return NSAccessibilityUnignoredAncestor(axObject->wrapper());
2716     return NSAccessibilityUnignoredAncestor(self);
2717 }
2718
2719 - (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName
2720 {
2721     if (![self updateObjectBackingStore])
2722         return nil;
2723     
2724     if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"])
2725         return YES;
2726     
2727     if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute])
2728         return m_object->canSetFocusAttribute();
2729     
2730     if ([attributeName isEqualToString: NSAccessibilityValueAttribute])
2731         return m_object->canSetValueAttribute();
2732     
2733     if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute])
2734         return m_object->canSetSelectedAttribute();
2735     
2736     if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute])
2737         return m_object->canSetSelectedChildrenAttribute();
2738     
2739     if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute])
2740         return m_object->canSetExpandedAttribute();
2741     
2742     if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute])
2743         return YES;
2744     
2745     if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute] ||
2746         [attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute] ||
2747         [attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
2748         return m_object->canSetTextRangeAttributes();
2749     
2750     if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute])
2751         return YES;
2752     
2753     return NO;
2754 }
2755
2756 // accessibilityShouldUseUniqueId is an AppKit method we override so that
2757 // objects will be given a unique ID, and therefore allow AppKit to know when they
2758 // become obsolete (e.g. when the user navigates to a new web page, making this one
2759 // unrendered but not deallocated because it is in the back/forward cache).
2760 // It is important to call NSAccessibilityUnregisterUniqueIdForUIElement in the
2761 // appropriate place (e.g. dealloc) to remove these non-retained references from
2762 // AppKit's id mapping tables. We do this in detach by calling unregisterUniqueIdForUIElement.
2763 //
2764 // Registering an object is also required for observing notifications. Only registered objects can be observed.
2765 - (BOOL)accessibilityIsIgnored
2766 {
2767     if (![self updateObjectBackingStore])
2768         return YES;
2769     
2770     if (m_object->isAttachment())
2771         return [[self attachmentView] accessibilityIsIgnored];
2772     return m_object->accessibilityIsIgnored();
2773 }
2774
2775 - (NSArray* )accessibilityParameterizedAttributeNames
2776 {
2777     if (![self updateObjectBackingStore])
2778         return nil;
2779     
2780     if (m_object->isAttachment())
2781         return nil;
2782     
2783     static NSArray* paramAttrs = nil;
2784     static NSArray* textParamAttrs = nil;
2785     static NSArray* tableParamAttrs = nil;
2786     static NSArray* webAreaParamAttrs = nil;
2787     if (paramAttrs == nil) {
2788         paramAttrs = [[NSArray alloc] initWithObjects:
2789                       @"AXUIElementForTextMarker",
2790                       @"AXTextMarkerRangeForUIElement",
2791                       @"AXLineForTextMarker",
2792                       @"AXTextMarkerRangeForLine",
2793                       @"AXStringForTextMarkerRange",
2794                       @"AXTextMarkerForPosition",
2795                       @"AXBoundsForTextMarkerRange",
2796                       @"AXAttributedStringForTextMarkerRange",
2797                       @"AXTextMarkerRangeForUnorderedTextMarkers",
2798                       @"AXNextTextMarkerForTextMarker",
2799                       @"AXPreviousTextMarkerForTextMarker",
2800                       @"AXLeftWordTextMarkerRangeForTextMarker",
2801                       @"AXRightWordTextMarkerRangeForTextMarker",
2802                       @"AXLeftLineTextMarkerRangeForTextMarker",
2803                       @"AXRightLineTextMarkerRangeForTextMarker",
2804                       @"AXSentenceTextMarkerRangeForTextMarker",
2805                       @"AXParagraphTextMarkerRangeForTextMarker",
2806                       @"AXNextWordEndTextMarkerForTextMarker",
2807                       @"AXPreviousWordStartTextMarkerForTextMarker",
2808                       @"AXNextLineEndTextMarkerForTextMarker",
2809                       @"AXPreviousLineStartTextMarkerForTextMarker",
2810                       @"AXNextSentenceEndTextMarkerForTextMarker",
2811                       @"AXPreviousSentenceStartTextMarkerForTextMarker",
2812                       @"AXNextParagraphEndTextMarkerForTextMarker",
2813                       @"AXPreviousParagraphStartTextMarkerForTextMarker",
2814                       @"AXStyleTextMarkerRangeForTextMarker",
2815                       @"AXLengthForTextMarkerRange",
2816                       NSAccessibilityBoundsForRangeParameterizedAttribute,
2817                       NSAccessibilityStringForRangeParameterizedAttribute,
2818                       NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute,
2819                       nil];
2820     }
2821     
2822     if (textParamAttrs == nil) {
2823         NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs];
2824         [tempArray addObject:(NSString*)kAXLineForIndexParameterizedAttribute];
2825         [tempArray addObject:(NSString*)kAXRangeForLineParameterizedAttribute];
2826         [tempArray addObject:(NSString*)kAXStringForRangeParameterizedAttribute];
2827         [tempArray addObject:(NSString*)kAXRangeForPositionParameterizedAttribute];
2828         [tempArray addObject:(NSString*)kAXRangeForIndexParameterizedAttribute];
2829         [tempArray addObject:(NSString*)kAXBoundsForRangeParameterizedAttribute];
2830         [tempArray addObject:(NSString*)kAXRTFForRangeParameterizedAttribute];
2831         [tempArray addObject:(NSString*)kAXAttributedStringForRangeParameterizedAttribute];
2832         [tempArray addObject:(NSString*)kAXStyleRangeForIndexParameterizedAttribute];
2833         textParamAttrs = [[NSArray alloc] initWithArray:tempArray];
2834         [tempArray release];
2835     }
2836     if (tableParamAttrs == nil) {
2837         NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs];
2838         [tempArray addObject:NSAccessibilityCellForColumnAndRowParameterizedAttribute];
2839         tableParamAttrs = [[NSArray alloc] initWithArray:tempArray];
2840         [tempArray release];
2841     }
2842     if (!webAreaParamAttrs) {
2843         NSMutableArray* tempArray = [[NSMutableArray alloc] initWithArray:paramAttrs];
2844         [tempArray addObject:NSAccessibilityTextMarkerForIndexParameterizedAttribute];
2845         [tempArray addObject:NSAccessibilityTextMarkerIsValidParameterizedAttribute];
2846         [tempArray addObject:NSAccessibilityIndexForTextMarkerParameterizedAttribute];
2847         webAreaParamAttrs = [[NSArray alloc] initWithArray:tempArray];
2848         [tempArray release];
2849     }
2850     
2851     if (m_object->isPasswordField())
2852         return [NSArray array];
2853     
2854     if (!m_object->isAccessibilityRenderObject())
2855         return paramAttrs;
2856     
2857     if (m_object->isTextControl())
2858         return textParamAttrs;
2859     
2860     if (m_object->isAccessibilityTable())
2861         return tableParamAttrs;
2862     
2863     if (m_object->isMenuRelated())
2864         return nil;
2865     
2866     if (m_object->isWebArea())
2867         return webAreaParamAttrs;
2868     
2869     return paramAttrs;
2870 }
2871
2872 - (void)accessibilityPerformPressAction
2873 {
2874     if (![self updateObjectBackingStore])
2875         return;
2876     
2877     if (m_object->isAttachment())
2878         [[self attachmentView] accessibilityPerformAction:NSAccessibilityPressAction];
2879     else
2880         m_object->press();
2881 }
2882
2883 - (void)accessibilityPerformIncrementAction
2884 {
2885     if (![self updateObjectBackingStore])
2886         return;
2887     
2888     if (m_object->isAttachment())
2889         [[self attachmentView] accessibilityPerformAction:NSAccessibilityIncrementAction];
2890     else
2891         m_object->increment();
2892 }
2893
2894 - (void)accessibilityPerformDecrementAction
2895 {
2896     if (![self updateObjectBackingStore])
2897         return;
2898     
2899     if (m_object->isAttachment())
2900         [[self attachmentView] accessibilityPerformAction:NSAccessibilityDecrementAction];
2901     else
2902         m_object->decrement();
2903 }
2904
2905 - (void)accessibilityPerformShowMenuAction
2906 {
2907     if (m_object->roleValue() == ComboBoxRole)
2908         m_object->setIsExpanded(true);
2909     else {
2910         // This needs to be performed in an iteration of the run loop that did not start from an AX call.
2911         // If it's the same run loop iteration, the menu open notification won't be sent
2912         [self performSelector:@selector(accessibilityShowContextMenu) withObject:nil afterDelay:0.0];
2913     }
2914 }
2915
2916 - (void)accessibilityShowContextMenu
2917 {
2918     Page* page = m_object->page();
2919     if (!page)
2920         return;
2921     
2922     IntRect rect = pixelSnappedIntRect(m_object->elementRect());
2923     FrameView* frameView = m_object->documentFrameView();
2924     
2925     // On WK2, we need to account for the scroll position.
2926     // On WK1, this isn't necessary, it's taken care of by the attachment views.
2927     if (frameView && !frameView->platformWidget()) {
2928         // Find the appropriate scroll view to use to convert the contents to the window.
2929         for (AccessibilityObject* parent = m_object->parentObject(); parent; parent = parent->parentObject()) {
2930             if (parent->isAccessibilityScrollView()) {
2931                 ScrollView* scrollView = toAccessibilityScrollView(parent)->scrollView();
2932                 rect = scrollView->contentsToRootView(rect);
2933                 break;
2934             }
2935         }
2936     }
2937     
2938     page->contextMenuController().showContextMenuAt(&page->mainFrame(), rect.center());
2939 }
2940
2941 - (void)accessibilityScrollToVisible
2942 {
2943     m_object->scrollToMakeVisible();
2944 }
2945
2946 - (void)accessibilityPerformAction:(NSString*)action
2947 {
2948     if (![self updateObjectBackingStore])
2949         return;
2950     
2951     if ([action isEqualToString:NSAccessibilityPressAction])
2952         [self accessibilityPerformPressAction];
2953     
2954     else if ([action isEqualToString:NSAccessibilityShowMenuAction])
2955         [self accessibilityPerformShowMenuAction];
2956     
2957     else if ([action isEqualToString:NSAccessibilityIncrementAction])
2958         [self accessibilityPerformIncrementAction];
2959     
2960     else if ([action isEqualToString:NSAccessibilityDecrementAction])
2961         [self accessibilityPerformDecrementAction];
2962     
2963     else if ([action isEqualToString:NSAccessibilityScrollToVisibleAction])
2964         [self accessibilityScrollToVisible];
2965 }
2966
2967 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attributeName
2968 {
2969     if (![self updateObjectBackingStore])
2970         return;
2971     
2972     id textMarkerRange = nil;
2973     NSNumber*               number = nil;
2974     NSString*               string = nil;
2975     NSRange                 range = {0, 0};
2976     NSArray*                array = nil;
2977     
2978     // decode the parameter
2979     if (AXObjectIsTextMarkerRange(value))
2980         textMarkerRange = value;
2981     
2982     else if ([value isKindOfClass:[NSNumber self]])
2983         number = value;
2984     
2985     else if ([value isKindOfClass:[NSString self]])
2986         string = value;
2987     
2988     else if ([value isKindOfClass:[NSValue self]])
2989         range = [value rangeValue];
2990     
2991     else if ([value isKindOfClass:[NSArray self]])
2992         array = value;
2993     
2994     // handle the command
2995     if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"]) {
2996         ASSERT(textMarkerRange);
2997         m_object->setSelectedVisiblePositionRange([self visiblePositionRangeForTextMarkerRange:textMarkerRange]);
2998     } else if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute]) {
2999         ASSERT(number);
3000         
3001         bool focus = [number boolValue];
3002         
3003         // If focus is just set without making the view the first responder, then keyboard focus won't move to the right place.
3004         if (focus && m_object->isWebArea() && !m_object->document()->frame()->selection().isFocusedAndActive()) {
3005             FrameView* frameView = m_object->documentFrameView();
3006             Page* page = m_object->page();
3007             if (page && frameView) {
3008                 ChromeClient& chromeClient = page->chrome().client();
3009                 chromeClient.focus();
3010                 if (frameView->platformWidget())
3011                     chromeClient.makeFirstResponder(frameView->platformWidget());
3012                 else
3013                     chromeClient.makeFirstResponder();
3014             }
3015         }
3016         
3017         m_object->setFocused(focus);
3018     } else if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) {
3019         if (number && m_object->canSetNumericValue())
3020             m_object->setValue([number floatValue]);
3021         else if (string)
3022             m_object->setValue(string);
3023     } else if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute]) {
3024         if (!number)
3025             return;
3026         m_object->setSelected([number boolValue]);
3027     } else if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) {
3028         if (!array || m_object->roleValue() != ListBoxRole)
3029             return;
3030         AccessibilityObject::AccessibilityChildrenVector selectedChildren;
3031         convertToVector(array, selectedChildren);
3032         static_cast<AccessibilityListBox*>(m_object)->setSelectedChildren(selectedChildren);
3033     } else if (m_object->isTextControl()) {
3034         if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) {
3035             m_object->setSelectedText(string);
3036         } else if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) {
3037             m_object->setSelectedTextRange(PlainTextRange(range.location, range.length));
3038         } else if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute]) {
3039             m_object->makeRangeVisible(PlainTextRange(range.location, range.length));
3040         }
3041     } else if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute])
3042         m_object->setIsE