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/SkFontTypes.h"
14 #include "include/core/SkPath.h"
15 #include "include/core/SkStream.h"
16 #include "include/core/SkString.h"
17 #include "include/ports/SkTypeface_win.h"
18 #include "include/private/SkColorData.h"
19 #include "include/private/base/SkMacros.h"
20 #include "include/private/base/SkOnce.h"
21 #include "include/private/base/SkTDArray.h"
22 #include "include/private/base/SkTemplates.h"
23 #include "include/private/base/SkTo.h"
24 #include "src/base/SkBase64.h"
25 #include "src/base/SkLeanWindows.h"
26 #include "src/base/SkUTF.h"
27 #include "src/core/SkAdvancedTypefaceMetrics.h"
28 #include "src/core/SkDescriptor.h"
29 #include "src/core/SkFontDescriptor.h"
30 #include "src/core/SkGlyph.h"
31 #include "src/core/SkMaskGamma.h"
32 #include "src/core/SkStrikeCache.h"
33 #include "src/core/SkTypefaceCache.h"
34 #include "src/sfnt/SkOTTable_OS_2.h"
35 #include "src/sfnt/SkOTTable_maxp.h"
36 #include "src/sfnt/SkOTTable_name.h"
37 #include "src/sfnt/SkOTUtils.h"
38 #include "src/sfnt/SkSFNTHeader.h"
39 #include "src/utils/SkMatrix22.h"
40 #include "src/utils/win/SkHRESULT.h"
41
42 #include <tchar.h>
43 #include <usp10.h>
44 #include <objbase.h>
45
46 using namespace skia_private;
47
48 namespace {
49 static inline const constexpr bool kSkShowTextBlitCoverage = false;
50 }
51
52 static void (*gEnsureLOGFONTAccessibleProc)(const LOGFONT&);
53
SkTypeface_SetEnsureLOGFONTAccessibleProc(void (* proc)(const LOGFONT &))54 void SkTypeface_SetEnsureLOGFONTAccessibleProc(void (*proc)(const LOGFONT&)) {
55 gEnsureLOGFONTAccessibleProc = proc;
56 }
57
call_ensure_accessible(const LOGFONT & lf)58 static void call_ensure_accessible(const LOGFONT& lf) {
59 if (gEnsureLOGFONTAccessibleProc) {
60 gEnsureLOGFONTAccessibleProc(lf);
61 }
62 }
63
64 ///////////////////////////////////////////////////////////////////////////////
65
66 // always packed xxRRGGBB
67 typedef uint32_t SkGdiRGB;
68
69 // define this in your Makefile or .gyp to enforce AA requests
70 // which GDI ignores at small sizes. This flag guarantees AA
71 // for rotated text, regardless of GDI's notions.
72 //#define SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
73
isLCD(const SkScalerContextRec & rec)74 static bool isLCD(const SkScalerContextRec& rec) {
75 return SkMask::kLCD16_Format == rec.fMaskFormat;
76 }
77
bothZero(SkScalar a,SkScalar b)78 static bool bothZero(SkScalar a, SkScalar b) {
79 return 0 == a && 0 == b;
80 }
81
82 // returns false if there is any non-90-rotation or skew
isAxisAligned(const SkScalerContextRec & rec)83 static bool isAxisAligned(const SkScalerContextRec& rec) {
84 return 0 == rec.fPreSkewX &&
85 (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
86 bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
87 }
88
needToRenderWithSkia(const SkScalerContextRec & rec)89 static bool needToRenderWithSkia(const SkScalerContextRec& rec) {
90 #ifdef SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
91 // What we really want to catch is when GDI will ignore the AA request and give
92 // us BW instead. Smallish rotated text is one heuristic, so this code is just
93 // an approximation. We shouldn't need to do this for larger sizes, but at those
94 // sizes, the quality difference gets less and less between our general
95 // scanconverter and GDI's.
96 if (SkMask::kA8_Format == rec.fMaskFormat && !isAxisAligned(rec)) {
97 return true;
98 }
99 #endif
100 return rec.getHinting() == SkFontHinting::kNone || rec.getHinting() == SkFontHinting::kSlight;
101 }
102
tchar_to_skstring(const TCHAR t[],SkString * s)103 static void tchar_to_skstring(const TCHAR t[], SkString* s) {
104 #ifdef UNICODE
105 size_t sSize = WideCharToMultiByte(CP_UTF8, 0, t, -1, nullptr, 0, nullptr, nullptr);
106 s->resize(sSize);
107 WideCharToMultiByte(CP_UTF8, 0, t, -1, s->data(), sSize, nullptr, nullptr);
108 #else
109 s->set(t);
110 #endif
111 }
112
dcfontname_to_skstring(HDC deviceContext,const LOGFONT & lf,SkString * familyName)113 static void dcfontname_to_skstring(HDC deviceContext, const LOGFONT& lf, SkString* familyName) {
114 int fontNameLen; //length of fontName in TCHARS.
115 if (0 == (fontNameLen = GetTextFace(deviceContext, 0, nullptr))) {
116 call_ensure_accessible(lf);
117 if (0 == (fontNameLen = GetTextFace(deviceContext, 0, nullptr))) {
118 fontNameLen = 0;
119 }
120 }
121
122 AutoSTArray<LF_FULLFACESIZE, TCHAR> fontName(fontNameLen+1);
123 if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) {
124 call_ensure_accessible(lf);
125 if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) {
126 fontName[0] = 0;
127 }
128 }
129
130 tchar_to_skstring(fontName.get(), familyName);
131 }
132
make_canonical(LOGFONT * lf)133 static void make_canonical(LOGFONT* lf) {
134 lf->lfHeight = -64;
135 lf->lfWidth = 0; // lfWidth is related to lfHeight, not to the OS/2::usWidthClass.
136 lf->lfQuality = CLEARTYPE_QUALITY;//PROOF_QUALITY;
137 lf->lfCharSet = DEFAULT_CHARSET;
138 // lf->lfClipPrecision = 64;
139 }
140
get_style(const LOGFONT & lf)141 static SkFontStyle get_style(const LOGFONT& lf) {
142 return SkFontStyle(lf.lfWeight,
143 SkFontStyle::kNormal_Width,
144 lf.lfItalic ? SkFontStyle::kItalic_Slant : SkFontStyle::kUpright_Slant);
145 }
146
SkFixedToFIXED(SkFixed x)147 static inline FIXED SkFixedToFIXED(SkFixed x) {
148 return *(FIXED*)(&x);
149 }
SkFIXEDToFixed(FIXED x)150 static inline SkFixed SkFIXEDToFixed(FIXED x) {
151 return *(SkFixed*)(&x);
152 }
153
SkScalarToFIXED(SkScalar x)154 static inline FIXED SkScalarToFIXED(SkScalar x) {
155 return SkFixedToFIXED(SkScalarToFixed(x));
156 }
157
SkFIXEDToScalar(FIXED x)158 static inline SkScalar SkFIXEDToScalar(FIXED x) {
159 return SkFixedToScalar(SkFIXEDToFixed(x));
160 }
161
calculateGlyphCount(HDC hdc,const LOGFONT & lf)162 static unsigned calculateGlyphCount(HDC hdc, const LOGFONT& lf) {
163 TEXTMETRIC textMetric;
164 if (0 == GetTextMetrics(hdc, &textMetric)) {
165 textMetric.tmPitchAndFamily = TMPF_VECTOR;
166 call_ensure_accessible(lf);
167 GetTextMetrics(hdc, &textMetric);
168 }
169
170 if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) {
171 return textMetric.tmLastChar;
172 }
173
174 // The 'maxp' table stores the number of glyphs at offset 4, in 2 bytes.
175 uint16_t glyphs;
176 if (GDI_ERROR != GetFontData(hdc, SkOTTableMaximumProfile::TAG, 4, &glyphs, sizeof(glyphs))) {
177 return SkEndian_SwapBE16(glyphs);
178 }
179
180 // Binary search for glyph count.
181 static const MAT2 mat2 = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
182 int32_t max = UINT16_MAX + 1;
183 int32_t min = 0;
184 GLYPHMETRICS gm;
185 while (min < max) {
186 int32_t mid = min + ((max - min) / 2);
187 if (GetGlyphOutlineW(hdc, mid, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0,
188 nullptr, &mat2) == GDI_ERROR) {
189 max = mid;
190 } else {
191 min = mid + 1;
192 }
193 }
194 SkASSERT(min == max);
195 return min;
196 }
197
calculateUPEM(HDC hdc,const LOGFONT & lf)198 static unsigned calculateUPEM(HDC hdc, const LOGFONT& lf) {
199 TEXTMETRIC textMetric;
200 if (0 == GetTextMetrics(hdc, &textMetric)) {
201 textMetric.tmPitchAndFamily = TMPF_VECTOR;
202 call_ensure_accessible(lf);
203 GetTextMetrics(hdc, &textMetric);
204 }
205
206 if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) {
207 return textMetric.tmMaxCharWidth;
208 }
209
210 OUTLINETEXTMETRIC otm;
211 unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
212 if (0 == otmRet) {
213 call_ensure_accessible(lf);
214 otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
215 }
216
217 return (0 == otmRet) ? 0 : otm.otmEMSquare;
218 }
219
220 class SkAutoHDC {
221 public:
SkAutoHDC(const LOGFONT & lf)222 explicit SkAutoHDC(const LOGFONT& lf)
223 : fHdc(::CreateCompatibleDC(nullptr))
224 , fFont(::CreateFontIndirect(&lf))
225 , fSavefont((HFONT)::SelectObject(fHdc, fFont))
226 { }
~SkAutoHDC()227 ~SkAutoHDC() {
228 if (fHdc) {
229 ::SelectObject(fHdc, fSavefont);
230 ::DeleteDC(fHdc);
231 }
232 if (fFont) {
233 ::DeleteObject(fFont);
234 }
235 }
operator HDC()236 operator HDC() { return fHdc; }
237 private:
238 HDC fHdc;
239 HFONT fFont;
240 HFONT fSavefont;
241 };
242
243 class LogFontTypeface : public SkTypeface {
244 public:
LogFontTypeface(const SkFontStyle & style,const LOGFONT & lf,bool serializeAsStream)245 LogFontTypeface(const SkFontStyle& style, const LOGFONT& lf, bool serializeAsStream)
246 : SkTypeface(style, false)
247 , fLogFont(lf)
248 , fSerializeAsStream(serializeAsStream)
249 {
250 SkAutoHDC hdc(fLogFont);
251 TEXTMETRIC textMetric;
252 if (0 == GetTextMetrics(hdc, &textMetric)) {
253 call_ensure_accessible(lf);
254 if (0 == GetTextMetrics(hdc, &textMetric)) {
255 textMetric.tmPitchAndFamily = TMPF_TRUETYPE;
256 }
257 }
258
259 // The fixed pitch bit is set if the font is *not* fixed pitch.
260 this->setIsFixedPitch((textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0);
261 this->setFontStyle(SkFontStyle(textMetric.tmWeight, style.width(), style.slant()));
262
263 // Used a logfont on a memory context, should never get a device font.
264 // Therefore all TMPF_DEVICE will be PostScript (cubic) fonts.
265 // If the font has cubic outlines, it will not be rendered with ClearType.
266 fCanBeLCD = !((textMetric.tmPitchAndFamily & TMPF_VECTOR) &&
267 (textMetric.tmPitchAndFamily & TMPF_DEVICE));
268 }
269
270 LOGFONT fLogFont;
271 bool fSerializeAsStream;
272 bool fCanBeLCD;
273
Make(const LOGFONT & lf)274 static sk_sp<LogFontTypeface> Make(const LOGFONT& lf) {
275 return sk_sp<LogFontTypeface>(new LogFontTypeface(get_style(lf), lf, false));
276 }
277
EnsureAccessible(const SkTypeface * face)278 static void EnsureAccessible(const SkTypeface* face) {
279 call_ensure_accessible(static_cast<const LogFontTypeface*>(face)->fLogFont);
280 }
281
282 protected:
283 std::unique_ptr<SkStreamAsset> onOpenStream(int* ttcIndex) const override;
284 sk_sp<SkTypeface> onMakeClone(const SkFontArguments& args) const override;
285 std::unique_ptr<SkScalerContext> onCreateScalerContext(const SkScalerContextEffects&,
286 const SkDescriptor*) const override;
287 void onFilterRec(SkScalerContextRec*) const override;
288 void getGlyphToUnicodeMap(SkUnichar*) const override;
289 std::unique_ptr<SkAdvancedTypefaceMetrics> onGetAdvancedMetrics() const override;
290 void onGetFontDescriptor(SkFontDescriptor*, bool*) const override;
291 void onCharsToGlyphs(const SkUnichar* chars, int count, SkGlyphID glyphs[]) const override;
292 int onCountGlyphs() const override;
293 void getPostScriptGlyphNames(SkString*) const override;
294 int onGetUPEM() const override;
295 void onGetFamilyName(SkString* familyName) const override;
onGetPostScriptName(SkString *) const296 bool onGetPostScriptName(SkString*) const override { return false; }
297 SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override;
onGlyphMaskNeedsCurrentColor() const298 bool onGlyphMaskNeedsCurrentColor() const override { return false; }
onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],int coordinateCount) const299 int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
300 int coordinateCount) const override
301 {
302 return -1;
303 }
onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],int parameterCount) const304 int onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[],
305 int parameterCount) const override
306 {
307 return -1;
308 }
309 int onGetTableTags(SkFontTableTag tags[]) const override;
310 size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void* data) const override;
311 sk_sp<SkData> onCopyTableData(SkFontTableTag) const override;
312 };
313
314 class FontMemResourceTypeface : public LogFontTypeface {
315 public:
316 /**
317 * The created FontMemResourceTypeface takes ownership of fontMemResource.
318 */
Make(const LOGFONT & lf,HANDLE fontMemResource)319 static sk_sp<FontMemResourceTypeface> Make(const LOGFONT& lf, HANDLE fontMemResource) {
320 return sk_sp<FontMemResourceTypeface>(
321 new FontMemResourceTypeface(get_style(lf), lf, fontMemResource));
322 }
323
324 protected:
weak_dispose() const325 void weak_dispose() const override {
326 RemoveFontMemResourceEx(fFontMemResource);
327 INHERITED::weak_dispose();
328 }
329
330 private:
331 /**
332 * Takes ownership of fontMemResource.
333 */
FontMemResourceTypeface(const SkFontStyle & style,const LOGFONT & lf,HANDLE fontMemResource)334 FontMemResourceTypeface(const SkFontStyle& style, const LOGFONT& lf, HANDLE fontMemResource)
335 : LogFontTypeface(style, lf, true), fFontMemResource(fontMemResource)
336 { }
337
338 HANDLE fFontMemResource;
339
340 using INHERITED = LogFontTypeface;
341 };
342
get_default_font()343 static const LOGFONT& get_default_font() {
344 static LOGFONT gDefaultFont;
345 return gDefaultFont;
346 }
347
FindByLogFont(SkTypeface * face,void * ctx)348 static bool FindByLogFont(SkTypeface* face, void* ctx) {
349 LogFontTypeface* lface = static_cast<LogFontTypeface*>(face);
350 const LOGFONT* lf = reinterpret_cast<const LOGFONT*>(ctx);
351
352 return !memcmp(&lface->fLogFont, lf, sizeof(LOGFONT));
353 }
354
355 /**
356 * This is public. It first searches the cache, and if a match is not found,
357 * it creates a new face.
358 */
SkCreateTypefaceFromLOGFONT(const LOGFONT & origLF)359 sk_sp<SkTypeface> SkCreateTypefaceFromLOGFONT(const LOGFONT& origLF) {
360 LOGFONT lf = origLF;
361 make_canonical(&lf);
362 sk_sp<SkTypeface> face = SkTypefaceCache::FindByProcAndRef(FindByLogFont, &lf);
363 if (!face) {
364 face = LogFontTypeface::Make(lf);
365 SkTypefaceCache::Add(face);
366 }
367 return face;
368 }
369
370 /**
371 * The created SkTypeface takes ownership of fontMemResource.
372 */
SkCreateFontMemResourceTypefaceFromLOGFONT(const LOGFONT & origLF,HANDLE fontMemResource)373 sk_sp<SkTypeface> SkCreateFontMemResourceTypefaceFromLOGFONT(const LOGFONT& origLF, HANDLE fontMemResource) {
374 LOGFONT lf = origLF;
375 make_canonical(&lf);
376 // We'll never get a cache hit, so no point in putting this in SkTypefaceCache.
377 return FontMemResourceTypeface::Make(lf, fontMemResource);
378 }
379
380 /**
381 * This is public
382 */
SkLOGFONTFromTypeface(const SkTypeface * face,LOGFONT * lf)383 void SkLOGFONTFromTypeface(const SkTypeface* face, LOGFONT* lf) {
384 if (nullptr == face) {
385 *lf = get_default_font();
386 } else {
387 *lf = static_cast<const LogFontTypeface*>(face)->fLogFont;
388 }
389 }
390
391 // Construct Glyph to Unicode table.
392 // Unicode code points that require conjugate pairs in utf16 are not
393 // supported.
394 // TODO(arthurhsu): Add support for conjugate pairs. It looks like that may
395 // require parsing the TTF cmap table (platform 4, encoding 12) directly instead
396 // of calling GetFontUnicodeRange().
populate_glyph_to_unicode(HDC fontHdc,const unsigned glyphCount,SkUnichar * glyphToUnicode)397 static void populate_glyph_to_unicode(HDC fontHdc, const unsigned glyphCount,
398 SkUnichar* glyphToUnicode) {
399 sk_bzero(glyphToUnicode, sizeof(SkUnichar) * glyphCount);
400 DWORD glyphSetBufferSize = GetFontUnicodeRanges(fontHdc, nullptr);
401 if (!glyphSetBufferSize) {
402 return;
403 }
404
405 std::unique_ptr<BYTE[]> glyphSetBuffer(new BYTE[glyphSetBufferSize]);
406 GLYPHSET* glyphSet =
407 reinterpret_cast<LPGLYPHSET>(glyphSetBuffer.get());
408 if (GetFontUnicodeRanges(fontHdc, glyphSet) != glyphSetBufferSize) {
409 return;
410 }
411
412 for (DWORD i = 0; i < glyphSet->cRanges; ++i) {
413 // There is no guarantee that within a Unicode range, the corresponding
414 // glyph id in a font file are continuous. So, even if we have ranges,
415 // we can't just use the first and last entry of the range to compute
416 // result. We need to enumerate them one by one.
417 int count = glyphSet->ranges[i].cGlyphs;
418 AutoTArray<WCHAR> chars(count + 1);
419 chars[count] = 0; // termintate string
420 AutoTArray<WORD> glyph(count);
421 for (USHORT j = 0; j < count; ++j) {
422 chars[j] = glyphSet->ranges[i].wcLow + j;
423 }
424 GetGlyphIndicesW(fontHdc, chars.get(), count, glyph.get(),
425 GGI_MARK_NONEXISTING_GLYPHS);
426 // If the glyph ID is valid, and the glyph is not mapped, then we will
427 // fill in the char id into the vector. If the glyph is mapped already,
428 // skip it.
429 // TODO(arthurhsu): better improve this. e.g. Get all used char ids from
430 // font cache, then generate this mapping table from there. It's
431 // unlikely to have collisions since glyph reuse happens mostly for
432 // different Unicode pages.
433 for (USHORT j = 0; j < count; ++j) {
434 if (glyph[j] != 0xFFFF && glyph[j] < glyphCount && glyphToUnicode[glyph[j]] == 0) {
435 glyphToUnicode[glyph[j]] = chars[j];
436 }
437 }
438 }
439 }
440
441 //////////////////////////////////////////////////////////////////////////////////////
442
alignTo32(int n)443 static int alignTo32(int n) {
444 return (n + 31) & ~31;
445 }
446
447 struct MyBitmapInfo : public BITMAPINFO {
448 RGBQUAD fMoreSpaceForColors[1];
449 };
450
451 class HDCOffscreen {
452 public:
453 HDCOffscreen() = default;
454
~HDCOffscreen()455 ~HDCOffscreen() {
456 if (fDC) {
457 ::SelectObject(fDC, fSavefont);
458 ::DeleteDC(fDC);
459 }
460 if (fBM) {
461 DeleteObject(fBM);
462 }
463 }
464
init(HFONT font,const XFORM & xform)465 void init(HFONT font, const XFORM& xform) {
466 fFont = font;
467 fXform = xform;
468 }
469
470 void* draw(const SkGlyph&, bool isBW, size_t* srcRBPtr);
471
472 private:
473 HDC fDC{nullptr};
474 HFONT fSavefont{nullptr};
475 HBITMAP fBM{nullptr};
476 HFONT fFont{nullptr};
477 XFORM fXform{1, 0, 0, 1, 0, 0};
478 void* fBits{nullptr}; // points into fBM
479 int fWidth{0};
480 int fHeight{0};
481 bool fIsBW{false};
482 };
483
draw(const SkGlyph & glyph,bool isBW,size_t * srcRBPtr)484 void* HDCOffscreen::draw(const SkGlyph& glyph, bool isBW, 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 (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 GlyphMetrics generateMetrics(const SkGlyph&, SkArenaAlloc*) override;
576 void generateImage(const SkGlyph&, void* imageBuffer) override;
577 bool generatePath(const SkGlyph& glyph, SkPath* path, bool* modified) override;
578 void generateFontMetrics(SkFontMetrics*) override;
579
580 private:
581 DWORD getGDIGlyphPath(SkGlyphID glyph, UINT flags,
582 AutoSTMalloc<BUFFERSIZE, uint8_t>* glyphbuf);
583 template<bool APPLY_PREBLEND>
584 static void RGBToA8(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
585 const SkGlyph& glyph, void* imageBuffer, const uint8_t* table8);
586
587 template<bool APPLY_PREBLEND>
588 static void RGBToLcd16(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph,
589 void* imageBuffer,
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
generateMetrics(const SkGlyph & glyph,SkArenaAlloc *)809 SkScalerContext::GlyphMetrics SkScalerContext_GDI::generateMetrics(const SkGlyph& glyph,
810 SkArenaAlloc*) {
811 SkASSERT(fDDC);
812
813 GlyphMetrics mx(glyph.maskFormat());
814
815 if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) {
816 SIZE size;
817 WORD glyphs = glyph.getGlyphID();
818 int width, height;
819 if (0 == GetTextExtentPointI(fDDC, &glyphs, 1, &size)) {
820 width = fTM.tmMaxCharWidth;
821 height = fTM.tmHeight;
822 } else {
823 width = size.cx;
824 height = size.cy;
825 }
826
827 // Bitmap FON cannot underhang, but vector FON may.
828 // There appears no means of determining underhang of vector FON.
829 int left = 0;
830 int top = -fTM.tmAscent;
831
832 mx.bounds = SkRect::MakeXYWH(left, top, width, height);
833 mx.advance = SkVector{(float)width, 0};
834
835 // Vector FON will transform nicely, but bitmap FON do not.
836 if (fType == SkScalerContext_GDI::kLine_Type) {
837 SkRect bounds = SkRect::MakeXYWH(left, top, width, height);
838 SkMatrix m;
839 m.setAll(SkFIXEDToScalar(fMat22.eM11), -SkFIXEDToScalar(fMat22.eM21), 0,
840 -SkFIXEDToScalar(fMat22.eM12), SkFIXEDToScalar(fMat22.eM22), 0,
841 0, 0, 1);
842 m.mapRect(&bounds);
843 bounds.roundOut(&mx.bounds);
844 }
845
846 // Apply matrix to advance.
847 mx.advance.fY = -SkFIXEDToFloat(fMat22.eM12) * mx.advance.fX;
848 mx.advance.fX *= SkFIXEDToFloat(fMat22.eM11);
849
850 // These do not have an outline path at all.
851 mx.neverRequestPath = true;
852 return mx;
853 }
854
855 UINT glyphId = glyph.getGlyphID();
856
857 GLYPHMETRICS gm;
858 sk_bzero(&gm, sizeof(gm));
859
860 DWORD status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, nullptr, &fMat22);
861 if (GDI_ERROR == status) {
862 LogFontTypeface::EnsureAccessible(this->getTypeface());
863 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, nullptr, &fMat22);
864 if (GDI_ERROR == status) {
865 return mx;
866 }
867 }
868
869 bool empty = false;
870 // The black box is either the embedded bitmap size or the outline extent.
871 // It is 1x1 if nothing is to be drawn, but will also be 1x1 if something very small
872 // is to be drawn, like a '.'. We need to outset '.' but do not wish to outset ' '.
873 if (1 == gm.gmBlackBoxX && 1 == gm.gmBlackBoxY) {
874 // If GetGlyphOutline with GGO_NATIVE returns 0, we know there was no outline.
875 DWORD bufferSize = GetGlyphOutlineW(fDDC, glyphId, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, 0, nullptr, &fMat22);
876 empty = (0 == bufferSize);
877 }
878
879
880 if (!empty) {
881 int y = -gm.gmptGlyphOrigin.y;
882 int x = gm.gmptGlyphOrigin.x;
883 // Outset, since the image may bleed out of the black box.
884 // For embedded bitmaps the black box should be exact.
885 // For outlines we need to outset by 1 in all directions for bleed.
886 // For ClearType we need to outset by 2 for bleed.
887 mx.bounds = SkRect::MakeXYWH(x, y, gm.gmBlackBoxX, gm.gmBlackBoxY).makeOutset(2, 2);
888 }
889 // TODO(benjaminwagner): What is the type of gm.gmCellInc[XY]?
890 mx.advance.fX = (float)((int)gm.gmCellIncX);
891 mx.advance.fY = (float)((int)gm.gmCellIncY);
892
893 if ((fTM.tmPitchAndFamily & TMPF_VECTOR) && this->isLinearMetrics()) {
894 sk_bzero(&gm, sizeof(gm));
895 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, nullptr, &fHighResMat22);
896 if (GDI_ERROR != status) {
897 mx.advance = fHiResMatrix.mapXY(SkIntToScalar(gm.gmCellIncX),
898 SkIntToScalar(gm.gmCellIncY));
899 }
900 } else if (!isAxisAligned(this->fRec)) {
901 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, nullptr, &fGsA);
902 if (GDI_ERROR != status) {
903 mx.advance = fG_inv.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY));
904 }
905 }
906 return mx;
907 }
908
909 static const MAT2 gMat2Identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
generateFontMetrics(SkFontMetrics * metrics)910 void SkScalerContext_GDI::generateFontMetrics(SkFontMetrics* metrics) {
911 if (nullptr == metrics) {
912 return;
913 }
914 sk_bzero(metrics, sizeof(*metrics));
915
916 SkASSERT(fDDC);
917
918 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
919 if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) {
920 #endif
921 metrics->fTop = SkIntToScalar(-fTM.tmAscent);
922 metrics->fAscent = SkIntToScalar(-fTM.tmAscent);
923 metrics->fDescent = SkIntToScalar(fTM.tmDescent);
924 metrics->fBottom = SkIntToScalar(fTM.tmDescent);
925 metrics->fLeading = SkIntToScalar(fTM.tmExternalLeading);
926 metrics->fAvgCharWidth = SkIntToScalar(fTM.tmAveCharWidth);
927 metrics->fMaxCharWidth = SkIntToScalar(fTM.tmMaxCharWidth);
928 metrics->fXMin = 0;
929 metrics->fXMax = metrics->fMaxCharWidth;
930 //metrics->fXHeight = 0;
931 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
932 return;
933 }
934 #endif
935
936 OUTLINETEXTMETRIC otm;
937
938 uint32_t ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
939 if (0 == ret) {
940 LogFontTypeface::EnsureAccessible(this->getTypeface());
941 ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
942 }
943 if (0 == ret) {
944 return;
945 }
946
947 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
948 metrics->fTop = SkIntToScalar(-otm.otmrcFontBox.top);
949 metrics->fAscent = SkIntToScalar(-otm.otmAscent);
950 metrics->fDescent = SkIntToScalar(-otm.otmDescent);
951 metrics->fBottom = SkIntToScalar(-otm.otmrcFontBox.bottom);
952 metrics->fLeading = SkIntToScalar(otm.otmLineGap);
953 metrics->fAvgCharWidth = SkIntToScalar(otm.otmTextMetrics.tmAveCharWidth);
954 metrics->fMaxCharWidth = SkIntToScalar(otm.otmTextMetrics.tmMaxCharWidth);
955 metrics->fXMin = SkIntToScalar(otm.otmrcFontBox.left);
956 metrics->fXMax = SkIntToScalar(otm.otmrcFontBox.right);
957 #endif
958 metrics->fUnderlineThickness = SkIntToScalar(otm.otmsUnderscoreSize);
959 metrics->fUnderlinePosition = -SkIntToScalar(otm.otmsUnderscorePosition);
960
961 metrics->fFlags |= SkFontMetrics::kUnderlineThicknessIsValid_Flag;
962 metrics->fFlags |= SkFontMetrics::kUnderlinePositionIsValid_Flag;
963
964 metrics->fXHeight = SkIntToScalar(otm.otmsXHeight);
965 GLYPHMETRICS gm;
966 sk_bzero(&gm, sizeof(gm));
967 DWORD len = GetGlyphOutlineW(fDDC, 'x', GGO_METRICS, &gm, 0, nullptr, &gMat2Identity);
968 if (len != GDI_ERROR && gm.gmBlackBoxY > 0) {
969 metrics->fXHeight = SkIntToScalar(gm.gmBlackBoxY);
970 }
971 }
972
973 ////////////////////////////////////////////////////////////////////////////////////////
974
build_power_table(uint8_t table[],float ee)975 static void build_power_table(uint8_t table[], float ee) {
976 for (int i = 0; i < 256; i++) {
977 float x = i / 255.f;
978 x = std::pow(x, ee);
979 int xx = SkScalarRoundToInt(x * 255);
980 table[i] = SkToU8(xx);
981 }
982 }
983
984 /**
985 * This will invert the gamma applied by GDI (gray-scale antialiased), so we
986 * can get linear values.
987 *
988 * GDI grayscale appears to use a hard-coded gamma of 2.3.
989 *
990 * GDI grayscale appears to draw using the black and white rasterizer at four
991 * times the size and then downsamples to compute the coverage mask. As a
992 * result there are only seventeen total grays. This lack of fidelity means
993 * that shifting into other color spaces is imprecise.
994 */
getInverseGammaTableGDI()995 static const uint8_t* getInverseGammaTableGDI() {
996 static SkOnce once;
997 static uint8_t gTableGdi[256];
998 once([]{
999 build_power_table(gTableGdi, 2.3f);
1000 });
1001 return gTableGdi;
1002 }
1003
1004 /**
1005 * This will invert the gamma applied by GDI ClearType, so we can get linear
1006 * values.
1007 *
1008 * GDI ClearType uses SPI_GETFONTSMOOTHINGCONTRAST / 1000 as the gamma value.
1009 * If this value is not specified, the default is a gamma of 1.4.
1010 */
getInverseGammaTableClearType()1011 static const uint8_t* getInverseGammaTableClearType() {
1012 static SkOnce once;
1013 static uint8_t gTableClearType[256];
1014 once([]{
1015 UINT level = 0;
1016 if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &level, 0) || !level) {
1017 // can't get the data, so use a default
1018 level = 1400;
1019 }
1020 build_power_table(gTableClearType, level / 1000.0f);
1021 });
1022 return gTableClearType;
1023 }
1024
1025 #include "include/private/SkColorData.h"
1026
1027 //Cannot assume that the input rgb is gray due to possible setting of kGenA8FromLCD_Flag.
1028 template<bool APPLY_PREBLEND>
rgb_to_a8(SkGdiRGB rgb,const uint8_t * table8)1029 static inline uint8_t rgb_to_a8(SkGdiRGB rgb, const uint8_t* table8) {
1030 U8CPU r = (rgb >> 16) & 0xFF;
1031 U8CPU g = (rgb >> 8) & 0xFF;
1032 U8CPU b = (rgb >> 0) & 0xFF;
1033 return sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8);
1034 }
1035
1036 template<bool APPLY_PREBLEND>
rgb_to_lcd16(SkGdiRGB rgb,const uint8_t * tableR,const uint8_t * tableG,const uint8_t * tableB)1037 static inline uint16_t rgb_to_lcd16(SkGdiRGB rgb, const uint8_t* tableR,
1038 const uint8_t* tableG,
1039 const uint8_t* tableB) {
1040 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
1041 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG);
1042 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB);
1043 if constexpr (kSkShowTextBlitCoverage) {
1044 r = std::max(r, 10u);
1045 g = std::max(g, 10u);
1046 b = std::max(b, 10u);
1047 }
1048 return SkPack888ToRGB16(r, g, b);
1049 }
1050
1051 template<bool APPLY_PREBLEND>
RGBToA8(const SkGdiRGB * SK_RESTRICT src,size_t srcRB,const SkGlyph & glyph,void * imageBuffer,const uint8_t * table8)1052 void SkScalerContext_GDI::RGBToA8(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
1053 const SkGlyph& glyph, void* imageBuffer, const uint8_t* table8) {
1054 const size_t dstRB = glyph.rowBytes();
1055 const int width = glyph.width();
1056 uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)imageBuffer + (glyph.height() - 1) * dstRB);
1057
1058 for (int y = 0; y < glyph.height(); y++) {
1059 for (int i = 0; i < width; i++) {
1060 dst[i] = rgb_to_a8<APPLY_PREBLEND>(src[i], table8);
1061 if constexpr (kSkShowTextBlitCoverage) {
1062 dst[i] = std::max<uint8_t>(dst[i], 10u);
1063 }
1064 }
1065 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1066 dst -= dstRB;
1067 }
1068 }
1069
1070 template<bool APPLY_PREBLEND>
RGBToLcd16(const SkGdiRGB * SK_RESTRICT src,size_t srcRB,const SkGlyph & glyph,void * imageBuffer,const uint8_t * tableR,const uint8_t * tableG,const uint8_t * tableB)1071 void SkScalerContext_GDI::RGBToLcd16(
1072 const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph, void* imageBuffer,
1073 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
1074 const size_t dstRB = glyph.rowBytes();
1075 const int width = glyph.width();
1076 uint16_t* SK_RESTRICT dst = (uint16_t*)((char*)imageBuffer + (glyph.height() - 1) * dstRB);
1077
1078 for (int y = 0; y < glyph.height(); y++) {
1079 for (int i = 0; i < width; i++) {
1080 dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(src[i], tableR, tableG, tableB);
1081 }
1082 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1083 dst = (uint16_t*)((char*)dst - dstRB);
1084 }
1085 }
1086
generateImage(const SkGlyph & glyph,void * imageBuffer)1087 void SkScalerContext_GDI::generateImage(const SkGlyph& glyph, void* imageBuffer) {
1088 SkASSERT(fDDC);
1089
1090 const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat;
1091 const bool isAA = !isLCD(fRec);
1092
1093 size_t srcRB;
1094 void* bits = fOffscreen.draw(glyph, isBW, &srcRB);
1095 if (nullptr == bits) {
1096 LogFontTypeface::EnsureAccessible(this->getTypeface());
1097 bits = fOffscreen.draw(glyph, isBW, &srcRB);
1098 if (nullptr == bits) {
1099 sk_bzero(imageBuffer, glyph.imageSize());
1100 return;
1101 }
1102 }
1103
1104 if (!isBW) {
1105 const uint8_t* table;
1106 //The offscreen contains a GDI blit if isAA and kGenA8FromLCD_Flag is not set.
1107 //Otherwise the offscreen contains a ClearType blit.
1108 if (isAA && !(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag)) {
1109 table = getInverseGammaTableGDI();
1110 } else {
1111 table = getInverseGammaTableClearType();
1112 }
1113 //Note that the following cannot really be integrated into the
1114 //pre-blend, since we may not be applying the pre-blend; when we aren't
1115 //applying the pre-blend it means that a filter wants linear anyway.
1116 //Other code may also be applying the pre-blend, so we'd need another
1117 //one with this and one without.
1118 SkGdiRGB* addr = (SkGdiRGB*)bits;
1119 for (int y = 0; y < glyph.height(); ++y) {
1120 for (int x = 0; x < glyph.width(); ++x) {
1121 int r = (addr[x] >> 16) & 0xFF;
1122 int g = (addr[x] >> 8) & 0xFF;
1123 int b = (addr[x] >> 0) & 0xFF;
1124 addr[x] = (table[r] << 16) | (table[g] << 8) | table[b];
1125 }
1126 addr = SkTAddOffset<SkGdiRGB>(addr, srcRB);
1127 }
1128 }
1129
1130 size_t dstRB = glyph.rowBytes();
1131 if (isBW) {
1132 const uint8_t* src = (const uint8_t*)bits;
1133 uint8_t* dst = (uint8_t*)((char*)imageBuffer + (glyph.height() - 1) * dstRB);
1134 for (int y = 0; y < glyph.height(); y++) {
1135 memcpy(dst, src, dstRB);
1136 src += srcRB;
1137 dst -= dstRB;
1138 }
1139 if constexpr (kSkShowTextBlitCoverage) {
1140 if (glyph.width() > 0 && glyph.height() > 0) {
1141 int bitCount = glyph.width() & 7;
1142 uint8_t* first = (uint8_t*)imageBuffer;
1143 uint8_t* last = first + glyph.height() * dstRB - 1;
1144 *first |= 1 << 7;
1145 *last |= bitCount == 0 ? 1 : 1 << (8 - bitCount);
1146 }
1147 }
1148 } else if (isAA) {
1149 // since the caller may require A8 for maskfilters, we can't check for BW
1150 // ... until we have the caller tell us that explicitly
1151 const SkGdiRGB* src = (const SkGdiRGB*)bits;
1152 if (fPreBlend.isApplicable()) {
1153 RGBToA8<true>(src, srcRB, glyph, imageBuffer, fPreBlend.fG);
1154 } else {
1155 RGBToA8<false>(src, srcRB, glyph, imageBuffer, fPreBlend.fG);
1156 }
1157 } else { // LCD16
1158 const SkGdiRGB* src = (const SkGdiRGB*)bits;
1159 SkASSERT(SkMask::kLCD16_Format == glyph.maskFormat());
1160 if (fPreBlend.isApplicable()) {
1161 RGBToLcd16<true>(src, srcRB, glyph, imageBuffer,
1162 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1163 } else {
1164 RGBToLcd16<false>(src, srcRB, glyph, imageBuffer,
1165 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1166 }
1167 }
1168 }
1169
1170 namespace {
1171
1172 class GDIGlyphbufferPointIter {
1173 public:
GDIGlyphbufferPointIter(const uint8_t * glyphbuf,DWORD total_size)1174 GDIGlyphbufferPointIter(const uint8_t* glyphbuf, DWORD total_size)
1175 : fHeaderIter(glyphbuf, total_size), fCurveIter(), fPointIter()
1176 { }
1177
next()1178 POINTFX const * next() {
1179 nextHeader:
1180 if (!fCurveIter.isSet()) {
1181 const TTPOLYGONHEADER* header = fHeaderIter.next();
1182 if (nullptr == header) {
1183 return nullptr;
1184 }
1185 fCurveIter.set(header);
1186 const TTPOLYCURVE* curve = fCurveIter.next();
1187 if (nullptr == curve) {
1188 return nullptr;
1189 }
1190 fPointIter.set(curve);
1191 return &header->pfxStart;
1192 }
1193
1194 const POINTFX* nextPoint = fPointIter.next();
1195 if (nullptr == nextPoint) {
1196 const TTPOLYCURVE* curve = fCurveIter.next();
1197 if (nullptr == curve) {
1198 fCurveIter.set();
1199 goto nextHeader;
1200 } else {
1201 fPointIter.set(curve);
1202 }
1203 nextPoint = fPointIter.next();
1204 }
1205 return nextPoint;
1206 }
1207
currentCurveType()1208 WORD currentCurveType() {
1209 return fPointIter.fCurveType;
1210 }
1211
1212 private:
1213 /** Iterates over all of the polygon headers in a glyphbuf. */
1214 class GDIPolygonHeaderIter {
1215 public:
GDIPolygonHeaderIter(const uint8_t * glyphbuf,DWORD total_size)1216 GDIPolygonHeaderIter(const uint8_t* glyphbuf, DWORD total_size)
1217 : fCurPolygon(reinterpret_cast<const TTPOLYGONHEADER*>(glyphbuf))
1218 , fEndPolygon(SkTAddOffset<const TTPOLYGONHEADER>(glyphbuf, total_size))
1219 { }
1220
next()1221 const TTPOLYGONHEADER* next() {
1222 if (fCurPolygon >= fEndPolygon) {
1223 return nullptr;
1224 }
1225 const TTPOLYGONHEADER* thisPolygon = fCurPolygon;
1226 fCurPolygon = SkTAddOffset<const TTPOLYGONHEADER>(fCurPolygon, fCurPolygon->cb);
1227 return thisPolygon;
1228 }
1229 private:
1230 const TTPOLYGONHEADER* fCurPolygon;
1231 const TTPOLYGONHEADER* fEndPolygon;
1232 };
1233
1234 /** Iterates over all of the polygon curves in a polygon header. */
1235 class GDIPolygonCurveIter {
1236 public:
GDIPolygonCurveIter()1237 GDIPolygonCurveIter() : fCurCurve(nullptr), fEndCurve(nullptr) { }
1238
GDIPolygonCurveIter(const TTPOLYGONHEADER * curPolygon)1239 GDIPolygonCurveIter(const TTPOLYGONHEADER* curPolygon)
1240 : fCurCurve(SkTAddOffset<const TTPOLYCURVE>(curPolygon, sizeof(TTPOLYGONHEADER)))
1241 , fEndCurve(SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon->cb))
1242 { }
1243
isSet()1244 bool isSet() { return fCurCurve != nullptr; }
1245
set(const TTPOLYGONHEADER * curPolygon)1246 void set(const TTPOLYGONHEADER* curPolygon) {
1247 fCurCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon, sizeof(TTPOLYGONHEADER));
1248 fEndCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon->cb);
1249 }
set()1250 void set() {
1251 fCurCurve = nullptr;
1252 fEndCurve = nullptr;
1253 }
1254
next()1255 const TTPOLYCURVE* next() {
1256 if (fCurCurve >= fEndCurve) {
1257 return nullptr;
1258 }
1259 const TTPOLYCURVE* thisCurve = fCurCurve;
1260 fCurCurve = SkTAddOffset<const TTPOLYCURVE>(fCurCurve, size_of_TTPOLYCURVE(*fCurCurve));
1261 return thisCurve;
1262 }
1263 private:
size_of_TTPOLYCURVE(const TTPOLYCURVE & curve)1264 size_t size_of_TTPOLYCURVE(const TTPOLYCURVE& curve) {
1265 return 2*sizeof(WORD) + curve.cpfx*sizeof(POINTFX);
1266 }
1267 const TTPOLYCURVE* fCurCurve;
1268 const TTPOLYCURVE* fEndCurve;
1269 };
1270
1271 /** Iterates over all of the polygon points in a polygon curve. */
1272 class GDIPolygonCurvePointIter {
1273 public:
GDIPolygonCurvePointIter()1274 GDIPolygonCurvePointIter() : fCurveType(0), fCurPoint(nullptr), fEndPoint(nullptr) { }
1275
GDIPolygonCurvePointIter(const TTPOLYCURVE * curPolygon)1276 GDIPolygonCurvePointIter(const TTPOLYCURVE* curPolygon)
1277 : fCurveType(curPolygon->wType)
1278 , fCurPoint(&curPolygon->apfx[0])
1279 , fEndPoint(&curPolygon->apfx[curPolygon->cpfx])
1280 { }
1281
isSet()1282 bool isSet() { return fCurPoint != nullptr; }
1283
set(const TTPOLYCURVE * curPolygon)1284 void set(const TTPOLYCURVE* curPolygon) {
1285 fCurveType = curPolygon->wType;
1286 fCurPoint = &curPolygon->apfx[0];
1287 fEndPoint = &curPolygon->apfx[curPolygon->cpfx];
1288 }
set()1289 void set() {
1290 fCurPoint = nullptr;
1291 fEndPoint = nullptr;
1292 }
1293
next()1294 const POINTFX* next() {
1295 if (fCurPoint >= fEndPoint) {
1296 return nullptr;
1297 }
1298 const POINTFX* thisPoint = fCurPoint;
1299 ++fCurPoint;
1300 return thisPoint;
1301 }
1302
1303 WORD fCurveType;
1304 private:
1305 const POINTFX* fCurPoint;
1306 const POINTFX* fEndPoint;
1307 };
1308
1309 GDIPolygonHeaderIter fHeaderIter;
1310 GDIPolygonCurveIter fCurveIter;
1311 GDIPolygonCurvePointIter fPointIter;
1312 };
1313
1314 class SkGDIGeometrySink {
1315 SkPath* fPath;
1316 bool fStarted = false;
1317 POINTFX fCurrent;
1318
goingTo(const POINTFX pt)1319 void goingTo(const POINTFX pt) {
1320 if (!fStarted) {
1321 fStarted = true;
1322 fPath->moveTo( SkFIXEDToScalar(fCurrent.x),
1323 -SkFIXEDToScalar(fCurrent.y));
1324 }
1325 fCurrent = pt;
1326 }
1327
currentIsNot(const POINTFX pt)1328 bool currentIsNot(const POINTFX pt) {
1329 return fCurrent.x.value != pt.x.value || fCurrent.x.fract != pt.x.fract ||
1330 fCurrent.y.value != pt.y.value || fCurrent.y.fract != pt.y.fract;
1331 }
1332
1333 public:
SkGDIGeometrySink(SkPath * path)1334 SkGDIGeometrySink(SkPath* path) : fPath(path) {}
1335 void process(const uint8_t* glyphbuf, DWORD total_size);
1336
1337 /** It is possible for the hinted and unhinted versions of the same path to have
1338 * a different number of points due to GDI's handling of flipped points.
1339 * If this is detected, this will return false.
1340 */
1341 bool process(const uint8_t* glyphbuf, DWORD total_size, GDIGlyphbufferPointIter hintedYs);
1342 };
1343
process(const uint8_t * glyphbuf,DWORD total_size)1344 void SkGDIGeometrySink::process(const uint8_t* glyphbuf, DWORD total_size) {
1345 const uint8_t* cur_glyph = glyphbuf;
1346 const uint8_t* end_glyph = glyphbuf + total_size;
1347
1348 while (cur_glyph < end_glyph) {
1349 const TTPOLYGONHEADER* th = (const TTPOLYGONHEADER*)cur_glyph;
1350
1351 const uint8_t* end_poly = cur_glyph + th->cb;
1352 const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
1353
1354 fStarted = false;
1355 fCurrent = th->pfxStart;
1356
1357 while (cur_poly < end_poly) {
1358 const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
1359 const POINTFX* apfx = pc->apfx;
1360 const WORD cpfx = pc->cpfx;
1361
1362 if (pc->wType == TT_PRIM_LINE) {
1363 for (uint16_t i = 0; i < cpfx; i++) {
1364 POINTFX pnt_b = apfx[i];
1365 if (this->currentIsNot(pnt_b)) {
1366 this->goingTo(pnt_b);
1367 fPath->lineTo( SkFIXEDToScalar(pnt_b.x),
1368 -SkFIXEDToScalar(pnt_b.y));
1369 }
1370 }
1371 }
1372
1373 if (pc->wType == TT_PRIM_QSPLINE) {
1374 for (uint16_t u = 0; u < cpfx - 1; u++) { // Walk through points in spline
1375 POINTFX pnt_b = apfx[u]; // B is always the current point
1376 POINTFX pnt_c = apfx[u+1];
1377
1378 if (u < cpfx - 2) { // If not on last spline, compute C
1379 pnt_c.x = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.x),
1380 SkFIXEDToFixed(pnt_c.x)));
1381 pnt_c.y = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.y),
1382 SkFIXEDToFixed(pnt_c.y)));
1383 }
1384
1385
1386 if (this->currentIsNot(pnt_b) || this->currentIsNot(pnt_c)) {
1387 this->goingTo(pnt_c);
1388 fPath->quadTo( SkFIXEDToScalar(pnt_b.x),
1389 -SkFIXEDToScalar(pnt_b.y),
1390 SkFIXEDToScalar(pnt_c.x),
1391 -SkFIXEDToScalar(pnt_c.y));
1392 }
1393 }
1394 }
1395
1396 // Advance past this TTPOLYCURVE.
1397 cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * cpfx;
1398 }
1399 cur_glyph += th->cb;
1400 if (this->fStarted) {
1401 fPath->close();
1402 }
1403 }
1404 }
1405
1406 #define move_next_expected_hinted_point(iter, pElem) do {\
1407 pElem = iter.next(); \
1408 if (nullptr == pElem) return false; \
1409 } while(0)
1410
process(const uint8_t * glyphbuf,DWORD total_size,GDIGlyphbufferPointIter hintedYs)1411 bool SkGDIGeometrySink::process(const uint8_t* glyphbuf, DWORD total_size,
1412 GDIGlyphbufferPointIter hintedYs) {
1413 const uint8_t* cur_glyph = glyphbuf;
1414 const uint8_t* end_glyph = glyphbuf + total_size;
1415
1416 POINTFX const * hintedPoint;
1417
1418 while (cur_glyph < end_glyph) {
1419 const TTPOLYGONHEADER* th = (const TTPOLYGONHEADER*)cur_glyph;
1420
1421 const uint8_t* end_poly = cur_glyph + th->cb;
1422 const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
1423
1424 move_next_expected_hinted_point(hintedYs, hintedPoint);
1425 fStarted = false;
1426 fCurrent = {th->pfxStart.x, hintedPoint->y};
1427
1428 while (cur_poly < end_poly) {
1429 const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
1430 const POINTFX* apfx = pc->apfx;
1431 const WORD cpfx = pc->cpfx;
1432
1433 if (pc->wType == TT_PRIM_LINE) {
1434 for (uint16_t i = 0; i < cpfx; i++) {
1435 move_next_expected_hinted_point(hintedYs, hintedPoint);
1436 POINTFX pnt_b = {apfx[i].x, hintedPoint->y};
1437 if (this->currentIsNot(pnt_b)) {
1438 this->goingTo(pnt_b);
1439 fPath->lineTo( SkFIXEDToScalar(pnt_b.x),
1440 -SkFIXEDToScalar(pnt_b.y));
1441 }
1442 }
1443 }
1444
1445 if (pc->wType == TT_PRIM_QSPLINE) {
1446 POINTFX currentPoint = apfx[0];
1447 move_next_expected_hinted_point(hintedYs, hintedPoint);
1448 // only take the hinted y if it wasn't flipped
1449 if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) {
1450 currentPoint.y = hintedPoint->y;
1451 }
1452 for (uint16_t u = 0; u < cpfx - 1; u++) { // Walk through points in spline
1453 POINTFX pnt_b = currentPoint;//pc->apfx[u]; // B is always the current point
1454 POINTFX pnt_c = apfx[u+1];
1455 move_next_expected_hinted_point(hintedYs, hintedPoint);
1456 // only take the hinted y if it wasn't flipped
1457 if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) {
1458 pnt_c.y = hintedPoint->y;
1459 }
1460 currentPoint.x = pnt_c.x;
1461 currentPoint.y = pnt_c.y;
1462
1463 if (u < cpfx - 2) { // If not on last spline, compute C
1464 pnt_c.x = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.x),
1465 SkFIXEDToFixed(pnt_c.x)));
1466 pnt_c.y = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.y),
1467 SkFIXEDToFixed(pnt_c.y)));
1468 }
1469
1470 if (this->currentIsNot(pnt_b) || this->currentIsNot(pnt_c)) {
1471 this->goingTo(pnt_c);
1472 fPath->quadTo( SkFIXEDToScalar(pnt_b.x),
1473 -SkFIXEDToScalar(pnt_b.y),
1474 SkFIXEDToScalar(pnt_c.x),
1475 -SkFIXEDToScalar(pnt_c.y));
1476 }
1477 }
1478 }
1479
1480 // Advance past this TTPOLYCURVE.
1481 cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * cpfx;
1482 }
1483 cur_glyph += th->cb;
1484 if (this->fStarted) {
1485 fPath->close();
1486 }
1487 }
1488 return true;
1489 }
1490 } // namespace
1491
getGDIGlyphPath(SkGlyphID glyph,UINT flags,AutoSTMalloc<BUFFERSIZE,uint8_t> * glyphbuf)1492 DWORD SkScalerContext_GDI::getGDIGlyphPath(SkGlyphID glyph, UINT flags,
1493 AutoSTMalloc<BUFFERSIZE, uint8_t>* glyphbuf)
1494 {
1495 GLYPHMETRICS gm;
1496
1497 DWORD total_size = GetGlyphOutlineW(fDDC, glyph, flags, &gm, BUFFERSIZE, glyphbuf->get(), &fMat22);
1498 // Sometimes GetGlyphOutlineW returns a number larger than BUFFERSIZE even if BUFFERSIZE > 0.
1499 // It has been verified that this does not involve a buffer overrun.
1500 if (GDI_ERROR == total_size || total_size > BUFFERSIZE) {
1501 // GDI_ERROR because the BUFFERSIZE was too small, or because the data was not accessible.
1502 // When the data is not accessable GetGlyphOutlineW fails rather quickly,
1503 // so just try to get the size. If that fails then ensure the data is accessible.
1504 total_size = GetGlyphOutlineW(fDDC, glyph, flags, &gm, 0, nullptr, &fMat22);
1505 if (GDI_ERROR == total_size) {
1506 LogFontTypeface::EnsureAccessible(this->getTypeface());
1507 total_size = GetGlyphOutlineW(fDDC, glyph, flags, &gm, 0, nullptr, &fMat22);
1508 if (GDI_ERROR == total_size) {
1509 // GetGlyphOutlineW is known to fail for some characters, such as spaces.
1510 // In these cases, just return that the glyph does not have a shape.
1511 return 0;
1512 }
1513 }
1514
1515 glyphbuf->reset(total_size);
1516
1517 DWORD ret = GetGlyphOutlineW(fDDC, glyph, flags, &gm, total_size, glyphbuf->get(), &fMat22);
1518 if (GDI_ERROR == ret) {
1519 LogFontTypeface::EnsureAccessible(this->getTypeface());
1520 ret = GetGlyphOutlineW(fDDC, glyph, flags, &gm, total_size, glyphbuf->get(), &fMat22);
1521 if (GDI_ERROR == ret) {
1522 SkASSERT(false);
1523 return 0;
1524 }
1525 }
1526 }
1527 return total_size;
1528 }
1529
generatePath(const SkGlyph & glyph,SkPath * path,bool * modified)1530 bool SkScalerContext_GDI::generatePath(const SkGlyph& glyph, SkPath* path, bool* modified) {
1531 SkASSERT(path);
1532 SkASSERT(fDDC);
1533
1534 path->reset();
1535
1536 SkGlyphID glyphID = glyph.getGlyphID();
1537
1538 // Out of all the fonts on a typical Windows box,
1539 // 25% of glyphs require more than 2KB.
1540 // 1% of glyphs require more than 4KB.
1541 // 0.01% of glyphs require more than 8KB.
1542 // 8KB is less than 1% of the normal 1MB stack on Windows.
1543 // Note that some web fonts glyphs require more than 20KB.
1544 //static const DWORD BUFFERSIZE = (1 << 13);
1545
1546 //GDI only uses hinted outlines when axis aligned.
1547 UINT format = GGO_NATIVE | GGO_GLYPH_INDEX;
1548 if (fRec.getHinting() == SkFontHinting::kNone || fRec.getHinting() == SkFontHinting::kSlight){
1549 format |= GGO_UNHINTED;
1550 }
1551 AutoSTMalloc<BUFFERSIZE, uint8_t> glyphbuf(BUFFERSIZE);
1552 DWORD total_size = getGDIGlyphPath(glyphID, format, &glyphbuf);
1553 if (0 == total_size) {
1554 return false;
1555 }
1556
1557 if (fRec.getHinting() != SkFontHinting::kSlight) {
1558 SkGDIGeometrySink sink(path);
1559 sink.process(glyphbuf, total_size);
1560 } else {
1561 AutoSTMalloc<BUFFERSIZE, uint8_t> hintedGlyphbuf(BUFFERSIZE);
1562 //GDI only uses hinted outlines when axis aligned.
1563 DWORD hinted_total_size = getGDIGlyphPath(glyphID, GGO_NATIVE | GGO_GLYPH_INDEX,
1564 &hintedGlyphbuf);
1565 if (0 == hinted_total_size) {
1566 return false;
1567 }
1568
1569 SkGDIGeometrySink sinkXBufYIter(path);
1570 if (!sinkXBufYIter.process(glyphbuf, total_size,
1571 GDIGlyphbufferPointIter(hintedGlyphbuf, hinted_total_size)))
1572 {
1573 // Both path and sinkXBufYIter are in the state they were in at the time of failure.
1574 path->reset();
1575 SkGDIGeometrySink sink(path);
1576 sink.process(glyphbuf, total_size);
1577 }
1578 }
1579 return true;
1580 }
1581
logfont_for_name(const char * familyName,LOGFONT * lf)1582 static void logfont_for_name(const char* familyName, LOGFONT* lf) {
1583 sk_bzero(lf, sizeof(LOGFONT));
1584 #ifdef UNICODE
1585 // Get the buffer size needed first.
1586 size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName,
1587 -1, nullptr, 0);
1588 // Allocate a buffer (str_len already has terminating null
1589 // accounted for).
1590 wchar_t *wideFamilyName = new wchar_t[str_len];
1591 // Now actually convert the string.
1592 ::MultiByteToWideChar(CP_UTF8, 0, familyName, -1,
1593 wideFamilyName, str_len);
1594 ::wcsncpy(lf->lfFaceName, wideFamilyName, LF_FACESIZE - 1);
1595 delete [] wideFamilyName;
1596 lf->lfFaceName[LF_FACESIZE-1] = L'\0';
1597 #else
1598 ::strncpy(lf->lfFaceName, familyName, LF_FACESIZE - 1);
1599 lf->lfFaceName[LF_FACESIZE - 1] = '\0';
1600 #endif
1601 }
1602
onGetFamilyName(SkString * familyName) const1603 void LogFontTypeface::onGetFamilyName(SkString* familyName) const {
1604 // Get the actual name of the typeface. The logfont may not know this.
1605 SkAutoHDC hdc(fLogFont);
1606 dcfontname_to_skstring(hdc, fLogFont, familyName);
1607 }
1608
onGetFontDescriptor(SkFontDescriptor * desc,bool * isLocalStream) const1609 void LogFontTypeface::onGetFontDescriptor(SkFontDescriptor* desc,
1610 bool* isLocalStream) const {
1611 SkString familyName;
1612 this->onGetFamilyName(&familyName);
1613 desc->setFamilyName(familyName.c_str());
1614 desc->setStyle(this->fontStyle());
1615 *isLocalStream = this->fSerializeAsStream;
1616 }
1617
getGlyphToUnicodeMap(SkUnichar * dstArray) const1618 void LogFontTypeface::getGlyphToUnicodeMap(SkUnichar* dstArray) const {
1619 SkAutoHDC hdc(fLogFont);
1620 unsigned int glyphCount = calculateGlyphCount(hdc, fLogFont);
1621 populate_glyph_to_unicode(hdc, glyphCount, dstArray);
1622 }
1623
onGetAdvancedMetrics() const1624 std::unique_ptr<SkAdvancedTypefaceMetrics> LogFontTypeface::onGetAdvancedMetrics() const {
1625 LOGFONT lf = fLogFont;
1626 std::unique_ptr<SkAdvancedTypefaceMetrics> info(nullptr);
1627
1628 // The design HFONT must be destroyed after the HDC
1629 using HFONT_T = typename std::remove_pointer<HFONT>::type;
1630 std::unique_ptr<HFONT_T, SkFunctionObject<DeleteObject>> designFont;
1631 SkAutoHDC hdc(lf);
1632
1633 const char stem_chars[] = {'i', 'I', '!', '1'};
1634 int16_t min_width;
1635 unsigned glyphCount;
1636
1637 // To request design units, create a logical font whose height is specified
1638 // as unitsPerEm.
1639 OUTLINETEXTMETRIC otm;
1640 unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
1641 if (0 == otmRet) {
1642 call_ensure_accessible(lf);
1643 otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
1644 }
1645 if (!otmRet || !GetTextFace(hdc, LF_FACESIZE, lf.lfFaceName)) {
1646 return info;
1647 }
1648 lf.lfHeight = -SkToS32(otm.otmEMSquare);
1649 designFont.reset(CreateFontIndirect(&lf));
1650 SelectObject(hdc, designFont.get());
1651 if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm)) {
1652 return info;
1653 }
1654 glyphCount = calculateGlyphCount(hdc, fLogFont);
1655
1656 info.reset(new SkAdvancedTypefaceMetrics);
1657
1658 SkOTTableOS2_V4::Type fsType;
1659 if (sizeof(fsType) == this->getTableData(SkTEndian_SwapBE32(SkOTTableOS2::TAG),
1660 offsetof(SkOTTableOS2_V4, fsType),
1661 sizeof(fsType),
1662 &fsType)) {
1663 SkOTUtils::SetAdvancedTypefaceFlags(fsType, info.get());
1664 } else {
1665 // If bit 1 is set, the font may not be embedded in a document.
1666 // If bit 1 is clear, the font can be embedded.
1667 // If bit 2 is set, the embedding is read-only.
1668 if (otm.otmfsType & 0x1) {
1669 info->fFlags |= SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag;
1670 }
1671 }
1672
1673 if (glyphCount == 0 || (otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE) == 0) {
1674 return info;
1675 }
1676 info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
1677
1678 // If this bit is clear the font is a fixed pitch font.
1679 if (!(otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
1680 info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
1681 }
1682 if (otm.otmTextMetrics.tmItalic) {
1683 info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
1684 }
1685 if (otm.otmTextMetrics.tmPitchAndFamily & FF_ROMAN) {
1686 info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
1687 } else if (otm.otmTextMetrics.tmPitchAndFamily & FF_SCRIPT) {
1688 info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
1689 }
1690
1691 // The main italic angle of the font, in tenths of a degree counterclockwise
1692 // from vertical.
1693 info->fItalicAngle = otm.otmItalicAngle / 10;
1694 info->fAscent = SkToS16(otm.otmTextMetrics.tmAscent);
1695 info->fDescent = SkToS16(-otm.otmTextMetrics.tmDescent);
1696 // TODO(ctguil): Use alternate cap height calculation.
1697 // MSDN says otmsCapEmHeight is not support but it is returning a value on
1698 // my Win7 box.
1699 info->fCapHeight = otm.otmsCapEmHeight;
1700 info->fBBox =
1701 SkIRect::MakeLTRB(otm.otmrcFontBox.left, otm.otmrcFontBox.top,
1702 otm.otmrcFontBox.right, otm.otmrcFontBox.bottom);
1703
1704 // Figure out a good guess for StemV - Min width of i, I, !, 1.
1705 // This probably isn't very good with an italic font.
1706 min_width = SHRT_MAX;
1707 info->fStemV = 0;
1708 for (size_t i = 0; i < std::size(stem_chars); i++) {
1709 ABC abcWidths;
1710 if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) {
1711 int16_t width = abcWidths.abcB;
1712 if (width > 0 && width < min_width) {
1713 min_width = width;
1714 info->fStemV = min_width;
1715 }
1716 }
1717 }
1718
1719 return info;
1720 }
1721
1722 //Placeholder representation of a Base64 encoded GUID from create_unique_font_name.
1723 #define BASE64_GUID_ID "XXXXXXXXXXXXXXXXXXXXXXXX"
1724 //Length of GUID representation from create_id, including nullptr terminator.
1725 #define BASE64_GUID_ID_LEN std::size(BASE64_GUID_ID)
1726
1727 static_assert(BASE64_GUID_ID_LEN < LF_FACESIZE, "GUID_longer_than_facesize");
1728
1729 /**
1730 NameID 6 Postscript names cannot have the character '/'.
1731 It would be easier to hex encode the GUID, but that is 32 bytes,
1732 and many systems have issues with names longer than 28 bytes.
1733 The following need not be any standard base64 encoding.
1734 The encoded value is never decoded.
1735 */
1736 static const char postscript_safe_base64_encode[] =
1737 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1738 "abcdefghijklmnopqrstuvwxyz"
1739 "0123456789-_=";
1740
1741 /**
1742 Formats a GUID into Base64 and places it into buffer.
1743 buffer should have space for at least BASE64_GUID_ID_LEN characters.
1744 The string will always be null terminated.
1745 XXXXXXXXXXXXXXXXXXXXXXXX0
1746 */
format_guid_b64(const GUID & guid,char * buffer,size_t bufferSize)1747 static void format_guid_b64(const GUID& guid, char* buffer, size_t bufferSize) {
1748 SkASSERT(bufferSize >= BASE64_GUID_ID_LEN);
1749 size_t written = SkBase64::Encode(&guid, sizeof(guid), buffer, postscript_safe_base64_encode);
1750 SkASSERT(written < LF_FACESIZE);
1751 buffer[written] = '\0';
1752 }
1753
1754 /**
1755 Creates a Base64 encoded GUID and places it into buffer.
1756 buffer should have space for at least BASE64_GUID_ID_LEN characters.
1757 The string will always be null terminated.
1758 XXXXXXXXXXXXXXXXXXXXXXXX0
1759 */
create_unique_font_name(char * buffer,size_t bufferSize)1760 static HRESULT create_unique_font_name(char* buffer, size_t bufferSize) {
1761 GUID guid = {};
1762 if (FAILED(CoCreateGuid(&guid))) {
1763 return E_UNEXPECTED;
1764 }
1765 format_guid_b64(guid, buffer, bufferSize);
1766
1767 return S_OK;
1768 }
1769
1770 /**
1771 Introduces a font to GDI. On failure will return nullptr. The returned handle
1772 should eventually be passed to RemoveFontMemResourceEx.
1773 */
activate_font(SkData * fontData)1774 static HANDLE activate_font(SkData* fontData) {
1775 DWORD numFonts = 0;
1776 //AddFontMemResourceEx just copies the data, but does not specify const.
1777 HANDLE fontHandle = AddFontMemResourceEx(const_cast<void*>(fontData->data()),
1778 static_cast<DWORD>(fontData->size()),
1779 nullptr,
1780 &numFonts);
1781
1782 if (fontHandle != nullptr && numFonts < 1) {
1783 RemoveFontMemResourceEx(fontHandle);
1784 return nullptr;
1785 }
1786
1787 return fontHandle;
1788 }
1789
1790 // Does not affect ownership of stream.
create_from_stream(std::unique_ptr<SkStreamAsset> stream)1791 static sk_sp<SkTypeface> create_from_stream(std::unique_ptr<SkStreamAsset> stream) {
1792 // Create a unique and unpredictable font name.
1793 // Avoids collisions and access from CSS.
1794 char familyName[BASE64_GUID_ID_LEN];
1795 const int familyNameSize = std::size(familyName);
1796 if (FAILED(create_unique_font_name(familyName, familyNameSize))) {
1797 return nullptr;
1798 }
1799
1800 // Change the name of the font.
1801 sk_sp<SkData> rewrittenFontData(SkOTUtils::RenameFont(stream.get(), familyName, familyNameSize-1));
1802 if (nullptr == rewrittenFontData.get()) {
1803 return nullptr;
1804 }
1805
1806 // Register the font with GDI.
1807 HANDLE fontReference = activate_font(rewrittenFontData.get());
1808 if (nullptr == fontReference) {
1809 return nullptr;
1810 }
1811
1812 // Create the typeface.
1813 LOGFONT lf;
1814 logfont_for_name(familyName, &lf);
1815
1816 return sk_sp<SkTypeface>(SkCreateFontMemResourceTypefaceFromLOGFONT(lf, fontReference));
1817 }
1818
onOpenStream(int * ttcIndex) const1819 std::unique_ptr<SkStreamAsset> LogFontTypeface::onOpenStream(int* ttcIndex) const {
1820 *ttcIndex = 0;
1821
1822 const DWORD kTTCTag = SkEndian_SwapBE32(SkSetFourByteTag('t', 't', 'c', 'f'));
1823 LOGFONT lf = fLogFont;
1824
1825 SkAutoHDC hdc(lf);
1826
1827 std::unique_ptr<SkStreamAsset> stream;
1828 DWORD tables[2] = {kTTCTag, 0};
1829 for (size_t i = 0; i < std::size(tables); i++) {
1830 DWORD bufferSize = GetFontData(hdc, tables[i], 0, nullptr, 0);
1831 if (bufferSize == GDI_ERROR) {
1832 call_ensure_accessible(lf);
1833 bufferSize = GetFontData(hdc, tables[i], 0, nullptr, 0);
1834 }
1835 if (bufferSize != GDI_ERROR) {
1836 sk_sp<SkData> streamData = SkData::MakeUninitialized(bufferSize);
1837 if (GetFontData(hdc, tables[i], 0, streamData->writable_data(), bufferSize)) {
1838 stream.reset(new SkMemoryStream(std::move(streamData)));
1839 break;
1840 } else {
1841 stream.reset();
1842 }
1843 }
1844 }
1845 return stream;
1846 }
1847
onMakeClone(const SkFontArguments & args) const1848 sk_sp<SkTypeface> LogFontTypeface::onMakeClone(const SkFontArguments& args) const {
1849 return sk_ref_sp(this);
1850 }
1851
bmpCharsToGlyphs(HDC hdc,const WCHAR * bmpChars,int count,uint16_t * glyphs,bool Ox1FHack)1852 static void bmpCharsToGlyphs(HDC hdc, const WCHAR* bmpChars, int count, uint16_t* glyphs,
1853 bool Ox1FHack)
1854 {
1855 // Type1 fonts fail with uniscribe API. Use GetGlyphIndices for plane 0.
1856
1857 /** Real documentation for GetGlyphIndicesW:
1858 *
1859 * When GGI_MARK_NONEXISTING_GLYPHS is not specified and a character does not map to a
1860 * glyph, then the 'default character's glyph is returned instead. The 'default character'
1861 * is available in fTM.tmDefaultChar. FON fonts have a default character, and there exists
1862 * a usDefaultChar in the 'OS/2' table, version 2 and later. If there is no
1863 * 'default character' specified by the font, then often the first character found is used.
1864 *
1865 * When GGI_MARK_NONEXISTING_GLYPHS is specified and a character does not map to a glyph,
1866 * then the glyph 0xFFFF is used. In Windows XP and earlier, Bitmap/Vector FON usually use
1867 * glyph 0x1F instead ('Terminal' appears to be special, returning 0xFFFF).
1868 * Type1 PFM/PFB, TT, OT TT, OT CFF all appear to use 0xFFFF, even on XP.
1869 */
1870 DWORD result = GetGlyphIndicesW(hdc, bmpChars, count, glyphs, GGI_MARK_NONEXISTING_GLYPHS);
1871 if (GDI_ERROR == result) {
1872 for (int i = 0; i < count; ++i) {
1873 glyphs[i] = 0;
1874 }
1875 return;
1876 }
1877
1878 if (Ox1FHack) {
1879 for (int i = 0; i < count; ++i) {
1880 if (0xFFFF == glyphs[i] || 0x1F == glyphs[i]) {
1881 glyphs[i] = 0;
1882 }
1883 }
1884 } else {
1885 for (int i = 0; i < count; ++i) {
1886 if (0xFFFF == glyphs[i]){
1887 glyphs[i] = 0;
1888 }
1889 }
1890 }
1891 }
1892
nonBmpCharToGlyph(HDC hdc,SCRIPT_CACHE * scriptCache,const WCHAR utf16[2])1893 static uint16_t nonBmpCharToGlyph(HDC hdc, SCRIPT_CACHE* scriptCache, const WCHAR utf16[2]) {
1894 uint16_t index = 0;
1895 // Use uniscribe to detemine glyph index for non-BMP characters.
1896 static const int numWCHAR = 2;
1897 static const int maxItems = 2;
1898 // MSDN states that this can be nullptr, but some things don't work then.
1899 SCRIPT_CONTROL scriptControl;
1900 memset(&scriptControl, 0, sizeof(scriptControl));
1901 // Add extra item to SCRIPT_ITEM to work around a bug (now documented).
1902 // https://bugzilla.mozilla.org/show_bug.cgi?id=366643
1903 SCRIPT_ITEM si[maxItems + 1];
1904 int numItems;
1905 HRZM(ScriptItemize(utf16, numWCHAR, maxItems, &scriptControl, nullptr, si, &numItems),
1906 "Could not itemize character.");
1907
1908 // Sometimes ScriptShape cannot find a glyph for a non-BMP and returns 2 space glyphs.
1909 static const int maxGlyphs = 2;
1910 SCRIPT_VISATTR vsa[maxGlyphs];
1911 WORD outGlyphs[maxGlyphs];
1912 WORD logClust[numWCHAR];
1913 int numGlyphs;
1914 SCRIPT_ANALYSIS& script = si[0].a;
1915 script.eScript = SCRIPT_UNDEFINED;
1916 script.fRTL = FALSE;
1917 script.fLayoutRTL = FALSE;
1918 script.fLinkBefore = FALSE;
1919 script.fLinkAfter = FALSE;
1920 script.fLogicalOrder = FALSE;
1921 script.fNoGlyphIndex = FALSE;
1922 script.s.uBidiLevel = 0;
1923 script.s.fOverrideDirection = 0;
1924 script.s.fInhibitSymSwap = TRUE;
1925 script.s.fCharShape = FALSE;
1926 script.s.fDigitSubstitute = FALSE;
1927 script.s.fInhibitLigate = FALSE;
1928 script.s.fDisplayZWG = TRUE;
1929 script.s.fArabicNumContext = FALSE;
1930 script.s.fGcpClusters = FALSE;
1931 script.s.fReserved = 0;
1932 script.s.fEngineReserved = 0;
1933 // For the future, 0x80040200 from here is USP_E_SCRIPT_NOT_IN_FONT
1934 HRZM(ScriptShape(hdc, scriptCache, utf16, numWCHAR, maxGlyphs, &script,
1935 outGlyphs, logClust, vsa, &numGlyphs),
1936 "Could not shape character.");
1937 if (1 == numGlyphs) {
1938 index = outGlyphs[0];
1939 }
1940 return index;
1941 }
1942
onCharsToGlyphs(const SkUnichar * uni,int glyphCount,SkGlyphID glyphs[]) const1943 void LogFontTypeface::onCharsToGlyphs(const SkUnichar* uni, int glyphCount,
1944 SkGlyphID glyphs[]) const
1945 {
1946 SkAutoHDC hdc(fLogFont);
1947
1948 TEXTMETRIC tm;
1949 if (0 == GetTextMetrics(hdc, &tm)) {
1950 call_ensure_accessible(fLogFont);
1951 if (0 == GetTextMetrics(hdc, &tm)) {
1952 tm.tmPitchAndFamily = TMPF_TRUETYPE;
1953 }
1954 }
1955 bool Ox1FHack = !(tm.tmPitchAndFamily & TMPF_VECTOR) /*&& winVer < Vista */;
1956
1957 SCRIPT_CACHE sc = nullptr;
1958 static const int scratchCount = 256;
1959 WCHAR scratch[scratchCount];
1960 int glyphIndex = 0;
1961 const uint32_t* utf32 = reinterpret_cast<const uint32_t*>(uni);
1962 while (glyphIndex < glyphCount) {
1963 // Try a run of bmp.
1964 int glyphsLeft = std::min(glyphCount - glyphIndex, scratchCount);
1965 int runLength = 0;
1966 while (runLength < glyphsLeft && utf32[glyphIndex + runLength] <= 0xFFFF) {
1967 scratch[runLength] = static_cast<WCHAR>(utf32[glyphIndex + runLength]);
1968 ++runLength;
1969 }
1970 if (runLength) {
1971 bmpCharsToGlyphs(hdc, scratch, runLength, &glyphs[glyphIndex], Ox1FHack);
1972 glyphIndex += runLength;
1973 }
1974
1975 // Try a run of non-bmp.
1976 while (glyphIndex < glyphCount && utf32[glyphIndex] > 0xFFFF) {
1977 SkUTF::ToUTF16(utf32[glyphIndex], reinterpret_cast<uint16_t*>(scratch));
1978 glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, scratch);
1979 ++glyphIndex;
1980 }
1981 }
1982
1983 if (sc) {
1984 ::ScriptFreeCache(&sc);
1985 }
1986 }
1987
onCountGlyphs() const1988 int LogFontTypeface::onCountGlyphs() const {
1989 SkAutoHDC hdc(fLogFont);
1990 return calculateGlyphCount(hdc, fLogFont);
1991 }
1992
getPostScriptGlyphNames(SkString *) const1993 void LogFontTypeface::getPostScriptGlyphNames(SkString*) const {}
1994
onGetUPEM() const1995 int LogFontTypeface::onGetUPEM() const {
1996 SkAutoHDC hdc(fLogFont);
1997 return calculateUPEM(hdc, fLogFont);
1998 }
1999
onCreateFamilyNameIterator() const2000 SkTypeface::LocalizedStrings* LogFontTypeface::onCreateFamilyNameIterator() const {
2001 sk_sp<SkTypeface::LocalizedStrings> nameIter =
2002 SkOTUtils::LocalizedStrings_NameTable::MakeForFamilyNames(*this);
2003 if (!nameIter) {
2004 SkString familyName;
2005 this->getFamilyName(&familyName);
2006 SkString language("und"); //undetermined
2007 nameIter = sk_make_sp<SkOTUtils::LocalizedStrings_SingleName>(familyName, language);
2008 }
2009 return nameIter.release();
2010 }
2011
onGetTableTags(SkFontTableTag tags[]) const2012 int LogFontTypeface::onGetTableTags(SkFontTableTag tags[]) const {
2013 SkSFNTHeader header;
2014 if (sizeof(header) != this->onGetTableData(0, 0, sizeof(header), &header)) {
2015 return 0;
2016 }
2017
2018 int numTables = SkEndian_SwapBE16(header.numTables);
2019
2020 if (tags) {
2021 size_t size = numTables * sizeof(SkSFNTHeader::TableDirectoryEntry);
2022 AutoSTMalloc<0x20, SkSFNTHeader::TableDirectoryEntry> dir(numTables);
2023 if (size != this->onGetTableData(0, sizeof(header), size, dir.get())) {
2024 return 0;
2025 }
2026
2027 for (int i = 0; i < numTables; ++i) {
2028 tags[i] = SkEndian_SwapBE32(dir[i].tag);
2029 }
2030 }
2031 return numTables;
2032 }
2033
onGetTableData(SkFontTableTag tag,size_t offset,size_t length,void * data) const2034 size_t LogFontTypeface::onGetTableData(SkFontTableTag tag, size_t offset,
2035 size_t length, void* data) const
2036 {
2037 LOGFONT lf = fLogFont;
2038 SkAutoHDC hdc(lf);
2039
2040 tag = SkEndian_SwapBE32(tag);
2041 if (nullptr == data) {
2042 length = 0;
2043 }
2044 DWORD bufferSize = GetFontData(hdc, tag, (DWORD) offset, data, (DWORD) length);
2045 if (bufferSize == GDI_ERROR) {
2046 call_ensure_accessible(lf);
2047 bufferSize = GetFontData(hdc, tag, (DWORD) offset, data, (DWORD) length);
2048 }
2049 return bufferSize == GDI_ERROR ? 0 : bufferSize;
2050 }
2051
onCopyTableData(SkFontTableTag tag) const2052 sk_sp<SkData> LogFontTypeface::onCopyTableData(SkFontTableTag tag) const {
2053 LOGFONT lf = fLogFont;
2054 SkAutoHDC hdc(lf);
2055
2056 tag = SkEndian_SwapBE32(tag);
2057 DWORD size = GetFontData(hdc, tag, 0, nullptr, 0);
2058 if (size == GDI_ERROR) {
2059 call_ensure_accessible(lf);
2060 size = GetFontData(hdc, tag, 0, nullptr, 0);
2061 }
2062
2063 sk_sp<SkData> data;
2064 if (size != GDI_ERROR) {
2065 data = SkData::MakeUninitialized(size);
2066 if (GetFontData(hdc, tag, 0, data->writable_data(), size) == GDI_ERROR) {
2067 data.reset();
2068 }
2069 }
2070 return data;
2071 }
2072
onCreateScalerContext(const SkScalerContextEffects & effects,const SkDescriptor * desc) const2073 std::unique_ptr<SkScalerContext> LogFontTypeface::onCreateScalerContext(
2074 const SkScalerContextEffects& effects, const SkDescriptor* desc) const
2075 {
2076 auto ctx = std::make_unique<SkScalerContext_GDI>(
2077 sk_ref_sp(const_cast<LogFontTypeface*>(this)), effects, desc);
2078 if (ctx->isValid()) {
2079 return std::move(ctx);
2080 }
2081
2082 ctx.reset();
2083 SkStrikeCache::PurgeAll();
2084 ctx = std::make_unique<SkScalerContext_GDI>(
2085 sk_ref_sp(const_cast<LogFontTypeface*>(this)), effects, desc);
2086 if (ctx->isValid()) {
2087 return std::move(ctx);
2088 }
2089
2090 return SkScalerContext::MakeEmpty(
2091 sk_ref_sp(const_cast<LogFontTypeface*>(this)), effects, desc);
2092 }
2093
onFilterRec(SkScalerContextRec * rec) const2094 void LogFontTypeface::onFilterRec(SkScalerContextRec* rec) const {
2095 rec->useStrokeForFakeBold();
2096
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() = *(const 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.size();
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 sk_sp<SkTypeface> createTypeface(int index) override {
2214 return SkCreateTypefaceFromLOGFONT(fArray[index].elfLogFont);
2215 }
2216
matchStyle(const SkFontStyle & pattern)2217 sk_sp<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.size();
2240 }
2241
onGetFamilyName(int index,SkString * familyName) const2242 void onGetFamilyName(int index, SkString* familyName) const override {
2243 SkASSERT(index < fLogFontArray.size());
2244 tchar_to_skstring(fLogFontArray[index].elfLogFont.lfFaceName, familyName);
2245 }
2246
onCreateStyleSet(int index) const2247 sk_sp<SkFontStyleSet> onCreateStyleSet(int index) const override {
2248 SkASSERT(index < fLogFontArray.size());
2249 return sk_sp<SkFontStyleSet>(
2250 new SkFontStyleSetGDI(fLogFontArray[index].elfLogFont.lfFaceName));
2251 }
2252
onMatchFamily(const char familyName[]) const2253 sk_sp<SkFontStyleSet> onMatchFamily(const char familyName[]) const override {
2254 if (nullptr == familyName) {
2255 familyName = ""; // do we need this check???
2256 }
2257 LOGFONT lf;
2258 logfont_for_name(familyName, &lf);
2259 return sk_sp<SkFontStyleSet>(new SkFontStyleSetGDI(lf.lfFaceName));
2260 }
2261
onMatchFamilyStyle(const char familyName[],const SkFontStyle & fontstyle) const2262 sk_sp<SkTypeface> onMatchFamilyStyle(const char familyName[],
2263 const SkFontStyle& fontstyle) const override {
2264 // could be in base impl
2265 sk_sp<SkFontStyleSet> sset(this->matchFamily(familyName));
2266 return sset->matchStyle(fontstyle);
2267 }
2268
onMatchFamilyStyleCharacter(const char familyName[],const SkFontStyle &,const char * bcp47[],int bcp47Count,SkUnichar character) const2269 sk_sp<SkTypeface> onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&,
2270 const char* bcp47[], int bcp47Count,
2271 SkUnichar character) const override {
2272 return nullptr;
2273 }
2274
onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,int ttcIndex) const2275 sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream,
2276 int ttcIndex) const override {
2277 if (ttcIndex != 0) {
2278 return nullptr;
2279 }
2280 return create_from_stream(std::move(stream));
2281 }
2282
onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,const SkFontArguments & args) const2283 sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream,
2284 const SkFontArguments& args) const override {
2285 return this->makeFromStream(std::move(stream), args.getCollectionIndex());
2286 }
2287
onMakeFromData(sk_sp<SkData> data,int ttcIndex) const2288 sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData> data, int ttcIndex) const override {
2289 // could be in base impl
2290 return this->makeFromStream(std::unique_ptr<SkStreamAsset>(new SkMemoryStream(std::move(data))),
2291 ttcIndex);
2292 }
2293
onMakeFromFile(const char path[],int ttcIndex) const2294 sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override {
2295 // could be in base impl
2296 auto stream = SkStream::MakeFromFile(path);
2297 return stream ? this->makeFromStream(std::move(stream), ttcIndex) : nullptr;
2298 }
2299
onLegacyMakeTypeface(const char familyName[],SkFontStyle style) const2300 sk_sp<SkTypeface> onLegacyMakeTypeface(const char familyName[], SkFontStyle style) const override {
2301 LOGFONT lf;
2302 if (nullptr == familyName) {
2303 lf = get_default_font();
2304 } else {
2305 logfont_for_name(familyName, &lf);
2306 }
2307
2308 lf.lfWeight = style.weight();
2309 lf.lfItalic = style.slant() == SkFontStyle::kUpright_Slant ? FALSE : TRUE;
2310 return sk_sp<SkTypeface>(SkCreateTypefaceFromLOGFONT(lf));
2311 }
2312
2313 private:
2314 SkTDArray<ENUMLOGFONTEX> fLogFontArray;
2315 };
2316
2317 ///////////////////////////////////////////////////////////////////////////////
2318
SkFontMgr_New_GDI()2319 sk_sp<SkFontMgr> SkFontMgr_New_GDI() { return sk_make_sp<SkFontMgrGDI>(); }
2320
2321 #endif//defined(SK_BUILD_FOR_WIN)
2322