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