From: George Wright Date: Wed, 1 Aug 2012 16:43:15 -0400 Subject: Bug 736276 - Add a new SkFontHost that takes a cairo_scaled_font_t r=karl diff --git a/gfx/skia/Makefile.in b/gfx/skia/Makefile.in index 5ebbd2e..7c8cdbf 100644 --- a/gfx/skia/Makefile.in +++ b/gfx/skia/Makefile.in @@ -60,15 +60,15 @@ VPATH += \ $(NULL) ifeq (android,$(MOZ_WIDGET_TOOLKIT)) -OS_CXXFLAGS += $(CAIRO_FT_CFLAGS) +OS_CXXFLAGS += $(MOZ_CAIRO_CFLAGS) $(CAIRO_FT_CFLAGS) endif ifeq (gtk2,$(MOZ_WIDGET_TOOLKIT)) -OS_CXXFLAGS += $(MOZ_PANGO_CFLAGS) +OS_CXXFLAGS += $(MOZ_CAIRO_CFLAGS) $(MOZ_PANGO_CFLAGS) $(CAIRO_FT_CFLAGS) endif ifeq (qt,$(MOZ_WIDGET_TOOLKIT)) -OS_CXXFLAGS += $(MOZ_PANGO_CFLAGS) +OS_CXXFLAGS += $(MOZ_CAIRO_CFLAGS) $(MOZ_PANGO_CFLAGS) $(CAIRO_FT_CFLAGS) ifeq (Linux,$(OS_TARGET)) DEFINES += -DSK_USE_POSIX_THREADS=1 endif diff --git a/gfx/skia/include/ports/SkTypeface_cairo.h b/gfx/skia/include/ports/SkTypeface_cairo.h new file mode 100644 index 0000000..7e44f04 --- /dev/null +++ b/gfx/skia/include/ports/SkTypeface_cairo.h @@ -0,0 +1,11 @@ +#ifndef SkTypeface_cairo_DEFINED +#define SkTypeface_cairo_DEFINED + +#include + +#include "SkTypeface.h" + +SK_API extern SkTypeface* SkCreateTypefaceFromCairoFont(cairo_font_face_t* fontFace, SkTypeface::Style style, bool isFixedWidth); + +#endif + diff --git a/gfx/skia/moz.build b/gfx/skia/moz.build index 9ceba59..66efd52 100644 --- a/gfx/skia/moz.build +++ b/gfx/skia/moz.build @@ -171,10 +171,12 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': 'SkTime_win.cpp', ] elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk2': + EXPORTS.skia += [ + 'include/ports/SkTypeface_cairo.h', + ] CPP_SOURCES += [ - 'SkFontHost_FreeType.cpp', + 'SkFontHost_cairo.cpp', 'SkFontHost_FreeType_common.cpp', - 'SkFontHost_linux.cpp', 'SkThread_pthread.cpp', 'SkThreadUtils_pthread.cpp', 'SkThreadUtils_pthread_linux.cpp', @@ -183,14 +185,15 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk2': ] elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt': CPP_SOURCES += [ - 'SkFontHost_FreeType.cpp', + 'SkFontHost_cairo.cpp', 'SkFontHost_FreeType_common.cpp', 'SkOSFile.cpp', ] if CONFIG['OS_TARGET'] == 'Linux': + EXPORTS.skia += [ + 'include/ports/SkTypeface_cairo.h', + ] CPP_SOURCES += [ - 'SkFontHost_linux.cpp', - 'SkFontHost_tables.cpp', 'SkThread_pthread.cpp', 'SkThreadUtils_pthread.cpp', 'SkThreadUtils_pthread_linux.cpp', @@ -204,11 +207,13 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': # Separate 'if' from above, since the else below applies to all != 'android' # toolkits. if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android': + EXPORTS.skia += [ + 'include/ports/SkTypeface_cairo.h', + ] CPP_SOURCES += [ 'ashmem.cpp', 'SkDebug_android.cpp', - 'SkFontHost_android_old.cpp', - 'SkFontHost_FreeType.cpp', + 'SkFontHost_cairo.cpp', 'SkFontHost_FreeType_common.cpp', 'SkImageRef_ashmem.cpp', 'SkTime_Unix.cpp', diff --git a/gfx/skia/src/ports/SkFontHost_cairo.cpp b/gfx/skia/src/ports/SkFontHost_cairo.cpp new file mode 100644 index 0000000..bb5b778 --- /dev/null +++ b/gfx/skia/src/ports/SkFontHost_cairo.cpp @@ -0,0 +1,364 @@ + +/* + * Copyright 2012 Mozilla Foundation + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "cairo.h" +#include "cairo-ft.h" + +#include "SkFontHost_FreeType_common.h" + +#include "SkAdvancedTypefaceMetrics.h" +#include "SkFontHost.h" +#include "SkPath.h" +#include "SkScalerContext.h" +#include "SkTypefaceCache.h" + +#include +#include FT_FREETYPE_H + +static cairo_user_data_key_t kSkTypefaceKey; + +class SkScalerContext_CairoFT : public SkScalerContext_FreeType_Base { +public: + SkScalerContext_CairoFT(SkTypeface* typeface, const SkDescriptor* desc); + virtual ~SkScalerContext_CairoFT(); + +protected: + virtual unsigned generateGlyphCount() SK_OVERRIDE; + virtual uint16_t generateCharToGlyph(SkUnichar uniChar) SK_OVERRIDE; + virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE; + virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE; + virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE; + virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE; + virtual void generateFontMetrics(SkPaint::FontMetrics* mx, + SkPaint::FontMetrics* my) SK_OVERRIDE; + virtual SkUnichar generateGlyphToChar(uint16_t glyph) SK_OVERRIDE; +private: + cairo_scaled_font_t* fScaledFont; + uint32_t fLoadGlyphFlags; +}; + +class CairoLockedFTFace { +public: + CairoLockedFTFace(cairo_scaled_font_t* scaledFont) + : fScaledFont(scaledFont) + , fFace(cairo_ft_scaled_font_lock_face(scaledFont)) + {} + + ~CairoLockedFTFace() + { + cairo_ft_scaled_font_unlock_face(fScaledFont); + } + + FT_Face getFace() + { + return fFace; + } + +private: + cairo_scaled_font_t* fScaledFont; + FT_Face fFace; +}; + +class SkCairoFTTypeface : public SkTypeface { +public: + static SkTypeface* CreateTypeface(cairo_font_face_t* fontFace, SkTypeface::Style style, bool isFixedWidth) { + SkASSERT(fontFace != NULL); + SkASSERT(cairo_font_face_get_type(fontFace) == CAIRO_FONT_TYPE_FT); + + SkFontID newId = SkTypefaceCache::NewFontID(); + + return SkNEW_ARGS(SkCairoFTTypeface, (fontFace, style, newId, isFixedWidth)); + } + + cairo_font_face_t* getFontFace() { + return fFontFace; + } + + virtual SkStream* onOpenStream(int*) const SK_OVERRIDE { return NULL; } + + virtual SkAdvancedTypefaceMetrics* + onGetAdvancedTypefaceMetrics(SkAdvancedTypefaceMetrics::PerGlyphInfo, + const uint32_t*, uint32_t) const SK_OVERRIDE + { + SkDEBUGCODE(SkDebugf("SkCairoFTTypeface::onGetAdvancedTypefaceMetrics unimplemented\n")); + return NULL; + } + + virtual SkScalerContext* onCreateScalerContext(const SkDescriptor* desc) const SK_OVERRIDE + { + return SkNEW_ARGS(SkScalerContext_CairoFT, (const_cast(this), desc)); + } + + virtual void onFilterRec(SkScalerContextRec*) const SK_OVERRIDE + { + SkDEBUGCODE(SkDebugf("SkCairoFTTypeface::onFilterRec unimplemented\n")); + } + + virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE + { + SkDEBUGCODE(SkDebugf("SkCairoFTTypeface::onGetFontDescriptor unimplemented\n")); + } + + +private: + + SkCairoFTTypeface(cairo_font_face_t* fontFace, SkTypeface::Style style, SkFontID id, bool isFixedWidth) + : SkTypeface(style, id, isFixedWidth) + , fFontFace(fontFace) + { + cairo_font_face_set_user_data(fFontFace, &kSkTypefaceKey, this, NULL); + cairo_font_face_reference(fFontFace); + } + + ~SkCairoFTTypeface() + { + cairo_font_face_set_user_data(fFontFace, &kSkTypefaceKey, NULL, NULL); + cairo_font_face_destroy(fFontFace); + } + + cairo_font_face_t* fFontFace; +}; + +SkTypeface* SkCreateTypefaceFromCairoFont(cairo_font_face_t* fontFace, SkTypeface::Style style, bool isFixedWidth) +{ + SkTypeface* typeface = reinterpret_cast(cairo_font_face_get_user_data(fontFace, &kSkTypefaceKey)); + + if (typeface) { + typeface->ref(); + } else { + typeface = SkCairoFTTypeface::CreateTypeface(fontFace, style, isFixedWidth); + SkTypefaceCache::Add(typeface, style); + } + + return typeface; +} + +SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, + const char famillyName[], + SkTypeface::Style style) +{ + SkDEBUGFAIL("SkFontHost::FindTypeface unimplemented"); + return NULL; +} + +SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream*) +{ + SkDEBUGFAIL("SkFontHost::CreateTypeface unimplemented"); + return NULL; +} + +SkTypeface* SkFontHost::CreateTypefaceFromFile(char const*) +{ + SkDEBUGFAIL("SkFontHost::CreateTypefaceFromFile unimplemented"); + return NULL; +} + +/////////////////////////////////////////////////////////////////////////////// + +static bool isLCD(const SkScalerContext::Rec& rec) { + switch (rec.fMaskFormat) { + case SkMask::kLCD16_Format: + case SkMask::kLCD32_Format: + return true; + default: + return false; + } +} + +/////////////////////////////////////////////////////////////////////////////// +SkScalerContext_CairoFT::SkScalerContext_CairoFT(SkTypeface* typeface, const SkDescriptor* desc) + : SkScalerContext_FreeType_Base(typeface, desc) +{ + SkMatrix matrix; + fRec.getSingleMatrix(&matrix); + + cairo_font_face_t* fontFace = static_cast(typeface)->getFontFace(); + + cairo_matrix_t fontMatrix, ctMatrix; + cairo_matrix_init(&fontMatrix, matrix.getScaleX(), matrix.getSkewY(), matrix.getSkewX(), matrix.getScaleY(), 0.0, 0.0); + cairo_matrix_init_scale(&ctMatrix, 1.0, 1.0); + + // We need to ensure that the font options match for hinting, as generateMetrics() + // uses the fScaledFont which uses these font options + cairo_font_options_t *fontOptions = cairo_font_options_create(); + + 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) { + cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_NONE); + loadFlags = FT_LOAD_NO_HINTING; + } + } else { + switch (fRec.getHinting()) { + case SkPaint::kNo_Hinting: + loadFlags = FT_LOAD_NO_HINTING; + cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_NONE); + break; + case SkPaint::kSlight_Hinting: + loadFlags = FT_LOAD_TARGET_LIGHT; // This implies FORCE_AUTOHINT + cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_SLIGHT); + break; + case SkPaint::kNormal_Hinting: + cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_MEDIUM); + if (fRec.fFlags & SkScalerContext::kAutohinting_Flag) { + loadFlags = FT_LOAD_FORCE_AUTOHINT; + } + break; + case SkPaint::kFull_Hinting: + cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_FULL); + if (fRec.fFlags & SkScalerContext::kAutohinting_Flag) { + loadFlags = FT_LOAD_FORCE_AUTOHINT; + } + if (isLCD(fRec)) { + if (SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag)) { + loadFlags = FT_LOAD_TARGET_LCD_V; + } else { + loadFlags = FT_LOAD_TARGET_LCD; + } + } + break; + default: + SkDebugf("---------- UNKNOWN hinting %d\n", fRec.getHinting()); + break; + } + } + + fScaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctMatrix, fontOptions); + + if ((fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag) == 0) { + loadFlags |= FT_LOAD_NO_BITMAP; + } + + // Always using FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH to get correct + // advances, as fontconfig and cairo do. + // See http://code.google.com/p/skia/issues/detail?id=222. + loadFlags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; + + fLoadGlyphFlags = loadFlags; +} + +SkScalerContext_CairoFT::~SkScalerContext_CairoFT() +{ + cairo_scaled_font_destroy(fScaledFont); +} + +unsigned SkScalerContext_CairoFT::generateGlyphCount() +{ + CairoLockedFTFace faceLock(fScaledFont); + return faceLock.getFace()->num_glyphs; +} + +uint16_t SkScalerContext_CairoFT::generateCharToGlyph(SkUnichar uniChar) +{ + CairoLockedFTFace faceLock(fScaledFont); + return SkToU16(FT_Get_Char_Index(faceLock.getFace(), uniChar)); +} + +void SkScalerContext_CairoFT::generateAdvance(SkGlyph* glyph) +{ + generateMetrics(glyph); +} + +void SkScalerContext_CairoFT::generateMetrics(SkGlyph* glyph) +{ + SkASSERT(fScaledFont != NULL); + cairo_text_extents_t extents; + cairo_glyph_t cairoGlyph = { glyph->getGlyphID(fBaseGlyphCount), 0.0, 0.0 }; + cairo_scaled_font_glyph_extents(fScaledFont, &cairoGlyph, 1, &extents); + + glyph->fAdvanceX = SkDoubleToFixed(extents.x_advance); + glyph->fAdvanceY = SkDoubleToFixed(extents.y_advance); + glyph->fWidth = SkToU16(SkScalarCeil(extents.width)); + glyph->fHeight = SkToU16(SkScalarCeil(extents.height)); + glyph->fLeft = SkToS16(SkScalarCeil(extents.x_bearing)); + glyph->fTop = SkToS16(SkScalarCeil(extents.y_bearing)); + glyph->fLsbDelta = 0; + glyph->fRsbDelta = 0; +} + +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(fBaseGlyphCount), fLoadGlyphFlags); + + if (err != 0) { + memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight); + return; + } + + generateGlyphImage(face, glyph); +} + +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(fBaseGlyphCount), flags); + + if (err != 0) { + path->reset(); + return; + } + + generateGlyphPath(face, path); +} + +void SkScalerContext_CairoFT::generateFontMetrics(SkPaint::FontMetrics* mx, + SkPaint::FontMetrics* my) +{ + SkDEBUGCODE(SkDebugf("SkScalerContext_CairoFT::generateFontMetrics unimplemented\n")); +} + +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; +} + +#ifdef SK_BUILD_FOR_ANDROID +SkTypeface* SkAndroidNextLogicalTypeface(SkFontID currFontID, + SkFontID origFontID) { + return NULL; +} +#endif + +/////////////////////////////////////////////////////////////////////////////// + +#include "SkFontMgr.h" + +SkFontMgr* SkFontMgr::Factory() { + // todo + return NULL; +} + -- 1.7.11.7