check-point (2) on mac fonts

- simplify typeface factories



git-svn-id: http://skia.googlecode.com/svn/trunk@115 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
reed@android.com 2009-03-09 15:25:11 +00:00
parent 60dfdbc1ae
commit ea446b9bc5

View File

@ -34,217 +34,46 @@ static inline uint32_t _rotl(uint32_t v, uint32_t r) {
return (v << r | v >> (32 - r));
}
// This will generate a unique ID based on the fontname + fontstyle
// and also used by upper layer
uint32_t FontFaceChecksum(const char *name,SkTypeface::Style style)
{
if (!name) return style;
char* q = (char*)name;
// From "Performance in Practice of String Hashing Functions"
// Ramakrishna & Zobel
const uint32_t L = 5;
const uint32_t R = 2;
uint32_t h = 0x12345678;
while (*q) {
uint32_t ql = tolower(*q);
h ^= ((h << L) + (h >> R) + ql);
q ++;
}
// add style
h = _rotl(h, 3) ^ style;
return h;
}
#pragma mark -
struct SkFaceRec {
SkFaceRec* fNext;
uint32_t fRefCnt;
ATSUFontID fFontID;
ATSUStyle fStyle;
SkFaceRec() : fFontID(0), fRefCnt(0), fStyle(NULL) {};
~SkFaceRec() {
if (fStyle) {
::ATSUDisposeStyle(fStyle);
fStyle = NULL;
}
}
uint32_t ref() {
return ++fRefCnt;
}
};
// Font Face list
static SkFaceRec* gFaceRecHead = NULL;
static SkFaceRec* find_ft_face(const ATSUFontID fontID) {
SkFaceRec* rec = gFaceRecHead;
while (rec) {
if (rec->fFontID == fontID) {
return rec;
}
rec = rec->fNext;
}
return NULL;
}
static SkFaceRec* insert_ft_face(const ATSUFontID afontID, const ATSUStyle atsuStyle) {
SkFaceRec* rec = find_ft_face(afontID);
if (rec) {
return rec; // found?
}
rec = SkNEW(SkFaceRec);
rec->fFontID = afontID;
rec->fStyle = atsuStyle;
rec->fNext = gFaceRecHead;
gFaceRecHead = rec;
return rec;
}
static void unref_ft_face(const ATSUFontID fontID) {
SkFaceRec* rec = gFaceRecHead;
SkFaceRec* prev = NULL;
while (rec) {
SkFaceRec* next = rec->fNext;
if (rec->fFontID == fontID) {
if (--rec->fRefCnt == 0) {
if (prev)
prev->fNext = next;
else
gFaceRecHead = next;
SkDELETE(rec);
}
return;
}
prev = rec;
rec = next;
}
SkASSERT("shouldn't get here, face not in list");
}
#pragma mark -
// have to do this because SkTypeface::SkTypeface() is protected
class SkTypeface_Mac : public SkTypeface {
public:
SkTypeface_Mac(SkTypeface::Style style, uint32_t id) : SkTypeface(style, id) {}
~SkTypeface_Mac() {}
SkTypeface_Mac(SkTypeface::Style style, uint32_t id)
: SkTypeface(style, id) {}
};
#pragma mark -
static SkTypeface* CreateTypeface_(const char *name, const SkTypeface::Style style) {
OSStatus err;
ATSUStyle atsuStyle;
::ATSUCreateStyle(&atsuStyle);
if (name != NULL) {
static const ATSUAttributeTag fontTag = kATSUFontTag;
static const ByteCount fontTagSize = sizeof(ATSUFontID);
ATSUFontID fontID = 0;
#if 1
err = ::ATSUFindFontFromName(
name,strlen(name),kFontNoNameCode, /* instead of regular, kFontFamilyName returns bold and/or italic sometimes, but why this works?? */
kFontMacintoshPlatform,kFontNoScriptCode,kFontNoLanguageCode,&fontID);
#else
CFStringRef cfontName = CFStringCreateWithCString(NULL, name, kCFStringEncodingASCII);
ATSFontRef fontRef = ::ATSFontFindFromName(cfontName,kATSOptionFlagsDefault);
fontID = ::FMGetFontFromATSFontRef(fontRef);
CFRelease(cfontName);
#endif
if (0 != fontID) {
const ATSUAttributeValuePtr values[] = { &fontID };
err = ::ATSUSetAttributes(atsuStyle,1,&fontTag,&fontTagSize,values);
}
else {
}
}
if (style != SkTypeface::kNormal) {
Boolean fontItalic = ((style & SkTypeface::kItalic) != 0);
Boolean fontBold = ((style & SkTypeface::kBold) != 0);
const ATSUAttributeTag tags[2] = { kATSUQDBoldfaceTag, kATSUQDItalicTag };
const ATSUAttributeValuePtr values[2] = { &fontBold, &fontItalic };
const ByteCount sizes[2] = { sizeof(Boolean), sizeof(Boolean) };
err = ::ATSUSetAttributes(atsuStyle,2,tags,sizes,values);
}
uint32_t cs = FontFaceChecksum(name,style);
SkTypeface_Mac* ptypeface = new SkTypeface_Mac(style,cs);
if (NULL == ptypeface) {
SkASSERT(false);
return NULL;
}
SkFaceRec* rec = insert_ft_face(cs, atsuStyle);
SkASSERT(rec);
return ptypeface;
static uint32_t find_from_name(const char name[]) {
CFStringRef str = CFStringCreateWithCString(NULL, name,
kCFStringEncodingUTF8);
uint32_t fontID = ::ATSFontFindFromName(str, kATSOptionFlagsDefault);
CFRelease(str);
return fontID;
}
static SkTypeface* CreateTypeface_(const SkFaceRec* rec, const SkTypeface::Style style) {
static uint32_t find_default_fontID() {
static const char* gDefaultNames[] = { "Arial", "Tahoma", "Helvetica" };
OSStatus err;
ATSUStyle atsuStyle;
err = ::ATSUCreateAndCopyStyle(rec->fStyle, &atsuStyle);
Boolean fontItalic = ((style & SkTypeface::kItalic) != 0);
Boolean fontBold = ((style & SkTypeface::kBold) != 0);
const ATSUAttributeTag tags[2] = { kATSUQDBoldfaceTag, kATSUQDItalicTag };
const ATSUAttributeValuePtr values[2] = { &fontBold, &fontItalic };
const ByteCount sizes[2] = { sizeof(Boolean), sizeof(Boolean) };
err = ::ATSUSetAttributes(atsuStyle,2,tags,sizes,values);
// get old font id and name
ATSUFontID fontID = 0;
ByteCount actual = 0;
err = ::ATSUGetAttribute(rec->fStyle,kATSUFontTag,sizeof(ATSUFontID),&fontID,&actual);
ByteCount actualLength = 0;
char *fontname = NULL;
err = ::ATSUFindFontName(fontID , kFontFamilyName, kFontUnicodePlatform, kFontNoScriptCode,
kFontNoLanguageCode , 0 , NULL , &actualLength , NULL );
if ( err == noErr)
{
actualLength += 1 ;
fontname = (char*)malloc( actualLength );
err = ::ATSUFindFontName(fontID, kFontFamilyName, kFontUnicodePlatform, kFontNoScriptCode,
kFontNoLanguageCode, actualLength, fontname , NULL, NULL);
}
SkTypeface_Mac* ptypeface = NULL;
if (fontname == NULL) {
ptypeface = new SkTypeface_Mac(style,rec->fFontID);
return ptypeface;
}
else {
uint32_t cs = FontFaceChecksum(fontname,style);
ptypeface = new SkTypeface_Mac(style, cs);
if (NULL == ptypeface) {
SkASSERT(false);
return NULL;
uint32_t fontID;
for (size_t i = 0; i < SK_ARRAY_COUNT(gDefaultNames); i++) {
fontID = find_from_name(gDefaultNames[i]);
if (fontID) {
return fontID;
}
free(fontname);
insert_ft_face(cs,atsuStyle);
}
return ptypeface;
sk_throw();
return 0;
}
static SkTypeface* CreateTypeface_(const char name[], SkTypeface::Style style) {
uint32_t fontID = 0;
if (NULL != name) {
fontID = find_from_name(name);
}
if (0 == fontID) {
fontID = find_default_fontID();
}
// we lie (for now) and report that we found the exact style bits
return new SkTypeface_Mac(style, fontID);
}
#pragma mark -
@ -277,46 +106,33 @@ private:
};
SkScalerContext_Mac::SkScalerContext_Mac(const SkDescriptor* desc)
: SkScalerContext(desc), fLayout(0), fStyle(0)
{
: SkScalerContext(desc), fLayout(0), fStyle(0) {
SkAutoMutexAcquire ac(gFTMutex);
OSStatus err;
SkFaceRec* rec = find_ft_face(fRec.fFontID);
if (rec) {
rec->ref();
err = ::ATSUCreateAndCopyStyle(rec->fStyle, &fStyle);
}
else {
SkASSERT(false);
// create a default
err = ::ATSUCreateStyle(&fStyle);
}
err = ::ATSUCreateStyle(&fStyle);
SkASSERT(0 == err);
uint32_t size = SkScalarFloor(fRec.fTextSize);
Fixed fixedSize = IntToFixed(size);
Fixed fixedSize = SkScalarToFixed(fRec.fTextSize);
static const ATSUAttributeTag sizeTag = kATSUSizeTag;
static const ByteCount sizeTagSize = sizeof(Fixed);
const ATSUAttributeValuePtr values[] = { &fixedSize };
err = ::ATSUSetAttributes(fStyle,1,&sizeTag,&sizeTagSize,values);
SkASSERT(0 == err);
err = ::ATSUCreateTextLayout(&fLayout);
SkASSERT(0 == err);
fGrayColorSpace = ::CGColorSpaceCreateDeviceGray();
}
SkScalerContext_Mac::~SkScalerContext_Mac()
{
SkScalerContext_Mac::~SkScalerContext_Mac() {
::CGColorSpaceRelease(fGrayColorSpace);
unref_ft_face(fRec.fFontID);
::ATSUDisposeTextLayout(fLayout);
::ATSUDisposeStyle(fStyle);
}
unsigned SkScalerContext_Mac::generateGlyphCount() const
{
unsigned SkScalerContext_Mac::generateGlyphCount() const {
return 0xFFFF;
}
@ -407,24 +223,13 @@ void SkScalerContext_Mac::generateImage(const SkGlyph& glyph)
::CGContextSetGrayFillColor(contextRef, 1.0, 1.0);
::CGContextSetTextDrawingMode(contextRef, kCGTextFill);
#if 1
ATSUAttributeTag tag = kATSUCGContextTag;
ByteCount size = sizeof(CGContextRef);
ATSUAttributeValuePtr value = &contextRef;
OSStatus err = ::ATSUSetLayoutControls(fLayout, 1, &tag, &size, &value);
SkASSERT(!err);
err = ::ATSUDrawText(fLayout, kATSUFromTextBeginning, kATSUToTextEnd,
SkIntToFixed(-glyph.fLeft),
SkIntToFixed(glyph.fTop + glyph.fHeight));
SkASSERT(!err);
#else
CGGlyph glyphID = glyph.getGlyphID();
CGFontRef fontRef = CGFontCreateWithPlatformFont(&fRec.fFontID);
CGContextSetFont(contextRef, fontRef);
CGContextSetFontSize(contextRef, SkScalarToFloat(fRec.fTextSize));
CGContextShowGlyphsAtPoint(contextRef, -glyph.fLeft,
glyph.fTop + glyph.fHeight, &glyphID, 1);
#endif
::CGContextRelease(contextRef);
}
@ -493,73 +298,41 @@ SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
}
SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
//Should not be used on Mac, keep linker happy
SkASSERT(false);
return CreateTypeface_(gDefaultfont,SkTypeface::kNormal);
return NULL;
}
SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
// TODO
return CreateTypeface_(gDefaultfont,SkTypeface::kNormal);
return NULL;
}
SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc)
{
SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) {
return new SkScalerContext_Mac(desc);
}
SkScalerContext* SkFontHost::CreateFallbackScalerContext(const SkScalerContext::Rec& rec)
{
SkAutoDescriptor ad(sizeof(rec) + sizeof(gDefaultfont) + SkDescriptor::ComputeOverhead(2));
SkAutoDescriptor ad(sizeof(rec) + SkDescriptor::ComputeOverhead(1));
SkDescriptor* desc = ad.getDesc();
desc->init();
SkScalerContext::Rec* newRec =
(SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
CreateTypeface_(gDefaultfont,SkTypeface::kNormal);
newRec->fFontID = FontFaceChecksum(gDefaultfont,SkTypeface::kNormal);
(SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag,
sizeof(rec), &rec);
newRec->fFontID = find_default_fontID();
desc->computeChecksum();
return SkFontHost::CreateScalerContext(desc);
}
SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
const char familyName[], SkTypeface::Style style) {
SkAutoMutexAcquire ac(gFTMutex);
// clip to legal style bits
style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic);
SkTypeface* tf = NULL;
if (NULL == familyFace && NULL == familyName) {
tf = CreateTypeface_(gDefaultfont,style);
// todo: we don't know how to respect style bits
if (NULL == familyName && NULL != familyFace) {
familyFace->ref();
return const_cast<SkTypeface*>(familyFace);
} else {
return CreateTypeface_(familyName, style);
}
else {
if (NULL != familyFace) {
uint32_t id = familyFace->uniqueID();
SkFaceRec* rec = find_ft_face(id);
if (!rec) {
SkASSERT(false);
tf = CreateTypeface_(gDefaultfont,style);
}
else {
tf = CreateTypeface_(rec,style);
}
}
else {
tf = CreateTypeface_(familyName,style);
}
}
if (NULL == tf) {
tf = CreateTypeface_(gDefaultfont,style);
}
return tf;
}
size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) {