2082 lines
54 KiB
C++
2082 lines
54 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
|
|
#include "nsFontMetricsWin.h"
|
|
#include "prmem.h"
|
|
#include "plhash.h"
|
|
|
|
static NS_DEFINE_IID(kIFontMetricsIID, NS_IFONT_METRICS_IID);
|
|
|
|
nsGlobalFont* nsFontMetricsWin::gGlobalFonts = nsnull;
|
|
static int gGlobalFontsAlloc = 0;
|
|
int nsFontMetricsWin::gGlobalFontsCount = 0;
|
|
|
|
PLHashTable* nsFontMetricsWin::gFamilyNames = nsnull;
|
|
|
|
//-- Font weight
|
|
PLHashTable* nsFontMetricsWin::gFontWeights = nsnull;
|
|
|
|
#define NS_MAX_FONT_WEIGHT 900
|
|
#define NS_MIN_FONT_WEIGHT 100
|
|
|
|
|
|
nsFontMetricsWin :: nsFontMetricsWin()
|
|
{
|
|
NS_INIT_REFCNT();
|
|
mSpaceWidth = 0;
|
|
}
|
|
|
|
nsFontMetricsWin :: ~nsFontMetricsWin()
|
|
{
|
|
if (nsnull != mFont) {
|
|
delete mFont;
|
|
mFont = nsnull;
|
|
}
|
|
|
|
mFontHandle = nsnull; // released below
|
|
|
|
if (mFonts) {
|
|
delete [] mFonts;
|
|
mFonts = nsnull;
|
|
}
|
|
|
|
if (mLoadedFonts) {
|
|
nsFontWin** font = mLoadedFonts;
|
|
nsFontWin** end = &mLoadedFonts[mLoadedFontsCount];
|
|
while (font < end) {
|
|
if ((*font)->font) {
|
|
::DeleteObject((*font)->font);
|
|
}
|
|
delete *font;
|
|
font++;
|
|
}
|
|
PR_Free(mLoadedFonts);
|
|
mLoadedFonts = nsnull;
|
|
}
|
|
|
|
mDeviceContext = nsnull;
|
|
}
|
|
|
|
#ifdef LEAK_DEBUG
|
|
nsrefcnt
|
|
nsFontMetricsWin :: AddRef()
|
|
{
|
|
NS_PRECONDITION(mRefCnt != 0, "resurrecting a dead object");
|
|
return ++mRefCnt;
|
|
}
|
|
|
|
nsrefcnt
|
|
nsFontMetricsWin :: Release()
|
|
{
|
|
NS_PRECONDITION(mRefCnt != 0, "too many release's");
|
|
if (--mRefCnt == 0) {
|
|
delete this;
|
|
}
|
|
return mRefCnt;
|
|
}
|
|
|
|
nsresult
|
|
nsFontMetricsWin :: QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
|
{
|
|
if (NULL == aInstancePtr) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
|
|
*aInstancePtr = NULL;
|
|
|
|
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
|
|
static NS_DEFINE_IID(kClassIID, kIFontMetricsIID);
|
|
if (aIID.Equals(kClassIID)) {
|
|
*aInstancePtr = (void*) this;
|
|
NS_ADDREF_THIS();
|
|
return NS_OK;
|
|
}
|
|
if (aIID.Equals(kISupportsIID)) {
|
|
*aInstancePtr = (void*) ((nsISupports*)this);
|
|
NS_ADDREF_THIS();
|
|
return NS_OK;
|
|
}
|
|
return NS_NOINTERFACE;
|
|
}
|
|
#else
|
|
NS_IMPL_ISUPPORTS(nsFontMetricsWin, kIFontMetricsIID)
|
|
#endif
|
|
|
|
NS_IMETHODIMP
|
|
nsFontMetricsWin :: Init(const nsFont& aFont, nsIDeviceContext *aContext)
|
|
{
|
|
mFont = new nsFont(aFont);
|
|
//don't addref this to avoid circular refs
|
|
mDeviceContext = (nsDeviceContextWin *)aContext;
|
|
RealizeFont();
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsFontMetricsWin :: Destroy()
|
|
{
|
|
mDeviceContext = nsnull;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult nsFontMetricsWin :: GetSpaceWidth(nscoord &aSpaceWidth)
|
|
{
|
|
aSpaceWidth = mSpaceWidth;
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
nsFontMetricsWin::FillLogFont(LOGFONT* logFont, PRInt32 aWeight)
|
|
{
|
|
// 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 = aWeight;
|
|
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
|
|
}
|
|
|
|
#undef CMAP
|
|
#define CMAP (('c') | ('m' << 8) | ('a' << 16) | ('p' << 24))
|
|
#undef HEAD
|
|
#define HEAD (('h') | ('e' << 8) | ('a' << 16) | ('d' << 24))
|
|
#undef LOCA
|
|
#define LOCA (('l') | ('o' << 8) | ('c' << 16) | ('a' << 24))
|
|
#undef NAME
|
|
#define NAME (('n') | ('a' << 8) | ('m' << 16) | ('e' << 24))
|
|
|
|
#undef GET_SHORT
|
|
#define GET_SHORT(p) (((p)[0] << 8) | (p)[1])
|
|
#undef GET_LONG
|
|
#define GET_LONG(p) (((p)[0] << 24) | ((p)[1] << 16) | ((p)[2] << 8) | (p)[3])
|
|
|
|
static PRUint16
|
|
GetGlyph(PRUint16 segCount, PRUint16* endCode, PRUint16* startCode,
|
|
PRUint16* idRangeOffset, PRUint16* idDelta, PRUint8* end, PRUint16 aChar)
|
|
{
|
|
PRUint16 glyph = 0;
|
|
PRUint16 i;
|
|
for (i = 0; i < segCount; i++) {
|
|
if (endCode[i] >= aChar) {
|
|
break;
|
|
}
|
|
}
|
|
PRUint16 startC = startCode[i];
|
|
if (startC <= aChar) {
|
|
if (idRangeOffset[i]) {
|
|
PRUint16* p =
|
|
(idRangeOffset[i]/2 + (aChar - startC) + &idRangeOffset[i]);
|
|
if ((PRUint8*) p < end) {
|
|
if (*p) {
|
|
glyph = idDelta[i] + *p;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
glyph = idDelta[i] + aChar;
|
|
}
|
|
}
|
|
|
|
return glyph;
|
|
}
|
|
|
|
static int
|
|
GetNAME(HDC aDC, nsString* aName)
|
|
{
|
|
DWORD len = GetFontData(aDC, NAME, 0, nsnull, 0);
|
|
if ((len == GDI_ERROR) || (!len)) {
|
|
return 0;
|
|
}
|
|
PRUint8* buf = (PRUint8*) PR_Malloc(len);
|
|
if (!buf) {
|
|
return 0;
|
|
}
|
|
DWORD newLen = GetFontData(aDC, NAME, 0, buf, len);
|
|
if (newLen != len) {
|
|
PR_Free(buf);
|
|
return 0;
|
|
}
|
|
PRUint8* p = buf + 2;
|
|
PRUint16 n = GET_SHORT(p);
|
|
p += 2;
|
|
PRUint16 offset = GET_SHORT(p);
|
|
p += 2;
|
|
PRUint16 i;
|
|
PRUint16 idLength;
|
|
PRUint16 idOffset;
|
|
for (i = 0; i < n; i++) {
|
|
PRUint16 platform = GET_SHORT(p);
|
|
p += 2;
|
|
PRUint16 encoding = GET_SHORT(p);
|
|
p += 4;
|
|
PRUint16 name = GET_SHORT(p);
|
|
p += 2;
|
|
idLength = GET_SHORT(p);
|
|
p += 2;
|
|
idOffset = GET_SHORT(p);
|
|
p += 2;
|
|
// XXX what about symbol? (platform 3, encoding 0)
|
|
if ((platform == 3) && (encoding == 1) && (name == 3)) {
|
|
break;
|
|
}
|
|
}
|
|
if (i == n) {
|
|
PR_Free(buf);
|
|
return 0;
|
|
}
|
|
p = buf + offset + idOffset;
|
|
idLength /= 2;
|
|
for (i = 0; i < idLength; i++) {
|
|
PRUnichar c = GET_SHORT(p);
|
|
p += 2;
|
|
aName->Append(c);
|
|
}
|
|
|
|
PR_Free(buf);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static PLHashNumber
|
|
HashKey(const void* aString)
|
|
{
|
|
return (PLHashNumber)
|
|
nsCRT::HashValue(((const nsString*) aString)->GetUnicode());
|
|
}
|
|
|
|
static PRIntn
|
|
CompareKeys(const void* aStr1, const void* aStr2)
|
|
{
|
|
return nsCRT::strcmp(((const nsString*) aStr1)->GetUnicode(),
|
|
((const nsString*) aStr2)->GetUnicode()) == 0;
|
|
}
|
|
|
|
static int
|
|
GetIndexToLocFormat(HDC aDC)
|
|
{
|
|
PRUint16 indexToLocFormat;
|
|
if (GetFontData(aDC, HEAD, 50, &indexToLocFormat, 2) != 2) {
|
|
return -1;
|
|
}
|
|
if (!indexToLocFormat) {
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static PRUint8*
|
|
GetSpaces(HDC aDC, PRUint32* aMaxGlyph)
|
|
{
|
|
int isLong = GetIndexToLocFormat(aDC);
|
|
if (isLong < 0) {
|
|
return nsnull;
|
|
}
|
|
DWORD len = GetFontData(aDC, LOCA, 0, nsnull, 0);
|
|
if ((len == GDI_ERROR) || (!len)) {
|
|
return nsnull;
|
|
}
|
|
PRUint8* buf = (PRUint8*) PR_Malloc(len);
|
|
if (!buf) {
|
|
return nsnull;
|
|
}
|
|
DWORD newLen = GetFontData(aDC, LOCA, 0, buf, len);
|
|
if (newLen != len) {
|
|
PR_Free(buf);
|
|
return nsnull;
|
|
}
|
|
if (isLong) {
|
|
DWORD longLen = ((len / 4) - 1);
|
|
*aMaxGlyph = longLen;
|
|
PRUint32* longBuf = (PRUint32*) buf;
|
|
for (PRUint32 i = 0; i < longLen; i++) {
|
|
if (longBuf[i] == longBuf[i+1]) {
|
|
buf[i] = 1;
|
|
}
|
|
else {
|
|
buf[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
DWORD shortLen = ((len / 2) - 1);
|
|
*aMaxGlyph = shortLen;
|
|
PRUint16* shortBuf = (PRUint16*) buf;
|
|
for (PRUint16 i = 0; i < shortLen; i++) {
|
|
if (shortBuf[i] == shortBuf[i+1]) {
|
|
buf[i] = 1;
|
|
}
|
|
else {
|
|
buf[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
#undef SET_SPACE
|
|
#define SET_SPACE(c) ADD_GLYPH(spaces, c)
|
|
#undef SHOULD_BE_SPACE
|
|
#define SHOULD_BE_SPACE(c) FONT_HAS_GLYPH(spaces, c)
|
|
|
|
PRUint8*
|
|
nsFontMetricsWin::GetCMAP(HDC aDC)
|
|
{
|
|
static PLHashTable* fontMaps = nsnull;
|
|
static int initialized = 0;
|
|
if (!initialized) {
|
|
initialized = 1;
|
|
fontMaps = PL_NewHashTable(0, HashKey, CompareKeys, nsnull, nsnull,
|
|
nsnull);
|
|
}
|
|
nsString* name = new nsString();
|
|
if (!name) {
|
|
return nsnull;
|
|
}
|
|
PRUint8* map;
|
|
if (GetNAME(aDC, name)) {
|
|
map = (PRUint8*) PL_HashTableLookup(fontMaps, name);
|
|
if (map) {
|
|
delete name;
|
|
return map;
|
|
}
|
|
map = (PRUint8*) PR_Calloc(8192, 1);
|
|
if (!map) {
|
|
delete name;
|
|
return nsnull;
|
|
}
|
|
}
|
|
else {
|
|
// return an empty map, so that we never try this font again
|
|
static PRUint8* emptyMap = nsnull;
|
|
if (!emptyMap) {
|
|
emptyMap = (PRUint8*) PR_Calloc(8192, 1);
|
|
}
|
|
delete name;
|
|
return emptyMap;
|
|
}
|
|
|
|
DWORD len = GetFontData(aDC, CMAP, 0, nsnull, 0);
|
|
if ((len == GDI_ERROR) || (!len)) {
|
|
delete name;
|
|
PR_Free(map);
|
|
return nsnull;
|
|
}
|
|
PRUint8* buf = (PRUint8*) PR_Malloc(len);
|
|
if (!buf) {
|
|
delete name;
|
|
PR_Free(map);
|
|
return nsnull;
|
|
}
|
|
DWORD newLen = GetFontData(aDC, CMAP, 0, buf, len);
|
|
if (newLen != len) {
|
|
PR_Free(buf);
|
|
delete name;
|
|
PR_Free(map);
|
|
return nsnull;
|
|
}
|
|
PRUint8* p = buf + 2;
|
|
PRUint16 n = GET_SHORT(p);
|
|
p += 2;
|
|
PRUint16 i;
|
|
PRUint32 offset;
|
|
for (i = 0; i < n; i++) {
|
|
PRUint16 platformID = GET_SHORT(p);
|
|
p += 2;
|
|
PRUint16 encodingID = GET_SHORT(p);
|
|
p += 2;
|
|
offset = GET_LONG(p);
|
|
p += 4;
|
|
// XXX what about symbol fonts? (platform = 3, encoding = 0)
|
|
if ((platformID == 3) && (encodingID == 1)) {
|
|
break;
|
|
}
|
|
}
|
|
if (i == n) {
|
|
PR_Free(buf);
|
|
delete name;
|
|
PR_Free(map);
|
|
return nsnull;
|
|
}
|
|
p = buf + offset;
|
|
PRUint16 format = GET_SHORT(p);
|
|
if (format != 4) {
|
|
PR_Free(buf);
|
|
delete name;
|
|
PR_Free(map);
|
|
return nsnull;
|
|
}
|
|
PRUint8* end = buf + len;
|
|
|
|
// XXX byte swapping only required for little endian (ifdef?)
|
|
while (p < end) {
|
|
PRUint8 tmp = p[0];
|
|
p[0] = p[1];
|
|
p[1] = tmp;
|
|
p += 2;
|
|
}
|
|
|
|
PRUint16* s = (PRUint16*) (buf + offset);
|
|
PRUint16 segCount = s[3] / 2;
|
|
PRUint16* endCode = &s[7];
|
|
PRUint16* startCode = endCode + segCount + 1;
|
|
PRUint16* idDelta = startCode + segCount;
|
|
PRUint16* idRangeOffset = idDelta + segCount;
|
|
PRUint16* glyphIdArray = idRangeOffset + segCount;
|
|
|
|
static int spacesInitialized = 0;
|
|
static PRUint8 spaces[8192];
|
|
if (!spacesInitialized) {
|
|
spacesInitialized = 1;
|
|
SET_SPACE(0x0020);
|
|
SET_SPACE(0x00A0);
|
|
for (PRUint16 c = 0x2000; c <= 0x200B; c++) {
|
|
SET_SPACE(c);
|
|
}
|
|
SET_SPACE(0x3000);
|
|
}
|
|
PRUint32 maxGlyph;
|
|
PRUint8* isSpace = GetSpaces(aDC, &maxGlyph);
|
|
if (!isSpace) {
|
|
PR_Free(buf);
|
|
delete name;
|
|
PR_Free(map);
|
|
return nsnull;
|
|
}
|
|
|
|
for (i = 0; i < segCount; i++) {
|
|
if (idRangeOffset[i]) {
|
|
PRUint16 startC = startCode[i];
|
|
PRUint16 endC = endCode[i];
|
|
for (PRUint32 c = startC; c <= endC; c++) {
|
|
PRUint16* g =
|
|
(idRangeOffset[i]/2 + (c - startC) + &idRangeOffset[i]);
|
|
if ((PRUint8*) g < end) {
|
|
if (*g) {
|
|
PRUint16 glyph = idDelta[i] + *g;
|
|
if (glyph < maxGlyph) {
|
|
if (isSpace[glyph]) {
|
|
if (SHOULD_BE_SPACE(c)) {
|
|
ADD_GLYPH(map, c);
|
|
}
|
|
}
|
|
else {
|
|
ADD_GLYPH(map, c);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// XXX should we trust this font at all if it does this?
|
|
}
|
|
}
|
|
//printf("0x%04X-0x%04X ", startC, endC);
|
|
}
|
|
else {
|
|
PRUint16 endC = endCode[i];
|
|
for (PRUint32 c = startCode[i]; c <= endC; c++) {
|
|
PRUint16 glyph = idDelta[i] + c;
|
|
if (glyph < maxGlyph) {
|
|
if (isSpace[glyph]) {
|
|
if (SHOULD_BE_SPACE(c)) {
|
|
ADD_GLYPH(map, c);
|
|
}
|
|
}
|
|
else {
|
|
ADD_GLYPH(map, c);
|
|
}
|
|
}
|
|
}
|
|
//printf("0x%04X-0x%04X ", startCode[i], endC);
|
|
}
|
|
}
|
|
//printf("\n");
|
|
|
|
PR_Free(buf);
|
|
PR_Free(isSpace);
|
|
|
|
// XXX check to see if an identical map has already been added to table
|
|
PL_HashTableAdd(fontMaps, name, map);
|
|
|
|
return map;
|
|
}
|
|
|
|
nsFontWin*
|
|
nsFontMetricsWin::LoadFont(HDC aDC, nsString* aName)
|
|
{
|
|
LOGFONT logFont;
|
|
|
|
PRUint16 weightTable = LookForFontWeightTable(aDC, aName);
|
|
PRInt32 weight = GetFontWeight(mFont->weight, weightTable);
|
|
FillLogFont(&logFont, weight);
|
|
|
|
/*
|
|
* XXX we are losing info by converting from Unicode to system code page
|
|
* but we don't really have a choice since CreateFontIndirectW is
|
|
* not supported on Windows 9X (see below) -- erik
|
|
*/
|
|
logFont.lfFaceName[0] = 0;
|
|
WideCharToMultiByte(CP_ACP, 0, aName->GetUnicode(), aName->Length() + 1,
|
|
logFont.lfFaceName, sizeof(logFont.lfFaceName), nsnull, nsnull);
|
|
|
|
/*
|
|
* According to http://msdn.microsoft.com/library/
|
|
* CreateFontIndirectW is only supported on NT/2000
|
|
*/
|
|
HFONT hfont = ::CreateFontIndirect(&logFont);
|
|
|
|
if (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 {
|
|
::DeleteObject(hfont);
|
|
return nsnull;
|
|
}
|
|
}
|
|
nsFontWin* font = new nsFontWin;
|
|
if (!font) {
|
|
::DeleteObject(hfont);
|
|
return nsnull;
|
|
}
|
|
mLoadedFonts[mLoadedFontsCount++] = font;
|
|
HFONT oldFont = (HFONT) ::SelectObject(aDC, (HGDIOBJ) hfont);
|
|
font->font = hfont;
|
|
font->map = GetCMAP(aDC);
|
|
if (!font->map) {
|
|
mLoadedFontsCount--;
|
|
::SelectObject(aDC, (HGDIOBJ) oldFont);
|
|
::DeleteObject(hfont);
|
|
return nsnull;
|
|
}
|
|
::SelectObject(aDC, (HGDIOBJ) oldFont);
|
|
|
|
return font;
|
|
}
|
|
|
|
return nsnull;
|
|
}
|
|
|
|
static int CALLBACK enumProc(const LOGFONT* logFont, const TEXTMETRIC* metrics,
|
|
DWORD fontType, LPARAM closure)
|
|
{
|
|
// XXX do we really want to ignore non-TrueType fonts?
|
|
if (!(fontType & TRUETYPE_FONTTYPE)) {
|
|
//printf("rejecting %s\n", logFont->lfFaceName);
|
|
return 1;
|
|
}
|
|
|
|
// XXX ignore vertical fonts
|
|
if (logFont->lfFaceName[0] == '@') {
|
|
return 1;
|
|
}
|
|
|
|
// XXX make this smarter: don't add font to list if we already have a font
|
|
// with the same font signature -- erik
|
|
if (nsFontMetricsWin::gGlobalFontsCount == gGlobalFontsAlloc) {
|
|
int newSize = 2 * (gGlobalFontsAlloc ? gGlobalFontsAlloc : 1);
|
|
nsGlobalFont* newPointer = (nsGlobalFont*)
|
|
PR_Realloc(nsFontMetricsWin::gGlobalFonts, newSize*sizeof(nsGlobalFont));
|
|
if (newPointer) {
|
|
nsFontMetricsWin::gGlobalFonts = newPointer;
|
|
gGlobalFontsAlloc = newSize;
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
}
|
|
nsGlobalFont* font =
|
|
&nsFontMetricsWin::gGlobalFonts[nsFontMetricsWin::gGlobalFontsCount++];
|
|
|
|
PRUnichar name[LF_FACESIZE];
|
|
name[0] = 0;
|
|
MultiByteToWideChar(CP_ACP, 0, logFont->lfFaceName,
|
|
strlen(logFont->lfFaceName) + 1, name, sizeof(name)/sizeof(name[0]));
|
|
font->name = new nsString(name);
|
|
if (!font->name) {
|
|
nsFontMetricsWin::gGlobalFontsCount--;
|
|
return 0;
|
|
}
|
|
font->map = nsnull;
|
|
font->logFont = *logFont;
|
|
font->skip = 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
nsGlobalFont*
|
|
nsFontMetricsWin::InitializeGlobalFonts(HDC aDC)
|
|
{
|
|
static int gInitialized = 0;
|
|
if (!gInitialized) {
|
|
gInitialized = 1;
|
|
LOGFONT logFont;
|
|
logFont.lfCharSet = DEFAULT_CHARSET;
|
|
logFont.lfFaceName[0] = 0;
|
|
logFont.lfPitchAndFamily = 0;
|
|
|
|
/*
|
|
* msdn.microsoft.com/library states that
|
|
* EnumFontFamiliesExW is only on NT/2000
|
|
*/
|
|
EnumFontFamiliesEx(aDC, &logFont, enumProc, nsnull, 0);
|
|
}
|
|
|
|
return gGlobalFonts;
|
|
}
|
|
|
|
int
|
|
nsFontMetricsWin::SameAsPreviousMap(int aIndex)
|
|
{
|
|
for (int i = 0; i < aIndex; i++) {
|
|
if (!gGlobalFonts[i].skip) {
|
|
if (gGlobalFonts[i].map == gGlobalFonts[aIndex].map) {
|
|
gGlobalFonts[aIndex].skip = 1;
|
|
return 1;
|
|
}
|
|
PRUint8* map1 = gGlobalFonts[i].map;
|
|
PRUint8* map2 = gGlobalFonts[aIndex].map;
|
|
int j;
|
|
for (j = 0; j < 8192; j++) {
|
|
if (map1[j] != map2[j]) {
|
|
break;
|
|
}
|
|
}
|
|
if (j == 8192) {
|
|
gGlobalFonts[aIndex].skip = 1;
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
nsFontWin*
|
|
nsFontMetricsWin::FindGlobalFont(HDC aDC, PRUnichar c)
|
|
{
|
|
if (!gGlobalFonts) {
|
|
if (!InitializeGlobalFonts(aDC)) {
|
|
return nsnull;
|
|
}
|
|
}
|
|
for (int i = 0; i < gGlobalFontsCount; i++) {
|
|
if (!gGlobalFonts[i].skip) {
|
|
if (!gGlobalFonts[i].map) {
|
|
HFONT font = ::CreateFontIndirect(&gGlobalFonts[i].logFont);
|
|
if (!font) {
|
|
continue;
|
|
}
|
|
HFONT oldFont = (HFONT) ::SelectObject(aDC, font);
|
|
gGlobalFonts[i].map = GetCMAP(aDC);
|
|
::SelectObject(aDC, oldFont);
|
|
::DeleteObject(font);
|
|
if (!gGlobalFonts[i].map) {
|
|
continue;
|
|
}
|
|
if (SameAsPreviousMap(i)) {
|
|
continue;
|
|
}
|
|
}
|
|
if (FONT_HAS_GLYPH(gGlobalFonts[i].map, c)) {
|
|
return LoadFont(aDC, gGlobalFonts[i].name);
|
|
}
|
|
}
|
|
}
|
|
|
|
return nsnull;
|
|
}
|
|
|
|
//------------ Font weight utilities -------------------
|
|
|
|
// XXX: Should not need to store all these in a hash table.
|
|
// We need to restructure the font management code so there is one
|
|
// global place to cache font info. As the code is right now, there
|
|
// are two separate places that font info is stored, in the gFamilyNames
|
|
// hash table and the global font array. There are also cases where the
|
|
// font info is not cached at all.
|
|
// I initially tried to add the font weight info to those two places, but
|
|
// it was messy. In addition I discovered another code path which does not
|
|
// cache anything.
|
|
|
|
// Entry for storing hash table. Store as a single
|
|
// entry rather than doing a separate allocation for the
|
|
// fontName and weight.
|
|
|
|
|
|
typedef struct nsFontWeightEntry
|
|
{
|
|
nsString mFontName;
|
|
PRUint16 mWeightTable; // Each bit indicates the availability of a font weight.
|
|
} nsFontWeightEntry;
|
|
|
|
|
|
static PLHashNumber
|
|
HashKeyFontWeight(const void* aFontWeightEntry)
|
|
{
|
|
const nsString* string = &((const nsFontWeightEntry*) aFontWeightEntry)->mFontName;
|
|
return (PLHashNumber)
|
|
nsCRT::HashValue(string->GetUnicode());
|
|
}
|
|
|
|
static PRIntn
|
|
CompareKeysFontWeight(const void* aFontWeightEntry1, const void* aFontWeightEntry2)
|
|
{
|
|
const nsString* str1 = &((const nsFontWeightEntry*) aFontWeightEntry1)->mFontName;
|
|
const nsString* str2 = &((const nsFontWeightEntry*) aFontWeightEntry2)->mFontName;
|
|
|
|
return nsCRT::strcmp(str1->GetUnicode(), str2->GetUnicode()) == 0;
|
|
}
|
|
|
|
|
|
// Store the font weight as a bit in the aWeightTable
|
|
void nsFontMetricsWin::SetFontWeight(PRInt32 aWeight, PRUint16* aWeightTable) {
|
|
NS_ASSERTION((aWeight >= 0) && (aWeight <= 9), "Invalid font weight passed");
|
|
*aWeightTable |= 1 << (aWeight - 1);
|
|
}
|
|
|
|
// Check to see if a font weight is available within the font weight table
|
|
PRBool nsFontMetricsWin::IsFontWeightAvailable(PRInt32 aWeight, PRUint16 aWeightTable) {
|
|
PRInt32 normalizedWeight = aWeight / 100;
|
|
NS_ASSERTION((aWeight >= 100) && (aWeight <= 900), "Invalid font weight passed");
|
|
PRUint16 bitwiseWeight = 1 << (normalizedWeight - 1);
|
|
if (bitwiseWeight & aWeightTable) {
|
|
return PR_TRUE;
|
|
}
|
|
else {
|
|
return PR_FALSE;
|
|
}
|
|
}
|
|
|
|
static int CALLBACK nsFontWeightCallback(const LOGFONT* logFont, const TEXTMETRIC * metrics,
|
|
DWORD fontType, LPARAM closure)
|
|
{
|
|
// printf("Name %s Log font sizes %d\n",logFont->lfFaceName,logFont->lfWeight);
|
|
if (!(fontType & TRUETYPE_FONTTYPE)) {
|
|
// printf("rejecting %s\n", logFont->lfFaceName);
|
|
return TRUE;
|
|
}
|
|
|
|
if (NULL != metrics) {
|
|
int pos = metrics->tmWeight / 100;
|
|
// Set a bit to indicate the font weight is available
|
|
nsFontMetricsWin::SetFontWeight(metrics->tmWeight / 100, (PRUint16*)closure);
|
|
}
|
|
|
|
return TRUE; // Keep looking for more weights.
|
|
}
|
|
|
|
PRUint16
|
|
nsFontMetricsWin::GetFontWeightTable(HDC aDC, nsString* aFontName) {
|
|
|
|
// Look for all of the weights for a given font.
|
|
LOGFONT logFont;
|
|
logFont.lfCharSet = DEFAULT_CHARSET;
|
|
aFontName->ToCString(logFont.lfFaceName, LF_FACESIZE);
|
|
logFont.lfPitchAndFamily = 0;
|
|
|
|
PRUint16 weights = 0;
|
|
::EnumFontFamiliesEx(aDC, &logFont, nsFontWeightCallback, (LPARAM)&weights, 0);
|
|
// printf("font weights for %s dec %d hex %x \n", logFont.lfFaceName, weights, weights);
|
|
return weights;
|
|
}
|
|
|
|
|
|
// Calculate the closest font weight. This is necessary because we need to
|
|
// control the mapping of logical font weight to available weight to handle both CSS2
|
|
// default algorithm + the case where a font weight is choosen which is not available then made
|
|
// bolder or lighter. (e.g. a font weight of 200 is choosen but not available
|
|
// on the system so a weight of 400 is used instead when mapping to a physical font.
|
|
// If the font is made bolder we need to know that a font weight of 400 was choosen, so
|
|
// we can select a font weight which is greater.
|
|
PRInt32
|
|
nsFontMetricsWin::GetClosestWeight(PRInt32 aWeight, PRUint16 aWeightTable)
|
|
{
|
|
// Algorithm used From CSS2 section 15.5.1 Mapping font weight values to font names
|
|
PRInt32 newWeight = aWeight;
|
|
// Check for exact match
|
|
if ((aWeight > 0) && (nsFontMetricsWin::IsFontWeightAvailable(aWeight, aWeightTable))) {
|
|
return aWeight;
|
|
}
|
|
|
|
// Find lighter and darker weights to be used later.
|
|
|
|
// First look for lighter
|
|
PRInt32 lighterWeight = 0;
|
|
PRInt32 proposedLighterWeight = PR_MAX(0, aWeight - 100);
|
|
|
|
PRBool done = PR_FALSE;
|
|
while ((PR_FALSE == done) && (proposedLighterWeight >= 100)) {
|
|
if (nsFontMetricsWin::IsFontWeightAvailable(proposedLighterWeight, aWeightTable)) {
|
|
lighterWeight = proposedLighterWeight;
|
|
done = PR_TRUE;
|
|
} else {
|
|
proposedLighterWeight-= 100;
|
|
}
|
|
}
|
|
|
|
// Now look for darker
|
|
PRInt32 darkerWeight = 0;
|
|
done = PR_FALSE;
|
|
PRInt32 proposedDarkerWeight = PR_MIN(aWeight + 100, 900);
|
|
while ((PR_FALSE == done) && (proposedDarkerWeight <= 900)) {
|
|
if (nsFontMetricsWin::IsFontWeightAvailable(proposedDarkerWeight, aWeightTable)) {
|
|
darkerWeight = proposedDarkerWeight;
|
|
done = PR_TRUE;
|
|
} else {
|
|
proposedDarkerWeight+= 100;
|
|
}
|
|
}
|
|
|
|
// From CSS2 section 15.5.1
|
|
|
|
// If '500' is unassigned, it will be
|
|
// assigned the same font as '400'.
|
|
// If any of '300', '200', or '100' remains unassigned, it is
|
|
// assigned to the next lighter assigned keyword, if any, or
|
|
// the next darker otherwise.
|
|
// What about if the desired weight is 500 and 400 is unassigned?.
|
|
// This is not inlcluded in the CSS spec so I'll treat it in a consistent
|
|
// manner with unassigned '300', '200' and '100'
|
|
|
|
|
|
if (aWeight <= 500) {
|
|
if (0 != lighterWeight) {
|
|
return lighterWeight;
|
|
}
|
|
else {
|
|
return darkerWeight;
|
|
}
|
|
|
|
} else {
|
|
|
|
// Automatically chose the bolder weight if the next lighter weight
|
|
// makes it normal. (i.e goes over the normal to bold threshold.)
|
|
|
|
// From CSS2 section 15.5.1
|
|
// if any of the values '600', '700', '800', or '900' remains unassigned,
|
|
// they are assigned to the same face as the next darker assigned keyword,
|
|
// if any, or the next lighter one otherwise.
|
|
|
|
if (0 != darkerWeight) {
|
|
return darkerWeight;
|
|
} else {
|
|
return lighterWeight;
|
|
}
|
|
}
|
|
|
|
return aWeight;
|
|
}
|
|
|
|
|
|
|
|
PRInt32
|
|
nsFontMetricsWin::GetBolderWeight(PRInt32 aWeight, PRInt32 aDistance, PRUint16 aWeightTable)
|
|
{
|
|
PRInt32 newWeight = aWeight;
|
|
|
|
PRInt32 proposedWeight = aWeight + 100; // Start 1 bolder than the current
|
|
for (PRInt32 j = 0; j < aDistance; j++) {
|
|
PRBool aFoundAWeight = PR_FALSE;
|
|
while ((proposedWeight <= NS_MAX_FONT_WEIGHT) && (PR_FALSE == aFoundAWeight)) {
|
|
if (nsFontMetricsWin::IsFontWeightAvailable(proposedWeight, aWeightTable)) {
|
|
//
|
|
newWeight = proposedWeight;
|
|
aFoundAWeight = PR_TRUE;
|
|
}
|
|
proposedWeight+=100;
|
|
}
|
|
}
|
|
|
|
return newWeight;
|
|
}
|
|
|
|
PRInt32
|
|
nsFontMetricsWin::GetLighterWeight(PRInt32 aWeight, PRInt32 aDistance, PRUint16 aWeightTable)
|
|
{
|
|
PRInt32 newWeight = aWeight;
|
|
|
|
PRInt32 proposedWeight = aWeight - 100; // Start 1 lighter than the current
|
|
for (PRInt32 j = 0; j < aDistance; j++) {
|
|
PRBool aFoundAWeight = PR_FALSE;
|
|
while ((proposedWeight >= NS_MIN_FONT_WEIGHT) && (PR_FALSE == aFoundAWeight)) {
|
|
if (nsFontMetricsWin::IsFontWeightAvailable(proposedWeight, aWeightTable)) {
|
|
//
|
|
newWeight = proposedWeight;
|
|
aFoundAWeight = PR_TRUE;
|
|
}
|
|
proposedWeight-=100;
|
|
}
|
|
}
|
|
|
|
return newWeight;
|
|
}
|
|
|
|
|
|
PRInt32
|
|
nsFontMetricsWin::GetFontWeight(PRInt32 aWeight, PRUint16 aWeightTable) {
|
|
|
|
// The remainder is used to determine whether to make
|
|
// the font lighter or bolder
|
|
|
|
PRInt32 remainder = aWeight % 100;
|
|
PRInt32 normalizedWeight = aWeight / 100;
|
|
PRInt32 selectedWeight = 0;
|
|
|
|
// No remainder, so get the closest weight
|
|
if (remainder == 0) {
|
|
selectedWeight = GetClosestWeight(aWeight, aWeightTable);
|
|
} else {
|
|
|
|
NS_ASSERTION((remainder < 10) || (remainder > 90), "Invalid bolder or lighter value");
|
|
|
|
if (remainder < 10) {
|
|
PRInt32 weight = GetClosestWeight(normalizedWeight * 100, aWeightTable);
|
|
selectedWeight = GetBolderWeight(weight, remainder, aWeightTable);
|
|
} else {
|
|
// Have to add back 1 for the lighter weight since aWeight really refers to the
|
|
// whole number. eq. 398 really means 2 lighter than font weight 400.
|
|
PRInt32 weight = GetClosestWeight((normalizedWeight + 1) * 100, aWeightTable);
|
|
selectedWeight = GetLighterWeight(weight, 100-remainder, aWeightTable);
|
|
}
|
|
}
|
|
|
|
// printf("XXX Input weight %d output weight %d weight table hex %x\n", aWeight, selectedWeight, aWeightTable);
|
|
return selectedWeight;
|
|
}
|
|
|
|
|
|
PRUint16
|
|
nsFontMetricsWin::LookForFontWeightTable(HDC aDC, nsString* aName)
|
|
{
|
|
static int gInitializedFontWeights = 0;
|
|
|
|
// Initialize the font weight table if need be.
|
|
if (!gInitializedFontWeights) {
|
|
gInitializedFontWeights = 1;
|
|
gFontWeights = PL_NewHashTable(0, HashKeyFontWeight, CompareKeysFontWeight, nsnull, nsnull,
|
|
nsnull);
|
|
if (!gFontWeights) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// Use lower case name for hash table searches. This eliminates
|
|
// keeping multiple font weights entries when the font name varies
|
|
// only by case.
|
|
nsAutoString low = *aName;
|
|
low.ToLowerCase();
|
|
|
|
// See if the font weight has already been computed.
|
|
nsFontWeightEntry searchEntry;
|
|
searchEntry.mFontName = low;
|
|
searchEntry.mWeightTable = 0;
|
|
|
|
nsFontWeightEntry* weightEntry = (nsFontWeightEntry*)PL_HashTableLookup(gFontWeights, &searchEntry);
|
|
if (nsnull != weightEntry) {
|
|
// printf("Re-use weight entry\n");
|
|
return weightEntry->mWeightTable;
|
|
}
|
|
|
|
// Hasn't been computed, so need to compute and store it.
|
|
PRUint16 weightTable = GetFontWeightTable(aDC, aName);
|
|
// printf("Compute font weight %d\n", weightTable);
|
|
|
|
// Store it in font weight HashTable.
|
|
nsFontWeightEntry* fontWeightEntry = new nsFontWeightEntry;
|
|
fontWeightEntry->mFontName = low;
|
|
fontWeightEntry->mWeightTable = weightTable;
|
|
PL_HashTableAdd(gFontWeights, fontWeightEntry, fontWeightEntry);
|
|
|
|
return weightTable;
|
|
}
|
|
|
|
|
|
// ------------ End of font weight utilities
|
|
|
|
typedef struct nsFontFamilyName
|
|
{
|
|
char* mName;
|
|
char* mWinName;
|
|
} nsFontFamilyName;
|
|
|
|
static nsFontFamilyName gFamilyNameTable[] =
|
|
{
|
|
{ "times", "Times New Roman" },
|
|
{ "times roman", "Times New Roman" },
|
|
{ "times new roman", "Times New Roman" },
|
|
{ "arial", "Arial" },
|
|
{ "helvetica", "Arial" },
|
|
{ "courier", "Courier New" },
|
|
{ "courier new", "Courier New" },
|
|
|
|
{ "serif", "Times New Roman" },
|
|
{ "sans-serif", "Arial" },
|
|
{ "fantasy", "Arial" },
|
|
{ "cursive", "Arial" },
|
|
{ "monospace", "Courier New" },
|
|
{ "-moz-fixed", "Courier New" },
|
|
|
|
{ nsnull, nsnull }
|
|
};
|
|
|
|
PLHashTable*
|
|
nsFontMetricsWin::InitializeFamilyNames(void)
|
|
{
|
|
static int gInitialized = 0;
|
|
if (!gInitialized) {
|
|
gInitialized = 1;
|
|
gFamilyNames = PL_NewHashTable(0, HashKey, CompareKeys, nsnull, nsnull,
|
|
nsnull);
|
|
if (!gFamilyNames) {
|
|
return nsnull;
|
|
}
|
|
nsFontFamilyName* f = gFamilyNameTable;
|
|
while (f->mName) {
|
|
nsString* name = new nsString(f->mName);
|
|
nsString* winName = new nsString(f->mWinName);
|
|
if (name && winName) {
|
|
PL_HashTableAdd(gFamilyNames, name, (void*) winName);
|
|
}
|
|
f++;
|
|
}
|
|
}
|
|
|
|
return gFamilyNames;
|
|
}
|
|
|
|
nsFontWin*
|
|
nsFontMetricsWin::FindLocalFont(HDC aDC, PRUnichar aChar)
|
|
{
|
|
if (!gFamilyNames) {
|
|
if (!InitializeFamilyNames()) {
|
|
return nsnull;
|
|
}
|
|
}
|
|
|
|
while (mFontsIndex < mFontsCount) {
|
|
nsString* name = &mFonts[mFontsIndex++];
|
|
nsString* low = new nsString(*name);
|
|
if (low) {
|
|
low->ToLowerCase();
|
|
nsString* winName = (nsString*) PL_HashTableLookup(gFamilyNames, low);
|
|
delete low;
|
|
if (!winName) {
|
|
winName = name;
|
|
}
|
|
nsFontWin* font = LoadFont(aDC, winName);
|
|
if (font && FONT_HAS_GLYPH(font->map, aChar)) {
|
|
return font;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nsnull;
|
|
}
|
|
|
|
nsFontWin*
|
|
nsFontMetricsWin::FindFont(HDC aDC, PRUnichar aChar)
|
|
{
|
|
nsFontWin* font = FindLocalFont(aDC, aChar);
|
|
if (!font) {
|
|
font = FindGlobalFont(aDC, aChar);
|
|
}
|
|
|
|
return font;
|
|
}
|
|
|
|
static PRBool
|
|
FontEnumCallback(const nsString& aFamily, PRBool aGeneric, void *aData)
|
|
{
|
|
nsFontMetricsWin* metrics = (nsFontMetricsWin*) aData;
|
|
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 PR_FALSE; // stop
|
|
}
|
|
}
|
|
metrics->mFonts[metrics->mFontsCount++].SetString(aFamily.GetUnicode());
|
|
|
|
if (aGeneric) {
|
|
return PR_FALSE; // stop
|
|
}
|
|
|
|
return PR_TRUE; // don't stop
|
|
}
|
|
|
|
/** ---------------------------------------------------
|
|
* See documentation in nsFontMetricsWin.h
|
|
* @update 05/28/99 dwc
|
|
*/
|
|
void
|
|
nsFontMetricsWin::RealizeFont()
|
|
{
|
|
HWND win = NULL;
|
|
HDC dc = NULL;
|
|
HDC dc1 = NULL;
|
|
|
|
|
|
if (NULL != mDeviceContext->mDC){
|
|
// XXX - DC If we are printing, we need to get the printer HDC and a screen HDC
|
|
// The screen HDC is because there seems to be a bug or requirment that the
|
|
// GetFontData() method call have a screen HDC, some printers HDC's return nothing
|
|
// thats will give us bad font data, and break us.
|
|
dc = mDeviceContext->mDC;
|
|
win = (HWND)mDeviceContext->mWidget;
|
|
dc1 = ::GetDC(win);
|
|
} else {
|
|
// Find font metrics and character widths
|
|
win = (HWND)mDeviceContext->mWidget;
|
|
dc = ::GetDC(win);
|
|
dc1 = dc;
|
|
}
|
|
|
|
mFont->EnumerateFamilies(FontEnumCallback, this);
|
|
|
|
nsFontWin* font = FindFont(dc1, 'a');
|
|
if (!font) {
|
|
return;
|
|
}
|
|
mFontHandle = font->font;
|
|
|
|
HFONT oldfont = (HFONT)::SelectObject(dc, (HGDIOBJ) mFontHandle);
|
|
|
|
// Get font metrics
|
|
float dev2app;
|
|
mDeviceContext->GetDevUnitsToAppUnits(dev2app);
|
|
OUTLINETEXTMETRIC oMetrics;
|
|
TEXTMETRIC& metrics = oMetrics.otmTextMetrics;
|
|
nscoord onePixel = NSToCoordRound(1 * dev2app);
|
|
|
|
if (0 < ::GetOutlineTextMetrics(dc, sizeof(oMetrics), &oMetrics)) {
|
|
// mXHeight = NSToCoordRound(oMetrics.otmsXHeight * dev2app); XXX not really supported on windows
|
|
mXHeight = NSToCoordRound((float)metrics.tmAscent * dev2app * 0.50f); // 50% of ascent, best guess for true type
|
|
mSuperscriptOffset = NSToCoordRound(oMetrics.otmptSuperscriptOffset.y * dev2app);
|
|
mSubscriptOffset = NSToCoordRound(oMetrics.otmptSubscriptOffset.y * dev2app);
|
|
|
|
mStrikeoutSize = MAX(onePixel, NSToCoordRound(oMetrics.otmsStrikeoutSize * dev2app));
|
|
mStrikeoutOffset = NSToCoordRound(oMetrics.otmsStrikeoutPosition * dev2app);
|
|
mUnderlineSize = MAX(onePixel, NSToCoordRound(oMetrics.otmsUnderscoreSize * dev2app));
|
|
mUnderlineOffset = NSToCoordRound(oMetrics.otmsUnderscorePosition * dev2app);
|
|
}
|
|
else {
|
|
// Make a best-effort guess at extended metrics
|
|
// this is based on general typographic guidelines
|
|
::GetTextMetrics(dc, &metrics);
|
|
mXHeight = NSToCoordRound((float)metrics.tmAscent * dev2app * 0.56f); // 56% of ascent, best guess for non-true type
|
|
mSuperscriptOffset = mXHeight; // XXX temporary code!
|
|
mSubscriptOffset = mXHeight; // XXX temporary code!
|
|
|
|
mStrikeoutSize = onePixel; // XXX this is a guess
|
|
mStrikeoutOffset = NSToCoordRound(mXHeight / 2.0f); // 50% of xHeight
|
|
mUnderlineSize = onePixel; // XXX this is a guess
|
|
mUnderlineOffset = -NSToCoordRound((float)metrics.tmDescent * dev2app * 0.30f); // 30% of descent
|
|
}
|
|
|
|
mHeight = NSToCoordRound(metrics.tmHeight * dev2app);
|
|
mAscent = NSToCoordRound(metrics.tmAscent * dev2app);
|
|
mDescent = NSToCoordRound(metrics.tmDescent * dev2app);
|
|
mLeading = NSToCoordRound(metrics.tmInternalLeading * dev2app);
|
|
mMaxAscent = NSToCoordRound(metrics.tmAscent * dev2app);
|
|
mMaxDescent = NSToCoordRound(metrics.tmDescent * dev2app);
|
|
mMaxAdvance = NSToCoordRound(metrics.tmMaxCharWidth * dev2app);
|
|
|
|
// Cache the width of a single space.
|
|
SIZE size;
|
|
::GetTextExtentPoint32(dc, " ", 1, &size);
|
|
mSpaceWidth = NSToCoordRound(size.cx * dev2app);
|
|
|
|
::SelectObject(dc, oldfont);
|
|
|
|
if (NULL == mDeviceContext->mDC){
|
|
::ReleaseDC(win, dc);
|
|
} else {
|
|
::ReleaseDC(win,dc1);
|
|
}
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsFontMetricsWin :: GetXHeight(nscoord& aResult)
|
|
{
|
|
aResult = mXHeight;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsFontMetricsWin :: GetSuperscriptOffset(nscoord& aResult)
|
|
{
|
|
aResult = mSuperscriptOffset;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsFontMetricsWin :: GetSubscriptOffset(nscoord& aResult)
|
|
{
|
|
aResult = mSubscriptOffset;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsFontMetricsWin :: GetStrikeout(nscoord& aOffset, nscoord& aSize)
|
|
{
|
|
aOffset = mStrikeoutOffset;
|
|
aSize = mStrikeoutSize;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsFontMetricsWin :: GetUnderline(nscoord& aOffset, nscoord& aSize)
|
|
{
|
|
aOffset = mUnderlineOffset;
|
|
aSize = mUnderlineSize;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsFontMetricsWin :: GetHeight(nscoord &aHeight)
|
|
{
|
|
aHeight = mHeight;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsFontMetricsWin :: GetLeading(nscoord &aLeading)
|
|
{
|
|
aLeading = mLeading;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsFontMetricsWin :: GetMaxAscent(nscoord &aAscent)
|
|
{
|
|
aAscent = mMaxAscent;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsFontMetricsWin :: GetMaxDescent(nscoord &aDescent)
|
|
{
|
|
aDescent = mMaxDescent;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsFontMetricsWin :: GetMaxAdvance(nscoord &aAdvance)
|
|
{
|
|
aAdvance = mMaxAdvance;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsFontMetricsWin :: GetFont(const nsFont *&aFont)
|
|
{
|
|
aFont = mFont;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsFontMetricsWin::GetFontHandle(nsFontHandle &aHandle)
|
|
{
|
|
aHandle = mFontHandle;
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
// The following is a workaround for a Japanese Windows 95 problem.
|
|
|
|
PRUint8 bitToCharSet[64] =
|
|
{
|
|
/*00*/ ANSI_CHARSET,
|
|
/*01*/ EASTEUROPE_CHARSET,
|
|
/*02*/ RUSSIAN_CHARSET,
|
|
/*03*/ GREEK_CHARSET,
|
|
/*04*/ TURKISH_CHARSET,
|
|
/*05*/ HEBREW_CHARSET,
|
|
/*06*/ ARABIC_CHARSET,
|
|
/*07*/ BALTIC_CHARSET,
|
|
/*08*/ DEFAULT_CHARSET,
|
|
/*09*/ DEFAULT_CHARSET,
|
|
/*10*/ DEFAULT_CHARSET,
|
|
/*11*/ DEFAULT_CHARSET,
|
|
/*12*/ DEFAULT_CHARSET,
|
|
/*13*/ DEFAULT_CHARSET,
|
|
/*14*/ DEFAULT_CHARSET,
|
|
/*15*/ DEFAULT_CHARSET,
|
|
/*16*/ THAI_CHARSET,
|
|
/*17*/ SHIFTJIS_CHARSET,
|
|
/*18*/ GB2312_CHARSET,
|
|
/*19*/ HANGEUL_CHARSET,
|
|
/*20*/ CHINESEBIG5_CHARSET,
|
|
/*21*/ JOHAB_CHARSET,
|
|
/*22*/ DEFAULT_CHARSET,
|
|
/*23*/ DEFAULT_CHARSET,
|
|
/*24*/ DEFAULT_CHARSET,
|
|
/*25*/ DEFAULT_CHARSET,
|
|
/*26*/ DEFAULT_CHARSET,
|
|
/*27*/ DEFAULT_CHARSET,
|
|
/*28*/ DEFAULT_CHARSET,
|
|
/*29*/ DEFAULT_CHARSET,
|
|
/*30*/ DEFAULT_CHARSET,
|
|
/*31*/ DEFAULT_CHARSET,
|
|
/*32*/ DEFAULT_CHARSET,
|
|
/*33*/ DEFAULT_CHARSET,
|
|
/*34*/ DEFAULT_CHARSET,
|
|
/*35*/ DEFAULT_CHARSET,
|
|
/*36*/ DEFAULT_CHARSET,
|
|
/*37*/ DEFAULT_CHARSET,
|
|
/*38*/ DEFAULT_CHARSET,
|
|
/*39*/ DEFAULT_CHARSET,
|
|
/*40*/ DEFAULT_CHARSET,
|
|
/*41*/ DEFAULT_CHARSET,
|
|
/*42*/ DEFAULT_CHARSET,
|
|
/*43*/ DEFAULT_CHARSET,
|
|
/*44*/ DEFAULT_CHARSET,
|
|
/*45*/ DEFAULT_CHARSET,
|
|
/*46*/ DEFAULT_CHARSET,
|
|
/*47*/ DEFAULT_CHARSET,
|
|
/*48*/ DEFAULT_CHARSET,
|
|
/*49*/ DEFAULT_CHARSET,
|
|
/*50*/ DEFAULT_CHARSET,
|
|
/*51*/ DEFAULT_CHARSET,
|
|
/*52*/ DEFAULT_CHARSET,
|
|
/*53*/ DEFAULT_CHARSET,
|
|
/*54*/ DEFAULT_CHARSET,
|
|
/*55*/ DEFAULT_CHARSET,
|
|
/*56*/ DEFAULT_CHARSET,
|
|
/*57*/ DEFAULT_CHARSET,
|
|
/*58*/ DEFAULT_CHARSET,
|
|
/*59*/ DEFAULT_CHARSET,
|
|
/*60*/ DEFAULT_CHARSET,
|
|
/*61*/ DEFAULT_CHARSET,
|
|
/*62*/ DEFAULT_CHARSET,
|
|
/*63*/ DEFAULT_CHARSET
|
|
};
|
|
|
|
enum nsCharSet
|
|
{
|
|
eCharSet_DEFAULT = 0,
|
|
eCharSet_ANSI,
|
|
eCharSet_EASTEUROPE,
|
|
eCharSet_RUSSIAN,
|
|
eCharSet_GREEK,
|
|
eCharSet_TURKISH,
|
|
eCharSet_HEBREW,
|
|
eCharSet_ARABIC,
|
|
eCharSet_BALTIC,
|
|
eCharSet_THAI,
|
|
eCharSet_SHIFTJIS,
|
|
eCharSet_GB2312,
|
|
eCharSet_HANGEUL,
|
|
eCharSet_CHINESEBIG5,
|
|
eCharSet_JOHAB,
|
|
eCharSet_COUNT
|
|
};
|
|
|
|
static nsCharSet gCharSetToIndex[256] =
|
|
{
|
|
/* 000 */ eCharSet_ANSI,
|
|
/* 001 */ eCharSet_DEFAULT,
|
|
/* 002 */ eCharSet_DEFAULT, // SYMBOL
|
|
/* 003 */ eCharSet_DEFAULT,
|
|
/* 004 */ eCharSet_DEFAULT,
|
|
/* 005 */ eCharSet_DEFAULT,
|
|
/* 006 */ eCharSet_DEFAULT,
|
|
/* 007 */ eCharSet_DEFAULT,
|
|
/* 008 */ eCharSet_DEFAULT,
|
|
/* 009 */ eCharSet_DEFAULT,
|
|
/* 010 */ eCharSet_DEFAULT,
|
|
/* 011 */ eCharSet_DEFAULT,
|
|
/* 012 */ eCharSet_DEFAULT,
|
|
/* 013 */ eCharSet_DEFAULT,
|
|
/* 014 */ eCharSet_DEFAULT,
|
|
/* 015 */ eCharSet_DEFAULT,
|
|
/* 016 */ eCharSet_DEFAULT,
|
|
/* 017 */ eCharSet_DEFAULT,
|
|
/* 018 */ eCharSet_DEFAULT,
|
|
/* 019 */ eCharSet_DEFAULT,
|
|
/* 020 */ eCharSet_DEFAULT,
|
|
/* 021 */ eCharSet_DEFAULT,
|
|
/* 022 */ eCharSet_DEFAULT,
|
|
/* 023 */ eCharSet_DEFAULT,
|
|
/* 024 */ eCharSet_DEFAULT,
|
|
/* 025 */ eCharSet_DEFAULT,
|
|
/* 026 */ eCharSet_DEFAULT,
|
|
/* 027 */ eCharSet_DEFAULT,
|
|
/* 028 */ eCharSet_DEFAULT,
|
|
/* 029 */ eCharSet_DEFAULT,
|
|
/* 030 */ eCharSet_DEFAULT,
|
|
/* 031 */ eCharSet_DEFAULT,
|
|
/* 032 */ eCharSet_DEFAULT,
|
|
/* 033 */ eCharSet_DEFAULT,
|
|
/* 034 */ eCharSet_DEFAULT,
|
|
/* 035 */ eCharSet_DEFAULT,
|
|
/* 036 */ eCharSet_DEFAULT,
|
|
/* 037 */ eCharSet_DEFAULT,
|
|
/* 038 */ eCharSet_DEFAULT,
|
|
/* 039 */ eCharSet_DEFAULT,
|
|
/* 040 */ eCharSet_DEFAULT,
|
|
/* 041 */ eCharSet_DEFAULT,
|
|
/* 042 */ eCharSet_DEFAULT,
|
|
/* 043 */ eCharSet_DEFAULT,
|
|
/* 044 */ eCharSet_DEFAULT,
|
|
/* 045 */ eCharSet_DEFAULT,
|
|
/* 046 */ eCharSet_DEFAULT,
|
|
/* 047 */ eCharSet_DEFAULT,
|
|
/* 048 */ eCharSet_DEFAULT,
|
|
/* 049 */ eCharSet_DEFAULT,
|
|
/* 050 */ eCharSet_DEFAULT,
|
|
/* 051 */ eCharSet_DEFAULT,
|
|
/* 052 */ eCharSet_DEFAULT,
|
|
/* 053 */ eCharSet_DEFAULT,
|
|
/* 054 */ eCharSet_DEFAULT,
|
|
/* 055 */ eCharSet_DEFAULT,
|
|
/* 056 */ eCharSet_DEFAULT,
|
|
/* 057 */ eCharSet_DEFAULT,
|
|
/* 058 */ eCharSet_DEFAULT,
|
|
/* 059 */ eCharSet_DEFAULT,
|
|
/* 060 */ eCharSet_DEFAULT,
|
|
/* 061 */ eCharSet_DEFAULT,
|
|
/* 062 */ eCharSet_DEFAULT,
|
|
/* 063 */ eCharSet_DEFAULT,
|
|
/* 064 */ eCharSet_DEFAULT,
|
|
/* 065 */ eCharSet_DEFAULT,
|
|
/* 066 */ eCharSet_DEFAULT,
|
|
/* 067 */ eCharSet_DEFAULT,
|
|
/* 068 */ eCharSet_DEFAULT,
|
|
/* 069 */ eCharSet_DEFAULT,
|
|
/* 070 */ eCharSet_DEFAULT,
|
|
/* 071 */ eCharSet_DEFAULT,
|
|
/* 072 */ eCharSet_DEFAULT,
|
|
/* 073 */ eCharSet_DEFAULT,
|
|
/* 074 */ eCharSet_DEFAULT,
|
|
/* 075 */ eCharSet_DEFAULT,
|
|
/* 076 */ eCharSet_DEFAULT,
|
|
/* 077 */ eCharSet_DEFAULT, // MAC
|
|
/* 078 */ eCharSet_DEFAULT,
|
|
/* 079 */ eCharSet_DEFAULT,
|
|
/* 080 */ eCharSet_DEFAULT,
|
|
/* 081 */ eCharSet_DEFAULT,
|
|
/* 082 */ eCharSet_DEFAULT,
|
|
/* 083 */ eCharSet_DEFAULT,
|
|
/* 084 */ eCharSet_DEFAULT,
|
|
/* 085 */ eCharSet_DEFAULT,
|
|
/* 086 */ eCharSet_DEFAULT,
|
|
/* 087 */ eCharSet_DEFAULT,
|
|
/* 088 */ eCharSet_DEFAULT,
|
|
/* 089 */ eCharSet_DEFAULT,
|
|
/* 090 */ eCharSet_DEFAULT,
|
|
/* 091 */ eCharSet_DEFAULT,
|
|
/* 092 */ eCharSet_DEFAULT,
|
|
/* 093 */ eCharSet_DEFAULT,
|
|
/* 094 */ eCharSet_DEFAULT,
|
|
/* 095 */ eCharSet_DEFAULT,
|
|
/* 096 */ eCharSet_DEFAULT,
|
|
/* 097 */ eCharSet_DEFAULT,
|
|
/* 098 */ eCharSet_DEFAULT,
|
|
/* 099 */ eCharSet_DEFAULT,
|
|
/* 100 */ eCharSet_DEFAULT,
|
|
/* 101 */ eCharSet_DEFAULT,
|
|
/* 102 */ eCharSet_DEFAULT,
|
|
/* 103 */ eCharSet_DEFAULT,
|
|
/* 104 */ eCharSet_DEFAULT,
|
|
/* 105 */ eCharSet_DEFAULT,
|
|
/* 106 */ eCharSet_DEFAULT,
|
|
/* 107 */ eCharSet_DEFAULT,
|
|
/* 108 */ eCharSet_DEFAULT,
|
|
/* 109 */ eCharSet_DEFAULT,
|
|
/* 110 */ eCharSet_DEFAULT,
|
|
/* 111 */ eCharSet_DEFAULT,
|
|
/* 112 */ eCharSet_DEFAULT,
|
|
/* 113 */ eCharSet_DEFAULT,
|
|
/* 114 */ eCharSet_DEFAULT,
|
|
/* 115 */ eCharSet_DEFAULT,
|
|
/* 116 */ eCharSet_DEFAULT,
|
|
/* 117 */ eCharSet_DEFAULT,
|
|
/* 118 */ eCharSet_DEFAULT,
|
|
/* 119 */ eCharSet_DEFAULT,
|
|
/* 120 */ eCharSet_DEFAULT,
|
|
/* 121 */ eCharSet_DEFAULT,
|
|
/* 122 */ eCharSet_DEFAULT,
|
|
/* 123 */ eCharSet_DEFAULT,
|
|
/* 124 */ eCharSet_DEFAULT,
|
|
/* 125 */ eCharSet_DEFAULT,
|
|
/* 126 */ eCharSet_DEFAULT,
|
|
/* 127 */ eCharSet_DEFAULT,
|
|
/* 128 */ eCharSet_SHIFTJIS,
|
|
/* 129 */ eCharSet_HANGEUL,
|
|
/* 130 */ eCharSet_JOHAB,
|
|
/* 131 */ eCharSet_DEFAULT,
|
|
/* 132 */ eCharSet_DEFAULT,
|
|
/* 133 */ eCharSet_DEFAULT,
|
|
/* 134 */ eCharSet_GB2312,
|
|
/* 135 */ eCharSet_DEFAULT,
|
|
/* 136 */ eCharSet_CHINESEBIG5,
|
|
/* 137 */ eCharSet_DEFAULT,
|
|
/* 138 */ eCharSet_DEFAULT,
|
|
/* 139 */ eCharSet_DEFAULT,
|
|
/* 140 */ eCharSet_DEFAULT,
|
|
/* 141 */ eCharSet_DEFAULT,
|
|
/* 142 */ eCharSet_DEFAULT,
|
|
/* 143 */ eCharSet_DEFAULT,
|
|
/* 144 */ eCharSet_DEFAULT,
|
|
/* 145 */ eCharSet_DEFAULT,
|
|
/* 146 */ eCharSet_DEFAULT,
|
|
/* 147 */ eCharSet_DEFAULT,
|
|
/* 148 */ eCharSet_DEFAULT,
|
|
/* 149 */ eCharSet_DEFAULT,
|
|
/* 150 */ eCharSet_DEFAULT,
|
|
/* 151 */ eCharSet_DEFAULT,
|
|
/* 152 */ eCharSet_DEFAULT,
|
|
/* 153 */ eCharSet_DEFAULT,
|
|
/* 154 */ eCharSet_DEFAULT,
|
|
/* 155 */ eCharSet_DEFAULT,
|
|
/* 156 */ eCharSet_DEFAULT,
|
|
/* 157 */ eCharSet_DEFAULT,
|
|
/* 158 */ eCharSet_DEFAULT,
|
|
/* 159 */ eCharSet_DEFAULT,
|
|
/* 160 */ eCharSet_DEFAULT,
|
|
/* 161 */ eCharSet_GREEK,
|
|
/* 162 */ eCharSet_TURKISH,
|
|
/* 163 */ eCharSet_DEFAULT, // VIETNAMESE
|
|
/* 164 */ eCharSet_DEFAULT,
|
|
/* 165 */ eCharSet_DEFAULT,
|
|
/* 166 */ eCharSet_DEFAULT,
|
|
/* 167 */ eCharSet_DEFAULT,
|
|
/* 168 */ eCharSet_DEFAULT,
|
|
/* 169 */ eCharSet_DEFAULT,
|
|
/* 170 */ eCharSet_DEFAULT,
|
|
/* 171 */ eCharSet_DEFAULT,
|
|
/* 172 */ eCharSet_DEFAULT,
|
|
/* 173 */ eCharSet_DEFAULT,
|
|
/* 174 */ eCharSet_DEFAULT,
|
|
/* 175 */ eCharSet_DEFAULT,
|
|
/* 176 */ eCharSet_DEFAULT,
|
|
/* 177 */ eCharSet_HEBREW,
|
|
/* 178 */ eCharSet_ARABIC,
|
|
/* 179 */ eCharSet_DEFAULT,
|
|
/* 180 */ eCharSet_DEFAULT,
|
|
/* 181 */ eCharSet_DEFAULT,
|
|
/* 182 */ eCharSet_DEFAULT,
|
|
/* 183 */ eCharSet_DEFAULT,
|
|
/* 184 */ eCharSet_DEFAULT,
|
|
/* 185 */ eCharSet_DEFAULT,
|
|
/* 186 */ eCharSet_BALTIC,
|
|
/* 187 */ eCharSet_DEFAULT,
|
|
/* 188 */ eCharSet_DEFAULT,
|
|
/* 189 */ eCharSet_DEFAULT,
|
|
/* 190 */ eCharSet_DEFAULT,
|
|
/* 191 */ eCharSet_DEFAULT,
|
|
/* 192 */ eCharSet_DEFAULT,
|
|
/* 193 */ eCharSet_DEFAULT,
|
|
/* 194 */ eCharSet_DEFAULT,
|
|
/* 195 */ eCharSet_DEFAULT,
|
|
/* 196 */ eCharSet_DEFAULT,
|
|
/* 197 */ eCharSet_DEFAULT,
|
|
/* 198 */ eCharSet_DEFAULT,
|
|
/* 199 */ eCharSet_DEFAULT,
|
|
/* 200 */ eCharSet_DEFAULT,
|
|
/* 201 */ eCharSet_DEFAULT,
|
|
/* 202 */ eCharSet_DEFAULT,
|
|
/* 203 */ eCharSet_DEFAULT,
|
|
/* 204 */ eCharSet_RUSSIAN,
|
|
/* 205 */ eCharSet_DEFAULT,
|
|
/* 206 */ eCharSet_DEFAULT,
|
|
/* 207 */ eCharSet_DEFAULT,
|
|
/* 208 */ eCharSet_DEFAULT,
|
|
/* 209 */ eCharSet_DEFAULT,
|
|
/* 210 */ eCharSet_DEFAULT,
|
|
/* 211 */ eCharSet_DEFAULT,
|
|
/* 212 */ eCharSet_DEFAULT,
|
|
/* 213 */ eCharSet_DEFAULT,
|
|
/* 214 */ eCharSet_DEFAULT,
|
|
/* 215 */ eCharSet_DEFAULT,
|
|
/* 216 */ eCharSet_DEFAULT,
|
|
/* 217 */ eCharSet_DEFAULT,
|
|
/* 218 */ eCharSet_DEFAULT,
|
|
/* 219 */ eCharSet_DEFAULT,
|
|
/* 220 */ eCharSet_DEFAULT,
|
|
/* 221 */ eCharSet_DEFAULT,
|
|
/* 222 */ eCharSet_THAI,
|
|
/* 223 */ eCharSet_DEFAULT,
|
|
/* 224 */ eCharSet_DEFAULT,
|
|
/* 225 */ eCharSet_DEFAULT,
|
|
/* 226 */ eCharSet_DEFAULT,
|
|
/* 227 */ eCharSet_DEFAULT,
|
|
/* 228 */ eCharSet_DEFAULT,
|
|
/* 229 */ eCharSet_DEFAULT,
|
|
/* 230 */ eCharSet_DEFAULT,
|
|
/* 231 */ eCharSet_DEFAULT,
|
|
/* 232 */ eCharSet_DEFAULT,
|
|
/* 233 */ eCharSet_DEFAULT,
|
|
/* 234 */ eCharSet_DEFAULT,
|
|
/* 235 */ eCharSet_DEFAULT,
|
|
/* 236 */ eCharSet_DEFAULT,
|
|
/* 237 */ eCharSet_DEFAULT,
|
|
/* 238 */ eCharSet_EASTEUROPE,
|
|
/* 239 */ eCharSet_DEFAULT,
|
|
/* 240 */ eCharSet_DEFAULT,
|
|
/* 241 */ eCharSet_DEFAULT,
|
|
/* 242 */ eCharSet_DEFAULT,
|
|
/* 243 */ eCharSet_DEFAULT,
|
|
/* 244 */ eCharSet_DEFAULT,
|
|
/* 245 */ eCharSet_DEFAULT,
|
|
/* 246 */ eCharSet_DEFAULT,
|
|
/* 247 */ eCharSet_DEFAULT,
|
|
/* 248 */ eCharSet_DEFAULT,
|
|
/* 249 */ eCharSet_DEFAULT,
|
|
/* 250 */ eCharSet_DEFAULT,
|
|
/* 251 */ eCharSet_DEFAULT,
|
|
/* 252 */ eCharSet_DEFAULT,
|
|
/* 253 */ eCharSet_DEFAULT,
|
|
/* 254 */ eCharSet_DEFAULT,
|
|
/* 255 */ eCharSet_DEFAULT // OEM
|
|
};
|
|
|
|
typedef struct nsCharSetInfo nsCharSetInfo;
|
|
|
|
struct nsCharSetInfo
|
|
{
|
|
char* mName;
|
|
PRUint16 mCodePage;
|
|
void (*GenerateMap)(nsCharSetInfo* aSelf);
|
|
PRUint8* mMap;
|
|
};
|
|
|
|
static void
|
|
GenerateDefault(nsCharSetInfo* aSelf)
|
|
{
|
|
printf("%s defaulted\n", aSelf->mName);
|
|
PRUint8* map = aSelf->mMap;
|
|
for (int i = 0; i < 8192; i++) {
|
|
map[i] = 0xFF;
|
|
}
|
|
}
|
|
|
|
static void
|
|
GenerateSingleByte(nsCharSetInfo* aSelf)
|
|
{
|
|
PRUint8 mb[256];
|
|
PRUint16 wc[256];
|
|
int i;
|
|
for (i = 0; i < 256; i++) {
|
|
mb[i] = i;
|
|
}
|
|
int len = MultiByteToWideChar(aSelf->mCodePage, 0, (char*) mb, 256, wc, 256);
|
|
if (len != 256) {
|
|
printf("%s: MultiByteToWideChar returned %d\n", aSelf->mName, len);
|
|
}
|
|
PRUint8* map = aSelf->mMap;
|
|
for (i = 0; i < 256; i++) {
|
|
ADD_GLYPH(map, wc[i]);
|
|
}
|
|
}
|
|
|
|
static void
|
|
GenerateMultiByte(nsCharSetInfo* aSelf)
|
|
{
|
|
PRUint8* map = aSelf->mMap;
|
|
for (PRUint16 c = 0; c < 0xFFFF; c++) {
|
|
BOOL defaulted = FALSE;
|
|
WideCharToMultiByte(aSelf->mCodePage, 0, &c, 1, nsnull, 0, nsnull,
|
|
&defaulted);
|
|
if (!defaulted) {
|
|
ADD_GLYPH(map, c);
|
|
}
|
|
}
|
|
}
|
|
|
|
static nsCharSetInfo gCharSetInfo[eCharSet_COUNT] =
|
|
{
|
|
{ "DEFAULT", 0, GenerateDefault },
|
|
{ "ANSI", 1252, GenerateSingleByte },
|
|
{ "EASTEUROPE", 1250, GenerateSingleByte },
|
|
{ "RUSSIAN", 1251, GenerateSingleByte },
|
|
{ "GREEK", 1253, GenerateSingleByte },
|
|
{ "TURKISH", 1254, GenerateSingleByte },
|
|
{ "HEBREW", 1255, GenerateSingleByte },
|
|
{ "ARABIC", 1256, GenerateSingleByte },
|
|
{ "BALTIC", 1257, GenerateSingleByte },
|
|
{ "THAI", 874, GenerateSingleByte },
|
|
{ "SHIFTJIS", 932, GenerateMultiByte },
|
|
{ "GB2312", 936, GenerateMultiByte },
|
|
{ "HANGEUL", 949, GenerateMultiByte },
|
|
{ "CHINESEBIG5", 950, GenerateMultiByte },
|
|
{ "JOHAB", 1361, GenerateMultiByte }
|
|
};
|
|
|
|
static int
|
|
HaveConverterFor(PRUint8 aCharSet)
|
|
{
|
|
PRUint16 wc = 'a';
|
|
char mb[8];
|
|
if (WideCharToMultiByte(gCharSetInfo[gCharSetToIndex[aCharSet]].mCodePage, 0,
|
|
&wc, 1, mb, sizeof(mb), nsnull, nsnull)) {
|
|
return 1;
|
|
}
|
|
|
|
// remove from table, since we can't support it anyway
|
|
for (int i = 0; i < sizeof(bitToCharSet); i++) {
|
|
if (bitToCharSet[i] == aCharSet) {
|
|
bitToCharSet[i] = DEFAULT_CHARSET;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
nsFontWinA::GetSubsets(HDC aDC)
|
|
{
|
|
FONTSIGNATURE signature;
|
|
if (::GetTextCharsetInfo(aDC, &signature, 0) == DEFAULT_CHARSET) {
|
|
return 0;
|
|
}
|
|
|
|
int dword;
|
|
DWORD* array = signature.fsCsb;
|
|
mSubsetsCount = 0;
|
|
int i = 0;
|
|
for (dword = 0; dword < 2; dword++) {
|
|
for (int bit = 0; bit < sizeof(DWORD) * 8; bit++) {
|
|
if ((array[dword] >> bit) & 1) {
|
|
PRUint8 charSet = bitToCharSet[i];
|
|
#ifdef DEBUG_FONT_SIGNATURE
|
|
printf(" %02d %s\n", i, gCharSetInfo[gCharSetToIndex[charSet]].mName);
|
|
#endif
|
|
if (charSet != DEFAULT_CHARSET) {
|
|
if (HaveConverterFor(charSet)) {
|
|
mSubsetsCount++;
|
|
}
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
|
|
mSubsets = (nsFontSubset*) PR_Calloc(mSubsetsCount, sizeof(nsFontSubset));
|
|
if (!mSubsets) {
|
|
mSubsetsCount = 0;
|
|
return 0;
|
|
}
|
|
|
|
i = 0;
|
|
int j = 0;
|
|
for (dword = 0; dword < 2; dword++) {
|
|
for (int bit = 0; bit < sizeof(DWORD) * 8; bit++) {
|
|
if ((array[dword] >> bit) & 1) {
|
|
PRUint8 charSet = bitToCharSet[i];
|
|
if (charSet != DEFAULT_CHARSET) {
|
|
if (HaveConverterFor(charSet)) {
|
|
mSubsets[j].mCharSet = charSet;
|
|
j++;
|
|
}
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void
|
|
FreeFont(nsFontWinA* aFont)
|
|
{
|
|
nsFontSubset* subset = aFont->mSubsets;
|
|
nsFontSubset* endSubsets = &(aFont->mSubsets[aFont->mSubsetsCount]);
|
|
while (subset < endSubsets) {
|
|
if (subset->mFont) {
|
|
::DeleteObject(subset->mFont);
|
|
}
|
|
if (subset->mMap) {
|
|
PR_Free(subset->mMap);
|
|
}
|
|
subset++;
|
|
}
|
|
PR_Free(aFont->mSubsets);
|
|
if (aFont->mFont) {
|
|
::DeleteObject(aFont->mFont);
|
|
}
|
|
delete aFont;
|
|
}
|
|
|
|
nsFontMetricsWinA::~nsFontMetricsWinA()
|
|
{
|
|
if (nsnull != mFont) {
|
|
delete mFont;
|
|
mFont = nsnull;
|
|
}
|
|
|
|
mFontHandle = nsnull; // released below
|
|
|
|
if (mFonts) {
|
|
delete [] mFonts;
|
|
mFonts = nsnull;
|
|
}
|
|
|
|
if (mLoadedFonts) {
|
|
nsFontWinA** font = (nsFontWinA**) mLoadedFonts;
|
|
nsFontWinA** end = (nsFontWinA**) &mLoadedFonts[mLoadedFontsCount];
|
|
while (font < end) {
|
|
FreeFont(*font);
|
|
font++;
|
|
}
|
|
PR_Free(mLoadedFonts);
|
|
mLoadedFonts = nsnull;
|
|
}
|
|
|
|
mDeviceContext = nsnull;
|
|
}
|
|
|
|
nsFontWin*
|
|
nsFontMetricsWinA::LoadFont(HDC aDC, nsString* aName)
|
|
{
|
|
LOGFONT logFont;
|
|
|
|
PRUint16 weightTable = LookForFontWeightTable(aDC, aName);
|
|
PRInt32 weight = GetFontWeight(mFont->weight, weightTable);
|
|
FillLogFont(&logFont, weight);
|
|
|
|
// XXX need to preserve Unicode chars in face name (use LOGFONTW) -- erik
|
|
aName->ToCString(logFont.lfFaceName, LF_FACESIZE);
|
|
|
|
HFONT hfont = ::CreateFontIndirect(&logFont);
|
|
|
|
if (hfont) {
|
|
if (mLoadedFontsCount == mLoadedFontsAlloc) {
|
|
int newSize = 2 * (mLoadedFontsAlloc ? mLoadedFontsAlloc : 1);
|
|
nsFontWinA** newPointer = (nsFontWinA**) PR_Realloc(mLoadedFonts,
|
|
newSize * sizeof(nsFontWinA*));
|
|
if (newPointer) {
|
|
mLoadedFonts = (nsFontWin**) newPointer;
|
|
mLoadedFontsAlloc = newSize;
|
|
}
|
|
else {
|
|
::DeleteObject(hfont);
|
|
return nsnull;
|
|
}
|
|
}
|
|
nsFontWinA* font = new nsFontWinA;
|
|
if (!font) {
|
|
::DeleteObject(hfont);
|
|
return nsnull;
|
|
}
|
|
mLoadedFonts[mLoadedFontsCount++] = (nsFontWin*) font;
|
|
HFONT oldFont = (HFONT) ::SelectObject(aDC, (HGDIOBJ) hfont);
|
|
font->mFont = hfont;
|
|
font->mLogFont = logFont;
|
|
#ifdef DEBUG_FONT_SIGNATURE
|
|
printf("%s\n", logFont.lfFaceName);
|
|
#endif
|
|
if (!font->GetSubsets(aDC)) {
|
|
mLoadedFontsCount--;
|
|
::SelectObject(aDC, (HGDIOBJ) oldFont);
|
|
::DeleteObject(hfont);
|
|
return nsnull;
|
|
}
|
|
font->mMap = GetCMAP(aDC);
|
|
if (!font->mMap) {
|
|
mLoadedFontsCount--;
|
|
::SelectObject(aDC, (HGDIOBJ) oldFont);
|
|
::DeleteObject(hfont);
|
|
return nsnull;
|
|
}
|
|
::SelectObject(aDC, (HGDIOBJ) oldFont);
|
|
|
|
return (nsFontWin*) font;
|
|
}
|
|
|
|
return nsnull;
|
|
}
|
|
|
|
int
|
|
nsFontSubset::Load(nsFontWinA* aFont)
|
|
{
|
|
LOGFONT* logFont = &aFont->mLogFont;
|
|
logFont->lfCharSet = mCharSet;
|
|
HFONT hfont = ::CreateFontIndirect(logFont);
|
|
if (hfont) {
|
|
int i = gCharSetToIndex[mCharSet];
|
|
PRUint8* charSetMap = gCharSetInfo[i].mMap;
|
|
if (!charSetMap) {
|
|
charSetMap = (PRUint8*) PR_Calloc(8192, 1);
|
|
if (charSetMap) {
|
|
gCharSetInfo[i].mMap = charSetMap;
|
|
gCharSetInfo[i].GenerateMap(&gCharSetInfo[i]);
|
|
}
|
|
else {
|
|
::DeleteObject(hfont);
|
|
return 0;
|
|
}
|
|
}
|
|
mMap = (PRUint8*) PR_Malloc(8192);
|
|
if (!mMap) {
|
|
::DeleteObject(hfont);
|
|
return 0;
|
|
}
|
|
PRUint8* fontMap = aFont->mMap;
|
|
for (int j = 0; j < 8192; j++) {
|
|
mMap[j] = (charSetMap[j] & fontMap[j]);
|
|
}
|
|
mCodePage = gCharSetInfo[i].mCodePage;
|
|
mFont = hfont;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
nsFontWin*
|
|
nsFontMetricsWinA::FindLocalFont(HDC aDC, PRUnichar aChar)
|
|
{
|
|
if (!gFamilyNames) {
|
|
if (!InitializeFamilyNames()) {
|
|
return nsnull;
|
|
}
|
|
}
|
|
|
|
while (mFontsIndex < mFontsCount) {
|
|
nsString* name = &mFonts[mFontsIndex++];
|
|
nsString* low = new nsString(*name);
|
|
if (low) {
|
|
low->ToLowerCase();
|
|
nsString* winName = (nsString*) PL_HashTableLookup(gFamilyNames, low);
|
|
delete low;
|
|
if (!winName) {
|
|
winName = name;
|
|
}
|
|
nsFontWinA* font = (nsFontWinA*) LoadFont(aDC, winName);
|
|
if (font && FONT_HAS_GLYPH(font->mMap, aChar)) {
|
|
nsFontSubset* subset = font->mSubsets;
|
|
nsFontSubset* endSubsets = &(font->mSubsets[font->mSubsetsCount]);
|
|
while (subset < endSubsets) {
|
|
if (!subset->mMap) {
|
|
if (!subset->Load(font)) {
|
|
subset++;
|
|
continue;
|
|
}
|
|
}
|
|
if (FONT_HAS_GLYPH(subset->mMap, aChar)) {
|
|
return (nsFontWin*) subset;
|
|
}
|
|
subset++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return nsnull;
|
|
}
|
|
|
|
nsFontWin*
|
|
nsFontMetricsWinA::FindGlobalFont(HDC aDC, PRUnichar c)
|
|
{
|
|
if (!gGlobalFonts) {
|
|
if (!InitializeGlobalFonts(aDC)) {
|
|
return nsnull;
|
|
}
|
|
}
|
|
for (int i = 0; i < gGlobalFontsCount; i++) {
|
|
if (!gGlobalFonts[i].skip) {
|
|
if (!gGlobalFonts[i].map) {
|
|
HFONT font = ::CreateFontIndirect(&gGlobalFonts[i].logFont);
|
|
if (!font) {
|
|
continue;
|
|
}
|
|
HFONT oldFont = (HFONT) ::SelectObject(aDC, font);
|
|
gGlobalFonts[i].map = GetCMAP(aDC);
|
|
::SelectObject(aDC, oldFont);
|
|
::DeleteObject(font);
|
|
if (!gGlobalFonts[i].map) {
|
|
continue;
|
|
}
|
|
if (SameAsPreviousMap(i)) {
|
|
continue;
|
|
}
|
|
}
|
|
if (FONT_HAS_GLYPH(gGlobalFonts[i].map, c)) {
|
|
nsFontWinA* font = (nsFontWinA*) LoadFont(aDC, gGlobalFonts[i].name);
|
|
if (font) {
|
|
nsFontSubset* subset = font->mSubsets;
|
|
nsFontSubset* endSubsets = &(font->mSubsets[font->mSubsetsCount]);
|
|
while (subset < endSubsets) {
|
|
if (!subset->mMap) {
|
|
if (!subset->Load(font)) {
|
|
subset++;
|
|
continue;
|
|
}
|
|
}
|
|
if (FONT_HAS_GLYPH(subset->mMap, c)) {
|
|
return (nsFontWin*) subset;
|
|
}
|
|
subset++;
|
|
}
|
|
mLoadedFontsCount--;
|
|
FreeFont(font);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return nsnull;
|
|
}
|