blob: c71f49064c9be9eba3b72c890aa9b3458aa56cd9 [file] [log] [blame]
reed@google.comac6b9792011-03-11 15:42:51 +00001/*
2 ** Copyright 2006, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17#include "SkString.h"
18//#include "SkStream.h"
19
20#include "SkEndian.h"
21#include "SkFontHost.h"
22#include "SkDescriptor.h"
23#include "SkAdvancedTypefaceMetrics.h"
24#include "SkStream.h"
25#include "SkThread.h"
26#include "SkTypeface_win.h"
reed@google.com59d2f632011-05-02 19:36:59 +000027#include "SkTypefaceCache.h"
reed@google.comac6b9792011-03-11 15:42:51 +000028#include "SkUtils.h"
29
30#ifdef WIN32
31#include "windows.h"
32#include "tchar.h"
33#include "Usp10.h"
34
35// client3d has to undefine this for now
36#define CAN_USE_LOGFONT_NAME
37
38using namespace skia_advanced_typeface_metrics_utils;
39
reed@google.comac6b9792011-03-11 15:42:51 +000040static const uint16_t BUFFERSIZE = (16384 - 32);
41static uint8_t glyphbuf[BUFFERSIZE];
42
43// Give 1MB font cache budget
44#define FONT_CACHE_MEMORY_BUDGET (1024 * 1024)
45
46/**
47 * Since LOGFONT wants its textsize as an int, and we support fractional sizes,
48 * and since we have a cache of LOGFONTs for our tyepfaces, we always set the
49 * lfHeight to a canonical size, and then we use the 2x2 matrix to achieve the
50 * actual requested size.
51 */
52static const int gCanonicalTextSize = 64;
53
54static void make_canonical(LOGFONT* lf) {
55 lf->lfHeight = -gCanonicalTextSize;
reed@google.com59d2f632011-05-02 19:36:59 +000056 lf->lfQuality = CLEARTYPE_QUALITY;//PROOF_QUALITY;
57 lf->lfCharSet = DEFAULT_CHARSET;
58}
59
60static SkTypeface::Style getStyle(const LOGFONT& lf) {
61 unsigned style = 0;
62 if (lf.lfWeight >= FW_BOLD) {
63 style |= SkTypeface::kBold;
64 }
65 if (lf.lfItalic) {
66 style |= SkTypeface::kItalic;
67 }
68 return (SkTypeface::Style)style;
69}
70
71static void setStyle(LOGFONT* lf, SkTypeface::Style style) {
72 lf->lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL ;
73 lf->lfItalic = ((style & SkTypeface::kItalic) != 0);
reed@google.comac6b9792011-03-11 15:42:51 +000074}
75
76static inline FIXED SkFixedToFIXED(SkFixed x) {
77 return *(FIXED*)(&x);
78}
79
80static inline FIXED SkScalarToFIXED(SkScalar x) {
81 return SkFixedToFIXED(SkScalarToFixed(x));
82}
83
84static unsigned calculateGlyphCount(HDC hdc) {
85 // The 'maxp' table stores the number of glyphs at offset 4, in 2 bytes.
86 const DWORD maxpTag = *(DWORD*) "maxp";
87 uint16_t glyphs;
88 if (GetFontData(hdc, maxpTag, 4, &glyphs, sizeof(glyphs)) != GDI_ERROR) {
89 return SkEndian_SwapBE16(glyphs);
90 }
91
92 // Binary search for glyph count.
93 static const MAT2 mat2 = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
94 int32_t max = SK_MaxU16 + 1;
95 int32_t min = 0;
96 GLYPHMETRICS gm;
97 while (min < max) {
98 int32_t mid = min + ((max - min) / 2);
99 if (GetGlyphOutlineW(hdc, mid, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0,
100 NULL, &mat2) == GDI_ERROR) {
101 max = mid;
102 } else {
103 min = mid + 1;
104 }
105 }
106 SkASSERT(min == max);
107 return min;
108}
109
110static SkTypeface::Style GetFontStyle(const LOGFONT& lf) {
111 int style = SkTypeface::kNormal;
112 if (lf.lfWeight == FW_SEMIBOLD || lf.lfWeight == FW_DEMIBOLD || lf.lfWeight == FW_BOLD)
113 style |= SkTypeface::kBold;
114 if (lf.lfItalic)
115 style |= SkTypeface::kItalic;
116
117 return (SkTypeface::Style)style;
118}
119
reed@google.comac6b9792011-03-11 15:42:51 +0000120class LogFontTypeface : public SkTypeface {
reed@google.comac6b9792011-03-11 15:42:51 +0000121public:
reed@google.com59d2f632011-05-02 19:36:59 +0000122 LogFontTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf) :
123 SkTypeface(style, fontID, false), fLogFont(lf) {}
reed@google.comac6b9792011-03-11 15:42:51 +0000124
reed@google.com59d2f632011-05-02 19:36:59 +0000125 LOGFONT fLogFont;
reed@google.comac6b9792011-03-11 15:42:51 +0000126
reed@google.com59d2f632011-05-02 19:36:59 +0000127 static LogFontTypeface* Create(const LOGFONT& lf) {
128 SkTypeface::Style style = GetFontStyle(lf);
129 SkFontID fontID = SkTypefaceCache::NewFontID();
130 return new LogFontTypeface(style, fontID, lf);
reed@google.comac6b9792011-03-11 15:42:51 +0000131 }
132};
133
reed@google.comac6b9792011-03-11 15:42:51 +0000134static const LOGFONT& get_default_font() {
135 static LOGFONT gDefaultFont;
136 // don't hardcode on Windows, Win2000, XP, Vista, and international all have different default
137 // and the user could change too
138
139
140// lfMessageFont is garbage on my XP, so skip for now
141#if 0
142 if (gDefaultFont.lfFaceName[0] != 0) {
143 return gDefaultFont;
144 }
145
146 NONCLIENTMETRICS ncm;
147 ncm.cbSize = sizeof(NONCLIENTMETRICS);
148 SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
149
150 //memcpy(&gDefaultFont, &(ncm.lfMessageFont), sizeof(LOGFONT));
151#endif
152
153 return gDefaultFont;
154}
155
reed@google.com59d2f632011-05-02 19:36:59 +0000156static bool FindByLogFont(SkTypeface* face, SkTypeface::Style requestedStyle, void* ctx) {
157 LogFontTypeface* lface = reinterpret_cast<LogFontTypeface*>(face);
158 const LOGFONT* lf = reinterpret_cast<const LOGFONT*>(ctx);
reed@google.comac6b9792011-03-11 15:42:51 +0000159
reed@google.com59d2f632011-05-02 19:36:59 +0000160 return getStyle(lface->fLogFont) == requestedStyle &&
161 !memcmp(&lface->fLogFont, lf, sizeof(LOGFONT));
162}
163
164/**
165 * This guy is public. It first searches the cache, and if a match is not found,
166 * it creates a new face.
167 */
168SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT& origLF) {
169 LOGFONT lf = origLF;
170 make_canonical(&lf);
171 SkTypeface* face = SkTypefaceCache::FindByProc(FindByLogFont, &lf);
172 if (face) {
173 face->ref();
reed@google.comac6b9792011-03-11 15:42:51 +0000174 } else {
reed@google.com59d2f632011-05-02 19:36:59 +0000175 face = LogFontTypeface::Create(lf);
176 SkTypefaceCache::Add(face, getStyle(lf));
177 }
178 return face;
reed@google.comac6b9792011-03-11 15:42:51 +0000179}
180
181uint32_t SkFontHost::NextLogicalFont(uint32_t fontID) {
182 // Zero means that we don't have any fallback fonts for this fontID.
183 // This function is implemented on Android, but doesn't have much
184 // meaning here.
185 return 0;
186}
187
reed@google.com59d2f632011-05-02 19:36:59 +0000188static void GetLogFontByID(SkFontID fontID, LOGFONT* lf) {
189 LogFontTypeface* face = (LogFontTypeface*)SkTypefaceCache::FindByID(fontID);
190 if (face) {
191 *lf = face->fLogFont;
192 } else {
193 sk_bzero(lf, sizeof(LOGFONT));
194 }
195}
196
197//////////////////////////////////////////////////////////////////////////////////////////////
198
reed@google.comac6b9792011-03-11 15:42:51 +0000199class SkScalerContext_Windows : public SkScalerContext {
200public:
201 SkScalerContext_Windows(const SkDescriptor* desc);
202 virtual ~SkScalerContext_Windows();
203
204protected:
205 virtual unsigned generateGlyphCount();
206 virtual uint16_t generateCharToGlyph(SkUnichar uni);
207 virtual void generateAdvance(SkGlyph* glyph);
208 virtual void generateMetrics(SkGlyph* glyph);
209 virtual void generateImage(const SkGlyph& glyph);
210 virtual void generatePath(const SkGlyph& glyph, SkPath* path);
211 virtual void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY);
212 //virtual SkDeviceContext getDC() {return ddc;}
213private:
214 SkScalar fScale; // to get from canonical size to real size
215 MAT2 fMat22;
216 XFORM fXform;
217 HDC fDDC;
218 HFONT fSavefont;
219 HFONT fFont;
220 SCRIPT_CACHE fSC;
221 int fGlyphCount;
222};
223
224static float mul2float(SkScalar a, SkScalar b) {
225 return SkScalarToFloat(SkScalarMul(a, b));
226}
227
228static FIXED float2FIXED(float x) {
229 return SkFixedToFIXED(SkFloatToFixed(x));
230}
231
reed@google.com59d2f632011-05-02 19:36:59 +0000232static SkMutex gFTMutex;
233
reed@google.comac6b9792011-03-11 15:42:51 +0000234SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc)
235 : SkScalerContext(desc), fDDC(0), fFont(0), fSavefont(0), fSC(0)
236 , fGlyphCount(-1) {
237 SkAutoMutexAcquire ac(gFTMutex);
238
239 fScale = fRec.fTextSize / gCanonicalTextSize;
240
241 fXform.eM11 = mul2float(fScale, fRec.fPost2x2[0][0]);
242 fXform.eM12 = mul2float(fScale, fRec.fPost2x2[1][0]);
243 fXform.eM21 = mul2float(fScale, fRec.fPost2x2[0][1]);
244 fXform.eM22 = mul2float(fScale, fRec.fPost2x2[1][1]);
245 fXform.eDx = 0;
246 fXform.eDy = 0;
247
248 fMat22.eM11 = float2FIXED(fXform.eM11);
249 fMat22.eM12 = float2FIXED(fXform.eM12);
250 fMat22.eM21 = float2FIXED(-fXform.eM21);
251 fMat22.eM22 = float2FIXED(-fXform.eM22);
252
253 fDDC = ::CreateCompatibleDC(NULL);
254 SetBkMode(fDDC, TRANSPARENT);
255
256 // Scaling by the DPI is inconsistent with how Skia draws elsewhere
257 //SkScalar height = -(fRec.fTextSize * GetDeviceCaps(ddc, LOGPIXELSY) / 72);
reed@google.com59d2f632011-05-02 19:36:59 +0000258 LOGFONT lf;
259 GetLogFontByID(fRec.fFontID, &lf);
reed@google.comac6b9792011-03-11 15:42:51 +0000260 lf.lfHeight = -gCanonicalTextSize;
261 fFont = CreateFontIndirect(&lf);
262 fSavefont = (HFONT)SelectObject(fDDC, fFont);
263}
264
265SkScalerContext_Windows::~SkScalerContext_Windows() {
266 if (fDDC) {
267 ::SelectObject(fDDC, fSavefont);
268 ::DeleteDC(fDDC);
269 }
270 if (fFont) {
271 ::DeleteObject(fFont);
272 }
273 if (fSC) {
274 ::ScriptFreeCache(&fSC);
275 }
276}
277
278unsigned SkScalerContext_Windows::generateGlyphCount() {
279 if (fGlyphCount < 0) {
280 fGlyphCount = calculateGlyphCount(fDDC);
281 }
282 return fGlyphCount;
283}
284
285uint16_t SkScalerContext_Windows::generateCharToGlyph(SkUnichar uni) {
286 uint16_t index = 0;
287 WCHAR c[2];
288 // TODO(ctguil): Support characters that generate more than one glyph.
289 if (SkUTF16_FromUnichar(uni, (uint16_t*)c) == 1) {
290 // Type1 fonts fail with uniscribe API. Use GetGlyphIndices for plane 0.
291 SkAssertResult(GetGlyphIndicesW(fDDC, c, 1, &index, 0));
292 } else {
293 // Use uniscribe to detemine glyph index for non-BMP characters.
294 // Need to add extra item to SCRIPT_ITEM to work around a bug in older
295 // windows versions. https://bugzilla.mozilla.org/show_bug.cgi?id=366643
296 SCRIPT_ITEM si[2 + 1];
297 int items;
298 SkAssertResult(
299 SUCCEEDED(ScriptItemize(c, 2, 2, NULL, NULL, si, &items)));
300
301 WORD log[2];
302 SCRIPT_VISATTR vsa;
303 int glyphs;
304 SkAssertResult(SUCCEEDED(ScriptShape(
305 fDDC, &fSC, c, 2, 1, &si[0].a, &index, log, &vsa, &glyphs)));
306 }
307 return index;
308}
309
310void SkScalerContext_Windows::generateAdvance(SkGlyph* glyph) {
311 this->generateMetrics(glyph);
312}
313
314void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) {
315
316 SkASSERT(fDDC);
317
318 GLYPHMETRICS gm;
319 memset(&gm, 0, sizeof(gm));
320
321 glyph->fRsbDelta = 0;
322 glyph->fLsbDelta = 0;
323
324 // Note: need to use GGO_GRAY8_BITMAP instead of GGO_METRICS because GGO_METRICS returns a smaller
325 // BlackBlox; we need the bigger one in case we need the image. fAdvance is the same.
326 uint32_t ret = GetGlyphOutlineW(fDDC, glyph->getGlyphID(0), GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
327
328 if (GDI_ERROR != ret) {
329 if (ret == 0) {
330 // for white space, ret is zero and gmBlackBoxX, gmBlackBoxY are 1 incorrectly!
331 gm.gmBlackBoxX = gm.gmBlackBoxY = 0;
332 }
333 glyph->fWidth = gm.gmBlackBoxX;
334 glyph->fHeight = gm.gmBlackBoxY;
335 glyph->fTop = SkToS16(gm.gmptGlyphOrigin.y - gm.gmBlackBoxY);
336 glyph->fLeft = SkToS16(gm.gmptGlyphOrigin.x);
337 glyph->fAdvanceX = SkIntToFixed(gm.gmCellIncX);
338 glyph->fAdvanceY = -SkIntToFixed(gm.gmCellIncY);
339
340 // we outset by 1 in all dimensions, since the lcd image may bleed outside
341 // of the computed bounds returned by GetGlyphOutline.
342 // This was deduced by trial and error for small text (e.g. 8pt), so there
343 // maybe a more precise way to make this adjustment...
344 if (SkMask::kLCD16_Format == fRec.fMaskFormat) {
345 glyph->fWidth += 2;
346 glyph->fHeight += 2;
347 glyph->fTop -= 1;
348 glyph->fLeft -= 1;
349 }
350 } else {
351 glyph->fWidth = 0;
352 }
353}
354
355void SkScalerContext_Windows::generateFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my) {
356// Note: This code was borrowed from generateLineHeight, which has a note
357// stating that it may be incorrect.
358 if (!(mx || my))
359 return;
360
361 SkASSERT(fDDC);
362
363 OUTLINETEXTMETRIC otm;
364
365 uint32_t ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
366 if (sizeof(otm) != ret) {
367 return;
368 }
369
370 if (mx) {
371 mx->fTop = -fScale * otm.otmTextMetrics.tmAscent;
372 mx->fAscent = -fScale * otm.otmAscent;
373 mx->fDescent = -fScale * otm.otmDescent;
374 mx->fBottom = fScale * otm.otmTextMetrics.tmDescent;
375 mx->fLeading = fScale * (otm.otmTextMetrics.tmInternalLeading
376 + otm.otmTextMetrics.tmExternalLeading);
377 }
378
379 if (my) {
380 my->fTop = -fScale * otm.otmTextMetrics.tmAscent;
381 my->fAscent = -fScale * otm.otmAscent;
382 my->fDescent = -fScale * otm.otmDescent;
383 my->fBottom = fScale * otm.otmTextMetrics.tmDescent;
384 my->fLeading = fScale * (otm.otmTextMetrics.tmInternalLeading
385 + otm.otmTextMetrics.tmExternalLeading);
386 }
387}
388
389#include "SkColorPriv.h"
390
391static inline uint16_t rgb_to_lcd16(uint32_t rgb) {
392 int r = (rgb >> 16) & 0xFF;
393 int g = (rgb >> 8) & 0xFF;
394 int b = (rgb >> 0) & 0xFF;
395
396 // invert, since we draw black-on-white, but we want the original
397 // src mask values.
398 r = 255 - r;
399 g = 255 - g;
400 b = 255 - b;
401 return SkPackRGB16(SkR32ToR16(r), SkG32ToG16(g), SkB32ToB16(b));
402}
403
404void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) {
405
406 SkAutoMutexAcquire ac(gFTMutex);
407
408 SkASSERT(fDDC);
409
410 if (SkMask::kLCD16_Format == fRec.fMaskFormat) {
411 HDC dc = CreateCompatibleDC(0);
412 void* bits = 0;
413 BITMAPINFO info;
414 sk_bzero(&info, sizeof(info));
415 info.bmiHeader.biSize = sizeof(info.bmiHeader);
416 info.bmiHeader.biWidth = glyph.fWidth;
417 info.bmiHeader.biHeight = glyph.fHeight;
418 info.bmiHeader.biPlanes = 1;
419 info.bmiHeader.biBitCount = 32;
420 info.bmiHeader.biCompression = BI_RGB;
421 HBITMAP bm = CreateDIBSection(dc, &info, DIB_RGB_COLORS, &bits, 0, 0);
422 SelectObject(dc, bm);
423
424 // erase to white
425 size_t srcRB = glyph.fWidth << 2;
426 size_t size = glyph.fHeight * srcRB;
427 memset(bits, 0xFF, size);
428
429 SetBkMode(dc, TRANSPARENT);
430 SetTextAlign(dc, TA_LEFT | TA_BASELINE);
431 SetGraphicsMode(dc, GM_ADVANCED);
432
433 XFORM xform = fXform;
434 xform.eDx = (float)-glyph.fLeft;
435 xform.eDy = (float)-glyph.fTop;
436 SetWorldTransform(dc, &xform);
437
438 HGDIOBJ prevFont = SelectObject(dc, fFont);
439 COLORREF color = SetTextColor(dc, 0); // black
440 SkASSERT(color != CLR_INVALID);
441 uint16_t glyphID = glyph.getGlyphID();
bsalomon@google.comc8ad63e2011-03-18 14:29:44 +0000442#if defined(UNICODE)
reed@google.comac6b9792011-03-11 15:42:51 +0000443 ExtTextOut(dc, 0, 0, ETO_GLYPH_INDEX, NULL, (LPCWSTR)&glyphID, 1, NULL);
bsalomon@google.comc8ad63e2011-03-18 14:29:44 +0000444#else
445 ExtTextOut(dc, 0, 0, ETO_GLYPH_INDEX, NULL, (LPCSTR)&glyphID, 1, NULL);
446#endif
reed@google.comac6b9792011-03-11 15:42:51 +0000447 GdiFlush();
448
449 // downsample from rgba to rgb565
450 int width = glyph.fWidth;
451 size_t dstRB = glyph.rowBytes();
452 const uint32_t* src = (const uint32_t*)bits;
453 // gdi's bitmap is upside-down, so we reverse dst walking in Y
454 uint16_t* dst = (uint16_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
455 for (int y = 0; y < glyph.fHeight; y++) {
456 for (int i = 0; i < width; i++) {
457 dst[i] = rgb_to_lcd16(src[i]);
458 }
459 src = (const uint32_t*)((const char*)src + srcRB);
460 dst = (uint16_t*)((char*)dst - dstRB);
461 }
462
463 DeleteDC(dc);
464 DeleteObject(bm);
465 return;
466 }
467
468 GLYPHMETRICS gm;
469 memset(&gm, 0, sizeof(gm));
470 uint32_t bytecount = 0;
471 uint32_t total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
472 if (GDI_ERROR != total_size && total_size > 0) {
473 uint8_t *pBuff = new uint8_t[total_size];
474 if (NULL != pBuff) {
475 total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX, &gm, total_size, pBuff, &fMat22);
476
477 SkASSERT(total_size != GDI_ERROR);
478
479 SkASSERT(glyph.fWidth == gm.gmBlackBoxX);
480 SkASSERT(glyph.fHeight == gm.gmBlackBoxY);
481
482 uint8_t* dst = (uint8_t*)glyph.fImage;
483 uint32_t pitch = (gm.gmBlackBoxX + 3) & ~0x3;
484 if (pitch != glyph.rowBytes()) {
485 SkASSERT(false); // glyph.fImage has different rowsize!?
486 }
487
488 for (int32_t y = gm.gmBlackBoxY - 1; y >= 0; y--) {
489 uint8_t* src = pBuff + pitch * y;
490
491 for (uint32_t x = 0; x < gm.gmBlackBoxX; x++) {
492 if (*src > 63) {
493 *dst = 0xFF;
494 }
495 else {
496 *dst = *src << 2; // scale to 0-255
497 }
498 dst++;
499 src++;
500 bytecount++;
501 }
502 memset(dst, 0, glyph.rowBytes() - glyph.fWidth);
503 dst += glyph.rowBytes() - glyph.fWidth;
504 }
505
506 delete[] pBuff;
507 }
508 }
509
510 SkASSERT(GDI_ERROR != total_size && total_size >= 0);
511
512}
513
514void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) {
515
516 SkAutoMutexAcquire ac(gFTMutex);
517
518 SkASSERT(&glyph && path);
519 SkASSERT(fDDC);
520
521 path->reset();
522
523#if 0
524 char buf[1024];
525 sprintf(buf, "generatePath: id:%d, w=%d, h=%d, font:%s,fh:%d\n", glyph.fID, glyph.fWidth, glyph.fHeight, lf.lfFaceName, lf.lfHeight);
526 OutputDebugString(buf);
527#endif
528
529 GLYPHMETRICS gm;
530 uint32_t total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, BUFFERSIZE, glyphbuf, &fMat22);
531
532 if (GDI_ERROR != total_size) {
533
534 const uint8_t* cur_glyph = glyphbuf;
535 const uint8_t* end_glyph = glyphbuf + total_size;
536
537 while(cur_glyph < end_glyph) {
538 const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
539
540 const uint8_t* end_poly = cur_glyph + th->cb;
541 const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
542
543 path->moveTo(SkFixedToScalar(*(SkFixed*)(&th->pfxStart.x)), SkFixedToScalar(*(SkFixed*)(&th->pfxStart.y)));
544
545 while(cur_poly < end_poly) {
546 const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
547
548 if (pc->wType == TT_PRIM_LINE) {
549 for (uint16_t i = 0; i < pc->cpfx; i++) {
550 path->lineTo(SkFixedToScalar(*(SkFixed*)(&pc->apfx[i].x)), SkFixedToScalar(*(SkFixed*)(&pc->apfx[i].y)));
551 }
552 }
553
554 if (pc->wType == TT_PRIM_QSPLINE) {
555 for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline
556 POINTFX pnt_b = pc->apfx[u]; // B is always the current point
557 POINTFX pnt_c = pc->apfx[u+1];
558
559 if (u < pc->cpfx - 2) { // If not on last spline, compute C
560 pnt_c.x = SkFixedToFIXED(SkFixedAve(*(SkFixed*)(&pnt_b.x), *(SkFixed*)(&pnt_c.x)));
561 pnt_c.y = SkFixedToFIXED(SkFixedAve(*(SkFixed*)(&pnt_b.y), *(SkFixed*)(&pnt_c.y)));
562 }
563
564 path->quadTo(SkFixedToScalar(*(SkFixed*)(&pnt_b.x)), SkFixedToScalar(*(SkFixed*)(&pnt_b.y)), SkFixedToScalar(*(SkFixed*)(&pnt_c.x)), SkFixedToScalar(*(SkFixed*)(&pnt_c.y)));
565 }
566 }
567 cur_poly += sizeof(uint16_t) * 2 + sizeof(POINTFX) * pc->cpfx;
568 }
569 cur_glyph += th->cb;
570 path->close();
571 }
572 }
573 else {
574 SkASSERT(false);
575 }
576 //char buf[1024];
577 //sprintf(buf, "generatePath: count:%d\n", count);
578 //OutputDebugString(buf);
579}
580
581void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
582 SkASSERT(!"SkFontHost::Serialize unimplemented");
583}
584
585SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
586 SkASSERT(!"SkFontHost::Deserialize unimplemented");
587 return NULL;
588}
589
590static bool getWidthAdvance(HDC hdc, int gId, int16_t* advance) {
591 // Initialize the MAT2 structure to the identify transformation matrix.
592 static const MAT2 mat2 = {SkScalarToFIXED(1), SkScalarToFIXED(0),
593 SkScalarToFIXED(0), SkScalarToFIXED(1)};
594 int flags = GGO_METRICS | GGO_GLYPH_INDEX;
595 GLYPHMETRICS gm;
596 if (GDI_ERROR == GetGlyphOutline(hdc, gId, flags, &gm, 0, NULL, &mat2)) {
597 return false;
598 }
599 SkASSERT(advance);
600 *advance = gm.gmCellIncX;
601 return true;
602}
603
604// static
605SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
vandebo@chromium.org325cb9a2011-03-30 18:36:29 +0000606 uint32_t fontID,
607 SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo) {
reed@google.com59d2f632011-05-02 19:36:59 +0000608 LOGFONT lf;
609 GetLogFontByID(fontID, &lf);
reed@google.comac6b9792011-03-11 15:42:51 +0000610 SkAdvancedTypefaceMetrics* info = NULL;
611
612 HDC hdc = CreateCompatibleDC(NULL);
613 HFONT font = CreateFontIndirect(&lf);
614 HFONT savefont = (HFONT)SelectObject(hdc, font);
615 HFONT designFont = NULL;
616
617 // To request design units, create a logical font whose height is specified
618 // as unitsPerEm.
619 OUTLINETEXTMETRIC otm;
620 if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm) ||
621 !GetTextFace(hdc, LF_FACESIZE, lf.lfFaceName)) {
622 goto Error;
623 }
624 lf.lfHeight = -SkToS32(otm.otmEMSquare);
625 designFont = CreateFontIndirect(&lf);
626 SelectObject(hdc, designFont);
627 if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm)) {
628 goto Error;
629 }
630 const unsigned glyphCount = calculateGlyphCount(hdc);
631
632 info = new SkAdvancedTypefaceMetrics;
633 info->fEmSize = otm.otmEMSquare;
634 info->fMultiMaster = false;
635 info->fLastGlyphID = SkToU16(glyphCount - 1);
636 info->fStyle = 0;
637#ifdef UNICODE
638 // Get the buffer size needed first.
639 size_t str_len = WideCharToMultiByte(CP_UTF8, 0, lf.lfFaceName, -1, NULL,
640 0, NULL, NULL);
641 // Allocate a buffer (str_len already has terminating null accounted for).
642 char *familyName = new char[str_len];
643 // Now actually convert the string.
644 WideCharToMultiByte(CP_UTF8, 0, lf.lfFaceName, -1, familyName, str_len,
645 NULL, NULL);
646 info->fFontName.set(familyName);
647 delete [] familyName;
648#else
649 info->fFontName.set(lf.lfFaceName);
650#endif
651
652 if (otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE) {
653 info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
654 } else {
655 info->fType = SkAdvancedTypefaceMetrics::kOther_Font;
656 info->fItalicAngle = 0;
657 info->fAscent = 0;
658 info->fDescent = 0;
659 info->fStemV = 0;
660 info->fCapHeight = 0;
661 info->fBBox = SkIRect::MakeEmpty();
662 return info;
663 }
664
665 // If this bit is clear the font is a fixed pitch font.
666 if (!(otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
667 info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
668 }
669 if (otm.otmTextMetrics.tmItalic) {
670 info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
671 }
672 // Setting symbolic style by default for now.
673 info->fStyle |= SkAdvancedTypefaceMetrics::kSymbolic_Style;
674 if (otm.otmTextMetrics.tmPitchAndFamily & FF_ROMAN) {
675 info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
676 } else if (otm.otmTextMetrics.tmPitchAndFamily & FF_SCRIPT) {
677 info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
678 }
679
680 // The main italic angle of the font, in tenths of a degree counterclockwise
681 // from vertical.
682 info->fItalicAngle = otm.otmItalicAngle / 10;
683 info->fAscent = SkToS16(otm.otmTextMetrics.tmAscent);
684 info->fDescent = SkToS16(-otm.otmTextMetrics.tmDescent);
685 // TODO(ctguil): Use alternate cap height calculation.
686 // MSDN says otmsCapEmHeight is not support but it is returning a value on
687 // my Win7 box.
688 info->fCapHeight = otm.otmsCapEmHeight;
689 info->fBBox =
690 SkIRect::MakeLTRB(otm.otmrcFontBox.left, otm.otmrcFontBox.top,
691 otm.otmrcFontBox.right, otm.otmrcFontBox.bottom);
692
693 // Figure out a good guess for StemV - Min width of i, I, !, 1.
694 // This probably isn't very good with an italic font.
695 int16_t min_width = SHRT_MAX;
696 info->fStemV = 0;
697 char stem_chars[] = {'i', 'I', '!', '1'};
698 for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) {
699 ABC abcWidths;
700 if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) {
701 int16_t width = abcWidths.abcB;
702 if (width > 0 && width < min_width) {
703 min_width = width;
704 info->fStemV = min_width;
705 }
706 }
707 }
708
709 // If bit 1 is set, the font may not be embedded in a document.
710 // If bit 1 is clear, the font can be embedded.
711 // If bit 2 is set, the embedding is read-only.
712 if (otm.otmfsType & 0x1) {
713 info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
ctguil@chromium.org0e6dc0a2011-03-30 20:41:16 +0000714 } else if (perGlyphInfo &
715 SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) {
reed@google.comac6b9792011-03-11 15:42:51 +0000716 info->fGlyphWidths.reset(
717 getAdvanceData(hdc, glyphCount, &getWidthAdvance));
718 }
719
720Error:
721 SelectObject(hdc, savefont);
722 DeleteObject(designFont);
723 DeleteObject(font);
724 DeleteDC(hdc);
725
726 return info;
727}
728
729SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
730
731 //Should not be used on Windows, keep linker happy
732 SkASSERT(false);
733 return SkCreateTypefaceFromLOGFONT(get_default_font());
734}
735
736SkStream* SkFontHost::OpenStream(SkFontID uniqueID) {
reed@google.com59d2f632011-05-02 19:36:59 +0000737 LOGFONT lf;
738 GetLogFontByID(uniqueID, &lf);
reed@google.comac6b9792011-03-11 15:42:51 +0000739
740 HDC hdc = ::CreateCompatibleDC(NULL);
reed@google.com59d2f632011-05-02 19:36:59 +0000741 HFONT font = CreateFontIndirect(&lf);
reed@google.comac6b9792011-03-11 15:42:51 +0000742 HFONT savefont = (HFONT)SelectObject(hdc, font);
743
744 size_t bufferSize = GetFontData(hdc, 0, 0, NULL, 0);
745 SkMemoryStream* stream = new SkMemoryStream(bufferSize);
746 if (!GetFontData(hdc, 0, 0, (void*)stream->getMemoryBase(), bufferSize)) {
747 delete stream;
748 stream = NULL;
749 }
750
751 SelectObject(hdc, savefont);
752 DeleteObject(font);
753 DeleteDC(hdc);
754
755 return stream;
756}
757
758SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) {
759 return SkNEW_ARGS(SkScalerContext_Windows, (desc));
760}
761
762/** Return the closest matching typeface given either an existing family
763 (specified by a typeface in that family) or by a familyName, and a
764 requested style.
765 1) If familyFace is null, use famillyName.
766 2) If famillyName is null, use familyFace.
767 3) If both are null, return the default font that best matches style
768 This MUST not return NULL.
769 */
770
771SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
772 const char familyName[],
773 const void* data, size_t bytelength,
774 SkTypeface::Style style) {
reed@google.com59d2f632011-05-02 19:36:59 +0000775 LOGFONT lf;
reed@google.comac6b9792011-03-11 15:42:51 +0000776 if (NULL == familyFace && NULL == familyName) {
reed@google.com59d2f632011-05-02 19:36:59 +0000777 lf = get_default_font();
778 } else if (familyFace) {
779 LogFontTypeface* face = (LogFontTypeface*)familyFace;
780 lf = face->fLogFont;
reed@google.comac6b9792011-03-11 15:42:51 +0000781 } else {
reed@google.com59d2f632011-05-02 19:36:59 +0000782 memset(&lf, 0, sizeof(LOGFONT));
reed@google.comac6b9792011-03-11 15:42:51 +0000783#ifdef UNICODE
reed@google.com59d2f632011-05-02 19:36:59 +0000784 // Get the buffer size needed first.
785 size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName,
786 -1, NULL, 0);
787 // Allocate a buffer (str_len already has terminating null
788 // accounted for).
789 wchar_t *wideFamilyName = new wchar_t[str_len];
790 // Now actually convert the string.
791 ::MultiByteToWideChar(CP_UTF8, 0, familyName, -1,
792 wideFamilyName, str_len);
793 ::wcsncpy(lf.lfFaceName, wideFamilyName, LF_FACESIZE);
794 delete [] wideFamilyName;
reed@google.comac6b9792011-03-11 15:42:51 +0000795#else
reed@google.com59d2f632011-05-02 19:36:59 +0000796 ::strncpy(lf.lfFaceName, familyName, LF_FACESIZE);
reed@google.comac6b9792011-03-11 15:42:51 +0000797#endif
reed@google.com59d2f632011-05-02 19:36:59 +0000798 lf.lfFaceName[LF_FACESIZE-1] = '\0';
reed@google.comac6b9792011-03-11 15:42:51 +0000799 }
reed@google.com59d2f632011-05-02 19:36:59 +0000800 setStyle(&lf, style);
801 return SkCreateTypefaceFromLOGFONT(lf);
reed@google.comac6b9792011-03-11 15:42:51 +0000802}
803
804size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) {
805 if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET)
806 return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET;
807 else
808 return 0; // nothing to do
809}
810
811int SkFontHost::ComputeGammaFlag(const SkPaint& paint) {
812 return 0;
813}
814
815void SkFontHost::GetGammaTables(const uint8_t* tables[2]) {
816 tables[0] = NULL; // black gamma (e.g. exp=1.4)
817 tables[1] = NULL; // white gamma (e.g. exp= 1/1.4)
818}
819
820SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
821 printf("SkFontHost::CreateTypefaceFromFile unimplemented");
822 return NULL;
823}
824
825void SkFontHost::FilterRec(SkScalerContext::Rec* rec) {
826 // We don't control the hinting nor ClearType settings here
827 rec->setHinting(SkPaint::kNormal_Hinting);
828
829 // we do support LCD16
830 if (SkMask::kLCD16_Format == rec->fMaskFormat) {
831 return;
832 }
833
834 if (SkMask::FormatIsLCD((SkMask::Format)rec->fMaskFormat)) {
835 rec->fMaskFormat = SkMask::kA8_Format;
836 }
837}
838
839#endif // WIN32