tor-browser

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

Quotes.cpp (2859B)


      1 /* -*- Mode: 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/. */
      5 
      6 #include "Quotes.h"
      7 #include "mozilla/ClearOnShutdown.h"
      8 #include "mozilla/StaticPtr.h"
      9 #include "mozilla/intl/Locale.h"
     10 #include "nsTHashMap.h"
     11 #include "nsPrintfCString.h"
     12 
     13 using namespace mozilla;
     14 using namespace mozilla::intl;
     15 
     16 namespace {
     17 struct LangQuotesRec {
     18  const char* mLangs;
     19  Quotes mQuotes;
     20 };
     21 
     22 #include "cldr-quotes.inc"
     23 
     24 static StaticAutoPtr<nsTHashMap<nsCStringHashKey, Quotes>> sQuotesForLang;
     25 }  // anonymous namespace
     26 
     27 namespace mozilla {
     28 namespace intl {
     29 
     30 const Quotes* QuotesForLang(const nsAtom* aLang) {
     31  MOZ_ASSERT(NS_IsMainThread());
     32 
     33  // On first use, initialize the hashtable from our CLDR-derived data array.
     34  if (!sQuotesForLang) {
     35    sQuotesForLang = new nsTHashMap<nsCStringHashKey, Quotes>(32);
     36    ClearOnShutdown(&sQuotesForLang);
     37    for (const auto& i : sLangQuotes) {
     38      const char* s = i.mLangs;
     39      size_t len;
     40      while ((len = strlen(s))) {
     41        sQuotesForLang->InsertOrUpdate(nsDependentCString(s, len), i.mQuotes);
     42        s += len + 1;
     43      }
     44    }
     45  }
     46 
     47  nsAtomCString langStr(aLang);
     48  const Quotes* entry = sQuotesForLang->Lookup(langStr).DataPtrOrNull();
     49  if (entry) {
     50    // Found an exact match for the requested lang.
     51    return entry;
     52  }
     53 
     54  // Try parsing lang as a Locale, then see if we can match it with region or
     55  // script subtags, if present, or just the primary language tag.
     56  // Note that the locale code (if well-formed) will have been canonicalized by
     57  // the attribute-mapping code, so we can rely on the expected casing for each
     58  // type of subtag.
     59  Locale loc;
     60  auto result = LocaleParser::TryParse(langStr, loc);
     61  if (result.isErr()) {
     62    return nullptr;
     63  }
     64  // Extract the primary language tag.
     65  const Span<const char> langAsSpan = loc.Language().Span();
     66  nsAutoCString lang(langAsSpan.data(), langAsSpan.size());
     67  const auto langLen = lang.Length();
     68  // See if we can match language + region.
     69  if (loc.Region().Present()) {
     70    lang.Append('-');
     71    lang.Append(loc.Region().Span());
     72    if ((entry = sQuotesForLang->Lookup(lang).DataPtrOrNull())) {
     73      return entry;
     74    }
     75    lang.Truncate(langLen);
     76  }
     77  // See if we can match language + script.
     78  if (loc.Script().Present()) {
     79    lang.Append('-');
     80    lang.Append(loc.Script().Span());
     81    if ((entry = sQuotesForLang->Lookup(lang).DataPtrOrNull())) {
     82      return entry;
     83    }
     84    lang.Truncate(langLen);
     85  }
     86  // OK, just try the primary language tag alone.
     87  if ((entry = sQuotesForLang->Lookup(lang).DataPtrOrNull())) {
     88    return entry;
     89  }
     90 
     91  return nullptr;
     92 }
     93 
     94 }  // namespace intl
     95 }  // namespace mozilla