Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8256109: Create implementation for NSAccessibilityButton protocol #1549

Closed
wants to merge 16 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -30,7 +30,7 @@
// <http://archives.java.sun.com/archives/java-access.html> (Sun's mailing list for Java accessibility)

#import "JavaComponentAccessibility.h"

#import "a11y/CommonComponentAccessibility.h"
#import "sun_lwawt_macosx_CAccessibility.h"

#import <AppKit/AppKit.h>
Expand Down Expand Up @@ -145,24 +145,6 @@ - (NSArray *)accessibilityRowsAttribute;
- (NSArray *)accessibilityColumnsAttribute;
@end


// In order to use a new NSAccessibility API and since our components
// are represented as a custom UI elements we need to implement a set
// of custom protocols. Definitions of these protocols will start here.

// This is a root interface in the NSAccessibility* protocols hierarchy
// and all the component-specific protocols should be derived from it.
// It is also a place for the functions that might be exposed by all the
// component accessibility peers.
// Please see https://developer.apple.com/documentation/appkit/nsaccessibilityprotocol
// for more details.
@interface CommonComponentAccessibility : JavaComponentAccessibility <NSAccessibilityElement> {

}
- (NSRect)accessibilityFrame;
- (nullable id)accessibilityParent;
@end

@implementation JavaComponentAccessibility

- (NSString *)description
Expand Down Expand Up @@ -438,18 +420,23 @@ + (JavaComponentAccessibility *) createWithParent:(JavaComponentAccessibility *)

