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