intl/hyphenation/src/nsHyphenationManager.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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/. */
     6 #include "nsHyphenationManager.h"
     7 #include "nsHyphenator.h"
     8 #include "nsIAtom.h"
     9 #include "nsIFile.h"
    10 #include "nsIURI.h"
    11 #include "nsIProperties.h"
    12 #include "nsISimpleEnumerator.h"
    13 #include "nsIDirectoryEnumerator.h"
    14 #include "nsDirectoryServiceDefs.h"
    15 #include "nsNetUtil.h"
    16 #include "nsUnicharUtils.h"
    17 #include "mozilla/Preferences.h"
    18 #include "nsZipArchive.h"
    19 #include "mozilla/Services.h"
    20 #include "nsIObserverService.h"
    21 #include "nsCRT.h"
    23 using namespace mozilla;
    25 static const char kIntlHyphenationAliasPrefix[] = "intl.hyphenation-alias.";
    26 static const char kMemoryPressureNotification[] = "memory-pressure";
    28 nsHyphenationManager *nsHyphenationManager::sInstance = nullptr;
    30 NS_IMPL_ISUPPORTS(nsHyphenationManager::MemoryPressureObserver,
    31                   nsIObserver)
    33 NS_IMETHODIMP
    34 nsHyphenationManager::MemoryPressureObserver::Observe(nsISupports *aSubject,
    35                                                       const char *aTopic,
    36                                                       const char16_t *aData)
    37 {
    38   if (!nsCRT::strcmp(aTopic, kMemoryPressureNotification)) {
    39     // We don't call Instance() here, as we don't want to create a hyphenation
    40     // manager if there isn't already one in existence.
    41     // (This observer class is local to the hyphenation manager, so it can use
    42     // the protected members directly.)
    43     if (nsHyphenationManager::sInstance) {
    44       nsHyphenationManager::sInstance->mHyphenators.Clear();
    45     }
    46   }
    47   return NS_OK;
    48 }
    50 nsHyphenationManager*
    51 nsHyphenationManager::Instance()
    52 {
    53   if (sInstance == nullptr) {
    54     sInstance = new nsHyphenationManager();
    56     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
    57     if (obs) {
    58         obs->AddObserver(new MemoryPressureObserver,
    59                          kMemoryPressureNotification, false);
    60     }
    61   }
    62   return sInstance;
    63 }
    65 void
    66 nsHyphenationManager::Shutdown()
    67 {
    68   delete sInstance;
    69   sInstance = nullptr;
    70 }
    72 nsHyphenationManager::nsHyphenationManager()
    73 {
    74   LoadPatternList();
    75   LoadAliases();
    76 }
    78 nsHyphenationManager::~nsHyphenationManager()
    79 {
    80   sInstance = nullptr;
    81 }
    83 already_AddRefed<nsHyphenator>
    84 nsHyphenationManager::GetHyphenator(nsIAtom *aLocale)
    85 {
    86   nsRefPtr<nsHyphenator> hyph;
    87   mHyphenators.Get(aLocale, getter_AddRefs(hyph));
    88   if (hyph) {
    89     return hyph.forget();
    90   }
    91   nsCOMPtr<nsIURI> uri = mPatternFiles.Get(aLocale);
    92   if (!uri) {
    93     nsCOMPtr<nsIAtom> alias = mHyphAliases.Get(aLocale);
    94     if (alias) {
    95       mHyphenators.Get(alias, getter_AddRefs(hyph));
    96       if (hyph) {
    97         return hyph.forget();
    98       }
    99       uri = mPatternFiles.Get(alias);
   100       if (uri) {
   101         aLocale = alias;
   102       }
   103     }
   104     if (!uri) {
   105       // In the case of a locale such as "de-DE-1996", we try replacing
   106       // successive trailing subtags with "-*" to find fallback patterns,
   107       // so "de-DE-1996" -> "de-DE-*" (and then recursively -> "de-*")
   108       nsAtomCString localeStr(aLocale);
   109       if (StringEndsWith(localeStr, NS_LITERAL_CSTRING("-*"))) {
   110         localeStr.Truncate(localeStr.Length() - 2);
   111       }
   112       int32_t i = localeStr.RFindChar('-');
   113       if (i > 1) {
   114         localeStr.Replace(i, localeStr.Length() - i, "-*");
   115         nsCOMPtr<nsIAtom> fuzzyLocale = do_GetAtom(localeStr);
   116         return GetHyphenator(fuzzyLocale);
   117       } else {
   118         return nullptr;
   119       }
   120     }
   121   }
   122   hyph = new nsHyphenator(uri);
   123   if (hyph->IsValid()) {
   124     mHyphenators.Put(aLocale, hyph);
   125     return hyph.forget();
   126   }
   127 #ifdef DEBUG
   128   nsCString msg;
   129   uri->GetSpec(msg);
   130   msg.Insert("failed to load patterns from ", 0);
   131   NS_WARNING(msg.get());
   132 #endif
   133   mPatternFiles.Remove(aLocale);
   134   return nullptr;
   135 }
   137 void
   138 nsHyphenationManager::LoadPatternList()
   139 {
   140   mPatternFiles.Clear();
   141   mHyphenators.Clear();
   143   LoadPatternListFromOmnijar(Omnijar::GRE);
   144   LoadPatternListFromOmnijar(Omnijar::APP);
   146   nsCOMPtr<nsIProperties> dirSvc =
   147     do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
   148   if (!dirSvc) {
   149     return;
   150   }
   152   nsresult rv;
   153   nsCOMPtr<nsIFile> greDir;
   154   rv = dirSvc->Get(NS_GRE_DIR,
   155                    NS_GET_IID(nsIFile), getter_AddRefs(greDir));
   156   if (NS_SUCCEEDED(rv)) {
   157     greDir->AppendNative(NS_LITERAL_CSTRING("hyphenation"));
   158     LoadPatternListFromDir(greDir);
   159   }
   161   nsCOMPtr<nsIFile> appDir;
   162   rv = dirSvc->Get(NS_XPCOM_CURRENT_PROCESS_DIR,
   163                    NS_GET_IID(nsIFile), getter_AddRefs(appDir));
   164   if (NS_SUCCEEDED(rv)) {
   165     appDir->AppendNative(NS_LITERAL_CSTRING("hyphenation"));
   166     bool equals;
   167     if (NS_SUCCEEDED(appDir->Equals(greDir, &equals)) && !equals) {
   168       LoadPatternListFromDir(appDir);
   169     }
   170   }
   171 }
   173 void
   174 nsHyphenationManager::LoadPatternListFromOmnijar(Omnijar::Type aType)
   175 {
   176   nsCString base;
   177   nsresult rv = Omnijar::GetURIString(aType, base);
   178   if (NS_FAILED(rv)) {
   179     return;
   180   }
   182   nsRefPtr<nsZipArchive> zip = Omnijar::GetReader(aType);
   183   if (!zip) {
   184     return;
   185   }
   187   nsZipFind *find;
   188   zip->FindInit("hyphenation/hyph_*.dic", &find);
   189   if (!find) {
   190     return;
   191   }
   193   const char *result;
   194   uint16_t len;
   195   while (NS_SUCCEEDED(find->FindNext(&result, &len))) {
   196     nsCString uriString(base);
   197     uriString.Append(result, len);
   198     nsCOMPtr<nsIURI> uri;
   199     rv = NS_NewURI(getter_AddRefs(uri), uriString);
   200     if (NS_FAILED(rv)) {
   201       continue;
   202     }
   203     nsCString locale;
   204     rv = uri->GetPath(locale);
   205     if (NS_FAILED(rv)) {
   206       continue;
   207     }
   208     ToLowerCase(locale);
   209     locale.SetLength(locale.Length() - 4); // strip ".dic"
   210     locale.Cut(0, locale.RFindChar('/') + 1); // strip directory
   211     if (StringBeginsWith(locale, NS_LITERAL_CSTRING("hyph_"))) {
   212       locale.Cut(0, 5);
   213     }
   214     for (uint32_t i = 0; i < locale.Length(); ++i) {
   215       if (locale[i] == '_') {
   216         locale.Replace(i, 1, '-');
   217       }
   218     }
   219     nsCOMPtr<nsIAtom> localeAtom = do_GetAtom(locale);
   220     if (NS_SUCCEEDED(rv)) {
   221       mPatternFiles.Put(localeAtom, uri);
   222     }
   223   }
   225   delete find;
   226 }
   228 void
   229 nsHyphenationManager::LoadPatternListFromDir(nsIFile *aDir)
   230 {
   231   nsresult rv;
   233   bool check = false;
   234   rv = aDir->Exists(&check);
   235   if (NS_FAILED(rv) || !check) {
   236     return;
   237   }
   239   rv = aDir->IsDirectory(&check);
   240   if (NS_FAILED(rv) || !check) {
   241     return;
   242   }
   244   nsCOMPtr<nsISimpleEnumerator> e;
   245   rv = aDir->GetDirectoryEntries(getter_AddRefs(e));
   246   if (NS_FAILED(rv)) {
   247     return;
   248   }
   250   nsCOMPtr<nsIDirectoryEnumerator> files(do_QueryInterface(e));
   251   if (!files) {
   252     return;
   253   }
   255   nsCOMPtr<nsIFile> file;
   256   while (NS_SUCCEEDED(files->GetNextFile(getter_AddRefs(file))) && file){
   257     nsAutoString dictName;
   258     file->GetLeafName(dictName);
   259     NS_ConvertUTF16toUTF8 locale(dictName);
   260     ToLowerCase(locale);
   261     if (!StringEndsWith(locale, NS_LITERAL_CSTRING(".dic"))) {
   262       continue;
   263     }
   264     if (StringBeginsWith(locale, NS_LITERAL_CSTRING("hyph_"))) {
   265       locale.Cut(0, 5);
   266     }
   267     locale.SetLength(locale.Length() - 4); // strip ".dic"
   268     for (uint32_t i = 0; i < locale.Length(); ++i) {
   269       if (locale[i] == '_') {
   270         locale.Replace(i, 1, '-');
   271       }
   272     }
   273 #ifdef DEBUG_hyph
   274     printf("adding hyphenation patterns for %s: %s\n", locale.get(),
   275            NS_ConvertUTF16toUTF8(dictName).get());
   276 #endif
   277     nsCOMPtr<nsIAtom> localeAtom = do_GetAtom(locale);
   278     nsCOMPtr<nsIURI> uri;
   279     nsresult rv = NS_NewFileURI(getter_AddRefs(uri), file);
   280     if (NS_SUCCEEDED(rv)) {
   281       mPatternFiles.Put(localeAtom, uri);
   282     }
   283   }
   284 }
   286 void
   287 nsHyphenationManager::LoadAliases()
   288 {
   289   nsIPrefBranch* prefRootBranch = Preferences::GetRootBranch();
   290   if (!prefRootBranch) {
   291     return;
   292   }
   293   uint32_t prefCount;
   294   char **prefNames;
   295   nsresult rv = prefRootBranch->GetChildList(kIntlHyphenationAliasPrefix,
   296                                              &prefCount, &prefNames);
   297   if (NS_SUCCEEDED(rv) && prefCount > 0) {
   298     for (uint32_t i = 0; i < prefCount; ++i) {
   299       nsAdoptingCString value = Preferences::GetCString(prefNames[i]);
   300       if (value) {
   301         nsAutoCString alias(prefNames[i]);
   302         alias.Cut(0, sizeof(kIntlHyphenationAliasPrefix) - 1);
   303         ToLowerCase(alias);
   304         ToLowerCase(value);
   305         nsCOMPtr<nsIAtom> aliasAtom = do_GetAtom(alias);
   306         nsCOMPtr<nsIAtom> valueAtom = do_GetAtom(value);
   307         mHyphAliases.Put(aliasAtom, valueAtom);
   308       }
   309     }
   310     NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(prefCount, prefNames);
   311   }
   312 }

mercurial