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