Added support for font weights

This commit is contained in:
kmcclusk%netscape.com 1999-09-20 21:02:01 +00:00
Родитель bd3c4e0658
Коммит ff5323094a
2 изменённых файлов: 352 добавлений и 5 удалений

Просмотреть файл

@ -28,6 +28,13 @@ 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();
@ -134,7 +141,7 @@ nsresult nsFontMetricsWin :: GetSpaceWidth(nscoord &aSpaceWidth)
}
void
nsFontMetricsWin::FillLogFont(LOGFONT* logFont)
nsFontMetricsWin::FillLogFont(LOGFONT* logFont, PRInt32 aWeight)
{
// Fill in logFont structure; stolen from awt
logFont->lfWidth = 0;
@ -151,7 +158,7 @@ nsFontMetricsWin::FillLogFont(LOGFONT* logFont)
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->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;
@ -544,7 +551,10 @@ nsFontWin*
nsFontMetricsWin::LoadFont(HDC aDC, nsString* aName)
{
LOGFONT logFont;
FillLogFont(&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
@ -728,6 +738,313 @@ nsFontMetricsWin::FindGlobalFont(HDC aDC, PRUnichar c)
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;
@ -1575,7 +1892,10 @@ nsFontWin*
nsFontMetricsWinA::LoadFont(HDC aDC, nsString* aName)
{
LOGFONT logFont;
FillLogFont(&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);

Просмотреть файл

@ -102,8 +102,34 @@ public:
static nsGlobalFont* gGlobalFonts;
static int gGlobalFontsCount;
static void SetFontWeight(PRInt32 aWeight, PRUint16* aWeightTable);
static PRBool IsFontWeightAvailable(PRInt32 aWeight, PRUint16 aWeightTable);
protected:
void FillLogFont(LOGFONT* aLogFont);
// @description Font Weights
// Each available font weight is stored as as single bit inside a PRUint16.
// e.g. The binary value 0000000000001000 indcates font weight 400 is available.
// while the binary value 0000000000001001 indicates both font weight 100 and 400 are available
// The font weights which will be represented include {100, 200, 300, 400, 500, 600, 700, 800, 900}
// The font weight specified in the mFont->weight may include values which are not an even multiple of 100.
// If so, the font weight mod 100 indicates the number steps to lighten are make bolder.
// This corresponds to the CSS lighter and bolder property values. If bolder is applied twice to the font which has
// a font weight of 400 then the mFont->weight will contain the value 402.
// If lighter is applied twice to a font of weight 400 then the mFont->weight will contain the value 398.
// Only nine steps of bolder or lighter are allowed by the CSS XPCODE.
// The font weight table is used in conjuction with the mFont->weight to determine
// what font weight to pass in the LOGFONT structure.
// Utility methods for managing font weights.
PRUint16 LookForFontWeightTable(HDC aDc, nsString* aName);
PRInt32 GetBolderWeight(PRInt32 aWeight, PRInt32 aDistance, PRUint16 aWeightTable);
PRInt32 GetLighterWeight(PRInt32 aWeight, PRInt32 aDistance, PRUint16 aWeightTable);
PRInt32 GetFontWeight(PRInt32 aWeight, PRUint16 aWeightTable);
PRInt32 GetClosestWeight(PRInt32 aWeight, PRUint16 aWeightTable);
PRUint16 GetFontWeightTable(HDC aDC, nsString* aFontName);
void FillLogFont(LOGFONT* aLogFont, PRInt32 aWeight);
void RealizeFont();
nsDeviceContextWin *mDeviceContext;
@ -126,6 +152,7 @@ protected:
static PLHashTable* InitializeFamilyNames(void);
static PLHashTable* gFamilyNames;
static PLHashTable* gFontWeights;
static nsGlobalFont* InitializeGlobalFonts(HDC aDC);