1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/ports/SkFontHost_cairo.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,392 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2012 Mozilla Foundation 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 +#include "cairo.h" 1.13 +#include "cairo-ft.h" 1.14 + 1.15 +#include "SkFontHost_FreeType_common.h" 1.16 + 1.17 +#include "SkAdvancedTypefaceMetrics.h" 1.18 +#include "SkFontHost.h" 1.19 +#include "SkPath.h" 1.20 +#include "SkScalerContext.h" 1.21 +#include "SkTypefaceCache.h" 1.22 + 1.23 +#include <ft2build.h> 1.24 +#include FT_FREETYPE_H 1.25 + 1.26 +#ifndef SK_FONTHOST_CAIRO_STANDALONE 1.27 +#define SK_FONTHOST_CAIRO_STANDALONE 1 1.28 +#endif 1.29 + 1.30 +static cairo_user_data_key_t kSkTypefaceKey; 1.31 + 1.32 +class SkScalerContext_CairoFT : public SkScalerContext_FreeType_Base { 1.33 +public: 1.34 + SkScalerContext_CairoFT(SkTypeface* typeface, const SkDescriptor* desc); 1.35 + virtual ~SkScalerContext_CairoFT(); 1.36 + 1.37 +protected: 1.38 + virtual unsigned generateGlyphCount() SK_OVERRIDE; 1.39 + virtual uint16_t generateCharToGlyph(SkUnichar uniChar) SK_OVERRIDE; 1.40 + virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE; 1.41 + virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE; 1.42 + virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE; 1.43 + virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE; 1.44 + virtual void generateFontMetrics(SkPaint::FontMetrics* mx, 1.45 + SkPaint::FontMetrics* my) SK_OVERRIDE; 1.46 + virtual SkUnichar generateGlyphToChar(uint16_t glyph) SK_OVERRIDE; 1.47 +private: 1.48 + cairo_scaled_font_t* fScaledFont; 1.49 + uint32_t fLoadGlyphFlags; 1.50 +}; 1.51 + 1.52 +class CairoLockedFTFace { 1.53 +public: 1.54 + CairoLockedFTFace(cairo_scaled_font_t* scaledFont) 1.55 + : fScaledFont(scaledFont) 1.56 + , fFace(cairo_ft_scaled_font_lock_face(scaledFont)) 1.57 + {} 1.58 + 1.59 + ~CairoLockedFTFace() 1.60 + { 1.61 + cairo_ft_scaled_font_unlock_face(fScaledFont); 1.62 + } 1.63 + 1.64 + FT_Face getFace() 1.65 + { 1.66 + return fFace; 1.67 + } 1.68 + 1.69 +private: 1.70 + cairo_scaled_font_t* fScaledFont; 1.71 + FT_Face fFace; 1.72 +}; 1.73 + 1.74 +class SkCairoFTTypeface : public SkTypeface { 1.75 +public: 1.76 + static SkTypeface* CreateTypeface(cairo_font_face_t* fontFace, SkTypeface::Style style, bool isFixedWidth) { 1.77 + SkASSERT(fontFace != NULL); 1.78 + SkASSERT(cairo_font_face_get_type(fontFace) == CAIRO_FONT_TYPE_FT); 1.79 + 1.80 + SkFontID newId = SkTypefaceCache::NewFontID(); 1.81 + 1.82 + return SkNEW_ARGS(SkCairoFTTypeface, (fontFace, style, newId, isFixedWidth)); 1.83 + } 1.84 + 1.85 + cairo_font_face_t* getFontFace() { 1.86 + return fFontFace; 1.87 + } 1.88 + 1.89 + virtual SkStream* onOpenStream(int*) const SK_OVERRIDE { return NULL; } 1.90 + 1.91 + virtual SkAdvancedTypefaceMetrics* 1.92 + onGetAdvancedTypefaceMetrics(SkAdvancedTypefaceMetrics::PerGlyphInfo, 1.93 + const uint32_t*, uint32_t) const SK_OVERRIDE 1.94 + { 1.95 + SkDEBUGCODE(SkDebugf("SkCairoFTTypeface::onGetAdvancedTypefaceMetrics unimplemented\n")); 1.96 + return NULL; 1.97 + } 1.98 + 1.99 + virtual SkScalerContext* onCreateScalerContext(const SkDescriptor* desc) const SK_OVERRIDE 1.100 + { 1.101 + return SkNEW_ARGS(SkScalerContext_CairoFT, (const_cast<SkCairoFTTypeface*>(this), desc)); 1.102 + } 1.103 + 1.104 + virtual void onFilterRec(SkScalerContextRec*) const SK_OVERRIDE 1.105 + { 1.106 + SkDEBUGCODE(SkDebugf("SkCairoFTTypeface::onFilterRec unimplemented\n")); 1.107 + } 1.108 + 1.109 + virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE 1.110 + { 1.111 + SkDEBUGCODE(SkDebugf("SkCairoFTTypeface::onGetFontDescriptor unimplemented\n")); 1.112 + } 1.113 + 1.114 + virtual int onCharsToGlyphs(void const*, SkTypeface::Encoding, uint16_t*, int) const SK_OVERRIDE 1.115 + { 1.116 + return 0; 1.117 + } 1.118 + 1.119 + virtual int onCountGlyphs() const SK_OVERRIDE 1.120 + { 1.121 + return 0; 1.122 + } 1.123 + 1.124 + virtual int onGetUPEM() const SK_OVERRIDE 1.125 + { 1.126 + return 0; 1.127 + } 1.128 + 1.129 + virtual SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const SK_OVERRIDE 1.130 + { 1.131 + return NULL; 1.132 + } 1.133 + 1.134 + virtual int onGetTableTags(SkFontTableTag*) const SK_OVERRIDE 1.135 + { 1.136 + return 0; 1.137 + } 1.138 + 1.139 + virtual size_t onGetTableData(SkFontTableTag, size_t, size_t, void*) const SK_OVERRIDE 1.140 + { 1.141 + return 0; 1.142 + } 1.143 + 1.144 +private: 1.145 + 1.146 + SkCairoFTTypeface(cairo_font_face_t* fontFace, SkTypeface::Style style, SkFontID id, bool isFixedWidth) 1.147 + : SkTypeface(style, id, isFixedWidth) 1.148 + , fFontFace(fontFace) 1.149 + { 1.150 + cairo_font_face_set_user_data(fFontFace, &kSkTypefaceKey, this, NULL); 1.151 + cairo_font_face_reference(fFontFace); 1.152 + } 1.153 + 1.154 + ~SkCairoFTTypeface() 1.155 + { 1.156 + cairo_font_face_set_user_data(fFontFace, &kSkTypefaceKey, NULL, NULL); 1.157 + cairo_font_face_destroy(fFontFace); 1.158 + } 1.159 + 1.160 + cairo_font_face_t* fFontFace; 1.161 +}; 1.162 + 1.163 +SkTypeface* SkCreateTypefaceFromCairoFont(cairo_font_face_t* fontFace, SkTypeface::Style style, bool isFixedWidth) 1.164 +{ 1.165 + SkTypeface* typeface = reinterpret_cast<SkTypeface*>(cairo_font_face_get_user_data(fontFace, &kSkTypefaceKey)); 1.166 + 1.167 + if (typeface) { 1.168 + typeface->ref(); 1.169 + } else { 1.170 + typeface = SkCairoFTTypeface::CreateTypeface(fontFace, style, isFixedWidth); 1.171 + SkTypefaceCache::Add(typeface, style); 1.172 + } 1.173 + 1.174 + return typeface; 1.175 +} 1.176 + 1.177 +#if defined(SK_FONTHOST_DOES_NOT_USE_FONTMGR) && SK_FONTHOST_CAIRO_STANDALONE 1.178 +SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, 1.179 + const char famillyName[], 1.180 + SkTypeface::Style style) 1.181 +{ 1.182 + SkDEBUGFAIL("SkFontHost::FindTypeface unimplemented"); 1.183 + return NULL; 1.184 +} 1.185 + 1.186 +SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream*) 1.187 +{ 1.188 + SkDEBUGFAIL("SkFontHost::CreateTypeface unimplemented"); 1.189 + return NULL; 1.190 +} 1.191 + 1.192 +SkTypeface* SkFontHost::CreateTypefaceFromFile(char const*) 1.193 +{ 1.194 + SkDEBUGFAIL("SkFontHost::CreateTypefaceFromFile unimplemented"); 1.195 + return NULL; 1.196 +} 1.197 +#endif 1.198 + 1.199 +/////////////////////////////////////////////////////////////////////////////// 1.200 + 1.201 +static bool isLCD(const SkScalerContext::Rec& rec) { 1.202 + switch (rec.fMaskFormat) { 1.203 + case SkMask::kLCD16_Format: 1.204 + case SkMask::kLCD32_Format: 1.205 + return true; 1.206 + default: 1.207 + return false; 1.208 + } 1.209 +} 1.210 + 1.211 +/////////////////////////////////////////////////////////////////////////////// 1.212 +SkScalerContext_CairoFT::SkScalerContext_CairoFT(SkTypeface* typeface, const SkDescriptor* desc) 1.213 + : SkScalerContext_FreeType_Base(typeface, desc) 1.214 +{ 1.215 + SkMatrix matrix; 1.216 + fRec.getSingleMatrix(&matrix); 1.217 + 1.218 + cairo_font_face_t* fontFace = static_cast<SkCairoFTTypeface*>(typeface)->getFontFace(); 1.219 + 1.220 + cairo_matrix_t fontMatrix, ctMatrix; 1.221 + cairo_matrix_init(&fontMatrix, matrix.getScaleX(), matrix.getSkewY(), matrix.getSkewX(), matrix.getScaleY(), 0.0, 0.0); 1.222 + cairo_matrix_init_scale(&ctMatrix, 1.0, 1.0); 1.223 + 1.224 + // We need to ensure that the font options match for hinting, as generateMetrics() 1.225 + // uses the fScaledFont which uses these font options 1.226 + cairo_font_options_t *fontOptions = cairo_font_options_create(); 1.227 + 1.228 + FT_Int32 loadFlags = FT_LOAD_DEFAULT; 1.229 + 1.230 + if (SkMask::kBW_Format == fRec.fMaskFormat) { 1.231 + // See http://code.google.com/p/chromium/issues/detail?id=43252#c24 1.232 + loadFlags = FT_LOAD_TARGET_MONO; 1.233 + if (fRec.getHinting() == SkPaint::kNo_Hinting) { 1.234 + cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_NONE); 1.235 + loadFlags = FT_LOAD_NO_HINTING; 1.236 + } 1.237 + } else { 1.238 + switch (fRec.getHinting()) { 1.239 + case SkPaint::kNo_Hinting: 1.240 + loadFlags = FT_LOAD_NO_HINTING; 1.241 + cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_NONE); 1.242 + break; 1.243 + case SkPaint::kSlight_Hinting: 1.244 + loadFlags = FT_LOAD_TARGET_LIGHT; // This implies FORCE_AUTOHINT 1.245 + cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_SLIGHT); 1.246 + break; 1.247 + case SkPaint::kNormal_Hinting: 1.248 + cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_MEDIUM); 1.249 + if (fRec.fFlags & SkScalerContext::kForceAutohinting_Flag) { 1.250 + loadFlags = FT_LOAD_FORCE_AUTOHINT; 1.251 + } 1.252 + break; 1.253 + case SkPaint::kFull_Hinting: 1.254 + cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_FULL); 1.255 + if (fRec.fFlags & SkScalerContext::kForceAutohinting_Flag) { 1.256 + loadFlags = FT_LOAD_FORCE_AUTOHINT; 1.257 + } 1.258 + if (isLCD(fRec)) { 1.259 + if (SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag)) { 1.260 + loadFlags = FT_LOAD_TARGET_LCD_V; 1.261 + } else { 1.262 + loadFlags = FT_LOAD_TARGET_LCD; 1.263 + } 1.264 + } 1.265 + break; 1.266 + default: 1.267 + SkDebugf("---------- UNKNOWN hinting %d\n", fRec.getHinting()); 1.268 + break; 1.269 + } 1.270 + } 1.271 + 1.272 + fScaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctMatrix, fontOptions); 1.273 + 1.274 + if ((fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag) == 0) { 1.275 + loadFlags |= FT_LOAD_NO_BITMAP; 1.276 + } 1.277 + 1.278 + // Always using FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH to get correct 1.279 + // advances, as fontconfig and cairo do. 1.280 + // See http://code.google.com/p/skia/issues/detail?id=222. 1.281 + loadFlags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; 1.282 + 1.283 + fLoadGlyphFlags = loadFlags; 1.284 +} 1.285 + 1.286 +SkScalerContext_CairoFT::~SkScalerContext_CairoFT() 1.287 +{ 1.288 + cairo_scaled_font_destroy(fScaledFont); 1.289 +} 1.290 + 1.291 +unsigned SkScalerContext_CairoFT::generateGlyphCount() 1.292 +{ 1.293 + CairoLockedFTFace faceLock(fScaledFont); 1.294 + return faceLock.getFace()->num_glyphs; 1.295 +} 1.296 + 1.297 +uint16_t SkScalerContext_CairoFT::generateCharToGlyph(SkUnichar uniChar) 1.298 +{ 1.299 + CairoLockedFTFace faceLock(fScaledFont); 1.300 + return SkToU16(FT_Get_Char_Index(faceLock.getFace(), uniChar)); 1.301 +} 1.302 + 1.303 +void SkScalerContext_CairoFT::generateAdvance(SkGlyph* glyph) 1.304 +{ 1.305 + generateMetrics(glyph); 1.306 +} 1.307 + 1.308 +void SkScalerContext_CairoFT::generateMetrics(SkGlyph* glyph) 1.309 +{ 1.310 + SkASSERT(fScaledFont != NULL); 1.311 + cairo_text_extents_t extents; 1.312 + cairo_glyph_t cairoGlyph = { glyph->getGlyphID(fBaseGlyphCount), 0.0, 0.0 }; 1.313 + cairo_scaled_font_glyph_extents(fScaledFont, &cairoGlyph, 1, &extents); 1.314 + 1.315 + glyph->fAdvanceX = SkDoubleToFixed(extents.x_advance); 1.316 + glyph->fAdvanceY = SkDoubleToFixed(extents.y_advance); 1.317 + glyph->fWidth = SkToU16(SkScalarCeilToInt(extents.width)); 1.318 + glyph->fHeight = SkToU16(SkScalarCeilToInt(extents.height)); 1.319 + glyph->fLeft = SkToS16(SkScalarCeilToInt(extents.x_bearing)); 1.320 + glyph->fTop = SkToS16(SkScalarCeilToInt(extents.y_bearing)); 1.321 + glyph->fLsbDelta = 0; 1.322 + glyph->fRsbDelta = 0; 1.323 +} 1.324 + 1.325 +void SkScalerContext_CairoFT::generateImage(const SkGlyph& glyph) 1.326 +{ 1.327 + SkASSERT(fScaledFont != NULL); 1.328 + CairoLockedFTFace faceLock(fScaledFont); 1.329 + FT_Face face = faceLock.getFace(); 1.330 + 1.331 + FT_Error err = FT_Load_Glyph(face, glyph.getGlyphID(fBaseGlyphCount), fLoadGlyphFlags); 1.332 + 1.333 + if (err != 0) { 1.334 + memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight); 1.335 + return; 1.336 + } 1.337 + 1.338 + generateGlyphImage(face, glyph); 1.339 +} 1.340 + 1.341 +void SkScalerContext_CairoFT::generatePath(const SkGlyph& glyph, SkPath* path) 1.342 +{ 1.343 + SkASSERT(fScaledFont != NULL); 1.344 + CairoLockedFTFace faceLock(fScaledFont); 1.345 + FT_Face face = faceLock.getFace(); 1.346 + 1.347 + SkASSERT(&glyph && path); 1.348 + 1.349 + uint32_t flags = fLoadGlyphFlags; 1.350 + flags |= FT_LOAD_NO_BITMAP; // ignore embedded bitmaps so we're sure to get the outline 1.351 + flags &= ~FT_LOAD_RENDER; // don't scan convert (we just want the outline) 1.352 + 1.353 + FT_Error err = FT_Load_Glyph(face, glyph.getGlyphID(fBaseGlyphCount), flags); 1.354 + 1.355 + if (err != 0) { 1.356 + path->reset(); 1.357 + return; 1.358 + } 1.359 + 1.360 + generateGlyphPath(face, path); 1.361 +} 1.362 + 1.363 +void SkScalerContext_CairoFT::generateFontMetrics(SkPaint::FontMetrics* mx, 1.364 + SkPaint::FontMetrics* my) 1.365 +{ 1.366 + SkDEBUGCODE(SkDebugf("SkScalerContext_CairoFT::generateFontMetrics unimplemented\n")); 1.367 +} 1.368 + 1.369 +SkUnichar SkScalerContext_CairoFT::generateGlyphToChar(uint16_t glyph) 1.370 +{ 1.371 + SkASSERT(fScaledFont != NULL); 1.372 + CairoLockedFTFace faceLock(fScaledFont); 1.373 + FT_Face face = faceLock.getFace(); 1.374 + 1.375 + FT_UInt glyphIndex; 1.376 + SkUnichar charCode = FT_Get_First_Char(face, &glyphIndex); 1.377 + while (glyphIndex != 0) { 1.378 + if (glyphIndex == glyph) { 1.379 + return charCode; 1.380 + } 1.381 + charCode = FT_Get_Next_Char(face, charCode, &glyphIndex); 1.382 + } 1.383 + 1.384 + return 0; 1.385 +} 1.386 + 1.387 +/////////////////////////////////////////////////////////////////////////////// 1.388 + 1.389 +#include "SkFontMgr.h" 1.390 + 1.391 +SkFontMgr* SkFontMgr::Factory() { 1.392 + // todo 1.393 + return NULL; 1.394 +} 1.395 +