Bug 455443 - cache the parent for the accessibilityAttributeValue(NSAccessibilityParentAttribute). r=surkov
authorHub Figuiere <hfiguiere@mozilla.com>
Thu, 08 Dec 2011 16:19:31 -0500
changeset 83961 fc3e43e28979263cde5a6d54b6c34429fa760933
parent 83960 c7d9b329a45da7d34efca2d35d4209e214f7da0d
child 83962 68f0d4831c487d8aa1898f691a4a0fa91874906e
push id519
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 00:38:35 +0000
treeherdermozilla-beta@788ea1ef610b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssurkov
bugs455443
milestone11.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 455443 - cache the parent for the accessibilityAttributeValue(NSAccessibilityParentAttribute). r=surkov
accessible/src/mac/mozAccessible.h
accessible/src/mac/mozAccessible.mm
--- a/accessible/src/mac/mozAccessible.h
+++ b/accessible/src/mac/mozAccessible.h
@@ -41,26 +41,42 @@
 #import <Cocoa/Cocoa.h>
 
 #import "mozAccessibleProtocol.h"
 
 @class mozRootAccessible;
 
 @interface mozAccessible : NSObject <mozAccessible>
 {
-  nsAccessibleWrap *mGeckoAccessible;  // weak reference; it owns us.
-  NSMutableArray   *mChildren;         // strong ref to array of children
+  /**
+   * Weak reference; it owns us.
+   */
+  nsAccessibleWrap* mGeckoAccessible;
+  
+  /**
+   * Strong ref to array of children
+   */
+  NSMutableArray* mChildren;
   
-  // we can be marked as 'expired' if Shutdown() is called on our geckoAccessible.
-  // since we might still be retained by some third-party, we need to do cleanup
-  // in |expire|, and prevent any potential harm that could come from someone using us
-  // after this point.
+  /** 
+   * Weak reference to the parent
+   */
+  mozAccessible* mParent;
+  
+  /**
+   * We can be marked as 'expired' if Shutdown() is called on our geckoAccessible.
+   * since we might still be retained by some third-party, we need to do cleanup
+   * in |expire|, and prevent any potential harm that could come from someone using us
+   * after this point.
+   */
   BOOL mIsExpired;
   
-  // the nsIAccessible role of our gecko accessible.
+  /**
+   * The nsIAccessible role of our gecko accessible.
+   */
   PRUint32        mRole;
 }
 
 // inits with the gecko owner.
 - (id)initWithAccessible:(nsAccessibleWrap*)geckoParent;
 
 // our accessible parent (AXParent)
 - (id <mozAccessible>)parent;
@@ -109,27 +125,30 @@
 - (void)didReceiveFocus;
 - (void)valueDidChange;
 
 #pragma mark -
 
 // invalidates and removes all our children from our cached array.
 - (void)invalidateChildren;
 
+// invalidates the cached parent, used by invalidateChildren.
+- (void)invalidateParent;
+
 // makes ourselves "expired". after this point, we might be around if someone
 // has retained us (e.g., a third-party), but we really contain no information.
 - (void)expire;
 - (BOOL)isExpired;
 
 #ifdef DEBUG
 - (void)printHierarchy;
 - (void)printHierarchyWithLevel:(unsigned)numSpaces;
 
 - (void)sanityCheckChildren;
-- (void)sanityCheckChildren:(NSArray *)theChildren;
+- (void)sanityCheckChildren:(NSArray*)theChildren;
 #endif
 
 // ---- NSAccessibility methods ---- //
 
 // whether to skip this element when traversing the accessibility
 // hierarchy.
 - (BOOL)accessibilityIsIgnored;
 
--- a/accessible/src/mac/mozAccessible.mm
+++ b/accessible/src/mac/mozAccessible.mm
@@ -350,33 +350,38 @@ GetNativeFromGeckoAccessible(nsIAccessib
 }
 
 #pragma mark -
 
 - (id <mozAccessible>)parent
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
 
+  if (mParent)
+    return mParent;
+
   nsCOMPtr<nsIAccessible> accessibleParent(mGeckoAccessible->GetUnignoredParent());
   if (accessibleParent) {
     id nativeParent = GetNativeFromGeckoAccessible(accessibleParent);
-    if (nativeParent)
-      return GetClosestInterestingAccessible(nativeParent);
+    if (nativeParent) {
+      return mParent = GetClosestInterestingAccessible(nativeParent);
+    }
   }
   
   // GetUnignoredParent() returns null when there is no unignored accessible all the way up to
   // the root accessible. so we'll have to return whatever native accessible is above our root accessible 
   // (which might be the owning NSWindow in the application, for example).
   //
   // get the native root accessible, and tell it to return its first parent unignored accessible.
   nsRootAccessible* root = mGeckoAccessible->RootAccessible();
   id nativeParent = GetNativeFromGeckoAccessible(static_cast<nsIAccessible*>(root));
   NSAssert1 (nativeParent, @"!!! we can't find a parent for %@", self);
   
-  return GetClosestInterestingAccessible(nativeParent);
+  mParent = GetClosestInterestingAccessible(nativeParent);
+  return mParent;
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
 }
 
 - (BOOL)hasRepresentedView
 {
   return NO;
 }
@@ -605,23 +610,30 @@ GetNativeFromGeckoAccessible(nsIAccessib
 
   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
 }
 
 - (void)invalidateChildren
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
+  [mChildren makeObjectsPerformSelector:@selector(invalidateParent)];
+
   // make room for new children
   [mChildren release];
   mChildren = nil;
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
+- (void)invalidateParent
+{
+  mParent = nil;
+}
+
 - (void)expire
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   [self invalidateChildren];
   mIsExpired = YES;
 
   NS_OBJC_END_TRY_ABORT_BLOCK;