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