aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar bungeman <bungeman@google.com>2014-12-01 14:01:32 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2014-12-01 14:01:32 -0800
commit9dc24686e719566fd9ef054d6d27cff3a12daa71 (patch)
tree0bfe77587771858013b0c4bc7418857e5617ca83
parentf786901ff03f78c86962a2a1ed227f1533d16d2b (diff)
Clean up FreeType library ref counting.
The existing reference counting and code for LCD is difficult to understand. This cleans it up a bit in preperation for the typefaces holding the references and faces themselves which will clean this up quite a bit more. Review URL: https://codereview.chromium.org/742483004
-rw-r--r--src/ports/SkFontHost_FreeType.cpp273
1 files changed, 142 insertions, 131 deletions
diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp
index 7f70d4e045..d5b7985528 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;