Opal: add locking to OPFreeTypeFont around FT calls so it is threadsafe (NSFont is required to be)

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/opal/trunk@32792 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
ericwa 2011-04-06 19:49:01 +00:00
parent 303520115c
commit df3134ede3
2 changed files with 105 additions and 16 deletions

View File

@ -31,6 +31,12 @@
@interface OPFreeTypeFont: NSFont
{
FT_Face fontFace;
/**
* NSFont can be used simultaneously by multiple threads, so it is
* necessary to lock before we call FreeType, because an FT_Face
* object may be used by only one thread.
*/
NSLock *fontFaceLock;
BOOL isType1;
NSCache *tableCache;
}

View File

@ -49,7 +49,7 @@
#ifndef NSRectFromCGRect
#define NSRectFromCGRect(r) NSMakeRect(r.origin.x, r.origin.y, r.size.width, r.size.height)
#endif
static FT_Library OPFreeTypeLibrary = 0;
static const NSString *kOPFreeTypeLibrary = @"OPFreeTypeLibrary";
@interface NSObject (NSFontconfigFontDescriptorInternals)
@ -58,17 +58,24 @@ static FT_Library OPFreeTypeLibrary = 0;
@end
@implementation OPFreeTypeFont
+ (void)initialize
- (FT_Library)currentThreadFreeTypeLibrary
{
if ([OPFreeTypeFont class] == self)
NSMutableDictionary *threadDict = [[NSThread currentThread] threadDictionary];
if (nil == [threadDict objectForKey: kOPFreeTypeLibrary])
{
NSInteger error = FT_Init_FreeType(&OPFreeTypeLibrary);
FT_Library library = NULL;
NSInteger error = FT_Init_FreeType(&library);
if (0 != error)
{
[NSException raise: @"OTFontSystemException"
format: @"An error (%ld) occurred when initializing the FreeType library.", error];
}
[threadDict setObject: [NSValue valueWithPointer: library] forKey: kOPFreeTypeLibrary];
}
return [[threadDict objectForKey: kOPFreeTypeLibrary] pointerValue];
}
- (id)_initWithDescriptor: (NSFontDescriptor*)aDescriptor
@ -106,7 +113,7 @@ static FT_Library OPFreeTypeLibrary = 0;
return nil;
}
error = FT_New_Face(OPFreeTypeLibrary, path, faceIndex, &fontFace);
error = FT_New_Face([self currentThreadFreeTypeLibrary], path, faceIndex, &fontFace);
if (0 != error)
{
NSWarnMLog(@"Could not initialize freetype font (error: %ld)",
@ -146,9 +153,14 @@ static FT_Library OPFreeTypeLibrary = 0;
FT_Vector vector = FT_VectorQ1616FromCGAffineTransform(_matrix.CGTransform);
FT_Set_Transform(fontFace, &matrix, &vector);
//FIXME: Do more stuff
fontFaceLock = [[NSLock alloc] init];
return self;
}
// FIXME: Implement -dealloc?
- (BOOL)attachMetricsForFontAtPath: (NSString*)path
{
NSString *extension = [[path pathExtension] lowercaseString];
@ -194,10 +206,12 @@ static FT_Library OPFreeTypeLibrary = 0;
}
// First, run with a NULL pointer for the buffer to obtain the length needed.
[fontFaceLock lock];
error = FT_Load_Sfnt_Table(fontFace, tag, 0, NULL, &length);
if (0 != error)
{
[fontFaceLock unlock];
return nil;
}
@ -205,12 +219,15 @@ static FT_Library OPFreeTypeLibrary = 0;
buffer = malloc(length);
if (NULL == buffer)
{
[fontFaceLock unlock];
return nil;
}
// Now load the table into the buffer:
error = FT_Load_Sfnt_Table(fontFace, tag, 0, buffer, &length);
[fontFaceLock unlock];
if (0 != error)
{
// Oops, we could not fill the buffer, so we throw it away.
@ -255,17 +272,30 @@ static FT_Library OPFreeTypeLibrary = 0;
- (CGFloat)unitsPerEm
{
return (CGFloat)fontFace->units_per_EM;
[fontFaceLock lock];
CGFloat result = (CGFloat)fontFace->units_per_EM;
[fontFaceLock unlock];
return result;
}
- (CGFloat)ascender
{
return ((fontFace->ascender * [_descriptor pointSize]) / (CGFloat)fontFace->units_per_EM);
[fontFaceLock lock];
CGFloat result = ((fontFace->ascender * [_descriptor pointSize]) / (CGFloat)fontFace->units_per_EM);
[fontFaceLock unlock];
return result;
}
- (CGFloat)descender
{
return ((fontFace->descender * [_descriptor pointSize]) / (CGFloat)fontFace->units_per_EM);
[fontFaceLock lock];
CGFloat result = ((fontFace->descender * [_descriptor pointSize]) / (CGFloat)fontFace->units_per_EM);
[fontFaceLock unlock];
return result;
}
/* TODO: If this kind of method is too slow, we will have to cache the results
@ -274,24 +304,34 @@ static FT_Library OPFreeTypeLibrary = 0;
- (CGFloat)capHeight
{
FT_Short rawCapHeight = 0;
[fontFaceLock lock];
TT_OS2* OS2Table = FT_Get_Sfnt_Table(fontFace, TTAG_OS2);
if (NULL == OS2Table)
{
[fontFaceLock unlock];
return 0;
}
rawCapHeight = OS2Table->sCapHeight;
[fontFaceLock unlock];
return TRANSFORMED_SIZE(0, rawCapHeight).height;
}
- (CGFloat)xHeight
{
FT_Short rawXHeight = 0;
[fontFaceLock lock];
TT_OS2* OS2Table = FT_Get_Sfnt_Table(fontFace, TTAG_OS2);
if (NULL == OS2Table)
{
[fontFaceLock unlock];
return 0;
}
rawXHeight = OS2Table->sxHeight;
[fontFaceLock unlock];
return TRANSFORMED_SIZE(0, rawXHeight).height;
}
@ -300,24 +340,32 @@ static FT_Library OPFreeTypeLibrary = 0;
{
BOOL isFixedPitch = NO;
[fontFaceLock lock];
TT_Postscript *postTable = FT_Get_Sfnt_Table(fontFace, TTAG_post);
if (NULL == postTable)
{
[fontFaceLock unlock];
return NO;
}
isFixedPitch = postTable->isFixedPitch;
[fontFaceLock unlock];
return isFixedPitch;
}
- (CGFloat)italicAngle
{
FT_Fixed rawItalicAngle = 0;
[fontFaceLock lock];
TT_Postscript *postTable = FT_Get_Sfnt_Table(fontFace, TTAG_post);
if (NULL == postTable)
{
[fontFaceLock unlock];
return 0;
}
rawItalicAngle = postTable->italicAngle;
[fontFaceLock unlock];
return CGFloatFromFT_Fixed(rawItalicAngle);
}
@ -329,12 +377,17 @@ static FT_Library OPFreeTypeLibrary = 0;
* to be identical.
*/
FT_Short rawLineGap = 0;
[fontFaceLock lock];
TT_HoriHeader *hheaTable = FT_Get_Sfnt_Table(fontFace, TTAG_hhea);
if (NULL == hheaTable)
{
[fontFaceLock unlock];
return 0;
}
rawLineGap = hheaTable->Line_Gap;
[fontFaceLock unlock];
return TRANSFORMED_SIZE(0, rawLineGap).height;
}
@ -343,7 +396,11 @@ static FT_Library OPFreeTypeLibrary = 0;
/*
* FIXME: We should make this conditional on horizontal/vertical orientation.
*/
return NSMakeSize(REAL_SIZE(fontFace->max_advance_width), REAL_SIZE(fontFace->max_advance_height));
[fontFaceLock lock];
NSSize size = NSMakeSize(REAL_SIZE(fontFace->max_advance_width), REAL_SIZE(fontFace->max_advance_height));
[fontFaceLock unlock];
return size;
}
- (NSSize)minimumAdvancement
@ -353,33 +410,48 @@ static FT_Library OPFreeTypeLibrary = 0;
* FIXME2: We should make this conditional on horizontal/vertical orientation.
* FIXME3: Does FreeType apply the transform to the bounding box?
*/
return NSMakeSize(REAL_SIZE((fontFace->bbox).xMin),
[fontFaceLock lock];
NSSize size = NSMakeSize(REAL_SIZE((fontFace->bbox).xMin),
REAL_SIZE((fontFace->bbox).yMin));
[fontFaceLock unlock];
return size;
}
- (NSUInteger)numberOfGlyphs
{
return fontFace->num_glyphs;
[fontFaceLock lock];
NSUInteger result = fontFace->num_glyphs;
[fontFaceLock unlock];
return result;
}
- (CGFloat)underlinePosition
{
[fontFaceLock lock];
TT_Postscript *postTable = FT_Get_Sfnt_Table(fontFace, TTAG_post);
if (NULL == postTable)
{
[fontFaceLock unlock];
return 0;
}
return TRANSFORMED_SIZE(0, postTable->underlinePosition).height;
CGFloat position = TRANSFORMED_SIZE(0, postTable->underlinePosition).height;
[fontFaceLock unlock];
return position;
}
- (CGFloat)underlineThickness
{
[fontFaceLock lock];
TT_Postscript *postTable = FT_Get_Sfnt_Table(fontFace, TTAG_post);
if (NULL == postTable)
{
[fontFaceLock unlock];
return 0;
}
return TRANSFORMED_SIZE(0, postTable->underlineThickness).height;
CGFloat thickness = TRANSFORMED_SIZE(0, postTable->underlineThickness).height;
[fontFaceLock unlock];
return thickness;
}
- (NSSize)advancementForGlyph: (NSGlyph)glyph
@ -388,10 +460,13 @@ static FT_Library OPFreeTypeLibrary = 0;
{
return NSMakeSize(0, 0);
}
[fontFaceLock lock];
FT_Load_Glyph(fontFace, glyph, FT_LOAD_DEFAULT);
return NSMakeSize(REAL_SIZE(fontFace->glyph->linearHoriAdvance),
NSSize size = NSMakeSize(REAL_SIZE(fontFace->glyph->linearHoriAdvance),
REAL_SIZE(fontFace->glyph->linearVertAdvance));
[fontFaceLock unlock];
return size;
/*
* FIXME: Add fast path for integer rendering modes. We don't need to do
* so many integer->float conversions then.
@ -454,10 +529,13 @@ static FT_Library OPFreeTypeLibrary = 0;
{
//FIXME: Determine whether FreeType already transforms the bounding box for
//us.
[fontFaceLock lock];
CGFloat originX = REAL_SIZE((fontFace->bbox).xMin);
CGFloat originY = REAL_SIZE((fontFace->bbox).yMin);
CGFloat sizeX = (REAL_SIZE((fontFace->bbox).xMax) - originX);
CGFloat sizeY = (REAL_SIZE((fontFace->bbox).yMax) - originY);
[fontFaceLock unlock];
return NSMakeRect(originX, originY, sizeX, sizeY);
}
@ -468,12 +546,15 @@ static FT_Library OPFreeTypeLibrary = 0;
{
return NSMakeRect(0, 0, 0, 0);
}
[fontFaceLock lock];
FT_Load_Glyph(fontFace, glyph, FT_LOAD_DEFAULT);
return NSRectFromCGRect(TRANSFORMED_RECT(fontFace->glyph->metrics.horiBearingX,
NSRect result = NSRectFromCGRect(TRANSFORMED_RECT(fontFace->glyph->metrics.horiBearingX,
fontFace->glyph->metrics.horiBearingY,
fontFace->glyph->metrics.width,
fontFace->glyph->metrics.height));
[fontFaceLock unlock];
return result;
}
- (void)getBoundingRects: (NSRectArray)rects
@ -497,7 +578,9 @@ static FT_Library OPFreeTypeLibrary = 0;
- (NSGlyph)glyphWithName: (NSString*)name
{
[fontFaceLock lock];
FT_UInt glyph = FT_Get_Name_Index(fontFace, (FT_String*)[name UTF8String]);
[fontFaceLock unlock];
if(0 == glyph)
{
return NSNullGlyph;