intl/hyphenation/src/nsHyphenationManager.cpp

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:d0dd9810528c
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 "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"
22
23 using namespace mozilla;
24
25 static const char kIntlHyphenationAliasPrefix[] = "intl.hyphenation-alias.";
26 static const char kMemoryPressureNotification[] = "memory-pressure";
27
28 nsHyphenationManager *nsHyphenationManager::sInstance = nullptr;
29
30 NS_IMPL_ISUPPORTS(nsHyphenationManager::MemoryPressureObserver,
31 nsIObserver)
32
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 }
49
50 nsHyphenationManager*
51 nsHyphenationManager::Instance()
52 {
53 if (sInstance == nullptr) {
54 sInstance = new nsHyphenationManager();
55
56 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
57 if (obs) {
58 obs->AddObserver(new MemoryPressureObserver,
59 kMemoryPressureNotification, false);
60 }
61 }
62 return sInstance;
63 }
64
65 void
66 nsHyphenationManager::Shutdown()
67 {
68 delete sInstance;
69 sInstance = nullptr;
70 }
71
72 nsHyphenationManager::nsHyphenationManager()
73 {
74 LoadPatternList();
75 LoadAliases();
76 }
77
78 nsHyphenationManager::~nsHyphenationManager()
79 {
80 sInstance = nullptr;
81 }
82
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 }
136
137 void
138 nsHyphenationManager::LoadPatternList()
139 {
140 mPatternFiles.Clear();
141 mHyphenators.Clear();
142
143 LoadPatternListFromOmnijar(Omnijar::GRE);
144 LoadPatternListFromOmnijar(Omnijar::APP);
145
146 nsCOMPtr<nsIProperties> dirSvc =
147 do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
148 if (!dirSvc) {
149 return;
150 }
151
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 }
160
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 }
172
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 }
181
182 nsRefPtr<nsZipArchive> zip = Omnijar::GetReader(aType);
183 if (!zip) {
184 return;
185 }
186
187 nsZipFind *find;
188 zip->FindInit("hyphenation/hyph_*.dic", &find);
189 if (!find) {
190 return;
191 }
192
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 }
224
225 delete find;
226 }
227
228 void
229 nsHyphenationManager::LoadPatternListFromDir(nsIFile *aDir)
230 {
231 nsresult rv;
232
233 bool check = false;
234 rv = aDir->Exists(&check);
235 if (NS_FAILED(rv) || !check) {
236 return;
237 }
238
239 rv = aDir->IsDirectory(&check);
240 if (NS_FAILED(rv) || !check) {
241 return;
242 }
243
244 nsCOMPtr<nsISimpleEnumerator> e;
245 rv = aDir->GetDirectoryEntries(getter_AddRefs(e));
246 if (NS_FAILED(rv)) {
247 return;
248 }
249
250 nsCOMPtr<nsIDirectoryEnumerator> files(do_QueryInterface(e));
251 if (!files) {
252 return;
253 }
254
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 }
285
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