tor-browser

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

MacUtils.mm (6304B)


      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 "MacUtils.h"
      9 #include "mozAccessible.h"
     10 
     11 #include "LocalAccessible.h"
     12 #include "DocAccessible.h"
     13 #include "DocAccessibleParent.h"
     14 #include "nsCocoaUtils.h"
     15 #include "mozilla/a11y/PDocAccessible.h"
     16 
     17 namespace mozilla {
     18 namespace a11y {
     19 namespace utils {
     20 
     21 /**
     22 * Get a localized string from the a11y string bundle.
     23 * Return nil if not found.
     24 */
     25 NSString* LocalizedString(const nsString& aString) {
     26  nsString text;
     27 
     28  Accessible::TranslateString(aString, text);
     29 
     30  return text.IsEmpty() ? nil : nsCocoaUtils::ToNSString(text);
     31 }
     32 
     33 NSString* GetAccAttr(mozAccessible* aNativeAccessible, nsAtom* aAttrName) {
     34  nsAutoString result;
     35  Accessible* acc = [aNativeAccessible geckoAccessible];
     36  RefPtr<AccAttributes> attributes = acc->Attributes();
     37 
     38  if (!attributes) {
     39    return nil;
     40  }
     41 
     42  attributes->GetAttribute(aAttrName, result);
     43 
     44  if (!result.IsEmpty()) {
     45    return nsCocoaUtils::ToNSString(result);
     46  }
     47 
     48  return nil;
     49 }
     50 
     51 bool DocumentExists(Accessible* aDoc, uintptr_t aDocPtr) {
     52  if (reinterpret_cast<uintptr_t>(aDoc) == aDocPtr) {
     53    return true;
     54  }
     55 
     56  if (aDoc->IsLocal()) {
     57    DocAccessible* docAcc = aDoc->AsLocal()->AsDoc();
     58    uint32_t docCount = docAcc->ChildDocumentCount();
     59    for (uint32_t i = 0; i < docCount; i++) {
     60      if (DocumentExists(docAcc->GetChildDocumentAt(i), aDocPtr)) {
     61        return true;
     62      }
     63    }
     64  } else {
     65    DocAccessibleParent* docProxy = aDoc->AsRemote()->AsDoc();
     66    size_t docCount = docProxy->ChildDocCount();
     67    for (uint32_t i = 0; i < docCount; i++) {
     68      if (DocumentExists(docProxy->ChildDocAt(i), aDocPtr)) {
     69        return true;
     70      }
     71    }
     72  }
     73 
     74  return false;
     75 }
     76 
     77 static NSColor* ColorFromColor(const Color& aColor) {
     78  return [NSColor colorWithCalibratedRed:NS_GET_R(aColor.mValue) / 255.0
     79                                   green:NS_GET_G(aColor.mValue) / 255.0
     80                                    blue:NS_GET_B(aColor.mValue) / 255.0
     81                                   alpha:1.0];
     82 }
     83 
     84 NSDictionary* StringAttributesFromAccAttributes(AccAttributes* aAttributes,
     85                                                Accessible* aContainer) {
     86  if (!aAttributes) {
     87    if (mozAccessible* mozAcc = GetNativeFromGeckoAccessible(aContainer)) {
     88      // If we don't have attributes provided this is probably a control like
     89      // a button or empty entry. Just provide the accessible as an
     90      // AXAttachment.
     91      return @{@"AXAttachment" : mozAcc};
     92    }
     93    return @{};
     94  }
     95 
     96  NSMutableDictionary* attrDict =
     97      [NSMutableDictionary dictionaryWithCapacity:aAttributes->Count()];
     98  NSMutableDictionary* fontAttrDict = [[NSMutableDictionary alloc] init];
     99  [attrDict setObject:fontAttrDict forKey:@"AXFont"];
    100  for (auto iter : *aAttributes) {
    101    if (iter.Name() == nsGkAtoms::background_color) {
    102      if (Maybe<Color> value = iter.Value<Color>()) {
    103        NSColor* color = ColorFromColor(*value);
    104        [attrDict setObject:(__bridge id)color.CGColor
    105                     forKey:@"AXBackgroundColor"];
    106      }
    107    } else if (iter.Name() == nsGkAtoms::color) {
    108      if (Maybe<Color> value = iter.Value<Color>()) {
    109        NSColor* color = ColorFromColor(*value);
    110        [attrDict setObject:(__bridge id)color.CGColor
    111                     forKey:@"AXForegroundColor"];
    112      }
    113    } else if (iter.Name() == nsGkAtoms::font_size) {
    114      if (Maybe<FontSize> pointSize = iter.Value<FontSize>()) {
    115        int32_t fontPixelSize = static_cast<int32_t>(pointSize->mValue * 4 / 3);
    116        [fontAttrDict setObject:@(fontPixelSize) forKey:@"AXFontSize"];
    117      }
    118    } else if (iter.Name() == nsGkAtoms::font_family) {
    119      nsAutoString fontFamily;
    120      iter.ValueAsString(fontFamily);
    121      [fontAttrDict setObject:nsCocoaUtils::ToNSString(fontFamily)
    122                       forKey:@"AXFontFamily"];
    123    } else if (iter.Name() == nsGkAtoms::textUnderlineColor) {
    124      [attrDict setObject:@1 forKey:@"AXUnderline"];
    125      if (Maybe<Color> value = iter.Value<Color>()) {
    126        NSColor* color = ColorFromColor(*value);
    127        [attrDict setObject:(__bridge id)color.CGColor
    128                     forKey:@"AXUnderlineColor"];
    129      }
    130    } else if (iter.Name() == nsGkAtoms::invalid) {
    131      // XXX: There is currently no attribute for grammar
    132      if (auto value = iter.Value<RefPtr<nsAtom>>()) {
    133        if (*value == nsGkAtoms::spelling) {
    134          [attrDict setObject:@YES
    135                       forKey:NSAccessibilityMarkedMisspelledTextAttribute];
    136        }
    137      }
    138    } else if (iter.Name() == nsGkAtoms::mark) {
    139      if (auto value = iter.Value<bool>()) {
    140        if (*value) {
    141          [attrDict setObject:@YES forKey:@"AXHighlight"];
    142        }
    143      }
    144    } else {
    145      nsAutoString valueStr;
    146      iter.ValueAsString(valueStr);
    147      nsAutoString keyStr;
    148      iter.NameAsString(keyStr);
    149      [attrDict setObject:nsCocoaUtils::ToNSString(valueStr)
    150                   forKey:nsCocoaUtils::ToNSString(keyStr)];
    151    }
    152  }
    153 
    154  mozAccessible* container = GetNativeFromGeckoAccessible(aContainer);
    155  id<MOXAccessible> link =
    156      [container moxFindAncestor:^BOOL(id<MOXAccessible> moxAcc, BOOL* stop) {
    157        return [[moxAcc moxRole] isEqualToString:NSAccessibilityLinkRole];
    158      }];
    159  if (link) {
    160    [attrDict setObject:link forKey:@"AXLink"];
    161  }
    162 
    163  id<MOXAccessible> heading =
    164      [container moxFindAncestor:^BOOL(id<MOXAccessible> moxAcc, BOOL* stop) {
    165        return [[moxAcc moxRole] isEqualToString:@"AXHeading"];
    166      }];
    167  if (heading) {
    168    [attrDict setObject:[heading moxValue] forKey:@"AXHeadingLevel"];
    169  }
    170 
    171  return attrDict;
    172 }
    173 
    174 NSScreen* GetNSScreenForAcc(mozAccessible* aAcc) {
    175  if (!aAcc) {
    176    return nil;
    177  }
    178 
    179  NSWindow* window = [aAcc moxWindow];
    180  NSScreen* screen = window ? [window screen] : nil;
    181  if (!screen) {
    182    // default to the main screen if we can't find one
    183    // specific to the window
    184    screen = [[NSScreen screens] objectAtIndex:0];
    185  }
    186 
    187  return screen;
    188 }
    189 }  // namespace utils
    190 }  // namespace a11y
    191 }  // namespace mozilla