Bug 458256. Use LoadLibraryW instead of LoadLibrary (patch by DougT). r+sr=vlad
[wine-gecko.git] / gfx / thebes / src / gfxWindowsPlatform.cpp
blob8d431dcdcb24ad91aa8d341774c96dd769b27927
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 PR_CALLBACK
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 // make a unique font name, limited on Windows to 31 two-byte characters
637 static void MakeUniqueFontName(PRUnichar aName[LF_FACESIZE])
639 static PRUint32 fontCount = 0;
640 ++fontCount;
642 char buf[LF_FACESIZE];
644 sprintf(buf, "mozfont%8.8x%8.8x", ::GetTickCount(), fontCount); // slightly retarded, figure something better later...
646 nsCAutoString fontName(buf);
648 PRUint32 nameLen = PR_MIN(fontName.Length(), LF_FACESIZE - 1);
649 memcpy(aName, nsPromiseFlatString(NS_ConvertUTF8toUTF16(fontName)).get(), nameLen * 2);
650 aName[nameLen] = 0;
653 // from t2embapi.h, included in Platform SDK 6.1 but not 6.0
655 #ifndef __t2embapi__
657 #define TTLOAD_PRIVATE 0x00000001
658 #define LICENSE_PREVIEWPRINT 0x0004
659 #define E_NONE 0x0000L
661 typedef unsigned long( WINAPIV *READEMBEDPROC ) ( void*, void*, const unsigned long );
663 typedef struct
665 unsigned short usStructSize; // size in bytes of structure client should set to sizeof(TTLOADINFO)
666 unsigned short usRefStrSize; // size in wide characters of pusRefStr including NULL terminator
667 unsigned short *pusRefStr; // reference or actual string.
668 }TTLOADINFO;
670 LONG WINAPI TTLoadEmbeddedFont
672 HANDLE* phFontReference, // on completion, contains handle to identify embedded font installed
673 // on system
674 ULONG ulFlags, // flags specifying the request
675 ULONG* pulPrivStatus, // on completion, contains the embedding status
676 ULONG ulPrivs, // allows for the reduction of licensing privileges
677 ULONG* pulStatus, // on completion, may contain status flags for request
678 READEMBEDPROC lpfnReadFromStream, // callback function for doc/disk reads
679 LPVOID lpvReadStream, // the input stream tokin
680 LPWSTR szWinFamilyName, // the new 16 bit windows family name can be NULL
681 LPSTR szMacFamilyName, // the new 8 bit mac family name can be NULL
682 TTLOADINFO* pTTLoadInfo // optional security
685 #endif // __t2embapi__
687 typedef LONG( WINAPI *TTLoadEmbeddedFontProc ) (HANDLE* phFontReference, ULONG ulFlags, ULONG* pulPrivStatus, ULONG ulPrivs, ULONG* pulStatus,
688 READEMBEDPROC lpfnReadFromStream, LPVOID lpvReadStream, LPWSTR szWinFamilyName,
689 LPSTR szMacFamilyName, TTLOADINFO* pTTLoadInfo);
691 typedef LONG( WINAPI *TTDeleteEmbeddedFontProc ) (HANDLE hFontReference, ULONG ulFlags, ULONG* pulStatus);
694 static TTLoadEmbeddedFontProc TTLoadEmbeddedFontPtr = nsnull;
695 static TTDeleteEmbeddedFontProc TTDeleteEmbeddedFontPtr = nsnull;
697 static void InitializeFontEmbeddingProcs()
699 HMODULE fontlib = LoadLibraryW(L"t2embed.dll");
700 if (!fontlib)
701 return;
702 TTLoadEmbeddedFontPtr = (TTLoadEmbeddedFontProc) GetProcAddress(fontlib, "TTLoadEmbeddedFont");
703 TTDeleteEmbeddedFontPtr = (TTDeleteEmbeddedFontProc) GetProcAddress(fontlib, "TTDeleteEmbeddedFont");
706 class WinUserFontData : public gfxUserFontData {
707 public:
708 WinUserFontData(HANDLE aFontRef)
709 : mFontRef(aFontRef)
712 virtual ~WinUserFontData()
714 ULONG pulStatus;
715 TTDeleteEmbeddedFontPtr(mFontRef, 0, &pulStatus);
718 HANDLE mFontRef;
721 // used to control stream read by Windows TTLoadEmbeddedFont API
723 class EOTFontStreamReader {
724 public:
725 EOTFontStreamReader(nsILocalFile *aFontFile, PRUint8 *aEOTHeader,
726 PRUint32 aEOTHeaderLen)
727 : mFontFile(aFontFile), mFd(nsnull), mOpenError(PR_FALSE),
728 mInHeader(PR_TRUE), mHeaderOffset(0), mEOTHeader(aEOTHeader),
729 mEOTHeaderLen(aEOTHeaderLen)
734 ~EOTFontStreamReader()
736 if (mFd) {
737 PR_Close(mFd);
740 mFontFile->Remove(PR_FALSE);
743 nsCOMPtr<nsILocalFile> mFontFile;
744 PRFileDesc *mFd;
745 PRPackedBool mOpenError;
746 PRPackedBool mInHeader;
747 PRUint32 mHeaderOffset;
748 PRUint8 *mEOTHeader;
749 PRUint32 mEOTHeaderLen;
751 PRBool OpenFontFile()
753 nsresult rv;
755 rv = mFontFile->OpenNSPRFileDesc(PR_RDONLY, 0, &mFd);
756 if (NS_FAILED(rv) || !mFd)
757 return PR_FALSE;
759 return PR_TRUE;
762 unsigned long Read(void *outBuffer, const unsigned long aBytesToRead)
764 PRUint32 bytesLeft = aBytesToRead;
765 PRUint8 *out = static_cast<PRUint8*> (outBuffer);
767 if (mOpenError)
768 return 0;
770 if (!mFd) {
771 if (!OpenFontFile()) {
772 mOpenError = PR_TRUE;
773 return 0;
777 // read from EOT header
778 if (mInHeader) {
779 PRUint32 toCopy = PR_MIN(aBytesToRead, mEOTHeaderLen - mHeaderOffset);
780 memcpy(out, mEOTHeader + mHeaderOffset, toCopy);
781 bytesLeft -= toCopy;
782 mHeaderOffset += toCopy;
783 out += toCopy;
784 if (mHeaderOffset == mEOTHeaderLen)
785 mInHeader = PR_FALSE;
788 if (bytesLeft) {
789 PRInt32 bytesRead = PR_Read(mFd, out, bytesLeft);
790 if (bytesRead > 0)
791 bytesLeft -= bytesRead;
794 return aBytesToRead - bytesLeft;
797 static unsigned long ReadEOTStream(void *aReadStream, void *outBuffer,
798 const unsigned long aBytesToRead)
800 EOTFontStreamReader *eotReader =
801 static_cast<EOTFontStreamReader*> (aReadStream);
802 return eotReader->Read(outBuffer, aBytesToRead);
807 gfxFontEntry*
808 gfxWindowsPlatform::MakePlatformFont(const gfxFontEntry *aProxyEntry,
809 const gfxDownloadedFontData* aFontData)
811 // if calls aren't available, bail
812 if (!TTLoadEmbeddedFontPtr || !TTDeleteEmbeddedFontPtr)
813 return nsnull;
815 // create an eot header
816 nsAutoTArray<PRUint8,2048> eotHeader;
817 PRUint8 *buffer;
818 PRUint32 eotlen;
819 PRUnichar fontName[LF_FACESIZE];
820 PRBool isCFF;
822 nsresult rv;
823 HANDLE fontRef;
824 PRInt32 ret;
827 nsCOMPtr<nsILocalFile> fontFile(do_QueryInterface(aFontData->mFontFile, &rv));
828 if (NS_FAILED(rv))
829 return nsnull;
831 rv = gfxFontUtils::MakeEOTHeader(fontFile, &eotHeader, &isCFF);
832 if (NS_FAILED(rv))
833 return nsnull;
835 // load in embedded font data
836 eotlen = eotHeader.Length();
837 buffer = reinterpret_cast<PRUint8*> (eotHeader.Elements());
839 ULONG privStatus, pulStatus;
840 MakeUniqueFontName(fontName);
841 EOTFontStreamReader eotReader(fontFile, buffer, eotlen);
843 ret = TTLoadEmbeddedFontPtr(&fontRef, TTLOAD_PRIVATE, &privStatus,
844 LICENSE_PREVIEWPRINT, &pulStatus,
845 EOTFontStreamReader::ReadEOTStream,
846 &eotReader, fontName, 0, 0);
849 if (ret != E_NONE)
850 return nsnull;
852 // make a new font entry using the unique name
853 WinUserFontData *winUserFontData = new WinUserFontData(fontRef);
854 PRUint16 w = (aProxyEntry->mWeight == 0 ? 400 : aProxyEntry->mWeight);
856 return FontEntry::CreateFontEntry(nsDependentString(fontName),
857 gfxWindowsFontType(isCFF ? GFX_FONT_TYPE_PS_OPENTYPE : GFX_FONT_TYPE_TRUETYPE) /*type*/,
858 PRUint32(aProxyEntry->mItalic ? FONT_STYLE_ITALIC : FONT_STYLE_NORMAL),
859 w, winUserFontData);
862 PRBool
863 gfxWindowsPlatform::IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags)
865 // reject based on format flags
866 if (aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_EOT | gfxUserFontSet::FLAG_FORMAT_SVG)) {
867 return PR_FALSE;
870 // exclude AAT fonts on platforms other than Mac OS X, this allows
871 // fonts for complex scripts which require AAT tables to be omitted
872 // on other platforms
873 if ((aFormatFlags & gfxUserFontSet::FLAG_FORMAT_TRUETYPE_AAT)
874 && !(aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_OPENTYPE | gfxUserFontSet::FLAG_FORMAT_TRUETYPE))) {
875 return PR_FALSE;
878 // reject based on filetype in URI
880 // otherwise, return true
881 return PR_TRUE;
884 FontFamily *
885 gfxWindowsPlatform::FindFontFamily(const nsAString& aName)
887 nsAutoString name(aName);
888 BuildKeyNameFromFontName(name);
890 nsRefPtr<FontFamily> ff;
891 if (!mFonts.Get(name, &ff) &&
892 !mFontSubstitutes.Get(name, &ff) &&
893 !mFontAliases.Get(name, &ff)) {
894 return nsnull;
896 return ff.get();
899 FontEntry *
900 gfxWindowsPlatform::FindFontEntry(const nsAString& aName, const gfxFontStyle& aFontStyle)
902 nsRefPtr<FontFamily> ff = FindFontFamily(aName);
903 if (!ff)
904 return nsnull;
906 return ff->FindFontEntry(aFontStyle);
909 cmsHPROFILE
910 gfxWindowsPlatform::GetPlatformCMSOutputProfile()
912 WCHAR str[1024+1];
913 DWORD size = 1024;
915 HDC dc = GetDC(nsnull);
916 GetICMProfileW(dc, &size, (LPWSTR)&str);
917 ReleaseDC(nsnull, dc);
919 cmsHPROFILE profile =
920 cmsOpenProfileFromFile(NS_ConvertUTF16toUTF8(str).get(), "r");
921 #ifdef DEBUG_tor
922 if (profile)
923 fprintf(stderr,
924 "ICM profile read from %s successfully\n",
925 NS_ConvertUTF16toUTF8(str).get());
926 #endif
927 return profile;
930 PRBool
931 gfxWindowsPlatform::GetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<FontEntry> > *array)
933 return mPrefFonts.Get(aKey, array);
936 void
937 gfxWindowsPlatform::SetPrefFontEntries(const nsCString& aKey, nsTArray<nsRefPtr<FontEntry> >& array)
939 mPrefFonts.Put(aKey, array);
942 void
943 gfxWindowsPlatform::InitLoader()
945 GetFontFamilyList(mFontFamilies);
946 mStartIndex = 0;
947 mNumFamilies = mFontFamilies.Length();
950 PRBool
951 gfxWindowsPlatform::RunLoader()
953 PRUint32 i, endIndex = ( mStartIndex + mIncrement < mNumFamilies ? mStartIndex + mIncrement : mNumFamilies );
955 // for each font family, load in various font info
956 for (i = mStartIndex; i < endIndex; i++) {
957 // load the cmaps for all variations
958 mFontFamilies[i]->FindStyleVariations();
961 mStartIndex += mIncrement;
962 if (mStartIndex < mNumFamilies)
963 return PR_FALSE;
964 return PR_TRUE;
967 void
968 gfxWindowsPlatform::FinishLoader()
970 mFontFamilies.Clear();
971 mNumFamilies = 0;