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"
53 #include "gfxWindowsFonts.h"
59 //#define DEBUG_CMAP_SIZE 1
61 /* Define this if we want to update the unicode range bitsets based
62 * on the actual characters a font supports.
64 * Doing this can result in very large lists of fonts being returned.
65 * Not doing this can let us prioritize fonts that do have the bit set
66 * as they are more likely to provide better glyphs (in theory).
68 //#define UPDATE_RANGES
71 gfxWindowsPlatform::PrefChangedCallback(const char *aPrefName
, void *closure
)
73 gfxWindowsPlatform
*plat
= static_cast<gfxWindowsPlatform
*>(closure
);
74 plat
->mPrefFonts
.Clear();
78 gfxWindowsPlatform::gfxWindowsPlatform()
81 mFontAliases
.Init(20);
82 mFontSubstitutes
.Init(50);
87 nsCOMPtr
<nsIPref
> pref
= do_GetService(NS_PREF_CONTRACTID
);
88 pref
->RegisterCallback("font.", PrefChangedCallback
, this);
89 pref
->RegisterCallback("font.name-list.", PrefChangedCallback
, this);
90 // don't bother unregistering. We'll get shutdown after the pref service
93 gfxWindowsPlatform::~gfxWindowsPlatform()
97 already_AddRefed
<gfxASurface
>
98 gfxWindowsPlatform::CreateOffscreenSurface(const gfxIntSize
& size
,
99 gfxASurface::gfxImageFormat imageFormat
)
101 gfxASurface
*surf
= new gfxWindowsSurface(size
, imageFormat
);
107 gfxWindowsPlatform::FontEnumProc(const ENUMLOGFONTEXW
*lpelfe
,
108 const NEWTEXTMETRICEXW
*nmetrics
,
109 DWORD fontType
, LPARAM data
)
111 gfxWindowsPlatform
*thisp
= reinterpret_cast<gfxWindowsPlatform
*>(data
);
113 const LOGFONTW
& logFont
= lpelfe
->elfLogFont
;
114 const NEWTEXTMETRICW
& metrics
= nmetrics
->ntmTm
;
117 printf("%s %d %d %d\n", NS_ConvertUTF16toUTF8(nsDependentString(logFont
.lfFaceName
)).get(),
118 logFont
.lfCharSet
, logFont
.lfItalic
, logFont
.lfWeight
);
121 // Ignore vertical fonts
122 if (logFont
.lfFaceName
[0] == L
'@') {
126 nsString
name(logFont
.lfFaceName
);
129 nsRefPtr
<FontEntry
> fe
;
130 if (!thisp
->mFonts
.Get(name
, &fe
)) {
131 fe
= new FontEntry(nsDependentString(logFont
.lfFaceName
), (PRUint16
)fontType
);
132 thisp
->mFonts
.Put(name
, fe
);
135 // mark the charset bit
136 fe
->mCharset
[metrics
.tmCharSet
] = 1;
138 // put the default weight in the weight table
139 fe
->mWeightTable
.SetWeight(PR_MAX(1, PR_MIN(9, metrics
.tmWeight
/ 100)), PR_TRUE
);
141 // store the default font weight
142 fe
->mDefaultWeight
= metrics
.tmWeight
;
144 fe
->mFamily
= logFont
.lfPitchAndFamily
& 0xF0;
145 fe
->mPitch
= logFont
.lfPitchAndFamily
& 0x0F;
147 if (nmetrics
->ntmFontSig
.fsUsb
[0] == 0x00000000 &&
148 nmetrics
->ntmFontSig
.fsUsb
[1] == 0x00000000 &&
149 nmetrics
->ntmFontSig
.fsUsb
[2] == 0x00000000 &&
150 nmetrics
->ntmFontSig
.fsUsb
[3] == 0x00000000) {
152 fe
->mUnicodeFont
= PR_FALSE
;
154 fe
->mUnicodeFont
= PR_TRUE
;
156 // set the unicode ranges
158 for (PRUint32 i
= 0; i
< 4; ++i
) {
159 DWORD range
= nmetrics
->ntmFontSig
.fsUsb
[i
];
160 for (PRUint32 k
= 0; k
< 32; ++k
) {
161 fe
->mUnicodeRanges
[x
++] = (range
& (1 << k
)) != 0;
169 static inline PRUint16
170 ReadShortAt(const PRUint8
*aBuf
, PRUint32 aIndex
)
172 return (aBuf
[aIndex
] << 8) | aBuf
[aIndex
+ 1];
175 static inline PRUint16
176 ReadShortAt16(const PRUint16
*aBuf
, PRUint32 aIndex
)
178 return (((aBuf
[aIndex
]&0xFF) << 8) | ((aBuf
[aIndex
]&0xFF00) >> 8));
181 static inline PRUint32
182 ReadLongAt(const PRUint8
*aBuf
, PRUint32 aIndex
)
184 return ((aBuf
[aIndex
] << 24) | (aBuf
[aIndex
+ 1] << 16) | (aBuf
[aIndex
+ 2] << 8) | (aBuf
[aIndex
+ 3]));
188 ReadCMAPTableFormat12(PRUint8
*aBuf
, PRInt32 aLength
, FontEntry
*aFontEntry
)
193 OffsetTableLength
= 4,
195 OffsetNumberGroups
= 12,
200 GroupOffsetStartCode
= 0,
201 GroupOffsetEndCode
= 4
203 NS_ENSURE_TRUE(aLength
>= 16, NS_ERROR_FAILURE
);
205 NS_ENSURE_TRUE(ReadShortAt(aBuf
, OffsetFormat
) == 12, NS_ERROR_FAILURE
);
206 NS_ENSURE_TRUE(ReadShortAt(aBuf
, OffsetReserved
) == 0, NS_ERROR_FAILURE
);
208 PRUint32 tablelen
= ReadLongAt(aBuf
, OffsetTableLength
);
209 NS_ENSURE_TRUE(tablelen
<= aLength
, NS_ERROR_FAILURE
);
210 NS_ENSURE_TRUE(tablelen
>= 16, NS_ERROR_FAILURE
);
212 NS_ENSURE_TRUE(ReadLongAt(aBuf
, OffsetLanguage
) == 0, NS_ERROR_FAILURE
);
214 const PRUint32 numGroups
= ReadLongAt(aBuf
, OffsetNumberGroups
);
215 NS_ENSURE_TRUE(tablelen
>= 16 + (12 * numGroups
), NS_ERROR_FAILURE
);
217 const PRUint8
*groups
= aBuf
+ OffsetGroups
;
218 for (PRUint32 i
= 0; i
< numGroups
; i
++, groups
+= SizeOfGroup
) {
219 const PRUint32 startCharCode
= ReadLongAt(groups
, GroupOffsetStartCode
);
220 const PRUint32 endCharCode
= ReadLongAt(groups
, GroupOffsetEndCode
);
221 aFontEntry
->mCharacterMap
.SetRange(startCharCode
, endCharCode
);
223 for (PRUint32 c
= startCharCode
; c
<= endCharCode
; ++c
) {
224 PRUint16 b
= CharRangeBit(c
);
225 if (b
!= NO_RANGE_FOUND
)
226 aFontEntry
->mUnicodeRanges
.set(b
, true);
235 ReadCMAPTableFormat4(PRUint8
*aBuf
, PRInt32 aLength
, FontEntry
*aFontEntry
)
244 NS_ENSURE_TRUE(ReadShortAt(aBuf
, OffsetFormat
) == 4, NS_ERROR_FAILURE
);
245 PRUint16 tablelen
= ReadShortAt(aBuf
, OffsetLength
);
246 NS_ENSURE_TRUE(tablelen
<= aLength
, NS_ERROR_FAILURE
);
247 NS_ENSURE_TRUE(tablelen
> 16, NS_ERROR_FAILURE
);
248 NS_ENSURE_TRUE(ReadShortAt(aBuf
, OffsetLanguage
) == 0, NS_ERROR_FAILURE
);
250 PRUint16 segCountX2
= ReadShortAt(aBuf
, OffsetSegCountX2
);
251 NS_ENSURE_TRUE(tablelen
>= 16 + (segCountX2
* 4), NS_ERROR_FAILURE
);
253 const PRUint16 segCount
= segCountX2
/ 2;
255 const PRUint16
*endCounts
= (PRUint16
*)(aBuf
+ 14);
256 const PRUint16
*startCounts
= endCounts
+ 1 /* skip one uint16 for reservedPad */ + segCount
;
257 const PRUint16
*idDeltas
= startCounts
+ segCount
;
258 const PRUint16
*idRangeOffsets
= idDeltas
+ segCount
;
259 for (PRUint16 i
= 0; i
< segCount
; i
++) {
260 const PRUint16 endCount
= ReadShortAt16(endCounts
, i
);
261 const PRUint16 startCount
= ReadShortAt16(startCounts
, i
);
262 const PRUint16 idRangeOffset
= ReadShortAt16(idRangeOffsets
, i
);
263 if (idRangeOffset
== 0) {
264 aFontEntry
->mCharacterMap
.SetRange(startCount
, endCount
);
266 for (PRUint32 c
= startCount
; c
<= endCount
; c
++) {
267 PRUint16 b
= CharRangeBit(c
);
268 if (b
!= NO_RANGE_FOUND
)
269 aFontEntry
->mUnicodeRanges
.set(b
, true);
273 const PRUint16 idDelta
= ReadShortAt16(idDeltas
, i
);
274 for (PRUint32 c
= startCount
; c
<= endCount
; ++c
) {
278 const PRUint16
*gdata
= (idRangeOffset
/2
280 + &idRangeOffsets
[i
]);
282 NS_ENSURE_TRUE((PRUint8
*)gdata
> aBuf
&& (PRUint8
*)gdata
< aBuf
+ aLength
, NS_ERROR_FAILURE
);
284 // make sure we have a glyph
286 // The glyph index at this point is:
287 // glyph = (ReadShortAt16(idDeltas, i) + *gdata) % 65536;
289 aFontEntry
->mCharacterMap
.set(c
);
291 PRUint16 b
= CharRangeBit(c
);
292 if (b
!= NO_RANGE_FOUND
)
293 aFontEntry
->mUnicodeRanges
.set(b
, true);
304 ReadCMAP(HDC hdc
, FontEntry
*aFontEntry
)
306 const PRUint32 kCMAP
= (('c') | ('m' << 8) | ('a' << 16) | ('p' << 24));
308 DWORD len
= GetFontData(hdc
, kCMAP
, 0, nsnull
, 0);
309 NS_ENSURE_TRUE(len
!= GDI_ERROR
&& len
!= 0, NS_ERROR_FAILURE
);
311 nsAutoTArray
<PRUint8
,16384> buffer
;
312 if (!buffer
.AppendElements(len
))
313 return NS_ERROR_OUT_OF_MEMORY
;
314 PRUint8
*buf
= buffer
.Elements();
316 DWORD newLen
= GetFontData(hdc
, kCMAP
, 0, buf
, len
);
317 NS_ENSURE_TRUE(newLen
== len
, NS_ERROR_FAILURE
);
324 TableOffsetPlatformID
= 0,
325 TableOffsetEncodingID
= 2,
326 TableOffsetOffset
= 4,
329 SubtableOffsetFormat
= 0
332 PlatformIDMicrosoft
= 3
335 EncodingIDSymbol
= 0,
336 EncodingIDMicrosoft
= 1,
340 PRUint16 version
= ReadShortAt(buf
, OffsetVersion
);
341 PRUint16 numTables
= ReadShortAt(buf
, OffsetNumTables
);
343 // save the format and offset we want here
344 PRUint32 keepOffset
= 0;
345 PRUint32 keepFormat
= 0;
347 PRUint8
*table
= buf
+ SizeOfHeader
;
348 for (PRUint16 i
= 0; i
< numTables
; ++i
, table
+= SizeOfTable
) {
349 const PRUint16 platformID
= ReadShortAt(table
, TableOffsetPlatformID
);
350 if (platformID
!= PlatformIDMicrosoft
)
353 const PRUint16 encodingID
= ReadShortAt(table
, TableOffsetEncodingID
);
354 const PRUint32 offset
= ReadLongAt(table
, TableOffsetOffset
);
356 NS_ASSERTION(offset
< newLen
, "ugh");
357 const PRUint8
*subtable
= buf
+ offset
;
358 const PRUint16 format
= ReadShortAt(subtable
, SubtableOffsetFormat
);
360 if (encodingID
== EncodingIDSymbol
) {
361 aFontEntry
->mUnicodeFont
= PR_FALSE
;
362 aFontEntry
->mSymbolFont
= PR_TRUE
;
366 } else if (format
== 4 && encodingID
== EncodingIDMicrosoft
) {
369 } else if (format
== 12 && encodingID
== EncodingIDUCS4
) {
372 break; // we don't want to try anything else when this format is available.
376 nsresult rv
= NS_ERROR_FAILURE
;
378 if (keepFormat
== 12)
379 rv
= ReadCMAPTableFormat12(buf
+ keepOffset
, len
- keepOffset
, aFontEntry
);
380 else if (keepFormat
== 4)
381 rv
= ReadCMAPTableFormat4(buf
+ keepOffset
, len
- keepOffset
, aFontEntry
);
386 PLDHashOperator PR_CALLBACK
387 gfxWindowsPlatform::FontGetCMapDataProc(nsStringHashKey::KeyType aKey
,
388 nsRefPtr
<FontEntry
>& aFontEntry
,
391 if (aFontEntry
->mFontType
!= TRUETYPE_FONTTYPE
) {
392 /* bitmap fonts suck -- just claim they support everything
393 between 0x20 and 0xFF. All the ones on my system do...
394 If we really wanted to test which characters in this
395 range were supported we could just generate a string with
396 each codepoint and do GetGlyphIndicies or similar to determine
399 for (PRUint16 ch
= 0x20; ch
<= 0xFF; ch
++)
400 aFontEntry
->mCharacterMap
.set(ch
);
401 return PL_DHASH_NEXT
;
404 HDC hdc
= GetDC(nsnull
);
407 memset(&logFont
, 0, sizeof(LOGFONTW
));
408 logFont
.lfCharSet
= DEFAULT_CHARSET
;
409 logFont
.lfPitchAndFamily
= 0;
410 PRUint32 l
= PR_MIN(aFontEntry
->mName
.Length(), LF_FACESIZE
- 1);
411 memcpy(logFont
.lfFaceName
,
412 nsPromiseFlatString(aFontEntry
->mName
).get(),
413 l
* sizeof(PRUnichar
));
414 logFont
.lfFaceName
[l
] = 0;
416 HFONT font
= CreateFontIndirectW(&logFont
);
419 HFONT oldFont
= (HFONT
)SelectObject(hdc
, font
);
421 nsresult rv
= ReadCMAP(hdc
, aFontEntry
);
424 aFontEntry
->mUnicodeFont
= PR_FALSE
;
425 //printf("%s failed to get cmap\n", NS_ConvertUTF16toUTF8(aFontEntry->mName).get());
428 SelectObject(hdc
, oldFont
);
432 ReleaseDC(nsnull
, hdc
);
434 return PL_DHASH_NEXT
;
438 struct FontListData
{
439 FontListData(const nsACString
& aLangGroup
, const nsACString
& aGenericFamily
, nsStringArray
& aListOfFonts
) :
440 mLangGroup(aLangGroup
), mGenericFamily(aGenericFamily
), mStringArray(aListOfFonts
) {}
441 const nsACString
& mLangGroup
;
442 const nsACString
& mGenericFamily
;
443 nsStringArray
& mStringArray
;
446 PLDHashOperator PR_CALLBACK
447 gfxWindowsPlatform::HashEnumFunc(nsStringHashKey::KeyType aKey
,
448 nsRefPtr
<FontEntry
>& aFontEntry
,
451 FontListData
*data
= (FontListData
*)userArg
;
453 /* skip symbol fonts */
454 if (aFontEntry
->mSymbolFont
)
455 return PL_DHASH_NEXT
;
457 if (aFontEntry
->SupportsLangGroup(data
->mLangGroup
) &&
458 aFontEntry
->MatchesGenericFamily(data
->mGenericFamily
))
459 data
->mStringArray
.AppendString(aFontEntry
->mName
);
461 return PL_DHASH_NEXT
;
465 gfxWindowsPlatform::GetFontList(const nsACString
& aLangGroup
,
466 const nsACString
& aGenericFamily
,
467 nsStringArray
& aListOfFonts
)
469 FontListData
data(aLangGroup
, aGenericFamily
, aListOfFonts
);
471 mFonts
.Enumerate(gfxWindowsPlatform::HashEnumFunc
, &data
);
474 aListOfFonts
.Compact();
480 RemoveCharsetFromFontSubstitute(nsAString
&aName
)
482 PRInt32 comma
= aName
.FindChar(PRUnichar(','));
484 aName
.Truncate(comma
);
488 BuildKeyNameFromFontName(nsAString
&aName
)
490 if (aName
.Length() >= LF_FACESIZE
)
491 aName
.Truncate(LF_FACESIZE
- 1);
496 gfxWindowsPlatform::UpdateFontList()
499 mFontAliases
.Clear();
500 mNonExistingFonts
.Clear();
501 mFontSubstitutes
.Clear();
505 logFont
.lfCharSet
= DEFAULT_CHARSET
;
506 logFont
.lfFaceName
[0] = 0;
507 logFont
.lfPitchAndFamily
= 0;
509 // Use the screen DC here.. should we use something else for printing?
510 HDC dc
= ::GetDC(nsnull
);
511 EnumFontFamiliesExW(dc
, &logFont
, (FONTENUMPROCW
)gfxWindowsPlatform::FontEnumProc
, (LPARAM
)this, 0);
512 ::ReleaseDC(nsnull
, dc
);
514 // Update all the fonts cmaps
515 mFonts
.Enumerate(gfxWindowsPlatform::FontGetCMapDataProc
, nsnull
);
517 // Create the list of FontSubstitutes
518 nsCOMPtr
<nsIWindowsRegKey
> regKey
= do_CreateInstance("@mozilla.org/windows-registry-key;1");
520 return NS_ERROR_FAILURE
;
521 NS_NAMED_LITERAL_STRING(kFontSubstitutesKey
, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes");
523 nsresult rv
= regKey
->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE
,
524 kFontSubstitutesKey
, nsIWindowsRegKey::ACCESS_READ
);
529 rv
= regKey
->GetValueCount(&count
);
530 if (NS_FAILED(rv
) || count
== 0)
532 for (PRUint32 i
= 0; i
< count
; i
++) {
533 nsAutoString substituteName
;
534 rv
= regKey
->GetValueName(i
, substituteName
);
535 if (NS_FAILED(rv
) || substituteName
.IsEmpty() ||
536 substituteName
.CharAt(1) == PRUnichar('@'))
539 rv
= regKey
->GetValueType(substituteName
, &valueType
);
540 if (NS_FAILED(rv
) || valueType
!= nsIWindowsRegKey::TYPE_STRING
)
542 nsAutoString actualFontName
;
543 rv
= regKey
->ReadStringValue(substituteName
, actualFontName
);
547 RemoveCharsetFromFontSubstitute(substituteName
);
548 BuildKeyNameFromFontName(substituteName
);
549 RemoveCharsetFromFontSubstitute(actualFontName
);
550 BuildKeyNameFromFontName(actualFontName
);
551 nsRefPtr
<FontEntry
> fe
;
552 if (!actualFontName
.IsEmpty() && mFonts
.Get(actualFontName
, &fe
))
553 mFontSubstitutes
.Put(substituteName
, fe
);
555 mNonExistingFonts
.AppendString(substituteName
);
562 ResolveData(gfxPlatform::FontResolverCallback aCallback
,
563 gfxWindowsPlatform
*aCaller
, const nsAString
*aFontName
,
565 mFoundCount(0), mCallback(aCallback
), mCaller(aCaller
),
566 mFontName(aFontName
), mClosure(aClosure
) {}
567 PRUint32 mFoundCount
;
568 gfxPlatform::FontResolverCallback mCallback
;
569 gfxWindowsPlatform
*mCaller
;
570 const nsAString
*mFontName
;
575 gfxWindowsPlatform::ResolveFontName(const nsAString
& aFontName
,
576 FontResolverCallback aCallback
,
580 if (aFontName
.IsEmpty())
581 return NS_ERROR_FAILURE
;
583 nsAutoString
keyName(aFontName
);
584 BuildKeyNameFromFontName(keyName
);
586 nsRefPtr
<FontEntry
> fe
;
587 if (mFonts
.Get(keyName
, &fe
) ||
588 mFontSubstitutes
.Get(keyName
, &fe
) ||
589 mFontAliases
.Get(keyName
, &fe
)) {
590 aAborted
= !(*aCallback
)(fe
->mName
, aClosure
);
591 // XXX If the font has font link, we should add the linked font.
595 if (mNonExistingFonts
.IndexOf(keyName
) >= 0) {
601 logFont
.lfCharSet
= DEFAULT_CHARSET
;
602 logFont
.lfPitchAndFamily
= 0;
603 PRInt32 len
= aFontName
.Length();
604 if (len
>= LF_FACESIZE
)
605 len
= LF_FACESIZE
- 1;
606 memcpy(logFont
.lfFaceName
,
607 nsPromiseFlatString(aFontName
).get(), len
* sizeof(PRUnichar
));
608 logFont
.lfFaceName
[len
] = 0;
610 HDC dc
= ::GetDC(nsnull
);
611 ResolveData
data(aCallback
, this, &keyName
, aClosure
);
613 !EnumFontFamiliesExW(dc
, &logFont
,
614 (FONTENUMPROCW
)gfxWindowsPlatform::FontResolveProc
,
616 if (data
.mFoundCount
== 0)
617 mNonExistingFonts
.AppendString(keyName
);
618 ::ReleaseDC(nsnull
, dc
);
624 gfxWindowsPlatform::FontResolveProc(const ENUMLOGFONTEXW
*lpelfe
,
625 const NEWTEXTMETRICEXW
*nmetrics
,
626 DWORD fontType
, LPARAM data
)
628 const LOGFONTW
& logFont
= lpelfe
->elfLogFont
;
629 // Ignore vertical fonts
630 if (logFont
.lfFaceName
[0] == L
'@' || logFont
.lfFaceName
[0] == 0)
633 ResolveData
*rData
= reinterpret_cast<ResolveData
*>(data
);
635 nsAutoString
name(logFont
.lfFaceName
);
637 // Save the alias name to cache
638 nsRefPtr
<FontEntry
> fe
;
639 nsAutoString
keyName(name
);
640 BuildKeyNameFromFontName(keyName
);
641 if (!rData
->mCaller
->mFonts
.Get(keyName
, &fe
)) {
642 // This case only occurs on failing to build
643 // the list of font substitue. In this case, the user should
644 // reboot the Windows. Probably, we don't have the good way for
645 // resolving in this time.
646 NS_WARNING("Cannot find actual font");
650 rData
->mFoundCount
++;
651 rData
->mCaller
->mFontAliases
.Put(*(rData
->mFontName
), fe
);
653 return (rData
->mCallback
)(name
, rData
->mClosure
);
655 // XXX If the font has font link, we should add the linked font.
659 FontSearch(const PRUnichar
*aString
, PRUint32 aLength
, gfxWindowsFont
*aFont
) :
660 string(aString
), length(aLength
), fontToMatch(aFont
), matchRank(0) {
662 const PRUnichar
*string
;
663 const PRUint32 length
;
664 nsRefPtr
<gfxWindowsFont
> fontToMatch
;
666 nsRefPtr
<FontEntry
> bestMatch
;
669 PLDHashOperator PR_CALLBACK
670 gfxWindowsPlatform::FindFontForStringProc(nsStringHashKey::KeyType aKey
,
671 nsRefPtr
<FontEntry
>& aFontEntry
,
675 if (aFontEntry
->IsCrappyFont())
676 return PL_DHASH_NEXT
;
678 FontSearch
*data
= (FontSearch
*)userArg
;
682 for (PRUint32 i
= 0; i
< data
->length
; ++i
) {
683 PRUint32 ch
= data
->string
[i
];
685 if ((i
+1 < data
->length
) && NS_IS_HIGH_SURROGATE(ch
) && NS_IS_LOW_SURROGATE(data
->string
[i
+1])) {
687 ch
= SURROGATE_TO_UCS4(ch
, data
->string
[i
]);
690 if (aFontEntry
->mCharacterMap
.test(ch
)) {
693 // fonts that claim to support the range are more
694 // likely to be "better fonts" than ones that don't... (in theory)
695 if (aFontEntry
->SupportsRange(CharRangeBit(ch
)))
700 // if we didn't match any characters don't bother wasting more time.
702 return PL_DHASH_NEXT
;
705 if (aFontEntry
->SupportsLangGroup(data
->fontToMatch
->GetStyle()->langGroup
))
708 if (data
->fontToMatch
->GetFontEntry()->mFamily
== aFontEntry
->mFamily
)
710 if (data
->fontToMatch
->GetFontEntry()->mFamily
== aFontEntry
->mPitch
)
714 PRInt8 baseWeight
, weightDistance
;
715 data
->fontToMatch
->GetStyle()->ComputeWeightAndOffset(&baseWeight
, &weightDistance
);
716 PRUint16 targetWeight
= (baseWeight
* 100) + (weightDistance
* 100);
717 if (targetWeight
== aFontEntry
->mDefaultWeight
)
720 if (rank
> data
->matchRank
||
721 (rank
== data
->matchRank
&& Compare(aFontEntry
->mName
, data
->bestMatch
->mName
) > 0)) {
722 data
->bestMatch
= aFontEntry
;
723 data
->matchRank
= rank
;
726 return PL_DHASH_NEXT
;
731 gfxWindowsPlatform::FindFontForString(const PRUnichar
*aString
, PRUint32 aLength
, gfxWindowsFont
*aFont
)
733 FontSearch
data(aString
, aLength
, aFont
);
735 // find fonts that support the character
736 mFonts
.Enumerate(gfxWindowsPlatform::FindFontForStringProc
, &data
);
738 return data
.bestMatch
;
742 gfxWindowsPlatform::CreateFontGroup(const nsAString
&aFamilies
,
743 const gfxFontStyle
*aStyle
)
745 return new gfxWindowsFontGroup(aFamilies
, aStyle
);
749 gfxWindowsPlatform::FindFontEntry(const nsAString
& aName
)
751 nsString
name(aName
);
754 nsRefPtr
<FontEntry
> fe
;
755 if (!mFonts
.Get(name
, &fe
) &&
756 !mFontSubstitutes
.Get(name
, &fe
) &&
757 !mFontAliases
.Get(name
, &fe
)) {
764 gfxWindowsPlatform::GetPlatformCMSOutputProfile()
769 HDC dc
= GetDC(nsnull
);
770 GetICMProfileW(dc
, &size
, (LPWSTR
)&str
);
771 ReleaseDC(nsnull
, dc
);
773 cmsHPROFILE profile
=
774 cmsOpenProfileFromFile(NS_ConvertUTF16toUTF8(str
).get(), "r");
778 "ICM profile read from %s successfully\n",
779 NS_ConvertUTF16toUTF8(str
).get());
785 gfxWindowsPlatform::GetPrefFontEntries(const char *aLangGroup
, nsTArray
<nsRefPtr
<FontEntry
> > *array
)
787 nsCAutoString
keyName(aLangGroup
);
788 return mPrefFonts
.Get(keyName
, array
);
792 gfxWindowsPlatform::SetPrefFontEntries(const char *aLangGroup
, nsTArray
<nsRefPtr
<FontEntry
> >& array
)
794 nsCAutoString
keyName(aLangGroup
);
795 mPrefFonts
.Put(keyName
, array
);