// otherwise, create a new instance
JavaComponentAccessibility *newChild = nil;
if ([javaRole isEqualToString:@"pagetablist"]) {
newChild = [TabGroupAccessibility alloc];
} else if ([javaRole isEqualToString:@"table"]) {
newChild = [TableAccessibility alloc];
} else if ([javaRole isEqualToString:@"scrollpane"]) {
newChild = [ScrollAreaAccessibility alloc];
} else {
NSString *nsRole = [sRoles objectForKey:javaRole];
if ([nsRole isEqualToString:NSAccessibilityStaticTextRole] || [nsRole isEqualToString:NSAccessibilityTextAreaRole] || [nsRole isEqualToString:NSAccessibilityTextFieldRole]) {
newChild = [JavaTextAccessibility alloc];
newChild = [CommonComponentAccessibility getComponentAccessibility:javaRole];
if (newChild == nil) {
if ([javaRole isEqualToString:@"pagetablist"]) {
newChild = [TabGroupAccessibility alloc];
} else if ([javaRole isEqualToString:@"table"]) {
newChild = [TableAccessibility alloc];
} else if ([javaRole isEqualToString:@"scrollpane"]) {
newChild = [ScrollAreaAccessibility alloc];
} else {
newChild = [JavaComponentAccessibility alloc];
NSString *nsRole = [sRoles objectForKey:javaRole];
if ([nsRole isEqualToString:NSAccessibilityStaticTextRole] ||
[nsRole isEqualToString:NSAccessibilityTextAreaRole] ||
[nsRole isEqualToString:NSAccessibilityTextFieldRole]) {
newChild = [JavaTextAccessibility alloc];
} else {
newChild = [JavaComponentAccessibility alloc];
}
}
}

Expand Down Expand Up @@ -2041,32 +2028,6 @@ - (id)accessibilityColumnCountAttribute {
}
@end

@implementation CommonComponentAccessibility
// NSAccessibilityElement protocol implementation
- (NSRect)accessibilityFrame
{
JNIEnv* env = [ThreadUtilities getJNIEnv];
GET_ACCESSIBLECOMPONENT_STATIC_METHOD_RETURN(NSZeroRect);
jobject axComponent = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility, sjm_getAccessibleComponent, fAccessible, fComponent);
CHECK_EXCEPTION();
NSSize size = getAxComponentSize(env, axComponent, fComponent);
NSPoint point = getAxComponentLocationOnScreen(env, axComponent, fComponent);
(*env)->DeleteLocalRef(env, axComponent);
point.y += size.height;

point.y = [[[[self view] window] screen] frame].size.height - point.y;

NSRect retval = NSMakeRect(point.x, point.y, size.width, size.height);
return retval;
}

- (nullable id)accessibilityParent
{
return [self accessibilityParentAttribute];
}

@end

/*
* Returns Object.equals for the two items
* This may use LWCToolkit.invokeAndWait(); don't call while holding fLock
Expand Down
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are no header guard here. Is it left intentionally?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, since the CommonComponentAccessibility being imported from the base class sometimes it causes compilation glitches - guess ObjC is not a big fan of forward-declaration. Adding header guard helps. And since i'm not planning to include sub-component header files in the base classes the ifdef guard is not required.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The headers in the obj-c usually do not have guards because they are included via "#import"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know. But in this case that was not enough - that still caused weird compilation glitches like full compilation works but incremental calculation gives compilation error about usage of non-initialized variables. Guards helped.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missed where the guards have helped, there are no guards in this file.
Same question about why did you add guards to the "CommonComponentAccessibility.h"?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added guards into CommonComponentAccessibility.h because without them importing them into JavaComponentAccessibility from which CommonComponentAccessibility is inherited creates intermittent build failures. I used ifdef guards and the problem was gone so i kept them. I do not include any of the implementing classes headers down the inheritance three so i decided not to add guards there.

#import "JavaComponentAccessibility.h"
#import "CommonComponentAccessibility.h"

#import <AppKit/AppKit.h>

@interface ButtonAccessibility : CommonComponentAccessibility <NSAccessibilityButton> {

};
- (nullable NSString *)accessibilityLabel;
- (BOOL)accessibilityPerformPress;
@end
@@ -0,0 +1,56 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

#import "ButtonAccessibility.h"
#import "JNIUtilities.h"
#import "ThreadUtilities.h"

static jclass sjc_CAccessibility = NULL;

/*
* Implementation of the accessibility peer for the pushbutton role
*/
@implementation ButtonAccessibility
- (nullable NSString *)accessibilityLabel
{
return [self accessibilityTitleAttribute];
}

- (BOOL)accessibilityPerformPress
{
AWT_ASSERT_APPKIT_THREAD;
JNIEnv* env = [ThreadUtilities getJNIEnv];

GET_CACCESSIBILITY_CLASS_RETURN(FALSE);
DECLARE_STATIC_METHOD_RETURN(jm_doAccessibleAction, sjc_CAccessibility, "doAccessibleAction",
"(Ljavax/accessibility/AccessibleAction;ILjava/awt/Component;)V", FALSE);
(*env)->CallStaticVoidMethod(env, sjc_CAccessibility, jm_doAccessibleAction,
[self axContextWithEnv:(env)], 0, fComponent);
CHECK_EXCEPTION();

return TRUE;
}

@end
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

#ifndef JAVA_COMPONENT_ACCESSIBILITY
#define JAVA_COMPONENT_ACCESSIBILITY

#import "JavaComponentAccessibility.h"
#import "JavaAccessibilityUtilities.h"

@interface CommonComponentAccessibility : JavaComponentAccessibility <NSAccessibilityElement> {

}
+ (void) initializeRolesMap;
+ (JavaComponentAccessibility * _Nullable) getComponentAccessibility:(NSString * _Nonnull)role;
- (NSRect)accessibilityFrame;
- (nullable id)accessibilityParent;
@end

#endif
@@ -0,0 +1,98 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

#import "CommonComponentAccessibility.h"
#import "JNIUtilities.h"
#import "ThreadUtilities.h"

static jclass sjc_CAccessibility = NULL;
static jmethodID sjm_getAccessibleComponent = NULL;

#define GET_ACCESSIBLECOMPONENT_STATIC_METHOD_RETURN(ret) \
GET_CACCESSIBILITY_CLASS_RETURN(ret); \
GET_STATIC_METHOD_RETURN(sjm_getAccessibleComponent, sjc_CAccessibility, "getAccessibleComponent", \
"(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/AccessibleComponent;", ret);

static NSMutableDictionary * _Nullable rolesMap;

/*
* Common ancestor for all the accessibility peers that implements the new method-based accessibility API
*/
@implementation CommonComponentAccessibility

+ (void) initializeRolesMap {
/*
* Here we should keep all the mapping between the accessibility roles and implementing classes
*/
rolesMap = [[NSMutableDictionary alloc] initWithCapacity:1];

[rolesMap setObject:@"ButtonAccessibility" forKey:@"pushbutton"];
}

/*
* If new implementation of the accessible component peer for the given role exists
* return the allocated class otherwise return nil to let old implementation being initialized
*/
+ (JavaComponentAccessibility *) getComponentAccessibility:(NSString *)role
{
AWT_ASSERT_APPKIT_THREAD;

if (rolesMap == nil) {
[self initializeRolesMap];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible that this will be called on the different threads? Or it is always appkit(probably AWT_ASSERT_APPKIT_THREAD could be useful)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, this method is being called from AppKit thread only but giving that it is static and public adding an assertion would be indeed wise. Fixed.

}

NSString *className = [rolesMap objectForKey:role];
if (className != nil) {
return [NSClassFromString(className) alloc];
}
return nil;
}

// NSAccessibilityElement protocol implementation
- (NSRect)accessibilityFrame
{
JNIEnv* env = [ThreadUtilities getJNIEnv];
GET_ACCESSIBLECOMPONENT_STATIC_METHOD_RETURN(NSZeroRect);
jobject axComponent = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility,
sjm_getAccessibleComponent,
fAccessible, fComponent);
CHECK_EXCEPTION();

NSSize size = getAxComponentSize(env, axComponent, fComponent);
NSPoint point = getAxComponentLocationOnScreen(env, axComponent, fComponent);
(*env)->DeleteLocalRef(env, axComponent);
point.y += size.height;

point.y = [[[[self view] window] screen] frame].size.height - point.y;

return NSMakeRect(point.x, point.y, size.width, size.height);
}

- (nullable id)accessibilityParent
{
return [self accessibilityParentAttribute];
}

@end