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