Index: src/ports/SkFontHost_FreeType.cpp |
diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp |
index fd87a66dc6a8f8d9da40fb993c459e8d4e52a966..a50939c7f47e4729e6f56d3c62bea36b433e9c74 100644 |
--- a/src/ports/SkFontHost_FreeType.cpp |
+++ b/src/ports/SkFontHost_FreeType.cpp |
@@ -190,6 +190,11 @@ private: |
bool fDoLinearMetrics; |
bool fLCDIsVert; |
+ // since different scalercontext may share the same face |
+ // using a ID to identify which settings are activated |
+ // this can help us to skip some unnecessary FreeType2 calls |
+ uint32_t fUniqueID; |
+ |
// Need scalar versions for generateFontMetrics |
SkVector fScale; |
SkMatrix fMatrix22Scalar; |
@@ -212,6 +217,14 @@ struct SkFaceRec { |
uint32_t fRefCnt; |
uint32_t fFontID; |
+ // record some information about the last glyph loaded |
+ // drawText will generateImage just after generateMetrics in most cases |
+ // a simple check can help us to skip the unnecessary call to FT_Load_Glyph |
+ // which is time consuming, especially for composite glyphs |
+ uint32_t fActivatedContextID; |
+ // glyph that has been already loaded, which is also ready for generateImage |
+ uint16_t fGlyphLoaded; |
+ |
// assumes ownership of the stream, will call unref() when its done |
SkFaceRec(SkStream* strm, uint32_t fontID); |
~SkFaceRec() { |
@@ -349,6 +362,9 @@ public: |
fRec = ref_ft_face(tf); |
if (fRec) { |
fFace = fRec->fFace; |
+ // someone will access to the FreeType face |
+ fRec->fActivatedContextID = 0; |
+ fRec->fGlyphLoaded = 0; |
} |
} |
@@ -772,6 +788,11 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(SkTypeface* typeface, |
} |
fFace = fFaceRec->fFace; |
+ // set ID for current scaler context |
+ // start from 1, regarding 0 as invalid |
+ static uint32_t gScalerContextID = 1; |
+ fUniqueID = gScalerContextID++; |
+ |
// compute our factors from the record |
SkMatrix m; |
@@ -892,6 +913,11 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(SkTypeface* typeface, |
{ |
FT_Error err; |
+ // no activated scaler context setting for the face |
+ fFaceRec->fActivatedContextID = 0; |
+ // regarding glyph 0 as an invalid glyph outline that we need to reload |
+ fFaceRec->fGlyphLoaded = 0; |
+ |
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", |
@@ -918,6 +944,9 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(SkTypeface* typeface, |
} |
FT_Set_Transform( fFace, &fMatrix22, NULL); |
+ |
+ // current scaler context setting is enabled for the face |
+ fFaceRec->fActivatedContextID = fUniqueID; |
} |
} |
@@ -942,16 +971,24 @@ 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 = 0; |
- 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; |
- } 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); |
+ if (fFaceRec->fActivatedContextID != fUniqueID) { |
+ // no scalercontext settings are activated for the FreeType face now |
+ fFaceRec->fActivatedContextID = 0; |
+ fFaceRec->fGlyphLoaded = 0; |
+ 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; |
+ } 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); |
+ // current scalercontext settings are activated |
+ fFaceRec->fActivatedContextID = fUniqueID; |
+ } |
} |
return err; |
} |
@@ -1075,7 +1112,9 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) { |
goto ERROR; |
} |
- err = FT_Load_Glyph( fFace, glyph->getGlyphID(fBaseGlyphCount), fLoadGlyphFlags ); |
+ // this glyph will be loaded to FreeType glyph slot |
+ fFaceRec->fGlyphLoaded = glyph->getGlyphID(fBaseGlyphCount); |
+ err = FT_Load_Glyph( fFace, fFaceRec->fGlyphLoaded, fLoadGlyphFlags ); |
if (err != 0) { |
#if 0 |
SkDEBUGF(("SkScalerContext_FreeType::generateMetrics(%x): FT_Load_Glyph(glyph:%d flags:%x) returned 0x%x\n", |
@@ -1083,8 +1122,11 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) { |
#endif |
ERROR: |
glyph->zeroMetrics(); |
+ // glyph not loadded |
+ fFaceRec->fGlyphLoaded = 0; |
return; |
} |
+ emboldenIfNeeded(fFace, fFace->glyph); |
switch ( fFace->glyph->format ) { |
case FT_GLYPH_FORMAT_OUTLINE: { |
@@ -1098,10 +1140,6 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) { |
break; |
} |
- if (fRec.fFlags & kEmbolden_Flag) { |
- emboldenOutline(fFace, &fFace->glyph->outline); |
- } |
- |
getBBoxForCurrentGlyph(glyph, &bbox, true); |
glyph->fWidth = SkToU16(SkFDot6Floor(bbox.xMax - bbox.xMin)); |
@@ -1115,11 +1153,6 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) { |
} |
case FT_GLYPH_FORMAT_BITMAP: |
- if (fRec.fFlags & kEmbolden_Flag) { |
- FT_GlyphSlot_Own_Bitmap(fFace->glyph); |
- FT_Bitmap_Embolden(gFTLibrary, &fFace->glyph->bitmap, kBitmapEmboldenStrength, 0); |
- } |
- |
if (fRec.fFlags & SkScalerContext::kVertical_Flag) { |
FT_Vector vector; |
vector.x = fFace->glyph->metrics.vertBearingX - fFace->glyph->metrics.horiBearingX; |
@@ -1175,18 +1208,26 @@ void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph) { |
SkAutoMutexAcquire ac(gFTMutex); |
FT_Error err; |
+ uint16_t glyphLoaded; |
if (this->setupSize()) { |
goto ERROR; |
} |
- err = FT_Load_Glyph( fFace, glyph.getGlyphID(fBaseGlyphCount), fLoadGlyphFlags); |
- if (err != 0) { |
- SkDEBUGF(("SkScalerContext_FreeType::generateImage: FT_Load_Glyph(glyph:%d width:%d height:%d rb:%d flags:%d) returned 0x%x\n", |
- glyph.getGlyphID(fBaseGlyphCount), glyph.fWidth, glyph.fHeight, glyph.rowBytes(), fLoadGlyphFlags, err)); |
- ERROR: |
- memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight); |
- return; |
+ glyphLoaded = fFaceRec->fGlyphLoaded; |
+ // no need to remember what is in the FreeType glyph slot |
+ // since the skia glyph cache won't query image for the same glyph shortly |
+ fFaceRec->fGlyphLoaded = 0; |
+ if (glyphLoaded == 0 || glyphLoaded != glyph.getGlyphID(fBaseGlyphCount)) { |
+ err = FT_Load_Glyph( fFace, glyph.getGlyphID(fBaseGlyphCount), fLoadGlyphFlags); |
+ if (err != 0) { |
+ SkDEBUGF(("SkScalerContext_FreeType::generateImage: FT_Load_Glyph(glyph:%d width:%d height:%d rb:%d flags:%d) returned 0x%x\n", |
+ glyph.getGlyphID(fBaseGlyphCount), glyph.fWidth, glyph.fHeight, glyph.rowBytes(), fLoadGlyphFlags, err)); |
+ ERROR: |
+ memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight); |
+ return; |
+ } |
+ emboldenIfNeeded(fFace, fFace->glyph); |
} |
generateGlyphImage(fFace, glyph); |
@@ -1208,6 +1249,8 @@ void SkScalerContext_FreeType::generatePath(const SkGlyph& glyph, |
flags |= FT_LOAD_NO_BITMAP; // ignore embedded bitmaps so we're sure to get the outline |
flags &= ~FT_LOAD_RENDER; // don't scan convert (we just want the outline) |
+ // FreeType glyph slot will be invalid for generateImage |
+ fFaceRec->fGlyphLoaded = 0; |
FT_Error err = FT_Load_Glyph( fFace, glyph.getGlyphID(fBaseGlyphCount), flags); |
if (err != 0) { |
@@ -1216,6 +1259,7 @@ void SkScalerContext_FreeType::generatePath(const SkGlyph& glyph, |
path->reset(); |
return; |
} |
+ emboldenIfNeeded(fFace, fFace->glyph); |
generateGlyphPath(fFace, path); |
@@ -1286,10 +1330,10 @@ void SkScalerContext_FreeType::generateFontMetrics(SkPaint::FontMetrics* mx, |
const FT_UInt x_glyph = FT_Get_Char_Index(fFace, 'x'); |
if (x_glyph) { |
FT_BBox bbox; |
+ // just set the glyph to be invalid for generateImage |
+ fFaceRec->fGlyphLoaded = 0; |
FT_Load_Glyph(fFace, x_glyph, fLoadGlyphFlags); |
- if (fRec.fFlags & kEmbolden_Flag) { |
- emboldenOutline(fFace, &fFace->glyph->outline); |
- } |
+ emboldenIfNeeded(fFace, fFace->glyph); |
FT_Outline_Get_CBox(&fFace->glyph->outline, &bbox); |
x_height = bbox.yMax / 64.0f; |
} else { |