1 /*
   2  * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #import "JavaAccessibilityUtilities.h"
  27 
  28 #import <AppKit/AppKit.h>
  29 #import <JavaNativeFoundation/JavaNativeFoundation.h>
  30 
  31 
  32 static BOOL JavaAccessibilityIsSupportedAttribute(id element, NSString *attribute);
  33 static void JavaAccessibilityLogError(NSString *message);
  34 static void _JavaAccessibilityRaiseException(NSString *reason, SInt32 errorCode);
  35 static NSString *AttributeWithoutAXPrefix(NSString *attribute);
  36 static SEL JavaAccessibilityAttributeGetter(NSString *attribute);
  37 static SEL JavaAccessibilityAttributeSettableTester(NSString *attribute);
  38 static SEL JavaAccessibilityAttributeSetter(NSString *attribute);
  39 
  40 NSString *const JavaAccessibilityIgnore = @"JavaAxIgnore";
  41 
  42 NSMutableDictionary *sRoles = nil;
  43 void initializeRoles();
  44 
  45 // Unique
  46 static JNF_CLASS_CACHE(sjc_AccessibleState, "javax/accessibility/AccessibleState");
  47 
  48 // Duplicate
  49 JNF_CLASS_CACHE(sjc_CAccessibility, "sun/lwawt/macosx/CAccessibility");
  50 JNF_CLASS_CACHE(sjc_AccessibleComponent, "javax/accessibility/AccessibleComponent");
  51 JNF_CLASS_CACHE(sjc_AccessibleContext, "javax/accessibility/AccessibleContext");
  52 JNF_CLASS_CACHE(sjc_Accessible, "javax/accessibility/Accessible");
  53 JNF_CLASS_CACHE(sjc_AccessibleRole, "javax/accessibility/AccessibleRole");
  54 JNF_CLASS_CACHE(sjc_Point, "java/awt/Point");
  55 JNF_CLASS_CACHE(sjc_AccessibleText, "javax/accessibility/AccessibleText");
  56 
  57 JNF_MEMBER_CACHE(sjf_key, sjc_AccessibleRole, "key", "Ljava/lang/String;");
  58 JNF_MEMBER_CACHE(sjf_X, sjc_Point, "x", "I");
  59 JNF_MEMBER_CACHE(sjf_Y, sjc_Point, "y", "I");
  60 
  61 NSSize getAxComponentSize(JNIEnv *env, jobject axComponent, jobject component)
  62 {
  63     static JNF_CLASS_CACHE(jc_Dimension, "java/awt/Dimension");
  64     static JNF_MEMBER_CACHE(jf_width, jc_Dimension, "width", "I");
  65     static JNF_MEMBER_CACHE(jf_height, jc_Dimension, "height", "I");
  66     static JNF_STATIC_MEMBER_CACHE(jm_getSize, sjc_CAccessibility, "getSize", "(Ljavax/accessibility/AccessibleComponent;Ljava/awt/Component;)Ljava/awt/Dimension;");
  67 
  68     jobject dimension = JNFCallStaticObjectMethod(env, jm_getSize, axComponent, component); // AWT_THREADING Safe (AWTRunLoopMode)
  69 
  70     if (dimension == NULL) return NSZeroSize;
  71     return NSMakeSize(JNFGetIntField(env, dimension, jf_width), JNFGetIntField(env, dimension, jf_height));
  72 }
  73 
  74 NSString *getJavaRole(JNIEnv *env, jobject axComponent, jobject component)
  75 {
  76     static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleRole, sjc_CAccessibility, "getAccessibleRole", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;");
  77     jobject axRole = JNFCallStaticObjectMethod(env, sjm_getAccessibleRole, axComponent, component); // AWT_THREADING Safe (AWTRunLoopMode)
  78     if (axRole == NULL) return @"unknown";
  79 
  80     NSString* str = JNFJavaToNSString(env, axRole);
  81     (*env)->DeleteLocalRef(env, axRole);
  82     return str;
  83 }
  84 
  85 jobject getAxSelection(JNIEnv *env, jobject axContext, jobject component)
  86 {
  87     static JNF_STATIC_MEMBER_CACHE(jm_getAccessibleSelection, sjc_CAccessibility, "getAccessibleSelection", "(Ljavax/accessibility/AccessibleContext;Ljava/awt/Component;)Ljavax/accessibility/AccessibleSelection;");
  88     return JNFCallStaticObjectMethod(env, jm_getAccessibleSelection, axContext, component); // AWT_THREADING Safe (AWTRunLoopMode)
  89 }
  90 
  91 jobject getAxContextSelection(JNIEnv *env, jobject axContext, jint index, jobject component)
  92 {
  93     static JNF_STATIC_MEMBER_CACHE(jm_ax_getAccessibleSelection, sjc_CAccessibility, "ax_getAccessibleSelection", "(Ljavax/accessibility/AccessibleContext;ILjava/awt/Component;)Ljavax/accessibility/Accessible;");
  94     return JNFCallStaticObjectMethod(env, jm_ax_getAccessibleSelection, axContext, index, component); // AWT_THREADING Safe (AWTRunLoopMode)
  95 }
  96 
  97 void setAxContextSelection(JNIEnv *env, jobject axContext, jint index, jobject component)
  98 {
  99     static JNF_STATIC_MEMBER_CACHE(jm_addAccessibleSelection, sjc_CAccessibility, "addAccessibleSelection", "(Ljavax/accessibility/AccessibleContext;ILjava/awt/Component;)V");
 100     JNFCallStaticVoidMethod(env, jm_addAccessibleSelection, axContext, index, component); // AWT_THREADING Safe (AWTRunLoopMode)
 101 }
 102 
 103 jobject getAxContext(JNIEnv *env, jobject accessible, jobject component)
 104 {
 105     static JNF_STATIC_MEMBER_CACHE(jm_getAccessibleContext, sjc_CAccessibility, "getAccessibleContext", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/AccessibleContext;");
 106     return JNFCallStaticObjectMethod(env, jm_getAccessibleContext, accessible, component); // AWT_THREADING Safe (AWTRunLoopMode)
 107 }
 108 
 109 BOOL isChildSelected(JNIEnv *env, jobject accessible, jint index, jobject component)
 110 {
 111     static JNF_STATIC_MEMBER_CACHE(jm_isAccessibleChildSelected, sjc_CAccessibility, "isAccessibleChildSelected", "(Ljavax/accessibility/Accessible;ILjava/awt/Component;)Z");
 112     return JNFCallStaticBooleanMethod(env, jm_isAccessibleChildSelected, accessible, index, component); // AWT_THREADING Safe (AWTRunLoopMode)
 113 }
 114 
 115 jobject getAxStateSet(JNIEnv *env, jobject axContext, jobject component)
 116 {
 117     static JNF_STATIC_MEMBER_CACHE(jm_getAccessibleStateSet, sjc_CAccessibility, "getAccessibleStateSet", "(Ljavax/accessibility/AccessibleContext;Ljava/awt/Component;)Ljavax/accessibility/AccessibleStateSet;");
 118     return JNFCallStaticObjectMethod(env, jm_getAccessibleStateSet, axContext, component); // AWT_THREADING Safe (AWTRunLoopMode)
 119 }
 120 
 121 BOOL containsAxState(JNIEnv *env, jobject axContext, jobject axState, jobject component)
 122 {
 123     static JNF_STATIC_MEMBER_CACHE(jm_contains, sjc_CAccessibility, "contains", "(Ljavax/accessibility/AccessibleContext;Ljavax/accessibility/AccessibleState;Ljava/awt/Component;)Z");
 124     return JNFCallStaticBooleanMethod(env, jm_contains, axContext, axState, component); // AWT_THREADING Safe (AWTRunLoopMode)
 125 }
 126 
 127 BOOL isVertical(JNIEnv *env, jobject axContext, jobject component)
 128 {
 129     static JNF_STATIC_MEMBER_CACHE(jm_VERTICAL, sjc_AccessibleState, "VERTICAL", "Ljavax/accessibility/AccessibleState;");
 130     jobject axVertState = JNFGetStaticObjectField(env, jm_VERTICAL);
 131     BOOL vertical = containsAxState(env, axContext, axVertState, component);
 132     (*env)->DeleteLocalRef(env, axVertState);
 133     return vertical;
 134 }
 135 
 136 BOOL isHorizontal(JNIEnv *env, jobject axContext, jobject component)
 137 {
 138     static JNF_STATIC_MEMBER_CACHE(jm_HORIZONTAL, sjc_AccessibleState, "HORIZONTAL", "Ljavax/accessibility/AccessibleState;");
 139     jobject axHorizState = JNFGetStaticObjectField(env, jm_HORIZONTAL);
 140     BOOL horizontal = containsAxState(env, axContext, axHorizState, component);
 141     (*env)->DeleteLocalRef(env, axHorizState);
 142     return horizontal;
 143 }
 144 
 145 BOOL isShowing(JNIEnv *env, jobject axContext, jobject component)
 146 {
 147     static JNF_STATIC_MEMBER_CACHE(jm_SHOWING, sjc_AccessibleState, "SHOWING", "Ljavax/accessibility/AccessibleState;");
 148     jobject axVisibleState = JNFGetStaticObjectField(env, jm_SHOWING);
 149     BOOL showing = containsAxState(env, axContext, axVisibleState, component);
 150     (*env)->DeleteLocalRef(env, axVisibleState);
 151     return showing;
 152 }
 153 
 154 BOOL isSelectable(JNIEnv *env, jobject axContext, jobject component)
 155 {
 156     static JNF_STATIC_MEMBER_CACHE( jm_SELECTABLE,
 157                                     sjc_AccessibleState,
 158                                     "SELECTABLE",
 159                                     "Ljavax/accessibility/AccessibleState;" );
 160     jobject axSelectableState = JNFGetStaticObjectField(env, jm_SELECTABLE);
 161     BOOL selectable = containsAxState(env, axContext, axSelectableState, component);
 162     (*env)->DeleteLocalRef(env, axSelectableState);
 163     return selectable;
 164 }
 165 
 166 NSPoint getAxComponentLocationOnScreen(JNIEnv *env, jobject axComponent, jobject component)
 167 {
 168     static JNF_STATIC_MEMBER_CACHE(jm_getLocationOnScreen, sjc_CAccessibility, "getLocationOnScreen", "(Ljavax/accessibility/AccessibleComponent;Ljava/awt/Component;)Ljava/awt/Point;");
 169     jobject jpoint = JNFCallStaticObjectMethod(env, jm_getLocationOnScreen, axComponent, component); // AWT_THREADING Safe (AWTRunLoopMode)
 170     if (jpoint == NULL) return NSZeroPoint;
 171     return NSMakePoint(JNFGetIntField(env, jpoint, sjf_X), JNFGetIntField(env, jpoint, sjf_Y));
 172 }
 173 
 174 jint getAxTextCharCount(JNIEnv *env, jobject axText, jobject component)
 175 {
 176     static JNF_STATIC_MEMBER_CACHE(jm_getCharCount, sjc_CAccessibility, "getCharCount", "(Ljavax/accessibility/AccessibleText;Ljava/awt/Component;)I");
 177     return JNFCallStaticIntMethod(env, jm_getCharCount, axText, component); // AWT_THREADING Safe (AWTRunLoopMode)
 178 }
 179 
 180 // The following JavaAccessibility methods are copied from the corresponding
 181 // NSAccessibility methods in NSAccessibility.m.
 182 //
 183 // They implement a key-value-like coding scheme to transform messages like
 184 //        [self accessibilityAttributeValue:NSAccessibilityEnabledAttribute]
 185 // into calls on to specific methods like
 186 //        [self accessibilityEnabledAttribute].
 187 
 188 static NSString *AttributeWithoutAXPrefix(NSString *attribute)
 189 {
 190     return [attribute hasPrefix:@"AX"] ? [attribute substringFromIndex:2] : attribute;
 191 }
 192 
 193 static SEL JavaAccessibilityAttributeGetter(NSString *attribute)
 194 {
 195     return NSSelectorFromString([NSString stringWithFormat:@"accessibility%@Attribute", AttributeWithoutAXPrefix(attribute)]);
 196 }
 197 
 198 static SEL JavaAccessibilityAttributeSettableTester(NSString *attribute)
 199 {
 200     return NSSelectorFromString([NSString stringWithFormat:@"accessibilityIs%@AttributeSettable", AttributeWithoutAXPrefix(attribute)]);
 201 }
 202 
 203 static SEL JavaAccessibilityAttributeSetter(NSString *attribute)
 204 {
 205     return NSSelectorFromString([NSString stringWithFormat:@"accessibilitySet%@Attribute:", AttributeWithoutAXPrefix(attribute)]);
 206 }
 207 
 208 id JavaAccessibilityAttributeValue(id element, NSString *attribute)
 209 {
 210     if (!JavaAccessibilityIsSupportedAttribute(element, attribute)) return nil;
 211 
 212     SEL getter = JavaAccessibilityAttributeGetter(attribute);
 213 #ifdef JAVA_AX_DEBUG_PARMS
 214     if (![element respondsToSelector:getter]) {
 215         JavaAccessibilityRaiseUnimplementedAttributeException(__FUNCTION__, element, attribute);
 216         return nil;
 217     }
 218 #endif
 219 
 220     return [element performSelector:getter];
 221 }
 222 
 223 BOOL JavaAccessibilityIsAttributeSettable(id element, NSString *attribute)
 224 {
 225     if (!JavaAccessibilityIsSupportedAttribute(element, attribute)) return NO;
 226 
 227     SEL tester = JavaAccessibilityAttributeSettableTester(attribute);
 228 #ifdef JAVA_AX_DEBUG_PARMS
 229     if (![element respondsToSelector:tester]) {
 230         JavaAccessibilityRaiseUnimplementedAttributeException(__FUNCTION__, element, attribute);
 231         return NO;
 232     }
 233 #endif
 234 
 235     return [element performSelector:tester] != nil;
 236 }
 237 
 238 void JavaAccessibilitySetAttributeValue(id element, NSString *attribute ,id value)
 239 {
 240     if (!JavaAccessibilityIsSupportedAttribute(element, attribute)) return;
 241 
 242     SEL setter = JavaAccessibilityAttributeSetter(attribute);
 243     if (![element accessibilityIsAttributeSettable:attribute]) return;
 244 
 245 #ifdef JAVA_AX_DEBUG_PARMS
 246     if (![element respondsToSelector:setter]) {
 247         JavaAccessibilityRaiseUnimplementedAttributeException(__FUNCTION__, element, attribute);
 248         return;
 249     }
 250 #endif
 251 
 252     [element performSelector:setter withObject:value];
 253 }
 254 
 255 static BOOL JavaAccessibilityIsSupportedAttribute(id element, NSString *attribute)
 256 {
 257     return [[element accessibilityAttributeNames] indexOfObject:attribute] != NSNotFound;
 258 }
 259 
 260 /*
 261  * Class:     sun_lwawt_macosx_CAccessibility
 262  * Method:    roleKey
 263  * Signature: (Ljavax/accessibility/AccessibleRole;)Ljava/lang/String;
 264  */
 265 JNIEXPORT jstring JNICALL Java_sun_lwawt_macosx_CAccessibility_roleKey
 266 (JNIEnv *env, jclass clz, jobject axRole)
 267 {
 268     return JNFGetObjectField(env, axRole, sjf_key);
 269 }
 270 
 271 
 272 // errors from NSAccessibilityErrors
 273 void JavaAccessibilityRaiseSetAttributeToIllegalTypeException(const char *functionName, id element, NSString *attribute, id value)
 274 {
 275     NSString *reason = [NSString stringWithFormat:@"%s: Attempt set \"%@\" attribute to illegal type of value (%@:%@) for element: %@", functionName, attribute, [value class], value, element];
 276     _JavaAccessibilityRaiseException(reason, kAXErrorIllegalArgument);
 277 }
 278 
 279 void JavaAccessibilityRaiseUnimplementedAttributeException(const char *functionName, id element, NSString *attribute)
 280 {
 281     NSString *reason = [NSString stringWithFormat:@"%s: \"%@\" attribute unimplemented by element: %@", functionName, attribute, element];
 282     _JavaAccessibilityRaiseException(reason, kAXErrorFailure);
 283 }
 284 
 285 void JavaAccessibilityRaiseIllegalParameterTypeException(const char *functionName, id element, NSString *attribute, id parameter)
 286 {
 287     NSString *reason = [NSString stringWithFormat:@"%s: \"%@\" parameterized attribute passed illegal type of parameter (%@:%@) for element: %@", functionName, attribute, [parameter class], parameter, element];
 288     _JavaAccessibilityRaiseException(reason, kAXErrorIllegalArgument);
 289 }
 290 
 291 static void _JavaAccessibilityRaiseException(NSString *reason, SInt32 errorCode)
 292 {
 293     JavaAccessibilityLogError(reason);
 294     [[NSException exceptionWithName:NSAccessibilityException reason:reason userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:errorCode], NSAccessibilityErrorCodeExceptionInfo, nil]] raise];
 295 }
 296 
 297 static void JavaAccessibilityLogError(NSString *message)
 298 {
 299     NSLog(@"!!! %@", message);
 300 }
 301 
 302 // end appKit copies
 303 
 304 /*
 305  To get the roles below, verify the perl has table below called macRoleCodes is correct.
 306  Then copy the perl code into a perl script called makeAxTables.pl (make
 307  sure to chmod +x makeAxTables.pl). Then run the perl script like this:
 308 
 309  ./makeAxTables.pl /Builds/jdk1_4_1/
 310 
 311  It will then write the void initializeRoles() method below to stdout.
 312 
 313  Any new AccessibleRole items that aren't in the perl hash table will be written out as follows:
 314  // Unknown AccessibleRole: <role>
 315 
 316  Add these unknowns to the perl hash table and re-run the script, and use the new generated table.
 317 */
 318 
 319 // NOTE: Don't modify this directly. It is machine generated. See below
 320 void initializeRoles()
 321 {
 322     sRoles = [[NSMutableDictionary alloc] initWithCapacity:56];
 323 
 324     [sRoles setObject:JavaAccessibilityIgnore forKey:@"alert"];
 325     [sRoles setObject:NSAccessibilityGroupRole forKey:@"awtcomponent"];
 326     [sRoles setObject:NSAccessibilityGroupRole forKey:@"canvas"];
 327     [sRoles setObject:NSAccessibilityCheckBoxRole forKey:@"checkbox"];
 328     [sRoles setObject:JavaAccessibilityIgnore forKey:@"colorchooser"];
 329     [sRoles setObject:NSAccessibilityColumnRole forKey:@"columnheader"];
 330     [sRoles setObject:NSAccessibilityComboBoxRole forKey:@"combobox"];
 331     [sRoles setObject:NSAccessibilityTextFieldRole forKey:@"dateeditor"];
 332     [sRoles setObject:NSAccessibilityImageRole forKey:@"desktopicon"];
 333     [sRoles setObject:JavaAccessibilityIgnore forKey:@"desktoppane"];
 334     [sRoles setObject:JavaAccessibilityIgnore forKey:@"dialog"];
 335     [sRoles setObject:JavaAccessibilityIgnore forKey:@"directorypane"];
 336     [sRoles setObject:JavaAccessibilityIgnore forKey:@"filechooser"];
 337     [sRoles setObject:JavaAccessibilityIgnore forKey:@"filler"];
 338     [sRoles setObject:JavaAccessibilityIgnore forKey:@"fontchooser"];
 339     [sRoles setObject:JavaAccessibilityIgnore forKey:@"frame"];
 340     [sRoles setObject:JavaAccessibilityIgnore forKey:@"glasspane"];
 341     [sRoles setObject:NSAccessibilityGroupRole forKey:@"groupbox"];
 342     [sRoles setObject:NSAccessibilityStaticTextRole forKey:@"hyperlink"]; //maybe a group?
 343     [sRoles setObject:NSAccessibilityImageRole forKey:@"icon"];
 344     [sRoles setObject:NSAccessibilityGroupRole forKey:@"internalframe"];
 345     [sRoles setObject:NSAccessibilityStaticTextRole forKey:@"label"];
 346     [sRoles setObject:JavaAccessibilityIgnore forKey:@"layeredpane"];
 347     [sRoles setObject:NSAccessibilityListRole forKey:@"list"]; // maybe a group? AccessibleRole.java says a list is: "An object that presents a list of objects to the user and allows the user to select one or more of them."
 348     [sRoles setObject:NSAccessibilityListRole forKey:@"listitem"];
 349     [sRoles setObject:NSAccessibilityMenuRole forKey:@"menu"];
 350     [sRoles setObject:NSAccessibilityMenuBarRole forKey:@"menubar"];
 351     [sRoles setObject:NSAccessibilityMenuItemRole forKey:@"menuitem"];
 352     [sRoles setObject:JavaAccessibilityIgnore forKey:@"optionpane"];
 353     [sRoles setObject:NSAccessibilityRadioButtonRole forKey:@"pagetab"]; // cmcnote: cocoa tabs are radio buttons - one selected button out of a group of options
 354     [sRoles setObject:NSAccessibilityTabGroupRole forKey:@"pagetablist"];
 355     [sRoles setObject:JavaAccessibilityIgnore forKey:@"panel"];
 356     [sRoles setObject:NSAccessibilityTextFieldRole forKey:@"passwordtext"];
 357     [sRoles setObject:NSAccessibilityPopUpButtonRole forKey:@"popupmenu"];
 358     [sRoles setObject:NSAccessibilityProgressIndicatorRole forKey:@"progressbar"];
 359     [sRoles setObject:NSAccessibilityButtonRole forKey:@"pushbutton"];
 360     [sRoles setObject:NSAccessibilityRadioButtonRole forKey:@"radiobutton"];
 361     [sRoles setObject:JavaAccessibilityIgnore forKey:@"rootpane"];
 362     [sRoles setObject:NSAccessibilityRowRole forKey:@"rowheader"];
 363     [sRoles setObject:NSAccessibilityScrollBarRole forKey:@"scrollbar"];
 364     [sRoles setObject:NSAccessibilityScrollAreaRole forKey:@"scrollpane"];
 365     [sRoles setObject:JavaAccessibilityIgnore forKey:@"separator"];
 366     [sRoles setObject:NSAccessibilitySliderRole forKey:@"slider"];
 367     [sRoles setObject:NSAccessibilityIncrementorRole forKey:@"spinbox"];
 368     [sRoles setObject:NSAccessibilitySplitGroupRole forKey:@"splitpane"];
 369     [sRoles setObject:NSAccessibilityValueIndicatorRole forKey:@"statusbar"];
 370     [sRoles setObject:NSAccessibilityGroupRole forKey:@"swingcomponent"];
 371     [sRoles setObject:NSAccessibilityTableRole forKey:@"table"];
 372     [sRoles setObject:NSAccessibilityTextFieldRole forKey:@"text"];
 373     [sRoles setObject:NSAccessibilityTextAreaRole forKey:@"textarea"]; // supports top/bottom of document notifications: CAccessability.getAccessibleRole()
 374     [sRoles setObject:NSAccessibilityCheckBoxRole forKey:@"togglebutton"];
 375     [sRoles setObject:NSAccessibilityToolbarRole forKey:@"toolbar"];
 376     [sRoles setObject:JavaAccessibilityIgnore forKey:@"tooltip"];
 377     [sRoles setObject:NSAccessibilityBrowserRole forKey:@"tree"];
 378     [sRoles setObject:NSAccessibilityUnknownRole forKey:@"unknown"];
 379     [sRoles setObject:JavaAccessibilityIgnore forKey:@"viewport"];
 380     [sRoles setObject:JavaAccessibilityIgnore forKey:@"window"];
 381 }