1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Corporation code.
16 : *
17 : * The Initial Developer of the Original Code is Mozilla Foundation.
18 : * Portions created by the Initial Developer are Copyright (C) 2006-2009
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Jonathan Kew <jfkthame@gmail.com>
23 : * John Daggett <jdaggett@mozilla.com>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * Based in part on sample code provided by Apple Computer, Inc.,
38 : * under the following license:
39 : *
40 : * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
41 : *
42 : * Redistribution and use in source and binary forms, with or without
43 : * modification, are permitted provided that the following conditions
44 : * are met:
45 : *
46 : * 1. Redistributions of source code must retain the above copyright
47 : * notice, this list of conditions and the following disclaimer.
48 : * 2. Redistributions in binary form must reproduce the above copyright
49 : * notice, this list of conditions and the following disclaimer in the
50 : * documentation and/or other materials provided with the distribution.
51 : * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
52 : * its contributors may be used to endorse or promote products derived
53 : * from this software without specific prior written permission.
54 : *
55 : * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
56 : * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
57 : * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
58 : * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
59 : * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
60 : * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
61 : * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
62 : * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
63 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
64 : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
65 : *
66 : * ***** END LICENSE BLOCK ***** */
67 :
68 : #ifdef MOZ_LOGGING
69 : #define FORCE_PR_LOG /* Allow logging in the release build */
70 : #endif
71 : #include "prlog.h"
72 :
73 : #include "gfxPlatformFontList.h"
74 :
75 : #include "nsUnicharUtils.h"
76 : #include "nsUnicodeRange.h"
77 : #include "nsUnicodeProperties.h"
78 :
79 : #include "mozilla/Preferences.h"
80 : #include "mozilla/Telemetry.h"
81 : #include "mozilla/TimeStamp.h"
82 :
83 : using namespace mozilla;
84 :
85 : // font info loader constants
86 : static const PRUint32 kDelayBeforeLoadingCmaps = 8 * 1000; // 8secs
87 : static const PRUint32 kIntervalBetweenLoadingCmaps = 150; // 150ms
88 : static const PRUint32 kNumFontsPerSlice = 10; // read in info 10 fonts at a time
89 :
90 : #ifdef PR_LOGGING
91 :
92 : #define LOG_FONTLIST(args) PR_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \
93 : PR_LOG_DEBUG, args)
94 : #define LOG_FONTLIST_ENABLED() PR_LOG_TEST( \
95 : gfxPlatform::GetLog(eGfxLog_fontlist), \
96 : PR_LOG_DEBUG)
97 :
98 : #endif // PR_LOGGING
99 :
100 : gfxPlatformFontList *gfxPlatformFontList::sPlatformFontList = nsnull;
101 :
102 :
103 : static const char* kObservedPrefs[] = {
104 : "font.",
105 : "font.name-list.",
106 : "intl.accept_languages", // hmmmm...
107 : nsnull
108 : };
109 :
110 0 : class gfxFontListPrefObserver : public nsIObserver {
111 : public:
112 : NS_DECL_ISUPPORTS
113 : NS_DECL_NSIOBSERVER
114 : };
115 :
116 : static gfxFontListPrefObserver* gFontListPrefObserver = nsnull;
117 :
118 0 : NS_IMPL_ISUPPORTS1(gfxFontListPrefObserver, nsIObserver)
119 :
120 : NS_IMETHODIMP
121 0 : gfxFontListPrefObserver::Observe(nsISupports *aSubject,
122 : const char *aTopic,
123 : const PRUnichar *aData)
124 : {
125 0 : NS_ASSERTION(!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID), "invalid topic");
126 : // XXX this could be made to only clear out the cache for the prefs that were changed
127 : // but it probably isn't that big a deal.
128 0 : gfxPlatformFontList::PlatformFontList()->ClearPrefFonts();
129 0 : gfxFontCache::GetCache()->AgeAllGenerations();
130 0 : return NS_OK;
131 : }
132 :
133 :
134 0 : gfxPlatformFontList::gfxPlatformFontList(bool aNeedFullnamePostscriptNames)
135 : : mNeedFullnamePostscriptNames(aNeedFullnamePostscriptNames),
136 0 : mStartIndex(0), mIncrement(kNumFontsPerSlice), mNumFamilies(0)
137 : {
138 0 : mFontFamilies.Init(100);
139 0 : mOtherFamilyNames.Init(30);
140 0 : mOtherFamilyNamesInitialized = false;
141 :
142 0 : if (mNeedFullnamePostscriptNames) {
143 0 : mFullnames.Init(100);
144 0 : mPostscriptNames.Init(100);
145 : }
146 0 : mFaceNamesInitialized = false;
147 :
148 0 : mPrefFonts.Init(10);
149 :
150 0 : mBadUnderlineFamilyNames.Init(10);
151 0 : LoadBadUnderlineList();
152 :
153 : // pref changes notification setup
154 0 : NS_ASSERTION(!gFontListPrefObserver,
155 : "There has been font list pref observer already");
156 0 : gFontListPrefObserver = new gfxFontListPrefObserver();
157 0 : NS_ADDREF(gFontListPrefObserver);
158 0 : Preferences::AddStrongObservers(gFontListPrefObserver, kObservedPrefs);
159 0 : }
160 :
161 0 : gfxPlatformFontList::~gfxPlatformFontList()
162 : {
163 0 : NS_ASSERTION(gFontListPrefObserver, "There is no font list pref observer");
164 0 : Preferences::RemoveObservers(gFontListPrefObserver, kObservedPrefs);
165 0 : NS_RELEASE(gFontListPrefObserver);
166 0 : }
167 :
168 : nsresult
169 0 : gfxPlatformFontList::InitFontList()
170 : {
171 0 : mFontFamilies.Clear();
172 0 : mOtherFamilyNames.Clear();
173 0 : mOtherFamilyNamesInitialized = false;
174 0 : if (mNeedFullnamePostscriptNames) {
175 0 : mFullnames.Clear();
176 0 : mPostscriptNames.Clear();
177 : }
178 0 : mFaceNamesInitialized = false;
179 0 : mPrefFonts.Clear();
180 0 : CancelLoader();
181 :
182 : // initialize ranges of characters for which system-wide font search should be skipped
183 0 : mCodepointsWithNoFonts.reset();
184 0 : mCodepointsWithNoFonts.SetRange(0,0x1f); // C0 controls
185 0 : mCodepointsWithNoFonts.SetRange(0x7f,0x9f); // C1 controls
186 :
187 0 : sPlatformFontList = this;
188 :
189 0 : return NS_OK;
190 : }
191 :
192 : void
193 0 : gfxPlatformFontList::GenerateFontListKey(const nsAString& aKeyName, nsAString& aResult)
194 : {
195 0 : aResult = aKeyName;
196 0 : ToLowerCase(aResult);
197 0 : }
198 :
199 : void
200 0 : gfxPlatformFontList::InitOtherFamilyNames()
201 : {
202 0 : mOtherFamilyNamesInitialized = true;
203 :
204 0 : Telemetry::AutoTimer<Telemetry::FONTLIST_INITOTHERFAMILYNAMES> timer;
205 : // iterate over all font families and read in other family names
206 0 : mFontFamilies.Enumerate(gfxPlatformFontList::InitOtherFamilyNamesProc, this);
207 0 : }
208 :
209 : PLDHashOperator PR_CALLBACK
210 0 : gfxPlatformFontList::InitOtherFamilyNamesProc(nsStringHashKey::KeyType aKey,
211 : nsRefPtr<gfxFontFamily>& aFamilyEntry,
212 : void* userArg)
213 : {
214 0 : gfxPlatformFontList *fc = static_cast<gfxPlatformFontList*>(userArg);
215 0 : aFamilyEntry->ReadOtherFamilyNames(fc);
216 0 : return PL_DHASH_NEXT;
217 : }
218 :
219 : void
220 0 : gfxPlatformFontList::InitFaceNameLists()
221 : {
222 0 : mFaceNamesInitialized = true;
223 :
224 : // iterate over all font families and read in other family names
225 0 : Telemetry::AutoTimer<Telemetry::FONTLIST_INITFACENAMELISTS> timer;
226 0 : mFontFamilies.Enumerate(gfxPlatformFontList::InitFaceNameListsProc, this);
227 0 : }
228 :
229 : PLDHashOperator PR_CALLBACK
230 0 : gfxPlatformFontList::InitFaceNameListsProc(nsStringHashKey::KeyType aKey,
231 : nsRefPtr<gfxFontFamily>& aFamilyEntry,
232 : void* userArg)
233 : {
234 0 : gfxPlatformFontList *fc = static_cast<gfxPlatformFontList*>(userArg);
235 0 : aFamilyEntry->ReadFaceNames(fc, fc->NeedFullnamePostscriptNames());
236 0 : return PL_DHASH_NEXT;
237 : }
238 :
239 : void
240 0 : gfxPlatformFontList::PreloadNamesList()
241 : {
242 0 : nsAutoTArray<nsString, 10> preloadFonts;
243 0 : gfxFontUtils::GetPrefsFontList("font.preload-names-list", preloadFonts);
244 :
245 0 : PRUint32 numFonts = preloadFonts.Length();
246 0 : for (PRUint32 i = 0; i < numFonts; i++) {
247 : bool found;
248 0 : nsAutoString key;
249 0 : GenerateFontListKey(preloadFonts[i], key);
250 :
251 : // only search canonical names!
252 0 : gfxFontFamily *familyEntry = mFontFamilies.GetWeak(key, &found);
253 0 : if (familyEntry) {
254 0 : familyEntry->ReadOtherFamilyNames(this);
255 : }
256 : }
257 :
258 0 : }
259 :
260 : void
261 0 : gfxPlatformFontList::SetFixedPitch(const nsAString& aFamilyName)
262 : {
263 0 : gfxFontFamily *family = FindFamily(aFamilyName);
264 0 : if (!family) return;
265 :
266 0 : family->FindStyleVariations();
267 0 : nsTArray<nsRefPtr<gfxFontEntry> >& fontlist = family->GetFontList();
268 :
269 0 : PRUint32 i, numFonts = fontlist.Length();
270 :
271 0 : for (i = 0; i < numFonts; i++) {
272 0 : fontlist[i]->mFixedPitch = 1;
273 : }
274 : }
275 :
276 : void
277 0 : gfxPlatformFontList::LoadBadUnderlineList()
278 : {
279 0 : nsAutoTArray<nsString, 10> blacklist;
280 0 : gfxFontUtils::GetPrefsFontList("font.blacklist.underline_offset", blacklist);
281 0 : PRUint32 numFonts = blacklist.Length();
282 0 : for (PRUint32 i = 0; i < numFonts; i++) {
283 0 : nsAutoString key;
284 0 : GenerateFontListKey(blacklist[i], key);
285 0 : mBadUnderlineFamilyNames.PutEntry(key);
286 : }
287 0 : }
288 :
289 : bool
290 0 : gfxPlatformFontList::ResolveFontName(const nsAString& aFontName, nsAString& aResolvedFontName)
291 : {
292 0 : gfxFontFamily *family = FindFamily(aFontName);
293 0 : if (family) {
294 0 : aResolvedFontName = family->Name();
295 0 : return true;
296 : }
297 0 : return false;
298 : }
299 :
300 : struct FontListData {
301 0 : FontListData(nsIAtom *aLangGroup,
302 : const nsACString& aGenericFamily,
303 : nsTArray<nsString>& aListOfFonts) :
304 : mLangGroup(aLangGroup), mGenericFamily(aGenericFamily),
305 0 : mListOfFonts(aListOfFonts) {}
306 : nsIAtom *mLangGroup;
307 : const nsACString& mGenericFamily;
308 : nsTArray<nsString>& mListOfFonts;
309 : };
310 :
311 : PLDHashOperator PR_CALLBACK
312 0 : gfxPlatformFontList::HashEnumFuncForFamilies(nsStringHashKey::KeyType aKey,
313 : nsRefPtr<gfxFontFamily>& aFamilyEntry,
314 : void *aUserArg)
315 : {
316 0 : FontListData *data = static_cast<FontListData*>(aUserArg);
317 :
318 : // use the first variation for now. This data should be the same
319 : // for all the variations and should probably be moved up to
320 : // the Family
321 0 : gfxFontStyle style;
322 0 : style.language = data->mLangGroup;
323 : bool needsBold;
324 0 : nsRefPtr<gfxFontEntry> aFontEntry = aFamilyEntry->FindFontForStyle(style, needsBold);
325 0 : NS_ASSERTION(aFontEntry, "couldn't find any font entry in family");
326 0 : if (!aFontEntry)
327 0 : return PL_DHASH_NEXT;
328 :
329 : /* skip symbol fonts */
330 0 : if (aFontEntry->IsSymbolFont())
331 0 : return PL_DHASH_NEXT;
332 :
333 0 : if (aFontEntry->SupportsLangGroup(data->mLangGroup) &&
334 0 : aFontEntry->MatchesGenericFamily(data->mGenericFamily)) {
335 0 : nsAutoString localizedFamilyName;
336 0 : aFamilyEntry->LocalizedName(localizedFamilyName);
337 0 : data->mListOfFonts.AppendElement(localizedFamilyName);
338 : }
339 :
340 0 : return PL_DHASH_NEXT;
341 : }
342 :
343 : void
344 0 : gfxPlatformFontList::GetFontList(nsIAtom *aLangGroup,
345 : const nsACString& aGenericFamily,
346 : nsTArray<nsString>& aListOfFonts)
347 : {
348 0 : FontListData data(aLangGroup, aGenericFamily, aListOfFonts);
349 :
350 0 : mFontFamilies.Enumerate(gfxPlatformFontList::HashEnumFuncForFamilies, &data);
351 :
352 0 : aListOfFonts.Sort();
353 0 : aListOfFonts.Compact();
354 0 : }
355 :
356 : struct FontFamilyListData {
357 0 : FontFamilyListData(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray)
358 0 : : mFamilyArray(aFamilyArray)
359 0 : {}
360 :
361 0 : static PLDHashOperator PR_CALLBACK AppendFamily(nsStringHashKey::KeyType aKey,
362 : nsRefPtr<gfxFontFamily>& aFamilyEntry,
363 : void *aUserArg)
364 : {
365 0 : FontFamilyListData *data = static_cast<FontFamilyListData*>(aUserArg);
366 0 : data->mFamilyArray.AppendElement(aFamilyEntry);
367 0 : return PL_DHASH_NEXT;
368 : }
369 :
370 : nsTArray<nsRefPtr<gfxFontFamily> >& mFamilyArray;
371 : };
372 :
373 : void
374 0 : gfxPlatformFontList::GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray)
375 : {
376 0 : FontFamilyListData data(aFamilyArray);
377 0 : mFontFamilies.Enumerate(FontFamilyListData::AppendFamily, &data);
378 0 : }
379 :
380 : gfxFontEntry*
381 0 : gfxPlatformFontList::SystemFindFontForChar(const PRUint32 aCh,
382 : PRInt32 aRunScript,
383 : const gfxFontStyle* aStyle)
384 : {
385 0 : gfxFontEntry* fontEntry = nsnull;
386 :
387 : // is codepoint with no matching font? return null immediately
388 0 : if (mCodepointsWithNoFonts.test(aCh)) {
389 0 : return nsnull;
390 : }
391 :
392 : // try to short-circuit font fallback for U+FFFD, used to represent
393 : // encoding errors: just use a platform-specific fallback system
394 : // font that is guaranteed (or at least highly likely) to be around,
395 : // or a cached family from last time U+FFFD was seen. this helps
396 : // speed up pages with lots of encoding errors, binary-as-text, etc.
397 0 : if (aCh == 0xFFFD && mReplacementCharFallbackFamily.Length() > 0) {
398 : bool needsBold; // ignored in the system fallback case
399 :
400 : fontEntry = FindFontForFamily(mReplacementCharFallbackFamily,
401 0 : aStyle, needsBold);
402 :
403 0 : if (fontEntry && fontEntry->TestCharacterMap(aCh))
404 0 : return fontEntry;
405 : }
406 :
407 0 : TimeStamp start = TimeStamp::Now();
408 :
409 : // search commonly available fonts
410 0 : bool common = true;
411 0 : fontEntry = CommonFontFallback(aCh, aRunScript, aStyle);
412 :
413 : // if didn't find a font, do system-wide fallback (except for specials)
414 0 : PRUint32 cmapCount = 0;
415 0 : if (!fontEntry) {
416 0 : common = false;
417 0 : fontEntry = GlobalFontFallback(aCh, aRunScript, aStyle, cmapCount);
418 : }
419 0 : TimeDuration elapsed = TimeStamp::Now() - start;
420 :
421 : #ifdef PR_LOGGING
422 0 : PRLogModuleInfo *log = gfxPlatform::GetLog(eGfxLog_textrun);
423 :
424 0 : if (NS_UNLIKELY(log)) {
425 0 : PRUint32 charRange = gfxFontUtils::CharRangeBit(aCh);
426 0 : PRUint32 unicodeRange = FindCharUnicodeRange(aCh);
427 0 : PRInt32 script = mozilla::unicode::GetScriptCode(aCh);
428 0 : PR_LOG(log, PR_LOG_WARNING,\
429 : ("(textrun-systemfallback-%s) char: u+%6.6x "
430 : "char-range: %d unicode-range: %d script: %d match: [%s]"
431 : " time: %dus cmaps: %d\n",
432 : (common ? "common" : "global"), aCh,
433 : charRange, unicodeRange, script,
434 : (fontEntry ? NS_ConvertUTF16toUTF8(fontEntry->Name()).get() :
435 : "<none>"),
436 : PRInt32(elapsed.ToMicroseconds()),
437 : cmapCount));
438 : }
439 : #endif
440 :
441 : // no match? add to set of non-matching codepoints
442 0 : if (!fontEntry) {
443 0 : mCodepointsWithNoFonts.set(aCh);
444 0 : } else if (aCh == 0xFFFD && fontEntry) {
445 0 : mReplacementCharFallbackFamily = fontEntry->FamilyName();
446 : }
447 :
448 : // track system fallback time
449 : static bool first = true;
450 0 : PRInt32 intElapsed = PRInt32(first ? elapsed.ToMilliseconds() :
451 0 : elapsed.ToMicroseconds());
452 : Telemetry::Accumulate((first ? Telemetry::SYSTEM_FONT_FALLBACK_FIRST :
453 : Telemetry::SYSTEM_FONT_FALLBACK),
454 0 : intElapsed);
455 0 : first = false;
456 :
457 : // track the script for which fallback occurred (incremented one make it
458 : // 1-based)
459 0 : Telemetry::Accumulate(Telemetry::SYSTEM_FONT_FALLBACK_SCRIPT, aRunScript + 1);
460 :
461 0 : return fontEntry;
462 : }
463 :
464 : PLDHashOperator PR_CALLBACK
465 0 : gfxPlatformFontList::FindFontForCharProc(nsStringHashKey::KeyType aKey, nsRefPtr<gfxFontFamily>& aFamilyEntry,
466 : void *userArg)
467 : {
468 0 : GlobalFontMatch *data = static_cast<GlobalFontMatch*>(userArg);
469 :
470 : // evaluate all fonts in this family for a match
471 0 : aFamilyEntry->FindFontForChar(data);
472 :
473 0 : return PL_DHASH_NEXT;
474 : }
475 :
476 : #define NUM_FALLBACK_FONTS 8
477 :
478 : gfxFontEntry*
479 0 : gfxPlatformFontList::CommonFontFallback(const PRUint32 aCh,
480 : PRInt32 aRunScript,
481 : const gfxFontStyle* aMatchStyle)
482 : {
483 0 : nsAutoTArray<const char*,NUM_FALLBACK_FONTS> defaultFallbacks;
484 : PRUint32 i, numFallbacks;
485 :
486 0 : gfxPlatform::GetPlatform()->GetCommonFallbackFonts(aCh, aRunScript,
487 0 : defaultFallbacks);
488 0 : numFallbacks = defaultFallbacks.Length();
489 0 : for (i = 0; i < numFallbacks; i++) {
490 0 : nsAutoString familyName;
491 0 : const char *fallbackFamily = defaultFallbacks[i];
492 :
493 0 : familyName.AppendASCII(fallbackFamily);
494 : gfxFontFamily *fallback =
495 0 : gfxPlatformFontList::PlatformFontList()->FindFamily(familyName);
496 0 : if (!fallback)
497 0 : continue;
498 :
499 : gfxFontEntry *fontEntry;
500 : bool needsBold; // ignored in the system fallback case
501 :
502 : // use first font in list that supports a given character
503 0 : fontEntry = fallback->FindFontForStyle(*aMatchStyle, needsBold);
504 0 : if (fontEntry && fontEntry->TestCharacterMap(aCh)) {
505 0 : return fontEntry;
506 : }
507 : }
508 :
509 0 : return nsnull;
510 : }
511 :
512 : gfxFontEntry*
513 0 : gfxPlatformFontList::GlobalFontFallback(const PRUint32 aCh,
514 : PRInt32 aRunScript,
515 : const gfxFontStyle* aMatchStyle,
516 : PRUint32& aCmapCount)
517 : {
518 : // otherwise, try to find it among local fonts
519 0 : GlobalFontMatch data(aCh, aRunScript, aMatchStyle);
520 :
521 : // iterate over all font families to find a font that support the character
522 0 : mFontFamilies.Enumerate(gfxPlatformFontList::FindFontForCharProc, &data);
523 :
524 0 : aCmapCount = data.mCmapsTested;
525 :
526 0 : return data.mBestMatch;
527 : }
528 :
529 : #ifdef XP_WIN
530 : #include <windows.h>
531 :
532 : // crude hack for using when monitoring process
533 : static void LogRegistryEvent(const wchar_t *msg)
534 : {
535 : HKEY dummyKey;
536 : HRESULT hr;
537 : wchar_t buf[512];
538 :
539 : wsprintfW(buf, L" log %s", msg);
540 : hr = RegOpenKeyExW(HKEY_LOCAL_MACHINE, buf, 0, KEY_READ, &dummyKey);
541 : if (SUCCEEDED(hr)) {
542 : RegCloseKey(dummyKey);
543 : }
544 : }
545 : #endif
546 :
547 : gfxFontFamily*
548 0 : gfxPlatformFontList::FindFamily(const nsAString& aFamily)
549 : {
550 0 : nsAutoString key;
551 : gfxFontFamily *familyEntry;
552 : bool found;
553 0 : GenerateFontListKey(aFamily, key);
554 :
555 0 : NS_ASSERTION(mFontFamilies.Count() != 0, "system font list was not initialized correctly");
556 :
557 : // lookup in canonical (i.e. English) family name list
558 0 : if ((familyEntry = mFontFamilies.GetWeak(key, &found))) {
559 0 : return familyEntry;
560 : }
561 :
562 : // lookup in other family names list (mostly localized names)
563 0 : if ((familyEntry = mOtherFamilyNames.GetWeak(key, &found)) != nsnull) {
564 0 : return familyEntry;
565 : }
566 :
567 : // name not found and other family names not yet fully initialized so
568 : // initialize the rest of the list and try again. this is done lazily
569 : // since reading name table entries is expensive.
570 : // although ASCII localized family names are possible they don't occur
571 : // in practice so avoid pulling in names at startup
572 0 : if (!mOtherFamilyNamesInitialized && !IsASCII(aFamily)) {
573 0 : InitOtherFamilyNames();
574 0 : if ((familyEntry = mOtherFamilyNames.GetWeak(key, &found)) != nsnull) {
575 0 : return familyEntry;
576 : }
577 : }
578 :
579 0 : return nsnull;
580 : }
581 :
582 : gfxFontEntry*
583 0 : gfxPlatformFontList::FindFontForFamily(const nsAString& aFamily, const gfxFontStyle* aStyle, bool& aNeedsBold)
584 : {
585 0 : gfxFontFamily *familyEntry = FindFamily(aFamily);
586 :
587 0 : aNeedsBold = false;
588 :
589 0 : if (familyEntry)
590 0 : return familyEntry->FindFontForStyle(*aStyle, aNeedsBold);
591 :
592 0 : return nsnull;
593 : }
594 :
595 : bool
596 0 : gfxPlatformFontList::GetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<gfxFontFamily> > *array)
597 : {
598 0 : return mPrefFonts.Get(PRUint32(aLangGroup), array);
599 : }
600 :
601 : void
602 0 : gfxPlatformFontList::SetPrefFontFamilyEntries(eFontPrefLang aLangGroup, nsTArray<nsRefPtr<gfxFontFamily> >& array)
603 : {
604 0 : mPrefFonts.Put(PRUint32(aLangGroup), array);
605 0 : }
606 :
607 : void
608 0 : gfxPlatformFontList::AddOtherFamilyName(gfxFontFamily *aFamilyEntry, nsAString& aOtherFamilyName)
609 : {
610 0 : nsAutoString key;
611 : bool found;
612 0 : GenerateFontListKey(aOtherFamilyName, key);
613 :
614 0 : if (!mOtherFamilyNames.GetWeak(key, &found)) {
615 0 : mOtherFamilyNames.Put(key, aFamilyEntry);
616 : #ifdef PR_LOGGING
617 0 : LOG_FONTLIST(("(fontlist-otherfamily) canonical family: %s, "
618 : "other family: %s\n",
619 : NS_ConvertUTF16toUTF8(aFamilyEntry->Name()).get(),
620 : NS_ConvertUTF16toUTF8(aOtherFamilyName).get()));
621 : #endif
622 0 : if (mBadUnderlineFamilyNames.Contains(key))
623 0 : aFamilyEntry->SetBadUnderlineFamily();
624 : }
625 0 : }
626 :
627 : void
628 0 : gfxPlatformFontList::AddFullname(gfxFontEntry *aFontEntry, nsAString& aFullname)
629 : {
630 : bool found;
631 :
632 0 : if (!mFullnames.GetWeak(aFullname, &found)) {
633 0 : mFullnames.Put(aFullname, aFontEntry);
634 : #ifdef PR_LOGGING
635 0 : LOG_FONTLIST(("(fontlist-fullname) name: %s, fullname: %s\n",
636 : NS_ConvertUTF16toUTF8(aFontEntry->Name()).get(),
637 : NS_ConvertUTF16toUTF8(aFullname).get()));
638 : #endif
639 : }
640 0 : }
641 :
642 : void
643 0 : gfxPlatformFontList::AddPostscriptName(gfxFontEntry *aFontEntry, nsAString& aPostscriptName)
644 : {
645 : bool found;
646 :
647 0 : if (!mPostscriptNames.GetWeak(aPostscriptName, &found)) {
648 0 : mPostscriptNames.Put(aPostscriptName, aFontEntry);
649 : #ifdef PR_LOGGING
650 0 : LOG_FONTLIST(("(fontlist-postscript) name: %s, psname: %s\n",
651 : NS_ConvertUTF16toUTF8(aFontEntry->Name()).get(),
652 : NS_ConvertUTF16toUTF8(aPostscriptName).get()));
653 : #endif
654 : }
655 0 : }
656 :
657 : bool
658 0 : gfxPlatformFontList::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
659 : {
660 0 : aFamilyName.Truncate();
661 0 : ResolveFontName(aFontName, aFamilyName);
662 0 : return !aFamilyName.IsEmpty();
663 : }
664 :
665 : void
666 0 : gfxPlatformFontList::InitLoader()
667 : {
668 0 : GetFontFamilyList(mFontFamiliesToLoad);
669 0 : mStartIndex = 0;
670 0 : mNumFamilies = mFontFamiliesToLoad.Length();
671 0 : }
672 :
673 : bool
674 0 : gfxPlatformFontList::RunLoader()
675 : {
676 0 : PRUint32 i, endIndex = (mStartIndex + mIncrement < mNumFamilies ? mStartIndex + mIncrement : mNumFamilies);
677 0 : bool loadCmaps = !UsesSystemFallback() ||
678 0 : gfxPlatform::GetPlatform()->UseCmapsDuringSystemFallback();
679 :
680 : // for each font family, load in various font info
681 0 : for (i = mStartIndex; i < endIndex; i++) {
682 0 : gfxFontFamily* familyEntry = mFontFamiliesToLoad[i];
683 :
684 : // find all faces that are members of this family
685 0 : familyEntry->FindStyleVariations();
686 0 : if (familyEntry->GetFontList().Length() == 0) {
687 : // failed to load any faces for this family, so discard it
688 0 : nsAutoString key;
689 0 : GenerateFontListKey(familyEntry->Name(), key);
690 0 : mFontFamilies.Remove(key);
691 0 : continue;
692 : }
693 :
694 : // load the cmaps if needed
695 0 : if (loadCmaps) {
696 0 : familyEntry->ReadAllCMAPs();
697 : }
698 :
699 : // read in face names
700 0 : familyEntry->ReadFaceNames(this, mNeedFullnamePostscriptNames);
701 :
702 : // check whether the family can be considered "simple" for style matching
703 0 : familyEntry->CheckForSimpleFamily();
704 : }
705 :
706 0 : mStartIndex = endIndex;
707 :
708 0 : return (mStartIndex >= mNumFamilies);
709 : }
710 :
711 : void
712 0 : gfxPlatformFontList::FinishLoader()
713 : {
714 0 : mFontFamiliesToLoad.Clear();
715 0 : mNumFamilies = 0;
716 0 : }
|