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