SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc) : SkScalerContext(desc) { SkAutoMutexAcquire ac(gFTMutex); if (gFTCount == 0) { if (!InitFreetype()) { sk_throw(); } } ++gFTCount; // load the font file fFTSize = NULL; fFace = NULL; fFaceRec = ref_ft_face(fRec.fFontID); if (NULL == fFaceRec) { return; } fFace = fFaceRec->fFace; // compute our factors from the record SkMatrix m; fRec.getSingleMatrix(&m); #ifdef DUMP_STRIKE_CREATION SkString keyString; SkFontHost::GetDescriptorKeyString(desc, &keyString); printf("========== strike [%g %g %g] [%g %g %g %g] hints %d format %d %s\n", SkScalarToFloat(fRec.fTextSize), SkScalarToFloat(fRec.fPreScaleX), SkScalarToFloat(fRec.fPreSkewX), SkScalarToFloat(fRec.fPost2x2[0][0]), SkScalarToFloat(fRec.fPost2x2[0][1]), SkScalarToFloat(fRec.fPost2x2[1][0]), SkScalarToFloat(fRec.fPost2x2[1][1]), fRec.getHinting(), fRec.fMaskFormat, keyString.c_str()); #endif // now compute our scale factors SkScalar sx = m.getScaleX(); SkScalar sy = m.getScaleY(); if (m.getSkewX() || m.getSkewY() || sx < 0 || sy < 0) { // sort of give up on hinting sx = SkMaxScalar(SkScalarAbs(sx), SkScalarAbs(m.getSkewX())); sy = SkMaxScalar(SkScalarAbs(m.getSkewY()), SkScalarAbs(sy)); sx = sy = SkScalarAve(sx, sy); SkScalar inv = SkScalarInvert(sx); // flip the skew elements to go from our Y-down system to FreeType's fMatrix22.xx = SkScalarToFixed(SkScalarMul(m.getScaleX(), inv)); fMatrix22.xy = -SkScalarToFixed(SkScalarMul(m.getSkewX(), inv)); fMatrix22.yx = -SkScalarToFixed(SkScalarMul(m.getSkewY(), inv)); fMatrix22.yy = SkScalarToFixed(SkScalarMul(m.getScaleY(), inv)); } else { fMatrix22.xx = fMatrix22.yy = SK_Fixed1; fMatrix22.xy = fMatrix22.yx = 0; } fScaleX = SkScalarToFixed(sx); fScaleY = SkScalarToFixed(sy); // compute the flags we send to Load_Glyph { FT_Int32 loadFlags = FT_LOAD_DEFAULT; if (SkMask::kBW_Format == fRec.fMaskFormat) { // See http://code.google.com/p/chromium/issues/detail?id=43252#c24 loadFlags = FT_LOAD_TARGET_MONO; if (fRec.getHinting() == SkPaint::kNo_Hinting) loadFlags = FT_LOAD_NO_HINTING; } else { switch (fRec.getHinting()) { case SkPaint::kNo_Hinting: loadFlags = FT_LOAD_NO_HINTING; break; case SkPaint::kSlight_Hinting: loadFlags = FT_LOAD_TARGET_LIGHT; // This implies FORCE_AUTOHINT break; case SkPaint::kNormal_Hinting: loadFlags = FT_LOAD_TARGET_NORMAL; break; case SkPaint::kFull_Hinting: loadFlags = FT_LOAD_TARGET_NORMAL; if (SkMask::kHorizontalLCD_Format == fRec.fMaskFormat) loadFlags = FT_LOAD_TARGET_LCD; else if (SkMask::kVerticalLCD_Format == fRec.fMaskFormat) loadFlags = FT_LOAD_TARGET_LCD_V; break; default: SkDebugf("---------- UNKNOWN hinting %d\n", fRec.getHinting()); break; } } if ((fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag) == 0) loadFlags |= FT_LOAD_NO_BITMAP; fLoadGlyphFlags = loadFlags; } // 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; } 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); } }
SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc) : SkScalerContext(desc), fFTSize(NULL) { SkAutoMutexAcquire ac(gFTMutex); FT_Error err; if (gFTCount == 0) { err = FT_Init_FreeType(&gFTLibrary); // SkDEBUGF(("FT_Init_FreeType returned %d\n", err)); SkASSERT(err == 0); } ++gFTCount; // load the font file fFaceRec = ref_ft_face(fRec.fFontID); fFace = fFaceRec ? fFaceRec->fFace : NULL; // compute our factors from the record SkMatrix m; fRec.getSingleMatrix(&m); #ifdef DUMP_STRIKE_CREATION SkString keyString; SkFontHost::GetDescriptorKeyString(desc, &keyString); printf("========== strike [%g %g %g] [%g %g %g %g] hints %d format %d %s\n", SkScalarToFloat(fRec.fTextSize), SkScalarToFloat(fRec.fPreScaleX), SkScalarToFloat(fRec.fPreSkewX), SkScalarToFloat(fRec.fPost2x2[0][0]), SkScalarToFloat(fRec.fPost2x2[0][1]), SkScalarToFloat(fRec.fPost2x2[1][0]), SkScalarToFloat(fRec.fPost2x2[1][1]), fRec.fHints, fRec.fMaskFormat, keyString.c_str()); #endif // now compute our scale factors SkScalar sx = m.getScaleX(); SkScalar sy = m.getScaleY(); if (m.getSkewX() || m.getSkewY() || sx < 0 || sy < 0) { // sort of give up on hinting sx = SkMaxScalar(SkScalarAbs(sx), SkScalarAbs(m.getSkewX())); sy = SkMaxScalar(SkScalarAbs(m.getSkewY()), SkScalarAbs(sy)); sx = sy = SkScalarAve(sx, sy); SkScalar inv = SkScalarInvert(sx); // flip the skew elements to go from our Y-down system to FreeType's fMatrix22.xx = SkScalarToFixed(SkScalarMul(m.getScaleX(), inv)); fMatrix22.xy = -SkScalarToFixed(SkScalarMul(m.getSkewX(), inv)); fMatrix22.yx = -SkScalarToFixed(SkScalarMul(m.getSkewY(), inv)); fMatrix22.yy = SkScalarToFixed(SkScalarMul(m.getScaleY(), inv)); } else { fMatrix22.xx = fMatrix22.yy = SK_Fixed1; fMatrix22.xy = fMatrix22.yx = 0; } fScaleX = SkScalarToFixed(sx); fScaleY = SkScalarToFixed(sy); // compute the flags we send to Load_Glyph { uint32_t flags = FT_LOAD_DEFAULT; uint32_t render_flags = FT_LOAD_TARGET_NORMAL; // we force autohinting at the moment switch (fRec.fHints) { case kNo_Hints: flags |= FT_LOAD_NO_HINTING; break; case kSubpixel_Hints: flags |= FT_LOAD_FORCE_AUTOHINT; render_flags = FT_LOAD_TARGET_LIGHT; break; case kNormal_Hints: flags |= FT_LOAD_FORCE_AUTOHINT; #ifdef ANDROID /* Switch to light hinting (vertical only) to address some chars that behaved poorly with NORMAL. In the future we could consider making this choice exposed at runtime to the caller. */ render_flags = FT_LOAD_TARGET_LIGHT; #endif break; } if (SkMask::kBW_Format == fRec.fMaskFormat) render_flags = FT_LOAD_TARGET_MONO; else if (SkMask::kLCD_Format == fRec.fMaskFormat) render_flags = FT_LOAD_TARGET_LCD; fLoadGlyphFlags = flags | render_flags; } // 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; } 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); } }