michael@0: From: George Wright michael@0: Date: Wed, 1 Aug 2012 16:43:15 -0400 michael@0: Subject: Bug 736276 - Add a new SkFontHost that takes a cairo_scaled_font_t r=karl michael@0: michael@0: michael@0: diff --git a/gfx/skia/Makefile.in b/gfx/skia/Makefile.in michael@0: index 5ebbd2e..7c8cdbf 100644 michael@0: --- a/gfx/skia/Makefile.in michael@0: +++ b/gfx/skia/Makefile.in michael@0: @@ -60,15 +60,15 @@ VPATH += \ michael@0: $(NULL) michael@0: michael@0: ifeq (android,$(MOZ_WIDGET_TOOLKIT)) michael@0: -OS_CXXFLAGS += $(CAIRO_FT_CFLAGS) michael@0: +OS_CXXFLAGS += $(MOZ_CAIRO_CFLAGS) $(CAIRO_FT_CFLAGS) michael@0: endif michael@0: michael@0: ifeq (gtk2,$(MOZ_WIDGET_TOOLKIT)) michael@0: -OS_CXXFLAGS += $(MOZ_PANGO_CFLAGS) michael@0: +OS_CXXFLAGS += $(MOZ_CAIRO_CFLAGS) $(MOZ_PANGO_CFLAGS) $(CAIRO_FT_CFLAGS) michael@0: endif michael@0: michael@0: ifeq (qt,$(MOZ_WIDGET_TOOLKIT)) michael@0: -OS_CXXFLAGS += $(MOZ_PANGO_CFLAGS) michael@0: +OS_CXXFLAGS += $(MOZ_CAIRO_CFLAGS) $(MOZ_PANGO_CFLAGS) $(CAIRO_FT_CFLAGS) michael@0: ifeq (Linux,$(OS_TARGET)) michael@0: DEFINES += -DSK_USE_POSIX_THREADS=1 michael@0: endif michael@0: diff --git a/gfx/skia/include/ports/SkTypeface_cairo.h b/gfx/skia/include/ports/SkTypeface_cairo.h michael@0: new file mode 100644 michael@0: index 0000000..7e44f04 michael@0: --- /dev/null michael@0: +++ b/gfx/skia/include/ports/SkTypeface_cairo.h michael@0: @@ -0,0 +1,11 @@ michael@0: +#ifndef SkTypeface_cairo_DEFINED michael@0: +#define SkTypeface_cairo_DEFINED michael@0: + michael@0: +#include michael@0: + michael@0: +#include "SkTypeface.h" michael@0: + michael@0: +SK_API extern SkTypeface* SkCreateTypefaceFromCairoFont(cairo_font_face_t* fontFace, SkTypeface::Style style, bool isFixedWidth); michael@0: + michael@0: +#endif michael@0: + michael@0: diff --git a/gfx/skia/moz.build b/gfx/skia/moz.build michael@0: index 9ceba59..66efd52 100644 michael@0: --- a/gfx/skia/moz.build michael@0: +++ b/gfx/skia/moz.build michael@0: @@ -171,10 +171,12 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': michael@0: 'SkTime_win.cpp', michael@0: ] michael@0: elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk2': michael@0: + EXPORTS.skia += [ michael@0: + 'include/ports/SkTypeface_cairo.h', michael@0: + ] michael@0: CPP_SOURCES += [ michael@0: - 'SkFontHost_FreeType.cpp', michael@0: + 'SkFontHost_cairo.cpp', michael@0: 'SkFontHost_FreeType_common.cpp', michael@0: - 'SkFontHost_linux.cpp', michael@0: 'SkThread_pthread.cpp', michael@0: 'SkThreadUtils_pthread.cpp', michael@0: 'SkThreadUtils_pthread_linux.cpp', michael@0: @@ -183,14 +185,15 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk2': michael@0: ] michael@0: elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt': michael@0: CPP_SOURCES += [ michael@0: - 'SkFontHost_FreeType.cpp', michael@0: + 'SkFontHost_cairo.cpp', michael@0: 'SkFontHost_FreeType_common.cpp', michael@0: 'SkOSFile.cpp', michael@0: ] michael@0: if CONFIG['OS_TARGET'] == 'Linux': michael@0: + EXPORTS.skia += [ michael@0: + 'include/ports/SkTypeface_cairo.h', michael@0: + ] michael@0: CPP_SOURCES += [ michael@0: - 'SkFontHost_linux.cpp', michael@0: - 'SkFontHost_tables.cpp', michael@0: 'SkThread_pthread.cpp', michael@0: 'SkThreadUtils_pthread.cpp', michael@0: 'SkThreadUtils_pthread_linux.cpp', michael@0: @@ -204,11 +207,13 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': michael@0: # Separate 'if' from above, since the else below applies to all != 'android' michael@0: # toolkits. michael@0: if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android': michael@0: + EXPORTS.skia += [ michael@0: + 'include/ports/SkTypeface_cairo.h', michael@0: + ] michael@0: CPP_SOURCES += [ michael@0: 'ashmem.cpp', michael@0: 'SkDebug_android.cpp', michael@0: - 'SkFontHost_android_old.cpp', michael@0: - 'SkFontHost_FreeType.cpp', michael@0: + 'SkFontHost_cairo.cpp', michael@0: 'SkFontHost_FreeType_common.cpp', michael@0: 'SkImageRef_ashmem.cpp', michael@0: 'SkTime_Unix.cpp', michael@0: diff --git a/gfx/skia/src/ports/SkFontHost_cairo.cpp b/gfx/skia/src/ports/SkFontHost_cairo.cpp michael@0: new file mode 100644 michael@0: index 0000000..bb5b778 michael@0: --- /dev/null michael@0: +++ b/gfx/skia/src/ports/SkFontHost_cairo.cpp michael@0: @@ -0,0 +1,364 @@ 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: +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: + 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: +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: + 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::kAutohinting_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::kAutohinting_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(SkScalarCeil(extents.width)); michael@0: + glyph->fHeight = SkToU16(SkScalarCeil(extents.height)); michael@0: + glyph->fLeft = SkToS16(SkScalarCeil(extents.x_bearing)); michael@0: + glyph->fTop = SkToS16(SkScalarCeil(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: +#ifdef SK_BUILD_FOR_ANDROID michael@0: +SkTypeface* SkAndroidNextLogicalTypeface(SkFontID currFontID, michael@0: + SkFontID origFontID) { michael@0: + return NULL; michael@0: +} michael@0: +#endif 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: + michael@0: -- michael@0: 1.7.11.7 michael@0: