1
2 /*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9 #include "SkAdvancedTypefaceMetrics.h"
10 #include "SkBase64.h"
11 #include "SkColorPriv.h"
12 #include "SkData.h"
13 #include "SkDescriptor.h"
14 #include "SkFontDescriptor.h"
15 #include "SkFontHost.h"
16 #include "SkGlyph.h"
17 #include "SkHRESULT.h"
18 #include "SkMaskGamma.h"
19 #include "SkMatrix22.h"
20 #include "SkOTTable_maxp.h"
21 #include "SkOTTable_name.h"
22 #include "SkOTUtils.h"
23 #include "SkPath.h"
24 #include "SkSFNTHeader.h"
25 #include "SkStream.h"
26 #include "SkString.h"
27 #include "SkTemplates.h"
28 #include "SkThread.h"
29 #include "SkTypeface_win.h"
30 #include "SkTypefaceCache.h"
31 #include "SkUtils.h"
32
33 #include "SkTypes.h"
34 #include <tchar.h>
35 #include <usp10.h>
36 #include <objbase.h>
37
38 static void (*gEnsureLOGFONTAccessibleProc)(const LOGFONT&);
39
SkTypeface_SetEnsureLOGFONTAccessibleProc(void (* proc)(const LOGFONT &))40 void SkTypeface_SetEnsureLOGFONTAccessibleProc(void (*proc)(const LOGFONT&)) {
41 gEnsureLOGFONTAccessibleProc = proc;
42 }
43
call_ensure_accessible(const LOGFONT & lf)44 static void call_ensure_accessible(const LOGFONT& lf) {
45 if (gEnsureLOGFONTAccessibleProc) {
46 gEnsureLOGFONTAccessibleProc(lf);
47 }
48 }
49
50 ///////////////////////////////////////////////////////////////////////////////
51
52 // always packed xxRRGGBB
53 typedef uint32_t SkGdiRGB;
54
55 // define this in your Makefile or .gyp to enforce AA requests
56 // which GDI ignores at small sizes. This flag guarantees AA
57 // for rotated text, regardless of GDI's notions.
58 //#define SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
59
isLCD(const SkScalerContext::Rec & rec)60 static bool isLCD(const SkScalerContext::Rec& rec) {
61 return SkMask::kLCD16_Format == rec.fMaskFormat ||
62 SkMask::kLCD32_Format == rec.fMaskFormat;
63 }
64
bothZero(SkScalar a,SkScalar b)65 static bool bothZero(SkScalar a, SkScalar b) {
66 return 0 == a && 0 == b;
67 }
68
69 // returns false if there is any non-90-rotation or skew
isAxisAligned(const SkScalerContext::Rec & rec)70 static bool isAxisAligned(const SkScalerContext::Rec& rec) {
71 return 0 == rec.fPreSkewX &&
72 (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
73 bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
74 }
75
needToRenderWithSkia(const SkScalerContext::Rec & rec)76 static bool needToRenderWithSkia(const SkScalerContext::Rec& rec) {
77 #ifdef SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
78 // What we really want to catch is when GDI will ignore the AA request and give
79 // us BW instead. Smallish rotated text is one heuristic, so this code is just
80 // an approximation. We shouldn't need to do this for larger sizes, but at those
81 // sizes, the quality difference gets less and less between our general
82 // scanconverter and GDI's.
83 if (SkMask::kA8_Format == rec.fMaskFormat && !isAxisAligned(rec)) {
84 return true;
85 }
86 #endif
87 return rec.getHinting() == SkPaint::kNo_Hinting || rec.getHinting() == SkPaint::kSlight_Hinting;
88 }
89
90 using namespace skia_advanced_typeface_metrics_utils;
91
tchar_to_skstring(const TCHAR t[],SkString * s)92 static void tchar_to_skstring(const TCHAR t[], SkString* s) {
93 #ifdef UNICODE
94 size_t sSize = WideCharToMultiByte(CP_UTF8, 0, t, -1, NULL, 0, NULL, NULL);
95 s->resize(sSize);
96 WideCharToMultiByte(CP_UTF8, 0, t, -1, s->writable_str(), sSize, NULL, NULL);
97 #else
98 s->set(t);
99 #endif
100 }
101
dcfontname_to_skstring(HDC deviceContext,const LOGFONT & lf,SkString * familyName)102 static void dcfontname_to_skstring(HDC deviceContext, const LOGFONT& lf, SkString* familyName) {
103 int fontNameLen; //length of fontName in TCHARS.
104 if (0 == (fontNameLen = GetTextFace(deviceContext, 0, NULL))) {
105 call_ensure_accessible(lf);
106 if (0 == (fontNameLen = GetTextFace(deviceContext, 0, NULL))) {
107 fontNameLen = 0;
108 }
109 }
110
111 SkAutoSTArray<LF_FULLFACESIZE, TCHAR> fontName(fontNameLen+1);
112 if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) {
113 call_ensure_accessible(lf);
114 if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) {
115 fontName[0] = 0;
116 }
117 }
118
119 tchar_to_skstring(fontName.get(), familyName);
120 }
121
make_canonical(LOGFONT * lf)122 static void make_canonical(LOGFONT* lf) {
123 lf->lfHeight = -64;
124 lf->lfQuality = CLEARTYPE_QUALITY;//PROOF_QUALITY;
125 lf->lfCharSet = DEFAULT_CHARSET;
126 // lf->lfClipPrecision = 64;
127 }
128
get_style(const LOGFONT & lf)129 static SkTypeface::Style get_style(const LOGFONT& lf) {
130 unsigned style = 0;
131 if (lf.lfWeight >= FW_BOLD) {
132 style |= SkTypeface::kBold;
133 }
134 if (lf.lfItalic) {
135 style |= SkTypeface::kItalic;
136 }
137 return static_cast<SkTypeface::Style>(style);
138 }
139
setStyle(LOGFONT * lf,SkTypeface::Style style)140 static void setStyle(LOGFONT* lf, SkTypeface::Style style) {
141 lf->lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL ;
142 lf->lfItalic = ((style & SkTypeface::kItalic) != 0);
143 }
144
SkFixedToFIXED(SkFixed x)145 static inline FIXED SkFixedToFIXED(SkFixed x) {
146 return *(FIXED*)(&x);
147 }
SkFIXEDToFixed(FIXED x)148 static inline SkFixed SkFIXEDToFixed(FIXED x) {
149 return *(SkFixed*)(&x);
150 }
151
SkScalarToFIXED(SkScalar x)152 static inline FIXED SkScalarToFIXED(SkScalar x) {
153 return SkFixedToFIXED(SkScalarToFixed(x));
154 }
155
SkFIXEDToScalar(FIXED x)156 static inline SkScalar SkFIXEDToScalar(FIXED x) {
157 return SkFixedToScalar(SkFIXEDToFixed(x));
158 }
159
calculateGlyphCount(HDC hdc,const LOGFONT & lf)160 static unsigned calculateGlyphCount(HDC hdc, const LOGFONT& lf) {
161 TEXTMETRIC textMetric;
162 if (0 == GetTextMetrics(hdc, &textMetric)) {
163 textMetric.tmPitchAndFamily = TMPF_VECTOR;
164 call_ensure_accessible(lf);
165 GetTextMetrics(hdc, &textMetric);
166 }
167
168 if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) {
169 return textMetric.tmLastChar;
170 }
171
172 // The 'maxp' table stores the number of glyphs at offset 4, in 2 bytes.
173 uint16_t glyphs;
174 if (GDI_ERROR != GetFontData(hdc, SkOTTableMaximumProfile::TAG, 4, &glyphs, sizeof(glyphs))) {
175 return SkEndian_SwapBE16(glyphs);
176 }
177
178 // Binary search for glyph count.
179 static const MAT2 mat2 = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
180 int32_t max = SK_MaxU16 + 1;
181 int32_t min = 0;
182 GLYPHMETRICS gm;
183 while (min < max) {
184 int32_t mid = min + ((max - min) / 2);
185 if (GetGlyphOutlineW(hdc, mid, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0,
186 NULL, &mat2) == GDI_ERROR) {
187 max = mid;
188 } else {
189 min = mid + 1;
190 }
191 }
192 SkASSERT(min == max);
193 return min;
194 }
195
calculateUPEM(HDC hdc,const LOGFONT & lf)196 static unsigned calculateUPEM(HDC hdc, const LOGFONT& lf) {
197 TEXTMETRIC textMetric;
198 if (0 == GetTextMetrics(hdc, &textMetric)) {
199 textMetric.tmPitchAndFamily = TMPF_VECTOR;
200 call_ensure_accessible(lf);
201 GetTextMetrics(hdc, &textMetric);
202 }
203
204 if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) {
205 return textMetric.tmMaxCharWidth;
206 }
207
208 OUTLINETEXTMETRIC otm;
209 unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
210 if (0 == otmRet) {
211 call_ensure_accessible(lf);
212 otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
213 }
214
215 return (0 == otmRet) ? 0 : otm.otmEMSquare;
216 }
217
218 class LogFontTypeface : public SkTypeface {
219 public:
LogFontTypeface(SkTypeface::Style style,SkFontID fontID,const LOGFONT & lf,bool serializeAsStream=false)220 LogFontTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf, bool serializeAsStream = false) :
221 SkTypeface(style, fontID, false), fLogFont(lf), fSerializeAsStream(serializeAsStream) {
222
223 // If the font has cubic outlines, it will not be rendered with ClearType.
224 HFONT font = CreateFontIndirect(&lf);
225
226 HDC deviceContext = ::CreateCompatibleDC(NULL);
227 HFONT savefont = (HFONT)SelectObject(deviceContext, font);
228
229 TEXTMETRIC textMetric;
230 if (0 == GetTextMetrics(deviceContext, &textMetric)) {
231 call_ensure_accessible(lf);
232 if (0 == GetTextMetrics(deviceContext, &textMetric)) {
233 textMetric.tmPitchAndFamily = TMPF_TRUETYPE;
234 }
235 }
236 if (deviceContext) {
237 ::SelectObject(deviceContext, savefont);
238 ::DeleteDC(deviceContext);
239 }
240 if (font) {
241 ::DeleteObject(font);
242 }
243
244 // The fixed pitch bit is set if the font is *not* fixed pitch.
245 this->setIsFixedPitch((textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0);
246
247 // Used a logfont on a memory context, should never get a device font.
248 // Therefore all TMPF_DEVICE will be PostScript (cubic) fonts.
249 fCanBeLCD = !((textMetric.tmPitchAndFamily & TMPF_VECTOR) &&
250 (textMetric.tmPitchAndFamily & TMPF_DEVICE));
251 }
252
253 LOGFONT fLogFont;
254 bool fSerializeAsStream;
255 bool fCanBeLCD;
256
Create(const LOGFONT & lf)257 static LogFontTypeface* Create(const LOGFONT& lf) {
258 SkTypeface::Style style = get_style(lf);
259 SkFontID fontID = SkTypefaceCache::NewFontID();
260 return new LogFontTypeface(style, fontID, lf);
261 }
262
EnsureAccessible(const SkTypeface * face)263 static void EnsureAccessible(const SkTypeface* face) {
264 call_ensure_accessible(static_cast<const LogFontTypeface*>(face)->fLogFont);
265 }
266
267 protected:
268 virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE;
269 virtual SkScalerContext* onCreateScalerContext(const SkDescriptor*) const SK_OVERRIDE;
270 virtual void onFilterRec(SkScalerContextRec*) const SK_OVERRIDE;
271 virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics(
272 SkAdvancedTypefaceMetrics::PerGlyphInfo,
273 const uint32_t*, uint32_t) const SK_OVERRIDE;
274 virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE;
275 virtual int onCharsToGlyphs(const void* chars, Encoding encoding,
276 uint16_t glyphs[], int glyphCount) const SK_OVERRIDE;
277 virtual int onCountGlyphs() const SK_OVERRIDE;
278 virtual int onGetUPEM() const SK_OVERRIDE;
279 virtual SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const SK_OVERRIDE;
280 virtual int onGetTableTags(SkFontTableTag tags[]) const SK_OVERRIDE;
281 virtual size_t onGetTableData(SkFontTableTag, size_t offset,
282 size_t length, void* data) const SK_OVERRIDE;
283 };
284
285 class FontMemResourceTypeface : public LogFontTypeface {
286 public:
287 /**
288 * The created FontMemResourceTypeface takes ownership of fontMemResource.
289 */
Create(const LOGFONT & lf,HANDLE fontMemResource)290 static FontMemResourceTypeface* Create(const LOGFONT& lf, HANDLE fontMemResource) {
291 SkTypeface::Style style = get_style(lf);
292 SkFontID fontID = SkTypefaceCache::NewFontID();
293 return new FontMemResourceTypeface(style, fontID, lf, fontMemResource);
294 }
295
296 protected:
weak_dispose() const297 virtual void weak_dispose() const SK_OVERRIDE {
298 RemoveFontMemResourceEx(fFontMemResource);
299 //SkTypefaceCache::Remove(this);
300 INHERITED::weak_dispose();
301 }
302
303 private:
304 /**
305 * Takes ownership of fontMemResource.
306 */
FontMemResourceTypeface(SkTypeface::Style style,SkFontID fontID,const LOGFONT & lf,HANDLE fontMemResource)307 FontMemResourceTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf, HANDLE fontMemResource) :
308 LogFontTypeface(style, fontID, lf, true), fFontMemResource(fontMemResource) {
309 }
310
311 HANDLE fFontMemResource;
312
313 typedef LogFontTypeface INHERITED;
314 };
315
get_default_font()316 static const LOGFONT& get_default_font() {
317 static LOGFONT gDefaultFont;
318 return gDefaultFont;
319 }
320
FindByLogFont(SkTypeface * face,SkTypeface::Style requestedStyle,void * ctx)321 static bool FindByLogFont(SkTypeface* face, SkTypeface::Style requestedStyle, void* ctx) {
322 LogFontTypeface* lface = static_cast<LogFontTypeface*>(face);
323 const LOGFONT* lf = reinterpret_cast<const LOGFONT*>(ctx);
324
325 return lface &&
326 get_style(lface->fLogFont) == requestedStyle &&
327 !memcmp(&lface->fLogFont, lf, sizeof(LOGFONT));
328 }
329
330 /**
331 * This guy is public. It first searches the cache, and if a match is not found,
332 * it creates a new face.
333 */
SkCreateTypefaceFromLOGFONT(const LOGFONT & origLF)334 SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT& origLF) {
335 LOGFONT lf = origLF;
336 make_canonical(&lf);
337 SkTypeface* face = SkTypefaceCache::FindByProcAndRef(FindByLogFont, &lf);
338 if (NULL == face) {
339 face = LogFontTypeface::Create(lf);
340 SkTypefaceCache::Add(face, get_style(lf));
341 }
342 return face;
343 }
344
345 /**
346 * The created SkTypeface takes ownership of fontMemResource.
347 */
SkCreateFontMemResourceTypefaceFromLOGFONT(const LOGFONT & origLF,HANDLE fontMemResource)348 SkTypeface* SkCreateFontMemResourceTypefaceFromLOGFONT(const LOGFONT& origLF, HANDLE fontMemResource) {
349 LOGFONT lf = origLF;
350 make_canonical(&lf);
351 FontMemResourceTypeface* face = FontMemResourceTypeface::Create(lf, fontMemResource);
352 SkTypefaceCache::Add(face, get_style(lf), false);
353 return face;
354 }
355
356 /**
357 * This guy is public
358 */
SkLOGFONTFromTypeface(const SkTypeface * face,LOGFONT * lf)359 void SkLOGFONTFromTypeface(const SkTypeface* face, LOGFONT* lf) {
360 if (NULL == face) {
361 *lf = get_default_font();
362 } else {
363 *lf = static_cast<const LogFontTypeface*>(face)->fLogFont;
364 }
365 }
366
367 // Construct Glyph to Unicode table.
368 // Unicode code points that require conjugate pairs in utf16 are not
369 // supported.
370 // TODO(arthurhsu): Add support for conjugate pairs. It looks like that may
371 // require parsing the TTF cmap table (platform 4, encoding 12) directly instead
372 // of calling GetFontUnicodeRange().
populate_glyph_to_unicode(HDC fontHdc,const unsigned glyphCount,SkTDArray<SkUnichar> * glyphToUnicode)373 static void populate_glyph_to_unicode(HDC fontHdc, const unsigned glyphCount,
374 SkTDArray<SkUnichar>* glyphToUnicode) {
375 DWORD glyphSetBufferSize = GetFontUnicodeRanges(fontHdc, NULL);
376 if (!glyphSetBufferSize) {
377 return;
378 }
379
380 SkAutoTDeleteArray<BYTE> glyphSetBuffer(new BYTE[glyphSetBufferSize]);
381 GLYPHSET* glyphSet =
382 reinterpret_cast<LPGLYPHSET>(glyphSetBuffer.get());
383 if (GetFontUnicodeRanges(fontHdc, glyphSet) != glyphSetBufferSize) {
384 return;
385 }
386
387 glyphToUnicode->setCount(glyphCount);
388 memset(glyphToUnicode->begin(), 0, glyphCount * sizeof(SkUnichar));
389 for (DWORD i = 0; i < glyphSet->cRanges; ++i) {
390 // There is no guarantee that within a Unicode range, the corresponding
391 // glyph id in a font file are continuous. So, even if we have ranges,
392 // we can't just use the first and last entry of the range to compute
393 // result. We need to enumerate them one by one.
394 int count = glyphSet->ranges[i].cGlyphs;
395 SkAutoTArray<WCHAR> chars(count + 1);
396 chars[count] = 0; // termintate string
397 SkAutoTArray<WORD> glyph(count);
398 for (USHORT j = 0; j < count; ++j) {
399 chars[j] = glyphSet->ranges[i].wcLow + j;
400 }
401 GetGlyphIndicesW(fontHdc, chars.get(), count, glyph.get(),
402 GGI_MARK_NONEXISTING_GLYPHS);
403 // If the glyph ID is valid, and the glyph is not mapped, then we will
404 // fill in the char id into the vector. If the glyph is mapped already,
405 // skip it.
406 // TODO(arthurhsu): better improve this. e.g. Get all used char ids from
407 // font cache, then generate this mapping table from there. It's
408 // unlikely to have collisions since glyph reuse happens mostly for
409 // different Unicode pages.
410 for (USHORT j = 0; j < count; ++j) {
411 if (glyph[j] != 0xffff && glyph[j] < glyphCount &&
412 (*glyphToUnicode)[glyph[j]] == 0) {
413 (*glyphToUnicode)[glyph[j]] = chars[j];
414 }
415 }
416 }
417 }
418
419 //////////////////////////////////////////////////////////////////////////////////////
420
alignTo32(int n)421 static int alignTo32(int n) {
422 return (n + 31) & ~31;
423 }
424
425 struct MyBitmapInfo : public BITMAPINFO {
426 RGBQUAD fMoreSpaceForColors[1];
427 };
428
429 class HDCOffscreen {
430 public:
HDCOffscreen()431 HDCOffscreen() {
432 fFont = 0;
433 fDC = 0;
434 fBM = 0;
435 fBits = NULL;
436 fWidth = fHeight = 0;
437 fIsBW = false;
438 }
439
~HDCOffscreen()440 ~HDCOffscreen() {
441 if (fDC) {
442 DeleteDC(fDC);
443 }
444 if (fBM) {
445 DeleteObject(fBM);
446 }
447 }
448
init(HFONT font,const XFORM & xform)449 void init(HFONT font, const XFORM& xform) {
450 fFont = font;
451 fXform = xform;
452 }
453
454 const void* draw(const SkGlyph&, bool isBW, size_t* srcRBPtr);
455
456 private:
457 HDC fDC;
458 HBITMAP fBM;
459 HFONT fFont;
460 XFORM fXform;
461 void* fBits; // points into fBM
462 int fWidth;
463 int fHeight;
464 bool fIsBW;
465 };
466
draw(const SkGlyph & glyph,bool isBW,size_t * srcRBPtr)467 const void* HDCOffscreen::draw(const SkGlyph& glyph, bool isBW,
468 size_t* srcRBPtr) {
469 // Can we share the scalercontext's fDDC, so we don't need to create
470 // a separate fDC here?
471 if (0 == fDC) {
472 fDC = CreateCompatibleDC(0);
473 if (0 == fDC) {
474 return NULL;
475 }
476 SetGraphicsMode(fDC, GM_ADVANCED);
477 SetBkMode(fDC, TRANSPARENT);
478 SetTextAlign(fDC, TA_LEFT | TA_BASELINE);
479 SelectObject(fDC, fFont);
480
481 COLORREF color = 0x00FFFFFF;
482 SkDEBUGCODE(COLORREF prev =) SetTextColor(fDC, color);
483 SkASSERT(prev != CLR_INVALID);
484 }
485
486 if (fBM && (fIsBW != isBW || fWidth < glyph.fWidth || fHeight < glyph.fHeight)) {
487 DeleteObject(fBM);
488 fBM = 0;
489 }
490 fIsBW = isBW;
491
492 fWidth = SkMax32(fWidth, glyph.fWidth);
493 fHeight = SkMax32(fHeight, glyph.fHeight);
494
495 int biWidth = isBW ? alignTo32(fWidth) : fWidth;
496
497 if (0 == fBM) {
498 MyBitmapInfo info;
499 sk_bzero(&info, sizeof(info));
500 if (isBW) {
501 RGBQUAD blackQuad = { 0, 0, 0, 0 };
502 RGBQUAD whiteQuad = { 0xFF, 0xFF, 0xFF, 0 };
503 info.bmiColors[0] = blackQuad;
504 info.bmiColors[1] = whiteQuad;
505 }
506 info.bmiHeader.biSize = sizeof(info.bmiHeader);
507 info.bmiHeader.biWidth = biWidth;
508 info.bmiHeader.biHeight = fHeight;
509 info.bmiHeader.biPlanes = 1;
510 info.bmiHeader.biBitCount = isBW ? 1 : 32;
511 info.bmiHeader.biCompression = BI_RGB;
512 if (isBW) {
513 info.bmiHeader.biClrUsed = 2;
514 }
515 fBM = CreateDIBSection(fDC, &info, DIB_RGB_COLORS, &fBits, 0, 0);
516 if (0 == fBM) {
517 return NULL;
518 }
519 SelectObject(fDC, fBM);
520 }
521
522 // erase
523 size_t srcRB = isBW ? (biWidth >> 3) : (fWidth << 2);
524 size_t size = fHeight * srcRB;
525 memset(fBits, 0, size);
526
527 XFORM xform = fXform;
528 xform.eDx = (float)-glyph.fLeft;
529 xform.eDy = (float)-glyph.fTop;
530 SetWorldTransform(fDC, &xform);
531
532 uint16_t glyphID = glyph.getGlyphID();
533 BOOL ret = ExtTextOutW(fDC, 0, 0, ETO_GLYPH_INDEX, NULL, reinterpret_cast<LPCWSTR>(&glyphID), 1, NULL);
534 GdiFlush();
535 if (0 == ret) {
536 return NULL;
537 }
538 *srcRBPtr = srcRB;
539 // offset to the start of the image
540 return (const char*)fBits + (fHeight - glyph.fHeight) * srcRB;
541 }
542
543 //////////////////////////////////////////////////////////////////////////////
544 #define BUFFERSIZE (1 << 13)
545
546 class SkScalerContext_GDI : public SkScalerContext {
547 public:
548 SkScalerContext_GDI(SkTypeface*, const SkDescriptor* desc);
549 virtual ~SkScalerContext_GDI();
550
551 // Returns true if the constructor was able to complete all of its
552 // initializations (which may include calling GDI).
553 bool isValid() const;
554
555 protected:
556 virtual unsigned generateGlyphCount() SK_OVERRIDE;
557 virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE;
558 virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE;
559 virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE;
560 virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE;
561 virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE;
562 virtual void generateFontMetrics(SkPaint::FontMetrics* mX,
563 SkPaint::FontMetrics* mY) SK_OVERRIDE;
564
565 private:
566 DWORD getGDIGlyphPath(const SkGlyph& glyph, UINT flags,
567 SkAutoSTMalloc<BUFFERSIZE, uint8_t>* glyphbuf);
568
569 HDCOffscreen fOffscreen;
570 /** fGsA is the non-rotational part of total matrix without the text height scale.
571 * Used to find the magnitude of advances.
572 */
573 MAT2 fGsA;
574 /** The total matrix without the textSize. */
575 MAT2 fMat22;
576 /** Scales font to EM size. */
577 MAT2 fHighResMat22;
578 HDC fDDC;
579 HFONT fSavefont;
580 HFONT fFont;
581 SCRIPT_CACHE fSC;
582 int fGlyphCount;
583
584 /** The total matrix which also removes EM scale. */
585 SkMatrix fHiResMatrix;
586 /** fG_inv is the inverse of the rotational part of the total matrix.
587 * Used to set the direction of advances.
588 */
589 SkMatrix fG_inv;
590 enum Type {
591 kTrueType_Type, kBitmap_Type, kLine_Type
592 } fType;
593 TEXTMETRIC fTM;
594 };
595
float2FIXED(float x)596 static FIXED float2FIXED(float x) {
597 return SkFixedToFIXED(SkFloatToFixed(x));
598 }
599
compute_quality(const SkScalerContext::Rec & rec)600 static BYTE compute_quality(const SkScalerContext::Rec& rec) {
601 switch (rec.fMaskFormat) {
602 case SkMask::kBW_Format:
603 return NONANTIALIASED_QUALITY;
604 case SkMask::kLCD16_Format:
605 case SkMask::kLCD32_Format:
606 return CLEARTYPE_QUALITY;
607 default:
608 if (rec.fFlags & SkScalerContext::kGenA8FromLCD_Flag) {
609 return CLEARTYPE_QUALITY;
610 } else {
611 return ANTIALIASED_QUALITY;
612 }
613 }
614 }
615
SkScalerContext_GDI(SkTypeface * rawTypeface,const SkDescriptor * desc)616 SkScalerContext_GDI::SkScalerContext_GDI(SkTypeface* rawTypeface,
617 const SkDescriptor* desc)
618 : SkScalerContext(rawTypeface, desc)
619 , fDDC(0)
620 , fSavefont(0)
621 , fFont(0)
622 , fSC(0)
623 , fGlyphCount(-1)
624 {
625 LogFontTypeface* typeface = reinterpret_cast<LogFontTypeface*>(rawTypeface);
626
627 fDDC = ::CreateCompatibleDC(NULL);
628 if (!fDDC) {
629 return;
630 }
631 SetGraphicsMode(fDDC, GM_ADVANCED);
632 SetBkMode(fDDC, TRANSPARENT);
633
634 SkPoint h = SkPoint::Make(SK_Scalar1, 0);
635 // A is the total matrix.
636 SkMatrix A;
637 fRec.getSingleMatrix(&A);
638 A.mapPoints(&h, 1);
639
640 // G is the Givens Matrix for A (rotational matrix where GA[0][1] == 0).
641 SkMatrix G;
642 SkComputeGivensRotation(h, &G);
643
644 // GA is the matrix A with rotation removed.
645 SkMatrix GA(G);
646 GA.preConcat(A);
647
648 // realTextSize is the actual device size we want (as opposed to the size the user requested).
649 // gdiTextSize is the size we request from GDI.
650 // If the scale is negative, this means the matrix will do the flip anyway.
651 SkScalar realTextSize = SkScalarAbs(GA.get(SkMatrix::kMScaleY));
652 SkScalar gdiTextSize = SkScalarRoundToScalar(realTextSize);
653 if (gdiTextSize == 0) {
654 gdiTextSize = SK_Scalar1;
655 }
656
657 // When not hinting, remove only the gdiTextSize scale which will be applied by GDI.
658 // When GDI hinting, remove the entire Y scale to prevent 'subpixel' metrics.
659 SkScalar scale = (fRec.getHinting() == SkPaint::kNo_Hinting ||
660 fRec.getHinting() == SkPaint::kSlight_Hinting)
661 ? SkScalarInvert(gdiTextSize)
662 : SkScalarInvert(realTextSize);
663
664 // sA is the total matrix A without the textSize (so GDI knows the text size separately).
665 // When this matrix is used with GetGlyphOutline, no further processing is needed.
666 SkMatrix sA(A);
667 sA.preScale(scale, scale); //remove text size
668
669 // GsA is the non-rotational part of A without the text height scale.
670 // This is what is used to find the magnitude of advances.
671 SkMatrix GsA(GA);
672 GsA.preScale(scale, scale); //remove text size, G is rotational so reorders with the scale.
673
674 fGsA.eM11 = SkScalarToFIXED(GsA.get(SkMatrix::kMScaleX));
675 fGsA.eM12 = SkScalarToFIXED(-GsA.get(SkMatrix::kMSkewY)); // This should be ~0.
676 fGsA.eM21 = SkScalarToFIXED(-GsA.get(SkMatrix::kMSkewX));
677 fGsA.eM22 = SkScalarToFIXED(GsA.get(SkMatrix::kMScaleY));
678
679 // fG_inv is G inverse, which is fairly simple since G is 2x2 rotational.
680 fG_inv.setAll(G.get(SkMatrix::kMScaleX), -G.get(SkMatrix::kMSkewX), G.get(SkMatrix::kMTransX),
681 -G.get(SkMatrix::kMSkewY), G.get(SkMatrix::kMScaleY), G.get(SkMatrix::kMTransY),
682 G.get(SkMatrix::kMPersp0), G.get(SkMatrix::kMPersp1), G.get(SkMatrix::kMPersp2));
683
684 LOGFONT lf = typeface->fLogFont;
685 lf.lfHeight = -SkScalarTruncToInt(gdiTextSize);
686 lf.lfQuality = compute_quality(fRec);
687 fFont = CreateFontIndirect(&lf);
688 if (!fFont) {
689 return;
690 }
691
692 fSavefont = (HFONT)SelectObject(fDDC, fFont);
693
694 if (0 == GetTextMetrics(fDDC, &fTM)) {
695 call_ensure_accessible(lf);
696 if (0 == GetTextMetrics(fDDC, &fTM)) {
697 fTM.tmPitchAndFamily = TMPF_TRUETYPE;
698 }
699 }
700
701 XFORM xform;
702 if (fTM.tmPitchAndFamily & TMPF_VECTOR) {
703 // Used a logfont on a memory context, should never get a device font.
704 // Therefore all TMPF_DEVICE will be PostScript fonts.
705
706 // If TMPF_VECTOR is set, one of TMPF_TRUETYPE or TMPF_DEVICE means that
707 // we have an outline font. Otherwise we have a vector FON, which is
708 // scalable, but not an outline font.
709 // This was determined by testing with Type1 PFM/PFB and
710 // OpenTypeCFF OTF, as well as looking at Wine bugs and sources.
711 if (fTM.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_DEVICE)) {
712 // Truetype or PostScript.
713 fType = SkScalerContext_GDI::kTrueType_Type;
714 } else {
715 // Stroked FON.
716 fType = SkScalerContext_GDI::kLine_Type;
717 }
718
719 // fPost2x2 is column-major, left handed (y down).
720 // XFORM 2x2 is row-major, left handed (y down).
721 xform.eM11 = SkScalarToFloat(sA.get(SkMatrix::kMScaleX));
722 xform.eM12 = SkScalarToFloat(sA.get(SkMatrix::kMSkewY));
723 xform.eM21 = SkScalarToFloat(sA.get(SkMatrix::kMSkewX));
724 xform.eM22 = SkScalarToFloat(sA.get(SkMatrix::kMScaleY));
725 xform.eDx = 0;
726 xform.eDy = 0;
727
728 // MAT2 is row major, right handed (y up).
729 fMat22.eM11 = float2FIXED(xform.eM11);
730 fMat22.eM12 = float2FIXED(-xform.eM12);
731 fMat22.eM21 = float2FIXED(-xform.eM21);
732 fMat22.eM22 = float2FIXED(xform.eM22);
733
734 if (needToRenderWithSkia(fRec)) {
735 this->forceGenerateImageFromPath();
736 }
737
738 // Create a hires matrix if we need linear metrics.
739 if (this->isSubpixel()) {
740 OUTLINETEXTMETRIC otm;
741 UINT success = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
742 if (0 == success) {
743 call_ensure_accessible(lf);
744 success = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
745 }
746 if (0 != success) {
747 SkScalar upem = SkIntToScalar(otm.otmEMSquare);
748
749 SkScalar gdiTextSizeToEMScale = upem / gdiTextSize;
750 fHighResMat22.eM11 = float2FIXED(gdiTextSizeToEMScale);
751 fHighResMat22.eM12 = float2FIXED(0);
752 fHighResMat22.eM21 = float2FIXED(0);
753 fHighResMat22.eM22 = float2FIXED(gdiTextSizeToEMScale);
754
755 SkScalar removeEMScale = SkScalarInvert(upem);
756 fHiResMatrix = A;
757 fHiResMatrix.preScale(removeEMScale, removeEMScale);
758 }
759 }
760
761 } else {
762 // Assume bitmap
763 fType = SkScalerContext_GDI::kBitmap_Type;
764
765 xform.eM11 = 1.0f;
766 xform.eM12 = 0.0f;
767 xform.eM21 = 0.0f;
768 xform.eM22 = 1.0f;
769 xform.eDx = 0.0f;
770 xform.eDy = 0.0f;
771
772 // fPost2x2 is column-major, left handed (y down).
773 // MAT2 is row major, right handed (y up).
774 fMat22.eM11 = SkScalarToFIXED(fRec.fPost2x2[0][0]);
775 fMat22.eM12 = SkScalarToFIXED(-fRec.fPost2x2[1][0]);
776 fMat22.eM21 = SkScalarToFIXED(-fRec.fPost2x2[0][1]);
777 fMat22.eM22 = SkScalarToFIXED(fRec.fPost2x2[1][1]);
778 }
779
780 fOffscreen.init(fFont, xform);
781 }
782
~SkScalerContext_GDI()783 SkScalerContext_GDI::~SkScalerContext_GDI() {
784 if (fDDC) {
785 ::SelectObject(fDDC, fSavefont);
786 ::DeleteDC(fDDC);
787 }
788 if (fFont) {
789 ::DeleteObject(fFont);
790 }
791 if (fSC) {
792 ::ScriptFreeCache(&fSC);
793 }
794 }
795
isValid() const796 bool SkScalerContext_GDI::isValid() const {
797 return fDDC && fFont;
798 }
799
generateGlyphCount()800 unsigned SkScalerContext_GDI::generateGlyphCount() {
801 if (fGlyphCount < 0) {
802 fGlyphCount = calculateGlyphCount(
803 fDDC, static_cast<const LogFontTypeface*>(this->getTypeface())->fLogFont);
804 }
805 return fGlyphCount;
806 }
807
generateCharToGlyph(SkUnichar utf32)808 uint16_t SkScalerContext_GDI::generateCharToGlyph(SkUnichar utf32) {
809 uint16_t index = 0;
810 WCHAR utf16[2];
811 // TODO(ctguil): Support characters that generate more than one glyph.
812 if (SkUTF16_FromUnichar(utf32, (uint16_t*)utf16) == 1) {
813 // Type1 fonts fail with uniscribe API. Use GetGlyphIndices for plane 0.
814
815 /** Real documentation for GetGlyphIndiciesW:
816 *
817 * When GGI_MARK_NONEXISTING_GLYPHS is not specified and a character does not map to a
818 * glyph, then the 'default character's glyph is returned instead. The 'default character'
819 * is available in fTM.tmDefaultChar. FON fonts have a default character, and there exists
820 * a usDefaultChar in the 'OS/2' table, version 2 and later. If there is no
821 * 'default character' specified by the font, then often the first character found is used.
822 *
823 * When GGI_MARK_NONEXISTING_GLYPHS is specified and a character does not map to a glyph,
824 * then the glyph 0xFFFF is used. In Windows XP and earlier, Bitmap/Vector FON usually use
825 * glyph 0x1F instead ('Terminal' appears to be special, returning 0xFFFF).
826 * Type1 PFM/PFB, TT, OT TT, OT CFF all appear to use 0xFFFF, even on XP.
827 */
828 DWORD result = GetGlyphIndicesW(fDDC, utf16, 1, &index, GGI_MARK_NONEXISTING_GLYPHS);
829 if (result == GDI_ERROR
830 || 0xFFFF == index
831 || (0x1F == index &&
832 (fType == SkScalerContext_GDI::kBitmap_Type ||
833 fType == SkScalerContext_GDI::kLine_Type)
834 /*&& winVer < Vista */)
835 )
836 {
837 index = 0;
838 }
839 } else {
840 // Use uniscribe to detemine glyph index for non-BMP characters.
841 static const int numWCHAR = 2;
842 static const int maxItems = 2;
843 // MSDN states that this can be NULL, but some things don't work then.
844 SCRIPT_CONTROL sc = { 0 };
845 // Add extra item to SCRIPT_ITEM to work around a bug (now documented).
846 // https://bugzilla.mozilla.org/show_bug.cgi?id=366643
847 SCRIPT_ITEM si[maxItems + 1];
848 int numItems;
849 HRZM(ScriptItemize(utf16, numWCHAR, maxItems, &sc, NULL, si, &numItems),
850 "Could not itemize character.");
851
852 // Sometimes ScriptShape cannot find a glyph for a non-BMP and returns 2 space glyphs.
853 static const int maxGlyphs = 2;
854 SCRIPT_VISATTR vsa[maxGlyphs];
855 WORD outGlyphs[maxGlyphs];
856 WORD logClust[numWCHAR];
857 int numGlyphs;
858 HRZM(ScriptShape(fDDC, &fSC, utf16, numWCHAR, maxGlyphs, &si[0].a,
859 outGlyphs, logClust, vsa, &numGlyphs),
860 "Could not shape character.");
861 if (1 == numGlyphs) {
862 index = outGlyphs[0];
863 }
864 }
865 return index;
866 }
867
generateAdvance(SkGlyph * glyph)868 void SkScalerContext_GDI::generateAdvance(SkGlyph* glyph) {
869 this->generateMetrics(glyph);
870 }
871
generateMetrics(SkGlyph * glyph)872 void SkScalerContext_GDI::generateMetrics(SkGlyph* glyph) {
873 SkASSERT(fDDC);
874
875 if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) {
876 SIZE size;
877 WORD glyphs = glyph->getGlyphID(0);
878 if (0 == GetTextExtentPointI(fDDC, &glyphs, 1, &size)) {
879 glyph->fWidth = SkToS16(fTM.tmMaxCharWidth);
880 } else {
881 glyph->fWidth = SkToS16(size.cx);
882 }
883 glyph->fHeight = SkToS16(size.cy);
884
885 glyph->fTop = SkToS16(-fTM.tmAscent);
886 // Bitmap FON cannot underhang, but vector FON may.
887 // There appears no means of determining underhang of vector FON.
888 glyph->fLeft = SkToS16(0);
889 glyph->fAdvanceX = SkIntToFixed(glyph->fWidth);
890 glyph->fAdvanceY = 0;
891
892 // Vector FON will transform nicely, but bitmap FON do not.
893 if (fType == SkScalerContext_GDI::kLine_Type) {
894 SkRect bounds = SkRect::MakeXYWH(glyph->fLeft, glyph->fTop,
895 glyph->fWidth, glyph->fHeight);
896 SkMatrix m;
897 m.setAll(SkFIXEDToScalar(fMat22.eM11), -SkFIXEDToScalar(fMat22.eM21), 0,
898 -SkFIXEDToScalar(fMat22.eM12), SkFIXEDToScalar(fMat22.eM22), 0,
899 0, 0, SkScalarToPersp(SK_Scalar1));
900 m.mapRect(&bounds);
901 bounds.roundOut();
902 glyph->fLeft = SkScalarTruncToInt(bounds.fLeft);
903 glyph->fTop = SkScalarTruncToInt(bounds.fTop);
904 glyph->fWidth = SkScalarTruncToInt(bounds.width());
905 glyph->fHeight = SkScalarTruncToInt(bounds.height());
906 }
907
908 // Apply matrix to advance.
909 glyph->fAdvanceY = SkFixedMul(-SkFIXEDToFixed(fMat22.eM12), glyph->fAdvanceX);
910 glyph->fAdvanceX = SkFixedMul(SkFIXEDToFixed(fMat22.eM11), glyph->fAdvanceX);
911
912 return;
913 }
914
915 UINT glyphId = glyph->getGlyphID(0);
916
917 GLYPHMETRICS gm;
918 sk_bzero(&gm, sizeof(gm));
919
920 DWORD status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
921 if (GDI_ERROR == status) {
922 LogFontTypeface::EnsureAccessible(this->getTypeface());
923 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
924 if (GDI_ERROR == status) {
925 glyph->zeroMetrics();
926 return;
927 }
928 }
929
930 bool empty = false;
931 // The black box is either the embedded bitmap size or the outline extent.
932 // It is 1x1 if nothing is to be drawn, but will also be 1x1 if something very small
933 // is to be drawn, like a '.'. We need to outset '.' but do not wish to outset ' '.
934 if (1 == gm.gmBlackBoxX && 1 == gm.gmBlackBoxY) {
935 // If GetGlyphOutline with GGO_NATIVE returns 0, we know there was no outline.
936 DWORD bufferSize = GetGlyphOutlineW(fDDC, glyphId, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
937 empty = (0 == bufferSize);
938 }
939
940 glyph->fTop = SkToS16(-gm.gmptGlyphOrigin.y);
941 glyph->fLeft = SkToS16(gm.gmptGlyphOrigin.x);
942 if (empty) {
943 glyph->fWidth = 0;
944 glyph->fHeight = 0;
945 } else {
946 // Outset, since the image may bleed out of the black box.
947 // For embedded bitmaps the black box should be exact.
948 // For outlines we need to outset by 1 in all directions for bleed.
949 // For ClearType we need to outset by 2 for bleed.
950 glyph->fWidth = gm.gmBlackBoxX + 4;
951 glyph->fHeight = gm.gmBlackBoxY + 4;
952 glyph->fTop -= 2;
953 glyph->fLeft -= 2;
954 }
955 glyph->fAdvanceX = SkIntToFixed(gm.gmCellIncX);
956 glyph->fAdvanceY = SkIntToFixed(gm.gmCellIncY);
957 glyph->fRsbDelta = 0;
958 glyph->fLsbDelta = 0;
959
960 if (this->isSubpixel()) {
961 sk_bzero(&gm, sizeof(gm));
962 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fHighResMat22);
963 if (GDI_ERROR != status) {
964 SkPoint advance;
965 fHiResMatrix.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance);
966 glyph->fAdvanceX = SkScalarToFixed(advance.fX);
967 glyph->fAdvanceY = SkScalarToFixed(advance.fY);
968 }
969 } else if (!isAxisAligned(this->fRec)) {
970 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fGsA);
971 if (GDI_ERROR != status) {
972 SkPoint advance;
973 fG_inv.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance);
974 glyph->fAdvanceX = SkScalarToFixed(advance.fX);
975 glyph->fAdvanceY = SkScalarToFixed(advance.fY);
976 }
977 }
978 }
979
980 static const MAT2 gMat2Identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
generateFontMetrics(SkPaint::FontMetrics * mx,SkPaint::FontMetrics * my)981 void SkScalerContext_GDI::generateFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my) {
982 if (!(mx || my)) {
983 return;
984 }
985
986 if (mx) {
987 sk_bzero(mx, sizeof(*mx));
988 }
989 if (my) {
990 sk_bzero(my, sizeof(*my));
991 }
992
993 SkASSERT(fDDC);
994
995 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
996 if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) {
997 #endif
998 if (mx) {
999 mx->fTop = SkIntToScalar(-fTM.tmAscent);
1000 mx->fAscent = SkIntToScalar(-fTM.tmAscent);
1001 mx->fDescent = SkIntToScalar(fTM.tmDescent);
1002 mx->fBottom = SkIntToScalar(fTM.tmDescent);
1003 mx->fLeading = SkIntToScalar(fTM.tmExternalLeading);
1004 }
1005
1006 if (my) {
1007 my->fTop = SkIntToScalar(-fTM.tmAscent);
1008 my->fAscent = SkIntToScalar(-fTM.tmAscent);
1009 my->fDescent = SkIntToScalar(fTM.tmDescent);
1010 my->fBottom = SkIntToScalar(fTM.tmDescent);
1011 my->fLeading = SkIntToScalar(fTM.tmExternalLeading);
1012 my->fAvgCharWidth = SkIntToScalar(fTM.tmAveCharWidth);
1013 my->fMaxCharWidth = SkIntToScalar(fTM.tmMaxCharWidth);
1014 my->fXMin = 0;
1015 my->fXMax = my->fMaxCharWidth;
1016 //my->fXHeight = 0;
1017 }
1018 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
1019 return;
1020 }
1021 #endif
1022
1023 OUTLINETEXTMETRIC otm;
1024
1025 uint32_t ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
1026 if (0 == ret) {
1027 LogFontTypeface::EnsureAccessible(this->getTypeface());
1028 ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
1029 }
1030 if (0 == ret) {
1031 return;
1032 }
1033
1034 if (mx) {
1035 mx->fTop = SkIntToScalar(-otm.otmrcFontBox.left);
1036 mx->fAscent = SkIntToScalar(-otm.otmAscent);
1037 mx->fDescent = SkIntToScalar(-otm.otmDescent);
1038 mx->fBottom = SkIntToScalar(otm.otmrcFontBox.right);
1039 mx->fLeading = SkIntToScalar(otm.otmLineGap);
1040 mx->fUnderlineThickness = SkIntToScalar(otm.otmsUnderscoreSize);
1041 mx->fUnderlinePosition = -SkIntToScalar(otm.otmsUnderscorePosition);
1042
1043 mx->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
1044 mx->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
1045 }
1046
1047 if (my) {
1048 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
1049 my->fTop = SkIntToScalar(-otm.otmrcFontBox.top);
1050 my->fAscent = SkIntToScalar(-otm.otmAscent);
1051 my->fDescent = SkIntToScalar(-otm.otmDescent);
1052 my->fBottom = SkIntToScalar(-otm.otmrcFontBox.bottom);
1053 my->fLeading = SkIntToScalar(otm.otmLineGap);
1054 my->fAvgCharWidth = SkIntToScalar(otm.otmTextMetrics.tmAveCharWidth);
1055 my->fMaxCharWidth = SkIntToScalar(otm.otmTextMetrics.tmMaxCharWidth);
1056 my->fXMin = SkIntToScalar(otm.otmrcFontBox.left);
1057 my->fXMax = SkIntToScalar(otm.otmrcFontBox.right);
1058 #endif
1059 my->fUnderlineThickness = SkIntToScalar(otm.otmsUnderscoreSize);
1060 my->fUnderlinePosition = -SkIntToScalar(otm.otmsUnderscorePosition);
1061
1062 my->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
1063 my->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
1064
1065 my->fXHeight = SkIntToScalar(otm.otmsXHeight);
1066
1067 GLYPHMETRICS gm;
1068 sk_bzero(&gm, sizeof(gm));
1069 DWORD len = GetGlyphOutlineW(fDDC, 'x', GGO_METRICS, &gm, 0, 0, &gMat2Identity);
1070 if (len != GDI_ERROR && gm.gmBlackBoxY > 0) {
1071 my->fXHeight = SkIntToScalar(gm.gmBlackBoxY);
1072 }
1073 }
1074 }
1075
1076 ////////////////////////////////////////////////////////////////////////////////////////
1077
1078 #define SK_SHOW_TEXT_BLIT_COVERAGE 0
1079
build_power_table(uint8_t table[],float ee)1080 static void build_power_table(uint8_t table[], float ee) {
1081 for (int i = 0; i < 256; i++) {
1082 float x = i / 255.f;
1083 x = sk_float_pow(x, ee);
1084 int xx = SkScalarRoundToInt(x * 255);
1085 table[i] = SkToU8(xx);
1086 }
1087 }
1088
1089 /**
1090 * This will invert the gamma applied by GDI (gray-scale antialiased), so we
1091 * can get linear values.
1092 *
1093 * GDI grayscale appears to use a hard-coded gamma of 2.3.
1094 *
1095 * GDI grayscale appears to draw using the black and white rasterizer at four
1096 * times the size and then downsamples to compute the coverage mask. As a
1097 * result there are only seventeen total grays. This lack of fidelity means
1098 * that shifting into other color spaces is imprecise.
1099 */
getInverseGammaTableGDI()1100 static const uint8_t* getInverseGammaTableGDI() {
1101 // Since build_power_table is idempotent, many threads can build gTableGdi
1102 // simultaneously.
1103
1104 // Microsoft Specific:
1105 // Making gInited volatile provides read-aquire and write-release in vc++.
1106 // In VS2012, see compiler option /volatile:(ms|iso).
1107 // Replace with C++11 atomics when possible.
1108 static volatile bool gInited;
1109 static uint8_t gTableGdi[256];
1110 if (gInited) {
1111 // Need a L/L (read) barrier (full acquire not needed). If gInited is observed
1112 // true then gTableGdi is observable, but it must be requested.
1113 } else {
1114 build_power_table(gTableGdi, 2.3f);
1115 // Need a S/S (write) barrier (full release not needed) here so that this
1116 // write to gInited becomes observable after gTableGdi.
1117 gInited = true;
1118 }
1119 return gTableGdi;
1120 }
1121
1122 /**
1123 * This will invert the gamma applied by GDI ClearType, so we can get linear
1124 * values.
1125 *
1126 * GDI ClearType uses SPI_GETFONTSMOOTHINGCONTRAST / 1000 as the gamma value.
1127 * If this value is not specified, the default is a gamma of 1.4.
1128 */
getInverseGammaTableClearType()1129 static const uint8_t* getInverseGammaTableClearType() {
1130 // We don't expect SPI_GETFONTSMOOTHINGCONTRAST to ever change, so building
1131 // gTableClearType with build_power_table is effectively idempotent.
1132
1133 // Microsoft Specific:
1134 // Making gInited volatile provides read-aquire and write-release in vc++.
1135 // In VS2012, see compiler option /volatile:(ms|iso).
1136 // Replace with C++11 atomics when possible.
1137 static volatile bool gInited;
1138 static uint8_t gTableClearType[256];
1139 if (gInited) {
1140 // Need a L/L (read) barrier (acquire not needed). If gInited is observed
1141 // true then gTableClearType is observable, but it must be requested.
1142 } else {
1143 UINT level = 0;
1144 if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &level, 0) || !level) {
1145 // can't get the data, so use a default
1146 level = 1400;
1147 }
1148 build_power_table(gTableClearType, level / 1000.0f);
1149 // Need a S/S (write) barrier (release not needed) here so that this
1150 // write to gInited becomes observable after gTableClearType.
1151 gInited = true;
1152 }
1153 return gTableClearType;
1154 }
1155
1156 #include "SkColorPriv.h"
1157
1158 //Cannot assume that the input rgb is gray due to possible setting of kGenA8FromLCD_Flag.
1159 template<bool APPLY_PREBLEND>
rgb_to_a8(SkGdiRGB rgb,const uint8_t * table8)1160 static inline uint8_t rgb_to_a8(SkGdiRGB rgb, const uint8_t* table8) {
1161 U8CPU r = (rgb >> 16) & 0xFF;
1162 U8CPU g = (rgb >> 8) & 0xFF;
1163 U8CPU b = (rgb >> 0) & 0xFF;
1164 return sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8);
1165 }
1166
1167 template<bool APPLY_PREBLEND>
rgb_to_lcd16(SkGdiRGB rgb,const uint8_t * tableR,const uint8_t * tableG,const uint8_t * tableB)1168 static inline uint16_t rgb_to_lcd16(SkGdiRGB rgb, const uint8_t* tableR,
1169 const uint8_t* tableG,
1170 const uint8_t* tableB) {
1171 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
1172 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG);
1173 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB);
1174 #if SK_SHOW_TEXT_BLIT_COVERAGE
1175 r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10);
1176 #endif
1177 return SkPack888ToRGB16(r, g, b);
1178 }
1179
1180 template<bool APPLY_PREBLEND>
rgb_to_lcd32(SkGdiRGB rgb,const uint8_t * tableR,const uint8_t * tableG,const uint8_t * tableB)1181 static inline SkPMColor rgb_to_lcd32(SkGdiRGB rgb, const uint8_t* tableR,
1182 const uint8_t* tableG,
1183 const uint8_t* tableB) {
1184 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
1185 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG);
1186 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB);
1187 #if SK_SHOW_TEXT_BLIT_COVERAGE
1188 r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10);
1189 #endif
1190 return SkPackARGB32(0xFF, r, g, b);
1191 }
1192
1193 // Is this GDI color neither black nor white? If so, we have to keep this
1194 // image as is, rather than smashing it down to a BW mask.
1195 //
1196 // returns int instead of bool, since we don't want/have to pay to convert
1197 // the zero/non-zero value into a bool
is_not_black_or_white(SkGdiRGB c)1198 static int is_not_black_or_white(SkGdiRGB c) {
1199 // same as (but faster than)
1200 // c &= 0x00FFFFFF;
1201 // return 0 == c || 0x00FFFFFF == c;
1202 return (c + (c & 1)) & 0x00FFFFFF;
1203 }
1204
is_rgb_really_bw(const SkGdiRGB * src,int width,int height,size_t srcRB)1205 static bool is_rgb_really_bw(const SkGdiRGB* src, int width, int height, size_t srcRB) {
1206 for (int y = 0; y < height; ++y) {
1207 for (int x = 0; x < width; ++x) {
1208 if (is_not_black_or_white(src[x])) {
1209 return false;
1210 }
1211 }
1212 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1213 }
1214 return true;
1215 }
1216
1217 // gdi's bitmap is upside-down, so we reverse dst walking in Y
1218 // whenever we copy it into skia's buffer
rgb_to_bw(const SkGdiRGB * SK_RESTRICT src,size_t srcRB,const SkGlyph & glyph)1219 static void rgb_to_bw(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
1220 const SkGlyph& glyph) {
1221 const int width = glyph.fWidth;
1222 const size_t dstRB = (width + 7) >> 3;
1223 uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1224
1225 int byteCount = width >> 3;
1226 int bitCount = width & 7;
1227
1228 // adjust srcRB to skip the values in our byteCount loop,
1229 // since we increment src locally there
1230 srcRB -= byteCount * 8 * sizeof(SkGdiRGB);
1231
1232 for (int y = 0; y < glyph.fHeight; ++y) {
1233 if (byteCount > 0) {
1234 for (int i = 0; i < byteCount; ++i) {
1235 unsigned byte = 0;
1236 byte |= src[0] & (1 << 7);
1237 byte |= src[1] & (1 << 6);
1238 byte |= src[2] & (1 << 5);
1239 byte |= src[3] & (1 << 4);
1240 byte |= src[4] & (1 << 3);
1241 byte |= src[5] & (1 << 2);
1242 byte |= src[6] & (1 << 1);
1243 byte |= src[7] & (1 << 0);
1244 dst[i] = byte;
1245 src += 8;
1246 }
1247 }
1248 if (bitCount > 0) {
1249 unsigned byte = 0;
1250 unsigned mask = 0x80;
1251 for (int i = 0; i < bitCount; i++) {
1252 byte |= src[i] & mask;
1253 mask >>= 1;
1254 }
1255 dst[byteCount] = byte;
1256 }
1257 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1258 dst -= dstRB;
1259 }
1260 #if SK_SHOW_TEXT_BLIT_COVERAGE
1261 if (glyph.fWidth > 0 && glyph.fHeight > 0) {
1262 uint8_t* first = (uint8_t*)glyph.fImage;
1263 uint8_t* last = (uint8_t*)((char*)glyph.fImage + glyph.fHeight * dstRB - 1);
1264 *first |= 1 << 7;
1265 *last |= bitCount == 0 ? 1 : 1 << (8 - bitCount);
1266 }
1267 #endif
1268 }
1269
1270 template<bool APPLY_PREBLEND>
rgb_to_a8(const SkGdiRGB * SK_RESTRICT src,size_t srcRB,const SkGlyph & glyph,const uint8_t * table8)1271 static void rgb_to_a8(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
1272 const SkGlyph& glyph, const uint8_t* table8) {
1273 const size_t dstRB = glyph.rowBytes();
1274 const int width = glyph.fWidth;
1275 uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1276
1277 for (int y = 0; y < glyph.fHeight; y++) {
1278 for (int i = 0; i < width; i++) {
1279 dst[i] = rgb_to_a8<APPLY_PREBLEND>(src[i], table8);
1280 #if SK_SHOW_TEXT_BLIT_COVERAGE
1281 dst[i] = SkMax32(dst[i], 10);
1282 #endif
1283 }
1284 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1285 dst -= dstRB;
1286 }
1287 }
1288
1289 template<bool APPLY_PREBLEND>
rgb_to_lcd16(const SkGdiRGB * SK_RESTRICT src,size_t srcRB,const SkGlyph & glyph,const uint8_t * tableR,const uint8_t * tableG,const uint8_t * tableB)1290 static void rgb_to_lcd16(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph,
1291 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
1292 const size_t dstRB = glyph.rowBytes();
1293 const int width = glyph.fWidth;
1294 uint16_t* SK_RESTRICT dst = (uint16_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1295
1296 for (int y = 0; y < glyph.fHeight; y++) {
1297 for (int i = 0; i < width; i++) {
1298 dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(src[i], tableR, tableG, tableB);
1299 }
1300 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1301 dst = (uint16_t*)((char*)dst - dstRB);
1302 }
1303 }
1304
1305 template<bool APPLY_PREBLEND>
rgb_to_lcd32(const SkGdiRGB * SK_RESTRICT src,size_t srcRB,const SkGlyph & glyph,const uint8_t * tableR,const uint8_t * tableG,const uint8_t * tableB)1306 static void rgb_to_lcd32(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph,
1307 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
1308 const size_t dstRB = glyph.rowBytes();
1309 const int width = glyph.fWidth;
1310 uint32_t* SK_RESTRICT dst = (uint32_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1311
1312 for (int y = 0; y < glyph.fHeight; y++) {
1313 for (int i = 0; i < width; i++) {
1314 dst[i] = rgb_to_lcd32<APPLY_PREBLEND>(src[i], tableR, tableG, tableB);
1315 }
1316 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1317 dst = (uint32_t*)((char*)dst - dstRB);
1318 }
1319 }
1320
clamp255(unsigned x)1321 static inline unsigned clamp255(unsigned x) {
1322 SkASSERT(x <= 256);
1323 return x - (x >> 8);
1324 }
1325
generateImage(const SkGlyph & glyph)1326 void SkScalerContext_GDI::generateImage(const SkGlyph& glyph) {
1327 SkASSERT(fDDC);
1328
1329 const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat;
1330 const bool isAA = !isLCD(fRec);
1331
1332 size_t srcRB;
1333 const void* bits = fOffscreen.draw(glyph, isBW, &srcRB);
1334 if (NULL == bits) {
1335 LogFontTypeface::EnsureAccessible(this->getTypeface());
1336 bits = fOffscreen.draw(glyph, isBW, &srcRB);
1337 if (NULL == bits) {
1338 sk_bzero(glyph.fImage, glyph.computeImageSize());
1339 return;
1340 }
1341 }
1342
1343 if (!isBW) {
1344 const uint8_t* table;
1345 //The offscreen contains a GDI blit if isAA and kGenA8FromLCD_Flag is not set.
1346 //Otherwise the offscreen contains a ClearType blit.
1347 if (isAA && !(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag)) {
1348 table = getInverseGammaTableGDI();
1349 } else {
1350 table = getInverseGammaTableClearType();
1351 }
1352 //Note that the following cannot really be integrated into the
1353 //pre-blend, since we may not be applying the pre-blend; when we aren't
1354 //applying the pre-blend it means that a filter wants linear anyway.
1355 //Other code may also be applying the pre-blend, so we'd need another
1356 //one with this and one without.
1357 SkGdiRGB* addr = (SkGdiRGB*)bits;
1358 for (int y = 0; y < glyph.fHeight; ++y) {
1359 for (int x = 0; x < glyph.fWidth; ++x) {
1360 int r = (addr[x] >> 16) & 0xFF;
1361 int g = (addr[x] >> 8) & 0xFF;
1362 int b = (addr[x] >> 0) & 0xFF;
1363 addr[x] = (table[r] << 16) | (table[g] << 8) | table[b];
1364 }
1365 addr = SkTAddOffset<SkGdiRGB>(addr, srcRB);
1366 }
1367 }
1368
1369 int width = glyph.fWidth;
1370 size_t dstRB = glyph.rowBytes();
1371 if (isBW) {
1372 const uint8_t* src = (const uint8_t*)bits;
1373 uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1374 for (int y = 0; y < glyph.fHeight; y++) {
1375 memcpy(dst, src, dstRB);
1376 src += srcRB;
1377 dst -= dstRB;
1378 }
1379 #if SK_SHOW_TEXT_BLIT_COVERAGE
1380 if (glyph.fWidth > 0 && glyph.fHeight > 0) {
1381 int bitCount = width & 7;
1382 uint8_t* first = (uint8_t*)glyph.fImage;
1383 uint8_t* last = (uint8_t*)((char*)glyph.fImage + glyph.fHeight * dstRB - 1);
1384 *first |= 1 << 7;
1385 *last |= bitCount == 0 ? 1 : 1 << (8 - bitCount);
1386 }
1387 #endif
1388 } else if (isAA) {
1389 // since the caller may require A8 for maskfilters, we can't check for BW
1390 // ... until we have the caller tell us that explicitly
1391 const SkGdiRGB* src = (const SkGdiRGB*)bits;
1392 if (fPreBlend.isApplicable()) {
1393 rgb_to_a8<true>(src, srcRB, glyph, fPreBlend.fG);
1394 } else {
1395 rgb_to_a8<false>(src, srcRB, glyph, fPreBlend.fG);
1396 }
1397 } else { // LCD16
1398 const SkGdiRGB* src = (const SkGdiRGB*)bits;
1399 if (is_rgb_really_bw(src, width, glyph.fHeight, srcRB)) {
1400 rgb_to_bw(src, srcRB, glyph);
1401 ((SkGlyph*)&glyph)->fMaskFormat = SkMask::kBW_Format;
1402 } else {
1403 if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
1404 if (fPreBlend.isApplicable()) {
1405 rgb_to_lcd16<true>(src, srcRB, glyph,
1406 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1407 } else {
1408 rgb_to_lcd16<false>(src, srcRB, glyph,
1409 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1410 }
1411 } else {
1412 SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat);
1413 if (fPreBlend.isApplicable()) {
1414 rgb_to_lcd32<true>(src, srcRB, glyph,
1415 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1416 } else {
1417 rgb_to_lcd32<false>(src, srcRB, glyph,
1418 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1419 }
1420 }
1421 }
1422 }
1423 }
1424
1425 class GDIGlyphbufferPointIter {
1426 public:
GDIGlyphbufferPointIter(const uint8_t * glyphbuf,DWORD total_size)1427 GDIGlyphbufferPointIter(const uint8_t* glyphbuf, DWORD total_size)
1428 : fHeaderIter(glyphbuf, total_size), fCurveIter(), fPointIter()
1429 { }
1430
next()1431 POINTFX const * next() {
1432 nextHeader:
1433 if (!fCurveIter.isSet()) {
1434 const TTPOLYGONHEADER* header = fHeaderIter.next();
1435 if (NULL == header) {
1436 return NULL;
1437 }
1438 fCurveIter.set(header);
1439 const TTPOLYCURVE* curve = fCurveIter.next();
1440 if (NULL == curve) {
1441 return NULL;
1442 }
1443 fPointIter.set(curve);
1444 return &header->pfxStart;
1445 }
1446
1447 const POINTFX* nextPoint = fPointIter.next();
1448 if (NULL == nextPoint) {
1449 const TTPOLYCURVE* curve = fCurveIter.next();
1450 if (NULL == curve) {
1451 fCurveIter.set();
1452 goto nextHeader;
1453 } else {
1454 fPointIter.set(curve);
1455 }
1456 nextPoint = fPointIter.next();
1457 }
1458 return nextPoint;
1459 }
1460
currentCurveType()1461 WORD currentCurveType() {
1462 return fPointIter.fCurveType;
1463 }
1464
1465 private:
1466 /** Iterates over all of the polygon headers in a glyphbuf. */
1467 class GDIPolygonHeaderIter {
1468 public:
GDIPolygonHeaderIter(const uint8_t * glyphbuf,DWORD total_size)1469 GDIPolygonHeaderIter(const uint8_t* glyphbuf, DWORD total_size)
1470 : fCurPolygon(reinterpret_cast<const TTPOLYGONHEADER*>(glyphbuf))
1471 , fEndPolygon(SkTAddOffset<const TTPOLYGONHEADER>(glyphbuf, total_size))
1472 { }
1473
next()1474 const TTPOLYGONHEADER* next() {
1475 if (fCurPolygon >= fEndPolygon) {
1476 return NULL;
1477 }
1478 const TTPOLYGONHEADER* thisPolygon = fCurPolygon;
1479 fCurPolygon = SkTAddOffset<const TTPOLYGONHEADER>(fCurPolygon, fCurPolygon->cb);
1480 return thisPolygon;
1481 }
1482 private:
1483 const TTPOLYGONHEADER* fCurPolygon;
1484 const TTPOLYGONHEADER* fEndPolygon;
1485 };
1486
1487 /** Iterates over all of the polygon curves in a polygon header. */
1488 class GDIPolygonCurveIter {
1489 public:
GDIPolygonCurveIter()1490 GDIPolygonCurveIter() : fCurCurve(NULL), fEndCurve(NULL) { }
1491
GDIPolygonCurveIter(const TTPOLYGONHEADER * curPolygon)1492 GDIPolygonCurveIter(const TTPOLYGONHEADER* curPolygon)
1493 : fCurCurve(SkTAddOffset<const TTPOLYCURVE>(curPolygon, sizeof(TTPOLYGONHEADER)))
1494 , fEndCurve(SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon->cb))
1495 { }
1496
isSet()1497 bool isSet() { return fCurCurve != NULL; }
1498
set(const TTPOLYGONHEADER * curPolygon)1499 void set(const TTPOLYGONHEADER* curPolygon) {
1500 fCurCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon, sizeof(TTPOLYGONHEADER));
1501 fEndCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon->cb);
1502 }
set()1503 void set() {
1504 fCurCurve = NULL;
1505 fEndCurve = NULL;
1506 }
1507
next()1508 const TTPOLYCURVE* next() {
1509 if (fCurCurve >= fEndCurve) {
1510 return NULL;
1511 }
1512 const TTPOLYCURVE* thisCurve = fCurCurve;
1513 fCurCurve = SkTAddOffset<const TTPOLYCURVE>(fCurCurve, size_of_TTPOLYCURVE(*fCurCurve));
1514 return thisCurve;
1515 }
1516 private:
size_of_TTPOLYCURVE(const TTPOLYCURVE & curve)1517 size_t size_of_TTPOLYCURVE(const TTPOLYCURVE& curve) {
1518 return 2*sizeof(WORD) + curve.cpfx*sizeof(POINTFX);
1519 }
1520 const TTPOLYCURVE* fCurCurve;
1521 const TTPOLYCURVE* fEndCurve;
1522 };
1523
1524 /** Iterates over all of the polygon points in a polygon curve. */
1525 class GDIPolygonCurvePointIter {
1526 public:
GDIPolygonCurvePointIter()1527 GDIPolygonCurvePointIter() : fCurveType(0), fCurPoint(NULL), fEndPoint(NULL) { }
1528
GDIPolygonCurvePointIter(const TTPOLYCURVE * curPolygon)1529 GDIPolygonCurvePointIter(const TTPOLYCURVE* curPolygon)
1530 : fCurveType(curPolygon->wType)
1531 , fCurPoint(&curPolygon->apfx[0])
1532 , fEndPoint(&curPolygon->apfx[curPolygon->cpfx])
1533 { }
1534
isSet()1535 bool isSet() { return fCurPoint != NULL; }
1536
set(const TTPOLYCURVE * curPolygon)1537 void set(const TTPOLYCURVE* curPolygon) {
1538 fCurveType = curPolygon->wType;
1539 fCurPoint = &curPolygon->apfx[0];
1540 fEndPoint = &curPolygon->apfx[curPolygon->cpfx];
1541 }
set()1542 void set() {
1543 fCurPoint = NULL;
1544 fEndPoint = NULL;
1545 }
1546
next()1547 const POINTFX* next() {
1548 if (fCurPoint >= fEndPoint) {
1549 return NULL;
1550 }
1551 const POINTFX* thisPoint = fCurPoint;
1552 ++fCurPoint;
1553 return thisPoint;
1554 }
1555
1556 WORD fCurveType;
1557 private:
1558 const POINTFX* fCurPoint;
1559 const POINTFX* fEndPoint;
1560 };
1561
1562 GDIPolygonHeaderIter fHeaderIter;
1563 GDIPolygonCurveIter fCurveIter;
1564 GDIPolygonCurvePointIter fPointIter;
1565 };
1566
sk_path_from_gdi_path(SkPath * path,const uint8_t * glyphbuf,DWORD total_size)1567 static void sk_path_from_gdi_path(SkPath* path, const uint8_t* glyphbuf, DWORD total_size) {
1568 const uint8_t* cur_glyph = glyphbuf;
1569 const uint8_t* end_glyph = glyphbuf + total_size;
1570
1571 while (cur_glyph < end_glyph) {
1572 const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
1573
1574 const uint8_t* end_poly = cur_glyph + th->cb;
1575 const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
1576
1577 path->moveTo(SkFixedToScalar( SkFIXEDToFixed(th->pfxStart.x)),
1578 SkFixedToScalar(-SkFIXEDToFixed(th->pfxStart.y)));
1579
1580 while (cur_poly < end_poly) {
1581 const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
1582
1583 if (pc->wType == TT_PRIM_LINE) {
1584 for (uint16_t i = 0; i < pc->cpfx; i++) {
1585 path->lineTo(SkFixedToScalar( SkFIXEDToFixed(pc->apfx[i].x)),
1586 SkFixedToScalar(-SkFIXEDToFixed(pc->apfx[i].y)));
1587 }
1588 }
1589
1590 if (pc->wType == TT_PRIM_QSPLINE) {
1591 for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline
1592 POINTFX pnt_b = pc->apfx[u]; // B is always the current point
1593 POINTFX pnt_c = pc->apfx[u+1];
1594
1595 if (u < pc->cpfx - 2) { // If not on last spline, compute C
1596 pnt_c.x = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.x),
1597 SkFIXEDToFixed(pnt_c.x)));
1598 pnt_c.y = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.y),
1599 SkFIXEDToFixed(pnt_c.y)));
1600 }
1601
1602 path->quadTo(SkFixedToScalar( SkFIXEDToFixed(pnt_b.x)),
1603 SkFixedToScalar(-SkFIXEDToFixed(pnt_b.y)),
1604 SkFixedToScalar( SkFIXEDToFixed(pnt_c.x)),
1605 SkFixedToScalar(-SkFIXEDToFixed(pnt_c.y)));
1606 }
1607 }
1608 // Advance past this TTPOLYCURVE.
1609 cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx;
1610 }
1611 cur_glyph += th->cb;
1612 path->close();
1613 }
1614 }
1615
1616 #define move_next_expected_hinted_point(iter, pElem) do {\
1617 pElem = iter.next(); \
1618 if (NULL == pElem) return false; \
1619 } while(0)
1620
1621 // It is possible for the hinted and unhinted versions of the same path to have
1622 // a different number of points due to GDI's handling of flipped points.
1623 // If this is detected, this will return false.
sk_path_from_gdi_paths(SkPath * path,const uint8_t * glyphbuf,DWORD total_size,GDIGlyphbufferPointIter hintedYs)1624 static bool sk_path_from_gdi_paths(SkPath* path, const uint8_t* glyphbuf, DWORD total_size,
1625 GDIGlyphbufferPointIter hintedYs) {
1626 const uint8_t* cur_glyph = glyphbuf;
1627 const uint8_t* end_glyph = glyphbuf + total_size;
1628
1629 POINTFX const * hintedPoint;
1630
1631 while (cur_glyph < end_glyph) {
1632 const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
1633
1634 const uint8_t* end_poly = cur_glyph + th->cb;
1635 const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
1636
1637 move_next_expected_hinted_point(hintedYs, hintedPoint);
1638 path->moveTo(SkFixedToScalar( SkFIXEDToFixed(th->pfxStart.x)),
1639 SkFixedToScalar(-SkFIXEDToFixed(hintedPoint->y)));
1640
1641 while (cur_poly < end_poly) {
1642 const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
1643
1644 if (pc->wType == TT_PRIM_LINE) {
1645 for (uint16_t i = 0; i < pc->cpfx; i++) {
1646 move_next_expected_hinted_point(hintedYs, hintedPoint);
1647 path->lineTo(SkFixedToScalar( SkFIXEDToFixed(pc->apfx[i].x)),
1648 SkFixedToScalar(-SkFIXEDToFixed(hintedPoint->y)));
1649 }
1650 }
1651
1652 if (pc->wType == TT_PRIM_QSPLINE) {
1653 POINTFX currentPoint = pc->apfx[0];
1654 move_next_expected_hinted_point(hintedYs, hintedPoint);
1655 // only take the hinted y if it wasn't flipped
1656 if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) {
1657 currentPoint.y = hintedPoint->y;
1658 }
1659 for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline
1660 POINTFX pnt_b = currentPoint;//pc->apfx[u]; // B is always the current point
1661 POINTFX pnt_c = pc->apfx[u+1];
1662 move_next_expected_hinted_point(hintedYs, hintedPoint);
1663 // only take the hinted y if it wasn't flipped
1664 if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) {
1665 pnt_c.y = hintedPoint->y;
1666 }
1667 currentPoint.x = pnt_c.x;
1668 currentPoint.y = pnt_c.y;
1669
1670 if (u < pc->cpfx - 2) { // If not on last spline, compute C
1671 pnt_c.x = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.x),
1672 SkFIXEDToFixed(pnt_c.x)));
1673 pnt_c.y = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.y),
1674 SkFIXEDToFixed(pnt_c.y)));
1675 }
1676
1677 path->quadTo(SkFixedToScalar( SkFIXEDToFixed(pnt_b.x)),
1678 SkFixedToScalar(-SkFIXEDToFixed(pnt_b.y)),
1679 SkFixedToScalar( SkFIXEDToFixed(pnt_c.x)),
1680 SkFixedToScalar(-SkFIXEDToFixed(pnt_c.y)));
1681 }
1682 }
1683 // Advance past this TTPOLYCURVE.
1684 cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx;
1685 }
1686 cur_glyph += th->cb;
1687 path->close();
1688 }
1689 return true;
1690 }
1691
getGDIGlyphPath(const SkGlyph & glyph,UINT flags,SkAutoSTMalloc<BUFFERSIZE,uint8_t> * glyphbuf)1692 DWORD SkScalerContext_GDI::getGDIGlyphPath(const SkGlyph& glyph, UINT flags,
1693 SkAutoSTMalloc<BUFFERSIZE, uint8_t>* glyphbuf)
1694 {
1695 GLYPHMETRICS gm;
1696
1697 DWORD total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, BUFFERSIZE, glyphbuf->get(), &fMat22);
1698 // Sometimes GetGlyphOutlineW returns a number larger than BUFFERSIZE even if BUFFERSIZE > 0.
1699 // It has been verified that this does not involve a buffer overrun.
1700 if (GDI_ERROR == total_size || total_size > BUFFERSIZE) {
1701 // GDI_ERROR because the BUFFERSIZE was too small, or because the data was not accessible.
1702 // When the data is not accessable GetGlyphOutlineW fails rather quickly,
1703 // so just try to get the size. If that fails then ensure the data is accessible.
1704 total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, 0, NULL, &fMat22);
1705 if (GDI_ERROR == total_size) {
1706 LogFontTypeface::EnsureAccessible(this->getTypeface());
1707 total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, 0, NULL, &fMat22);
1708 if (GDI_ERROR == total_size) {
1709 SkASSERT(false);
1710 return 0;
1711 }
1712 }
1713
1714 glyphbuf->reset(total_size);
1715
1716 DWORD ret = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, total_size, glyphbuf->get(), &fMat22);
1717 if (GDI_ERROR == ret) {
1718 LogFontTypeface::EnsureAccessible(this->getTypeface());
1719 ret = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, total_size, glyphbuf->get(), &fMat22);
1720 if (GDI_ERROR == ret) {
1721 SkASSERT(false);
1722 return 0;
1723 }
1724 }
1725 }
1726 return total_size;
1727 }
1728
generatePath(const SkGlyph & glyph,SkPath * path)1729 void SkScalerContext_GDI::generatePath(const SkGlyph& glyph, SkPath* path) {
1730 SkASSERT(&glyph && path);
1731 SkASSERT(fDDC);
1732
1733 path->reset();
1734
1735 // Out of all the fonts on a typical Windows box,
1736 // 25% of glyphs require more than 2KB.
1737 // 1% of glyphs require more than 4KB.
1738 // 0.01% of glyphs require more than 8KB.
1739 // 8KB is less than 1% of the normal 1MB stack on Windows.
1740 // Note that some web fonts glyphs require more than 20KB.
1741 //static const DWORD BUFFERSIZE = (1 << 13);
1742
1743 //GDI only uses hinted outlines when axis aligned.
1744 UINT format = GGO_NATIVE | GGO_GLYPH_INDEX;
1745 if (fRec.getHinting() == SkPaint::kNo_Hinting || fRec.getHinting() == SkPaint::kSlight_Hinting){
1746 format |= GGO_UNHINTED;
1747 }
1748 SkAutoSTMalloc<BUFFERSIZE, uint8_t> glyphbuf(BUFFERSIZE);
1749 DWORD total_size = getGDIGlyphPath(glyph, format, &glyphbuf);
1750 if (0 == total_size) {
1751 return;
1752 }
1753
1754 if (fRec.getHinting() != SkPaint::kSlight_Hinting) {
1755 sk_path_from_gdi_path(path, glyphbuf, total_size);
1756 } else {
1757 //GDI only uses hinted outlines when axis aligned.
1758 UINT format = GGO_NATIVE | GGO_GLYPH_INDEX;
1759
1760 SkAutoSTMalloc<BUFFERSIZE, uint8_t> hintedGlyphbuf(BUFFERSIZE);
1761 DWORD hinted_total_size = getGDIGlyphPath(glyph, format, &hintedGlyphbuf);
1762 if (0 == hinted_total_size) {
1763 return;
1764 }
1765
1766 if (!sk_path_from_gdi_paths(path, glyphbuf, total_size,
1767 GDIGlyphbufferPointIter(hintedGlyphbuf, hinted_total_size)))
1768 {
1769 path->reset();
1770 sk_path_from_gdi_path(path, glyphbuf, total_size);
1771 }
1772 }
1773 }
1774
logfont_for_name(const char * familyName,LOGFONT * lf)1775 static void logfont_for_name(const char* familyName, LOGFONT* lf) {
1776 sk_bzero(lf, sizeof(LOGFONT));
1777 #ifdef UNICODE
1778 // Get the buffer size needed first.
1779 size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName,
1780 -1, NULL, 0);
1781 // Allocate a buffer (str_len already has terminating null
1782 // accounted for).
1783 wchar_t *wideFamilyName = new wchar_t[str_len];
1784 // Now actually convert the string.
1785 ::MultiByteToWideChar(CP_UTF8, 0, familyName, -1,
1786 wideFamilyName, str_len);
1787 ::wcsncpy(lf->lfFaceName, wideFamilyName, LF_FACESIZE - 1);
1788 delete [] wideFamilyName;
1789 lf->lfFaceName[LF_FACESIZE-1] = L'\0';
1790 #else
1791 ::strncpy(lf->lfFaceName, familyName, LF_FACESIZE - 1);
1792 lf->lfFaceName[LF_FACESIZE - 1] = '\0';
1793 #endif
1794 }
1795
onGetFontDescriptor(SkFontDescriptor * desc,bool * isLocalStream) const1796 void LogFontTypeface::onGetFontDescriptor(SkFontDescriptor* desc,
1797 bool* isLocalStream) const {
1798 // Get the actual name of the typeface. The logfont may not know this.
1799 HFONT font = CreateFontIndirect(&fLogFont);
1800
1801 HDC deviceContext = ::CreateCompatibleDC(NULL);
1802 HFONT savefont = (HFONT)SelectObject(deviceContext, font);
1803
1804 SkString familyName;
1805 dcfontname_to_skstring(deviceContext, fLogFont, &familyName);
1806
1807 if (deviceContext) {
1808 ::SelectObject(deviceContext, savefont);
1809 ::DeleteDC(deviceContext);
1810 }
1811 if (font) {
1812 ::DeleteObject(font);
1813 }
1814
1815 desc->setFamilyName(familyName.c_str());
1816 *isLocalStream = this->fSerializeAsStream;
1817 }
1818
getWidthAdvance(HDC hdc,int gId,int16_t * advance)1819 static bool getWidthAdvance(HDC hdc, int gId, int16_t* advance) {
1820 // Initialize the MAT2 structure to the identify transformation matrix.
1821 static const MAT2 mat2 = {SkScalarToFIXED(1), SkScalarToFIXED(0),
1822 SkScalarToFIXED(0), SkScalarToFIXED(1)};
1823 int flags = GGO_METRICS | GGO_GLYPH_INDEX;
1824 GLYPHMETRICS gm;
1825 if (GDI_ERROR == GetGlyphOutline(hdc, gId, flags, &gm, 0, NULL, &mat2)) {
1826 return false;
1827 }
1828 SkASSERT(advance);
1829 *advance = gm.gmCellIncX;
1830 return true;
1831 }
1832
onGetAdvancedTypefaceMetrics(SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,const uint32_t * glyphIDs,uint32_t glyphIDsCount) const1833 SkAdvancedTypefaceMetrics* LogFontTypeface::onGetAdvancedTypefaceMetrics(
1834 SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
1835 const uint32_t* glyphIDs,
1836 uint32_t glyphIDsCount) const {
1837 LOGFONT lf = fLogFont;
1838 SkAdvancedTypefaceMetrics* info = NULL;
1839
1840 HDC hdc = CreateCompatibleDC(NULL);
1841 HFONT font = CreateFontIndirect(&lf);
1842 HFONT savefont = (HFONT)SelectObject(hdc, font);
1843 HFONT designFont = NULL;
1844
1845 const char stem_chars[] = {'i', 'I', '!', '1'};
1846 int16_t min_width;
1847 unsigned glyphCount;
1848
1849 // To request design units, create a logical font whose height is specified
1850 // as unitsPerEm.
1851 OUTLINETEXTMETRIC otm;
1852 unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
1853 if (0 == otmRet) {
1854 call_ensure_accessible(lf);
1855 otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
1856 }
1857 if (!otmRet || !GetTextFace(hdc, LF_FACESIZE, lf.lfFaceName)) {
1858 goto Error;
1859 }
1860 lf.lfHeight = -SkToS32(otm.otmEMSquare);
1861 designFont = CreateFontIndirect(&lf);
1862 SelectObject(hdc, designFont);
1863 if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm)) {
1864 goto Error;
1865 }
1866 glyphCount = calculateGlyphCount(hdc, fLogFont);
1867
1868 info = new SkAdvancedTypefaceMetrics;
1869 info->fEmSize = otm.otmEMSquare;
1870 info->fLastGlyphID = SkToU16(glyphCount - 1);
1871 info->fStyle = 0;
1872 tchar_to_skstring(lf.lfFaceName, &info->fFontName);
1873 info->fFlags = SkAdvancedTypefaceMetrics::kEmpty_FontFlag;
1874 // If bit 1 is set, the font may not be embedded in a document.
1875 // If bit 1 is clear, the font can be embedded.
1876 // If bit 2 is set, the embedding is read-only.
1877 if (otm.otmfsType & 0x1) {
1878 info->fFlags = SkTBitOr<SkAdvancedTypefaceMetrics::FontFlags>(
1879 info->fFlags,
1880 SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag);
1881 }
1882
1883 if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) {
1884 populate_glyph_to_unicode(hdc, glyphCount, &(info->fGlyphToUnicode));
1885 }
1886
1887 if (glyphCount > 0 &&
1888 (otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE)) {
1889 info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
1890 } else {
1891 info->fType = SkAdvancedTypefaceMetrics::kOther_Font;
1892 info->fItalicAngle = 0;
1893 info->fAscent = 0;
1894 info->fDescent = 0;
1895 info->fStemV = 0;
1896 info->fCapHeight = 0;
1897 info->fBBox = SkIRect::MakeEmpty();
1898 goto ReturnInfo;
1899 }
1900
1901 // If this bit is clear the font is a fixed pitch font.
1902 if (!(otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
1903 info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
1904 }
1905 if (otm.otmTextMetrics.tmItalic) {
1906 info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
1907 }
1908 if (otm.otmTextMetrics.tmPitchAndFamily & FF_ROMAN) {
1909 info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
1910 } else if (otm.otmTextMetrics.tmPitchAndFamily & FF_SCRIPT) {
1911 info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
1912 }
1913
1914 // The main italic angle of the font, in tenths of a degree counterclockwise
1915 // from vertical.
1916 info->fItalicAngle = otm.otmItalicAngle / 10;
1917 info->fAscent = SkToS16(otm.otmTextMetrics.tmAscent);
1918 info->fDescent = SkToS16(-otm.otmTextMetrics.tmDescent);
1919 // TODO(ctguil): Use alternate cap height calculation.
1920 // MSDN says otmsCapEmHeight is not support but it is returning a value on
1921 // my Win7 box.
1922 info->fCapHeight = otm.otmsCapEmHeight;
1923 info->fBBox =
1924 SkIRect::MakeLTRB(otm.otmrcFontBox.left, otm.otmrcFontBox.top,
1925 otm.otmrcFontBox.right, otm.otmrcFontBox.bottom);
1926
1927 // Figure out a good guess for StemV - Min width of i, I, !, 1.
1928 // This probably isn't very good with an italic font.
1929 min_width = SHRT_MAX;
1930 info->fStemV = 0;
1931 for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) {
1932 ABC abcWidths;
1933 if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) {
1934 int16_t width = abcWidths.abcB;
1935 if (width > 0 && width < min_width) {
1936 min_width = width;
1937 info->fStemV = min_width;
1938 }
1939 }
1940 }
1941
1942 if (perGlyphInfo & SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) {
1943 if (info->fStyle & SkAdvancedTypefaceMetrics::kFixedPitch_Style) {
1944 appendRange(&info->fGlyphWidths, 0);
1945 info->fGlyphWidths->fAdvance.append(1, &min_width);
1946 finishRange(info->fGlyphWidths.get(), 0,
1947 SkAdvancedTypefaceMetrics::WidthRange::kDefault);
1948 } else {
1949 info->fGlyphWidths.reset(
1950 getAdvanceData(hdc,
1951 glyphCount,
1952 glyphIDs,
1953 glyphIDsCount,
1954 &getWidthAdvance));
1955 }
1956 }
1957
1958 Error:
1959 ReturnInfo:
1960 SelectObject(hdc, savefont);
1961 DeleteObject(designFont);
1962 DeleteObject(font);
1963 DeleteDC(hdc);
1964
1965 return info;
1966 }
1967
1968 //Dummy representation of a Base64 encoded GUID from create_unique_font_name.
1969 #define BASE64_GUID_ID "XXXXXXXXXXXXXXXXXXXXXXXX"
1970 //Length of GUID representation from create_id, including NULL terminator.
1971 #define BASE64_GUID_ID_LEN SK_ARRAY_COUNT(BASE64_GUID_ID)
1972
1973 SK_COMPILE_ASSERT(BASE64_GUID_ID_LEN < LF_FACESIZE, GUID_longer_than_facesize);
1974
1975 /**
1976 NameID 6 Postscript names cannot have the character '/'.
1977 It would be easier to hex encode the GUID, but that is 32 bytes,
1978 and many systems have issues with names longer than 28 bytes.
1979 The following need not be any standard base64 encoding.
1980 The encoded value is never decoded.
1981 */
1982 static const char postscript_safe_base64_encode[] =
1983 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1984 "abcdefghijklmnopqrstuvwxyz"
1985 "0123456789-_=";
1986
1987 /**
1988 Formats a GUID into Base64 and places it into buffer.
1989 buffer should have space for at least BASE64_GUID_ID_LEN characters.
1990 The string will always be null terminated.
1991 XXXXXXXXXXXXXXXXXXXXXXXX0
1992 */
format_guid_b64(const GUID & guid,char * buffer,size_t bufferSize)1993 static void format_guid_b64(const GUID& guid, char* buffer, size_t bufferSize) {
1994 SkASSERT(bufferSize >= BASE64_GUID_ID_LEN);
1995 size_t written = SkBase64::Encode(&guid, sizeof(guid), buffer, postscript_safe_base64_encode);
1996 SkASSERT(written < LF_FACESIZE);
1997 buffer[written] = '\0';
1998 }
1999
2000 /**
2001 Creates a Base64 encoded GUID and places it into buffer.
2002 buffer should have space for at least BASE64_GUID_ID_LEN characters.
2003 The string will always be null terminated.
2004 XXXXXXXXXXXXXXXXXXXXXXXX0
2005 */
create_unique_font_name(char * buffer,size_t bufferSize)2006 static HRESULT create_unique_font_name(char* buffer, size_t bufferSize) {
2007 GUID guid = {};
2008 if (FAILED(CoCreateGuid(&guid))) {
2009 return E_UNEXPECTED;
2010 }
2011 format_guid_b64(guid, buffer, bufferSize);
2012
2013 return S_OK;
2014 }
2015
2016 /**
2017 Introduces a font to GDI. On failure will return NULL. The returned handle
2018 should eventually be passed to RemoveFontMemResourceEx.
2019 */
activate_font(SkData * fontData)2020 static HANDLE activate_font(SkData* fontData) {
2021 DWORD numFonts = 0;
2022 //AddFontMemResourceEx just copies the data, but does not specify const.
2023 HANDLE fontHandle = AddFontMemResourceEx(const_cast<void*>(fontData->data()),
2024 static_cast<DWORD>(fontData->size()),
2025 0,
2026 &numFonts);
2027
2028 if (fontHandle != NULL && numFonts < 1) {
2029 RemoveFontMemResourceEx(fontHandle);
2030 return NULL;
2031 }
2032
2033 return fontHandle;
2034 }
2035
create_from_stream(SkStream * stream)2036 static SkTypeface* create_from_stream(SkStream* stream) {
2037 // Create a unique and unpredictable font name.
2038 // Avoids collisions and access from CSS.
2039 char familyName[BASE64_GUID_ID_LEN];
2040 const int familyNameSize = SK_ARRAY_COUNT(familyName);
2041 if (FAILED(create_unique_font_name(familyName, familyNameSize))) {
2042 return NULL;
2043 }
2044
2045 // Change the name of the font.
2046 SkAutoTUnref<SkData> rewrittenFontData(SkOTUtils::RenameFont(stream, familyName, familyNameSize-1));
2047 if (NULL == rewrittenFontData.get()) {
2048 return NULL;
2049 }
2050
2051 // Register the font with GDI.
2052 HANDLE fontReference = activate_font(rewrittenFontData.get());
2053 if (NULL == fontReference) {
2054 return NULL;
2055 }
2056
2057 // Create the typeface.
2058 LOGFONT lf;
2059 logfont_for_name(familyName, &lf);
2060
2061 return SkCreateFontMemResourceTypefaceFromLOGFONT(lf, fontReference);
2062 }
2063
onOpenStream(int * ttcIndex) const2064 SkStream* LogFontTypeface::onOpenStream(int* ttcIndex) const {
2065 *ttcIndex = 0;
2066
2067 const DWORD kTTCTag =
2068 SkEndian_SwapBE32(SkSetFourByteTag('t', 't', 'c', 'f'));
2069 LOGFONT lf = fLogFont;
2070
2071 HDC hdc = ::CreateCompatibleDC(NULL);
2072 HFONT font = CreateFontIndirect(&lf);
2073 HFONT savefont = (HFONT)SelectObject(hdc, font);
2074
2075 SkMemoryStream* stream = NULL;
2076 DWORD tables[2] = {kTTCTag, 0};
2077 for (int i = 0; i < SK_ARRAY_COUNT(tables); i++) {
2078 DWORD bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0);
2079 if (bufferSize == GDI_ERROR) {
2080 call_ensure_accessible(lf);
2081 bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0);
2082 }
2083 if (bufferSize != GDI_ERROR) {
2084 stream = new SkMemoryStream(bufferSize);
2085 if (GetFontData(hdc, tables[i], 0, (void*)stream->getMemoryBase(), bufferSize)) {
2086 break;
2087 } else {
2088 delete stream;
2089 stream = NULL;
2090 }
2091 }
2092 }
2093
2094 SelectObject(hdc, savefont);
2095 DeleteObject(font);
2096 DeleteDC(hdc);
2097
2098 return stream;
2099 }
2100
bmpCharsToGlyphs(HDC hdc,const WCHAR * bmpChars,int count,uint16_t * glyphs,bool Ox1FHack)2101 static void bmpCharsToGlyphs(HDC hdc, const WCHAR* bmpChars, int count, uint16_t* glyphs,
2102 bool Ox1FHack)
2103 {
2104 DWORD result = GetGlyphIndicesW(hdc, bmpChars, count, glyphs, GGI_MARK_NONEXISTING_GLYPHS);
2105 if (GDI_ERROR == result) {
2106 for (int i = 0; i < count; ++i) {
2107 glyphs[i] = 0;
2108 }
2109 return;
2110 }
2111
2112 if (Ox1FHack) {
2113 for (int i = 0; i < count; ++i) {
2114 if (0xFFFF == glyphs[i] || 0x1F == glyphs[i]) {
2115 glyphs[i] = 0;
2116 }
2117 }
2118 } else {
2119 for (int i = 0; i < count; ++i) {
2120 if (0xFFFF == glyphs[i]){
2121 glyphs[i] = 0;
2122 }
2123 }
2124 }
2125 }
2126
nonBmpCharToGlyph(HDC hdc,SCRIPT_CACHE * scriptCache,const WCHAR utf16[2])2127 static uint16_t nonBmpCharToGlyph(HDC hdc, SCRIPT_CACHE* scriptCache, const WCHAR utf16[2]) {
2128 uint16_t index = 0;
2129 // Use uniscribe to detemine glyph index for non-BMP characters.
2130 static const int numWCHAR = 2;
2131 static const int maxItems = 2;
2132 // MSDN states that this can be NULL, but some things don't work then.
2133 SCRIPT_CONTROL scriptControl = { 0 };
2134 // Add extra item to SCRIPT_ITEM to work around a bug (now documented).
2135 // https://bugzilla.mozilla.org/show_bug.cgi?id=366643
2136 SCRIPT_ITEM si[maxItems + 1];
2137 int numItems;
2138 HRZM(ScriptItemize(utf16, numWCHAR, maxItems, &scriptControl, NULL, si, &numItems),
2139 "Could not itemize character.");
2140
2141 // Sometimes ScriptShape cannot find a glyph for a non-BMP and returns 2 space glyphs.
2142 static const int maxGlyphs = 2;
2143 SCRIPT_VISATTR vsa[maxGlyphs];
2144 WORD outGlyphs[maxGlyphs];
2145 WORD logClust[numWCHAR];
2146 int numGlyphs;
2147 HRZM(ScriptShape(hdc, scriptCache, utf16, numWCHAR, maxGlyphs, &si[0].a,
2148 outGlyphs, logClust, vsa, &numGlyphs),
2149 "Could not shape character.");
2150 if (1 == numGlyphs) {
2151 index = outGlyphs[0];
2152 }
2153 return index;
2154 }
2155
2156 class SkAutoHDC {
2157 public:
SkAutoHDC(const LOGFONT & lf)2158 SkAutoHDC(const LOGFONT& lf)
2159 : fHdc(::CreateCompatibleDC(NULL))
2160 , fFont(::CreateFontIndirect(&lf))
2161 , fSavefont((HFONT)SelectObject(fHdc, fFont))
2162 { }
~SkAutoHDC()2163 ~SkAutoHDC() {
2164 SelectObject(fHdc, fSavefont);
2165 DeleteObject(fFont);
2166 DeleteDC(fHdc);
2167 }
operator HDC()2168 operator HDC() { return fHdc; }
2169 private:
2170 HDC fHdc;
2171 HFONT fFont;
2172 HFONT fSavefont;
2173 };
2174 #define SkAutoHDC(...) SK_REQUIRE_LOCAL_VAR(SkAutoHDC)
2175
onCharsToGlyphs(const void * chars,Encoding encoding,uint16_t userGlyphs[],int glyphCount) const2176 int LogFontTypeface::onCharsToGlyphs(const void* chars, Encoding encoding,
2177 uint16_t userGlyphs[], int glyphCount) const
2178 {
2179 SkAutoHDC hdc(fLogFont);
2180
2181 TEXTMETRIC tm;
2182 if (0 == GetTextMetrics(hdc, &tm)) {
2183 call_ensure_accessible(fLogFont);
2184 if (0 == GetTextMetrics(hdc, &tm)) {
2185 tm.tmPitchAndFamily = TMPF_TRUETYPE;
2186 }
2187 }
2188 bool Ox1FHack = !(tm.tmPitchAndFamily & TMPF_VECTOR) /*&& winVer < Vista */;
2189
2190 SkAutoSTMalloc<256, uint16_t> scratchGlyphs;
2191 uint16_t* glyphs;
2192 if (userGlyphs != NULL) {
2193 glyphs = userGlyphs;
2194 } else {
2195 glyphs = scratchGlyphs.reset(glyphCount);
2196 }
2197
2198 SCRIPT_CACHE sc = 0;
2199 switch (encoding) {
2200 case SkTypeface::kUTF8_Encoding: {
2201 static const int scratchCount = 256;
2202 WCHAR scratch[scratchCount];
2203 int glyphIndex = 0;
2204 const char* currentUtf8 = reinterpret_cast<const char*>(chars);
2205 SkUnichar currentChar;
2206 if (glyphCount) {
2207 currentChar = SkUTF8_NextUnichar(¤tUtf8);
2208 }
2209 while (glyphIndex < glyphCount) {
2210 // Try a run of bmp.
2211 int glyphsLeft = SkTMin(glyphCount - glyphIndex, scratchCount);
2212 int runLength = 0;
2213 while (runLength < glyphsLeft && currentChar <= 0xFFFF) {
2214 scratch[runLength] = static_cast<WCHAR>(currentChar);
2215 ++runLength;
2216 if (runLength < glyphsLeft) {
2217 currentChar = SkUTF8_NextUnichar(¤tUtf8);
2218 }
2219 }
2220 if (runLength) {
2221 bmpCharsToGlyphs(hdc, scratch, runLength, &glyphs[glyphIndex], Ox1FHack);
2222 glyphIndex += runLength;
2223 }
2224
2225 // Try a run of non-bmp.
2226 while (glyphIndex < glyphCount && currentChar > 0xFFFF) {
2227 SkUTF16_FromUnichar(currentChar, reinterpret_cast<uint16_t*>(scratch));
2228 glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, scratch);
2229 ++glyphIndex;
2230 if (glyphIndex < glyphCount) {
2231 currentChar = SkUTF8_NextUnichar(¤tUtf8);
2232 }
2233 }
2234 }
2235 break;
2236 }
2237 case SkTypeface::kUTF16_Encoding: {
2238 int glyphIndex = 0;
2239 const WCHAR* currentUtf16 = reinterpret_cast<const WCHAR*>(chars);
2240 while (glyphIndex < glyphCount) {
2241 // Try a run of bmp.
2242 int glyphsLeft = glyphCount - glyphIndex;
2243 int runLength = 0;
2244 while (runLength < glyphsLeft && !SkUTF16_IsHighSurrogate(currentUtf16[runLength])) {
2245 ++runLength;
2246 }
2247 if (runLength) {
2248 bmpCharsToGlyphs(hdc, currentUtf16, runLength, &glyphs[glyphIndex], Ox1FHack);
2249 glyphIndex += runLength;
2250 currentUtf16 += runLength;
2251 }
2252
2253 // Try a run of non-bmp.
2254 while (glyphIndex < glyphCount && SkUTF16_IsHighSurrogate(*currentUtf16)) {
2255 glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, currentUtf16);
2256 ++glyphIndex;
2257 currentUtf16 += 2;
2258 }
2259 }
2260 break;
2261 }
2262 case SkTypeface::kUTF32_Encoding: {
2263 static const int scratchCount = 256;
2264 WCHAR scratch[scratchCount];
2265 int glyphIndex = 0;
2266 const uint32_t* utf32 = reinterpret_cast<const uint32_t*>(chars);
2267 while (glyphIndex < glyphCount) {
2268 // Try a run of bmp.
2269 int glyphsLeft = SkTMin(glyphCount - glyphIndex, scratchCount);
2270 int runLength = 0;
2271 while (runLength < glyphsLeft && utf32[glyphIndex + runLength] <= 0xFFFF) {
2272 scratch[runLength] = static_cast<WCHAR>(utf32[glyphIndex + runLength]);
2273 ++runLength;
2274 }
2275 if (runLength) {
2276 bmpCharsToGlyphs(hdc, scratch, runLength, &glyphs[glyphIndex], Ox1FHack);
2277 glyphIndex += runLength;
2278 }
2279
2280 // Try a run of non-bmp.
2281 while (glyphIndex < glyphCount && utf32[glyphIndex] > 0xFFFF) {
2282 SkUTF16_FromUnichar(utf32[glyphIndex], reinterpret_cast<uint16_t*>(scratch));
2283 glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, scratch);
2284 ++glyphIndex;
2285 }
2286 }
2287 break;
2288 }
2289 default:
2290 SK_CRASH();
2291 }
2292
2293 if (sc) {
2294 ::ScriptFreeCache(&sc);
2295 }
2296
2297 for (int i = 0; i < glyphCount; ++i) {
2298 if (0 == glyphs[i]) {
2299 return i;
2300 }
2301 }
2302 return glyphCount;
2303 }
2304
onCountGlyphs() const2305 int LogFontTypeface::onCountGlyphs() const {
2306 HDC hdc = ::CreateCompatibleDC(NULL);
2307 HFONT font = CreateFontIndirect(&fLogFont);
2308 HFONT savefont = (HFONT)SelectObject(hdc, font);
2309
2310 unsigned int glyphCount = calculateGlyphCount(hdc, fLogFont);
2311
2312 SelectObject(hdc, savefont);
2313 DeleteObject(font);
2314 DeleteDC(hdc);
2315
2316 return glyphCount;
2317 }
2318
onGetUPEM() const2319 int LogFontTypeface::onGetUPEM() const {
2320 HDC hdc = ::CreateCompatibleDC(NULL);
2321 HFONT font = CreateFontIndirect(&fLogFont);
2322 HFONT savefont = (HFONT)SelectObject(hdc, font);
2323
2324 unsigned int upem = calculateUPEM(hdc, fLogFont);
2325
2326 SelectObject(hdc, savefont);
2327 DeleteObject(font);
2328 DeleteDC(hdc);
2329
2330 return upem;
2331 }
2332
onCreateFamilyNameIterator() const2333 SkTypeface::LocalizedStrings* LogFontTypeface::onCreateFamilyNameIterator() const {
2334 SkTypeface::LocalizedStrings* nameIter =
2335 SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(*this);
2336 if (NULL == nameIter) {
2337 SkString familyName;
2338 this->getFamilyName(&familyName);
2339 SkString language("und"); //undetermined
2340 nameIter = new SkOTUtils::LocalizedStrings_SingleName(familyName, language);
2341 }
2342 return nameIter;
2343 }
2344
onGetTableTags(SkFontTableTag tags[]) const2345 int LogFontTypeface::onGetTableTags(SkFontTableTag tags[]) const {
2346 SkSFNTHeader header;
2347 if (sizeof(header) != this->onGetTableData(0, 0, sizeof(header), &header)) {
2348 return 0;
2349 }
2350
2351 int numTables = SkEndian_SwapBE16(header.numTables);
2352
2353 if (tags) {
2354 size_t size = numTables * sizeof(SkSFNTHeader::TableDirectoryEntry);
2355 SkAutoSTMalloc<0x20, SkSFNTHeader::TableDirectoryEntry> dir(numTables);
2356 if (size != this->onGetTableData(0, sizeof(header), size, dir.get())) {
2357 return 0;
2358 }
2359
2360 for (int i = 0; i < numTables; ++i) {
2361 tags[i] = SkEndian_SwapBE32(dir[i].tag);
2362 }
2363 }
2364 return numTables;
2365 }
2366
onGetTableData(SkFontTableTag tag,size_t offset,size_t length,void * data) const2367 size_t LogFontTypeface::onGetTableData(SkFontTableTag tag, size_t offset,
2368 size_t length, void* data) const
2369 {
2370 LOGFONT lf = fLogFont;
2371
2372 HDC hdc = ::CreateCompatibleDC(NULL);
2373 HFONT font = CreateFontIndirect(&lf);
2374 HFONT savefont = (HFONT)SelectObject(hdc, font);
2375
2376 tag = SkEndian_SwapBE32(tag);
2377 if (NULL == data) {
2378 length = 0;
2379 }
2380 DWORD bufferSize = GetFontData(hdc, tag, (DWORD) offset, data, (DWORD) length);
2381 if (bufferSize == GDI_ERROR) {
2382 call_ensure_accessible(lf);
2383 bufferSize = GetFontData(hdc, tag, (DWORD) offset, data, (DWORD) length);
2384 }
2385
2386 SelectObject(hdc, savefont);
2387 DeleteObject(font);
2388 DeleteDC(hdc);
2389
2390 return bufferSize == GDI_ERROR ? 0 : bufferSize;
2391 }
2392
onCreateScalerContext(const SkDescriptor * desc) const2393 SkScalerContext* LogFontTypeface::onCreateScalerContext(const SkDescriptor* desc) const {
2394 SkScalerContext_GDI* ctx = SkNEW_ARGS(SkScalerContext_GDI,
2395 (const_cast<LogFontTypeface*>(this), desc));
2396 if (!ctx->isValid()) {
2397 SkDELETE(ctx);
2398 ctx = NULL;
2399 }
2400 return ctx;
2401 }
2402
onFilterRec(SkScalerContextRec * rec) const2403 void LogFontTypeface::onFilterRec(SkScalerContextRec* rec) const {
2404 if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag ||
2405 rec->fFlags & SkScalerContext::kLCD_Vertical_Flag)
2406 {
2407 rec->fMaskFormat = SkMask::kA8_Format;
2408 rec->fFlags |= SkScalerContext::kGenA8FromLCD_Flag;
2409 }
2410
2411 unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag |
2412 SkScalerContext::kForceAutohinting_Flag |
2413 SkScalerContext::kEmbeddedBitmapText_Flag |
2414 SkScalerContext::kEmbolden_Flag |
2415 SkScalerContext::kLCD_BGROrder_Flag |
2416 SkScalerContext::kLCD_Vertical_Flag;
2417 rec->fFlags &= ~flagsWeDontSupport;
2418
2419 SkPaint::Hinting h = rec->getHinting();
2420 switch (h) {
2421 case SkPaint::kNo_Hinting:
2422 break;
2423 case SkPaint::kSlight_Hinting:
2424 // Only do slight hinting when axis aligned.
2425 // TODO: re-enable slight hinting when FontHostTest can pass.
2426 //if (!isAxisAligned(*rec)) {
2427 h = SkPaint::kNo_Hinting;
2428 //}
2429 break;
2430 case SkPaint::kNormal_Hinting:
2431 case SkPaint::kFull_Hinting:
2432 // TODO: need to be able to distinguish subpixel positioned glyphs
2433 // and linear metrics.
2434 //rec->fFlags &= ~SkScalerContext::kSubpixelPositioning_Flag;
2435 h = SkPaint::kNormal_Hinting;
2436 break;
2437 default:
2438 SkDEBUGFAIL("unknown hinting");
2439 }
2440 //TODO: if this is a bitmap font, squash hinting and subpixel.
2441 rec->setHinting(h);
2442
2443 // turn this off since GDI might turn A8 into BW! Need a bigger fix.
2444 #if 0
2445 // Disable LCD when rotated, since GDI's output is ugly
2446 if (isLCD(*rec) && !isAxisAligned(*rec)) {
2447 rec->fMaskFormat = SkMask::kA8_Format;
2448 }
2449 #endif
2450
2451 if (!fCanBeLCD && isLCD(*rec)) {
2452 rec->fMaskFormat = SkMask::kA8_Format;
2453 rec->fFlags &= ~SkScalerContext::kGenA8FromLCD_Flag;
2454 }
2455 }
2456
2457 ///////////////////////////////////////////////////////////////////////////////
2458
2459 #include "SkFontMgr.h"
2460 #include "SkDataTable.h"
2461
valid_logfont_for_enum(const LOGFONT & lf)2462 static bool valid_logfont_for_enum(const LOGFONT& lf) {
2463 // TODO: Vector FON is unsupported and should not be listed.
2464 return
2465 // Ignore implicit vertical variants.
2466 lf.lfFaceName[0] && lf.lfFaceName[0] != '@'
2467
2468 // DEFAULT_CHARSET is used to get all fonts, but also implies all
2469 // character sets. Filter assuming all fonts support ANSI_CHARSET.
2470 && ANSI_CHARSET == lf.lfCharSet
2471 ;
2472 }
2473
2474 /** An EnumFontFamExProc implementation which interprets builderParam as
2475 * an SkTDArray<ENUMLOGFONTEX>* and appends logfonts which
2476 * pass the valid_logfont_for_enum predicate.
2477 */
enum_family_proc(const LOGFONT * lf,const TEXTMETRIC *,DWORD fontType,LPARAM builderParam)2478 static int CALLBACK enum_family_proc(const LOGFONT* lf, const TEXTMETRIC*,
2479 DWORD fontType, LPARAM builderParam) {
2480 if (valid_logfont_for_enum(*lf)) {
2481 SkTDArray<ENUMLOGFONTEX>* array = (SkTDArray<ENUMLOGFONTEX>*)builderParam;
2482 *array->append() = *(ENUMLOGFONTEX*)lf;
2483 }
2484 return 1; // non-zero means continue
2485 }
2486
compute_fontstyle(const LOGFONT & lf)2487 static SkFontStyle compute_fontstyle(const LOGFONT& lf) {
2488 return SkFontStyle(lf.lfWeight, SkFontStyle::kNormal_Width,
2489 lf.lfItalic ? SkFontStyle::kItalic_Slant
2490 : SkFontStyle::kUpright_Slant);
2491 }
2492
2493 class SkFontStyleSetGDI : public SkFontStyleSet {
2494 public:
SkFontStyleSetGDI(const TCHAR familyName[])2495 SkFontStyleSetGDI(const TCHAR familyName[]) {
2496 LOGFONT lf;
2497 sk_bzero(&lf, sizeof(lf));
2498 lf.lfCharSet = DEFAULT_CHARSET;
2499 _tcscpy_s(lf.lfFaceName, familyName);
2500
2501 HDC hdc = ::CreateCompatibleDC(NULL);
2502 ::EnumFontFamiliesEx(hdc, &lf, enum_family_proc, (LPARAM)&fArray, 0);
2503 ::DeleteDC(hdc);
2504 }
2505
count()2506 virtual int count() SK_OVERRIDE {
2507 return fArray.count();
2508 }
2509
getStyle(int index,SkFontStyle * fs,SkString * styleName)2510 virtual void getStyle(int index, SkFontStyle* fs, SkString* styleName) SK_OVERRIDE {
2511 if (fs) {
2512 *fs = compute_fontstyle(fArray[index].elfLogFont);
2513 }
2514 if (styleName) {
2515 const ENUMLOGFONTEX& ref = fArray[index];
2516 // For some reason, ENUMLOGFONTEX and LOGFONT disagree on their type in the
2517 // non-unicode version.
2518 // ENUMLOGFONTEX uses BYTE
2519 // LOGFONT uses CHAR
2520 // Here we assert they that the style name is logically the same (size) as
2521 // a TCHAR, so we can use the same converter function.
2522 SkASSERT(sizeof(TCHAR) == sizeof(ref.elfStyle[0]));
2523 tchar_to_skstring((const TCHAR*)ref.elfStyle, styleName);
2524 }
2525 }
2526
createTypeface(int index)2527 virtual SkTypeface* createTypeface(int index) SK_OVERRIDE {
2528 return SkCreateTypefaceFromLOGFONT(fArray[index].elfLogFont);
2529 }
2530
matchStyle(const SkFontStyle & pattern)2531 virtual SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE {
2532 // todo:
2533 return SkCreateTypefaceFromLOGFONT(fArray[0].elfLogFont);
2534 }
2535
2536 private:
2537 SkTDArray<ENUMLOGFONTEX> fArray;
2538 };
2539
2540 class SkFontMgrGDI : public SkFontMgr {
2541 public:
SkFontMgrGDI()2542 SkFontMgrGDI() {
2543 LOGFONT lf;
2544 sk_bzero(&lf, sizeof(lf));
2545 lf.lfCharSet = DEFAULT_CHARSET;
2546
2547 HDC hdc = ::CreateCompatibleDC(NULL);
2548 ::EnumFontFamiliesEx(hdc, &lf, enum_family_proc, (LPARAM)&fLogFontArray, 0);
2549 ::DeleteDC(hdc);
2550 }
2551
2552 protected:
onCountFamilies() const2553 virtual int onCountFamilies() const SK_OVERRIDE {
2554 return fLogFontArray.count();
2555 }
2556
onGetFamilyName(int index,SkString * familyName) const2557 virtual void onGetFamilyName(int index, SkString* familyName) const SK_OVERRIDE {
2558 SkASSERT((unsigned)index < (unsigned)fLogFontArray.count());
2559 tchar_to_skstring(fLogFontArray[index].elfLogFont.lfFaceName, familyName);
2560 }
2561
onCreateStyleSet(int index) const2562 virtual SkFontStyleSet* onCreateStyleSet(int index) const SK_OVERRIDE {
2563 SkASSERT((unsigned)index < (unsigned)fLogFontArray.count());
2564 return SkNEW_ARGS(SkFontStyleSetGDI, (fLogFontArray[index].elfLogFont.lfFaceName));
2565 }
2566
onMatchFamily(const char familyName[]) const2567 virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const SK_OVERRIDE {
2568 if (NULL == familyName) {
2569 familyName = ""; // do we need this check???
2570 }
2571 LOGFONT lf;
2572 logfont_for_name(familyName, &lf);
2573 return SkNEW_ARGS(SkFontStyleSetGDI, (lf.lfFaceName));
2574 }
2575
onMatchFamilyStyle(const char familyName[],const SkFontStyle & fontstyle) const2576 virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
2577 const SkFontStyle& fontstyle) const SK_OVERRIDE {
2578 // could be in base impl
2579 SkAutoTUnref<SkFontStyleSet> sset(this->matchFamily(familyName));
2580 return sset->matchStyle(fontstyle);
2581 }
2582
onMatchFaceStyle(const SkTypeface * familyMember,const SkFontStyle & fontstyle) const2583 virtual SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember,
2584 const SkFontStyle& fontstyle) const SK_OVERRIDE {
2585 // could be in base impl
2586 SkString familyName;
2587 ((LogFontTypeface*)familyMember)->getFamilyName(&familyName);
2588 return this->matchFamilyStyle(familyName.c_str(), fontstyle);
2589 }
2590
onCreateFromStream(SkStream * stream,int ttcIndex) const2591 virtual SkTypeface* onCreateFromStream(SkStream* stream, int ttcIndex) const SK_OVERRIDE {
2592 return create_from_stream(stream);
2593 }
2594
onCreateFromData(SkData * data,int ttcIndex) const2595 virtual SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const SK_OVERRIDE {
2596 // could be in base impl
2597 SkAutoTUnref<SkStream> stream(SkNEW_ARGS(SkMemoryStream, (data)));
2598 return this->createFromStream(stream);
2599 }
2600
onCreateFromFile(const char path[],int ttcIndex) const2601 virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const SK_OVERRIDE {
2602 // could be in base impl
2603 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path));
2604 return this->createFromStream(stream);
2605 }
2606
onLegacyCreateTypeface(const char familyName[],unsigned styleBits) const2607 virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
2608 unsigned styleBits) const SK_OVERRIDE {
2609 LOGFONT lf;
2610 if (NULL == familyName) {
2611 lf = get_default_font();
2612 } else {
2613 logfont_for_name(familyName, &lf);
2614 }
2615 setStyle(&lf, (SkTypeface::Style)styleBits);
2616 return SkCreateTypefaceFromLOGFONT(lf);
2617 }
2618
2619 private:
2620 SkTDArray<ENUMLOGFONTEX> fLogFontArray;
2621 };
2622
2623 ///////////////////////////////////////////////////////////////////////////////
2624
SkFontMgr_New_GDI()2625 SkFontMgr* SkFontMgr_New_GDI() {
2626 return SkNEW(SkFontMgrGDI);
2627 }
2628