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

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

mercurial