0005-Bug-736276-Add-a-new-SkFontHost-that-takes-a-cairo_s.patch (14679B)
1 From: George Wright <george@mozilla.com> 2 Date: Wed, 1 Aug 2012 16:43:15 -0400 3 Subject: Bug 736276 - Add a new SkFontHost that takes a cairo_scaled_font_t r=karl 4 5 6 diff --git a/gfx/skia/include/ports/SkTypeface_cairo.h b/gfx/skia/include/ports/SkTypeface_cairo.h 7 new file mode 100644 8 index 0000000..7e44f04 9 --- /dev/null 10 +++ b/gfx/skia/include/ports/SkTypeface_cairo.h 11 @@ -0,0 +1,11 @@ 12 +#ifndef SkTypeface_cairo_DEFINED 13 +#define SkTypeface_cairo_DEFINED 14 + 15 +#include <cairo.h> 16 + 17 +#include "SkTypeface.h" 18 + 19 +SK_API extern SkTypeface* SkCreateTypefaceFromCairoFont(cairo_font_face_t* fontFace, SkTypeface::Style style, bool isFixedWidth); 20 + 21 +#endif 22 + 23 diff --git a/gfx/skia/moz.build b/gfx/skia/moz.build 24 index 9ceba59..66efd52 100644 25 --- a/gfx/skia/moz.build 26 +++ b/gfx/skia/moz.build 27 @@ -171,10 +171,12 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': 28 'SkTime_win.cpp', 29 ] 30 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk2': 31 + EXPORTS.skia += [ 32 + 'include/ports/SkTypeface_cairo.h', 33 + ] 34 CPP_SOURCES += [ 35 - 'SkFontHost_FreeType.cpp', 36 + 'SkFontHost_cairo.cpp', 37 'SkFontHost_FreeType_common.cpp', 38 - 'SkFontHost_linux.cpp', 39 'SkThread_pthread.cpp', 40 'SkThreadUtils_pthread.cpp', 41 'SkThreadUtils_pthread_linux.cpp', 42 @@ -183,14 +185,15 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk2': 43 ] 44 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt': 45 CPP_SOURCES += [ 46 - 'SkFontHost_FreeType.cpp', 47 + 'SkFontHost_cairo.cpp', 48 'SkFontHost_FreeType_common.cpp', 49 'SkOSFile.cpp', 50 ] 51 if CONFIG['OS_TARGET'] == 'Linux': 52 + EXPORTS.skia += [ 53 + 'include/ports/SkTypeface_cairo.h', 54 + ] 55 CPP_SOURCES += [ 56 - 'SkFontHost_linux.cpp', 57 - 'SkFontHost_tables.cpp', 58 'SkThread_pthread.cpp', 59 'SkThreadUtils_pthread.cpp', 60 'SkThreadUtils_pthread_linux.cpp', 61 @@ -204,11 +207,13 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': 62 # Separate 'if' from above, since the else below applies to all != 'android' 63 # toolkits. 64 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android': 65 + EXPORTS.skia += [ 66 + 'include/ports/SkTypeface_cairo.h', 67 + ] 68 CPP_SOURCES += [ 69 'ashmem.cpp', 70 'SkDebug_android.cpp', 71 - 'SkFontHost_android_old.cpp', 72 - 'SkFontHost_FreeType.cpp', 73 + 'SkFontHost_cairo.cpp', 74 'SkFontHost_FreeType_common.cpp', 75 'SkImageRef_ashmem.cpp', 76 'SkTime_Unix.cpp', 77 diff --git a/gfx/skia/src/ports/SkFontHost_cairo.cpp b/gfx/skia/src/ports/SkFontHost_cairo.cpp 78 new file mode 100644 79 index 0000000..bb5b778 80 --- /dev/null 81 +++ b/gfx/skia/src/ports/SkFontHost_cairo.cpp 82 @@ -0,0 +1,364 @@ 83 + 84 +/* 85 + * Copyright 2012 Mozilla Foundation 86 + * 87 + * Use of this source code is governed by a BSD-style license that can be 88 + * found in the LICENSE file. 89 + */ 90 + 91 +#include "cairo.h" 92 +#include "cairo-ft.h" 93 + 94 +#include "SkFontHost_FreeType_common.h" 95 + 96 +#include "SkAdvancedTypefaceMetrics.h" 97 +#include "SkFontHost.h" 98 +#include "SkPath.h" 99 +#include "SkScalerContext.h" 100 +#include "SkTypefaceCache.h" 101 + 102 +#include <ft2build.h> 103 +#include FT_FREETYPE_H 104 + 105 +static cairo_user_data_key_t kSkTypefaceKey; 106 + 107 +class SkScalerContext_CairoFT : public SkScalerContext_FreeType_Base { 108 +public: 109 + SkScalerContext_CairoFT(SkTypeface* typeface, const SkDescriptor* desc); 110 + virtual ~SkScalerContext_CairoFT(); 111 + 112 +protected: 113 + virtual unsigned generateGlyphCount() SK_OVERRIDE; 114 + virtual uint16_t generateCharToGlyph(SkUnichar uniChar) SK_OVERRIDE; 115 + virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE; 116 + virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE; 117 + virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE; 118 + virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE; 119 + virtual void generateFontMetrics(SkPaint::FontMetrics* mx, 120 + SkPaint::FontMetrics* my) SK_OVERRIDE; 121 + virtual SkUnichar generateGlyphToChar(uint16_t glyph) SK_OVERRIDE; 122 +private: 123 + cairo_scaled_font_t* fScaledFont; 124 + uint32_t fLoadGlyphFlags; 125 +}; 126 + 127 +class CairoLockedFTFace { 128 +public: 129 + CairoLockedFTFace(cairo_scaled_font_t* scaledFont) 130 + : fScaledFont(scaledFont) 131 + , fFace(cairo_ft_scaled_font_lock_face(scaledFont)) 132 + {} 133 + 134 + ~CairoLockedFTFace() 135 + { 136 + cairo_ft_scaled_font_unlock_face(fScaledFont); 137 + } 138 + 139 + FT_Face getFace() 140 + { 141 + return fFace; 142 + } 143 + 144 +private: 145 + cairo_scaled_font_t* fScaledFont; 146 + FT_Face fFace; 147 +}; 148 + 149 +class SkCairoFTTypeface : public SkTypeface { 150 +public: 151 + static SkTypeface* CreateTypeface(cairo_font_face_t* fontFace, SkTypeface::Style style, bool isFixedWidth) { 152 + SkASSERT(fontFace != NULL); 153 + SkASSERT(cairo_font_face_get_type(fontFace) == CAIRO_FONT_TYPE_FT); 154 + 155 + SkFontID newId = SkTypefaceCache::NewFontID(); 156 + 157 + return SkNEW_ARGS(SkCairoFTTypeface, (fontFace, style, newId, isFixedWidth)); 158 + } 159 + 160 + cairo_font_face_t* getFontFace() { 161 + return fFontFace; 162 + } 163 + 164 + virtual SkStream* onOpenStream(int*) const SK_OVERRIDE { return NULL; } 165 + 166 + virtual SkAdvancedTypefaceMetrics* 167 + onGetAdvancedTypefaceMetrics(SkAdvancedTypefaceMetrics::PerGlyphInfo, 168 + const uint32_t*, uint32_t) const SK_OVERRIDE 169 + { 170 + SkDEBUGCODE(SkDebugf("SkCairoFTTypeface::onGetAdvancedTypefaceMetrics unimplemented\n")); 171 + return NULL; 172 + } 173 + 174 + virtual SkScalerContext* onCreateScalerContext(const SkDescriptor* desc) const SK_OVERRIDE 175 + { 176 + return SkNEW_ARGS(SkScalerContext_CairoFT, (const_cast<SkCairoFTTypeface*>(this), desc)); 177 + } 178 + 179 + virtual void onFilterRec(SkScalerContextRec*) const SK_OVERRIDE 180 + { 181 + SkDEBUGCODE(SkDebugf("SkCairoFTTypeface::onFilterRec unimplemented\n")); 182 + } 183 + 184 + virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE 185 + { 186 + SkDEBUGCODE(SkDebugf("SkCairoFTTypeface::onGetFontDescriptor unimplemented\n")); 187 + } 188 + 189 + 190 +private: 191 + 192 + SkCairoFTTypeface(cairo_font_face_t* fontFace, SkTypeface::Style style, SkFontID id, bool isFixedWidth) 193 + : SkTypeface(style, id, isFixedWidth) 194 + , fFontFace(fontFace) 195 + { 196 + cairo_font_face_set_user_data(fFontFace, &kSkTypefaceKey, this, NULL); 197 + cairo_font_face_reference(fFontFace); 198 + } 199 + 200 + ~SkCairoFTTypeface() 201 + { 202 + cairo_font_face_set_user_data(fFontFace, &kSkTypefaceKey, NULL, NULL); 203 + cairo_font_face_destroy(fFontFace); 204 + } 205 + 206 + cairo_font_face_t* fFontFace; 207 +}; 208 + 209 +SkTypeface* SkCreateTypefaceFromCairoFont(cairo_font_face_t* fontFace, SkTypeface::Style style, bool isFixedWidth) 210 +{ 211 + SkTypeface* typeface = reinterpret_cast<SkTypeface*>(cairo_font_face_get_user_data(fontFace, &kSkTypefaceKey)); 212 + 213 + if (typeface) { 214 + typeface->ref(); 215 + } else { 216 + typeface = SkCairoFTTypeface::CreateTypeface(fontFace, style, isFixedWidth); 217 + SkTypefaceCache::Add(typeface, style); 218 + } 219 + 220 + return typeface; 221 +} 222 + 223 +SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace, 224 + const char famillyName[], 225 + SkTypeface::Style style) 226 +{ 227 + SkDEBUGFAIL("SkFontHost::FindTypeface unimplemented"); 228 + return NULL; 229 +} 230 + 231 +SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream*) 232 +{ 233 + SkDEBUGFAIL("SkFontHost::CreateTypeface unimplemented"); 234 + return NULL; 235 +} 236 + 237 +SkTypeface* SkFontHost::CreateTypefaceFromFile(char const*) 238 +{ 239 + SkDEBUGFAIL("SkFontHost::CreateTypefaceFromFile unimplemented"); 240 + return NULL; 241 +} 242 + 243 +/////////////////////////////////////////////////////////////////////////////// 244 + 245 +static bool isLCD(const SkScalerContext::Rec& rec) { 246 + switch (rec.fMaskFormat) { 247 + case SkMask::kLCD16_Format: 248 + case SkMask::kLCD32_Format: 249 + return true; 250 + default: 251 + return false; 252 + } 253 +} 254 + 255 +/////////////////////////////////////////////////////////////////////////////// 256 +SkScalerContext_CairoFT::SkScalerContext_CairoFT(SkTypeface* typeface, const SkDescriptor* desc) 257 + : SkScalerContext_FreeType_Base(typeface, desc) 258 +{ 259 + SkMatrix matrix; 260 + fRec.getSingleMatrix(&matrix); 261 + 262 + cairo_font_face_t* fontFace = static_cast<SkCairoFTTypeface*>(typeface)->getFontFace(); 263 + 264 + cairo_matrix_t fontMatrix, ctMatrix; 265 + cairo_matrix_init(&fontMatrix, matrix.getScaleX(), matrix.getSkewY(), matrix.getSkewX(), matrix.getScaleY(), 0.0, 0.0); 266 + cairo_matrix_init_scale(&ctMatrix, 1.0, 1.0); 267 + 268 + // We need to ensure that the font options match for hinting, as generateMetrics() 269 + // uses the fScaledFont which uses these font options 270 + cairo_font_options_t *fontOptions = cairo_font_options_create(); 271 + 272 + FT_Int32 loadFlags = FT_LOAD_DEFAULT; 273 + 274 + if (SkMask::kBW_Format == fRec.fMaskFormat) { 275 + // See http://code.google.com/p/chromium/issues/detail?id=43252#c24 276 + loadFlags = FT_LOAD_TARGET_MONO; 277 + if (fRec.getHinting() == SkPaint::kNo_Hinting) { 278 + cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_NONE); 279 + loadFlags = FT_LOAD_NO_HINTING; 280 + } 281 + } else { 282 + switch (fRec.getHinting()) { 283 + case SkPaint::kNo_Hinting: 284 + loadFlags = FT_LOAD_NO_HINTING; 285 + cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_NONE); 286 + break; 287 + case SkPaint::kSlight_Hinting: 288 + loadFlags = FT_LOAD_TARGET_LIGHT; // This implies FORCE_AUTOHINT 289 + cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_SLIGHT); 290 + break; 291 + case SkPaint::kNormal_Hinting: 292 + cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_MEDIUM); 293 + if (fRec.fFlags & SkScalerContext::kAutohinting_Flag) { 294 + loadFlags = FT_LOAD_FORCE_AUTOHINT; 295 + } 296 + break; 297 + case SkPaint::kFull_Hinting: 298 + cairo_font_options_set_hint_style(fontOptions, CAIRO_HINT_STYLE_FULL); 299 + if (fRec.fFlags & SkScalerContext::kAutohinting_Flag) { 300 + loadFlags = FT_LOAD_FORCE_AUTOHINT; 301 + } 302 + if (isLCD(fRec)) { 303 + if (SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag)) { 304 + loadFlags = FT_LOAD_TARGET_LCD_V; 305 + } else { 306 + loadFlags = FT_LOAD_TARGET_LCD; 307 + } 308 + } 309 + break; 310 + default: 311 + SkDebugf("---------- UNKNOWN hinting %d\n", fRec.getHinting()); 312 + break; 313 + } 314 + } 315 + 316 + fScaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctMatrix, fontOptions); 317 + 318 + if ((fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag) == 0) { 319 + loadFlags |= FT_LOAD_NO_BITMAP; 320 + } 321 + 322 + // Always using FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH to get correct 323 + // advances, as fontconfig and cairo do. 324 + // See http://code.google.com/p/skia/issues/detail?id=222. 325 + loadFlags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; 326 + 327 + fLoadGlyphFlags = loadFlags; 328 +} 329 + 330 +SkScalerContext_CairoFT::~SkScalerContext_CairoFT() 331 +{ 332 + cairo_scaled_font_destroy(fScaledFont); 333 +} 334 + 335 +unsigned SkScalerContext_CairoFT::generateGlyphCount() 336 +{ 337 + CairoLockedFTFace faceLock(fScaledFont); 338 + return faceLock.getFace()->num_glyphs; 339 +} 340 + 341 +uint16_t SkScalerContext_CairoFT::generateCharToGlyph(SkUnichar uniChar) 342 +{ 343 + CairoLockedFTFace faceLock(fScaledFont); 344 + return SkToU16(FT_Get_Char_Index(faceLock.getFace(), uniChar)); 345 +} 346 + 347 +void SkScalerContext_CairoFT::generateAdvance(SkGlyph* glyph) 348 +{ 349 + generateMetrics(glyph); 350 +} 351 + 352 +void SkScalerContext_CairoFT::generateMetrics(SkGlyph* glyph) 353 +{ 354 + SkASSERT(fScaledFont != NULL); 355 + cairo_text_extents_t extents; 356 + cairo_glyph_t cairoGlyph = { glyph->getGlyphID(fBaseGlyphCount), 0.0, 0.0 }; 357 + cairo_scaled_font_glyph_extents(fScaledFont, &cairoGlyph, 1, &extents); 358 + 359 + glyph->fAdvanceX = SkDoubleToFixed(extents.x_advance); 360 + glyph->fAdvanceY = SkDoubleToFixed(extents.y_advance); 361 + glyph->fWidth = SkToU16(SkScalarCeil(extents.width)); 362 + glyph->fHeight = SkToU16(SkScalarCeil(extents.height)); 363 + glyph->fLeft = SkToS16(SkScalarCeil(extents.x_bearing)); 364 + glyph->fTop = SkToS16(SkScalarCeil(extents.y_bearing)); 365 + glyph->fLsbDelta = 0; 366 + glyph->fRsbDelta = 0; 367 +} 368 + 369 +void SkScalerContext_CairoFT::generateImage(const SkGlyph& glyph) 370 +{ 371 + SkASSERT(fScaledFont != NULL); 372 + CairoLockedFTFace faceLock(fScaledFont); 373 + FT_Face face = faceLock.getFace(); 374 + 375 + FT_Error err = FT_Load_Glyph(face, glyph.getGlyphID(fBaseGlyphCount), fLoadGlyphFlags); 376 + 377 + if (err != 0) { 378 + memset(glyph.fImage, 0, glyph.rowBytes() * glyph.fHeight); 379 + return; 380 + } 381 + 382 + generateGlyphImage(face, glyph); 383 +} 384 + 385 +void SkScalerContext_CairoFT::generatePath(const SkGlyph& glyph, SkPath* path) 386 +{ 387 + SkASSERT(fScaledFont != NULL); 388 + CairoLockedFTFace faceLock(fScaledFont); 389 + FT_Face face = faceLock.getFace(); 390 + 391 + SkASSERT(&glyph && path); 392 + 393 + uint32_t flags = fLoadGlyphFlags; 394 + flags |= FT_LOAD_NO_BITMAP; // ignore embedded bitmaps so we're sure to get the outline 395 + flags &= ~FT_LOAD_RENDER; // don't scan convert (we just want the outline) 396 + 397 + FT_Error err = FT_Load_Glyph(face, glyph.getGlyphID(fBaseGlyphCount), flags); 398 + 399 + if (err != 0) { 400 + path->reset(); 401 + return; 402 + } 403 + 404 + generateGlyphPath(face, path); 405 +} 406 + 407 +void SkScalerContext_CairoFT::generateFontMetrics(SkPaint::FontMetrics* mx, 408 + SkPaint::FontMetrics* my) 409 +{ 410 + SkDEBUGCODE(SkDebugf("SkScalerContext_CairoFT::generateFontMetrics unimplemented\n")); 411 +} 412 + 413 +SkUnichar SkScalerContext_CairoFT::generateGlyphToChar(uint16_t glyph) 414 +{ 415 + SkASSERT(fScaledFont != NULL); 416 + CairoLockedFTFace faceLock(fScaledFont); 417 + FT_Face face = faceLock.getFace(); 418 + 419 + FT_UInt glyphIndex; 420 + SkUnichar charCode = FT_Get_First_Char(face, &glyphIndex); 421 + while (glyphIndex != 0) { 422 + if (glyphIndex == glyph) { 423 + return charCode; 424 + } 425 + charCode = FT_Get_Next_Char(face, charCode, &glyphIndex); 426 + } 427 + 428 + return 0; 429 +} 430 + 431 +#ifdef SK_BUILD_FOR_ANDROID 432 +SkTypeface* SkAndroidNextLogicalTypeface(SkFontID currFontID, 433 + SkFontID origFontID) { 434 + return NULL; 435 +} 436 +#endif 437 + 438 +/////////////////////////////////////////////////////////////////////////////// 439 + 440 +#include "SkFontMgr.h" 441 + 442 +SkFontMgr* SkFontMgr::Factory() { 443 + // todo 444 + return NULL; 445 +} 446 + 447 -- 448 1.7.11.7