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