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