implement fontmetrics

git-svn-id: http://skia.googlecode.com/svn/trunk@116 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
reed@android.com 2009-03-09 17:22:22 +00:00
parent ea446b9bc5
commit 0bf64d48cc

View File

@ -17,6 +17,7 @@
#include <carbon/carbon.h>
#include "SkFontHost.h"
#include "SkDescriptor.h"
#include "SkEndian.h"
#include "SkPoint.h"
// Give 1MB font cache budget
@ -90,14 +91,13 @@ protected:
virtual void generateMetrics(SkGlyph* glyph);
virtual void generateImage(const SkGlyph& glyph);
virtual void generatePath(const SkGlyph& glyph, SkPath* path);
virtual void generateLineHeight(SkPoint* ascent, SkPoint* descent);
virtual void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY);
// virtual SkDeviceContext getDC() { return NULL; } // not implemented on Mac
private:
ATSUTextLayout fLayout;
ATSUStyle fStyle;
CGColorSpaceRef fGrayColorSpace;
CGAffineTransform fTransform;
static OSStatus MoveTo(const Float32Point *pt, void *cb);
static OSStatus Line(const Float32Point *pt, void *cb);
@ -106,18 +106,31 @@ 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;
err = ::ATSUCreateStyle(&fStyle);
SkASSERT(0 == err);
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);
SkMatrix m;
fRec.getSingleMatrix(&m);
fTransform = CGAffineTransformMake(SkScalarToFloat(m[SkMatrix::kMScaleX]),
SkScalarToFloat(m[SkMatrix::kMSkewX]),
SkScalarToFloat(m[SkMatrix::kMSkewY]),
SkScalarToFloat(m[SkMatrix::kMScaleY]),
SkScalarToFloat(m[SkMatrix::kMTransX]),
SkScalarToFloat(m[SkMatrix::kMTransY]));
Fixed fixedSize = SK_Fixed1; //SkScalarToFixed(fRec.fTextSize);
static const ATSUAttributeTag tags[] = { kATSUSizeTag, kATSUFontMatrixTag };
static const ByteCount sizes[] = { sizeof(Fixed), sizeof(fTransform) };
const ATSUAttributeValuePtr values[] = { &fixedSize, &fTransform };
err = ::ATSUSetAttributes(fStyle, SK_ARRAY_COUNT(tags),
tags, sizes, values);
SkASSERT(0 == err);
err = ::ATSUCreateTextLayout(&fLayout);
@ -188,21 +201,118 @@ void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) {
}
}
static void convert_metrics(SkPaint::FontMetrics* dst,
const ATSFontMetrics& src) {
dst->fTop = -SkFloatToScalar(src.ascent);
dst->fAscent = -SkFloatToScalar(src.ascent);
dst->fDescent = SkFloatToScalar(src.descent);
dst->fBottom = SkFloatToScalar(src.descent);
dst->fLeading = SkFloatToScalar(src.leading);
}
static void* get_font_table(ATSFontRef fontID, uint32_t tag) {
ByteCount size;
OSStatus err = ATSFontGetTable(fontID, tag, 0, 0, NULL, &size);
if (err) {
return NULL;
}
void* data = sk_malloc_throw(size);
err = ATSFontGetTable(fontID, tag, 0, size, data, &size);
if (err) {
sk_free(data);
data = NULL;
}
return data;
}
static int get_be16(const void* data, size_t offset) {
const char* ptr = reinterpret_cast<const char*>(data);
uint16_t value = *reinterpret_cast<const uint16_t*>(ptr + offset);
int n = SkEndian_SwapBE16(value);
// now force it to be signed
return n << 16 >> 16;
}
#define SFNT_HEAD_UPEM_OFFSET 18
#define SFNT_HEAD_YMIN_OFFSET 38
#define SFNT_HEAD_YMAX_OFFSET 42
#define SFNT_HEAD_STYLE_OFFSET 44
#define SFNT_HHEA_ASCENT_OFFSET 4
#define SFNT_HHEA_DESCENT_OFFSET 6
#define SFNT_HHEA_LEADING_OFFSET 8
static bool init_vertical_metrics(ATSFontRef font, SkPoint pts[5]) {
void* head = get_font_table(font, 'head');
if (NULL == head) {
return false;
}
void* hhea = get_font_table(font, 'hhea');
if (NULL == hhea) {
sk_free(head);
return false;
}
int upem = get_be16(head, SFNT_HEAD_UPEM_OFFSET);
int ys[5];
ys[0] = -get_be16(head, SFNT_HEAD_YMAX_OFFSET);
ys[1] = -get_be16(hhea, SFNT_HHEA_ASCENT_OFFSET);
ys[2] = -get_be16(hhea, SFNT_HHEA_DESCENT_OFFSET);
ys[3] = -get_be16(head, SFNT_HEAD_YMIN_OFFSET);
ys[4] = get_be16(hhea, SFNT_HHEA_LEADING_OFFSET);
// now do some cleanup, to ensure y[max,min] are really that
if (ys[0] > ys[1]) {
ys[0] = ys[1];
}
if (ys[3] < ys[2]) {
ys[3] = ys[2];
}
for (int i = 0; i < 5; i++) {
pts[i].set(0, SkIntToScalar(ys[i]) / upem);
}
sk_free(hhea);
sk_free(head);
return true;
}
void SkScalerContext_Mac::generateFontMetrics(SkPaint::FontMetrics* mx,
SkPaint::FontMetrics* my) {
#if 0
OSStatus ATSFontGetVerticalMetrics (
ATSFontRef iFont,
ATSOptionFlags iOptions,
ATSFontMetrics *oMetrics
);
#endif
//SkASSERT(false);
if (mx)
memset(mx, 0, sizeof(SkPaint::FontMetrics));
if (my)
memset(my, 0, sizeof(SkPaint::FontMetrics));
return;
SkPoint pts[5];
if (!init_vertical_metrics(fRec.fFontID, pts)) {
// these are not as accurate as init_vertical_metrics :(
ATSFontMetrics metrics;
ATSFontGetVerticalMetrics(fRec.fFontID, kATSOptionFlagsDefault,
&metrics);
pts[0].set(0, -SkFloatToScalar(metrics.ascent));
pts[1].set(0, -SkFloatToScalar(metrics.ascent));
pts[2].set(0, -SkFloatToScalar(metrics.descent));
pts[3].set(0, -SkFloatToScalar(metrics.descent));
pts[4].set(0, SkFloatToScalar(metrics.leading)); //+ or -?
}
SkMatrix m;
fRec.getSingleMatrix(&m);
m.mapPoints(pts, 5);
if (mx) {
mx->fTop = pts[0].fX;
mx->fAscent = pts[1].fX;
mx->fDescent = pts[2].fX;
mx->fBottom = pts[3].fX;
mx->fLeading = pts[4].fX;
}
if (my) {
my->fTop = pts[0].fY;
my->fAscent = pts[1].fY;
my->fDescent = pts[2].fY;
my->fBottom = pts[3].fY;
my->fLeading = pts[4].fY;
}
}
void SkScalerContext_Mac::generateImage(const SkGlyph& glyph)
@ -226,7 +336,8 @@ void SkScalerContext_Mac::generateImage(const SkGlyph& glyph)
CGGlyph glyphID = glyph.getGlyphID();
CGFontRef fontRef = CGFontCreateWithPlatformFont(&fRec.fFontID);
CGContextSetFont(contextRef, fontRef);
CGContextSetFontSize(contextRef, SkScalarToFloat(fRec.fTextSize));
CGContextSetFontSize(contextRef, 1); //SkScalarToFloat(fRec.fTextSize));
CGContextSetTextMatrix(contextRef, fTransform);
CGContextShowGlyphsAtPoint(contextRef, -glyph.fLeft,
glyph.fTop + glyph.fHeight, &glyphID, 1);
@ -248,16 +359,6 @@ void SkScalerContext_Mac::generatePath(const SkGlyph& glyph, SkPath* path)
SkASSERT(err == noErr);
}
void SkScalerContext_Mac::generateLineHeight(SkPoint* ascent, SkPoint* descent)
{
ATSUTextMeasurement textAscent, textDescent;
ByteCount actual = 0;
OSStatus err = ::ATSUGetAttribute(fStyle,kATSULineAscentTag,sizeof(ATSUTextMeasurement),&textAscent,&actual);
ascent->set(0,textAscent);
err = ::ATSUGetAttribute(fStyle,kATSULineDescentTag,sizeof(ATSUTextMeasurement),&textDescent,&actual);
descent->set(0,textDescent);
}
OSStatus SkScalerContext_Mac::MoveTo(const Float32Point *pt, void *cb)
{
reinterpret_cast<SkPath*>(cb)->moveTo(F32PtToSkPoint(*pt));