Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / gfx / thebes / src / gfxWindowsPlatform.cpp
blob07a9e0bcb98f535d20e4d3807e7e7595c940b525
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
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/
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.
15 * The Original Code is Mozilla Foundation code.
17 * The Initial Developer of the Original Code is Mozilla Foundation.
18 * Portions created by the Initial Developer are Copyright (C) 2005
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
22 * Stuart Parmenter <stuart@mozilla.com>
23 * Vladimir Vukicevic <vladimir@pobox.com>
24 * Masayuki Nakano <masayuki@d-toybox.com>
25 * Masatoshi Kimura <VYV03354@nifty.ne.jp>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
41 #include "gfxWindowsPlatform.h"
43 #include "gfxImageSurface.h"
44 #include "gfxWindowsSurface.h"
46 #include "nsUnicharUtils.h"
48 #include "nsIPref.h"
49 #include "nsServiceManagerUtils.h"
51 #include "nsIWindowsRegKey.h"
52 #include "nsILocalFile.h"
53 #include "plbase64.h"
55 #include "gfxWindowsFonts.h"
56 #include "gfxUserFontSet.h"
58 #include <string>
60 #include "lcms.h"
62 static void InitializeFontEmbeddingProcs();
64 // font info loader constants
65 static const PRUint32 kDelayBeforeLoadingCmaps = 8 * 1000; // 8secs
66 static const PRUint32 kIntervalBetweenLoadingCmaps = 150; // 150ms
67 static const PRUint32 kNumFontsPerSlice = 10; // read in info 10 fonts at a time
69 static __inline void
70 BuildKeyNameFromFontName(nsAString &aName)
72 if (aName.Length() >= LF_FACESIZE)
73 aName.Truncate(LF_FACESIZE - 1);
74 ToLowerCase(aName);
77 int
78 gfxWindowsPlatform::PrefChangedCallback(const char *aPrefName, void *closure)
80 // XXX this could be made to only clear out the cache for the prefs that were changed
81 // but it probably isn't that big a deal.
82 gfxWindowsPlatform *plat = static_cast<gfxWindowsPlatform *>(closure);
83 plat->mPrefFonts.Clear();
84 return 0;
87 gfxWindowsPlatform::gfxWindowsPlatform()
88 : mStartIndex(0), mIncrement(kNumFontsPerSlice), mNumFamilies(0)
90 mFonts.Init(200);
91 mFontAliases.Init(20);
92 mFontSubstitutes.Init(50);
93 mPrefFonts.Init(10);
95 UpdateFontList();
97 nsCOMPtr<nsIPref> pref = do_GetService(NS_PREF_CONTRACTID);
98 pref->RegisterCallback("font.", PrefChangedCallback, this);
99 pref->RegisterCallback("font.name-list.", PrefChangedCallback, this);
100 pref->RegisterCallback("intl.accept_languages", PrefChangedCallback, this);
101 // don't bother unregistering. We'll get shutdown after the pref service
103 InitializeFontEmbeddingProcs();
106 gfxWindowsPlatform::~gfxWindowsPlatform()
110 already_AddRefed<gfxASurface>
111 gfxWindowsPlatform::CreateOffscreenSurface(const gfxIntSize& size,
112 gfxASurface::gfxImageFormat imageFormat)
114 gfxASurface *surf = new gfxWindowsSurface(size, imageFormat);
115 NS_IF_ADDREF(surf);
116 return surf;
119 int CALLBACK
120 gfxWindowsPlatform::FontEnumProc(const ENUMLOGFONTEXW *lpelfe,
121 const NEWTEXTMETRICEXW *nmetrics,
122 DWORD fontType, LPARAM data)
124 FontTable *ht = reinterpret_cast<FontTable*>(data);
126 const NEWTEXTMETRICW& metrics = nmetrics->ntmTm;
127 const LOGFONTW& logFont = lpelfe->elfLogFont;
129 // Ignore vertical fonts
130 if (logFont.lfFaceName[0] == L'@')
131 return 1;
133 nsAutoString name(logFont.lfFaceName);
134 BuildKeyNameFromFontName(name);
136 nsRefPtr<FontFamily> ff;
137 if (!ht->Get(name, &ff)) {
138 ff = new FontFamily(nsDependentString(logFont.lfFaceName));
139 ht->Put(name, ff);
142 return 1;
146 // general cmap reading routines moved to gfxFontUtils.cpp
148 struct FontListData {
149 FontListData(const nsACString& aLangGroup, const nsACString& aGenericFamily, nsStringArray& aListOfFonts) :
150 mLangGroup(aLangGroup), mGenericFamily(aGenericFamily), mStringArray(aListOfFonts) {}
151 const nsACString& mLangGroup;
152 const nsACString& mGenericFamily;
153 nsStringArray& mStringArray;
156 PLDHashOperator
157 gfxWindowsPlatform::HashEnumFunc(nsStringHashKey::KeyType aKey,
158 nsRefPtr<FontFamily>& aFontFamily,
159 void* userArg)
161 FontListData *data = (FontListData*)userArg;
163 // use the first variation for now. This data should be the same
164 // for all the variations and should probably be moved up to
165 // the Family
166 gfxFontStyle style;
167 style.langGroup = data->mLangGroup;
168 nsRefPtr<FontEntry> aFontEntry = aFontFamily->FindFontEntry(style);
170 /* skip symbol fonts */
171 if (aFontEntry->mSymbolFont)
172 return PL_DHASH_NEXT;
174 if (aFontEntry->SupportsLangGroup(data->mLangGroup) &&
175 aFontEntry->MatchesGenericFamily(data->mGenericFamily))
176 data->mStringArray.AppendString(aFontFamily->mName);
178 return PL_DHASH_NEXT;
181 nsresult
182 gfxWindowsPlatform::GetFontList(const nsACString& aLangGroup,
183 const nsACString& aGenericFamily,
184 nsStringArray& aListOfFonts)
186 FontListData data(aLangGroup, aGenericFamily, aListOfFonts);
188 mFonts.Enumerate(gfxWindowsPlatform::HashEnumFunc, &data);
190 aListOfFonts.Sort();
191 aListOfFonts.Compact();
193 return NS_OK;
196 static void
197 RemoveCharsetFromFontSubstitute(nsAString &aName)
199 PRInt32 comma = aName.FindChar(PRUnichar(','));
200 if (comma >= 0)
201 aName.Truncate(comma);
204 nsresult
205 gfxWindowsPlatform::UpdateFontList()
207 gfxFontCache *fc = gfxFontCache::GetCache();
208 if (fc)
209 fc->AgeAllGenerations();
210 mFonts.Clear();
211 mFontAliases.Clear();
212 mNonExistingFonts.Clear();
213 mFontSubstitutes.Clear();
214 mPrefFonts.Clear();
215 mCodepointsWithNoFonts.reset();
216 CancelLoader();
218 LOGFONTW logFont;
219 logFont.lfCharSet = DEFAULT_CHARSET;
220 logFont.lfFaceName[0] = 0;
221 logFont.lfPitchAndFamily = 0;
223 // Use the screen DC here.. should we use something else for printing?
224 HDC dc = ::GetDC(nsnull);
225 EnumFontFamiliesExW(dc, &logFont, (FONTENUMPROCW)gfxWindowsPlatform::FontEnumProc, (LPARAM)&mFonts, 0);
226 ::ReleaseDC(nsnull, dc);
228 // initialize the cmap loading process after font list has been initialized
229 StartLoader(kDelayBeforeLoadingCmaps, kIntervalBetweenLoadingCmaps);
231 // Create the list of FontSubstitutes
232 nsCOMPtr<nsIWindowsRegKey> regKey = do_CreateInstance("@mozilla.org/windows-registry-key;1");
233 if (!regKey)
234 return NS_ERROR_FAILURE;
235 NS_NAMED_LITERAL_STRING(kFontSubstitutesKey, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes");
237 nsresult rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE,
238 kFontSubstitutesKey, nsIWindowsRegKey::ACCESS_READ);
239 if (NS_FAILED(rv))
240 return rv;
242 PRUint32 count;
243 rv = regKey->GetValueCount(&count);
244 if (NS_FAILED(rv) || count == 0)
245 return rv;
246 for (PRUint32 i = 0; i < count; i++) {
247 nsAutoString substituteName;
248 rv = regKey->GetValueName(i, substituteName);
249 if (NS_FAILED(rv) || substituteName.IsEmpty() ||
250 substituteName.CharAt(1) == PRUnichar('@'))
251 continue;
252 PRUint32 valueType;
253 rv = regKey->GetValueType(substituteName, &valueType);
254 if (NS_FAILED(rv) || valueType != nsIWindowsRegKey::TYPE_STRING)
255 continue;
256 nsAutoString actualFontName;
257 rv = regKey->ReadStringValue(substituteName, actualFontName);
258 if (NS_FAILED(rv))
259 continue;
261 RemoveCharsetFromFontSubstitute(substituteName);
262 BuildKeyNameFromFontName(substituteName);
263 RemoveCharsetFromFontSubstitute(actualFontName);
264 BuildKeyNameFromFontName(actualFontName);
265 nsRefPtr<FontFamily> ff;
266 if (!actualFontName.IsEmpty() && mFonts.Get(actualFontName, &ff))
267 mFontSubstitutes.Put(substituteName, ff);
268 else
269 mNonExistingFonts.AppendString(substituteName);
272 // initialize ranges of characters for which system-wide font search should be skipped
273 mCodepointsWithNoFonts.SetRange(0,0x1f); // C0 controls
274 mCodepointsWithNoFonts.SetRange(0x7f,0x9f); // C1 controls
276 InitBadUnderlineList();
278 return NS_OK;
281 struct FontFamilyListData {
282 FontFamilyListData(nsTArray<nsRefPtr<FontFamily> >& aFamilyArray)
283 : mFamilyArray(aFamilyArray)
286 static PLDHashOperator AppendFamily(nsStringHashKey::KeyType aKey,
287 nsRefPtr<FontFamily>& aFamilyEntry,
288 void *aUserArg)
290 FontFamilyListData *data = (FontFamilyListData*)aUserArg;
291 data->mFamilyArray.AppendElement(aFamilyEntry);
292 return PL_DHASH_NEXT;
295 nsTArray<nsRefPtr<FontFamily> >& mFamilyArray;
298 void
299 gfxWindowsPlatform::GetFontFamilyList(nsTArray<nsRefPtr<FontFamily> >& aFamilyArray)
301 FontFamilyListData data(aFamilyArray);
302 mFonts.Enumerate(FontFamilyListData::AppendFamily, &data);
305 static PRBool SimpleResolverCallback(const nsAString& aName, void* aClosure)
307 nsString *result = static_cast<nsString*>(aClosure);
308 result->Assign(aName);
309 return PR_FALSE;
312 void
313 gfxWindowsPlatform::InitBadUnderlineList()
315 nsAutoTArray<nsString, 10> blacklist;
316 gfxFontUtils::GetPrefsFontList("font.blacklist.underline_offset", blacklist);
317 PRUint32 numFonts = blacklist.Length();
318 for (PRUint32 i = 0; i < numFonts; i++) {
319 PRBool aborted;
320 nsAutoString resolved;
321 ResolveFontName(blacklist[i], SimpleResolverCallback, &resolved, aborted);
322 if (resolved.IsEmpty())
323 continue;
324 FontFamily *ff = FindFontFamily(resolved);
325 if (!ff)
326 continue;
327 ff->mIsBadUnderlineFontFamily = 1;
331 nsresult
332 gfxWindowsPlatform::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
334 aFamilyName.Truncate();
335 PRBool aborted;
336 return ResolveFontName(aFontName, SimpleResolverCallback, &aFamilyName, aborted);
339 struct ResolveData {
340 ResolveData(gfxPlatform::FontResolverCallback aCallback,
341 gfxWindowsPlatform *aCaller, const nsAString *aFontName,
342 void *aClosure) :
343 mFoundCount(0), mCallback(aCallback), mCaller(aCaller),
344 mFontName(aFontName), mClosure(aClosure) {}
345 PRUint32 mFoundCount;
346 gfxPlatform::FontResolverCallback mCallback;
347 gfxWindowsPlatform *mCaller;
348 const nsAString *mFontName;
349 void *mClosure;
352 nsresult
353 gfxWindowsPlatform::ResolveFontName(const nsAString& aFontName,
354 FontResolverCallback aCallback,
355 void *aClosure,
356 PRBool& aAborted)
358 if (aFontName.IsEmpty())
359 return NS_ERROR_FAILURE;
361 nsAutoString keyName(aFontName);
362 BuildKeyNameFromFontName(keyName);
364 nsRefPtr<FontFamily> ff;
365 if (mFonts.Get(keyName, &ff) ||
366 mFontSubstitutes.Get(keyName, &ff) ||
367 mFontAliases.Get(keyName, &ff)) {
368 aAborted = !(*aCallback)(ff->mName, aClosure);
369 // XXX If the font has font link, we should add the linked font.
370 return NS_OK;
373 if (mNonExistingFonts.IndexOf(keyName) >= 0) {
374 aAborted = PR_FALSE;
375 return NS_OK;
378 LOGFONTW logFont;
379 logFont.lfCharSet = DEFAULT_CHARSET;
380 logFont.lfPitchAndFamily = 0;
381 PRInt32 len = aFontName.Length();
382 if (len >= LF_FACESIZE)
383 len = LF_FACESIZE - 1;
384 memcpy(logFont.lfFaceName,
385 nsPromiseFlatString(aFontName).get(), len * sizeof(PRUnichar));
386 logFont.lfFaceName[len] = 0;
388 HDC dc = ::GetDC(nsnull);
389 ResolveData data(aCallback, this, &keyName, aClosure);
390 aAborted = !EnumFontFamiliesExW(dc, &logFont,
391 (FONTENUMPROCW)gfxWindowsPlatform::FontResolveProc,
392 (LPARAM)&data, 0);
393 if (data.mFoundCount == 0)
394 mNonExistingFonts.AppendString(keyName);
395 ::ReleaseDC(nsnull, dc);
397 return NS_OK;
400 int CALLBACK
401 gfxWindowsPlatform::FontResolveProc(const ENUMLOGFONTEXW *lpelfe,
402 const NEWTEXTMETRICEXW *nmetrics,
403 DWORD fontType, LPARAM data)
405 const LOGFONTW& logFont = lpelfe->elfLogFont;
406 // Ignore vertical fonts
407 if (logFont.lfFaceName[0] == L'@' || logFont.lfFaceName[0] == 0)
408 return 1;
410 ResolveData *rData = reinterpret_cast<ResolveData*>(data);
412 nsAutoString name(logFont.lfFaceName);
414 // Save the alias name to cache
415 nsRefPtr<FontFamily> ff;
416 nsAutoString keyName(name);
417 BuildKeyNameFromFontName(keyName);
418 if (!rData->mCaller->mFonts.Get(keyName, &ff)) {
419 // This case only occurs on failing to build
420 // the list of font substitue. In this case, the user should
421 // reboot the Windows. Probably, we don't have the good way for
422 // resolving in this time.
423 NS_WARNING("Cannot find actual font");
424 return 1;
427 rData->mFoundCount++;
428 rData->mCaller->mFontAliases.Put(*(rData->mFontName), ff);
430 return (rData->mCallback)(name, rData->mClosure);
432 // XXX If the font has font link, we should add the linked font.
435 struct FontSearch {
436 FontSearch(PRUint32 aCh, gfxWindowsFont *aFont) :
437 ch(aCh), fontToMatch(aFont), matchRank(-1) {
439 PRUint32 ch;
440 nsRefPtr<gfxWindowsFont> fontToMatch;
441 PRInt32 matchRank;
442 nsRefPtr<FontEntry> bestMatch;
445 PLDHashOperator
446 gfxWindowsPlatform::FindFontForCharProc(nsStringHashKey::KeyType aKey,
447 nsRefPtr<FontFamily>& aFontFamily,
448 void* userArg)
450 FontSearch *data = (FontSearch*)userArg;
452 const PRUint32 ch = data->ch;
454 nsRefPtr<FontEntry> fe = aFontFamily->FindFontEntry(*data->fontToMatch->GetStyle());
456 // skip over non-unicode and bitmap fonts and fonts that don't have
457 // the code point we're looking for
458 if (fe->IsCrappyFont() || !fe->mCharacterMap.test(ch))
459 return PL_DHASH_NEXT;
461 PRInt32 rank = 0;
462 // fonts that claim to support the range are more
463 // likely to be "better fonts" than ones that don't... (in theory)
464 if (fe->SupportsRange(gfxFontUtils::CharRangeBit(ch)))
465 rank += 1;
467 if (fe->SupportsLangGroup(data->fontToMatch->GetStyle()->langGroup))
468 rank += 2;
470 if (fe->mWindowsFamily == data->fontToMatch->GetFontEntry()->mWindowsFamily)
471 rank += 3;
472 if (fe->mWindowsPitch == data->fontToMatch->GetFontEntry()->mWindowsFamily)
473 rank += 3;
475 /* italic */
476 const PRBool italic = (data->fontToMatch->GetStyle()->style != FONT_STYLE_NORMAL);
477 if (fe->mItalic != italic)
478 rank += 3;
480 /* weight */
481 PRInt8 baseWeight, weightDistance;
482 data->fontToMatch->GetStyle()->ComputeWeightAndOffset(&baseWeight, &weightDistance);
483 if (fe->mWeight == (baseWeight * 100) + (weightDistance * 100))
484 rank += 2;
485 else if (fe->mWeight == data->fontToMatch->GetFontEntry()->mWeight)
486 rank += 1;
488 if (rank > data->matchRank ||
489 (rank == data->matchRank && Compare(fe->Name(), data->bestMatch->Name()) > 0)) {
490 data->bestMatch = fe;
491 data->matchRank = rank;
494 return PL_DHASH_NEXT;
497 already_AddRefed<gfxWindowsFont>
498 gfxWindowsPlatform::FindFontForChar(PRUint32 aCh, gfxWindowsFont *aFont)
500 // is codepoint with no matching font? return null immediately
501 if (mCodepointsWithNoFonts.test(aCh)) {
502 return nsnull;
505 FontSearch data(aCh, aFont);
507 // find fonts that support the character
508 mFonts.Enumerate(gfxWindowsPlatform::FindFontForCharProc, &data);
510 if (data.bestMatch) {
511 nsRefPtr<gfxWindowsFont> font =
512 gfxWindowsFont::GetOrMakeFont(data.bestMatch, aFont->GetStyle());
513 if (font->IsValid())
514 return font.forget();
515 return nsnull;
518 // no match? add to set of non-matching codepoints
519 mCodepointsWithNoFonts.set(aCh);
520 return nsnull;
523 gfxFontGroup *
524 gfxWindowsPlatform::CreateFontGroup(const nsAString &aFamilies,
525 const gfxFontStyle *aStyle,
526 gfxUserFontSet *aUserFontSet)
528 return new gfxWindowsFontGroup(aFamilies, aStyle, aUserFontSet);
532 struct FullFontNameSearch {
533 FullFontNameSearch(const nsAString& aFullName)
534 : mFound(PR_FALSE), mFullName(aFullName), mDC(nsnull), mFontEntry(nsnull)
537 PRPackedBool mFound;
538 nsString mFullName;
539 nsString mFamilyName;
540 HDC mDC;
541 gfxFontEntry *mFontEntry;
544 // callback called for each face within a single family
545 // match against elfFullName
547 static int CALLBACK
548 FindFullNameForFace(const ENUMLOGFONTEXW *lpelfe,
549 const NEWTEXTMETRICEXW *nmetrics,
550 DWORD fontType, LPARAM userArg)
552 FullFontNameSearch *data = reinterpret_cast<FullFontNameSearch*>(userArg);
554 // does the full name match?
555 if (!data->mFullName.Equals(nsDependentString(lpelfe->elfFullName)))
556 return 1; // continue
558 // found match, create a new font entry
559 data->mFound = PR_TRUE;
561 const NEWTEXTMETRICW& metrics = nmetrics->ntmTm;
562 LOGFONTW logFont = lpelfe->elfLogFont;
564 // Some fonts claim to support things > 900, but we don't so clamp the sizes
565 logFont.lfWeight = PR_MAX(PR_MIN(logFont.lfWeight, 900), 100);
567 gfxWindowsFontType feType = FontEntry::DetermineFontType(metrics, fontType);
569 data->mFontEntry = FontEntry::CreateFontEntry(data->mFamilyName, feType, (logFont.lfItalic == 0xFF), (PRUint16) (logFont.lfWeight), nsnull, data->mDC, &logFont);
571 return 0; // stop iteration
575 // callback called for each family name, based on the assumption that the
576 // first part of the full name is the family name
578 static PLDHashOperator
579 FindFullName(nsStringHashKey::KeyType aKey,
580 nsRefPtr<FontFamily>& aFontFamily,
581 void* userArg)
583 FullFontNameSearch *data = reinterpret_cast<FullFontNameSearch*>(userArg);
585 // does the family name match up to the length of the family name?
586 const nsString& family = aFontFamily->Name();
588 nsString fullNameFamily;
589 data->mFullName.Left(fullNameFamily, family.Length());
591 // if so, iterate over faces in this family to see if there is a match
592 if (family.Equals(fullNameFamily)) {
593 HDC hdc;
595 if (!data->mDC) {
596 data->mDC= GetDC(nsnull);
597 SetGraphicsMode(data->mDC, GM_ADVANCED);
599 hdc = data->mDC;
601 LOGFONTW logFont;
602 memset(&logFont, 0, sizeof(LOGFONTW));
603 logFont.lfCharSet = DEFAULT_CHARSET;
604 logFont.lfPitchAndFamily = 0;
605 PRUint32 l = PR_MIN(family.Length(), LF_FACESIZE - 1);
606 memcpy(logFont.lfFaceName,
607 nsPromiseFlatString(family).get(),
608 l * sizeof(PRUnichar));
609 logFont.lfFaceName[l] = 0;
610 data->mFamilyName.Assign(family);
612 EnumFontFamiliesExW(hdc, &logFont, (FONTENUMPROCW)FindFullNameForFace, (LPARAM)data, 0);
615 if (data->mFound)
616 return PL_DHASH_STOP;
618 return PL_DHASH_NEXT;
621 gfxFontEntry*
622 gfxWindowsPlatform::LookupLocalFont(const nsAString& aFontName)
624 // walk over list of names
625 FullFontNameSearch data(aFontName);
627 // find fonts that support the character
628 mFonts.Enumerate(FindFullName, &data);
630 if (data.mDC)
631 ReleaseDC(nsnull, data.mDC);
633 return data.mFontEntry;
636 static void MakeUniqueFontName(nsAString& aName)
638 char buf[50];
640 static PRUint32 fontCount = 0;
641 ++fontCount;
643 sprintf(buf, "mozfont%8.8x%8.8x", ::GetTickCount(), fontCount); // slightly retarded, figure something better later...
644 aName.AssignASCII(buf);
647 // from t2embapi.h, included in Platform SDK 6.1 but not 6.0
649 #ifndef __t2embapi__
651 #define TTLOAD_PRIVATE 0x00000001
652 #define LICENSE_PREVIEWPRINT 0x0004
653 #define E_NONE 0x0000L
655 typedef unsigned long( WINAPIV *READEMBEDPROC ) ( void*, void*, const unsigned long );
657 typedef struct
659 unsigned short usStructSize; // size in bytes of structure client should set to sizeof(TTLOADINFO)
660 unsigned short usRefStrSize; // size in wide characters of pusRefStr including NULL terminator
661 unsigned short *pusRefStr; // reference or actual string.
662 }TTLOADINFO;
664 LONG WINAPI TTLoadEmbeddedFont
666 HANDLE* phFontReference, // on completion, contains handle to identify embedded font installed
667 // on system
668 ULONG ulFlags, // flags specifying the request
669 ULONG* pulPrivStatus, // on completion, contains the embedding status
670 ULONG ulPrivs, // allows for the reduction of licensing privileges
671 ULONG* pulStatus, // on completion, may contain status flags for request
672 READEMBEDPROC lpfnReadFromStream, // callback function for doc/disk reads
673 LPVOID lpvReadStream, // the input stream tokin
674 LPWSTR szWinFamilyName, // the new 16 bit windows family name can be NULL
675 LPSTR szMacFamilyName, // the new 8 bit mac family name can be NULL
676 TTLOADINFO* pTTLoadInfo // optional security
679 #endif // __t2embapi__
681 typedef LONG( WINAPI *TTLoadEmbeddedFontProc ) (HANDLE* phFontReference, ULONG ulFlags, ULONG* pulPrivStatus, ULONG ulPrivs, ULONG* pulStatus,
682 READEMBEDPROC lpfnReadFromStream, LPVOID lpvReadStream, LPWSTR szWinFamilyName,
683 LPSTR szMacFamilyName, TTLOADINFO* pTTLoadInfo);
685 typedef LONG( WINAPI *TTDeleteEmbeddedFontProc ) (HANDLE hFontReference, ULONG ulFlags, ULONG* pulStatus);
688 static TTLoadEmbeddedFontProc TTLoadEmbeddedFontPtr = nsnull;
689 static TTDeleteEmbeddedFontProc TTDeleteEmbeddedFontPtr = nsnull;
691 static void InitializeFontEmbeddingProcs()
693 HMODULE fontlib = LoadLibraryW(L"t2embed.dll");
694 if (!fontlib)
695 return;
696 TTLoadEmbeddedFontPtr = (TTLoadEmbeddedFontProc) GetProcAddress(fontlib, "TTLoadEmbeddedFont");
697 TTDeleteEmbeddedFontPtr = (TTDeleteEmbeddedFontProc) GetProcAddress(fontlib, "TTDeleteEmbeddedFont");
700 class WinUserFontData : public gfxUserFontData {
701 public:
702 WinUserFontData(HANDLE aFontRef, PRBool aIsCFF)
703 : mFontRef(aFontRef), mIsCFF(aIsCFF)
706 virtual ~WinUserFontData()
708 if (mIsCFF) {
709 RemoveFontMemResourceEx(mFontRef);
710 } else {
711 ULONG pulStatus;
712 TTDeleteEmbeddedFontPtr(mFontRef, 0, &pulStatus);
716 HANDLE mFontRef;
717 PRPackedBool mIsCFF;
720 // used to control stream read by Windows TTLoadEmbeddedFont API
722 class EOTFontStreamReader {
723 public:
724 EOTFontStreamReader(const PRUint8 *aFontData, PRUint32 aLength, PRUint8 *aEOTHeader,
725 PRUint32 aEOTHeaderLen)
726 : mInHeader(PR_TRUE), mHeaderOffset(0), mEOTHeader(aEOTHeader),
727 mEOTHeaderLen(aEOTHeaderLen), mFontData(aFontData), mFontDataLen(aLength),
728 mFontDataOffset(0)
733 ~EOTFontStreamReader()
738 PRPackedBool mInHeader;
739 PRUint32 mHeaderOffset;
740 PRUint8 *mEOTHeader;
741 PRUint32 mEOTHeaderLen;
742 const PRUint8 *mFontData;
743 PRUint32 mFontDataLen;
744 PRUint32 mFontDataOffset;
746 unsigned long Read(void *outBuffer, const unsigned long aBytesToRead)
748 PRUint32 bytesLeft = aBytesToRead;
749 PRUint8 *out = static_cast<PRUint8*> (outBuffer);
751 // read from EOT header
752 if (mInHeader) {
753 PRUint32 toCopy = PR_MIN(aBytesToRead, mEOTHeaderLen - mHeaderOffset);
754 memcpy(out, mEOTHeader + mHeaderOffset, toCopy);
755 bytesLeft -= toCopy;
756 mHeaderOffset += toCopy;
757 out += toCopy;
758 if (mHeaderOffset == mEOTHeaderLen)
759 mInHeader = PR_FALSE;
762 if (bytesLeft) {
763 PRInt32 bytesRead = PR_MIN(bytesLeft, mFontDataLen - mFontDataOffset);
764 memcpy(out, mFontData, bytesRead);
765 mFontData += bytesRead;
766 mFontDataOffset += bytesRead;
767 if (bytesRead > 0)
768 bytesLeft -= bytesRead;
771 return aBytesToRead - bytesLeft;
774 static unsigned long ReadEOTStream(void *aReadStream, void *outBuffer,
775 const unsigned long aBytesToRead)
777 EOTFontStreamReader *eotReader =
778 static_cast<EOTFontStreamReader*> (aReadStream);
779 return eotReader->Read(outBuffer, aBytesToRead);
784 gfxFontEntry*
785 gfxWindowsPlatform::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
786 nsISupports *aLoader,
787 const PRUint8 *aFontData, PRUint32 aLength)
789 // if calls aren't available, bail
790 if (!TTLoadEmbeddedFontPtr || !TTDeleteEmbeddedFontPtr)
791 return nsnull;
793 PRBool isCFF;
794 if (!gfxFontUtils::ValidateSFNTHeaders(aFontData, aLength, &isCFF))
795 return nsnull;
797 nsresult rv;
798 HANDLE fontRef;
800 nsAutoString uniqueName;
801 MakeUniqueFontName(uniqueName);
803 if (isCFF) {
804 // Postscript-style glyphs, swizzle name table, load directly
805 nsTArray<PRUint8> newFontData;
807 rv = gfxFontUtils::RenameFont(uniqueName, aFontData, aLength, &newFontData);
809 if (NS_FAILED(rv))
810 return nsnull;
812 DWORD numFonts = 0;
814 PRUint8 *fontData = reinterpret_cast<PRUint8*> (newFontData.Elements());
815 PRUint32 fontLength = newFontData.Length();
816 NS_ASSERTION(fontData, "null font data after renaming");
818 // http://msdn.microsoft.com/en-us/library/ms533942(VS.85).aspx
819 // "A font that is added by AddFontMemResourceEx is always private
820 // to the process that made the call and is not enumerable."
821 fontRef = AddFontMemResourceEx(fontData, fontLength,
822 0 /* reserved */, &numFonts);
824 if (!fontRef)
825 return nsnull;
827 // only load fonts with a single face contained in the data
828 if (fontRef && numFonts != 1) {
829 RemoveFontMemResourceEx(fontRef);
830 return nsnull;
832 } else {
833 // TrueType-style glyphs, use EOT library
834 nsAutoTArray<PRUint8,2048> eotHeader;
835 PRUint8 *buffer;
836 PRUint32 eotlen;
838 PRUint32 nameLen = PR_MIN(uniqueName.Length(), LF_FACESIZE - 1);
839 nsPromiseFlatString fontName(Substring(uniqueName, 0, nameLen));
841 rv = gfxFontUtils::MakeEOTHeader(aFontData, aLength, &eotHeader);
842 if (NS_FAILED(rv))
843 return nsnull;
845 // load in embedded font data
846 eotlen = eotHeader.Length();
847 buffer = reinterpret_cast<PRUint8*> (eotHeader.Elements());
849 PRInt32 ret;
850 ULONG privStatus, pulStatus;
851 EOTFontStreamReader eotReader(aFontData, aLength, buffer, eotlen);
853 ret = TTLoadEmbeddedFontPtr(&fontRef, TTLOAD_PRIVATE, &privStatus,
854 LICENSE_PREVIEWPRINT, &pulStatus,
855 EOTFontStreamReader::ReadEOTStream,
856 &eotReader, (PRUnichar*)(fontName.get()), 0, 0);
857 if (ret != E_NONE)
858 return nsnull;
862 // make a new font entry using the unique name
863 WinUserFontData *winUserFontData = new WinUserFontData(fontRef, isCFF);
864 PRUint16 w = (aProxyEntry->mWeight == 0 ? 400 : aProxyEntry->mWeight);
866 FontEntry *fe = FontEntry::CreateFontEntry(uniqueName,
867 gfxWindowsFontType(isCFF ? GFX_FONT_TYPE_PS_OPENTYPE : GFX_FONT_TYPE_TRUETYPE) /*type*/,
868 PRUint32(aProxyEntry->mItalic ? FONT_STYLE_ITALIC : FONT_STYLE_NORMAL),
869 w, winUserFontData);
871 if (fe && isCFF)
872 fe->mForceGDI = PR_TRUE;
874 return fe;
877 PRBool
878 gfxWindowsPlatform::IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags)
880 // reject based on format flags
881 if (aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_EOT | gfxUserFontSet::FLAG_FORMAT_SVG)) {
882 return PR_FALSE;
885 // exclude AAT fonts on platforms other than Mac OS X, this allows
886 // fonts for complex scripts which require AAT tables to be omitted
887 // on other platforms
888 if ((aFormatFlags & gfxUserFontSet::FLAG_FORMAT_TRUETYPE_AAT)
889 && !(aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_OPENTYPE | gfxUserFontSet::FLAG_FORMAT_TRUETYPE))) {
890 return PR_FALSE;
893 // reject based on filetype in URI
895 // otherwise, return true
896 return PR_TRUE;
899 FontFamily *
900 gfxWindowsPlatform::FindFontFamily(const nsAString& aName)
902 nsAutoString name(aName);
903 BuildKeyNameFromFontName(name);
905 nsRefPtr<FontFamily> ff;
906 if (!mFonts.Get(name, &ff) &&
907 !mFontSubstitutes.Get(name, &ff) &&
908 !mFontAliases.Get(name, &ff)) {
909 return nsnull;
911 return ff.get();
914 FontEntry *
915 gfxWindowsPlatform::FindFontEntry(const nsAString& aName, const gfxFontStyle& aFontStyle)
917 nsRefPtr<FontFamily> ff = FindFontFamily(aName);
918 if (!ff)
919 return nsnull;
921 return ff->FindFontEntry(aFontStyle);
924 cmsHPROFILE
925 gfxWindowsPlatform::GetPlatformCMSOutputProfile()
927 #ifndef WINCE
928 WCHAR str[1024+1];
929 DWORD size = 1024;
931 HDC dc = GetDC(nsnull);
932 GetICMProfileW(dc, &size, (LPWSTR)&str);
933 ReleaseDC(nsnull, dc);
935 cmsHPROFILE profile =
936 cmsOpenProfileFromFile(NS_ConvertUTF16toUTF8(str).get(), "r");
937 #ifdef DEBUG_tor
938 if (profile)
939 fprintf(stderr,
940 "ICM profile read from %s successfully\n",
941 NS_ConvertUTF16toUTF8(str).get());
942 #endif
943 return profile;
944 #else
945 return nsnull;
946 #endif
949 PRBool
950 gfxWindowsPlatform::GetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<FontEntry> > *array)
952 return mPrefFonts.Get(aKey, array);
955 void
956 gfxWindowsPlatform::SetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<FontEntry> >& array)
958 mPrefFonts.Put(aKey, array);
961 void
962 gfxWindowsPlatform::InitLoader()
964 GetFontFamilyList(mFontFamilies);
965 mStartIndex = 0;
966 mNumFamilies = mFontFamilies.Length();
969 PRBool
970 gfxWindowsPlatform::RunLoader()
972 PRUint32 i, endIndex = ( mStartIndex + mIncrement < mNumFamilies ? mStartIndex + mIncrement : mNumFamilies );
974 // for each font family, load in various font info
975 for (i = mStartIndex; i < endIndex; i++) {
976 // load the cmaps for all variations
977 mFontFamilies[i]->FindStyleVariations();
980 mStartIndex += mIncrement;
981 if (mStartIndex < mNumFamilies)
982 return PR_FALSE;
983 return PR_TRUE;
986 void
987 gfxWindowsPlatform::FinishLoader()
989 mFontFamilies.Clear();
990 mNumFamilies = 0;