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