summaryrefslogtreecommitdiffstats
path: root/skia/ports/SkFontHost_win.cpp
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-27 00:09:42 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-27 00:09:42 +0000
commitae2c20f398933a9e86c387dcc465ec0f71065ffc (patch)
treede668b1411e2ee0b4e49b6d8f8b68183134ac990 /skia/ports/SkFontHost_win.cpp
parent09911bf300f1a419907a9412154760efd0b7abc3 (diff)
downloadchromium_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.cpp908
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
+
+
+