зеркало из https://github.com/mozilla/gecko-dev.git
Unicode support for fonts on Windows. Reviewed by Michael Plitkins.
This commit is contained in:
Родитель
1bc67ead98
Коммит
7d226e6cb9
|
@ -17,9 +17,461 @@
|
|||
*/
|
||||
|
||||
#include "nsFontMetricsWin.h"
|
||||
#include "prmem.h"
|
||||
|
||||
static NS_DEFINE_IID(kIFontMetricsIID, NS_IFONT_METRICS_IID);
|
||||
|
||||
typedef struct UnicodeRange
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
PRUint8 bit;
|
||||
char* description;
|
||||
#endif
|
||||
PRUint16 begin;
|
||||
PRUint16 end;
|
||||
} UnicodeRange;
|
||||
|
||||
static UnicodeRange unicodeRanges[] =
|
||||
{
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
0, "Basic Latin",
|
||||
#endif
|
||||
0x0020, 0x007E
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
1, "Latin-1 Supplement",
|
||||
#endif
|
||||
0x00A0, 0x00FF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
2, "Latin Extended-A",
|
||||
#endif
|
||||
0x0100, 0x017F
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
3, "Latin Extended-B",
|
||||
#endif
|
||||
0x0180, 0x024F
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
4, "IPA Extensions",
|
||||
#endif
|
||||
0x0250, 0x02AF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
5, "Spacing Modifier Letters",
|
||||
#endif
|
||||
0x02B0, 0x02FF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
6, "Combining Diacritical Marks",
|
||||
#endif
|
||||
0x0300, 0x036F
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
7, "Basic Greek",
|
||||
#endif
|
||||
0x0370, 0x03CF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
8, "Greek Symbols and Coptic",
|
||||
#endif
|
||||
0x03D0, 0x03FF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
9, "Cyrillic",
|
||||
#endif
|
||||
0x0400, 0x04FF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
10, "Armenian",
|
||||
#endif
|
||||
0x0530, 0x058F
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
11, "Basic Hebrew",
|
||||
#endif
|
||||
0x05D0, 0x05FF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
12, "Hebrew Extended",
|
||||
#endif
|
||||
0x0590, 0x05CF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
13, "Basic Arabic",
|
||||
#endif
|
||||
0x0600, 0x0652
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
14, "Arabic Extended",
|
||||
#endif
|
||||
0x0653, 0x06FF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
15, "Devanagari",
|
||||
#endif
|
||||
0x0900, 0x097F
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
16, "Bengali",
|
||||
#endif
|
||||
0x0980, 0x09FF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
17, "Gurmukhi",
|
||||
#endif
|
||||
0x0A00, 0x0A7F
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
18, "Gujarati",
|
||||
#endif
|
||||
0x0A80, 0x0AFF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
19, "Oriya",
|
||||
#endif
|
||||
0x0B00, 0x0B7F
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
20, "Tamil",
|
||||
#endif
|
||||
0x0B80, 0x0BFF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
21, "Telugu",
|
||||
#endif
|
||||
0x0C00, 0x0C7F
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
22, "Kannada",
|
||||
#endif
|
||||
0x0C80, 0x0CFF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
23, "Malayalam",
|
||||
#endif
|
||||
0x0D00, 0x0D7F
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
24, "Thai",
|
||||
#endif
|
||||
0x0E00, 0x0E7F
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
25, "Lao",
|
||||
#endif
|
||||
0x0E80, 0x0EFF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
26, "Basic Georgian",
|
||||
#endif
|
||||
0x10D0, 0x10FF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
27, "Georgian Extended",
|
||||
#endif
|
||||
0x10A0, 0x10CF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
28, "Hangul Jamo",
|
||||
#endif
|
||||
0x1100, 0x11FF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
29, "Latin Extended Additional",
|
||||
#endif
|
||||
0x1E00, 0x1EFF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
30, "Greek Extended",
|
||||
#endif
|
||||
0x1F00, 0x1FFF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
31, "General Punctuation",
|
||||
#endif
|
||||
0x2000, 0x206F
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
32, "Subscripts and Superscripts",
|
||||
#endif
|
||||
0x2070, 0x209F
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
33, "Currency Symbols",
|
||||
#endif
|
||||
0x20A0, 0x20CF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
34, "Combining Diacritical Marks for Symbols",
|
||||
#endif
|
||||
0x20D0, 0x20FF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
35, "Letter-like Symbols",
|
||||
#endif
|
||||
0x2100, 0x214F
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
36, "Number Forms",
|
||||
#endif
|
||||
0x2150, 0x218F
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
37, "Arrows",
|
||||
#endif
|
||||
0x2190, 0x21FF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
38, "Mathematical Operators",
|
||||
#endif
|
||||
0x2200, 0x22FF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
39, "Miscellaneous Technical",
|
||||
#endif
|
||||
0x2300, 0x23FF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
40, "Control Pictures",
|
||||
#endif
|
||||
0x2400, 0x243F
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
41, "Optical Character Recognition",
|
||||
#endif
|
||||
0x2440, 0x245F
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
42, "Enclosed Alphanumerics",
|
||||
#endif
|
||||
0x2460, 0x24FF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
43, "Box Drawing",
|
||||
#endif
|
||||
0x2500, 0x257F
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
44, "Block Elements",
|
||||
#endif
|
||||
0x2580, 0x259F
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
45, "Geometric Shapes",
|
||||
#endif
|
||||
0x25A0, 0x25FF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
46, "Miscellaneous Symbols",
|
||||
#endif
|
||||
0x2600, 0x26FF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
47, "Dingbats",
|
||||
#endif
|
||||
0x2700, 0x27BF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
48, "Chinese, Japanese, and Korean (CJK) Symbols and Punctuation",
|
||||
#endif
|
||||
0x3000, 0x303F
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
49, "Hiragana",
|
||||
#endif
|
||||
0x3040, 0x309F
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
50, "Katakana",
|
||||
#endif
|
||||
0x30A0, 0x30FF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
51, "Bopomofo",
|
||||
#endif
|
||||
0x3100, 0x312F
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
52, "Hangul Compatibility Jamo",
|
||||
#endif
|
||||
0x3130, 0x318F
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
53, "CJK Miscellaneous",
|
||||
#endif
|
||||
0x3190, 0x319F
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
54, "Enclosed CJK",
|
||||
#endif
|
||||
0x3200, 0x32FF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
55, "CJK Compatibility",
|
||||
#endif
|
||||
0x3300, 0x33FF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
56, "Hangul",
|
||||
#endif
|
||||
0x3400, 0x3D2D
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
57, "Reserved for Unicode Subranges",
|
||||
#endif
|
||||
0x3D2E, 0x44B7
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
58, "Reserved for Unicode Subranges",
|
||||
#endif
|
||||
0x44B8, 0x4DFF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
59, "CJK Unified Ideographs",
|
||||
#endif
|
||||
0x4E00, 0x9FFF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
60, "Private Use Area",
|
||||
#endif
|
||||
0xE000, 0xF8FF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
61, "CJK Compatibility Ideographs",
|
||||
#endif
|
||||
0xF900, 0xFAFF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
62, "Alphabetic Presentation Forms",
|
||||
#endif
|
||||
0xFB00, 0xFB4F
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
63, "Arabic Presentation Forms-A",
|
||||
#endif
|
||||
0xFB50, 0xFDFF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
64, "Combining Half Marks",
|
||||
#endif
|
||||
0xFE20, 0xFE2F
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
65, "CJK Compatibility Forms",
|
||||
#endif
|
||||
0xFE30, 0xFE4F
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
66, "Small Form Variants",
|
||||
#endif
|
||||
0xFE50, 0xFE6F
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
67, "Arabic Presentation Forms-B",
|
||||
#endif
|
||||
0xFE70, 0xFEFE
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
68, "Halfwidth and Fullwidth Forms",
|
||||
#endif
|
||||
0xFF00, 0xFFEF
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
69, "Specials",
|
||||
#endif
|
||||
0xFFF0, 0xFFFD
|
||||
},
|
||||
{
|
||||
#ifdef NS_DEBUG
|
||||
70-127, "Reserved for Unicode Subranges",
|
||||
#endif
|
||||
0x0000, 0x0000
|
||||
}
|
||||
};
|
||||
|
||||
typedef struct nsGlobalFont
|
||||
{
|
||||
nsString* name;
|
||||
FONTSIGNATURE signature;
|
||||
PRUint8* map;
|
||||
} nsGlobalFont;
|
||||
|
||||
static nsGlobalFont* gGlobalFonts = nsnull;
|
||||
static int gGlobalFontsAlloc = 0;
|
||||
static int gGlobalFontsCount = 0;
|
||||
|
||||
nsFontMetricsWin :: nsFontMetricsWin()
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
|
@ -39,6 +491,28 @@ nsFontMetricsWin :: ~nsFontMetricsWin()
|
|||
mFontHandle = NULL;
|
||||
}
|
||||
|
||||
#ifdef FONT_SWITCHING
|
||||
|
||||
if (mFonts) {
|
||||
delete [] mFonts;
|
||||
mFonts = nsnull;
|
||||
}
|
||||
|
||||
if (mLoadedFonts) {
|
||||
nsFontWin* font = mLoadedFonts;
|
||||
nsFontWin* end = &mLoadedFonts[mLoadedFontsCount];
|
||||
while (font < end) {
|
||||
if (font->font) {
|
||||
::DeleteObject(font->font);
|
||||
}
|
||||
font++;
|
||||
}
|
||||
PR_Free(mLoadedFonts);
|
||||
mLoadedFonts = nsnull;
|
||||
}
|
||||
|
||||
#endif /* FONT_SWITCHING */
|
||||
|
||||
mDeviceContext = nsnull;
|
||||
}
|
||||
|
||||
|
@ -132,16 +606,199 @@ MapGenericFamilyToFont(const nsString& aGenericFamily,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsFontMetricsWin::FillLogFont(LOGFONT* logFont)
|
||||
{
|
||||
// Fill in logFont structure; stolen from awt
|
||||
logFont->lfWidth = 0;
|
||||
logFont->lfEscapement = 0;
|
||||
logFont->lfOrientation = 0;
|
||||
logFont->lfUnderline =
|
||||
(mFont->decorations & NS_FONT_DECORATION_UNDERLINE)
|
||||
? TRUE : FALSE;
|
||||
logFont->lfStrikeOut =
|
||||
(mFont->decorations & NS_FONT_DECORATION_LINE_THROUGH)
|
||||
? TRUE : FALSE;
|
||||
logFont->lfCharSet = DEFAULT_CHARSET;
|
||||
logFont->lfOutPrecision = OUT_DEFAULT_PRECIS;
|
||||
logFont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
|
||||
logFont->lfQuality = DEFAULT_QUALITY;
|
||||
logFont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
|
||||
logFont->lfWeight = ((400 < mFont->weight) ? FW_BOLD : FW_NORMAL); // XXX could be smarter
|
||||
logFont->lfItalic = (mFont->style & (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE))
|
||||
? TRUE : FALSE; // XXX need better oblique support
|
||||
float app2dev, app2twip, scale;
|
||||
mDeviceContext->GetAppUnitsToDevUnits(app2dev);
|
||||
mDeviceContext->GetDevUnitsToTwips(app2twip);
|
||||
mDeviceContext->GetCanonicalPixelScale(scale);
|
||||
app2twip *= app2dev * scale;
|
||||
|
||||
// this interesting bit of code rounds the font size off to the floor point value
|
||||
// this is necessary for proper font scaling under windows
|
||||
PRInt32 sizePoints = NSTwipsToFloorIntPoints(nscoord(mFont->size * app2twip));
|
||||
float rounded = ((float)NSIntPointsToTwips(sizePoints)) / app2twip;
|
||||
|
||||
// round font size off to floor point size to be windows compatible
|
||||
logFont->lfHeight = - NSToIntRound(rounded * app2dev); // this is proper (windows) rounding
|
||||
// logFont->lfHeight = - LONG(rounded * app2dev); // this floor rounding is to make ours compatible with Nav 4.0
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
// Make Purify happy
|
||||
memset(logFont->lfFaceName, 0, sizeof(logFont->lfFaceName));
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef FONT_SWITCHING
|
||||
|
||||
static void
|
||||
FillBitMap(FONTSIGNATURE* aSignature, PRUint8* aMap)
|
||||
{
|
||||
DWORD* array = aSignature->fsUsb;
|
||||
int i = 0;
|
||||
for (int dword = 0; dword < 4; dword++) {
|
||||
for (int bit = 0; bit < sizeof(DWORD) * 8; bit++) {
|
||||
if ((array[dword] >> bit) & 1) {
|
||||
int end = unicodeRanges[i].end;
|
||||
for (int c = unicodeRanges[i].begin; c <= end; c++) {
|
||||
ADD_GLYPH(aMap, c);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsFontWin*
|
||||
nsFontMetricsWin::LoadFont(HDC aDC, nsString* aName)
|
||||
{
|
||||
LOGFONT logFont;
|
||||
FillLogFont(&logFont);
|
||||
|
||||
// XXX need to preserve Unicode chars in face name (use LOGFONTW) -- erik
|
||||
aName->ToCString(logFont.lfFaceName, LF_FACESIZE);
|
||||
|
||||
HFONT hfont = ::CreateFontIndirect(&logFont);
|
||||
|
||||
if (hfont) {
|
||||
HFONT oldFont = (HFONT) ::SelectObject(aDC, (HGDIOBJ) hfont);
|
||||
if (mLoadedFontsCount == mLoadedFontsAlloc) {
|
||||
int newSize = 2 * (mLoadedFontsAlloc ? mLoadedFontsAlloc : 1);
|
||||
nsFontWin* newPointer = (nsFontWin*) PR_Realloc(mLoadedFonts,
|
||||
newSize * sizeof(nsFontWin));
|
||||
if (newPointer) {
|
||||
mLoadedFonts = newPointer;
|
||||
mLoadedFontsAlloc = newSize;
|
||||
}
|
||||
else {
|
||||
return nsnull;
|
||||
}
|
||||
}
|
||||
nsFontWin* font = &mLoadedFonts[mLoadedFontsCount++];
|
||||
font->font = hfont;
|
||||
memset(font->map, 0, sizeof(font->map));
|
||||
FONTSIGNATURE signature;
|
||||
GetTextCharsetInfo(aDC, &signature, 0);
|
||||
FillBitMap(&signature, font->map);
|
||||
::SelectObject(aDC, (HGDIOBJ) oldFont);
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
static int CALLBACK enumProc(const LOGFONT* logFont, const TEXTMETRIC* metrics,
|
||||
DWORD fontType, LPARAM closure)
|
||||
{
|
||||
// XXX make this smarter: don't add font to list if we already have a font
|
||||
// with the same font signature -- erik
|
||||
if (gGlobalFontsCount == gGlobalFontsAlloc) {
|
||||
int newSize = 2 * (gGlobalFontsAlloc ? gGlobalFontsAlloc : 1);
|
||||
nsGlobalFont* newPointer = (nsGlobalFont*) PR_Realloc(gGlobalFonts,
|
||||
newSize * sizeof(nsGlobalFont));
|
||||
if (newPointer) {
|
||||
gGlobalFonts = newPointer;
|
||||
gGlobalFontsAlloc = newSize;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
nsGlobalFont* font = &gGlobalFonts[gGlobalFontsCount++];
|
||||
NEWTEXTMETRICEX* metricsEx = (NEWTEXTMETRICEX*) metrics;
|
||||
font->name = new nsString(logFont->lfFaceName);
|
||||
font->signature = metricsEx->ntmFontSig;
|
||||
font->map = nsnull;
|
||||
return 1;
|
||||
}
|
||||
|
||||
nsFontWin*
|
||||
nsFontMetricsWin::FindGlobalFont(HDC aDC, PRUnichar c)
|
||||
{
|
||||
if (!gGlobalFonts) {
|
||||
LOGFONT logFont;
|
||||
logFont.lfCharSet = DEFAULT_CHARSET;
|
||||
logFont.lfFaceName[0] = 0;
|
||||
logFont.lfPitchAndFamily = 0;
|
||||
EnumFontFamiliesEx(aDC, &logFont, enumProc, NULL, 0);
|
||||
}
|
||||
for (int i = 0; i < gGlobalFontsCount; i++) {
|
||||
if (!gGlobalFonts[i].map) {
|
||||
gGlobalFonts[i].map = (PRUint8*) PR_Calloc(8192, 1);
|
||||
if (!gGlobalFonts[i].map) {
|
||||
return nsnull;
|
||||
}
|
||||
FillBitMap(&gGlobalFonts[i].signature, gGlobalFonts[i].map);
|
||||
}
|
||||
if (FONT_HAS_GLYPH(gGlobalFonts[i].map, c)) {
|
||||
return LoadFont(aDC, gGlobalFonts[i].name);
|
||||
}
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsFontWin*
|
||||
nsFontMetricsWin::FindLocalFont(HDC aDC, PRUnichar aChar)
|
||||
{
|
||||
while (mFontsIndex < mFontsCount) {
|
||||
nsFontWin* font = LoadFont(aDC, &mFonts[mFontsIndex++]);
|
||||
if (font && FONT_HAS_GLYPH(font->map, aChar)) {
|
||||
return font;
|
||||
}
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
#endif /* FONT_SWITCHING */
|
||||
|
||||
struct FontEnumData {
|
||||
FontEnumData(nsIDeviceContext* aContext, TCHAR* aFaceName)
|
||||
FontEnumData(nsIDeviceContext* aContext, TCHAR* aFaceName
|
||||
#ifdef FONT_SWITCHING
|
||||
, nsFontMetricsWin* aMetrics, HDC aDC
|
||||
#endif /* FONT_SWITCHING */
|
||||
)
|
||||
{
|
||||
mContext = aContext;
|
||||
mFaceName = aFaceName;
|
||||
#ifdef FONT_SWITCHING
|
||||
mMetrics = aMetrics;
|
||||
mDC = aDC;
|
||||
mFoundASCIIFont = 0;
|
||||
#endif /* FONT_SWITCHING */
|
||||
}
|
||||
nsIDeviceContext* mContext;
|
||||
TCHAR* mFaceName;
|
||||
#ifdef FONT_SWITCHING
|
||||
nsFontMetricsWin* mMetrics;
|
||||
HDC mDC;
|
||||
char mFoundASCIIFont;
|
||||
#endif /* FONT_SWITCHING */
|
||||
};
|
||||
|
||||
#ifndef FONT_SWITCHING
|
||||
|
||||
static PRBool
|
||||
FontEnumCallback(const nsString& aFamily, PRBool aGeneric, void *aData)
|
||||
{
|
||||
|
@ -164,55 +821,69 @@ FontEnumCallback(const nsString& aFamily, PRBool aGeneric, void *aData)
|
|||
return PR_TRUE;
|
||||
}
|
||||
|
||||
#else /* FONT_SWITCHING */
|
||||
|
||||
static void
|
||||
FontEnumHelper(FontEnumData* data, nsString* realFace)
|
||||
{
|
||||
nsFontMetricsWin* metrics = data->mMetrics;
|
||||
if (metrics->mFontsCount == metrics->mFontsAlloc) {
|
||||
int newSize = 2 * (metrics->mFontsAlloc ? metrics->mFontsAlloc : 1);
|
||||
nsString* newPointer = new nsString[newSize];
|
||||
if (newPointer) {
|
||||
for (int i = metrics->mFontsCount - 1; i >= 0; i--) {
|
||||
newPointer[i].SetString(metrics->mFonts[i].GetUnicode());
|
||||
}
|
||||
delete [] metrics->mFonts;
|
||||
metrics->mFonts = newPointer;
|
||||
metrics->mFontsAlloc = newSize;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
metrics->mFonts[metrics->mFontsCount++].SetString(realFace->GetUnicode());
|
||||
if (!data->mFoundASCIIFont) {
|
||||
nsFontWin* font =
|
||||
metrics->LoadFont(data->mDC, &metrics->mFonts[metrics->mFontsIndex++]);
|
||||
if (font && FONT_HAS_GLYPH(font->map, 'a')) {
|
||||
data->mFoundASCIIFont = 1;
|
||||
realFace->ToCString(data->mFaceName, LF_FACESIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static PRBool
|
||||
FontEnumCallback(const nsString& aFamily, PRBool aGeneric, void *aData)
|
||||
{
|
||||
FontEnumData* data = (FontEnumData*)aData;
|
||||
if (aGeneric) {
|
||||
nsAutoString realFace;
|
||||
MapGenericFamilyToFont(aFamily, data->mContext, realFace);
|
||||
FontEnumHelper(data, &realFace);
|
||||
return PR_TRUE; // don't stop
|
||||
}
|
||||
else {
|
||||
nsAutoString realFace;
|
||||
PRBool aliased;
|
||||
data->mContext->GetLocalFontName(aFamily, realFace, aliased);
|
||||
if (aliased || (NS_OK == data->mContext->CheckFontExistence(realFace))) {
|
||||
FontEnumHelper(data, &realFace);
|
||||
return PR_TRUE; // don't stop
|
||||
}
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
#endif /* FONT_SWITCHING */
|
||||
|
||||
void
|
||||
nsFontMetricsWin::RealizeFont()
|
||||
{
|
||||
// Fill in logFont structure; stolen from awt
|
||||
LOGFONT logFont;
|
||||
logFont.lfWidth = 0;
|
||||
logFont.lfEscapement = 0;
|
||||
logFont.lfOrientation = 0;
|
||||
logFont.lfUnderline =
|
||||
(mFont->decorations & NS_FONT_DECORATION_UNDERLINE)
|
||||
? TRUE : FALSE;
|
||||
logFont.lfStrikeOut =
|
||||
(mFont->decorations & NS_FONT_DECORATION_LINE_THROUGH)
|
||||
? TRUE : FALSE;
|
||||
logFont.lfCharSet = DEFAULT_CHARSET;
|
||||
logFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
|
||||
logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
|
||||
logFont.lfQuality = DEFAULT_QUALITY;
|
||||
logFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
|
||||
logFont.lfWeight = ((400 < mFont->weight) ? FW_BOLD : FW_NORMAL); // XXX could be smarter
|
||||
logFont.lfItalic = (mFont->style & (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE))
|
||||
? TRUE : FALSE; // XXX need better oblique support
|
||||
float app2dev, app2twip, scale;
|
||||
mDeviceContext->GetAppUnitsToDevUnits(app2dev);
|
||||
mDeviceContext->GetDevUnitsToTwips(app2twip);
|
||||
mDeviceContext->GetCanonicalPixelScale(scale);
|
||||
app2twip *= app2dev * scale;
|
||||
|
||||
// this interesting bit of code rounds the font size off to the floor point value
|
||||
// this is necessary for proper font scaling under windows
|
||||
PRInt32 sizePoints = NSTwipsToFloorIntPoints(nscoord(mFont->size * app2twip));
|
||||
float rounded = ((float)NSIntPointsToTwips(sizePoints)) / app2twip;
|
||||
|
||||
// round font size off to floor point size to be windows compatible
|
||||
logFont.lfHeight = - NSToIntRound(rounded * app2dev); // this is proper (windows) rounding
|
||||
// logFont.lfHeight = - LONG(rounded * app2dev); // this floor rounding is to make ours compatible with Nav 4.0
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
// Make Purify happy
|
||||
memset(logFont.lfFaceName, 0, sizeof(logFont.lfFaceName));
|
||||
#endif
|
||||
FillLogFont(&logFont);
|
||||
logFont.lfFaceName[0] = '\0';
|
||||
|
||||
FontEnumData data(mDeviceContext, logFont.lfFaceName);
|
||||
mFont->EnumerateFamilies(FontEnumCallback, &data);
|
||||
|
||||
// Create font handle from font spec
|
||||
mFontHandle = ::CreateFontIndirect(&logFont);
|
||||
|
||||
HWND win = NULL;
|
||||
HDC dc = NULL;
|
||||
|
||||
|
@ -225,6 +896,16 @@ nsFontMetricsWin::RealizeFont()
|
|||
dc = ::GetDC(win);
|
||||
}
|
||||
|
||||
#ifdef FONT_SWITCHING
|
||||
FontEnumData data(mDeviceContext, logFont.lfFaceName, this, dc);
|
||||
#else
|
||||
FontEnumData data(mDeviceContext, logFont.lfFaceName);
|
||||
#endif
|
||||
mFont->EnumerateFamilies(FontEnumCallback, &data);
|
||||
|
||||
// Create font handle from font spec
|
||||
mFontHandle = ::CreateFontIndirect(&logFont);
|
||||
|
||||
HFONT oldfont = (HFONT)::SelectObject(dc, (HGDIOBJ) mFontHandle);
|
||||
|
||||
// Get font metrics
|
||||
|
|
|
@ -29,6 +29,27 @@
|
|||
#include "nsCRT.h"
|
||||
#include "nsDeviceContextWin.h"
|
||||
|
||||
#define FONT_SWITCHING
|
||||
#ifdef FONT_SWITCHING
|
||||
|
||||
#ifdef FONT_HAS_GLYPH
|
||||
#undef FONT_HAS_GLYPH
|
||||
#endif
|
||||
#define FONT_HAS_GLYPH(map, g) (((map)[(g) >> 3] >> ((g) & 7)) & 1)
|
||||
|
||||
#ifdef ADD_GLYPH
|
||||
#undef ADD_GLYPH
|
||||
#endif
|
||||
#define ADD_GLYPH(map, g) (map)[(g) >> 3] |= (1 << ((g) & 7))
|
||||
|
||||
typedef struct nsFontWin
|
||||
{
|
||||
HFONT font;
|
||||
PRUint8 map[8192]; // XXX save memory by sharing these among fonts -- erik
|
||||
} nsFontWin;
|
||||
|
||||
#endif /* FONT_SWITCHING */
|
||||
|
||||
class nsFontMetricsWin : public nsIFontMetrics
|
||||
{
|
||||
public:
|
||||
|
@ -56,7 +77,25 @@ public:
|
|||
NS_IMETHOD GetFont(const nsFont *&aFont);
|
||||
NS_IMETHOD GetFontHandle(nsFontHandle &aHandle);
|
||||
|
||||
#ifdef FONT_SWITCHING
|
||||
|
||||
nsFontWin* FindGlobalFont(HDC aDC, PRUnichar aChar);
|
||||
nsFontWin* FindLocalFont(HDC aDC, PRUnichar aChar);
|
||||
nsFontWin* LoadFont(HDC aDC, nsString* aName);
|
||||
|
||||
nsFontWin *mLoadedFonts;
|
||||
PRUint16 mLoadedFontsAlloc;
|
||||
PRUint16 mLoadedFontsCount;
|
||||
|
||||
nsString *mFonts;
|
||||
PRUint16 mFontsAlloc;
|
||||
PRUint16 mFontsCount;
|
||||
PRUint16 mFontsIndex;
|
||||
|
||||
#endif /* FONT_SWITCHING */
|
||||
|
||||
protected:
|
||||
void FillLogFont(LOGFONT* aLogFont);
|
||||
void RealizeFont();
|
||||
|
||||
nsDeviceContextWin *mDeviceContext;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
|
||||
#include "nsRenderingContextWin.h"
|
||||
#include "nsFontMetricsWin.h"
|
||||
#include "nsRegionWin.h"
|
||||
#include <math.h>
|
||||
#include "libimg.h"
|
||||
|
@ -1445,6 +1446,8 @@ NS_IMETHODIMP nsRenderingContextWin :: GetWidth(const nsString& aString, nscoord
|
|||
return GetWidth(aString.GetUnicode(), aString.Length(), aWidth, aFontID);
|
||||
}
|
||||
|
||||
#ifndef FONT_SWITCHING
|
||||
|
||||
NS_IMETHODIMP nsRenderingContextWin :: GetWidth(const PRUnichar *aString,
|
||||
PRUint32 aLength,
|
||||
nscoord &aWidth,
|
||||
|
@ -1467,6 +1470,84 @@ NS_IMETHODIMP nsRenderingContextWin :: GetWidth(const PRUnichar *aString,
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
#else /* FONT_SWITCHING */
|
||||
|
||||
NS_IMETHODIMP nsRenderingContextWin :: GetWidth(const PRUnichar *aString,
|
||||
PRUint32 aLength,
|
||||
nscoord &aWidth,
|
||||
PRInt32 *aFontID)
|
||||
{
|
||||
if (nsnull != mFontMetrics)
|
||||
{
|
||||
nsFontMetricsWin* metrics = (nsFontMetricsWin*) mFontMetrics;
|
||||
HFONT prevFont = nsnull;
|
||||
SIZE size;
|
||||
|
||||
SetupFontAndColor();
|
||||
|
||||
LONG width = 0;
|
||||
PRUint32 start = 0;
|
||||
for (PRUint32 i = 0; i < aLength; i++) {
|
||||
PRUnichar c = aString[i];
|
||||
HFONT currFont = mCurrFont;
|
||||
nsFontWin* font = metrics->mLoadedFonts;
|
||||
nsFontWin* end = &metrics->mLoadedFonts[metrics->mLoadedFontsCount];
|
||||
while (font < end) {
|
||||
if (FONT_HAS_GLYPH(font->map, c)) {
|
||||
currFont = font->font;
|
||||
goto FoundFont; // for speed -- avoid "if" statement
|
||||
}
|
||||
font++;
|
||||
}
|
||||
font = metrics->FindLocalFont(mDC, c);
|
||||
if (font) {
|
||||
currFont = font->font;
|
||||
}
|
||||
else {
|
||||
// XXX get CSS to pass inherited or default font list?
|
||||
font = metrics->FindGlobalFont(mDC, c);
|
||||
if (font) {
|
||||
currFont = font->font;
|
||||
}
|
||||
}
|
||||
FoundFont:
|
||||
// XXX avoid this test by duplicating code
|
||||
if (prevFont) {
|
||||
if (currFont != prevFont) {
|
||||
::SelectObject(mDC, prevFont);
|
||||
::GetTextExtentPoint32W(mDC, &aString[start], i - start, &size);
|
||||
width += size.cx;
|
||||
prevFont = currFont;
|
||||
start = i;
|
||||
}
|
||||
}
|
||||
else {
|
||||
prevFont = currFont;
|
||||
start = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (prevFont) {
|
||||
::SelectObject(mDC, prevFont);
|
||||
::GetTextExtentPoint32W(mDC, &aString[start], i - start, &size);
|
||||
width += size.cx;
|
||||
}
|
||||
|
||||
aWidth = NSToCoordRound(float(width) * mP2T);
|
||||
|
||||
::SelectObject(mDC, mCurrFont);
|
||||
|
||||
if (nsnull != aFontID)
|
||||
*aFontID = 0;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
else
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
#endif /* FONT_SWITCHING */
|
||||
|
||||
NS_IMETHODIMP nsRenderingContextWin :: DrawString(const char *aString, PRUint32 aLength,
|
||||
nscoord aX, nscoord aY,
|
||||
const nscoord* aSpacing)
|
||||
|
@ -1496,6 +1577,8 @@ NS_IMETHODIMP nsRenderingContextWin :: DrawString(const char *aString, PRUint32
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifndef FONT_SWITCHING
|
||||
|
||||
NS_IMETHODIMP nsRenderingContextWin :: DrawString(const PRUnichar *aString, PRUint32 aLength,
|
||||
nscoord aX, nscoord aY,
|
||||
PRInt32 aFontID,
|
||||
|
@ -1552,6 +1635,122 @@ NS_IMETHODIMP nsRenderingContextWin :: DrawString(const PRUnichar *aString, PRUi
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
#else /* FONT_SWITCHING */
|
||||
|
||||
NS_IMETHODIMP nsRenderingContextWin :: DrawString(const PRUnichar *aString, PRUint32 aLength,
|
||||
nscoord aX, nscoord aY,
|
||||
PRInt32 aFontID,
|
||||
const nscoord* aSpacing)
|
||||
{
|
||||
if (nsnull != mFontMetrics)
|
||||
{
|
||||
PRInt32 x = aX;
|
||||
PRInt32 y = aY;
|
||||
mTMatrix->TransformCoord(&x, &y);
|
||||
nsFontMetricsWin* metrics = (nsFontMetricsWin*) mFontMetrics;
|
||||
HFONT prevFont = nsnull;
|
||||
SIZE size;
|
||||
|
||||
SetupFontAndColor();
|
||||
|
||||
PRUint32 start = 0;
|
||||
for (PRUint32 i = 0; i < aLength; i++) {
|
||||
PRUnichar c = aString[i];
|
||||
HFONT currFont = mCurrFont;
|
||||
nsFontWin* font = metrics->mLoadedFonts;
|
||||
nsFontWin* end = &metrics->mLoadedFonts[metrics->mLoadedFontsCount];
|
||||
while (font < end) {
|
||||
if (FONT_HAS_GLYPH(font->map, c)) {
|
||||
currFont = font->font;
|
||||
goto FoundFont; // for speed -- avoid "if" statement
|
||||
}
|
||||
font++;
|
||||
}
|
||||
font = metrics->FindLocalFont(mDC, c);
|
||||
if (font) {
|
||||
currFont = font->font;
|
||||
}
|
||||
else {
|
||||
// XXX get CSS to pass UA's default font list?
|
||||
font = metrics->FindGlobalFont(mDC, c);
|
||||
if (font) {
|
||||
currFont = font->font;
|
||||
}
|
||||
}
|
||||
FoundFont:
|
||||
if (prevFont) {
|
||||
if (currFont != prevFont) {
|
||||
::SelectObject(mDC, prevFont);
|
||||
if (aSpacing) {
|
||||
// XXX Fix path to use a twips transform in the DC and use the
|
||||
// spacing values directly and let windows deal with the sub-pixel
|
||||
// positioning.
|
||||
|
||||
// Slow, but accurate rendering
|
||||
const PRUnichar* str = &aString[start];
|
||||
const PRUnichar* end = &aString[i];
|
||||
while (str < end) {
|
||||
// XXX can shave some cycles by inlining a version of transform
|
||||
// coord where y is constant and transformed once
|
||||
x = aX;
|
||||
y = aY;
|
||||
mTMatrix->TransformCoord(&x, &y);
|
||||
::ExtTextOutW(mDC, x, y, 0, NULL, str, 1, NULL);
|
||||
aX += *aSpacing++;
|
||||
str++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
::ExtTextOutW(mDC, x, y, 0, NULL, &aString[start], i - start, NULL);
|
||||
::GetTextExtentPoint32W(mDC, &aString[start], i - start, &size);
|
||||
x += size.cx;
|
||||
}
|
||||
prevFont = currFont;
|
||||
start = i;
|
||||
}
|
||||
}
|
||||
else {
|
||||
prevFont = currFont;
|
||||
start = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (prevFont) {
|
||||
::SelectObject(mDC, prevFont);
|
||||
if (aSpacing) {
|
||||
// XXX Fix path to use a twips transform in the DC and use the
|
||||
// spacing values directly and let windows deal with the sub-pixel
|
||||
// positioning.
|
||||
|
||||
// Slow, but accurate rendering
|
||||
const PRUnichar* str = &aString[start];
|
||||
const PRUnichar* end = &aString[i];
|
||||
while (str < end) {
|
||||
// XXX can shave some cycles by inlining a version of transform
|
||||
// coord where y is constant and transformed once
|
||||
x = aX;
|
||||
y = aY;
|
||||
mTMatrix->TransformCoord(&x, &y);
|
||||
::ExtTextOutW(mDC, x, y, 0, NULL, str, 1, NULL);
|
||||
aX += *aSpacing++;
|
||||
str++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
::ExtTextOutW(mDC, x, y, 0, NULL, &aString[start], i - start, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
::SelectObject(mDC, mCurrFont);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
else
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
#endif /* FONT_SWITCHING */
|
||||
|
||||
NS_IMETHODIMP nsRenderingContextWin :: DrawString(const nsString& aString,
|
||||
nscoord aX, nscoord aY,
|
||||
PRInt32 aFontID,
|
||||
|
|
Загрузка…
Ссылка в новой задаче