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