Index: src/ports/SkFontHost_FreeType.cpp |
diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp |
index 8d6c4d0cb322aafb124230255ff82c67f6d6de16..eaf94ab365053c4aa8d725bfe6f784f005e1426a 100644 |
--- a/src/ports/SkFontHost_FreeType.cpp |
+++ b/src/ports/SkFontHost_FreeType.cpp |
@@ -63,6 +63,8 @@ |
//#define SK_GAMMA_APPLY_TO_A8 |
+//#define DEBUG_METRICS |
bungeman-skia
2013/11/22 18:09:14
Note to myself: remove most, if not all, of this a
|
+ |
using namespace skia_advanced_typeface_metrics_utils; |
static bool isLCD(const SkScalerContext::Rec& rec) { |
@@ -184,6 +186,7 @@ private: |
SkFaceRec* fFaceRec; |
FT_Face fFace; // reference to shared face in gFaceRecHead |
FT_Size fFTSize; // our own copy |
+ FT_Int fStrikeIndex; |
SkFixed fScaleX, fScaleY; |
FT_Matrix fMatrix22; |
uint32_t fLoadGlyphFlags; |
@@ -729,6 +732,110 @@ int SkTypeface_FreeType::onGetUPEM() const { |
return face ? face->units_per_EM : 0; |
} |
+#ifdef DEBUG_METRICS |
+static void dumpFTFaceMetrics(const FT_Face face) { |
+ SkASSERT(face); |
+ SkDebugf(" units_per_EM: %hu\n", face->units_per_EM); |
+ SkDebugf(" ascender: %hd\n", face->ascender); |
+ SkDebugf(" descender: %hd\n", face->descender); |
+ SkDebugf(" height: %hd\n", face->height); |
+ SkDebugf(" max_advance_width: %hd\n", face->max_advance_width); |
+ SkDebugf(" max_advance_height: %hd\n", face->max_advance_height); |
+} |
+ |
+static void dumpFTSize(const FT_Size size) { |
+ SkASSERT(size); |
+ SkDebugf(" x_ppem: %hu\n", size->metrics.x_ppem); |
+ SkDebugf(" y_ppem: %hu\n", size->metrics.y_ppem); |
+ SkDebugf(" x_scale: %f\n", size->metrics.x_scale / 65536.0f); |
+ SkDebugf(" y_scale: %f\n", size->metrics.y_scale / 65536.0f); |
+ SkDebugf(" ascender: %f\n", size->metrics.ascender / 64.0f); |
+ SkDebugf(" descender: %f\n", size->metrics.descender / 64.0f); |
+ SkDebugf(" height: %f\n", size->metrics.height / 64.0f); |
+ SkDebugf(" max_advance: %f\n", size->metrics.max_advance / 64.0f); |
+} |
+ |
+static void dumpBitmapStrikeMetrics(const FT_Face face, int strikeIndex) { |
+ SkASSERT(face); |
+ SkASSERT(strikeIndex >= 0 && strikeIndex < face->num_fixed_sizes); |
+ SkDebugf(" height: %hd\n", face->available_sizes[strikeIndex].height); |
+ SkDebugf(" width: %hd\n", face->available_sizes[strikeIndex].width); |
+ SkDebugf(" size: %f\n", face->available_sizes[strikeIndex].size / 64.0f); |
+ SkDebugf(" x_ppem: %f\n", face->available_sizes[strikeIndex].x_ppem / 64.0f); |
+ SkDebugf(" y_ppem: %f\n", face->available_sizes[strikeIndex].y_ppem / 64.0f); |
+} |
+ |
+static void dumpSkFontMetrics(const SkPaint::FontMetrics& metrics) { |
+ SkDebugf(" fTop: %f\n", metrics.fTop); |
+ SkDebugf(" fAscent: %f\n", metrics.fAscent); |
+ SkDebugf(" fDescent: %f\n", metrics.fDescent); |
+ SkDebugf(" fBottom: %f\n", metrics.fBottom); |
+ SkDebugf(" fLeading: %f\n", metrics.fLeading); |
+ SkDebugf(" fAvgCharWidth: %f\n", metrics.fAvgCharWidth); |
+ SkDebugf(" fXMin: %f\n", metrics.fXMin); |
+ SkDebugf(" fXMax: %f\n", metrics.fXMax); |
+ SkDebugf(" fXHeight: %f\n", metrics.fXHeight); |
+} |
+ |
+static void dumpSkGlyphMetrics(const SkGlyph& glyph) { |
+ SkDebugf(" fAdvanceX: %f\n", SkFixedToScalar(glyph.fAdvanceX)); |
+ SkDebugf(" fAdvanceY: %f\n", SkFixedToScalar(glyph.fAdvanceY)); |
+ SkDebugf(" fWidth: %hu\n", glyph.fWidth); |
+ SkDebugf(" fHeight: %hu\n", glyph.fHeight); |
+ SkDebugf(" fTop: %hd\n", glyph.fTop); |
+ SkDebugf(" fLeft: %hd\n", glyph.fLeft); |
+} |
+#endif |
+ |
+static FT_Int chooseBitmapStrike(FT_Face face, SkFixed scaleY) { |
+ // early out if face is bad |
+ if (face == NULL) { |
+ SkDEBUGF(("chooseBitmapStrike aborted due to NULL face\n")); |
+ return -1; |
+ } |
+ // determine target ppem |
+ FT_Pos targetPPEM = SkFixedToFDot6(scaleY); |
+ // find a bitmap strike equal to or just larger than the requested size |
+ FT_Int chosenStrikeIndex = -1; |
+ FT_Pos chosenPPEM = 0; |
+ for (FT_Int strikeIndex = 0; strikeIndex < face->num_fixed_sizes; ++strikeIndex) { |
+ FT_Pos thisPPEM = face->available_sizes[strikeIndex].y_ppem; |
+ if (thisPPEM == targetPPEM) { |
+ // exact match - our search stops here |
+ chosenPPEM = thisPPEM; |
+ chosenStrikeIndex = strikeIndex; |
+ break; |
+ } else if (chosenPPEM < targetPPEM) { |
+ // attempt to increase chosenPPEM |
+ if (thisPPEM > chosenPPEM) { |
+ chosenPPEM = thisPPEM; |
+ chosenStrikeIndex = strikeIndex; |
+ } |
+ } else { |
+ // attempt to decrease chosenPPEM, but not below targetPPEM |
+ if (thisPPEM < chosenPPEM && thisPPEM > targetPPEM) { |
+ chosenPPEM = thisPPEM; |
+ chosenStrikeIndex = strikeIndex; |
+ } |
+ } |
+ } |
+ if (chosenStrikeIndex != -1) { |
+ // use the chosen strike |
+#ifdef DEBUG_METRICS |
+ SkDebugf("chooseBitmapStrike: chose strike %d for face \"%s\" at size %f\n", |
+ chosenStrikeIndex, face->family_name, SkFixedToScalar(scaleY)); |
+ dumpBitmapStrikeMetrics(face, chosenStrikeIndex); |
+#endif |
+ FT_Error err = FT_Select_Size(face, chosenStrikeIndex); |
+ if (err != 0) { |
+ SkDEBUGF(("FT_Select_Size(%s, %d) returned 0x%x\n", face->family_name, |
+ chosenStrikeIndex, err)); |
+ chosenStrikeIndex = -1; |
+ } |
+ } |
+ return chosenStrikeIndex; |
+} |
+ |
SkScalerContext_FreeType::SkScalerContext_FreeType(SkTypeface* typeface, |
const SkDescriptor* desc) |
: SkScalerContext_FreeType_Base(typeface, desc) { |
@@ -742,6 +849,7 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(SkTypeface* typeface, |
++gFTCount; |
// load the font file |
+ fStrikeIndex = -1; |
fFTSize = NULL; |
fFace = NULL; |
fFaceRec = ref_ft_face(typeface); |
@@ -801,9 +909,9 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(SkTypeface* typeface, |
fLCDIsVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag); |
// compute the flags we send to Load_Glyph |
+ bool linearMetrics = SkToBool(fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag); |
{ |
FT_Int32 loadFlags = FT_LOAD_DEFAULT; |
- bool linearMetrics = SkToBool(fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag); |
if (SkMask::kBW_Format == fRec.fMaskFormat) { |
// See http://code.google.com/p/chromium/issues/detail?id=43252#c24 |
@@ -861,42 +969,51 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(SkTypeface* typeface, |
loadFlags |= FT_LOAD_VERTICAL_LAYOUT; |
} |
+#ifdef FT_LOAD_COLOR |
+ loadFlags |= FT_LOAD_COLOR; |
+#endif |
+ |
fLoadGlyphFlags = loadFlags; |
- fDoLinearMetrics = linearMetrics; |
} |
- // now create the FT_Size |
- |
- { |
- FT_Error err; |
- |
- err = FT_New_Size(fFace, &fFTSize); |
- if (err != 0) { |
- SkDEBUGF(("SkScalerContext_FreeType::FT_New_Size(%x): FT_Set_Char_Size(0x%x, 0x%x) returned 0x%x\n", |
- fFaceRec->fFontID, fScaleX, fScaleY, err)); |
- fFace = NULL; |
- return; |
- } |
+ FT_Error err = FT_New_Size(fFace, &fFTSize); |
+ if (err != 0) { |
+ SkDEBUGF(("FT_New_Size returned %x for face %s\n", err, fFace->family_name)); |
+ fFace = NULL; |
+ return; |
+ } |
+ err = FT_Activate_Size(fFTSize); |
+ if (err != 0) { |
+ SkDEBUGF(("FT_Activate_Size(%08x, 0x%x, 0x%x) returned 0x%x\n", fFace, fScaleX, fScaleY, |
+ err)); |
+ fFTSize = NULL; |
+ return; |
+ } |
- err = FT_Activate_Size(fFTSize); |
- if (err != 0) { |
- SkDEBUGF(("SkScalerContext_FreeType::FT_Activate_Size(%x, 0x%x, 0x%x) returned 0x%x\n", |
- fFaceRec->fFontID, fScaleX, fScaleY, err)); |
- fFTSize = NULL; |
- } |
+ if (fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag) { |
+ fStrikeIndex = chooseBitmapStrike(fFace, fScaleY); |
+ } |
- err = FT_Set_Char_Size( fFace, |
- SkFixedToFDot6(fScaleX), SkFixedToFDot6(fScaleY), |
- 72, 72); |
- if (err != 0) { |
- SkDEBUGF(("SkScalerContext_FreeType::FT_Set_Char_Size(%x, 0x%x, 0x%x) returned 0x%x\n", |
- fFaceRec->fFontID, fScaleX, fScaleY, err)); |
- fFace = NULL; |
- return; |
+ if (fStrikeIndex == -1) { |
+ if (fFace->face_flags & FT_FACE_FLAG_SCALABLE) { |
+ err = FT_Set_Char_Size(fFace, |
+ SkFixedToFDot6(fScaleX), SkFixedToFDot6(fScaleY), |
+ 72, 72); |
+ if (err != 0) { |
+ SkDEBUGF(("FT_Set_CharSize(%08x, 0x%x, 0x%x) returned 0x%x\n", fFace, fScaleX, |
+ fScaleY, err)); |
+ fFace = NULL; |
+ return; |
+ } |
+ FT_Set_Transform(fFace, &fMatrix22, NULL); |
+ } else { |
+ SkDEBUGF(("no glyphs for font \"%s\" size %f?\n", fFace->family_name, |
+ SkFixedToScalar(fScaleY))); |
} |
- |
- FT_Set_Transform( fFace, &fMatrix22, NULL); |
+ } else { |
+ linearMetrics = false; // no linear metrics for bitmap fonts |
} |
+ fDoLinearMetrics = linearMetrics; |
} |
SkScalerContext_FreeType::~SkScalerContext_FreeType() { |
@@ -920,18 +1037,18 @@ SkScalerContext_FreeType::~SkScalerContext_FreeType() { |
this face with other context (at different sizes). |
*/ |
FT_Error SkScalerContext_FreeType::setupSize() { |
- FT_Error err = FT_Activate_Size(fFTSize); |
- |
+ FT_Error err = FT_Activate_Size(fFTSize); |
if (err != 0) { |
SkDEBUGF(("SkScalerContext_FreeType::FT_Activate_Size(%x, 0x%x, 0x%x) returned 0x%x\n", |
- fFaceRec->fFontID, fScaleX, fScaleY, err)); |
+ fFaceRec->fFontID, fScaleX, fScaleY, err)); |
fFTSize = NULL; |
- } else { |
- // seems we need to reset this every time (not sure why, but without it |
- // I get random italics from some other fFTSize) |
- FT_Set_Transform( fFace, &fMatrix22, NULL); |
+ return err; |
} |
- return err; |
+ |
+ // seems we need to reset this every time (not sure why, but without it |
+ // I get random italics from some other fFTSize) |
+ FT_Set_Transform(fFace, &fMatrix22, NULL); |
+ return 0; |
} |
unsigned SkScalerContext_FreeType::generateGlyphCount() { |
@@ -1041,6 +1158,17 @@ void SkScalerContext_FreeType::updateGlyphIfLCD(SkGlyph* glyph) { |
} |
} |
+inline void scaleGlyphMetrics(SkGlyph& glyph, SkScalar scale) { |
+ glyph.fWidth *= scale; |
+ glyph.fHeight *= scale; |
+ glyph.fTop *= scale; |
+ glyph.fLeft *= scale; |
+ |
+ SkFixed fixedScale = SkScalarToFixed(scale); |
+ glyph.fAdvanceX = SkFixedMul(glyph.fAdvanceX, fixedScale); |
+ glyph.fAdvanceY = SkFixedMul(glyph.fAdvanceY, fixedScale); |
+} |
+ |
void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) { |
SkAutoMutexAcquire ac(gFTMutex); |
@@ -1065,32 +1193,28 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) { |
} |
switch ( fFace->glyph->format ) { |
- case FT_GLYPH_FORMAT_OUTLINE: { |
- FT_BBox bbox; |
- |
+ case FT_GLYPH_FORMAT_OUTLINE: |
if (0 == fFace->glyph->outline.n_contours) { |
glyph->fWidth = 0; |
glyph->fHeight = 0; |
glyph->fTop = 0; |
glyph->fLeft = 0; |
- break; |
- } |
- |
- if (fRec.fFlags & kEmbolden_Flag) { |
- emboldenOutline(fFace, &fFace->glyph->outline); |
- } |
- |
- getBBoxForCurrentGlyph(glyph, &bbox, true); |
+ } else { |
+ if (fRec.fFlags & kEmbolden_Flag && !(fFace->style_flags & FT_STYLE_FLAG_BOLD)) { |
+ emboldenOutline(fFace, &fFace->glyph->outline); |
+ } |
- glyph->fWidth = SkToU16(SkFDot6Floor(bbox.xMax - bbox.xMin)); |
- glyph->fHeight = SkToU16(SkFDot6Floor(bbox.yMax - bbox.yMin)); |
- glyph->fTop = -SkToS16(SkFDot6Floor(bbox.yMax)); |
- glyph->fLeft = SkToS16(SkFDot6Floor(bbox.xMin)); |
+ FT_BBox bbox; |
+ getBBoxForCurrentGlyph(glyph, &bbox, true); |
- updateGlyphIfLCD(glyph); |
+ glyph->fWidth = SkToU16(SkFDot6Floor(bbox.xMax - bbox.xMin)); |
+ glyph->fHeight = SkToU16(SkFDot6Floor(bbox.yMax - bbox.yMin)); |
+ glyph->fTop = -SkToS16(SkFDot6Floor(bbox.yMax)); |
+ glyph->fLeft = SkToS16(SkFDot6Floor(bbox.xMin)); |
+ updateGlyphIfLCD(glyph); |
+ } |
break; |
- } |
case FT_GLYPH_FORMAT_BITMAP: |
if (fRec.fFlags & kEmbolden_Flag) { |
@@ -1107,6 +1231,12 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) { |
fFace->glyph->bitmap_top += SkFDot6Floor(vector.y); |
} |
+#ifdef FT_LOAD_COLOR |
bungeman-skia
2013/11/22 18:09:14
Maybe these are equivalent (in that they were adde
bungeman-skia
2013/11/25 16:32:50
Ack, now I see the issue, FT_LOAD_COLOR is a macro
|
+ if (fFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) { |
+ glyph->fMaskFormat = SkMask::kARGB32_Format; |
+ } |
+#endif |
+ |
glyph->fWidth = SkToU16(fFace->glyph->bitmap.width); |
glyph->fHeight = SkToU16(fFace->glyph->bitmap.rows); |
glyph->fTop = -SkToS16(fFace->glyph->bitmap_top); |
@@ -1141,6 +1271,20 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) { |
} |
} |
+ if (fFace->glyph->format == FT_GLYPH_FORMAT_BITMAP && fScaleY && fFace->size->metrics.y_ppem) { |
+#ifdef DEBUG_METRICS |
+ SkDebugf("pre-scale glyph metrics:\n"); |
+ dumpSkGlyphMetrics(*glyph); |
+#endif |
+ // NOTE: both dimensions are scaled by y_ppem. this is WAI. |
+ scaleGlyphMetrics(*glyph, SkScalarDiv(SkFixedToScalar(fScaleY), |
+ SkIntToScalar(fFace->size->metrics.y_ppem))); |
+ } |
+#ifdef DEBUG_METRICS |
+ SkDebugf("post-scale glyph metrics:\n"); |
+ dumpSkGlyphMetrics(*glyph); |
+#endif |
+ |
#ifdef ENABLE_GLYPH_SPEW |
SkDEBUGF(("FT_Set_Char_Size(this:%p sx:%x sy:%x ", this, fScaleX, fScaleY)); |
@@ -1208,16 +1352,16 @@ void SkScalerContext_FreeType::generatePath(const SkGlyph& glyph, |
} |
} |
-void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* mx, |
- SkPaint::FontMetrics* my) { |
+#ifdef DEBUG_METRICS |
+void generateFontMetricsOLD(FT_Face face, SkScalar scaleX, SkScalar scaleY, |
+ uint32_t loadGlyphFlags, uint16_t recFlags, SkMatrix matrix22Scalar, |
+ SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my) { |
if (NULL == mx && NULL == my) { |
return; |
} |
- SkAutoMutexAcquire ac(gFTMutex); |
- |
- if (this->setupSize()) { |
- ERROR: |
+ if (false) { |
+ ERROR: |
if (mx) { |
sk_bzero(mx, sizeof(SkPaint::FontMetrics)); |
} |
@@ -1227,7 +1371,6 @@ void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* mx, |
return; |
} |
- FT_Face face = fFace; |
int upem = face->units_per_EM; |
if (upem <= 0) { |
goto ERROR; |
@@ -1235,9 +1378,8 @@ void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* mx, |
SkPoint pts[6]; |
SkFixed ys[6]; |
- SkScalar scaleY = fScale.y(); |
- SkScalar mxy = fMatrix22Scalar.getSkewX(); |
- SkScalar myy = fMatrix22Scalar.getScaleY(); |
+ SkScalar mxy = matrix22Scalar.getSkewX(); |
+ SkScalar myy = matrix22Scalar.getScaleY(); |
SkScalar xmin = SkIntToScalar(face->bbox.xMin) / upem; |
SkScalar xmax = SkIntToScalar(face->bbox.xMax) / upem; |
@@ -1246,8 +1388,6 @@ void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* mx, |
leading = 0; |
} |
- // Try to get the OS/2 table from the font. This contains the specific |
- // average font width metrics which Windows uses. |
TT_OS2* os2 = (TT_OS2*) FT_Get_Sfnt_Table(face, ft_sfnt_os2); |
ys[0] = -face->bbox.yMax; |
@@ -1259,23 +1399,22 @@ void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* mx, |
SkScalar x_height; |
if (os2 && os2->sxHeight) { |
- x_height = fScale.x() * os2->sxHeight / upem; |
+ x_height = scaleX * os2->sxHeight / upem; |
} else { |
- const FT_UInt x_glyph = FT_Get_Char_Index(fFace, 'x'); |
+ const FT_UInt x_glyph = FT_Get_Char_Index(face, 'x'); |
if (x_glyph) { |
FT_BBox bbox; |
- FT_Load_Glyph(fFace, x_glyph, fLoadGlyphFlags); |
- if (fRec.fFlags & kEmbolden_Flag) { |
- emboldenOutline(fFace, &fFace->glyph->outline); |
+ FT_Load_Glyph(face, x_glyph, loadGlyphFlags); |
+ if (recFlags & SkScalerContext::kEmbolden_Flag) { |
+ SkDebugf("x_height is incorrect (skipped embolden step)\n"); |
} |
- FT_Outline_Get_CBox(&fFace->glyph->outline, &bbox); |
+ FT_Outline_Get_CBox(&face->glyph->outline, &bbox); |
x_height = bbox.yMax / 64.0f; |
- } else { |
+ } else { |
x_height = 0; |
- } |
+ } |
} |
- // convert upem-y values into scalar points |
for (int i = 0; i < 6; i++) { |
SkScalar y = scaleY * ys[i] / upem; |
pts[i].set(y * mxy, y * myy); |
@@ -1291,8 +1430,11 @@ void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* mx, |
mx->fXMin = xmin; |
mx->fXMax = xmax; |
mx->fXHeight = x_height; |
- } |
- if (my) { |
+ SkDebugf("generateFontMetricsOLD(\"%s\"): mx is:\n", face->family_name); |
+ dumpSkFontMetrics(*mx); |
+ } |
+ |
+ if (my) { |
my->fTop = pts[0].fY; |
my->fAscent = pts[1].fY; |
my->fDescent = pts[2].fY; |
@@ -1302,6 +1444,154 @@ void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* mx, |
my->fXMin = xmin; |
my->fXMax = xmax; |
my->fXHeight = x_height; |
+ SkDebugf("generateFontMetricsOLD(\"%s\"): my is:\n", face->family_name); |
+ dumpSkFontMetrics(*my); |
+ } |
+} |
+#endif |
+ |
+void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* mx, |
+ SkPaint::FontMetrics* my) { |
+ if (NULL == mx && NULL == my) { |
+ return; |
+ } |
+ |
+ SkAutoMutexAcquire ac(gFTMutex); |
+ |
+ if (this->setupSize()) { |
+ ERROR: |
+ if (mx) { |
+ sk_bzero(mx, sizeof(SkPaint::FontMetrics)); |
+ } |
+ if (my) { |
+ sk_bzero(my, sizeof(SkPaint::FontMetrics)); |
+ } |
+ return; |
+ } |
+ |
+ FT_Face face = fFace; |
+ SkScalar scaleX = fScale.x(); |
+ SkScalar scaleY = fScale.y(); |
+ SkScalar mxy = fMatrix22Scalar.getSkewX() * scaleY; |
+ SkScalar myy = fMatrix22Scalar.getScaleY() * scaleY; |
+ |
+#ifdef DEBUG_METRICS |
+ SkDebugf("generateFontMetrics(\"%s\"):\n", face->family_name); |
+ dumpFTFaceMetrics(face); |
+ dumpFTSize(face->size); |
+#endif |
+ |
+ // fetch units/EM from "head" table if needed (ie for bitmap fonts) |
+ SkScalar upem = SkIntToScalar(face->units_per_EM); |
+ if (!upem) { |
+ TT_Header* ttHeader = (TT_Header*)FT_Get_Sfnt_Table(face, ft_sfnt_head); |
+ if (ttHeader) { |
+ upem = SkIntToScalar(ttHeader->Units_Per_EM); |
+ } |
+ } |
+ |
+ // use the os/2 table as a source of reasonable defaults. |
+ SkScalar x_height = 0.0f; |
+ SkScalar avgCharWidth = 0.0f; |
+ TT_OS2* os2 = (TT_OS2*) FT_Get_Sfnt_Table(face, ft_sfnt_os2); |
+ if (os2) { |
+ x_height = scaleX * SkIntToScalar(os2->sxHeight) / upem; |
+ avgCharWidth = SkIntToScalar(os2->xAvgCharWidth) / upem; |
+ } |
+ |
+ // pull from format-specific metrics as needed |
+ SkScalar ascent, descent, leading, xmin, xmax, ymin, ymax; |
+ if (face->face_flags & FT_FACE_FLAG_SCALABLE) { // scalable outline font |
+ ascent = -SkIntToScalar(face->ascender) / upem; |
+ descent = -SkIntToScalar(face->descender) / upem; |
+ leading = SkIntToScalar(face->height + (face->descender - face->ascender)) / upem; |
+ xmin = SkIntToScalar(face->bbox.xMin) / upem; |
+ xmax = SkIntToScalar(face->bbox.xMax) / upem; |
+ ymin = -SkIntToScalar(face->bbox.yMin) / upem; |
+ ymax = -SkIntToScalar(face->bbox.yMax) / upem; |
+ // we may be able to synthesize x_height from outline |
+ if (!x_height) { |
+ const FT_UInt x_glyph = FT_Get_Char_Index(fFace, 'x'); |
+ if (x_glyph) { |
+ FT_BBox bbox; |
+ FT_Load_Glyph(fFace, x_glyph, fLoadGlyphFlags); |
+ if ((fRec.fFlags & kEmbolden_Flag) && !(fFace->style_flags & FT_STYLE_FLAG_BOLD)) { |
+ emboldenOutline(fFace, &fFace->glyph->outline); |
+ } |
+ FT_Outline_Get_CBox(&fFace->glyph->outline, &bbox); |
+ x_height = SkIntToScalar(bbox.yMax) / 64.0f; |
+ } |
+ } |
+ } else if (fStrikeIndex != -1) { // bitmap strike metrics |
+#ifdef DEBUG_METRICS |
+ dumpBitmapStrikeMetrics(fFace, fStrikeIndex); |
+#endif |
+ SkScalar xppem = SkIntToScalar(face->size->metrics.x_ppem); |
+ SkScalar yppem = SkIntToScalar(face->size->metrics.y_ppem); |
+ ascent = -SkIntToScalar(face->size->metrics.ascender) / (yppem * 64.0f); |
+ descent = -SkIntToScalar(face->size->metrics.descender) / (yppem * 64.0f); |
+ leading = (SkIntToScalar(face->size->metrics.height) / (yppem * 64.0f)) |
+ + ascent - descent; |
+ xmin = 0.0f; |
+ xmax = SkIntToScalar(face->available_sizes[fStrikeIndex].width) / xppem; |
+ ymin = descent + leading; |
+ ymax = ascent - descent; |
+ if (!x_height) { |
+ x_height = -ascent; |
+ } |
+ if (!avgCharWidth) { |
+ avgCharWidth = xmax - xmin; |
+ } |
+ } else { |
+ goto ERROR; |
+ } |
+ |
+ // synthesize elements that were not provided by the os/2 table or format-specific metrics |
+ if (!x_height) { |
+ x_height = -ascent; |
+ } |
+ if (!avgCharWidth) { |
+ avgCharWidth = xmax - xmin; |
+ } |
+ |
+ // disallow negative linespacing |
+ if (leading < 0.0f) { |
+ leading = 0.0f; |
+ } |
+ |
+#ifdef DEBUG_METRICS |
+ generateFontMetricsOLD(fFace, fScale.x(), fScale.y(), fLoadGlyphFlags, fRec.fFlags, |
+ fMatrix22Scalar, mx, my); |
+#endif |
+ if (mx) { |
+ mx->fTop = ymax * mxy; |
+ mx->fAscent = ascent * mxy; |
+ mx->fDescent = descent * mxy; |
+ mx->fBottom = ymin * mxy; |
+ mx->fLeading = leading * mxy; |
+ mx->fAvgCharWidth = avgCharWidth * mxy; |
+ mx->fXMin = xmin; |
+ mx->fXMax = xmax; |
+ mx->fXHeight = x_height; |
+#ifdef DEBUG_METRICS |
+ SkDebugf("generateFontMetrics(\"%s\"): mx is:\n", face->family_name); |
+ dumpSkFontMetrics(*mx); |
+#endif |
+ } |
+ if (my) { |
+ my->fTop = ymax * myy; |
+ my->fAscent = ascent * myy; |
+ my->fDescent = descent * myy; |
+ my->fBottom = ymin * myy; |
+ my->fLeading = leading * myy; |
+ my->fAvgCharWidth = avgCharWidth * myy; |
+ my->fXMin = xmin; |
+ my->fXMax = xmax; |
+ my->fXHeight = x_height; |
+#ifdef DEBUG_METRICS |
+ SkDebugf("generateFontMetrics(\"%s\"): my is:\n", face->family_name); |
+ dumpSkFontMetrics(*my); |
+#endif |
} |
} |