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