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