void SkScalerContext_CairoFT::generateImage(const SkGlyph& glyph) { SkASSERT(fScaledFont != nullptr); CairoLockedFTFace faceLock(fScaledFont); FT_Face face = faceLock.getFace(); FT_Error err = FT_Load_Glyph(face, glyph.getGlyphID(), fLoadGlyphFlags); if (err != 0) { memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight); return; } prepareGlyph(face->glyph); bool useLcdFilter = face->glyph->format == FT_GLYPH_FORMAT_OUTLINE && isLCD(glyph) && gSetLcdFilter; if (useLcdFilter) { gSetLcdFilter(face->glyph->library, fLcdFilter); } generateGlyphImage(face, glyph); if (useLcdFilter) { gSetLcdFilter(face->glyph->library, FT_LCD_FILTER_NONE); } }
void SkScalerContext_CairoFT::generateImage(const SkGlyph& glyph) { SkASSERT(fScaledFont != NULL); CairoLockedFTFace faceLock(fScaledFont); FT_Face face = faceLock.getFace(); FT_Error err = FT_Load_Glyph(face, glyph.getGlyphID(), fLoadGlyphFlags); if (err != 0) { memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight); return; } generateGlyphImage(face, glyph); }
SkUnichar SkScalerContext_CairoFT::generateGlyphToChar(uint16_t glyph) { SkASSERT(fScaledFont != NULL); CairoLockedFTFace faceLock(fScaledFont); FT_Face face = faceLock.getFace(); FT_UInt glyphIndex; SkUnichar charCode = FT_Get_First_Char(face, &glyphIndex); while (glyphIndex != 0) { if (glyphIndex == glyph) { return charCode; } charCode = FT_Get_Next_Char(face, charCode, &glyphIndex); } return 0; }
SkTypeface* SkCreateTypefaceFromCairoFTFontWithFontconfig(cairo_scaled_font_t* scaledFont, FcPattern* pattern) { cairo_font_face_t* fontFace = cairo_scaled_font_get_font_face(scaledFont); SkASSERT(cairo_font_face_status(fontFace) == CAIRO_STATUS_SUCCESS); SkTypeface* typeface = reinterpret_cast<SkTypeface*>(cairo_font_face_get_user_data(fontFace, &kSkTypefaceKey)); if (typeface) { typeface->ref(); } else { CairoLockedFTFace faceLock(scaledFont); if (FT_Face face = faceLock.getFace()) { typeface = SkCairoFTTypeface::CreateTypeface(fontFace, face, pattern); SkTypefaceCache::Add(typeface, typeface->fontStyle()); } } return typeface; }
void SkScalerContext_CairoFT::generatePath(const SkGlyph& glyph, SkPath* path) { SkASSERT(fScaledFont != NULL); CairoLockedFTFace faceLock(fScaledFont); FT_Face face = faceLock.getFace(); SkASSERT(&glyph && path); uint32_t flags = fLoadGlyphFlags; 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) FT_Error err = FT_Load_Glyph(face, glyph.getGlyphID(), flags); if (err != 0) { path->reset(); return; } generateGlyphPath(face, path); }
uint16_t SkScalerContext_CairoFT::generateCharToGlyph(SkUnichar uniChar) { CairoLockedFTFace faceLock(fScaledFont); return SkToU16(FT_Get_Char_Index(faceLock.getFace(), uniChar)); }
unsigned SkScalerContext_CairoFT::generateGlyphCount() { CairoLockedFTFace faceLock(fScaledFont); return faceLock.getFace()->num_glyphs; }
void SkScalerContext_CairoFT::generateMetrics(SkGlyph* glyph) { SkASSERT(fScaledFont != nullptr); glyph->zeroMetrics(); CairoLockedFTFace faceLock(fScaledFont); FT_Face face = faceLock.getFace(); FT_Error err = FT_Load_Glyph( face, glyph->getGlyphID(), fLoadGlyphFlags ); if (err != 0) { return; } prepareGlyph(face->glyph); switch (face->glyph->format) { case FT_GLYPH_FORMAT_OUTLINE: if (!face->glyph->outline.n_contours) { break; } FT_BBox bbox; FT_Outline_Get_CBox(&face->glyph->outline, &bbox); bbox.xMin &= ~63; bbox.yMin &= ~63; bbox.xMax = (bbox.xMax + 63) & ~63; bbox.yMax = (bbox.yMax + 63) & ~63; 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)); if (isLCD(fRec) && gSetLcdFilter && (fLcdFilter == FT_LCD_FILTER_DEFAULT || fLcdFilter == FT_LCD_FILTER_LIGHT)) { if (fRec.fFlags & kLCD_Vertical_Flag) { glyph->fTop -= 1; glyph->fHeight += 2; } else { glyph->fLeft -= 1; glyph->fWidth += 2; } } break; case FT_GLYPH_FORMAT_BITMAP: #ifdef FT_LOAD_COLOR if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) { glyph->fMaskFormat = SkMask::kARGB32_Format; } #endif if (isLCD(fRec)) { fRec.fMaskFormat = SkMask::kA8_Format; } if (fHaveShape) { // Apply the shape matrix to the glyph's bounding box. SkMatrix matrix; fRec.getSingleMatrix(&matrix); matrix.preScale(SkScalarInvert(fScaleX), SkScalarInvert(fScaleY)); SkRect srcRect = SkRect::MakeXYWH( SkIntToScalar(face->glyph->bitmap_left), -SkIntToScalar(face->glyph->bitmap_top), SkIntToScalar(face->glyph->bitmap.width), SkIntToScalar(face->glyph->bitmap.rows)); SkRect destRect; matrix.mapRect(&destRect, srcRect); SkIRect glyphRect = destRect.roundOut(); glyph->fWidth = SkToU16(glyphRect.width()); glyph->fHeight = SkToU16(glyphRect.height()); glyph->fTop = SkToS16(SkScalarRoundToInt(destRect.fTop)); glyph->fLeft = SkToS16(SkScalarRoundToInt(destRect.fLeft)); } else { glyph->fWidth = SkToU16(face->glyph->bitmap.width); glyph->fHeight = SkToU16(face->glyph->bitmap.rows); glyph->fTop = -SkToS16(face->glyph->bitmap_top); glyph->fLeft = SkToS16(face->glyph->bitmap_left); } break; default: SkDEBUGFAIL("unknown glyph format"); return; } if (fRec.fFlags & SkScalerContext::kVertical_Flag) { glyph->fAdvanceX = -SkFDot6ToFloat(face->glyph->advance.x); glyph->fAdvanceY = SkFDot6ToFloat(face->glyph->advance.y); } else { glyph->fAdvanceX = SkFDot6ToFloat(face->glyph->advance.x); glyph->fAdvanceY = -SkFDot6ToFloat(face->glyph->advance.y); } }
bool SkScalerContext_CairoFT::computeShapeMatrix(const SkMatrix& m) { // Compute a shape matrix compatible with Cairo's _compute_transform. // Finds major/minor scales and uses them to normalize the transform. double scaleX = m.getScaleX(); double skewX = m.getSkewX(); double skewY = m.getSkewY(); double scaleY = m.getScaleY(); double det = scaleX * scaleY - skewY * skewX; if (!std::isfinite(det)) { fScaleX = fRec.fTextSize * fRec.fPreScaleX; fScaleY = fRec.fTextSize; fHaveShape = false; return false; } double major = det != 0.0 ? hypot(scaleX, skewY) : 0.0; double minor = major != 0.0 ? fabs(det) / major : 0.0; // Limit scales to be above 1pt. major = SkTMax(major, 1.0); minor = SkTMax(minor, 1.0); // If the font is not scalable, then choose the best available size. CairoLockedFTFace faceLock(fScaledFont); FT_Face face = faceLock.getFace(); if (face && !FT_IS_SCALABLE(face)) { double bestDist = DBL_MAX; FT_Int bestSize = -1; for (FT_Int i = 0; i < face->num_fixed_sizes; i++) { // Distance is positive if strike is larger than desired size, // or negative if smaller. If previously a found smaller strike, // then prefer a larger strike. Otherwise, minimize distance. double dist = face->available_sizes[i].y_ppem / 64.0 - minor; if (bestDist < 0 ? dist >= bestDist : fabs(dist) <= bestDist) { bestDist = dist; bestSize = i; } } if (bestSize < 0) { fScaleX = fRec.fTextSize * fRec.fPreScaleX; fScaleY = fRec.fTextSize; fHaveShape = false; return false; } major = face->available_sizes[bestSize].x_ppem / 64.0; minor = face->available_sizes[bestSize].y_ppem / 64.0; fHaveShape = true; } else { fHaveShape = !m.isScaleTranslate(); } fScaleX = SkDoubleToScalar(major); fScaleY = SkDoubleToScalar(minor); if (fHaveShape) { // Normalize the transform and convert to fixed-point. double invScaleX = 65536.0 / major; double invScaleY = 65536.0 / minor; fShapeMatrix.xx = (FT_Fixed)(scaleX * invScaleX); fShapeMatrix.yx = -(FT_Fixed)(skewY * invScaleX); fShapeMatrix.xy = -(FT_Fixed)(skewX * invScaleY); fShapeMatrix.yy = (FT_Fixed)(scaleY * invScaleY); } return true; }