mirror of
https://github.com/gnustep/libs-back.git
synced 2025-02-23 20:01:22 +00:00
Handle "strange" font weights
Fontconfig's font weights are almost but not entirely defined by the constants found in its source code. Things like FC_WEIGHT_LIGHT are not, as we had presumed, a list of definitive weights. As such, it seems there are a goodly number of fonts that have weights not appearing in the list. For example, say there's a font that is heavier than Medium (weight 100 for fontconfig, and 6 for us) but not as heavy as Demibold (FC: 180, GS: 7), then it might tell Fontconfig it has a weight of 130. When this happens, we _could_ assign its NSWeight to be 6 or 7, but it's possible that there will be another face in that font that ALSO fits there, which might throw off the sorting. Instead, what I suggest is to do what I have done...assign an NSWeight with a weight class that represents the numeric distance _between_ the two defined values. So the GS weight for this font face becomes something like: NSWeight = 6 + ((FCWeight - Medium) * (1.0 / (Demibold - Medium))) or, in numeric terms, 6 + 0.375 In service of this change, I have switched the actual Weight value within the font dictionary from int to float. This is an attempt to translate this situation into a sortable form we can work with, compressing an approximate range of possible FC font weights into our 0-15 system. There may well be a better way to go about this, such as figuring out where fontconfig gets this info in the first place and converting from the source directly, but accessing the SFNT tables (which will almost certainly be required) is something for a later day.
This commit is contained in:
parent
5737e249f5
commit
d0a9f5b943
1 changed files with 126 additions and 94 deletions
|
@ -53,6 +53,29 @@
|
||||||
#define FC_WEIGHT_ULTRABLACK FC_WEIGHT_BLACK
|
#define FC_WEIGHT_ULTRABLACK FC_WEIGHT_BLACK
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static float
|
||||||
|
convertWeight (int fcWeight, int bottomValue, int topValue)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
This is the distance between topValue and bottomValue expressed as a
|
||||||
|
fraction between zero and one. We do this to express the range of
|
||||||
|
fontconfig font weights in a useful manner.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (fcWeight <= bottomValue)
|
||||||
|
{
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
else if (fcWeight >= topValue)
|
||||||
|
{
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return (float) (fcWeight - bottomValue) * (1.0f / (topValue - bottomValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static NSComparisonResult
|
static NSComparisonResult
|
||||||
sortFontFacesArray(id fontArr1, id fontArr2, void *context)
|
sortFontFacesArray(id fontArr1, id fontArr2, void *context)
|
||||||
{
|
{
|
||||||
|
@ -65,8 +88,8 @@ sortFontFacesArray(id fontArr1, id fontArr2, void *context)
|
||||||
*/
|
*/
|
||||||
NSString *style1 = [fontArr1 objectAtIndex: 1];
|
NSString *style1 = [fontArr1 objectAtIndex: 1];
|
||||||
NSString *style2 = [fontArr2 objectAtIndex: 1];
|
NSString *style2 = [fontArr2 objectAtIndex: 1];
|
||||||
int weight1 = [[fontArr1 objectAtIndex: 2] intValue];
|
float weight1 = [[fontArr1 objectAtIndex: 2] floatValue];
|
||||||
int weight2 = [[fontArr2 objectAtIndex: 2] intValue];
|
float weight2 = [[fontArr2 objectAtIndex: 2] floatValue];
|
||||||
unsigned int traits1 = [[fontArr1 objectAtIndex: 3] unsignedIntValue];
|
unsigned int traits1 = [[fontArr1 objectAtIndex: 3] unsignedIntValue];
|
||||||
unsigned int traits2 = [[fontArr2 objectAtIndex: 3] unsignedIntValue];
|
unsigned int traits2 = [[fontArr2 objectAtIndex: 3] unsignedIntValue];
|
||||||
|
|
||||||
|
@ -123,7 +146,8 @@ NSMutableDictionary * __allFonts;
|
||||||
// Make a GNUstep style font descriptor from a FcPattern
|
// Make a GNUstep style font descriptor from a FcPattern
|
||||||
static NSArray *faFromFc(FcPattern *pat)
|
static NSArray *faFromFc(FcPattern *pat)
|
||||||
{
|
{
|
||||||
int weight, slant, spacing, width, nsweight;
|
int weight, slant, spacing, width;
|
||||||
|
float nsweight;
|
||||||
unsigned int nstraits = 0;
|
unsigned int nstraits = 0;
|
||||||
char *fcfamily, *fcstyle;
|
char *fcfamily, *fcstyle;
|
||||||
NSMutableString *name, *family, *style;
|
NSMutableString *name, *family, *style;
|
||||||
|
@ -150,99 +174,107 @@ static NSArray *faFromFc(FcPattern *pat)
|
||||||
family = [NSMutableString stringWithUTF8String: fcfamily];
|
family = [NSMutableString stringWithUTF8String: fcfamily];
|
||||||
style = [NSMutableString stringWithCapacity: 100];
|
style = [NSMutableString stringWithCapacity: 100];
|
||||||
|
|
||||||
switch (weight)
|
if (weight < FC_WEIGHT_ULTRALIGHT)
|
||||||
{
|
{
|
||||||
case FC_WEIGHT_THIN:
|
[style appendString: @"Thin"];
|
||||||
[style appendString: @"Thin"];
|
nsweight = 1 + convertWeight (weight, FC_WEIGHT_THIN, FC_WEIGHT_ULTRALIGHT);
|
||||||
nsweight = 1;
|
}
|
||||||
break;
|
else if (weight < FC_WEIGHT_LIGHT)
|
||||||
case FC_WEIGHT_ULTRALIGHT:
|
{
|
||||||
[style appendString: @"Ultralight"];
|
[style appendString: @"Ultralight"];
|
||||||
nsweight = 2;
|
nsweight = 2 + convertWeight (weight, FC_WEIGHT_ULTRALIGHT, FC_WEIGHT_LIGHT);
|
||||||
break;
|
}
|
||||||
case FC_WEIGHT_LIGHT:
|
else if (weight < FC_WEIGHT_BOOK)
|
||||||
[style appendString: @"Light"];
|
{
|
||||||
nsweight = 3;
|
[style appendString: @"Light"];
|
||||||
break;
|
nsweight = 3 + convertWeight (weight, FC_WEIGHT_LIGHT, FC_WEIGHT_BOOK);
|
||||||
case FC_WEIGHT_BOOK:
|
}
|
||||||
[style appendString: @"Book"];
|
else if (weight < FC_WEIGHT_REGULAR)
|
||||||
nsweight = 4;
|
{
|
||||||
break;
|
[style appendString: @"Book"];
|
||||||
case FC_WEIGHT_REGULAR:
|
nsweight = 4 + convertWeight (weight, FC_WEIGHT_BOOK, FC_WEIGHT_REGULAR);
|
||||||
// [style appendString: @"Regular"];
|
}
|
||||||
nsweight = 5;
|
else if (weight < FC_WEIGHT_MEDIUM)
|
||||||
break;
|
{
|
||||||
case FC_WEIGHT_MEDIUM:
|
nsweight = 5 + convertWeight (weight, FC_WEIGHT_REGULAR, FC_WEIGHT_MEDIUM);
|
||||||
[style appendString: @"Medium"];
|
}
|
||||||
nsweight = 6;
|
else if (weight < FC_WEIGHT_DEMIBOLD)
|
||||||
break;
|
{
|
||||||
case FC_WEIGHT_DEMIBOLD:
|
[style appendString: @"Medium"];
|
||||||
[style appendString: @"Demibold"];
|
nsweight = 6 + convertWeight (weight, FC_WEIGHT_MEDIUM, FC_WEIGHT_DEMIBOLD);
|
||||||
nsweight = 7;
|
}
|
||||||
break;
|
else if (weight < FC_WEIGHT_BOLD)
|
||||||
case FC_WEIGHT_BOLD:
|
{
|
||||||
[style appendString: @"Bold"];
|
[style appendString: @"Demibold"];
|
||||||
nsweight = 9;
|
nsweight = 7 + convertWeight (weight, FC_WEIGHT_DEMIBOLD, FC_WEIGHT_BOLD);
|
||||||
nstraits |= NSBoldFontMask;
|
}
|
||||||
break;
|
else if (weight < FC_WEIGHT_ULTRABOLD)
|
||||||
case FC_WEIGHT_ULTRABOLD:
|
{
|
||||||
[style appendString: @"Ultrabold"];
|
[style appendString: @"Bold"];
|
||||||
nsweight = 11;
|
nsweight = 9 + convertWeight (weight, FC_WEIGHT_BOLD, FC_WEIGHT_ULTRABOLD);
|
||||||
nstraits |= NSBoldFontMask;
|
nstraits |= NSBoldFontMask;
|
||||||
break;
|
}
|
||||||
case FC_WEIGHT_BLACK:
|
else if (weight < FC_WEIGHT_BLACK)
|
||||||
[style appendString: @"Black"];
|
{
|
||||||
nsweight = 12;
|
[style appendString: @"Ultrabold"];
|
||||||
nstraits |= NSBoldFontMask;
|
nsweight = 11 + convertWeight (weight, FC_WEIGHT_ULTRABOLD, FC_WEIGHT_BLACK);
|
||||||
break;
|
nstraits |= NSBoldFontMask;
|
||||||
case FC_WEIGHT_ULTRABLACK:
|
}
|
||||||
[style appendString: @"Ultrablack"];
|
else if (weight < FC_WEIGHT_ULTRABLACK)
|
||||||
nsweight = 13;
|
{
|
||||||
nstraits |= NSBoldFontMask;
|
[style appendString: @"Black"];
|
||||||
break;
|
nsweight = 12 + convertWeight (weight, FC_WEIGHT_BLACK, FC_WEIGHT_ULTRABLACK);
|
||||||
default:
|
nstraits |= NSBoldFontMask;
|
||||||
nsweight = 5;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[style appendString: @"Ultrablack"];
|
||||||
|
nsweight = 13 + convertWeight (weight, FC_WEIGHT_ULTRABLACK, FC_WEIGHT_ULTRABLACK + 20);
|
||||||
|
nstraits |= NSBoldFontMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FcPatternGetInteger(pat, FC_WIDTH, 0, &width) == FcResultMatch)
|
if (FcPatternGetInteger(pat, FC_WIDTH, 0, &width) == FcResultMatch)
|
||||||
switch (width)
|
{
|
||||||
{
|
if (width < FC_WIDTH_EXTRACONDENSED)
|
||||||
case FC_WIDTH_ULTRACONDENSED:
|
{
|
||||||
[style appendString: @"Ultracondensed"];
|
[style appendString: @"Ultracondensed"];
|
||||||
nstraits |= NSCondensedFontMask;
|
nstraits |= NSCondensedFontMask;
|
||||||
break;
|
}
|
||||||
case FC_WIDTH_EXTRACONDENSED:
|
else if (width < FC_WIDTH_CONDENSED)
|
||||||
[style appendString: @"Extracondensed"];
|
{
|
||||||
nstraits |= NSCondensedFontMask;
|
[style appendString: @"Extracondensed"];
|
||||||
break;
|
nstraits |= NSCondensedFontMask;
|
||||||
case FC_WIDTH_CONDENSED:
|
}
|
||||||
[style appendString: @"Condensed"];
|
else if (width < FC_WIDTH_SEMICONDENSED)
|
||||||
nstraits |= NSCondensedFontMask;
|
{
|
||||||
break;
|
[style appendString: @"Condensed"];
|
||||||
case FC_WIDTH_SEMICONDENSED:
|
nstraits |= NSCondensedFontMask;
|
||||||
[style appendString: @"Semicondensed"];
|
}
|
||||||
nstraits |= NSCondensedFontMask;
|
else if (width < FC_WIDTH_SEMIEXPANDED)
|
||||||
break;
|
{
|
||||||
case FC_WIDTH_SEMIEXPANDED:
|
// do nothing, this is "regular"
|
||||||
[style appendString: @"Semiexpanded"];
|
}
|
||||||
nstraits |= NSExpandedFontMask;
|
else if (width < FC_WIDTH_EXPANDED)
|
||||||
break;
|
{
|
||||||
case FC_WIDTH_EXPANDED:
|
[style appendString: @"Semiexpanded"];
|
||||||
[style appendString: @"Expanded"];
|
nstraits |= NSExpandedFontMask;
|
||||||
nstraits |= NSExpandedFontMask;
|
}
|
||||||
break;
|
else if (width < FC_WIDTH_EXTRAEXPANDED)
|
||||||
case FC_WIDTH_EXTRAEXPANDED:
|
{
|
||||||
[style appendString: @"Extraexpanded"];
|
[style appendString: @"Expanded"];
|
||||||
nstraits |= NSExpandedFontMask;
|
nstraits |= NSExpandedFontMask;
|
||||||
break;
|
}
|
||||||
case FC_WIDTH_ULTRAEXPANDED:
|
else if (width < FC_WIDTH_ULTRAEXPANDED)
|
||||||
[style appendString: @"Ultraexpanded"];
|
{
|
||||||
nstraits |= NSExpandedFontMask;
|
[style appendString: @"Extraexpanded"];
|
||||||
break;
|
nstraits |= NSExpandedFontMask;
|
||||||
|
}
|
||||||
default:
|
else
|
||||||
break;
|
{
|
||||||
}
|
[style appendString: @"Ultraexpanded"];
|
||||||
|
nstraits |= NSExpandedFontMask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (slant)
|
switch (slant)
|
||||||
{
|
{
|
||||||
|
@ -280,7 +312,7 @@ static NSArray *faFromFc(FcPattern *pat)
|
||||||
// NSLog (@"family: %@, style: %s/%@", name, fcstyle, style);
|
// NSLog (@"family: %@, style: %s/%@", name, fcstyle, style);
|
||||||
return [NSArray arrayWithObjects: name,
|
return [NSArray arrayWithObjects: name,
|
||||||
style,
|
style,
|
||||||
[NSNumber numberWithInt: nsweight],
|
[NSNumber numberWithFloat: nsweight],
|
||||||
[NSNumber numberWithUnsignedInt: nstraits],
|
[NSNumber numberWithUnsignedInt: nstraits],
|
||||||
nil];
|
nil];
|
||||||
}
|
}
|
||||||
|
@ -338,7 +370,7 @@ static NSArray *faFromFc(FcPattern *pat)
|
||||||
[familyArray addObject: fontArray];
|
[familyArray addObject: fontArray];
|
||||||
[fcxft_allFontNames addObject: name];
|
[fcxft_allFontNames addObject: name];
|
||||||
aFont = [[faceInfoClass alloc] initWithfamilyName: familyString
|
aFont = [[faceInfoClass alloc] initWithfamilyName: familyString
|
||||||
weight: [[fontArray objectAtIndex: 2] intValue]
|
weight: [[fontArray objectAtIndex: 2] floatValue]
|
||||||
traits: [[fontArray objectAtIndex: 3] unsignedIntValue]
|
traits: [[fontArray objectAtIndex: 3] unsignedIntValue]
|
||||||
pattern: fs->fonts[i]];
|
pattern: fs->fonts[i]];
|
||||||
[fcxft_allFonts setObject: aFont forKey: name];
|
[fcxft_allFonts setObject: aFont forKey: name];
|
||||||
|
|
Loading…
Reference in a new issue