michael@0: michael@0: /* michael@0: * Copyright 2012 Mozilla Foundation michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: #include "cairo.h" michael@0: #include "cairo-ft.h" michael@0: michael@0: #include "SkFontHost_FreeType_common.h" michael@0: michael@0: #include "SkAdvancedTypefaceMetrics.h" michael@0: #include "SkFontHost.h" michael@0: #include "SkPath.h" michael@0: #include "SkScalerContext.h" michael@0: #include "SkTypefaceCache.h" michael@0: michael@0: #include michael@0: #include FT_FREETYPE_H michael@0: michael@0: #ifndef SK_FONTHOST_CAIRO_STANDALONE michael@0: #define SK_FONTHOST_CAIRO_STANDALONE 1 michael@0: #endif michael@0: michael@0: static cairo_user_data_key_t kSkTypefaceKey; michael@0: michael@0: class SkScalerContext_CairoFT : public SkScalerContext_FreeType_Base { michael@0: public: michael@0: SkScalerContext_CairoFT(SkTypeface* typeface, const SkDescriptor* desc); michael@0: virtual ~SkScalerContext_CairoFT(); michael@0: michael@0: protected: michael@0: virtual unsigned generateGlyphCount() SK_OVERRIDE; michael@0: virtual uint16_t generateCharToGlyph(SkUnichar uniChar) SK_OVERRIDE; michael@0: virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE; michael@0: virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE; michael@0: virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE; michael@0: virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE; michael@0: virtual void generateFontMetrics(SkPaint::FontMetrics* mx, michael@0: SkPaint::FontMetrics* my) SK_OVERRIDE; michael@0: virtual SkUnichar generateGlyphToChar(uint16_t glyph) SK_OVERRIDE; michael@0: private: michael@0: cairo_scaled_font_t* fScaledFont; michael@0: uint32_t fLoadGlyphFlags; michael@0: }; michael@0: michael@0: class CairoLockedFTFace { michael@0: public: michael@0: CairoLockedFTFace(cairo_scaled_font_t* scaledFont) michael@0: : fScaledFont(scaledFont) michael@0: , fFace(cairo_ft_scaled_font_lock_face(scaledFont)) michael@0: {} michael@0: michael@0: ~CairoLockedFTFace() michael@0: { michael@0: cairo_ft_scaled_font_unlock_face(fScaledFont); michael@0: } michael@0: michael@0: FT_Face getFace() michael@0: { michael@0: return fFace; michael@0: } michael@0: michael@0: private: michael@0: cairo_scaled_font_t* fScaledFont; michael@0: FT_Face fFace; michael@0: }; michael@0: michael@0: class SkCairoFTTypeface : public SkTypeface { michael@0: public: michael@0: static SkTypeface* CreateTypeface(cairo_font_face_t* fontFace, SkTypeface::Style style, bool isFixedWidth) { michael@0: SkASSERT(fontFace != NULL); michael@0: SkASSERT(cairo_font_face_get_type(fontFace) == CAIRO_FONT_TYPE_FT); michael@0: michael@0: SkFontID newId = SkTypefaceCache::NewFontID(); michael@0: michael@0: return SkNEW_ARGS(SkCairoFTTypeface, (fontFace, style, newId, isFixedWidth)); michael@0: } michael@0: michael@0: cairo_font_face_t* getFontFace() { michael@0: return fFontFace; michael@0: } michael@0: michael@0: virtual SkStream* onOpenStream(int*) const SK_OVERRIDE { return NULL; } michael@0: michael@0: virtual SkAdvancedTypefaceMetrics* michael@0: onGetAdvancedTypefaceMetrics(SkAdvancedTypefaceMetrics::PerGlyphInfo, michael@0: const uint32_t*, uint32_t) const SK_OVERRIDE michael@0: { michael@0: SkDEBUGCODE(SkDebugf("SkCairoFTTypeface::onGetAdvancedTypefaceMetrics unimplemented\n")); michael@0: return NULL; michael@0: } michael@0: michael@0: virtual SkScalerContext* onCreateScalerContext(const SkDescriptor* desc) const SK_OVERRIDE michael@0: { michael@0: return SkNEW_ARGS(SkScalerContext_CairoFT, (const_cast(this), desc)); michael@0: } michael@0: michael@0: virtual void onFilterRec(SkScalerContextRec*) const SK_OVERRIDE michael@0: { michael@0: SkDEBUGCODE(SkDebugf("SkCairoFTTypeface::onFilterRec unimplemented\n")); michael@0: } michael@0: michael@0: virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE michael@0: { michael@0: SkDEBUGCODE(SkDebugf("SkCairoFTTypeface::onGetFontDescriptor unimplemented\n")); michael@0: } michael@0: michael@0: virtual int onCharsToGlyphs(void const*, SkTypeface::Encoding, uint16_t*, int) const SK_OVERRIDE michael@0: { michael@0: return 0; michael@0: } michael@0: michael@0: virtual int onCountGlyphs() const SK_OVERRIDE michael@0: { michael@0: return 0; michael@0: } michael@0: michael@0: virtual int onGetUPEM() const SK_OVERRIDE michael@0: { michael@0: return 0; michael@0: } michael@0: michael@0: virtual SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const SK_OVERRIDE michael@0: { michael@0: return NULL; michael@0: } michael@0: michael@0: virtual int onGetTableTags(SkFontTableTag*) const SK_OVERRIDE michael@0: { michael@0: return 0; michael@0: } michael@0: michael@0: virtual size_t onGetTableData(SkFontTableTag, size_t, size_t, void*) const SK_OVERRIDE michael@0: { michael@0: return 0; michael@0: } michael@0: michael@0: private: michael@0: michael@0: SkCairoFTTypeface(cairo_font_face_t* fontFace, SkTypeface::Style style, SkFontID id, bool isFixedWidth) michael@0: : SkTypeface(style, id, isFixedWidth) michael@0: , fFontFace(fontFace) michael@0: { michael@0: cairo_font_face_set_user_data(fFontFace, &kSkTypefaceKey, this, NULL); michael@0: cairo_font_face_reference(fFontFace); michael@0: } michael@0: michael@0: ~SkCairoFTTypeface() michael@0: { michael@0: cairo_font_face_set_user_data(fFontFace, &kSkTypefaceKey, NULL, NULL); michael@0: cairo_font_face_destroy(fFontFace); michael@0: } michael@0: michael@0: cairo_font_face_t* fFontFace; michael@0: }; michael@0: michael@0: SkTypeface* SkCreateTypefaceFromCairoFont(cairo_font_face_t* fontFace, SkTypeface::Style style, bool isFixedWidth) michael@0: { michael@0: SkTypeface* typeface = reinterpret_cast(cairo_font_face_get_user_data(fontFace, &kSkTypefaceKey)); michael@0: michael@0: if (typeface) { michael@0: typeface->ref(); michael@0: } else { michael@0: typeface = SkCairoFTTypeface::CreateTypeface(fontFace, style, isFixedWidth); michael@0: SkTypefaceCache::Add(typeface, style); michael@0: } michael@0: michael@0: return typeface; michael@0: } michael@0: michael@0: #if defined(SK_FONTHOST_DOES_NOT_USE_FONTMGR) && SK_FONTHOST_CAIRO_STANDALONE michael@0: SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, michael@0: const char famillyName[], michael@0: SkTypeface::Style style) michael@0: { michael@0: SkDEBUGFAIL("SkFontHost::FindTypeface unimplemented"); michael@0: return NULL; michael@0: } michael@0: michael@0: SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream*) michael@0: { michael@0: SkDEBUGFAIL("SkFontHost::CreateTypeface unimplemented"); michael@0: return NULL; michael@0: } michael@0: michael@0: SkTypeface* SkFontHost::CreateTypefaceFromFile(char const*) michael@0: { michael@0: SkDEBUGFAIL("SkFontHost::CreateTypefaceFromFile unimplemented"); michael@0: return NULL; michael@0: } michael@0: #endif michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: static bool isLCD(const SkScalerContext::Rec& rec) { michael@0: switch (rec.fMaskFormat) { michael@0: case SkMask::kLCD16_Format: michael@0: case SkMask::kLCD32_Format: michael@0: return true; michael@0: default: michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: SkScalerContext_CairoFT::SkScalerContext_CairoFT(SkTypeface* typeface, const SkDescriptor* desc) michael@0: : SkScalerContext_FreeType_Base(typeface, desc) michael@0: { michael@0: SkMatrix matrix; michael@0: fRec.getSingleMatrix(&matrix); michael@0: michael@0: cairo_font_face_t* fontFace = static_cast(typeface)->getFontFace(); michael@0: michael@0: cairo_matrix_t fontMatrix, ctMatrix; michael@0: cairo_matrix_init(&fontMatrix, matrix.getScaleX(), matrix.getSkewY(), matrix.getSkewX(), matrix.getScaleY(), 0.0, 0.0); michael@0: cairo_matrix_init_scale(&ctMatrix, 1.0, 1.0); michael@0: michael@0: // We need to ensure that the font options match for hinting, as generateMetrics() michael@0: // uses the fScaledFont which uses these font options michael@0: cairo_font_options_t *fontOptions = cairo_font_options_create(); michael@0: michael@0: FT_Int32 loadFlags = FT_LOAD_DEFAULT; michael@0: michael@0: if (SkMask::kBW_Format == fRec.fMaskFormat) { michael@0: // See http://code.google.com/p/chromium/issues/detail?id=43252#c24 michael@0: loadFlags = FT_LOAD_TARGET_MONO; michael@0: if (fRec.getHinting() == SkPaint::kNo_Hinting) { michael@0: cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_NONE); michael@0: loadFlags = FT_LOAD_NO_HINTING; michael@0: } michael@0: } else { michael@0: switch (fRec.getHinting()) { michael@0: case SkPaint::kNo_Hinting: michael@0: loadFlags = FT_LOAD_NO_HINTING; michael@0: cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_NONE); michael@0: break; michael@0: case SkPaint::kSlight_Hinting: michael@0: loadFlags = FT_LOAD_TARGET_LIGHT; // This implies FORCE_AUTOHINT michael@0: cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_SLIGHT); michael@0: break; michael@0: case SkPaint::kNormal_Hinting: michael@0: cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_MEDIUM); michael@0: if (fRec.fFlags & SkScalerContext::kForceAutohinting_Flag) { michael@0: loadFlags = FT_LOAD_FORCE_AUTOHINT; michael@0: } michael@0: break; michael@0: case SkPaint::kFull_Hinting: michael@0: cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_FULL); michael@0: if (fRec.fFlags & SkScalerContext::kForceAutohinting_Flag) { michael@0: loadFlags = FT_LOAD_FORCE_AUTOHINT; michael@0: } michael@0: if (isLCD(fRec)) { michael@0: if (SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag)) { michael@0: loadFlags = FT_LOAD_TARGET_LCD_V; michael@0: } else { michael@0: loadFlags = FT_LOAD_TARGET_LCD; michael@0: } michael@0: } michael@0: break; michael@0: default: michael@0: SkDebugf("---------- UNKNOWN hinting %d\n", fRec.getHinting()); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: fScaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctMatrix, fontOptions); michael@0: michael@0: if ((fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag) == 0) { michael@0: loadFlags |= FT_LOAD_NO_BITMAP; michael@0: } michael@0: michael@0: // Always using FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH to get correct michael@0: // advances, as fontconfig and cairo do. michael@0: // See http://code.google.com/p/skia/issues/detail?id=222. michael@0: loadFlags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; michael@0: michael@0: fLoadGlyphFlags = loadFlags; michael@0: } michael@0: michael@0: SkScalerContext_CairoFT::~SkScalerContext_CairoFT() michael@0: { michael@0: cairo_scaled_font_destroy(fScaledFont); michael@0: } michael@0: michael@0: unsigned SkScalerContext_CairoFT::generateGlyphCount() michael@0: { michael@0: CairoLockedFTFace faceLock(fScaledFont); michael@0: return faceLock.getFace()->num_glyphs; michael@0: } michael@0: michael@0: uint16_t SkScalerContext_CairoFT::generateCharToGlyph(SkUnichar uniChar) michael@0: { michael@0: CairoLockedFTFace faceLock(fScaledFont); michael@0: return SkToU16(FT_Get_Char_Index(faceLock.getFace(), uniChar)); michael@0: } michael@0: michael@0: void SkScalerContext_CairoFT::generateAdvance(SkGlyph* glyph) michael@0: { michael@0: generateMetrics(glyph); michael@0: } michael@0: michael@0: void SkScalerContext_CairoFT::generateMetrics(SkGlyph* glyph) michael@0: { michael@0: SkASSERT(fScaledFont != NULL); michael@0: cairo_text_extents_t extents; michael@0: cairo_glyph_t cairoGlyph = { glyph->getGlyphID(fBaseGlyphCount), 0.0, 0.0 }; michael@0: cairo_scaled_font_glyph_extents(fScaledFont, &cairoGlyph, 1, &extents); michael@0: michael@0: glyph->fAdvanceX = SkDoubleToFixed(extents.x_advance); michael@0: glyph->fAdvanceY = SkDoubleToFixed(extents.y_advance); michael@0: glyph->fWidth = SkToU16(SkScalarCeilToInt(extents.width)); michael@0: glyph->fHeight = SkToU16(SkScalarCeilToInt(extents.height)); michael@0: glyph->fLeft = SkToS16(SkScalarCeilToInt(extents.x_bearing)); michael@0: glyph->fTop = SkToS16(SkScalarCeilToInt(extents.y_bearing)); michael@0: glyph->fLsbDelta = 0; michael@0: glyph->fRsbDelta = 0; michael@0: } michael@0: michael@0: void SkScalerContext_CairoFT::generateImage(const SkGlyph& glyph) michael@0: { michael@0: SkASSERT(fScaledFont != NULL); michael@0: CairoLockedFTFace faceLock(fScaledFont); michael@0: FT_Face face = faceLock.getFace(); michael@0: michael@0: FT_Error err = FT_Load_Glyph(face, glyph.getGlyphID(fBaseGlyphCount), fLoadGlyphFlags); michael@0: michael@0: if (err != 0) { michael@0: memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight); michael@0: return; michael@0: } michael@0: michael@0: generateGlyphImage(face, glyph); michael@0: } michael@0: michael@0: void SkScalerContext_CairoFT::generatePath(const SkGlyph& glyph, SkPath* path) michael@0: { michael@0: SkASSERT(fScaledFont != NULL); michael@0: CairoLockedFTFace faceLock(fScaledFont); michael@0: FT_Face face = faceLock.getFace(); michael@0: michael@0: SkASSERT(&glyph && path); michael@0: michael@0: uint32_t flags = fLoadGlyphFlags; michael@0: flags |= FT_LOAD_NO_BITMAP; // ignore embedded bitmaps so we're sure to get the outline michael@0: flags &= ~FT_LOAD_RENDER; // don't scan convert (we just want the outline) michael@0: michael@0: FT_Error err = FT_Load_Glyph(face, glyph.getGlyphID(fBaseGlyphCount), flags); michael@0: michael@0: if (err != 0) { michael@0: path->reset(); michael@0: return; michael@0: } michael@0: michael@0: generateGlyphPath(face, path); michael@0: } michael@0: michael@0: void SkScalerContext_CairoFT::generateFontMetrics(SkPaint::FontMetrics* mx, michael@0: SkPaint::FontMetrics* my) michael@0: { michael@0: SkDEBUGCODE(SkDebugf("SkScalerContext_CairoFT::generateFontMetrics unimplemented\n")); michael@0: } michael@0: michael@0: SkUnichar SkScalerContext_CairoFT::generateGlyphToChar(uint16_t glyph) michael@0: { michael@0: SkASSERT(fScaledFont != NULL); michael@0: CairoLockedFTFace faceLock(fScaledFont); michael@0: FT_Face face = faceLock.getFace(); michael@0: michael@0: FT_UInt glyphIndex; michael@0: SkUnichar charCode = FT_Get_First_Char(face, &glyphIndex); michael@0: while (glyphIndex != 0) { michael@0: if (glyphIndex == glyph) { michael@0: return charCode; michael@0: } michael@0: charCode = FT_Get_Next_Char(face, charCode, &glyphIndex); michael@0: } michael@0: michael@0: return 0; michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: #include "SkFontMgr.h" michael@0: michael@0: SkFontMgr* SkFontMgr::Factory() { michael@0: // todo michael@0: return NULL; michael@0: } michael@0: