Index: src/ports/SkFontHost_FreeType.cpp |
diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp |
index 7f70d4e045af56959119309503da2169a4cbf0fc..d5b79855281cb05ee5edda36fc9ba75d3e2c5d08 100644 |
--- a/src/ports/SkFontHost_FreeType.cpp |
+++ b/src/ports/SkFontHost_FreeType.cpp |
@@ -1,4 +1,3 @@ |
- |
/* |
* Copyright 2006 The Android Open Source Project |
* |
@@ -12,7 +11,6 @@ |
#include "SkColorPriv.h" |
#include "SkDescriptor.h" |
#include "SkFDot6.h" |
-#include "SkFloatingPoint.h" |
#include "SkFontHost.h" |
#include "SkFontHost_FreeType_common.h" |
#include "SkGlyph.h" |
@@ -20,12 +18,12 @@ |
#include "SkMaskGamma.h" |
#include "SkMatrix22.h" |
#include "SkOTUtils.h" |
-#include "SkOnce.h" |
#include "SkScalerContext.h" |
#include "SkStream.h" |
#include "SkString.h" |
#include "SkTemplates.h" |
#include "SkThread.h" |
+#include "SkTypes.h" |
#if defined(SK_CAN_USE_DLOPEN) |
#include <dlfcn.h> |
@@ -35,8 +33,10 @@ |
#include FT_BITMAP_H |
#include FT_FREETYPE_H |
#include FT_LCD_FILTER_H |
+#include FT_MODULE_H |
#include FT_OUTLINE_H |
#include FT_SIZES_H |
+#include FT_SYSTEM_H |
#include FT_TRUETYPE_TABLES_H |
#include FT_TYPE1_TABLES_H |
#include FT_XFREE86_H |
@@ -65,97 +65,121 @@ |
using namespace skia_advanced_typeface_metrics_utils; |
static bool isLCD(const SkScalerContext::Rec& rec) { |
- switch (rec.fMaskFormat) { |
- case SkMask::kLCD16_Format: |
- return true; |
- default: |
- return false; |
- } |
+ return SkMask::kLCD16_Format == rec.fMaskFormat; |
} |
////////////////////////////////////////////////////////////////////////// |
-struct SkFaceRec; |
- |
-SK_DECLARE_STATIC_MUTEX(gFTMutex); |
-static int gFTCount; |
-static FT_Library gFTLibrary; |
-static SkFaceRec* gFaceRecHead; |
-static bool gLCDSupportValid; // true iff |gLCDSupport| has been set. |
-static bool gLCDSupport; // true iff LCD is supported by the runtime. |
-static int gLCDExtra; // number of extra pixels for filtering. |
- |
-///////////////////////////////////////////////////////////////////////// |
- |
-// FT_Library_SetLcdFilterWeights was introduced in FreeType 2.4.0. |
-// The following platforms provide FreeType of at least 2.4.0. |
-// Ubuntu >= 11.04 (previous deprecated April 2013) |
-// Debian >= 6.0 (good) |
-// OpenSuse >= 11.4 (previous deprecated January 2012 / Nov 2013 for Evergreen 11.2) |
-// Fedora >= 14 (good) |
-// Android >= Gingerbread (good) |
-typedef FT_Error (*FT_Library_SetLcdFilterWeightsProc)(FT_Library, unsigned char*); |
- |
-// Caller must lock gFTMutex before calling this function. |
-static bool InitFreetype() { |
- gFTMutex.assertHeld(); |
- |
- FT_Error err = FT_Init_FreeType(&gFTLibrary); |
- if (err) { |
- return false; |
+extern "C" { |
+ static void* sk_ft_alloc(FT_Memory, long size) { |
+ return sk_malloc_throw(size); |
+ } |
+ static void sk_ft_free(FT_Memory, void* block) { |
+ sk_free(block); |
} |
+ static void* sk_ft_realloc(FT_Memory, long cur_size, long new_size, void* block) { |
+ return sk_realloc_throw(block, new_size); |
+ } |
+}; |
+FT_MemoryRec_ gFTMemory = { NULL, sk_ft_alloc, sk_ft_free, sk_ft_realloc }; |
- // Setup LCD filtering. This reduces color fringes for LCD smoothed glyphs. |
- // Use default { 0x10, 0x40, 0x70, 0x40, 0x10 }, as it adds up to 0x110, simulating ink spread. |
- // SetLcdFilter must be called before SetLcdFilterWeights. |
- err = FT_Library_SetLcdFilter(gFTLibrary, FT_LCD_FILTER_DEFAULT); |
- if (0 == err) { |
- gLCDSupport = true; |
- gLCDExtra = 2; //Using a filter adds one full pixel to each side. |
+class FreeTypeLibrary : SkNoncopyable { |
+public: |
+ FreeTypeLibrary() : fLibrary(NULL), fIsLCDSupported(false), fLCDExtra(0) { |
+ if (FT_New_Library(&gFTMemory, &fLibrary)) { |
+ return; |
+ } |
+ FT_Add_Default_Modules(fLibrary); |
+ |
+ // Setup LCD filtering. This reduces color fringes for LCD smoothed glyphs. |
+ // Default { 0x10, 0x40, 0x70, 0x40, 0x10 } adds up to 0x110, simulating ink spread. |
+ // SetLcdFilter must be called before SetLcdFilterWeights. |
+ if (FT_Library_SetLcdFilter(fLibrary, FT_LCD_FILTER_DEFAULT) == 0) { |
+ fIsLCDSupported = true; |
+ fLCDExtra = 2; //Using a filter adds one full pixel to each side. |
#ifdef SK_FONTHOST_FREETYPE_USE_NORMAL_LCD_FILTER |
- // This also adds to 0x110 simulating ink spread, but provides better results than default. |
- static unsigned char gGaussianLikeHeavyWeights[] = { 0x1A, 0x43, 0x56, 0x43, 0x1A, }; |
- |
-#if SK_FONTHOST_FREETYPE_RUNTIME_VERSION > 0x020400 |
- err = FT_Library_SetLcdFilterWeights(gFTLibrary, gGaussianLikeHeavyWeights); |
-#elif SK_CAN_USE_DLOPEN == 1 |
- //The FreeType library is already loaded, so symbols are available in process. |
- void* self = dlopen(NULL, RTLD_LAZY); |
- if (self) { |
- FT_Library_SetLcdFilterWeightsProc setLcdFilterWeights; |
- //The following cast is non-standard, but safe for POSIX. |
- *reinterpret_cast<void**>(&setLcdFilterWeights) = dlsym(self, "FT_Library_SetLcdFilterWeights"); |
- dlclose(self); |
- |
- if (setLcdFilterWeights) { |
- err = setLcdFilterWeights(gFTLibrary, gGaussianLikeHeavyWeights); |
+ // Adds to 0x110 simulating ink spread, but provides better results than default. |
+ static unsigned char gGaussianLikeHeavyWeights[] = { 0x1A, 0x43, 0x56, 0x43, 0x1A, }; |
+ |
+# if SK_FONTHOST_FREETYPE_RUNTIME_VERSION > 0x020400 |
+ FT_Library_SetLcdFilterWeights(fLibrary, gGaussianLikeHeavyWeights); |
+# elif SK_CAN_USE_DLOPEN == 1 |
+ //The FreeType library is already loaded, so symbols are available in process. |
+ void* self = dlopen(NULL, RTLD_LAZY); |
+ if (self) { |
+ FT_Library_SetLcdFilterWeightsProc setLcdFilterWeights; |
+ //The following cast is non-standard, but safe for POSIX. |
+ *reinterpret_cast<void**>(&setLcdFilterWeights) = |
+ dlsym(self, "FT_Library_SetLcdFilterWeights"); |
+ dlclose(self); |
+ |
+ if (setLcdFilterWeights) { |
+ setLcdFilterWeights(fLibrary, gGaussianLikeHeavyWeights); |
+ } |
} |
- } |
-#endif |
+# endif |
#endif |
+ } |
+ } |
+ ~FreeTypeLibrary() { |
+ if (fLibrary) { |
+ FT_Done_Library(fLibrary); |
+ } |
} |
- gLCDSupportValid = true; |
- return true; |
-} |
+ FT_Library library() { return fLibrary; } |
+ bool isLCDSupported() { return fIsLCDSupported; } |
+ int lcdExtra() { return fLCDExtra; } |
+ |
+private: |
+ FT_Library fLibrary; |
+ bool fIsLCDSupported; |
+ int fLCDExtra; |
+ |
+ // FT_Library_SetLcdFilterWeights was introduced in FreeType 2.4.0. |
+ // The following platforms provide FreeType of at least 2.4.0. |
+ // Ubuntu >= 11.04 (previous deprecated April 2013) |
+ // Debian >= 6.0 (good) |
+ // OpenSuse >= 11.4 (previous deprecated January 2012 / Nov 2013 for Evergreen 11.2) |
+ // Fedora >= 14 (good) |
+ // Android >= Gingerbread (good) |
+ typedef FT_Error (*FT_Library_SetLcdFilterWeightsProc)(FT_Library, unsigned char*); |
+}; |
+ |
+struct SkFaceRec; |
+ |
+SK_DECLARE_STATIC_MUTEX(gFTMutex); |
+static FreeTypeLibrary* gFTLibrary; |
+static SkFaceRec* gFaceRecHead; |
+ |
+// Private to RefFreeType and UnrefFreeType |
+static int gFTCount; |
-// Called while holding gFTMutex. |
-static void determine_lcd_support(bool* lcdSupported) { |
- if (!gLCDSupportValid) { |
- // This will determine LCD support as a side effect. |
- InitFreetype(); |
- FT_Done_FreeType(gFTLibrary); |
+// Caller must lock gFTMutex before calling this function. |
+static bool ref_ft_library() { |
+ gFTMutex.assertHeld(); |
+ SkASSERT(gFTCount >= 0); |
+ |
+ if (0 == gFTCount) { |
+ SkASSERT(NULL == gFTLibrary); |
+ gFTLibrary = SkNEW(FreeTypeLibrary); |
} |
- SkASSERT(gLCDSupportValid); |
- *lcdSupported = gLCDSupport; |
+ ++gFTCount; |
+ return gFTLibrary->library(); |
} |
-// Lazy, once, wrapper to ask the FreeType Library if it can support LCD text |
-static bool is_lcd_supported() { |
- static bool lcdSupported = false; |
- SkOnce(&gLCDSupportValid, &gFTMutex, determine_lcd_support, &lcdSupported); |
- return lcdSupported; |
+// Caller must lock gFTMutex before calling this function. |
+static void unref_ft_library() { |
+ gFTMutex.assertHeld(); |
+ SkASSERT(gFTCount > 0); |
+ |
+ --gFTCount; |
+ if (0 == gFTCount) { |
+ SkASSERT(NULL != gFTLibrary); |
+ SkDELETE(gFTLibrary); |
+ SkDEBUGCODE(gFTLibrary = NULL;) |
+ } |
} |
class SkScalerContext_FreeType : public SkScalerContext_FreeType_Base { |
@@ -224,34 +248,28 @@ struct SkFaceRec { |
}; |
extern "C" { |
- static unsigned long sk_stream_read(FT_Stream stream, |
- unsigned long offset, |
- unsigned char* buffer, |
- unsigned long count ) { |
+ static unsigned long sk_ft_stream_io(FT_Stream stream, |
+ unsigned long offset, |
+ unsigned char* buffer, |
+ unsigned long count) |
+ { |
SkStream* str = (SkStream*)stream->descriptor.pointer; |
if (count) { |
if (!str->rewind()) { |
return 0; |
- } else { |
- unsigned long ret; |
- if (offset) { |
- ret = str->read(NULL, offset); |
- if (ret != offset) { |
- return 0; |
- } |
- } |
- ret = str->read(buffer, count); |
- if (ret != count) { |
+ } |
+ if (offset) { |
+ if (str->skip(offset) != offset) { |
return 0; |
} |
- count = ret; |
} |
+ count = str->read(buffer, count); |
} |
return count; |
} |
- static void sk_stream_close(FT_Stream) {} |
+ static void sk_ft_stream_close(FT_Stream) {} |
} |
SkFaceRec::SkFaceRec(SkStream* strm, uint32_t fontID) |
@@ -261,8 +279,8 @@ SkFaceRec::SkFaceRec(SkStream* strm, uint32_t fontID) |
sk_bzero(&fFTStream, sizeof(fFTStream)); |
fFTStream.size = fSkStream->getLength(); |
fFTStream.descriptor.pointer = fSkStream; |
- fFTStream.read = sk_stream_read; |
- fFTStream.close = sk_stream_close; |
+ fFTStream.read = sk_ft_stream_io; |
+ fFTStream.close = sk_ft_stream_close; |
} |
// Will return 0 on failure |
@@ -290,7 +308,7 @@ static SkFaceRec* ref_ft_face(const SkTypeface* typeface) { |
// this passes ownership of strm to the rec |
rec = SkNEW_ARGS(SkFaceRec, (strm, fontID)); |
- FT_Open_Args args; |
+ FT_Open_Args args; |
memset(&args, 0, sizeof(args)); |
const void* memoryBase = strm->getMemoryBase(); |
@@ -303,17 +321,16 @@ static SkFaceRec* ref_ft_face(const SkTypeface* typeface) { |
args.stream = &rec->fFTStream; |
} |
- FT_Error err = FT_Open_Face(gFTLibrary, &args, face_index, &rec->fFace); |
+ FT_Error err = FT_Open_Face(gFTLibrary->library(), &args, face_index, &rec->fFace); |
if (err) { // bad filename, try the default font |
SkDEBUGF(("ERROR: unable to open font '%x'\n", fontID)); |
SkDELETE(rec); |
return NULL; |
- } else { |
- SkASSERT(rec->fFace); |
- rec->fNext = gFaceRecHead; |
- gFaceRecHead = rec; |
- return rec; |
} |
+ SkASSERT(rec->fFace); |
+ rec->fNext = gFaceRecHead; |
+ gFaceRecHead = rec; |
+ return rec; |
} |
// Caller must lock gFTMutex before calling this function. |
@@ -346,10 +363,8 @@ class AutoFTAccess { |
public: |
AutoFTAccess(const SkTypeface* tf) : fRec(NULL), fFace(NULL) { |
gFTMutex.acquire(); |
- if (1 == ++gFTCount) { |
- if (!InitFreetype()) { |
- sk_throw(); |
- } |
+ if (!ref_ft_library()) { |
+ sk_throw(); |
} |
fRec = ref_ft_face(tf); |
if (fRec) { |
@@ -361,9 +376,7 @@ public: |
if (fFace) { |
unref_ft_face(fFace); |
} |
- if (0 == --gFTCount) { |
- FT_Done_FreeType(gFTLibrary); |
- } |
+ unref_ft_library(); |
gFTMutex.release(); |
} |
@@ -684,7 +697,8 @@ void SkTypeface_FreeType::onFilterRec(SkScalerContextRec* rec) const { |
rec->fTextSize = SkIntToScalar(1 << 14); |
} |
- if (!is_lcd_supported() && isLCD(*rec)) { |
+ AutoFTAccess fta(this); |
+ if (!gFTLibrary->isLCDSupported() && isLCD(*rec)) { |
// If the runtime Freetype library doesn't support LCD mode, we disable |
// it here. |
rec->fMaskFormat = SkMask::kA8_Format; |
@@ -789,12 +803,9 @@ SkScalerContext_FreeType::SkScalerContext_FreeType(SkTypeface* typeface, |
: SkScalerContext_FreeType_Base(typeface, desc) { |
SkAutoMutexAcquire ac(gFTMutex); |
- if (gFTCount == 0) { |
- if (!InitFreetype()) { |
- sk_throw(); |
- } |
+ if (!ref_ft_library()) { |
+ sk_throw(); |
} |
- ++gFTCount; |
// load the font file |
fStrikeIndex = -1; |
@@ -990,10 +1001,8 @@ SkScalerContext_FreeType::~SkScalerContext_FreeType() { |
if (fFace != NULL) { |
unref_ft_face(fFace); |
} |
- if (--gFTCount == 0) { |
- FT_Done_FreeType(gFTLibrary); |
- SkDEBUGCODE(gFTLibrary = NULL;) |
- } |
+ |
+ unref_ft_library(); |
} |
/* We call this before each use of the fFace, since we may be sharing |
@@ -1124,11 +1133,11 @@ bool SkScalerContext_FreeType::getCBoxForLetter(char letter, FT_BBox* bbox) { |
void SkScalerContext_FreeType::updateGlyphIfLCD(SkGlyph* glyph) { |
if (isLCD(fRec)) { |
if (fLCDIsVert) { |
- glyph->fHeight += gLCDExtra; |
- glyph->fTop -= gLCDExtra >> 1; |
+ glyph->fHeight += gFTLibrary->lcdExtra(); |
+ glyph->fTop -= gFTLibrary->lcdExtra() >> 1; |
} else { |
- glyph->fWidth += gLCDExtra; |
- glyph->fLeft -= gLCDExtra >> 1; |
+ glyph->fWidth += gFTLibrary->lcdExtra(); |
+ glyph->fLeft -= gFTLibrary->lcdExtra() >> 1; |
} |
} |
} |
@@ -1604,14 +1613,16 @@ size_t SkTypeface_FreeType::onGetTableData(SkFontTableTag tag, size_t offset, |
/////////////////////////////////////////////////////////////////////////////// |
/////////////////////////////////////////////////////////////////////////////// |
- |
-SkTypeface_FreeType::Scanner::Scanner() { |
- if (FT_Init_FreeType(&fLibrary)) { |
- fLibrary = NULL; |
+SkTypeface_FreeType::Scanner::Scanner() : fLibrary(NULL) { |
+ if (FT_New_Library(&gFTMemory, &fLibrary)) { |
+ return; |
} |
+ FT_Add_Default_Modules(fLibrary); |
} |
SkTypeface_FreeType::Scanner::~Scanner() { |
- FT_Done_FreeType(fLibrary); |
+ if (fLibrary) { |
+ FT_Done_Library(fLibrary); |
+ } |
} |
FT_Face SkTypeface_FreeType::Scanner::openFace(SkStream* stream, int ttcIndex, |
@@ -1634,8 +1645,8 @@ FT_Face SkTypeface_FreeType::Scanner::openFace(SkStream* stream, int ttcIndex, |
memset(ftStream, 0, sizeof(*ftStream)); |
ftStream->size = stream->getLength(); |
ftStream->descriptor.pointer = stream; |
- ftStream->read = sk_stream_read; |
- ftStream->close = sk_stream_close; |
+ ftStream->read = sk_ft_stream_io; |
+ ftStream->close = sk_ft_stream_close; |
args.flags = FT_OPEN_STREAM; |
args.stream = ftStream; |