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 "JavaTextAccessibility.h"
  27 #import "JavaAccessibilityAction.h"
  28 #import "JavaAccessibilityUtilities.h"
  29 #import "ThreadUtilities.h"
  30 
  31 
  32 static JNF_CLASS_CACHE(sjc_CAccessibleText, "sun/lwawt/macosx/CAccessibleText");
  33 static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleText, sjc_CAccessibility, "getAccessibleText", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/AccessibleText;");
  34 static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleEditableText, sjc_CAccessibleText, "getAccessibleEditableText", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/AccessibleEditableText;");
  35 static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleName, sjc_CAccessibility, "getAccessibleName", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;");
  36 
  37 /*
  38  * Converts an int array to an NSRange wrapped inside an NSValue
  39  * takes [start, end] values and returns [start, end - start]
  40  */
  41 NSValue *javaIntArrayToNSRangeValue(JNIEnv* env, jintArray array) {
  42     jint *values = (*env)->GetIntArrayElements(env, array, 0);
  43     if (values == NULL) {
  44         // Note: Java will not be on the stack here so a java exception can't happen and no need to call ExceptionCheck.
  45         NSLog(@"%s failed calling GetIntArrayElements", __FUNCTION__);
  46         return nil;
  47     };
  48     NSValue *value = [NSValue valueWithRange:NSMakeRange(values[0], values[1] - values[0])];
  49     (*env)->ReleaseIntArrayElements(env, array, values, 0);
  50     return value;
  51 }
  52 
  53 @implementation JavaTextAccessibility
  54 
  55 // based strongly upon NSTextViewAccessibility:accessibilityAttributeNames
  56 - (NSArray *)initializeAttributeNamesWithEnv:(JNIEnv *)env
  57 {
  58     static NSArray *attributes = nil;
  59 
  60     if (attributes == nil) {
  61         //APPKIT_LOCK;
  62         if (attributes == nil) {
  63             NSMutableArray *temp = [[super initializeAttributeNamesWithEnv:env] mutableCopy];
  64             //[temp removeObject:NSAccessibilityTitleAttribute]; // title may have been set in the superclass implementation - some static text reports from java that it has a name
  65             [temp addObjectsFromArray:[NSArray arrayWithObjects:
  66                 NSAccessibilityValueAttribute,
  67                 NSAccessibilitySelectedTextAttribute,
  68                 NSAccessibilitySelectedTextRangeAttribute,
  69                 NSAccessibilityNumberOfCharactersAttribute,
  70                 NSAccessibilityVisibleCharacterRangeAttribute,
  71                 NSAccessibilityInsertionPointLineNumberAttribute,
  72                 //    NSAccessibilitySharedTextUIElementsAttribute, // cmcnote: investigate what these two are for. currently unimplemented
  73                 //    NSAccessibilitySharedCharacterRangeAttribute,
  74                 nil]];
  75             attributes = [[NSArray alloc] initWithArray:temp];
  76             [temp release];
  77         }
  78         //APPKIT_UNLOCK;
  79     }
  80     return attributes;
  81 }
  82 
  83 // copied from NSTextViewAccessibility.
  84 - (NSArray *)accessibilityParameterizedAttributeNames
  85 {
  86     static NSArray *attributes = nil;
  87 
  88     if (attributes == nil) {
  89         //APPKIT_LOCK;
  90         if (attributes == nil) {
  91             attributes = [[NSArray alloc] initWithObjects:
  92                 NSAccessibilityLineForIndexParameterizedAttribute,
  93                 NSAccessibilityRangeForLineParameterizedAttribute,
  94                 NSAccessibilityStringForRangeParameterizedAttribute,
  95                 NSAccessibilityRangeForPositionParameterizedAttribute,
  96                 NSAccessibilityRangeForIndexParameterizedAttribute,
  97                 NSAccessibilityBoundsForRangeParameterizedAttribute,
  98                 //NSAccessibilityRTFForRangeParameterizedAttribute, // cmcnote: not sure when/how these three are used. Investigate. radr://3960026
  99                 //NSAccessibilityStyleRangeForIndexParameterizedAttribute,
 100                 //NSAccessibilityAttributedStringForRangeParameterizedAttribute,
 101                 nil];
 102         }
 103         //APPKIT_UNLOCK;
 104     }
 105     return attributes;
 106 }
 107 
 108 - (NSString *)accessibilityValueAttribute
 109 {
 110     JNIEnv *env = [ThreadUtilities getJNIEnv];
 111     if ([[self accessibilityRoleAttribute] isEqualToString:NSAccessibilityStaticTextRole]) {
 112         // if it's static text, the AppKit AXValue is the java accessibleName
 113         jobject axName = JNFCallStaticObjectMethod(env, sjm_getAccessibleName, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
 114         if (axName != NULL) {
 115             NSString* str = JNFJavaToNSString(env, axName);
 116             (*env)->DeleteLocalRef(env, axName);
 117             return str;
 118         }
 119         // value is still nil if no accessibleName for static text. Below, try to get the accessibleText.
 120     }
 121 
 122     // cmcnote: inefficient to make three distinct JNI calls. Coalesce. radr://3951923
 123     jobject axText = JNFCallStaticObjectMethod(env, sjm_getAccessibleText, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
 124     if (axText == NULL) return nil;
 125     (*env)->DeleteLocalRef(env, axText);
 126     
 127     jobject axEditableText = JNFCallStaticObjectMethod(env, sjm_getAccessibleEditableText, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
 128     if (axEditableText == NULL) return nil;
 129 
 130     static JNF_STATIC_MEMBER_CACHE(jm_getTextRange, sjc_CAccessibleText, "getTextRange", "(Ljavax/accessibility/AccessibleEditableText;IILjava/awt/Component;)Ljava/lang/String;");
 131     jobject jrange = JNFCallStaticObjectMethod(env, jm_getTextRange, axEditableText, 0, getAxTextCharCount(env, axEditableText, fComponent), fComponent);
 132     NSString *string = JNFJavaToNSString(env, jrange); // AWT_THREADING Safe (AWTRunLoop)
 133 
 134     (*env)->DeleteLocalRef(env, jrange);
 135     (*env)->DeleteLocalRef(env, axEditableText);
 136     
 137     if (string == nil) string = @"";
 138     return string;
 139 }
 140 
 141 - (BOOL)accessibilityIsValueAttributeSettable
 142 {
 143     // if text is enabled and editable, it's settable (according to NSCellTextAttributesAccessibility)
 144     BOOL isEnabled = [(NSNumber *)[self accessibilityEnabledAttribute] boolValue];
 145     if (!isEnabled) return NO;
 146 
 147     JNIEnv* env = [ThreadUtilities getJNIEnv];
 148     jobject axEditableText = JNFCallStaticObjectMethod(env, sjm_getAccessibleEditableText, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
 149     if (axEditableText == NULL) return NO;
 150     (*env)->DeleteLocalRef(env, axEditableText);
 151     return YES;
 152 }
 153 
 154 - (void)accessibilitySetValueAttribute:(id)value
 155 {
 156 // cmcnote: should set the accessibleEditableText to the stringValue of value - AccessibleEditableText.setTextContents(String s)
 157 #ifdef JAVA_AX_DEBUG
 158     NSLog(@"Not yet implemented: %s\n", __FUNCTION__); // radr://3954018
 159 #endif
 160 }
 161 
 162 // Currently selected text (NSString)
 163 - (NSString *)accessibilitySelectedTextAttribute
 164 {
 165     JNIEnv* env = [ThreadUtilities getJNIEnv];
 166     static JNF_STATIC_MEMBER_CACHE(jm_getSelectedText, sjc_CAccessibleText, "getSelectedText", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;");
 167     jobject axText = JNFCallStaticObjectMethod(env, jm_getSelectedText, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
 168     if (axText == NULL) return @"";
 169     NSString* str = JNFJavaToNSString(env, axText);
 170     (*env)->DeleteLocalRef(env, axText);
 171     return str;
 172 }
 173 
 174 - (BOOL)accessibilityIsSelectedTextAttributeSettable
 175 {
 176     return YES; //cmcnote: for AXTextField that's selectable, it's settable. Investigate further.
 177 }
 178 
 179 - (void)accessibilitySetSelectedTextAttribute:(id)value
 180 {
 181 #ifdef JAVA_AX_DEBUG_PARMS
 182     if (![value isKindOfClass:[NSString class]]) {
 183         JavaAccessibilityRaiseSetAttributeToIllegalTypeException(__FUNCTION__, self, NSAccessibilitySelectedTextAttribute, value);
 184         return;
 185     }
 186 #endif
 187 
 188     JNIEnv *env = [ThreadUtilities getJNIEnv];
 189     jstring jstringValue = JNFNSToJavaString(env, (NSString *)value);
 190     static JNF_STATIC_MEMBER_CACHE(jm_setSelectedText, sjc_CAccessibleText, "setSelectedText", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;Ljava/lang/String;)V");
 191     JNFCallStaticVoidMethod(env, jm_setSelectedText, fAccessible, fComponent, jstringValue); // AWT_THREADING Safe (AWTRunLoop)
 192 }
 193 
 194 // Range of selected text (NSValue)
 195 - (NSValue *)accessibilitySelectedTextRangeAttribute
 196 {
 197     JNIEnv *env = [ThreadUtilities getJNIEnv];
 198     static JNF_STATIC_MEMBER_CACHE(jm_getSelectedTextRange, sjc_CAccessibleText, "getSelectedTextRange", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)[I");
 199     jintArray axTextRange = JNFCallStaticObjectMethod(env, jm_getSelectedTextRange, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
 200     if (axTextRange == NULL) return nil;
 201 
 202     return javaIntArrayToNSRangeValue(env, axTextRange);
 203 }
 204 
 205 - (BOOL)accessibilityIsSelectedTextRangeAttributeSettable
 206 {
 207     return [(NSNumber *)[self accessibilityEnabledAttribute] boolValue]; // cmcnote: also may want to find out if isSelectable. Investigate.
 208 }
 209 
 210 - (void)accessibilitySetSelectedTextRangeAttribute:(id)value
 211 {
 212 #ifdef JAVA_AX_DEBUG_PARMS
 213     if (!([value isKindOfClass:[NSValue class]] && strcmp([(NSValue *)value objCType], @encode(NSRange)) == 0)) {
 214         JavaAccessibilityRaiseSetAttributeToIllegalTypeException(__FUNCTION__, self, NSAccessibilitySelectedTextRangeAttribute, value);
 215         return;
 216     }
 217 #endif
 218 
 219     NSRange range = [(NSValue *)value rangeValue];
 220     jint startIndex = range.location;
 221     jint endIndex = startIndex + range.length;
 222 
 223     JNIEnv *env = [ThreadUtilities getJNIEnv];
 224     static JNF_STATIC_MEMBER_CACHE(jm_setSelectedTextRange, sjc_CAccessibleText, "setSelectedTextRange", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;II)V");
 225     JNFCallStaticVoidMethod(env, jm_setSelectedTextRange, fAccessible, fComponent, startIndex, endIndex); // AWT_THREADING Safe (AWTRunLoop)
 226 }
 227 
 228 - (NSNumber *)accessibilityNumberOfCharactersAttribute
 229 {
 230     // cmcnote: should coalesce these two calls - radr://3951923
 231     // also, static text doesn't always have accessibleText. if axText is null, should get the charcount of the accessibleName instead
 232     JNIEnv *env = [ThreadUtilities getJNIEnv];
 233     jobject axText = JNFCallStaticObjectMethod(env, sjm_getAccessibleText, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
 234     NSNumber* num = [NSNumber numberWithInt:getAxTextCharCount(env, axText, fComponent)];
 235     (*env)->DeleteLocalRef(env, axText);
 236     return num;
 237 }
 238 
 239 - (BOOL)accessibilityIsNumberOfCharactersAttributeSettable
 240 {
 241     return NO; // according to NSTextViewAccessibility.m and NSCellTextAttributesAccessibility.m
 242 }
 243 
 244 - (NSValue *)accessibilityVisibleCharacterRangeAttribute
 245 {
 246     JNIEnv *env = [ThreadUtilities getJNIEnv];
 247     static JNF_STATIC_MEMBER_CACHE(jm_getVisibleCharacterRange, sjc_CAccessibleText, "getVisibleCharacterRange", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)[I");
 248     jintArray axTextRange = JNFCallStaticObjectMethod(env, jm_getVisibleCharacterRange, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
 249     if (axTextRange == NULL) return nil;
 250 
 251     return javaIntArrayToNSRangeValue(env, axTextRange);
 252 }
 253 
 254 - (BOOL)accessibilityIsVisibleCharacterRangeAttributeSettable
 255 {
 256 #ifdef JAVA_AX_DEBUG
 257     NSLog(@"Not yet implemented: %s\n", __FUNCTION__);
 258 #endif
 259     return NO;
 260 }
 261 
 262 - (NSValue *)accessibilityInsertionPointLineNumberAttribute
 263 {
 264     JNIEnv *env = [ThreadUtilities getJNIEnv];
 265     static JNF_STATIC_MEMBER_CACHE(jm_getLineNumberForInsertionPoint, sjc_CAccessibleText, "getLineNumberForInsertionPoint", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)I");
 266     jint row = JNFCallStaticIntMethod(env, jm_getLineNumberForInsertionPoint, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
 267     if (row < 0) return nil;
 268     return [NSNumber numberWithInt:row];
 269 }
 270 
 271 - (BOOL)accessibilityIsInsertionPointLineNumberAttributeSettable
 272 {
 273 #ifdef JAVA_AX_DEBUG
 274     NSLog(@"Not yet implemented: %s\n", __FUNCTION__);
 275 #endif
 276     return NO;
 277 }
 278 
 279 // parameterized attributes
 280 
 281 //
 282 // Usage of accessibilityBoundsForRangeAttributeForParameter:
 283 // ---
 284 // called by VoiceOver when interacting with text via ctrl-option-shift-downArrow.
 285 // Need to know bounding box for the character / word / line of interest in
 286 // order to draw VoiceOver cursor
 287 //
 288 - (NSValue *)accessibilityBoundsForRangeAttributeForParameter:(id)parameter
 289 {
 290 #ifdef JAVA_AX_DEBUG_PARMS
 291     if (!([parameter isKindOfClass:[NSValue class]] && strcmp([(NSValue *)parameter objCType], @encode(NSRange)) == 0)) {
 292         JavaAccessibilityRaiseIllegalParameterTypeException(__FUNCTION__, self, NSAccessibilityBoundsForRangeParameterizedAttribute, parameter);
 293         return nil;
 294     }
 295 #endif
 296 
 297     NSRange range = [(NSValue *)parameter rangeValue];
 298 
 299     JNIEnv *env = [ThreadUtilities getJNIEnv];
 300     static JNF_STATIC_MEMBER_CACHE(jm_getBoundsForRange, sjc_CAccessibleText, "getBoundsForRange", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;II)[D");
 301     jdoubleArray axBounds = (jdoubleArray)JNFCallStaticObjectMethod(env, jm_getBoundsForRange, fAccessible, fComponent, range.location, range.length); // AWT_THREADING Safe (AWTRunLoop)
 302     if (axBounds == NULL) return nil;
 303 
 304     // We cheat because we know that the array is 4 elements long (x, y, width, height)
 305     jdouble *values = (*env)->GetDoubleArrayElements(env, axBounds, 0);
 306     if (values == NULL) {
 307         // Note: Java will not be on the stack here so a java exception can't happen and no need to call ExceptionCheck.
 308         NSLog(@"%s failed calling GetDoubleArrayElements", __FUNCTION__); 
 309         return nil;
 310     };
 311     NSRect bounds;
 312     bounds.origin.x = values[0];
 313     bounds.origin.y = [[[[self view] window] screen] frame].size.height - values[1] - values[3]; //values[1] is y-coord from top-left of screen. Flip. Account for the height (values[3]) when flipping
 314     bounds.size.width = values[2];
 315     bounds.size.height = values[3];
 316     NSValue *result = [NSValue valueWithRect:bounds];
 317     (*env)->ReleaseDoubleArrayElements(env, axBounds, values, 0);
 318     return result;
 319 }
 320 
 321 - (NSNumber *)accessibilityLineForIndexAttributeForParameter:(id)parameter
 322 {
 323     NSNumber *line = (NSNumber *) parameter;
 324     if (line == nil) return nil;
 325 
 326     JNIEnv *env = [ThreadUtilities getJNIEnv];
 327     static JNF_STATIC_MEMBER_CACHE(jm_getLineNumberForIndex, sjc_CAccessibleText, "getLineNumberForIndex", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;I)I");
 328     jint row = JNFCallStaticIntMethod(env, jm_getLineNumberForIndex, fAccessible, fComponent, [line intValue]); // AWT_THREADING Safe (AWTRunLoop)
 329     if (row < 0) return nil;
 330     return [NSNumber numberWithInt:row];
 331 }
 332 
 333 - (NSValue *)accessibilityRangeForLineAttributeForParameter:(id)parameter
 334 {
 335     NSNumber *line = (NSNumber *) parameter;
 336     if (line == nil) return nil;
 337 
 338     JNIEnv *env = [ThreadUtilities getJNIEnv];
 339     static JNF_STATIC_MEMBER_CACHE(jm_getRangeForLine, sjc_CAccessibleText, "getRangeForLine", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;I)[I");
 340     jintArray axTextRange = (jintArray)JNFCallStaticObjectMethod(env, jm_getRangeForLine, fAccessible, fComponent, [line intValue]); // AWT_THREADING Safe (AWTRunLoop)
 341     if (axTextRange == NULL) return nil;
 342 
 343     return javaIntArrayToNSRangeValue(env,axTextRange);
 344 }
 345 
 346 //
 347 // Usage of accessibilityStringForRangeAttributeForParameter:
 348 // ---
 349 // called by VoiceOver when interacting with text via ctrl-option-shift-downArrow.
 350 // VO needs to know the particular string its currently dealing with so it can
 351 // speak the string
 352 //
 353 - (NSString *)accessibilityStringForRangeAttributeForParameter:(id)parameter
 354 {
 355 #ifdef JAVA_AX_DEBUG_PARMS
 356     if (!([parameter isKindOfClass:[NSValue class]] && strcmp([(NSValue *)parameter objCType], @encode(NSRange)) == 0)) {
 357         JavaAccessibilityRaiseIllegalParameterTypeException(__FUNCTION__, self, NSAccessibilityBoundsForRangeParameterizedAttribute, parameter);
 358         return nil;
 359     }
 360 #endif
 361 
 362     NSRange range = [(NSValue *)parameter rangeValue];
 363 
 364     JNIEnv *env = [ThreadUtilities getJNIEnv];
 365     static JNF_STATIC_MEMBER_CACHE(jm_getStringForRange, sjc_CAccessibleText, "getStringForRange", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;II)Ljava/lang/String;");
 366     jstring jstringForRange = (jstring)JNFCallStaticObjectMethod(env, jm_getStringForRange, fAccessible, fComponent, range.location, range.length); // AWT_THREADING Safe (AWTRunLoop)
 367 
 368     if (jstringForRange == NULL) return @"";
 369     NSString* str = JNFJavaToNSString(env, jstringForRange);
 370     (*env)->DeleteLocalRef(env, jstringForRange);
 371     return str;
 372 }
 373 
 374 //
 375 // Usage of accessibilityRangeForPositionAttributeForParameter:
 376 // ---
 377 // cmcnote: I'm not sure when this is called / how it's used. Investigate.
 378 // probably could be used in a special text-only accessibilityHitTest to
 379 // find the index of the string under the mouse?
 380 //
 381 - (NSValue *)accessibilityRangeForPositionAttributeForParameter:(id)parameter
 382 {
 383 #ifdef JAVA_AX_DEBUG_PARMS
 384     if (!([parameter isKindOfClass:[NSValue class]] && strcmp([(NSValue *)parameter objCType], @encode(NSPoint)) == 0)) {
 385         JavaAccessibilityRaiseIllegalParameterTypeException(__FUNCTION__, self, NSAccessibilityRangeForPositionParameterizedAttribute, parameter);
 386         return nil;
 387     }
 388 #endif
 389 
 390     NSPoint point = [(NSValue *)parameter pointValue]; // point is in screen coords
 391     point.y = [[[[self view] window] screen] frame].size.height - point.y; // flip into java screen coords (0 is at upper-left corner of screen)
 392 
 393     JNIEnv *env = [ThreadUtilities getJNIEnv];
 394     static JNF_STATIC_MEMBER_CACHE(jm_getCharacterIndexAtPosition, sjc_CAccessibleText, "getCharacterIndexAtPosition", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;II)I");
 395     jint charIndex = JNFCallStaticIntMethod(env, jm_getCharacterIndexAtPosition, fAccessible, fComponent, point.x, point.y); // AWT_THREADING Safe (AWTRunLoop)
 396     if (charIndex == -1) return nil;
 397 
 398     // AccessibleText.getIndexAtPoint returns -1 for an invalid point
 399     NSRange range = NSMakeRange(charIndex, 1); //range's length is 1 - one-character range
 400     return [NSValue valueWithRange:range];
 401 }
 402 
 403 //
 404 // Usage of accessibilityRangeForIndexAttributeForParameter:
 405 // ---
 406 // cmcnote: I'm not sure when this is called / how it's used. Investigate.
 407 // AppKit version calls: [string rangeOfComposedCharacterSequenceAtIndex:index]
 408 // We call: CAccessibility.getRangeForIndex, which calls AccessibleText.getAtIndex(AccessibleText.WORD, index)
 409 // to determine the word closest to the given index. Then we find the length/location of this string.
 410 //
 411 - (NSValue *)accessibilityRangeForIndexAttributeForParameter:(id)parameter
 412 {
 413 #ifdef JAVA_AX_DEBUG_PARMS
 414     if (![parameter isKindOfClass:[NSNumber class]]) {
 415         JavaAccessibilityRaiseIllegalParameterTypeException(__FUNCTION__, self, NSAccessibilityRangeForIndexParameterizedAttribute, parameter);
 416         return nil;
 417     }
 418 #endif
 419 
 420     NSUInteger index = [(NSNumber *)parameter unsignedIntegerValue];
 421 
 422     JNIEnv *env = [ThreadUtilities getJNIEnv];
 423     static JNF_STATIC_MEMBER_CACHE(jm_getRangeForIndex, sjc_CAccessibleText, "getRangeForIndex", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;I)[I");
 424     jintArray axTextRange = (jintArray)JNFCallStaticObjectMethod(env, jm_getRangeForIndex, fAccessible, fComponent, index); // AWT_THREADING Safe (AWTRunLoop)
 425     if (axTextRange == NULL) return nil;
 426 
 427     return javaIntArrayToNSRangeValue(env, axTextRange);
 428 }
 429 
 430 /* 
 431  * - (NSDictionary *)getActions:(JNIEnv *)env { ... }
 432  *
 433  * In the future, possibly add support: Editable text has AXShowMenu.
 434  * Textfields have AXConfirm.
 435  *
 436  * Note: JLabels (static text) in JLists have a press/click selection action
 437  *   which is currently handled in superclass JavaComponentAccessibility.
 438  *   If function is added here be sure to use [super getActions:env] for JLabels.
 439  */
 440 
 441 @end