intl/hyphenation/src/nsHyphenationManager.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/intl/hyphenation/src/nsHyphenationManager.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,312 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "nsHyphenationManager.h"
    1.10 +#include "nsHyphenator.h"
    1.11 +#include "nsIAtom.h"
    1.12 +#include "nsIFile.h"
    1.13 +#include "nsIURI.h"
    1.14 +#include "nsIProperties.h"
    1.15 +#include "nsISimpleEnumerator.h"
    1.16 +#include "nsIDirectoryEnumerator.h"
    1.17 +#include "nsDirectoryServiceDefs.h"
    1.18 +#include "nsNetUtil.h"
    1.19 +#include "nsUnicharUtils.h"
    1.20 +#include "mozilla/Preferences.h"
    1.21 +#include "nsZipArchive.h"
    1.22 +#include "mozilla/Services.h"
    1.23 +#include "nsIObserverService.h"
    1.24 +#include "nsCRT.h"
    1.25 +
    1.26 +using namespace mozilla;
    1.27 +
    1.28 +static const char kIntlHyphenationAliasPrefix[] = "intl.hyphenation-alias.";
    1.29 +static const char kMemoryPressureNotification[] = "memory-pressure";
    1.30 +
    1.31 +nsHyphenationManager *nsHyphenationManager::sInstance = nullptr;
    1.32 +
    1.33 +NS_IMPL_ISUPPORTS(nsHyphenationManager::MemoryPressureObserver,
    1.34 +                  nsIObserver)
    1.35 +
    1.36 +NS_IMETHODIMP
    1.37 +nsHyphenationManager::MemoryPressureObserver::Observe(nsISupports *aSubject,
    1.38 +                                                      const char *aTopic,
    1.39 +                                                      const char16_t *aData)
    1.40 +{
    1.41 +  if (!nsCRT::strcmp(aTopic, kMemoryPressureNotification)) {
    1.42 +    // We don't call Instance() here, as we don't want to create a hyphenation
    1.43 +    // manager if there isn't already one in existence.
    1.44 +    // (This observer class is local to the hyphenation manager, so it can use
    1.45 +    // the protected members directly.)
    1.46 +    if (nsHyphenationManager::sInstance) {
    1.47 +      nsHyphenationManager::sInstance->mHyphenators.Clear();
    1.48 +    }
    1.49 +  }
    1.50 +  return NS_OK;
    1.51 +}
    1.52 +
    1.53 +nsHyphenationManager*
    1.54 +nsHyphenationManager::Instance()
    1.55 +{
    1.56 +  if (sInstance == nullptr) {
    1.57 +    sInstance = new nsHyphenationManager();
    1.58 +
    1.59 +    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
    1.60 +    if (obs) {
    1.61 +        obs->AddObserver(new MemoryPressureObserver,
    1.62 +                         kMemoryPressureNotification, false);
    1.63 +    }
    1.64 +  }
    1.65 +  return sInstance;
    1.66 +}
    1.67 +
    1.68 +void
    1.69 +nsHyphenationManager::Shutdown()
    1.70 +{
    1.71 +  delete sInstance;
    1.72 +  sInstance = nullptr;
    1.73 +}
    1.74 +
    1.75 +nsHyphenationManager::nsHyphenationManager()
    1.76 +{
    1.77 +  LoadPatternList();
    1.78 +  LoadAliases();
    1.79 +}
    1.80 +
    1.81 +nsHyphenationManager::~nsHyphenationManager()
    1.82 +{
    1.83 +  sInstance = nullptr;
    1.84 +}
    1.85 +
    1.86 +already_AddRefed<nsHyphenator>
    1.87 +nsHyphenationManager::GetHyphenator(nsIAtom *aLocale)
    1.88 +{
    1.89 +  nsRefPtr<nsHyphenator> hyph;
    1.90 +  mHyphenators.Get(aLocale, getter_AddRefs(hyph));
    1.91 +  if (hyph) {
    1.92 +    return hyph.forget();
    1.93 +  }
    1.94 +  nsCOMPtr<nsIURI> uri = mPatternFiles.Get(aLocale);
    1.95 +  if (!uri) {
    1.96 +    nsCOMPtr<nsIAtom> alias = mHyphAliases.Get(aLocale);
    1.97 +    if (alias) {
    1.98 +      mHyphenators.Get(alias, getter_AddRefs(hyph));
    1.99 +      if (hyph) {
   1.100 +        return hyph.forget();
   1.101 +      }
   1.102 +      uri = mPatternFiles.Get(alias);
   1.103 +      if (uri) {
   1.104 +        aLocale = alias;
   1.105 +      }
   1.106 +    }
   1.107 +    if (!uri) {
   1.108 +      // In the case of a locale such as "de-DE-1996", we try replacing
   1.109 +      // successive trailing subtags with "-*" to find fallback patterns,
   1.110 +      // so "de-DE-1996" -> "de-DE-*" (and then recursively -> "de-*")
   1.111 +      nsAtomCString localeStr(aLocale);
   1.112 +      if (StringEndsWith(localeStr, NS_LITERAL_CSTRING("-*"))) {
   1.113 +        localeStr.Truncate(localeStr.Length() - 2);
   1.114 +      }
   1.115 +      int32_t i = localeStr.RFindChar('-');
   1.116 +      if (i > 1) {
   1.117 +        localeStr.Replace(i, localeStr.Length() - i, "-*");
   1.118 +        nsCOMPtr<nsIAtom> fuzzyLocale = do_GetAtom(localeStr);
   1.119 +        return GetHyphenator(fuzzyLocale);
   1.120 +      } else {
   1.121 +        return nullptr;
   1.122 +      }
   1.123 +    }
   1.124 +  }
   1.125 +  hyph = new nsHyphenator(uri);
   1.126 +  if (hyph->IsValid()) {
   1.127 +    mHyphenators.Put(aLocale, hyph);
   1.128 +    return hyph.forget();
   1.129 +  }
   1.130 +#ifdef DEBUG
   1.131 +  nsCString msg;
   1.132 +  uri->GetSpec(msg);
   1.133 +  msg.Insert("failed to load patterns from ", 0);
   1.134 +  NS_WARNING(msg.get());
   1.135 +#endif
   1.136 +  mPatternFiles.Remove(aLocale);
   1.137 +  return nullptr;
   1.138 +}
   1.139 +
   1.140 +void
   1.141 +nsHyphenationManager::LoadPatternList()
   1.142 +{
   1.143 +  mPatternFiles.Clear();
   1.144 +  mHyphenators.Clear();
   1.145 +
   1.146 +  LoadPatternListFromOmnijar(Omnijar::GRE);
   1.147 +  LoadPatternListFromOmnijar(Omnijar::APP);
   1.148 +
   1.149 +  nsCOMPtr<nsIProperties> dirSvc =
   1.150 +    do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
   1.151 +  if (!dirSvc) {
   1.152 +    return;
   1.153 +  }
   1.154 +
   1.155 +  nsresult rv;
   1.156 +  nsCOMPtr<nsIFile> greDir;
   1.157 +  rv = dirSvc->Get(NS_GRE_DIR,
   1.158 +                   NS_GET_IID(nsIFile), getter_AddRefs(greDir));
   1.159 +  if (NS_SUCCEEDED(rv)) {
   1.160 +    greDir->AppendNative(NS_LITERAL_CSTRING("hyphenation"));
   1.161 +    LoadPatternListFromDir(greDir);
   1.162 +  }
   1.163 +
   1.164 +  nsCOMPtr<nsIFile> appDir;
   1.165 +  rv = dirSvc->Get(NS_XPCOM_CURRENT_PROCESS_DIR,
   1.166 +                   NS_GET_IID(nsIFile), getter_AddRefs(appDir));
   1.167 +  if (NS_SUCCEEDED(rv)) {
   1.168 +    appDir->AppendNative(NS_LITERAL_CSTRING("hyphenation"));
   1.169 +    bool equals;
   1.170 +    if (NS_SUCCEEDED(appDir->Equals(greDir, &equals)) && !equals) {
   1.171 +      LoadPatternListFromDir(appDir);
   1.172 +    }
   1.173 +  }
   1.174 +}
   1.175 +
   1.176 +void
   1.177 +nsHyphenationManager::LoadPatternListFromOmnijar(Omnijar::Type aType)
   1.178 +{
   1.179 +  nsCString base;
   1.180 +  nsresult rv = Omnijar::GetURIString(aType, base);
   1.181 +  if (NS_FAILED(rv)) {
   1.182 +    return;
   1.183 +  }
   1.184 +
   1.185 +  nsRefPtr<nsZipArchive> zip = Omnijar::GetReader(aType);
   1.186 +  if (!zip) {
   1.187 +    return;
   1.188 +  }
   1.189 +
   1.190 +  nsZipFind *find;
   1.191 +  zip->FindInit("hyphenation/hyph_*.dic", &find);
   1.192 +  if (!find) {
   1.193 +    return;
   1.194 +  }
   1.195 +
   1.196 +  const char *result;
   1.197 +  uint16_t len;
   1.198 +  while (NS_SUCCEEDED(find->FindNext(&result, &len))) {
   1.199 +    nsCString uriString(base);
   1.200 +    uriString.Append(result, len);
   1.201 +    nsCOMPtr<nsIURI> uri;
   1.202 +    rv = NS_NewURI(getter_AddRefs(uri), uriString);
   1.203 +    if (NS_FAILED(rv)) {
   1.204 +      continue;
   1.205 +    }
   1.206 +    nsCString locale;
   1.207 +    rv = uri->GetPath(locale);
   1.208 +    if (NS_FAILED(rv)) {
   1.209 +      continue;
   1.210 +    }
   1.211 +    ToLowerCase(locale);
   1.212 +    locale.SetLength(locale.Length() - 4); // strip ".dic"
   1.213 +    locale.Cut(0, locale.RFindChar('/') + 1); // strip directory
   1.214 +    if (StringBeginsWith(locale, NS_LITERAL_CSTRING("hyph_"))) {
   1.215 +      locale.Cut(0, 5);
   1.216 +    }
   1.217 +    for (uint32_t i = 0; i < locale.Length(); ++i) {
   1.218 +      if (locale[i] == '_') {
   1.219 +        locale.Replace(i, 1, '-');
   1.220 +      }
   1.221 +    }
   1.222 +    nsCOMPtr<nsIAtom> localeAtom = do_GetAtom(locale);
   1.223 +    if (NS_SUCCEEDED(rv)) {
   1.224 +      mPatternFiles.Put(localeAtom, uri);
   1.225 +    }
   1.226 +  }
   1.227 +
   1.228 +  delete find;
   1.229 +}
   1.230 +
   1.231 +void
   1.232 +nsHyphenationManager::LoadPatternListFromDir(nsIFile *aDir)
   1.233 +{
   1.234 +  nsresult rv;
   1.235 +
   1.236 +  bool check = false;
   1.237 +  rv = aDir->Exists(&check);
   1.238 +  if (NS_FAILED(rv) || !check) {
   1.239 +    return;
   1.240 +  }
   1.241 +
   1.242 +  rv = aDir->IsDirectory(&check);
   1.243 +  if (NS_FAILED(rv) || !check) {
   1.244 +    return;
   1.245 +  }
   1.246 +
   1.247 +  nsCOMPtr<nsISimpleEnumerator> e;
   1.248 +  rv = aDir->GetDirectoryEntries(getter_AddRefs(e));
   1.249 +  if (NS_FAILED(rv)) {
   1.250 +    return;
   1.251 +  }
   1.252 +
   1.253 +  nsCOMPtr<nsIDirectoryEnumerator> files(do_QueryInterface(e));
   1.254 +  if (!files) {
   1.255 +    return;
   1.256 +  }
   1.257 +
   1.258 +  nsCOMPtr<nsIFile> file;
   1.259 +  while (NS_SUCCEEDED(files->GetNextFile(getter_AddRefs(file))) && file){
   1.260 +    nsAutoString dictName;
   1.261 +    file->GetLeafName(dictName);
   1.262 +    NS_ConvertUTF16toUTF8 locale(dictName);
   1.263 +    ToLowerCase(locale);
   1.264 +    if (!StringEndsWith(locale, NS_LITERAL_CSTRING(".dic"))) {
   1.265 +      continue;
   1.266 +    }
   1.267 +    if (StringBeginsWith(locale, NS_LITERAL_CSTRING("hyph_"))) {
   1.268 +      locale.Cut(0, 5);
   1.269 +    }
   1.270 +    locale.SetLength(locale.Length() - 4); // strip ".dic"
   1.271 +    for (uint32_t i = 0; i < locale.Length(); ++i) {
   1.272 +      if (locale[i] == '_') {
   1.273 +        locale.Replace(i, 1, '-');
   1.274 +      }
   1.275 +    }
   1.276 +#ifdef DEBUG_hyph
   1.277 +    printf("adding hyphenation patterns for %s: %s\n", locale.get(),
   1.278 +           NS_ConvertUTF16toUTF8(dictName).get());
   1.279 +#endif
   1.280 +    nsCOMPtr<nsIAtom> localeAtom = do_GetAtom(locale);
   1.281 +    nsCOMPtr<nsIURI> uri;
   1.282 +    nsresult rv = NS_NewFileURI(getter_AddRefs(uri), file);
   1.283 +    if (NS_SUCCEEDED(rv)) {
   1.284 +      mPatternFiles.Put(localeAtom, uri);
   1.285 +    }
   1.286 +  }
   1.287 +}
   1.288 +
   1.289 +void
   1.290 +nsHyphenationManager::LoadAliases()
   1.291 +{
   1.292 +  nsIPrefBranch* prefRootBranch = Preferences::GetRootBranch();
   1.293 +  if (!prefRootBranch) {
   1.294 +    return;
   1.295 +  }
   1.296 +  uint32_t prefCount;
   1.297 +  char **prefNames;
   1.298 +  nsresult rv = prefRootBranch->GetChildList(kIntlHyphenationAliasPrefix,
   1.299 +                                             &prefCount, &prefNames);
   1.300 +  if (NS_SUCCEEDED(rv) && prefCount > 0) {
   1.301 +    for (uint32_t i = 0; i < prefCount; ++i) {
   1.302 +      nsAdoptingCString value = Preferences::GetCString(prefNames[i]);
   1.303 +      if (value) {
   1.304 +        nsAutoCString alias(prefNames[i]);
   1.305 +        alias.Cut(0, sizeof(kIntlHyphenationAliasPrefix) - 1);
   1.306 +        ToLowerCase(alias);
   1.307 +        ToLowerCase(value);
   1.308 +        nsCOMPtr<nsIAtom> aliasAtom = do_GetAtom(alias);
   1.309 +        nsCOMPtr<nsIAtom> valueAtom = do_GetAtom(value);
   1.310 +        mHyphAliases.Put(aliasAtom, valueAtom);
   1.311 +      }
   1.312 +    }
   1.313 +    NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, prefNames);
   1.314 +  }
   1.315 +}

mercurial