tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

MOXSearchInfo.mm (14105B)


      1 /* clang-format off */
      2 /* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      3 /* clang-format on */
      4 /* This Source Code Form is subject to the terms of the Mozilla Public
      5 * License, v. 2.0. If a copy of the MPL was not distributed with this
      6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      7 
      8 #import "MOXSearchInfo.h"
      9 #import "MOXWebAreaAccessible.h"
     10 #import "RotorRules.h"
     11 
     12 #include "nsCocoaUtils.h"
     13 #include "DocAccessibleParent.h"
     14 #include "nsAccessibilityService.h"
     15 
     16 using namespace mozilla::a11y;
     17 
     18 @interface MOXSearchInfo ()
     19 - (NSArray*)getMatchesForRule:(PivotRule&)rule;
     20 
     21 - (Accessible*)rootGeckoAccessible;
     22 
     23 - (Accessible*)startGeckoAccessible;
     24 @end
     25 
     26 @implementation MOXSearchInfo
     27 
     28 - (id)initWithParameters:(NSDictionary*)params
     29                 andRoot:(MOXAccessibleBase*)root {
     30  if (id searchKeyParam = [params objectForKey:@"AXSearchKey"]) {
     31    mSearchKeys = [searchKeyParam isKindOfClass:[NSString class]]
     32                      ? [[NSArray alloc] initWithObjects:searchKeyParam, nil]
     33                      : [searchKeyParam retain];
     34  }
     35 
     36  if (id startElemParam = [params objectForKey:@"AXStartElement"]) {
     37    mStartElem = startElemParam;
     38  } else {
     39    mStartElem = root;
     40  }
     41 
     42  mRoot = root;
     43 
     44  mResultLimit = [[params objectForKey:@"AXResultsLimit"] intValue];
     45 
     46  mSearchForward =
     47      [[params objectForKey:@"AXDirection"] isEqualToString:@"AXDirectionNext"];
     48 
     49  mImmediateDescendantsOnly =
     50      [[params objectForKey:@"AXImmediateDescendantsOnly"] boolValue];
     51 
     52  mSearchText = [params objectForKey:@"AXSearchText"];
     53 
     54  return [super init];
     55 }
     56 
     57 - (Accessible*)rootGeckoAccessible {
     58  id root =
     59      [mRoot isKindOfClass:[mozAccessible class]] ? mRoot : [mRoot moxParent];
     60 
     61  return [static_cast<mozAccessible*>(root) geckoAccessible];
     62 }
     63 
     64 - (Accessible*)startGeckoAccessible {
     65  if ([mStartElem isKindOfClass:[mozAccessible class]]) {
     66    return [static_cast<mozAccessible*>(mStartElem) geckoAccessible];
     67  }
     68 
     69  // If it isn't a mozAccessible, it doesn't have a gecko accessible
     70  // this is most likely the root group. Use the gecko doc as the start
     71  // accessible.
     72  return [self rootGeckoAccessible];
     73 }
     74 
     75 - (NSArray*)getMatchesForRule:(PivotRule&)rule {
     76  int resultLimit = mResultLimit;
     77 
     78  NSMutableArray<mozAccessible*>* matches =
     79      [[[NSMutableArray alloc] init] autorelease];
     80  Accessible* geckoRootAcc = [self rootGeckoAccessible];
     81  Accessible* geckoStartAcc = [self startGeckoAccessible];
     82  Pivot p = Pivot(geckoRootAcc);
     83  Accessible* match;
     84  if (mSearchForward) {
     85    match = p.Next(geckoStartAcc, rule);
     86  } else {
     87    // Search backwards
     88    if (geckoRootAcc == geckoStartAcc) {
     89      // If we have no explicit start accessible, start from the last match.
     90      match = p.Last(rule);
     91    } else {
     92      match = p.Prev(geckoStartAcc, rule);
     93    }
     94  }
     95 
     96  while (match && resultLimit != 0) {
     97    if (!mSearchForward && match == geckoRootAcc) {
     98      // If searching backwards, don't include root.
     99      break;
    100    }
    101 
    102    // we use mResultLimit != 0 to capture the case where mResultLimit is -1
    103    // when it is set from the params dictionary. If that's true, we want
    104    // to return all matches (ie. have no limit)
    105    mozAccessible* nativeMatch = GetNativeFromGeckoAccessible(match);
    106    if (nativeMatch) {
    107      // only add/count results for which there is a matching
    108      // native accessible
    109      [matches addObject:nativeMatch];
    110      resultLimit -= 1;
    111    }
    112 
    113    match = mSearchForward ? p.Next(match, rule) : p.Prev(match, rule);
    114  }
    115 
    116  return matches;
    117 }
    118 
    119 - (NSArray*)performSearch {
    120  Accessible* geckoRootAcc = [self rootGeckoAccessible];
    121  Accessible* geckoStartAcc = [self startGeckoAccessible];
    122  NSMutableArray* matches = [[[NSMutableArray alloc] init] autorelease];
    123  nsString searchText;
    124  nsCocoaUtils::GetStringForNSString(mSearchText, searchText);
    125  for (id key in mSearchKeys) {
    126    if ([key isEqualToString:@"AXAnyTypeSearchKey"]) {
    127      RotorRule rule = mImmediateDescendantsOnly
    128                           ? RotorRule(geckoRootAcc, searchText)
    129                           : RotorRule(searchText);
    130 
    131      if (searchText.IsEmpty() &&
    132          [mStartElem isKindOfClass:[MOXWebAreaAccessible class]]) {
    133        // Don't include the root group when a search text is defined.
    134        if (id rootGroup =
    135                [static_cast<MOXWebAreaAccessible*>(mStartElem) rootGroup]) {
    136          // Moving forward from web area, rootgroup; if it exists, is next.
    137          [matches addObject:rootGroup];
    138          if (mResultLimit == 1) {
    139            // Found one match, continue in search keys for block.
    140            continue;
    141          }
    142        }
    143      }
    144 
    145      if (mImmediateDescendantsOnly && mStartElem != mRoot &&
    146          [mStartElem isKindOfClass:[MOXRootGroup class]]) {
    147        // Moving forward from root group. If we don't match descendants,
    148        // there is no match. Continue.
    149        continue;
    150      }
    151      [matches addObjectsFromArray:[self getMatchesForRule:rule]];
    152    }
    153 
    154    if ([key isEqualToString:@"AXHeadingSearchKey"]) {
    155      RotorRoleRule rule =
    156          mImmediateDescendantsOnly
    157              ? RotorRoleRule(roles::HEADING, geckoRootAcc, searchText)
    158              : RotorRoleRule(roles::HEADING, searchText);
    159      [matches addObjectsFromArray:[self getMatchesForRule:rule]];
    160    }
    161 
    162    if ([key isEqualToString:@"AXArticleSearchKey"]) {
    163      RotorRoleRule rule =
    164          mImmediateDescendantsOnly
    165              ? RotorRoleRule(roles::ARTICLE, geckoRootAcc, searchText)
    166              : RotorRoleRule(roles::ARTICLE, searchText);
    167      [matches addObjectsFromArray:[self getMatchesForRule:rule]];
    168    }
    169 
    170    if ([key isEqualToString:@"AXTableSearchKey"]) {
    171      RotorRoleRule rule =
    172          mImmediateDescendantsOnly
    173              ? RotorRoleRule(roles::TABLE, geckoRootAcc, searchText)
    174              : RotorRoleRule(roles::TABLE, searchText);
    175      [matches addObjectsFromArray:[self getMatchesForRule:rule]];
    176    }
    177 
    178    if ([key isEqualToString:@"AXLandmarkSearchKey"]) {
    179      RotorRoleRule rule =
    180          mImmediateDescendantsOnly
    181              ? RotorRoleRule(roles::LANDMARK, geckoRootAcc, searchText)
    182              : RotorRoleRule(roles::LANDMARK, searchText);
    183      [matches addObjectsFromArray:[self getMatchesForRule:rule]];
    184    }
    185 
    186    if ([key isEqualToString:@"AXListSearchKey"]) {
    187      RotorRoleRule rule =
    188          mImmediateDescendantsOnly
    189              ? RotorRoleRule(roles::LIST, geckoRootAcc, searchText)
    190              : RotorRoleRule(roles::LIST, searchText);
    191      [matches addObjectsFromArray:[self getMatchesForRule:rule]];
    192    }
    193 
    194    if ([key isEqualToString:@"AXLinkSearchKey"]) {
    195      RotorLinkRule rule = mImmediateDescendantsOnly
    196                               ? RotorLinkRule(geckoRootAcc, searchText)
    197                               : RotorLinkRule(searchText);
    198      [matches addObjectsFromArray:[self getMatchesForRule:rule]];
    199    }
    200 
    201    if ([key isEqualToString:@"AXVisitedLinkSearchKey"]) {
    202      RotorVisitedLinkRule rule =
    203          mImmediateDescendantsOnly
    204              ? RotorVisitedLinkRule(geckoRootAcc, searchText)
    205              : RotorVisitedLinkRule(searchText);
    206      [matches addObjectsFromArray:[self getMatchesForRule:rule]];
    207    }
    208 
    209    if ([key isEqualToString:@"AXUnvisitedLinkSearchKey"]) {
    210      RotorUnvisitedLinkRule rule =
    211          mImmediateDescendantsOnly
    212              ? RotorUnvisitedLinkRule(geckoRootAcc, searchText)
    213              : RotorUnvisitedLinkRule(searchText);
    214      [matches addObjectsFromArray:[self getMatchesForRule:rule]];
    215    }
    216 
    217    if ([key isEqualToString:@"AXButtonSearchKey"]) {
    218      RotorRoleRule rule =
    219          mImmediateDescendantsOnly
    220              ? RotorRoleRule(roles::PUSHBUTTON, geckoRootAcc, searchText)
    221              : RotorRoleRule(roles::PUSHBUTTON, searchText);
    222      [matches addObjectsFromArray:[self getMatchesForRule:rule]];
    223    }
    224 
    225    if ([key isEqualToString:@"AXControlSearchKey"]) {
    226      RotorControlRule rule = mImmediateDescendantsOnly
    227                                  ? RotorControlRule(geckoRootAcc, searchText)
    228                                  : RotorControlRule(searchText);
    229      [matches addObjectsFromArray:[self getMatchesForRule:rule]];
    230    }
    231 
    232    if ([key isEqualToString:@"AXSameTypeSearchKey"]) {
    233      mozAccessible* native = GetNativeFromGeckoAccessible(geckoStartAcc);
    234      NSString* macRole = [native moxRole];
    235      RotorMacRoleRule rule =
    236          mImmediateDescendantsOnly
    237              ? RotorMacRoleRule(macRole, geckoRootAcc, searchText)
    238              : RotorMacRoleRule(macRole, searchText);
    239      [matches addObjectsFromArray:[self getMatchesForRule:rule]];
    240    }
    241 
    242    if ([key isEqualToString:@"AXDifferentTypeSearchKey"]) {
    243      mozAccessible* native = GetNativeFromGeckoAccessible(geckoStartAcc);
    244      NSString* macRole = [native moxRole];
    245      RotorNotMacRoleRule rule =
    246          mImmediateDescendantsOnly
    247              ? RotorNotMacRoleRule(macRole, geckoRootAcc, searchText)
    248              : RotorNotMacRoleRule(macRole, searchText);
    249      [matches addObjectsFromArray:[self getMatchesForRule:rule]];
    250    }
    251 
    252    if ([key isEqualToString:@"AXRadioGroupSearchKey"]) {
    253      RotorRoleRule rule =
    254          mImmediateDescendantsOnly
    255              ? RotorRoleRule(roles::RADIO_GROUP, geckoRootAcc, searchText)
    256              : RotorRoleRule(roles::RADIO_GROUP, searchText);
    257      [matches addObjectsFromArray:[self getMatchesForRule:rule]];
    258    }
    259 
    260    if ([key isEqualToString:@"AXFrameSearchKey"]) {
    261      RotorRoleRule rule =
    262          mImmediateDescendantsOnly
    263              ? RotorRoleRule(roles::DOCUMENT, geckoRootAcc, searchText)
    264              : RotorRoleRule(roles::DOCUMENT, searchText);
    265      [matches addObjectsFromArray:[self getMatchesForRule:rule]];
    266    }
    267 
    268    if ([key isEqualToString:@"AXImageSearchKey"] ||
    269        [key isEqualToString:@"AXGraphicSearchKey"]) {
    270      RotorRoleRule rule =
    271          mImmediateDescendantsOnly
    272              ? RotorRoleRule(roles::GRAPHIC, geckoRootAcc, searchText)
    273              : RotorRoleRule(roles::GRAPHIC, searchText);
    274      [matches addObjectsFromArray:[self getMatchesForRule:rule]];
    275    }
    276 
    277    if ([key isEqualToString:@"AXCheckBoxSearchKey"]) {
    278      RotorRoleRule rule =
    279          mImmediateDescendantsOnly
    280              ? RotorRoleRule(roles::CHECKBUTTON, geckoRootAcc, searchText)
    281              : RotorRoleRule(roles::CHECKBUTTON, searchText);
    282      [matches addObjectsFromArray:[self getMatchesForRule:rule]];
    283    }
    284 
    285    if ([key isEqualToString:@"AXStaticTextSearchKey"]) {
    286      RotorStaticTextRule rule =
    287          mImmediateDescendantsOnly
    288              ? RotorStaticTextRule(geckoRootAcc, searchText)
    289              : RotorStaticTextRule(searchText);
    290      [matches addObjectsFromArray:[self getMatchesForRule:rule]];
    291    }
    292 
    293    if ([key isEqualToString:@"AXHeadingLevel1SearchKey"]) {
    294      RotorHeadingLevelRule rule =
    295          mImmediateDescendantsOnly
    296              ? RotorHeadingLevelRule(1, geckoRootAcc, searchText)
    297              : RotorHeadingLevelRule(1, searchText);
    298      [matches addObjectsFromArray:[self getMatchesForRule:rule]];
    299    }
    300 
    301    if ([key isEqualToString:@"AXHeadingLevel2SearchKey"]) {
    302      RotorHeadingLevelRule rule =
    303          mImmediateDescendantsOnly
    304              ? RotorHeadingLevelRule(2, geckoRootAcc, searchText)
    305              : RotorHeadingLevelRule(2, searchText);
    306      [matches addObjectsFromArray:[self getMatchesForRule:rule]];
    307    }
    308 
    309    if ([key isEqualToString:@"AXHeadingLevel3SearchKey"]) {
    310      RotorHeadingLevelRule rule =
    311          mImmediateDescendantsOnly
    312              ? RotorHeadingLevelRule(3, geckoRootAcc, searchText)
    313              : RotorHeadingLevelRule(3, searchText);
    314      [matches addObjectsFromArray:[self getMatchesForRule:rule]];
    315    }
    316 
    317    if ([key isEqualToString:@"AXHeadingLevel4SearchKey"]) {
    318      RotorHeadingLevelRule rule =
    319          mImmediateDescendantsOnly
    320              ? RotorHeadingLevelRule(4, geckoRootAcc, searchText)
    321              : RotorHeadingLevelRule(4, searchText);
    322      [matches addObjectsFromArray:[self getMatchesForRule:rule]];
    323    }
    324 
    325    if ([key isEqualToString:@"AXHeadingLevel5SearchKey"]) {
    326      RotorHeadingLevelRule rule =
    327          mImmediateDescendantsOnly
    328              ? RotorHeadingLevelRule(5, geckoRootAcc, searchText)
    329              : RotorHeadingLevelRule(5, searchText);
    330      [matches addObjectsFromArray:[self getMatchesForRule:rule]];
    331    }
    332 
    333    if ([key isEqualToString:@"AXHeadingLevel6SearchKey"]) {
    334      RotorHeadingLevelRule rule =
    335          mImmediateDescendantsOnly
    336              ? RotorHeadingLevelRule(6, geckoRootAcc, searchText)
    337              : RotorHeadingLevelRule(6, searchText);
    338      [matches addObjectsFromArray:[self getMatchesForRule:rule]];
    339    }
    340 
    341    if ([key isEqualToString:@"AXBlockquoteSearchKey"]) {
    342      RotorRoleRule rule =
    343          mImmediateDescendantsOnly
    344              ? RotorRoleRule(roles::BLOCKQUOTE, geckoRootAcc, searchText)
    345              : RotorRoleRule(roles::BLOCKQUOTE, searchText);
    346      [matches addObjectsFromArray:[self getMatchesForRule:rule]];
    347    }
    348 
    349    if ([key isEqualToString:@"AXTextFieldSearchKey"]) {
    350      RotorTextEntryRule rule =
    351          mImmediateDescendantsOnly
    352              ? RotorTextEntryRule(geckoRootAcc, searchText)
    353              : RotorTextEntryRule(searchText);
    354      [matches addObjectsFromArray:[self getMatchesForRule:rule]];
    355    }
    356 
    357    if ([key isEqualToString:@"AXLiveRegionSearchKey"]) {
    358      RotorLiveRegionRule rule =
    359          mImmediateDescendantsOnly
    360              ? RotorLiveRegionRule(geckoRootAcc, searchText)
    361              : RotorLiveRegionRule(searchText);
    362      [matches addObjectsFromArray:[self getMatchesForRule:rule]];
    363    }
    364 
    365    if ([key isEqualToString:@"AXKeyboardFocusableSearchKey"]) {
    366      RotorFocusableRule rule =
    367          mImmediateDescendantsOnly
    368              ? RotorFocusableRule(geckoRootAcc, searchText)
    369              : RotorFocusableRule(searchText);
    370      [matches addObjectsFromArray:[self getMatchesForRule:rule]];
    371    }
    372  }
    373 
    374  return matches;
    375 }
    376 
    377 - (void)dealloc {
    378  [mSearchKeys release];
    379  [super dealloc];
    380 }
    381 
    382 @end