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
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.
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"
49 #include "nsServiceManagerUtils.h"
51 #include "nsIWindowsRegKey.h"
52 #include "nsILocalFile.h"
55 #include "gfxWindowsFonts.h"
56 #include "gfxUserFontSet.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
70 BuildKeyNameFromFontName(nsAString
&aName
)
72 if (aName
.Length() >= LF_FACESIZE
)
73 aName
.Truncate(LF_FACESIZE
- 1);
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();
87 gfxWindowsPlatform::gfxWindowsPlatform()
88 : mStartIndex(0), mIncrement(kNumFontsPerSlice
), mNumFamilies(0)
91 mFontAliases
.Init(20);
92 mFontSubstitutes
.Init(50);
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
);
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
'@')
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
));
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
;
157 gfxWindowsPlatform::HashEnumFunc(nsStringHashKey::KeyType aKey
,
158 nsRefPtr
<FontFamily
>& aFontFamily
,
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
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
;
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
);
191 aListOfFonts
.Compact();
197 RemoveCharsetFromFontSubstitute(nsAString
&aName
)
199 PRInt32 comma
= aName
.FindChar(PRUnichar(','));
201 aName
.Truncate(comma
);
205 gfxWindowsPlatform::UpdateFontList()
207 gfxFontCache
*fc
= gfxFontCache::GetCache();
209 fc
->AgeAllGenerations();
211 mFontAliases
.Clear();
212 mNonExistingFonts
.Clear();
213 mFontSubstitutes
.Clear();
215 mCodepointsWithNoFonts
.reset();
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");
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
);
243 rv
= regKey
->GetValueCount(&count
);
244 if (NS_FAILED(rv
) || count
== 0)
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('@'))
253 rv
= regKey
->GetValueType(substituteName
, &valueType
);
254 if (NS_FAILED(rv
) || valueType
!= nsIWindowsRegKey::TYPE_STRING
)
256 nsAutoString actualFontName
;
257 rv
= regKey
->ReadStringValue(substituteName
, actualFontName
);
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
);
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();
281 struct FontFamilyListData
{
282 FontFamilyListData(nsTArray
<nsRefPtr
<FontFamily
> >& aFamilyArray
)
283 : mFamilyArray(aFamilyArray
)
286 static PLDHashOperator
AppendFamily(nsStringHashKey::KeyType aKey
,
287 nsRefPtr
<FontFamily
>& aFamilyEntry
,
290 FontFamilyListData
*data
= (FontFamilyListData
*)aUserArg
;
291 data
->mFamilyArray
.AppendElement(aFamilyEntry
);
292 return PL_DHASH_NEXT
;
295 nsTArray
<nsRefPtr
<FontFamily
> >& mFamilyArray
;
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
);
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
++) {
320 nsAutoString resolved
;
321 ResolveFontName(blacklist
[i
], SimpleResolverCallback
, &resolved
, aborted
);
322 if (resolved
.IsEmpty())
324 FontFamily
*ff
= FindFontFamily(resolved
);
327 ff
->mIsBadUnderlineFontFamily
= 1;
332 gfxWindowsPlatform::GetStandardFamilyName(const nsAString
& aFontName
, nsAString
& aFamilyName
)
334 aFamilyName
.Truncate();
336 return ResolveFontName(aFontName
, SimpleResolverCallback
, &aFamilyName
, aborted
);
340 ResolveData(gfxPlatform::FontResolverCallback aCallback
,
341 gfxWindowsPlatform
*aCaller
, const nsAString
*aFontName
,
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
;
353 gfxWindowsPlatform::ResolveFontName(const nsAString
& aFontName
,
354 FontResolverCallback aCallback
,
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.
373 if (mNonExistingFonts
.IndexOf(keyName
) >= 0) {
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
,
393 if (data
.mFoundCount
== 0)
394 mNonExistingFonts
.AppendString(keyName
);
395 ::ReleaseDC(nsnull
, dc
);
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)
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");
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.
436 FontSearch(PRUint32 aCh
, gfxWindowsFont
*aFont
) :
437 ch(aCh
), fontToMatch(aFont
), matchRank(-1) {
440 nsRefPtr
<gfxWindowsFont
> fontToMatch
;
442 nsRefPtr
<FontEntry
> bestMatch
;
446 gfxWindowsPlatform::FindFontForCharProc(nsStringHashKey::KeyType aKey
,
447 nsRefPtr
<FontFamily
>& aFontFamily
,
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
;
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
)))
467 if (fe
->SupportsLangGroup(data
->fontToMatch
->GetStyle()->langGroup
))
470 if (fe
->mWindowsFamily
== data
->fontToMatch
->GetFontEntry()->mWindowsFamily
)
472 if (fe
->mWindowsPitch
== data
->fontToMatch
->GetFontEntry()->mWindowsFamily
)
476 const PRBool italic
= (data
->fontToMatch
->GetStyle()->style
!= FONT_STYLE_NORMAL
);
477 if (fe
->mItalic
!= italic
)
481 PRInt8 baseWeight
, weightDistance
;
482 data
->fontToMatch
->GetStyle()->ComputeWeightAndOffset(&baseWeight
, &weightDistance
);
483 if (fe
->mWeight
== (baseWeight
* 100) + (weightDistance
* 100))
485 else if (fe
->mWeight
== data
->fontToMatch
->GetFontEntry()->mWeight
)
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
)) {
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());
514 return font
.forget();
518 // no match? add to set of non-matching codepoints
519 mCodepointsWithNoFonts
.set(aCh
);
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
)
539 nsString mFamilyName
;
541 gfxFontEntry
*mFontEntry
;
544 // callback called for each face within a single family
545 // match against elfFullName
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
,
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
)) {
596 data
->mDC
= GetDC(nsnull
);
597 SetGraphicsMode(data
->mDC
, GM_ADVANCED
);
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);
616 return PL_DHASH_STOP
;
618 return PL_DHASH_NEXT
;
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
);
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;
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);
653 // from t2embapi.h, included in Platform SDK 6.1 but not 6.0
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 );
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.
670 LONG WINAPI TTLoadEmbeddedFont
672 HANDLE
* phFontReference
, // on completion, contains handle to identify embedded font installed
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");
702 TTLoadEmbeddedFontPtr
= (TTLoadEmbeddedFontProc
) GetProcAddress(fontlib
, "TTLoadEmbeddedFont");
703 TTDeleteEmbeddedFontPtr
= (TTDeleteEmbeddedFontProc
) GetProcAddress(fontlib
, "TTDeleteEmbeddedFont");
706 class WinUserFontData
: public gfxUserFontData
{
708 WinUserFontData(HANDLE aFontRef
)
712 virtual ~WinUserFontData()
715 TTDeleteEmbeddedFontPtr(mFontRef
, 0, &pulStatus
);
721 // used to control stream read by Windows TTLoadEmbeddedFont API
723 class EOTFontStreamReader
{
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()
740 mFontFile
->Remove(PR_FALSE
);
743 nsCOMPtr
<nsILocalFile
> mFontFile
;
745 PRPackedBool mOpenError
;
746 PRPackedBool mInHeader
;
747 PRUint32 mHeaderOffset
;
749 PRUint32 mEOTHeaderLen
;
751 PRBool
OpenFontFile()
755 rv
= mFontFile
->OpenNSPRFileDesc(PR_RDONLY
, 0, &mFd
);
756 if (NS_FAILED(rv
) || !mFd
)
762 unsigned long Read(void *outBuffer
, const unsigned long aBytesToRead
)
764 PRUint32 bytesLeft
= aBytesToRead
;
765 PRUint8
*out
= static_cast<PRUint8
*> (outBuffer
);
771 if (!OpenFontFile()) {
772 mOpenError
= PR_TRUE
;
777 // read from EOT header
779 PRUint32 toCopy
= PR_MIN(aBytesToRead
, mEOTHeaderLen
- mHeaderOffset
);
780 memcpy(out
, mEOTHeader
+ mHeaderOffset
, toCopy
);
782 mHeaderOffset
+= toCopy
;
784 if (mHeaderOffset
== mEOTHeaderLen
)
785 mInHeader
= PR_FALSE
;
789 PRInt32 bytesRead
= PR_Read(mFd
, out
, bytesLeft
);
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
);
808 gfxWindowsPlatform::MakePlatformFont(const gfxFontEntry
*aProxyEntry
,
809 const gfxDownloadedFontData
* aFontData
)
811 // if calls aren't available, bail
812 if (!TTLoadEmbeddedFontPtr
|| !TTDeleteEmbeddedFontPtr
)
815 // create an eot header
816 nsAutoTArray
<PRUint8
,2048> eotHeader
;
819 PRUnichar fontName
[LF_FACESIZE
];
827 nsCOMPtr
<nsILocalFile
> fontFile(do_QueryInterface(aFontData
->mFontFile
, &rv
));
831 rv
= gfxFontUtils::MakeEOTHeader(fontFile
, &eotHeader
, &isCFF
);
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);
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
),
863 gfxWindowsPlatform::IsFontFormatSupported(nsIURI
*aFontURI
, PRUint32 aFormatFlags
)
865 // reject based on format flags
866 if (aFormatFlags
& (gfxUserFontSet::FLAG_FORMAT_EOT
| gfxUserFontSet::FLAG_FORMAT_SVG
)) {
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
))) {
878 // reject based on filetype in URI
880 // otherwise, return true
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
)) {
900 gfxWindowsPlatform::FindFontEntry(const nsAString
& aName
, const gfxFontStyle
& aFontStyle
)
902 nsRefPtr
<FontFamily
> ff
= FindFontFamily(aName
);
906 return ff
->FindFontEntry(aFontStyle
);
910 gfxWindowsPlatform::GetPlatformCMSOutputProfile()
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");
924 "ICM profile read from %s successfully\n",
925 NS_ConvertUTF16toUTF8(str
).get());
931 gfxWindowsPlatform::GetPrefFontEntries(const nsCString
& aKey
, nsTArray
<nsRefPtr
<FontEntry
> > *array
)
933 return mPrefFonts
.Get(aKey
, array
);
937 gfxWindowsPlatform::SetPrefFontEntries(const nsCString
& aKey
, nsTArray
<nsRefPtr
<FontEntry
> >& array
)
939 mPrefFonts
.Put(aKey
, array
);
943 gfxWindowsPlatform::InitLoader()
945 GetFontFamilyList(mFontFamilies
);
947 mNumFamilies
= mFontFamilies
.Length();
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
)
968 gfxWindowsPlatform::FinishLoader()
970 mFontFamilies
.Clear();