Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(904)

Unified Diff: src/ports/SkFontHost_FreeType.cpp

Issue 23684041: improve bitmap font support (FreeType only) (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/ports/SkFontHost_FreeType.cpp
===================================================================
--- src/ports/SkFontHost_FreeType.cpp (revision 12480)
+++ src/ports/SkFontHost_FreeType.cpp (working copy)
@@ -58,11 +58,28 @@
#include <freetype/ftsynth.h>
#endif
+// FT_LOAD_COLOR and the corresponding FT_Pixel_Mode::FT_PIXEL_MODE_BGRA
+// were introduced in FreeType 2.5.0.
+// The following may be removed once FreeType 2.5.0 is required to build.
+#ifndef FT_LOAD_COLOR
+# define FT_LOAD_COLOR ( 1L << 20 )
+# define FT_PIXEL_MODE_BGRA 7
+#endif
+
+// FT_HAS_COLOR and the corresponding FT_FACE_FLAG_COLOR
+// were introduced in FreeType 2.5.1
+// The following may be removed once FreeType 2.5.1 is required to build.
+#ifndef FT_HAS_COLOR
+# define FT_HAS_COLOR(face) false
+#endif
+
//#define ENABLE_GLYPH_SPEW // for tracing calls
//#define DUMP_STRIKE_CREATION
//#define SK_GAMMA_APPLY_TO_A8
+//#define DEBUG_METRICS
+
using namespace skia_advanced_typeface_metrics_utils;
static bool isLCD(const SkScalerContext::Rec& rec) {
@@ -184,6 +201,7 @@
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;
@@ -751,6 +769,110 @@
return true;
}
+#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) {
@@ -764,6 +886,7 @@
++gFTCount;
// load the font file
+ fStrikeIndex = -1;
fFTSize = NULL;
fFace = NULL;
fFaceRec = ref_ft_face(typeface);
@@ -823,9 +946,9 @@
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
@@ -883,42 +1006,51 @@
loadFlags |= FT_LOAD_VERTICAL_LAYOUT;
}
+ loadFlags |= FT_LOAD_COLOR;
+
fLoadGlyphFlags = loadFlags;
- fDoLinearMetrics = linearMetrics;
}
- // now create the FT_Size
+ 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;
+ }
- {
- FT_Error err;
+ if (fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag) {
+ fStrikeIndex = chooseBitmapStrike(fFace, fScaleY);
+ }
- 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;
+ 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)));
}
-
- 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;
- }
-
- 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;
- }
-
- FT_Set_Transform( fFace, &fMatrix22, NULL);
+ } else {
+ // Bitmap fonts do not provide linear metrics.
+ // In some sense, these are always linear.
+ linearMetrics = false;
}
+ fDoLinearMetrics = linearMetrics;
}
SkScalerContext_FreeType::~SkScalerContext_FreeType() {
@@ -942,18 +1074,18 @@
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() {
@@ -1063,6 +1195,17 @@
}
}
+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);
@@ -1087,32 +1230,28 @@
}
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;
- }
+ } else {
+ if (fRec.fFlags & kEmbolden_Flag && !(fFace->style_flags & FT_STYLE_FLAG_BOLD)) {
+ emboldenOutline(fFace, &fFace->glyph->outline);
+ }
- if (fRec.fFlags & kEmbolden_Flag) {
- emboldenOutline(fFace, &fFace->glyph->outline);
- }
+ FT_BBox bbox;
+ getBBoxForCurrentGlyph(glyph, &bbox, true);
- getBBoxForCurrentGlyph(glyph, &bbox, true);
+ 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));
- 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);
-
+ updateGlyphIfLCD(glyph);
+ }
break;
- }
case FT_GLYPH_FORMAT_BITMAP:
if (fRec.fFlags & kEmbolden_Flag) {
@@ -1129,6 +1268,10 @@
fFace->glyph->bitmap_top += SkFDot6Floor(vector.y);
}
+ if (fFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) {
+ glyph->fMaskFormat = SkMask::kARGB32_Format;
+ }
+
glyph->fWidth = SkToU16(fFace->glyph->bitmap.width);
glyph->fHeight = SkToU16(fFace->glyph->bitmap.rows);
glyph->fTop = -SkToS16(fFace->glyph->bitmap_top);
@@ -1163,7 +1306,21 @@
}
}
+ 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));
SkDEBUGF(("Metrics(glyph:%d flags:0x%x) w:%d\n", glyph->getGlyphID(fBaseGlyphCount), fLoadGlyphFlags, glyph->fWidth));
@@ -1230,16 +1387,16 @@
}
}
-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) {
reed1 2013/12/09 16:58:42 Can we move this to the upem check directly?
bungeman-skia 2013/12/09 19:42:44 Not sure if this comment is in the right place? Th
+ ERROR:
if (mx) {
sk_bzero(mx, sizeof(SkPaint::FontMetrics));
}
@@ -1249,7 +1406,6 @@
return;
}
- FT_Face face = fFace;
int upem = face->units_per_EM;
if (upem <= 0) {
goto ERROR;
@@ -1257,9 +1413,8 @@
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;
@@ -1268,8 +1423,6 @@
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;
@@ -1281,23 +1434,22 @@
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);
@@ -1313,8 +1465,11 @@
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;
@@ -1324,7 +1479,155 @@
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
+ }
}
///////////////////////////////////////////////////////////////////////////////

Powered by Google App Engine
This is Rietveld 408576698