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