tor-browser

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

mozActionElements.mm (7011B)


      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 "mozActionElements.h"
      9 
     10 #import "MacUtils.h"
     11 #include "LocalAccessible-inl.h"
     12 #include "DocAccessible.h"
     13 #include "XULTabAccessible.h"
     14 #include "HTMLFormControlAccessible.h"
     15 
     16 #include "nsCocoaUtils.h"
     17 
     18 using namespace mozilla::a11y;
     19 
     20 @implementation mozButtonAccessible
     21 
     22 - (NSNumber*)moxHasPopup {
     23  return @([self stateWithMask:states::HASPOPUP] != 0);
     24 }
     25 
     26 - (NSString*)moxPopupValue {
     27  if ([self stateWithMask:states::HASPOPUP] != 0) {
     28    return utils::GetAccAttr(self, nsGkAtoms::aria_haspopup);
     29  }
     30 
     31  return nil;
     32 }
     33 
     34 @end
     35 
     36 @implementation mozPopupButtonAccessible
     37 
     38 - (NSString*)moxTitle {
     39  // Popup buttons don't have titles.
     40  return @"";
     41 }
     42 
     43 - (BOOL)moxBlockSelector:(SEL)selector {
     44  if (selector == @selector(moxHasPopup)) {
     45    return YES;
     46  }
     47 
     48  return [super moxBlockSelector:selector];
     49 }
     50 
     51 - (NSArray*)moxChildren {
     52  if ([self stateWithMask:states::EXPANDED] == 0) {
     53    // If the popup button is collapsed don't return its children.
     54    return @[];
     55  }
     56 
     57  return [super moxChildren];
     58 }
     59 
     60 - (void)stateChanged:(uint64_t)state isEnabled:(BOOL)enabled {
     61  [super stateChanged:state isEnabled:enabled];
     62 
     63  if (state == states::EXPANDED) {
     64    // If the EXPANDED state is updated, fire AXMenu events on the
     65    // popups child which is the actual menu.
     66    if (mozAccessible* popup = (mozAccessible*)[self childAt:0]) {
     67      [popup moxPostNotification:(enabled ? @"AXMenuOpened" : @"AXMenuClosed")];
     68    }
     69  }
     70 }
     71 
     72 @end
     73 
     74 @implementation mozRadioButtonAccessible
     75 
     76 - (NSArray*)moxLinkedUIElements {
     77  return [[self getRelationsByType:RelationType::MEMBER_OF]
     78      arrayByAddingObjectsFromArray:[super moxLinkedUIElements]];
     79 }
     80 
     81 @end
     82 
     83 @implementation mozCheckboxAccessible
     84 
     85 - (int)isChecked {
     86  // check if we're checked or in a mixed state
     87  uint64_t state =
     88      [self stateWithMask:(states::CHECKED | states::PRESSED | states::MIXED)];
     89  if (state & (states::CHECKED | states::PRESSED)) {
     90    return kChecked;
     91  }
     92 
     93  if (state & states::MIXED) {
     94    return kMixed;
     95  }
     96 
     97  return kUnchecked;
     98 }
     99 
    100 - (id)moxValue {
    101  NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
    102 
    103  return [NSNumber numberWithInt:[self isChecked]];
    104 
    105  NS_OBJC_END_TRY_BLOCK_RETURN(nil);
    106 }
    107 
    108 - (void)stateChanged:(uint64_t)state isEnabled:(BOOL)enabled {
    109  [super stateChanged:state isEnabled:enabled];
    110 
    111  if (state & (states::CHECKED | states::PRESSED | states::MIXED)) {
    112    [self moxPostNotification:NSAccessibilityValueChangedNotification];
    113  }
    114 }
    115 
    116 @end
    117 
    118 @implementation mozPaneAccessible
    119 
    120 - (NSArray*)moxChildren {
    121  // By default, all tab panels are exposed in the a11y tree
    122  // even if the tab they represent isn't the active tab. To
    123  // prevent VoiceOver from navigating background tab content,
    124  // only expose the tab panel that is currently on screen.
    125  for (mozAccessible* child in [super moxChildren]) {
    126    if (!([child state] & states::OFFSCREEN)) {
    127      return [NSArray arrayWithObject:GetObjectOrRepresentedView(child)];
    128    }
    129  }
    130  MOZ_ASSERT_UNREACHABLE("We have no on screen tab content?");
    131  return @[];
    132 }
    133 
    134 @end
    135 
    136 @implementation mozRangeAccessible
    137 
    138 - (id)moxValue {
    139  return [NSNumber numberWithDouble:mGeckoAccessible->CurValue()];
    140 }
    141 
    142 - (id)moxMinValue {
    143  return [NSNumber numberWithDouble:mGeckoAccessible->MinValue()];
    144 }
    145 
    146 - (id)moxMaxValue {
    147  return [NSNumber numberWithDouble:mGeckoAccessible->MaxValue()];
    148 }
    149 
    150 - (NSString*)moxOrientation {
    151  RefPtr<AccAttributes> attributes = mGeckoAccessible->Attributes();
    152  if (attributes) {
    153    nsAutoString result;
    154    attributes->GetAttribute(nsGkAtoms::aria_orientation, result);
    155    if (result.Equals(u"horizontal"_ns)) {
    156      return NSAccessibilityHorizontalOrientationValue;
    157    } else if (result.Equals(u"vertical"_ns)) {
    158      return NSAccessibilityVerticalOrientationValue;
    159    }
    160  }
    161 
    162  return NSAccessibilityUnknownOrientationValue;
    163 }
    164 
    165 - (void)handleAccessibleEvent:(uint32_t)eventType {
    166  switch (eventType) {
    167    case nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE:
    168    case nsIAccessibleEvent::EVENT_VALUE_CHANGE:
    169      [self moxPostNotification:NSAccessibilityValueChangedNotification];
    170      break;
    171    default:
    172      [super handleAccessibleEvent:eventType];
    173      break;
    174  }
    175 }
    176 
    177 @end
    178 
    179 @implementation mozMeterAccessible
    180 
    181 - (NSString*)moxValueDescription {
    182  nsAutoString valueDesc;
    183  mGeckoAccessible->Value(valueDesc);
    184  if (mGeckoAccessible->TagName() != nsGkAtoms::meter) {
    185    // We're dealing with an aria meter, which shouldn't get
    186    // a value region.
    187    return nsCocoaUtils::ToNSString(valueDesc);
    188  }
    189 
    190  if (!valueDesc.IsEmpty()) {
    191    // Append a comma to separate the existing value description
    192    // from the value region.
    193    valueDesc.Append(u", "_ns);
    194  }
    195  // We need to concat the given value description
    196  // with a description of the value as either optimal,
    197  // suboptimal, or critical.
    198  int32_t region;
    199  if (mGeckoAccessible->IsRemote()) {
    200    region = mGeckoAccessible->AsRemote()->ValueRegion();
    201  } else {
    202    HTMLMeterAccessible* localMeter =
    203        static_cast<HTMLMeterAccessible*>(mGeckoAccessible->AsLocal());
    204    region = localMeter->ValueRegion();
    205  }
    206 
    207  if (region == 1) {
    208    valueDesc.Append(u"Optimal value"_ns);
    209  } else if (region == 0) {
    210    valueDesc.Append(u"Suboptimal value"_ns);
    211  } else {
    212    MOZ_ASSERT(region == -1);
    213    valueDesc.Append(u"Critical value"_ns);
    214  }
    215 
    216  return nsCocoaUtils::ToNSString(valueDesc);
    217 }
    218 
    219 @end
    220 
    221 @implementation mozIncrementableAccessible
    222 
    223 - (NSString*)moxValueDescription {
    224  nsAutoString valueDesc;
    225  mGeckoAccessible->Value(valueDesc);
    226  return nsCocoaUtils::ToNSString(valueDesc);
    227 }
    228 
    229 - (void)moxSetValue:(id)value {
    230  [self setValue:([value doubleValue])];
    231 }
    232 
    233 - (void)moxPerformIncrement {
    234  [self changeValueBySteps:1];
    235 }
    236 
    237 - (void)moxPerformDecrement {
    238  [self changeValueBySteps:-1];
    239 }
    240 
    241 /*
    242 * Updates the accessible's current value by factor and step.
    243 *
    244 * factor: A signed integer representing the number of times to
    245 *    apply step to the current value. A positive value will increment,
    246 *    while a negative one will decrement.
    247 * step: An unsigned integer specified by the webauthor and indicating the
    248 *    amount by which to increment/decrement the current value.
    249 */
    250 - (void)changeValueBySteps:(int)factor {
    251  MOZ_ASSERT(mGeckoAccessible, "mGeckoAccessible is null");
    252 
    253  double newValue =
    254      mGeckoAccessible->CurValue() + (mGeckoAccessible->Step() * factor);
    255  [self setValue:(newValue)];
    256 }
    257 
    258 /*
    259 * Updates the accessible's current value to the specified value
    260 */
    261 - (void)setValue:(double)value {
    262  MOZ_ASSERT(mGeckoAccessible, "mGeckoAccessible is null");
    263  mGeckoAccessible->SetCurValue(value);
    264 }
    265 
    266 @end
    267 
    268 @implementation mozDatePickerAccessible
    269 
    270 - (NSString*)moxTitle {
    271  return utils::LocalizedString(u"dateField"_ns);
    272 }
    273 
    274 @end