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