diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java index 19ac4818928cc9904a40556f800674d4caba55fa..0ab38fc06b4ecd050817df298aa7792b5630984b 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, 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 @@ -35,10 +35,11 @@ import java.awt.event.KeyEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.lang.annotation.Native; -import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.concurrent.Callable; import java.util.Arrays; @@ -64,7 +65,6 @@ import javax.swing.JTextArea; import javax.swing.JList; import javax.swing.JTree; import javax.swing.KeyStroke; -import javax.swing.tree.TreePath; import sun.awt.AWTAccessor; import sun.lwawt.LWWindowPeer; @@ -742,21 +742,6 @@ class CAccessibility implements PropertyChangeListener { return new Object[]{childrenAndRoles.get(whichChildren * 2), childrenAndRoles.get((whichChildren * 2) + 1)}; } - private static Accessible createAccessibleTreeNode(JTree t, TreePath p) { - Accessible a = null; - - try { - Class<?> accessibleJTreeNodeClass = Class.forName("javax.swing.JTree$AccessibleJTree$AccessibleJTreeNode"); - Constructor<?> constructor = accessibleJTreeNodeClass.getConstructor(t.getAccessibleContext().getClass(), JTree.class, TreePath.class, Accessible.class); - constructor.setAccessible(true); - a = ((Accessible) constructor.newInstance(t.getAccessibleContext(), t, p, null)); - } catch (Exception e) { - e.printStackTrace(); - } - - return a; - } - // This method is called from the native // Each child takes up three entries in the array: one for itself, one for its role, and one for the recursion level private static Object[] getChildrenAndRolesRecursive(final Accessible a, final Component c, final int whichChildren, final boolean allowIgnored, final int level) { @@ -764,62 +749,21 @@ class CAccessibility implements PropertyChangeListener { return invokeAndWait(new Callable<Object[]>() { public Object[] call() throws Exception { ArrayList<Object> allChildren = new ArrayList<Object>(); - - Accessible at = null; - if (a instanceof CAccessible) { - at = CAccessible.getSwingAccessible(a); - } else { - at = a; - } - - if (at instanceof JTree) { - JTree tree = ((JTree) at); - - if (whichChildren == JAVA_AX_ALL_CHILDREN) { - int count = tree.getRowCount(); - for (int i = 0; i < count; i++) { - TreePath path = tree.getPathForRow(i); - Accessible an = createAccessibleTreeNode(tree, path); - if (an != null) { - AccessibleContext ac = an.getAccessibleContext(); - if (ac != null) { - allChildren.add(an); - allChildren.add(ac.getAccessibleRole());; - allChildren.add(String.valueOf((tree.isRootVisible() ? path.getPathCount() : path.getPathCount() - 1))); - } - } - } - } - - if (whichChildren == JAVA_AX_SELECTED_CHILDREN) { - int count = tree.getSelectionCount(); - for (int i = 0; i < count; i++) { - TreePath path = tree.getSelectionPaths()[i]; - Accessible an = createAccessibleTreeNode(tree, path); - if (an != null) { - AccessibleContext ac = an.getAccessibleContext(); - if (ac != null) { - allChildren.add(an); - allChildren.add(ac.getAccessibleRole()); - allChildren.add(String.valueOf((tree.isRootVisible() ? path.getPathCount() : path.getPathCount() - 1))); - } - } - } - } - - return allChildren.toArray(); - } - ArrayList<Object> currentLevelChildren = new ArrayList<Object>(); ArrayList<Accessible> parentStack = new ArrayList<Accessible>(); + HashMap<Accessible, List<Object>> childrenOfParent = new HashMap<>(); parentStack.add(a); ArrayList<Integer> indexses = new ArrayList<Integer>(); Integer index = 0; int currentLevel = level; while (!parentStack.isEmpty()) { Accessible p = parentStack.get(parentStack.size() - 1); - - currentLevelChildren.addAll(Arrays.asList(getChildrenAndRolesImpl(p, c, JAVA_AX_ALL_CHILDREN, allowIgnored, ChildrenOperations.COMMON))); + if (!childrenOfParent.containsKey(p)) { + childrenOfParent.put(p, Arrays.asList(getChildrenAndRolesImpl(p, + c, JAVA_AX_ALL_CHILDREN, allowIgnored, + ChildrenOperations.COMMON))); + } + currentLevelChildren.addAll(childrenOfParent.get(p)); if ((currentLevelChildren.size() == 0) || (index >= currentLevelChildren.size())) { if (!parentStack.isEmpty()) parentStack.remove(parentStack.size() - 1); if (!indexses.isEmpty()) index = indexses.remove(indexses.size() - 1); @@ -862,7 +806,6 @@ class CAccessibility implements PropertyChangeListener { currentLevel += 1; continue; } - } return allChildren.toArray(); diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.h b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.h index 2992d82cbe4f521ebf444979f287897b5a6579f5..8281f0b0213db9f14aa4994aeb80a615f1c5748a 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.h +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2021, JetBrains s.r.o.. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, JetBrains s.r.o.. 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 @@ -29,7 +29,12 @@ // This is a tree representation. See: https://developer.apple.com/documentation/appkit/nsoutlineview @interface OutlineAccessibility : ListAccessibility <NSAccessibilityOutline> - +{ + NSMutableArray<id<NSAccessibilityRow>> *rowCache; + BOOL rowCacheValid; + NSMutableArray<id<NSAccessibilityRow>> *selectedRowCache; + BOOL selectedRowCacheValid; +} @property(readonly) BOOL isTreeRootVisible; @end diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.m index cdf6dbbd4ab7783d393246ded05d6a5911038ebd..08240614bf774312d6d7e7219db39643dc7e50ef 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.m @@ -1,6 +1,6 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2021, JetBrains s.r.o.. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, JetBrains s.r.o.. 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 @@ -55,4 +55,88 @@ static jmethodID sjm_isTreeRootVisible = NULL; return [[super accessibilityLabel] isEqualToString:@"list"] ? @"tree" : [super accessibilityLabel]; } +- (nullable NSArray<id<NSAccessibilityRow>> *)accessibilityRows +{ + return [self accessibilityChildren]; +} + +- (nullable NSArray<id<NSAccessibilityRow>> *)accessibilitySelectedRows +{ + return [self accessibilitySelectedChildren]; +} + +- (nullable NSArray<id<NSAccessibilityRow>> *)accessibilityChildren +{ + if (![self isCacheValid]) { + NSArray *t = [super accessibilityChildren]; + if (t != nil) { + rowCache = [[NSMutableArray arrayWithArray:t] retain]; + } else { + rowCache = nil; + } + rowCacheValid = YES; + } + return rowCache; +} + +- (nullable NSArray<id<NSAccessibilityRow>> *)accessibilitySelectedChildren +{ + if (!selectedRowCacheValid) { + NSArray *t = [super accessibilitySelectedChildren]; + if (t != nil) { + selectedRowCache = [[NSMutableArray arrayWithArray:t] retain]; + } else { + selectedRowCache = nil; + } + selectedRowCacheValid = YES; + } + return selectedRowCache; +} + +- (BOOL)isCacheValid +{ + if (rowCacheValid && [[self parent] respondsToSelector:NSSelectorFromString(@"isCacheValid")]) { + return [[self parent] isCacheValid]; + } + return rowCacheValid; +} + +- (void)invalidateCache +{ + rowCacheValid = NO; +} + +- (void)invalidateSelectionCache +{ + selectedRowCacheValid = NO; +} + +- (void)postSelectionChanged +{ + AWT_ASSERT_APPKIT_THREAD; + [self invalidateSelectionCache]; + [super postSelectionChanged]; +} + +- (void)postTreeNodeCollapsed +{ + AWT_ASSERT_APPKIT_THREAD; + [self invalidateCache]; + [super postTreeNodeCollapsed]; +} + +- (void)postTreeNodeExpanded +{ + AWT_ASSERT_APPKIT_THREAD; + [self invalidateCache]; + [super postTreeNodeExpanded]; +} + +- (void)postSelectedCellsChanged +{ + AWT_ASSERT_APPKIT_THREAD; + [self invalidateSelectionCache]; + [super postSelectedCellsChanged]; +} + @end