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