update to latest api (need a test for this port!)

git-svn-id: http://skia.googlecode.com/svn/trunk@225 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
reed@android.com 2009-06-19 20:35:36 +00:00
parent 5c44d321d0
commit 90e764e3d9

View File

@ -1,16 +1,16 @@
/*
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
@ -34,7 +34,7 @@ static SkMutex gFTMutex;
static LOGFONT gDefaultFont = {0};
static const uint16_t BUFFERSIZE = (16384 - 32);
static uint8_t glyphbuf[BUFFERSIZE];
static uint8_t glyphbuf[BUFFERSIZE];
// Give 1MB font cache budget
#define FONT_CACHE_MEMORY_BUDGET (1024 * 1024)
@ -52,32 +52,32 @@ static inline FIXED SkScalarToFIXED(SkScalar x) {
uint32_t FontFaceChecksum(const TCHAR *q, SkTypeface::Style style)
{
if (!q) return style;
// 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) + *q);
q ++;
}
// add style
h = _rotl(h, 3) ^ style;
return h;
}
static SkTypeface::Style GetFontStyle(const LOGFONT& lf) {
static SkTypeface::Style GetFontStyle(const LOGFONT& lf) {
int style = SkTypeface::kNormal;
if (lf.lfWeight == FW_SEMIBOLD || lf.lfWeight == FW_DEMIBOLD || lf.lfWeight == FW_BOLD)
style |= SkTypeface::kBold;
if (lf.lfItalic)
style |= SkTypeface::kItalic;
return (SkTypeface::Style)style;
}
@ -86,12 +86,12 @@ struct SkFaceRec {
uint32_t fRefCnt;
uint32_t fFontID; // checksum of fFace
LOGFONT fFace;
SkFaceRec() : fFontID(-1), fRefCnt(0) {
SkFaceRec() : fFontID(-1), fRefCnt(0) {
memset(&fFace, 0, sizeof(LOGFONT));
}
~SkFaceRec() {}
uint32_t ref() {
return ++fRefCnt;
}
@ -108,7 +108,7 @@ static SkFaceRec* find_ft_face(uint32_t fontID) {
}
rec = rec->fNext;
}
return NULL;
}
@ -119,18 +119,18 @@ static SkFaceRec* insert_ft_face(const LOGFONT& lf) {
if (rec) {
return rec; // found?
}
rec = SkNEW(SkFaceRec);
rec->fFontID = id;
memcpy(&(rec->fFace), &lf, sizeof(LOGFONT));
rec->fNext = gFaceRecHead;
gFaceRecHead = rec;
return rec;
}
static void unref_ft_face(uint32_t fontID) {
SkFaceRec* rec = gFaceRecHead;
SkFaceRec* prev = NULL;
while (rec) {
@ -141,7 +141,7 @@ static void unref_ft_face(uint32_t fontID) {
prev->fNext = next;
else
gFaceRecHead = next;
SkDELETE(rec);
}
return;
@ -155,50 +155,57 @@ static void unref_ft_face(uint32_t fontID) {
// have to do this because SkTypeface::SkTypeface() is protected
class FontFaceRec_Typeface : public SkTypeface {
public:
FontFaceRec_Typeface(Style style, uint32_t id) : SkTypeface(style, id) {};
virtual ~FontFaceRec_Typeface() {};
};
static const LOGFONT* get_default_font() {
// don't hardcode on Windows, Win2000, XP, Vista, and international all have different default
// and the user could change too
if (gDefaultFont.lfFaceName[0] != 0) {
return &gDefaultFont;
}
NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof(NONCLIENTMETRICS);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
memcpy(&gDefaultFont, &(ncm.lfMessageFont), sizeof(LOGFONT));
return &gDefaultFont;
}
static SkTypeface* CreateTypeface_(const LOGFONT& lf) {
SkTypeface::Style style = GetFontStyle(lf);
FontFaceRec_Typeface* ptypeface = new FontFaceRec_Typeface(style, FontFaceChecksum(lf.lfFaceName, style));
if (NULL == ptypeface) {
SkASSERT(false);
return NULL;
}
SkFaceRec* rec = insert_ft_face(lf);
SkASSERT(rec);
return ptypeface;
}
uint32_t SkFontHost::NextLogicalFont(uint32_t fontID) {
// Zero means that we don't have any fallback fonts for this fontID.
// This function is implemented on Android, but doesn't have much
// meaning here.
return 0;
}
class SkScalerContext_Windows : public SkScalerContext {
public:
SkScalerContext_Windows(const SkDescriptor* desc);
virtual ~SkScalerContext_Windows();
protected:
virtual unsigned generateGlyphCount() const;
virtual uint16_t generateCharToGlyph(SkUnichar uni);
@ -211,7 +218,7 @@ protected:
//virtual SkDeviceContext getDC() {return ddc;}
private:
uint32_t fFontID;
LOGFONT lf;
LOGFONT lf;
MAT2 mat22;
HDC ddc;
HFONT savefont;
@ -220,7 +227,7 @@ private:
SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc) : SkScalerContext(desc), ddc(0), font(0), savefont(0) {
SkAutoMutexAcquire ac(gFTMutex);
fFontID = fRec.fFontID;
SkFaceRec* rec = find_ft_face(fRec.fFontID);
if (rec) {
@ -231,23 +238,25 @@ SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc) : SkS
SkASSERT(false);
memcpy(&lf, &gDefaultFont, sizeof(LOGFONT));
}
mat22.eM11 = SkScalarToFIXED(fRec.fPost2x2[0][0]);
mat22.eM12 = SkScalarToFIXED(-fRec.fPost2x2[0][1]);
mat22.eM21 = SkScalarToFIXED(fRec.fPost2x2[1][0]);
mat22.eM11 = SkScalarToFIXED(fRec.fPost2x2[0][0]);
mat22.eM12 = SkScalarToFIXED(fRec.fPost2x2[0][1]);
mat22.eM21 = SkScalarToFIXED(-fRec.fPost2x2[1][0]);
mat22.eM22 = SkScalarToFIXED(-fRec.fPost2x2[1][1]);
ddc = ::CreateCompatibleDC(NULL);
SetBkMode(ddc, TRANSPARENT);
lf.lfHeight = SkScalarFloor(fRec.fTextSize);
// Perform the dpi adjustment.
LONG lfHeight = -(fRec.fTextSize * GetDeviceCaps(ddc, LOGPIXELSY) / 72);
lf.lfHeight = lfHeight;
font = CreateFontIndirect(&lf);
savefont = (HFONT)SelectObject(ddc, font);
}
SkScalerContext_Windows::~SkScalerContext_Windows() {
unref_ft_face(fFontID);
if (ddc) {
::SelectObject(ddc, savefont);
::DeleteDC(ddc);
@ -264,11 +273,11 @@ unsigned SkScalerContext_Windows::generateGlyphCount() const {
}
uint16_t SkScalerContext_Windows::generateCharToGlyph(SkUnichar uni) {
//uint16_t index = 0;
//GetGlyphIndicesW(ddc, &(uint16_t&)uni, 1, &index, 0);
//return index;
// let's just use the uni as index on Windows
return SkToU16(uni);
}
@ -278,21 +287,21 @@ void SkScalerContext_Windows::generateAdvance(SkGlyph* glyph) {
}
void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) {
SkASSERT(ddc);
GLYPHMETRICS gm;
memset(&gm, 0, sizeof(gm));
glyph->fRsbDelta = 0;
glyph->fLsbDelta = 0;
UINT glyphIndexFlag = 0; //glyph->fIsCodePoint ? 0 : GGO_GLYPH_INDEX;
// UINT glyphIndexFlag = GGO_GLYPH_INDEX;
// Note: need to use GGO_GRAY8_BITMAP instead of GGO_METRICS because GGO_METRICS returns a smaller
// BlackBlox; we need the bigger one in case we need the image. fAdvance is the same.
uint32_t ret = GetGlyphOutlineW(ddc, glyph->getGlyphID(0), GGO_GRAY8_BITMAP | glyphIndexFlag, &gm, 0, NULL, &mat22);
if (GDI_ERROR != ret) {
if (ret == 0) {
// for white space, ret is zero and gmBlackBoxX, gmBlackBoxY are 1 incorrectly!
@ -307,7 +316,7 @@ void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) {
} else {
glyph->fWidth = 0;
}
#if 0
char buf[1024];
sprintf(buf, "generateMetrics: id:%d, w=%d, h=%d, font:%s, fh:%d\n", glyph->fID, glyph->fWidth, glyph->fHeight, lf.lfFaceName, lf.lfHeight);
@ -316,29 +325,54 @@ void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) {
}
void SkScalerContext_Windows::generateFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my) {
//SkASSERT(false);
if (mx)
memset(mx, 0, sizeof(SkPaint::FontMetrics));
if (my)
memset(my, 0, sizeof(SkPaint::FontMetrics));
return;
// Note: This code was borrowed from generateLineHeight, which has a note
// stating that it may be incorrect.
if (!(mx || my))
return;
SkASSERT(ddc);
OUTLINETEXTMETRIC otm;
uint32_t ret = GetOutlineTextMetrics(ddc, sizeof(otm), &otm);
if (sizeof(otm) != ret) {
return;
}
if (mx) {
mx->fTop = -SkIntToScalar(otm.otmTextMetrics.tmAscent); // Actually a long.
mx->fAscent = -SkIntToScalar(otm.otmAscent);
mx->fDescent = -SkIntToScalar(otm.otmDescent);
mx->fBottom = SkIntToScalar(otm.otmTextMetrics.tmDescent); // Long
mx->fLeading = SkIntToScalar(otm.otmTextMetrics.tmInternalLeading
+ otm.otmTextMetrics.tmExternalLeading); // Long
}
if (my) {
my->fTop = -SkIntToScalar(otm.otmTextMetrics.tmAscent); // Actually a long.
my->fAscent = -SkIntToScalar(otm.otmAscent);
my->fDescent = -SkIntToScalar(otm.otmDescent);
my->fBottom = SkIntToScalar(otm.otmTextMetrics.tmDescent); // Long
my->fLeading = SkIntToScalar(otm.otmTextMetrics.tmInternalLeading
+ otm.otmTextMetrics.tmExternalLeading); // Long
}
}
void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) {
SkAutoMutexAcquire ac(gFTMutex);
SkASSERT(ddc);
GLYPHMETRICS gm;
memset(&gm, 0, sizeof(gm));
#if 0
char buf[1024];
sprintf(buf, "generateImage: id:%d, w=%d, h=%d, font:%s,fh:%d\n", glyph.fID, glyph.fWidth, glyph.fHeight, lf.lfFaceName, lf.lfHeight);
OutputDebugString(buf);
#endif
uint32_t bytecount = 0;
UINT glyphIndexFlag = 0; //glyph.fIsCodePoint ? 0 : GGO_GLYPH_INDEX;
// UINT glyphIndexFlag = GGO_GLYPH_INDEX;
@ -347,21 +381,21 @@ void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) {
uint8_t *pBuff = new uint8_t[total_size];
if (NULL != pBuff) {
total_size = GetGlyphOutlineW(ddc, glyph.fID, GGO_GRAY8_BITMAP | glyphIndexFlag, &gm, total_size, pBuff, &mat22);
SkASSERT(total_size != GDI_ERROR);
SkASSERT(glyph.fWidth == gm.gmBlackBoxX);
SkASSERT(glyph.fHeight == gm.gmBlackBoxY);
uint8_t* dst = (uint8_t*)glyph.fImage;
uint32_t pitch = (gm.gmBlackBoxX + 3) & ~0x3;
if (pitch != glyph.rowBytes()) {
SkASSERT(false); // glyph.fImage has different rowsize!?
}
for (int32_t y = gm.gmBlackBoxY - 1; y >= 0; y--) {
uint8_t* src = pBuff + pitch * y;
for (uint32_t x = 0; x < gm.gmBlackBoxX; x++) {
if (*src > 63) {
*dst = 0xFF;
@ -376,66 +410,66 @@ void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) {
memset(dst, 0, glyph.rowBytes() - glyph.fWidth);
dst += glyph.rowBytes() - glyph.fWidth;
}
delete[] pBuff;
}
}
SkASSERT(GDI_ERROR != total_size && total_size >= 0);
}
void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) {
SkAutoMutexAcquire ac(gFTMutex);
SkASSERT(&glyph && path);
SkASSERT(ddc);
path->reset();
#if 0
char buf[1024];
sprintf(buf, "generatePath: id:%d, w=%d, h=%d, font:%s,fh:%d\n", glyph.fID, glyph.fWidth, glyph.fHeight, lf.lfFaceName, lf.lfHeight);
OutputDebugString(buf);
#endif
GLYPHMETRICS gm;
UINT glyphIndexFlag = 0; //glyph.fIsCodePoint ? 0 : GGO_GLYPH_INDEX;
uint32_t total_size = GetGlyphOutlineW(ddc, glyph.fID, GGO_NATIVE | glyphIndexFlag, &gm, BUFFERSIZE, glyphbuf, &mat22);
if (GDI_ERROR != total_size) {
const uint8_t* cur_glyph = glyphbuf;
const uint8_t* end_glyph = glyphbuf + total_size;
while(cur_glyph < end_glyph) {
const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
const uint8_t* end_poly = cur_glyph + th->cb;
const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
path->moveTo(SkFixedToScalar(*(SkFixed*)(&th->pfxStart.x)), SkFixedToScalar(*(SkFixed*)(&th->pfxStart.y)));
while(cur_poly < end_poly) {
const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
if (pc->wType == TT_PRIM_LINE) {
for (uint16_t i = 0; i < pc->cpfx; i++) {
path->lineTo(SkFixedToScalar(*(SkFixed*)(&pc->apfx[i].x)), SkFixedToScalar(*(SkFixed*)(&pc->apfx[i].y)));
}
}
if (pc->wType == TT_PRIM_QSPLINE) {
for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline
POINTFX pnt_b = pc->apfx[u]; // B is always the current point
POINTFX pnt_c = pc->apfx[u+1];
if (u < pc->cpfx - 2) { // If not on last spline, compute C
if (u < pc->cpfx - 2) { // If not on last spline, compute C
pnt_c.x = SkFixedToFIXED(SkFixedAve(*(SkFixed*)(&pnt_b.x), *(SkFixed*)(&pnt_c.x)));
pnt_c.y = SkFixedToFIXED(SkFixedAve(*(SkFixed*)(&pnt_b.y), *(SkFixed*)(&pnt_c.y)));
}
path->quadTo(SkFixedToScalar(*(SkFixed*)(&pnt_b.x)), SkFixedToScalar(*(SkFixed*)(&pnt_b.y)), SkFixedToScalar(*(SkFixed*)(&pnt_c.x)), SkFixedToScalar(*(SkFixed*)(&pnt_c.y)));
}
}
@ -456,20 +490,20 @@ void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) {
// Note: not sure this is the correct implementation
void SkScalerContext_Windows::generateLineHeight(SkPoint* ascent, SkPoint* descent) {
SkASSERT(ddc);
OUTLINETEXTMETRIC otm;
uint32_t ret = GetOutlineTextMetrics(ddc, sizeof(otm), &otm);
if (sizeof(otm) == ret) {
if (ascent)
ascent->iset(0, otm.otmAscent);
if (descent)
descent->iset(0, otm.otmDescent);
}
return;
}
@ -483,7 +517,7 @@ SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
}
SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
//Should not be used on Windows, keep linker happy
SkASSERT(false);
get_default_font();
@ -494,24 +528,6 @@ SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) {
return SkNEW_ARGS(SkScalerContext_Windows, (desc));
}
SkScalerContext* SkFontHost::CreateFallbackScalerContext(const SkScalerContext::Rec& rec) {
get_default_font();
SkAutoDescriptor ad(sizeof(rec) + sizeof(gDefaultFont) + SkDescriptor::ComputeOverhead(2));
SkDescriptor* desc = ad.getDesc();
desc->init();
SkScalerContext::Rec* newRec =
(SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
get_default_font();
CreateTypeface_(gDefaultFont);
newRec->fFontID = FontFaceChecksum(gDefaultFont.lfFaceName, GetFontStyle(gDefaultFont));
desc->computeChecksum();
return SkFontHost::CreateScalerContext(desc);
}
/** Return the closest matching typeface given either an existing family
(specified by a typeface in that family) or by a familyName, and a
requested style.
@ -522,8 +538,9 @@ SkScalerContext* SkFontHost::CreateFallbackScalerContext(const SkScalerContext::
*/
SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
const char familyName[], SkTypeface::Style style) {
const char familyName[],
SkTypeface::Style style) {
SkAutoMutexAcquire ac(gFTMutex);
#ifndef CAN_USE_LOGFONT_NAME
@ -533,13 +550,13 @@ SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
// clip to legal style bits
style = (SkTypeface::Style)(style & SkTypeface::kBoldItalic);
SkTypeface* tf = NULL;
if (NULL == familyFace && NULL == familyName) {
LOGFONT lf;
get_default_font();
memcpy(&lf, &gDefaultFont, sizeof(LOGFONT));
lf.lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL ;
lf.lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL ;
lf.lfItalic = ((style & SkTypeface::kItalic) != 0);
tf = CreateTypeface_(lf);
} else {
@ -559,17 +576,31 @@ SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
}
else {
memset(&lf, 0, sizeof(LOGFONT));
lf.lfHeight = -11; // default
lf.lfQuality = PROOF_QUALITY;
lf.lfCharSet = DEFAULT_CHARSET;
_tcsncpy(lf.lfFaceName, familyName, LF_FACESIZE);
#ifdef UNICODE
// Get the buffer size needed first.
size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName,
-1, NULL, 0);
// Allocate a buffer (str_len already has terminating null
// accounted for).
wchar_t *wideFamilyName = new wchar_t[str_len];
// Now actually convert the string.
::MultiByteToWideChar(CP_UTF8, 0, familyName, -1,
wideFamilyName, str_len);
::wcsncpy(lf.lfFaceName, wideFamilyName, LF_FACESIZE);
delete [] wideFamilyName;
#else
::strncpy(lf.lfFaceName, familyName, LF_FACESIZE);
#endif
lf.lfFaceName[LF_FACESIZE-1] = '\0';
}
// use the style desired
lf.lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL ;
lf.lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL ;
lf.lfItalic = ((style & SkTypeface::kItalic) != 0);
tf = CreateTypeface_(lf);
#endif
@ -598,5 +629,9 @@ void SkFontHost::GetGammaTables(const uint8_t* tables[2]) {
tables[1] = NULL; // white gamma (e.g. exp= 1/1.4)
}
#endif // WIN32
SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
SkASSERT(!"SkFontHost::CreateTypefaceFromFile unimplemented");
return NULL;
}
#endif // WIN32