diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-27 00:09:42 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-27 00:09:42 +0000 |
commit | ae2c20f398933a9e86c387dcc465ec0f71065ffc (patch) | |
tree | de668b1411e2ee0b4e49b6d8f8b68183134ac990 /skia/ports/SkFontHost_win.cpp | |
parent | 09911bf300f1a419907a9412154760efd0b7abc3 (diff) | |
download | chromium_src-ae2c20f398933a9e86c387dcc465ec0f71065ffc.zip chromium_src-ae2c20f398933a9e86c387dcc465ec0f71065ffc.tar.gz chromium_src-ae2c20f398933a9e86c387dcc465ec0f71065ffc.tar.bz2 |
Add skia to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@16 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'skia/ports/SkFontHost_win.cpp')
-rw-r--r-- | skia/ports/SkFontHost_win.cpp | 908 |
1 files changed, 908 insertions, 0 deletions
diff --git a/skia/ports/SkFontHost_win.cpp b/skia/ports/SkFontHost_win.cpp new file mode 100644 index 0000000..d66297a --- /dev/null +++ b/skia/ports/SkFontHost_win.cpp @@ -0,0 +1,908 @@ +/* libs/graphics/ports/SkFontHost_win.cpp + +** + +** Copyright 2006, Google Inc. + +** + +*/ + + + +#include "SkString.h" + +//#include "SkStream.h" + + + +#include "SkFontHost.h" + +#include "SkDescriptor.h" + +#include "SkThread.h" + + + +#ifdef WIN32 + +#include "windows.h" + +#include "tchar.h" + + + +static SkMutex gFTMutex; + + + +static LOGFONT gDefaultFont; + + + +static const uint16_t BUFFERSIZE = (16384 - 32); + +static uint8_t glyphbuf[BUFFERSIZE]; + + + +#ifndef SK_FONTKEY + + #define SK_FONTKEY "Windows Font Key" + +#endif + + + +inline FIXED SkFixedToFIXED(SkFixed x) { + + return *(FIXED*)(&x); + +} + + + +class FontFaceRec_Typeface : public SkTypeface { + +public: + +#if 0 + + FontFaceRec_Typeface(const LOGFONT& face) : fFace(face) + + { + + int style = 0; + + if (face.lfWeight == FW_SEMIBOLD || face.lfWeight == FW_DEMIBOLD || face.lfWeight == FW_BOLD) + + style |= SkTypeface::kBold; + + if (face.lfItalic) + + style |= SkTypeface::kItalic; + + this->setStyle((SkTypeface::Style)style); + + } + +#endif + + ~FontFaceRec_Typeface() {}; + + + + TCHAR* GetFontName() { return fFace.lfFaceName; } + + + + SkTypeface::Style GetFontStyle() { + + int style = SkTypeface::kNormal; + + if (fFace.lfWeight == FW_SEMIBOLD || fFace.lfWeight == FW_DEMIBOLD || fFace.lfWeight == FW_BOLD) + + style |= SkTypeface::kBold; + + if (fFace.lfItalic) + + style |= SkTypeface::kItalic; + + + + return (SkTypeface::Style)style; + + } + + + + long GetFontSize() { return fFace.lfHeight; } + + + + LOGFONT fFace; + +}; + + + + + +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 + + + + NONCLIENTMETRICS ncm; + + ncm.cbSize = sizeof(NONCLIENTMETRICS); + + SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0); + + + + memcpy(&gDefaultFont, &(ncm.lfMessageFont), sizeof(LOGFONT)); + + + + return &gDefaultFont; + +} + + + +static uint32_t FontFaceChecksum(const LOGFONT& face) + +{ + + uint32_t cs = 0; + + uint32_t bytesize = sizeof(LOGFONT); + + bytesize >>= 2; + + uint32_t *p32 = (uint32_t*)&face; + + + + while (bytesize) { + + bytesize --; + + cs ^= *p32; + + p32 ++; + + } + + + + return cs; + +} + + + +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); + + 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); + + + +private: + + LOGFONT* plf; + + MAT2 mat22; + +}; + + + +SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc) + + : SkScalerContext(desc), plf(NULL) + +{ + + SkAutoMutexAcquire ac(gFTMutex); + + + + const LOGFONT** face = (const LOGFONT**)desc->findEntry(kTypeface_SkDescriptorTag, NULL); + + plf = (LOGFONT*)*face; + + SkASSERT(plf); + + + + mat22.eM11 = SkFixedToFIXED(fRec.fPost2x2[0][0]); + + mat22.eM12 = SkFixedToFIXED(-fRec.fPost2x2[0][1]); + + mat22.eM21 = SkFixedToFIXED(fRec.fPost2x2[1][0]); + + mat22.eM22 = SkFixedToFIXED(-fRec.fPost2x2[1][1]); + +} + + + +SkScalerContext_Windows::~SkScalerContext_Windows() { + +} + + + +unsigned SkScalerContext_Windows::generateGlyphCount() const { + + return 0xFFFF; + +// return fFace->num_glyphs; + +} + + + +uint16_t SkScalerContext_Windows::generateCharToGlyph(SkUnichar uni) { + + + + // let's just use the uni as index on Windows + + return SkToU16(uni); + +} + + + +void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) { + + + + HDC ddc = ::CreateCompatibleDC(NULL); + + SetBkMode(ddc, TRANSPARENT); + + + + SkASSERT(plf); + + plf->lfHeight = -SkFixedFloor(fRec.fTextSize); + + + + HFONT font = CreateFontIndirect(plf); + + HFONT oldfont = (HFONT)SelectObject(ddc, font); + + + + GLYPHMETRICS gm; + + memset(&gm, 0, sizeof(gm)); + + + + glyph->fRsbDelta = 0; + + glyph->fLsbDelta = 0; + + + + // 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->f_GlyphID, GGO_GRAY8_BITMAP, &gm, 0, NULL, &mat22); + + + + if (GDI_ERROR != ret) { + + if (ret == 0) { + + // for white space, ret is zero and gmBlackBoxX, gmBlackBoxY are 1 incorrectly! + + gm.gmBlackBoxX = gm.gmBlackBoxY = 0; + + } + + glyph->fWidth = gm.gmBlackBoxX; + + glyph->fHeight = gm.gmBlackBoxY; + + glyph->fTop = gm.gmptGlyphOrigin.y - gm.gmBlackBoxY; + + glyph->fLeft = gm.gmptGlyphOrigin.x; + + glyph->fAdvanceX = SkIntToFixed(gm.gmCellIncX); + + glyph->fAdvanceY = -SkIntToFixed(gm.gmCellIncY); + + } + + + + ::SelectObject(ddc, oldfont); + + ::DeleteObject(font); + + ::DeleteDC(ddc); + +} + + + +void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) { + + + + SkAutoMutexAcquire ac(gFTMutex); + + + + SkASSERT(plf); + + + + HDC ddc = ::CreateCompatibleDC(NULL); + + SetBkMode(ddc, TRANSPARENT); + + + + plf->lfHeight = -SkFixedFloor(fRec.fTextSize); + + + + HFONT font = CreateFontIndirect(plf); + + HFONT oldfont = (HFONT)SelectObject(ddc, font); + + + + GLYPHMETRICS gm; + + memset(&gm, 0, sizeof(gm)); + + + + uint32_t total_size = GetGlyphOutlineW(ddc, glyph.f_GlyphID, GGO_GRAY8_BITMAP, &gm, 0, NULL, &mat22); + + if (GDI_ERROR != total_size && total_size > 0) { + + uint8_t *pBuff = new uint8_t[total_size]; + + if (NULL != pBuff) { + + total_size = GetGlyphOutlineW(ddc, glyph.f_GlyphID, GGO_GRAY8_BITMAP, &gm, total_size, pBuff, &mat22); + + + + SkASSERT(total_size != GDI_ERROR); + + + + uint8_t* dst = (uint8_t*)glyph.fImage; + + uint32_t pitch = (gm.gmBlackBoxX + 3) & ~0x3; + + + + 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; + + } + + else { + + *dst = *src << 2; // scale to 0-255 + + } + + dst++; + + src++; + + } + + } + + + + delete[] pBuff; + + } + + } + + + + SkASSERT(GDI_ERROR != total_size && total_size >= 0); + + + + ::SelectObject(ddc, oldfont); + + ::DeleteObject(font); + + ::DeleteDC(ddc); + +} + + + +void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) { + + + + SkAutoMutexAcquire ac(gFTMutex); + + + + SkASSERT(&glyph && path); + + + + SkASSERT(plf); + + + + path->reset(); + + + + HDC ddc = ::CreateCompatibleDC(NULL); + + SetBkMode(ddc, TRANSPARENT); + + + + plf->lfHeight = -SkFixedFloor(fRec.fTextSize); + + + + HFONT font = CreateFontIndirect(plf); + + HFONT oldfont = (HFONT)SelectObject(ddc, font); + + + + GLYPHMETRICS gm; + + + + uint32_t total_size = GetGlyphOutlineW(ddc, glyph.f_GlyphID, GGO_NATIVE, &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(*(SkFixed*)(&th->pfxStart.x), *(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(*(SkFixed*)(&pc->apfx[i].x), *(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 + + 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(*(SkFixed*)(&pnt_b.x), *(SkFixed*)(&pnt_b.y), *(SkFixed*)(&pnt_c.x), *(SkFixed*)(&pnt_c.y)); + + } + + } + + cur_poly += sizeof(uint16_t) * 2 + sizeof(POINTFX) * pc->cpfx; + + } + + cur_glyph += th->cb; + + } + + } + + else { + + SkASSERT(false); + + } + + + + path->close(); + + + + ::SelectObject(ddc, oldfont); + + ::DeleteObject(font); + + ::DeleteDC(ddc); + +} + + + + + +// Note: not sure this is the correct implementation + +void SkScalerContext_Windows::generateLineHeight(SkPoint* ascent, SkPoint* descent) { + + + + HDC ddc = ::CreateCompatibleDC(NULL); + + SetBkMode(ddc, TRANSPARENT); + + + + SkASSERT(plf); + + plf->lfHeight = -SkFixedFloor(fRec.fTextSize); + + + + HFONT font = CreateFontIndirect(plf); + + HFONT oldfont = (HFONT)SelectObject(ddc, font); + + + + 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); + + } + + + + ::SelectObject(ddc, oldfont); + + ::DeleteObject(font); + + ::DeleteDC(ddc); + + + + return; + +} + + + +SkTypeface* SkFontHost::CreateTypeface( const SkTypeface* familyFace, const char familyName[], SkTypeface::Style style) { + + + + FontFaceRec_Typeface* ptypeface = new FontFaceRec_Typeface; + + + + if (NULL == ptypeface) { + + SkASSERT(false); + + return NULL; + + } + + + + memset(&ptypeface->fFace, 0, sizeof(LOGFONT)); + + + + // default + + ptypeface->fFace.lfHeight = -11; // default + + ptypeface->fFace.lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL ; + + ptypeface->fFace.lfItalic = ((style & SkTypeface::kItalic) != 0); + + ptypeface->fFace.lfQuality = PROOF_QUALITY; + + + + _tcscpy(ptypeface->fFace.lfFaceName, familyName); + + + + + + return ptypeface; + +} + + + +uint32_t SkFontHost::FlattenTypeface(const SkTypeface* tface, void* buffer) { + + const LOGFONT* face; + + + + if (tface) + + face = &((const FontFaceRec_Typeface*)tface)->fFace; + + else + + face = get_default_font(); + + + + size_t size = sizeof(face); + + + + size += sizeof(uint32_t); + + + + if (buffer) { + + uint8_t* buf = (uint8_t*)buffer; + + memcpy(buf, &face, sizeof(face)); + + uint32_t cs = FontFaceChecksum(*face); + + + + memcpy(buf+sizeof(face), &cs, sizeof(cs)); + + } + + + + return size; + +} + + + +SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) { + + return SkNEW_ARGS(SkScalerContext_Windows, (desc)); + +} + + + +void SkFontHost::GetDescriptorKeyString(const SkDescriptor* desc, SkString* keyString) { + + const LOGFONT** face = (const LOGFONT**)desc->findEntry(kTypeface_SkDescriptorTag, NULL); + + LOGFONT*lf = (LOGFONT*)*face; + + keyString->set(SK_FONTKEY); + + if (lf) { + + keyString->append(lf->lfFaceName); + + } + +} + + + +SkScalerContext* SkFontHost::CreateFallbackScalerContext(const SkScalerContext::Rec& rec) { + + const LOGFONT* face = get_default_font(); + + + + SkAutoDescriptor ad(sizeof(rec) + sizeof(face) + SkDescriptor::ComputeOverhead(2)); + + SkDescriptor* desc = ad.getDesc(); + + + + desc->init(); + + desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); + + desc->addEntry(kTypeface_SkDescriptorTag, sizeof(face), &face); + + desc->computeChecksum(); + + + + return SkFontHost::CreateScalerContext(desc); + +} + + + +SkStream* SkFontHost::OpenDescriptorStream(const SkDescriptor* desc, const char keyString[]) { + + SkASSERT(!"SkFontHost::OpenDescriptorStream unimplemented"); + + return NULL; + +} + + + +uint32_t SkFontHost::TypefaceHash(const SkTypeface* face) { + + + +// FontFaceRec_Typeface *ptypeface = dynamic_cast<FontFaceRec_Typeface*>(face); + + FontFaceRec_Typeface *ptypeface = (FontFaceRec_Typeface*)(face); + + SkASSERT(ptypeface); + + + + return FontFaceChecksum(ptypeface->fFace); + +} + + + +bool SkFontHost::TypefaceEqual(const SkTypeface* facea, const SkTypeface* faceb) { + + + + FontFaceRec_Typeface *ptypefaceA = (FontFaceRec_Typeface*)facea; + + SkASSERT(ptypefaceA); + + + + FontFaceRec_Typeface *ptypefaceB = (FontFaceRec_Typeface*)faceb; + + SkASSERT(ptypefaceB); + + + + if (_tcscmp(ptypefaceA->GetFontName(), ptypefaceB->GetFontName())) return false; + + if (ptypefaceA->GetFontStyle() != ptypefaceB->GetFontStyle()) return false; + + if (ptypefaceA->GetFontSize() != ptypefaceB->GetFontSize()) return false; + + + + return true; + +} + + + +int SkFontHost::ComputeGammaFlag(const SkPaint& paint) + +{ + + return 0; + +} + + + +void SkFontHost::GetGammaTables(const uint8_t* tables[2]) + +{ + + tables[0] = NULL; // black gamma (e.g. exp=1.4) + + tables[1] = NULL; // white gamma (e.g. exp= 1/1.4) + +} + + + +#endif // WIN32 + + + |