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