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