accessible/src/mac/mozAccessible.mm

Wed, 31 Dec 2014 07:16:47 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:16:47 +0100
branch
TOR_BUG_9701
changeset 3
141e0f1194b1
permissions
-rw-r--r--

Revert simplistic fix pending revisit of Mozilla integration attempt.

     1 /* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #import "mozAccessible.h"
     8 #import "MacUtils.h"
     9 #import "mozView.h"
    11 #include "Accessible-inl.h"
    12 #include "nsAccUtils.h"
    13 #include "nsIAccessibleRelation.h"
    14 #include "nsIAccessibleText.h"
    15 #include "nsIAccessibleEditableText.h"
    16 #include "nsIPersistentProperties2.h"
    17 #include "Relation.h"
    18 #include "Role.h"
    19 #include "RootAccessible.h"
    21 #include "mozilla/Services.h"
    22 #include "nsRect.h"
    23 #include "nsCocoaUtils.h"
    24 #include "nsCoord.h"
    25 #include "nsObjCExceptions.h"
    26 #include "nsWhitespaceTokenizer.h"
    28 using namespace mozilla;
    29 using namespace mozilla::a11y;
    31 // returns the passed in object if it is not ignored. if it's ignored, will return
    32 // the first unignored ancestor.
    33 static inline id
    34 GetClosestInterestingAccessible(id anObject)
    35 {
    36   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
    38   // this object is not ignored, so let's return it.
    39   if (![anObject accessibilityIsIgnored])
    40     return GetObjectOrRepresentedView(anObject);
    42   // find the closest ancestor that is not ignored.
    43   id unignoredObject = anObject;
    44   while ((unignoredObject = [unignoredObject accessibilityAttributeValue:NSAccessibilityParentAttribute])) {
    45     if (![unignoredObject accessibilityIsIgnored])
    46       // object is not ignored, so let's stop the search.
    47       break;
    48   }
    50   // if it's a mozAccessible, we need to take care to maybe return the view we
    51   // represent, to the AT.
    52   if ([unignoredObject respondsToSelector:@selector(hasRepresentedView)])
    53     return GetObjectOrRepresentedView(unignoredObject);
    55   return unignoredObject;
    57   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
    58 }
    60 #pragma mark -
    62 @implementation mozAccessible
    64 - (id)initWithAccessible:(AccessibleWrap*)geckoAccessible
    65 {
    66   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
    68   if ((self = [super init])) {
    69     mGeckoAccessible = geckoAccessible;
    70     mRole = geckoAccessible->Role();
    71   }
    73   return self;
    75   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
    76 }
    78 - (void)dealloc
    79 {
    80   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
    82   [mChildren release];
    83   [super dealloc];
    85   NS_OBJC_END_TRY_ABORT_BLOCK;
    86 }
    88 #pragma mark -
    90 - (BOOL)accessibilityIsIgnored
    91 {
    92   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
    94   // unknown (either unimplemented, or irrelevant) elements are marked as ignored
    95   // as well as expired elements.
    96   return !mGeckoAccessible || ([[self role] isEqualToString:NSAccessibilityUnknownRole] &&
    97                                !(mGeckoAccessible->InteractiveState() & states::FOCUSABLE));
    99   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO);
   100 }
   102 - (NSArray*)accessibilityAttributeNames
   103 {
   104   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
   106   // if we're expired, we don't support any attributes.
   107   if (!mGeckoAccessible)
   108     return [NSArray array];
   110   static NSArray *generalAttributes = nil;
   112   if (!generalAttributes) {
   113     // standard attributes that are shared and supported by all generic elements.
   114     generalAttributes = [[NSArray alloc] initWithObjects:  NSAccessibilityChildrenAttribute, 
   115                                                            NSAccessibilityParentAttribute,
   116                                                            NSAccessibilityRoleAttribute,
   117                                                            NSAccessibilityTitleAttribute,
   118                                                            NSAccessibilityValueAttribute,
   119                                                            NSAccessibilitySubroleAttribute,
   120                                                            NSAccessibilityRoleDescriptionAttribute,
   121                                                            NSAccessibilityPositionAttribute,
   122                                                            NSAccessibilityEnabledAttribute,
   123                                                            NSAccessibilitySizeAttribute,
   124                                                            NSAccessibilityWindowAttribute,
   125                                                            NSAccessibilityFocusedAttribute,
   126                                                            NSAccessibilityHelpAttribute,
   127                                                            NSAccessibilityTitleUIElementAttribute,
   128                                                            NSAccessibilityTopLevelUIElementAttribute,
   129                                                            NSAccessibilityDescriptionAttribute,
   130 #if DEBUG
   131                                                            @"AXMozDescription",
   132 #endif
   133                                                            nil];
   134   }
   136   return generalAttributes;
   138   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
   139 }
   141 - (id)accessibilityAttributeValue:(NSString*)attribute
   142 {  
   143   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
   145   if (!mGeckoAccessible)
   146     return nil;
   148 #if DEBUG
   149   if ([attribute isEqualToString:@"AXMozDescription"])
   150     return [NSString stringWithFormat:@"role = %u native = %@", mRole, [self class]];
   151 #endif
   153   if ([attribute isEqualToString:NSAccessibilityChildrenAttribute])
   154     return [self children];
   155   if ([attribute isEqualToString:NSAccessibilityParentAttribute]) 
   156     return [self parent];
   158 #ifdef DEBUG_hakan
   159   NSLog (@"(%@ responding to attr %@)", self, attribute);
   160 #endif
   162   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
   163     return [self role];
   164   if ([attribute isEqualToString:NSAccessibilityPositionAttribute]) 
   165     return [self position];
   166   if ([attribute isEqualToString:NSAccessibilitySubroleAttribute])
   167     return [self subrole];
   168   if ([attribute isEqualToString:NSAccessibilityEnabledAttribute])
   169     return [NSNumber numberWithBool:[self isEnabled]];
   170   if ([attribute isEqualToString:NSAccessibilityValueAttribute])
   171     return [self value];
   172   if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) 
   173     return [self roleDescription];  
   174   if ([attribute isEqualToString:NSAccessibilityDescriptionAttribute])
   175     return [self customDescription];
   176   if ([attribute isEqualToString:NSAccessibilityFocusedAttribute])
   177     return [NSNumber numberWithBool:[self isFocused]];
   178   if ([attribute isEqualToString:NSAccessibilitySizeAttribute])
   179     return [self size];
   180   if ([attribute isEqualToString:NSAccessibilityWindowAttribute])
   181     return [self window];
   182   if ([attribute isEqualToString:NSAccessibilityTopLevelUIElementAttribute])
   183     return [self window];
   184   if ([attribute isEqualToString:NSAccessibilityTitleAttribute])
   185     return [self title];
   186   if ([attribute isEqualToString:NSAccessibilityTitleUIElementAttribute]) {
   187     Relation rel = mGeckoAccessible->RelationByType(RelationType::LABELLED_BY);
   188     Accessible* tempAcc = rel.Next();
   189     return tempAcc ? GetNativeFromGeckoAccessible(tempAcc) : nil;
   190   }
   191   if ([attribute isEqualToString:NSAccessibilityHelpAttribute])
   192     return [self help];
   194 #ifdef DEBUG
   195  NSLog (@"!!! %@ can't respond to attribute %@", self, attribute);
   196 #endif
   197   return nil;
   199   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
   200 }
   202 - (BOOL)accessibilityIsAttributeSettable:(NSString*)attribute
   203 {
   204   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
   206   if ([attribute isEqualToString:NSAccessibilityFocusedAttribute])
   207     return [self canBeFocused];
   209   return NO;
   211   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO);
   212 }
   214 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute
   215 {
   216   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
   218 #ifdef DEBUG_hakan
   219   NSLog (@"[%@] %@='%@'", self, attribute, value);
   220 #endif
   222   // we only support focusing elements so far.
   223   if ([attribute isEqualToString:NSAccessibilityFocusedAttribute] && [value boolValue])
   224     [self focus];
   226   NS_OBJC_END_TRY_ABORT_BLOCK;
   227 }
   229 - (id)accessibilityHitTest:(NSPoint)point
   230 {
   231   if (!mGeckoAccessible)
   232     return nil;
   234   // Convert the given screen-global point in the cocoa coordinate system (with
   235   // origin in the bottom-left corner of the screen) into point in the Gecko
   236   // coordinate system (with origin in a top-left screen point).
   237   NSScreen* mainView = [[NSScreen screens] objectAtIndex:0];
   238   NSPoint tmpPoint = NSMakePoint(point.x,
   239                                  [mainView frame].size.height - point.y);
   240   nsIntPoint geckoPoint = nsCocoaUtils::
   241     CocoaPointsToDevPixels(tmpPoint, nsCocoaUtils::GetBackingScaleFactor(mainView));
   243   Accessible* child = mGeckoAccessible->ChildAtPoint(geckoPoint.x, geckoPoint.y,
   244                                                      Accessible::eDeepestChild);
   246   if (child) {
   247     mozAccessible* nativeChild = GetNativeFromGeckoAccessible(child);
   248     if (nativeChild)
   249       return GetClosestInterestingAccessible(nativeChild);
   250   }
   252   // if we didn't find anything, return ourself (or the first unignored ancestor).
   253   return GetClosestInterestingAccessible(self); 
   254 }
   256 - (NSArray*)accessibilityActionNames 
   257 {
   258   return nil;
   259 }
   261 - (NSString*)accessibilityActionDescription:(NSString*)action 
   262 {
   263   // by default we return whatever the MacOS API know about.
   264   // if you have custom actions, override.
   265   return NSAccessibilityActionDescription(action);
   266 }
   268 - (void)accessibilityPerformAction:(NSString*)action 
   269 {
   270 }
   272 - (id)accessibilityFocusedUIElement
   273 {
   274   if (!mGeckoAccessible)
   275     return nil;
   277   Accessible* focusedGeckoChild = mGeckoAccessible->FocusedChild();
   278   if (focusedGeckoChild) {
   279     mozAccessible *focusedChild = GetNativeFromGeckoAccessible(focusedGeckoChild);
   280     if (focusedChild)
   281       return GetClosestInterestingAccessible(focusedChild);
   282   }
   284   // return ourself if we can't get a native focused child.
   285   return GetClosestInterestingAccessible(self);
   286 }
   288 #pragma mark -
   290 - (id <mozAccessible>)parent
   291 {
   292   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
   294   Accessible* accessibleParent = mGeckoAccessible->GetUnignoredParent();
   295   if (accessibleParent) {
   296     id nativeParent = GetNativeFromGeckoAccessible(accessibleParent);
   297     if (nativeParent)
   298       return GetClosestInterestingAccessible(nativeParent);
   299   }
   301   // GetUnignoredParent() returns null when there is no unignored accessible all the way up to
   302   // the root accessible. so we'll have to return whatever native accessible is above our root accessible 
   303   // (which might be the owning NSWindow in the application, for example).
   304   //
   305   // get the native root accessible, and tell it to return its first parent unignored accessible.
   306   RootAccessible* root = mGeckoAccessible->RootAccessible();
   307   id nativeParent = GetNativeFromGeckoAccessible(static_cast<nsIAccessible*>(root));
   308   NSAssert1 (nativeParent, @"!!! we can't find a parent for %@", self);
   310   return GetClosestInterestingAccessible(nativeParent);
   312   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
   313 }
   315 - (BOOL)hasRepresentedView
   316 {
   317   return NO;
   318 }
   320 - (id)representedView
   321 {
   322   return nil;
   323 }
   325 - (BOOL)isRoot
   326 {
   327   return NO;
   328 }
   330 // gets our native children lazily.
   331 // returns nil when there are no children.
   332 - (NSArray*)children
   333 {
   334   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
   336   if (mChildren || !mGeckoAccessible->AreChildrenCached())
   337     return mChildren;
   339   mChildren = [[NSMutableArray alloc] init];
   341   // get the array of children.
   342   nsAutoTArray<Accessible*, 10> childrenArray;
   343   mGeckoAccessible->GetUnignoredChildren(&childrenArray);
   345   // now iterate through the children array, and get each native accessible.
   346   uint32_t totalCount = childrenArray.Length();
   347   for (uint32_t idx = 0; idx < totalCount; idx++) {
   348     Accessible* curAccessible = childrenArray.ElementAt(idx);
   349     if (curAccessible) {
   350       mozAccessible *curNative = GetNativeFromGeckoAccessible(curAccessible);
   351       if (curNative)
   352         [mChildren addObject:GetObjectOrRepresentedView(curNative)];
   353     }
   354   }
   356 #ifdef DEBUG_hakan
   357   // make sure we're not returning any ignored accessibles.
   358   NSEnumerator *e = [mChildren objectEnumerator];
   359   mozAccessible *m = nil;
   360   while ((m = [e nextObject])) {
   361     NSAssert1(![m accessibilityIsIgnored], @"we should never return an ignored accessible! (%@)", m);
   362   }
   363 #endif
   365   return mChildren;
   367   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
   368 }
   370 - (NSValue*)position
   371 {
   372   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
   374   if (!mGeckoAccessible)
   375     return nil;
   377   int32_t x = 0, y = 0, width = 0, height = 0;
   378   mGeckoAccessible->GetBounds(&x, &y, &width, &height);
   380   NSScreen* mainView = [[NSScreen screens] objectAtIndex:0];
   381   CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mainView);
   382   NSPoint p = NSMakePoint(static_cast<CGFloat>(x) / scaleFactor,
   383                          [mainView frame].size.height - static_cast<CGFloat>(y + height) / scaleFactor);
   385   return [NSValue valueWithPoint:p];
   387   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
   388 }
   390 - (NSValue*)size
   391 {
   392   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
   394   if (!mGeckoAccessible)
   395     return nil;
   397   int32_t x = 0, y = 0, width = 0, height = 0;
   398   mGeckoAccessible->GetBounds (&x, &y, &width, &height);
   399   CGFloat scaleFactor =
   400     nsCocoaUtils::GetBackingScaleFactor([[NSScreen screens] objectAtIndex:0]);
   401   return [NSValue valueWithSize:NSMakeSize(static_cast<CGFloat>(width) / scaleFactor,
   402                                            static_cast<CGFloat>(height) / scaleFactor)];
   404   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
   405 }
   407 - (NSString*)role
   408 {
   409   if (!mGeckoAccessible)
   410     return nil;
   412 #ifdef DEBUG_A11Y
   413   NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(mGeckoAccessible),
   414                "Does not support nsIAccessibleText when it should");
   415 #endif
   417 #define ROLE(geckoRole, stringRole, atkRole, macRole, msaaRole, ia2Role, nameRule) \
   418   case roles::geckoRole: \
   419     return macRole;
   421   switch (mRole) {
   422 #include "RoleMap.h"
   423     default:
   424       NS_NOTREACHED("Unknown role.");
   425       return NSAccessibilityUnknownRole;
   426   }
   428 #undef ROLE
   429 }
   431 - (NSString*)subrole
   432 {
   433   if (!mGeckoAccessible)
   434     return nil;
   436   // XXX maybe we should cache the subrole.
   437   nsAutoString xmlRoles;
   439   // XXX we don't need all the attributes (see bug 771113)
   440   nsCOMPtr<nsIPersistentProperties> attributes = mGeckoAccessible->Attributes();
   441   if (attributes)
   442     nsAccUtils::GetAccAttr(attributes, nsGkAtoms::xmlroles, xmlRoles);
   444   nsWhitespaceTokenizer tokenizer(xmlRoles);
   446   while (tokenizer.hasMoreTokens()) {
   447     const nsDependentSubstring token(tokenizer.nextToken());
   449     if (token.EqualsLiteral("banner"))
   450       return @"AXLandmarkBanner";
   452     if (token.EqualsLiteral("complementary"))
   453       return @"AXLandmarkComplementary";
   455     if (token.EqualsLiteral("contentinfo"))
   456       return @"AXLandmarkContentInfo";
   458     if (token.EqualsLiteral("main"))
   459       return @"AXLandmarkMain";
   461     if (token.EqualsLiteral("navigation"))
   462       return @"AXLandmarkNavigation";
   464     if (token.EqualsLiteral("search"))
   465       return @"AXLandmarkSearch";
   466   }
   468   switch (mRole) {
   469     case roles::LIST:
   470       return @"AXContentList"; // 10.6+ NSAccessibilityContentListSubrole;
   472     case roles::DEFINITION_LIST:
   473       return @"AXDefinitionList"; // 10.6+ NSAccessibilityDefinitionListSubrole;
   475     case roles::TERM:
   476       return @"AXTerm";
   478     case roles::DEFINITION:
   479       return @"AXDefinition";
   481     default:
   482       break;
   483   }
   485   return nil;
   486 }
   488 - (NSString*)roleDescription
   489 {
   490   if (mRole == roles::DOCUMENT)
   491     return utils::LocalizedString(NS_LITERAL_STRING("htmlContent"));
   493   NSString* subrole = [self subrole];
   495   if ((mRole == roles::LISTITEM) && [subrole isEqualToString:@"AXTerm"])
   496     return utils::LocalizedString(NS_LITERAL_STRING("term"));
   497   if ((mRole == roles::PARAGRAPH) && [subrole isEqualToString:@"AXDefinition"])
   498     return utils::LocalizedString(NS_LITERAL_STRING("definition"));
   500   NSString* role = [self role];
   502   // the WAI-ARIA Landmarks
   503   if ([role isEqualToString:NSAccessibilityGroupRole]) {
   504     if ([subrole isEqualToString:@"AXLandmarkBanner"])
   505       return utils::LocalizedString(NS_LITERAL_STRING("banner"));
   506     if ([subrole isEqualToString:@"AXLandmarkComplementary"])
   507       return utils::LocalizedString(NS_LITERAL_STRING("complementary"));
   508     if ([subrole isEqualToString:@"AXLandmarkContentInfo"])
   509       return utils::LocalizedString(NS_LITERAL_STRING("content"));
   510     if ([subrole isEqualToString:@"AXLandmarkMain"])
   511       return utils::LocalizedString(NS_LITERAL_STRING("main"));
   512     if ([subrole isEqualToString:@"AXLandmarkNavigation"])
   513       return utils::LocalizedString(NS_LITERAL_STRING("navigation"));
   514     if ([subrole isEqualToString:@"AXLandmarkSearch"])
   515       return utils::LocalizedString(NS_LITERAL_STRING("search"));
   516   }
   518   return NSAccessibilityRoleDescription(role, subrole);
   519 }
   521 - (NSString*)title
   522 {
   523   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
   525   nsAutoString title;
   526   mGeckoAccessible->Name(title);
   527   return nsCocoaUtils::ToNSString(title);
   529   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
   530 }
   532 - (id)value
   533 {
   534   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
   536   nsAutoString value;
   537   mGeckoAccessible->GetValue (value);
   538   return value.IsEmpty() ? nil : [NSString stringWithCharacters:reinterpret_cast<const unichar*>(value.BeginReading())
   539                                                          length:value.Length()];
   541   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
   542 }
   544 - (void)valueDidChange
   545 {
   546   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
   548 #ifdef DEBUG_hakan
   549   NSLog(@"%@'s value changed!", self);
   550 #endif
   551   // sending out a notification is expensive, so we don't do it other than for really important objects,
   552   // like mozTextAccessible.
   554   NS_OBJC_END_TRY_ABORT_BLOCK;
   555 }
   557 - (void)selectedTextDidChange
   558 {
   559   // Do nothing. mozTextAccessible will.
   560 }
   562 - (NSString*)customDescription
   563 {
   564   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
   566   if (mGeckoAccessible->IsDefunct())
   567     return nil;
   569   nsAutoString desc;
   570   mGeckoAccessible->Description(desc);
   572   return nsCocoaUtils::ToNSString(desc);
   574   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
   575 }
   577 - (NSString*)help
   578 {
   579   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
   581   nsAutoString helpText;
   582   mGeckoAccessible->GetHelp (helpText);
   583   return helpText.IsEmpty() ? nil : [NSString stringWithCharacters:reinterpret_cast<const unichar*>(helpText.BeginReading())
   584                                                             length:helpText.Length()];
   586   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
   587 }
   589 // objc-style description (from NSObject); not to be confused with the accessible description above.
   590 - (NSString*)description
   591 {
   592   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
   594   return [NSString stringWithFormat:@"(%p) %@", self, [self role]];
   596   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
   597 }
   599 - (BOOL)isFocused
   600 {
   601   return FocusMgr()->IsFocused(mGeckoAccessible);
   602 }
   604 - (BOOL)canBeFocused
   605 {
   606   return mGeckoAccessible && (mGeckoAccessible->InteractiveState() & states::FOCUSABLE);
   607 }
   609 - (BOOL)focus
   610 {
   611   if (!mGeckoAccessible)
   612     return NO;
   614   nsresult rv = mGeckoAccessible->TakeFocus();
   615   return NS_SUCCEEDED(rv);
   616 }
   618 - (BOOL)isEnabled
   619 {
   620   return mGeckoAccessible && ((mGeckoAccessible->InteractiveState() & states::UNAVAILABLE) == 0);
   621 }
   623 // The root accessible calls this when the focused node was
   624 // changed to us.
   625 - (void)didReceiveFocus
   626 {
   627   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
   629 #ifdef DEBUG_hakan
   630   NSLog (@"%@ received focus!", self);
   631 #endif
   632   NSAssert1(![self accessibilityIsIgnored], @"trying to set focus to ignored element! (%@)", self);
   633   NSAccessibilityPostNotification(GetObjectOrRepresentedView(self),
   634                                   NSAccessibilityFocusedUIElementChangedNotification);
   636   NS_OBJC_END_TRY_ABORT_BLOCK;
   637 }
   639 - (NSWindow*)window
   640 {
   641   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
   643   AccessibleWrap* accWrap = static_cast<AccessibleWrap*>(mGeckoAccessible);
   645   // Get a pointer to the native window (NSWindow) we reside in.
   646   NSWindow *nativeWindow = nil;
   647   DocAccessible* docAcc = accWrap->Document();
   648   if (docAcc)
   649     nativeWindow = static_cast<NSWindow*>(docAcc->GetNativeWindow());
   651   NSAssert1(nativeWindow, @"Could not get native window for %@", self);
   652   return nativeWindow;
   654   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
   655 }
   657 - (void)invalidateChildren
   658 {
   659   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
   661   // make room for new children
   662   [mChildren release];
   663   mChildren = nil;
   665   NS_OBJC_END_TRY_ABORT_BLOCK;
   666 }
   668 - (void)appendChild:(Accessible*)aAccessible
   669 {
   670   // if mChildren is nil, then we don't even need to bother
   671   if (!mChildren)
   672     return;
   674   mozAccessible *curNative = GetNativeFromGeckoAccessible(aAccessible);
   675   if (curNative)
   676     [mChildren addObject:GetObjectOrRepresentedView(curNative)];
   677 }
   679 - (void)expire
   680 {
   681   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
   683   [self invalidateChildren];
   685   mGeckoAccessible = nullptr;
   687   NS_OBJC_END_TRY_ABORT_BLOCK;
   688 }
   690 - (BOOL)isExpired
   691 {
   692   return !mGeckoAccessible;
   693 }
   695 #pragma mark -
   696 #pragma mark Debug methods
   697 #pragma mark -
   699 #ifdef DEBUG
   701 // will check that our children actually reference us as their
   702 // parent.
   703 - (void)sanityCheckChildren:(NSArray *)children
   704 {
   705   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
   707   NSAssert(![self accessibilityIsIgnored], @"can't sanity check children of an ignored accessible!");
   708   NSEnumerator *iter = [children objectEnumerator];
   709   mozAccessible *curObj = nil;
   711   NSLog(@"sanity checking %@", self);
   713   while ((curObj = [iter nextObject])) {
   714     id realSelf = GetObjectOrRepresentedView(self);
   715     NSLog(@"checking %@", realSelf);
   716     NSAssert2([curObj parent] == realSelf, 
   717               @"!!! %@ not returning %@ as AXParent, even though it is a AXChild of it!", curObj, realSelf);
   718   }
   720   NS_OBJC_END_TRY_ABORT_BLOCK;
   721 }
   723 - (void)sanityCheckChildren
   724 {
   725   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
   727   [self sanityCheckChildren:[self children]];
   729   NS_OBJC_END_TRY_ABORT_BLOCK;
   730 }
   732 - (void)printHierarchy
   733 {
   734   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
   736   [self printHierarchyWithLevel:0];
   738   NS_OBJC_END_TRY_ABORT_BLOCK;
   739 }
   741 - (void)printHierarchyWithLevel:(unsigned)level
   742 {
   743   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
   745   NSAssert(![self isExpired], @"!!! trying to print hierarchy of expired object!");
   747   // print this node
   748   NSMutableString *indent = [NSMutableString stringWithCapacity:level];
   749   unsigned i=0;
   750   for (;i<level;i++)
   751     [indent appendString:@" "];
   753   NSLog (@"%@(#%i) %@", indent, level, self);
   755   // use |children| method to make sure our children are lazily fetched first.
   756   NSArray *children = [self children];
   757   if (!children)
   758     return;
   760   if (![self accessibilityIsIgnored])
   761     [self sanityCheckChildren];
   763   NSEnumerator *iter = [children objectEnumerator];
   764   mozAccessible *object = nil;
   766   while (iter && (object = [iter nextObject]))
   767     // print every child node's subtree, increasing the indenting
   768     // by two for every level.
   769     [object printHierarchyWithLevel:(level+1)];
   771   NS_OBJC_END_TRY_ABORT_BLOCK;
   772 }
   774 #endif /* DEBUG */
   776 @end

mercurial