3 * Copyright 2006 The Android Open Source Project
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
9 #include "SkAdvancedTypefaceMetrics.h"
11 #include "SkColorPriv.h"
13 #include "SkDescriptor.h"
14 #include "SkFontDescriptor.h"
15 #include "SkFontHost.h"
17 #include "SkHRESULT.h"
18 #include "SkMaskGamma.h"
19 #include "SkMatrix22.h"
20 #include "SkOTTable_maxp.h"
21 #include "SkOTTable_name.h"
22 #include "SkOTUtils.h"
24 #include "SkSFNTHeader.h"
27 #include "SkTemplates.h"
29 #include "SkTypeface_win.h"
30 #include "SkTypefaceCache.h"
38 static void (*gEnsureLOGFONTAccessibleProc)(const LOGFONT&);
40 void SkTypeface_SetEnsureLOGFONTAccessibleProc(void (*proc)(const LOGFONT&)) {
41 gEnsureLOGFONTAccessibleProc = proc;
44 static void call_ensure_accessible(const LOGFONT& lf) {
45 if (gEnsureLOGFONTAccessibleProc) {
46 gEnsureLOGFONTAccessibleProc(lf);
50 ///////////////////////////////////////////////////////////////////////////////
52 // always packed xxRRGGBB
53 typedef uint32_t SkGdiRGB;
55 // define this in your Makefile or .gyp to enforce AA requests
56 // which GDI ignores at small sizes. This flag guarantees AA
57 // for rotated text, regardless of GDI's notions.
58 //#define SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
60 static bool isLCD(const SkScalerContext::Rec& rec) {
61 return SkMask::kLCD16_Format == rec.fMaskFormat ||
62 SkMask::kLCD32_Format == rec.fMaskFormat;
65 static bool bothZero(SkScalar a, SkScalar b) {
66 return 0 == a && 0 == b;
69 // returns false if there is any non-90-rotation or skew
70 static bool isAxisAligned(const SkScalerContext::Rec& rec) {
71 return 0 == rec.fPreSkewX &&
72 (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
73 bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
76 static bool needToRenderWithSkia(const SkScalerContext::Rec& rec) {
77 #ifdef SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
78 // What we really want to catch is when GDI will ignore the AA request and give
79 // us BW instead. Smallish rotated text is one heuristic, so this code is just
80 // an approximation. We shouldn't need to do this for larger sizes, but at those
81 // sizes, the quality difference gets less and less between our general
82 // scanconverter and GDI's.
83 if (SkMask::kA8_Format == rec.fMaskFormat && !isAxisAligned(rec)) {
87 return rec.getHinting() == SkPaint::kNo_Hinting || rec.getHinting() == SkPaint::kSlight_Hinting;
90 using namespace skia_advanced_typeface_metrics_utils;
92 static void tchar_to_skstring(const TCHAR t[], SkString* s) {
94 size_t sSize = WideCharToMultiByte(CP_UTF8, 0, t, -1, NULL, 0, NULL, NULL);
96 WideCharToMultiByte(CP_UTF8, 0, t, -1, s->writable_str(), sSize, NULL, NULL);
102 static void dcfontname_to_skstring(HDC deviceContext, const LOGFONT& lf, SkString* familyName) {
103 int fontNameLen; //length of fontName in TCHARS.
104 if (0 == (fontNameLen = GetTextFace(deviceContext, 0, NULL))) {
105 call_ensure_accessible(lf);
106 if (0 == (fontNameLen = GetTextFace(deviceContext, 0, NULL))) {
111 SkAutoSTArray<LF_FULLFACESIZE, TCHAR> fontName(fontNameLen+1);
112 if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) {
113 call_ensure_accessible(lf);
114 if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) {
119 tchar_to_skstring(fontName.get(), familyName);
122 static void make_canonical(LOGFONT* lf) {
124 lf->lfQuality = CLEARTYPE_QUALITY;//PROOF_QUALITY;
125 lf->lfCharSet = DEFAULT_CHARSET;
126 // lf->lfClipPrecision = 64;
129 static SkFontStyle get_style(const LOGFONT& lf) {
130 return SkFontStyle(lf.lfWeight,
132 lf.lfItalic ? SkFontStyle::kItalic_Slant : SkFontStyle::kUpright_Slant);
135 static inline FIXED SkFixedToFIXED(SkFixed x) {
136 return *(FIXED*)(&x);
138 static inline SkFixed SkFIXEDToFixed(FIXED x) {
139 return *(SkFixed*)(&x);
142 static inline FIXED SkScalarToFIXED(SkScalar x) {
143 return SkFixedToFIXED(SkScalarToFixed(x));
146 static inline SkScalar SkFIXEDToScalar(FIXED x) {
147 return SkFixedToScalar(SkFIXEDToFixed(x));
150 static unsigned calculateGlyphCount(HDC hdc, const LOGFONT& lf) {
151 TEXTMETRIC textMetric;
152 if (0 == GetTextMetrics(hdc, &textMetric)) {
153 textMetric.tmPitchAndFamily = TMPF_VECTOR;
154 call_ensure_accessible(lf);
155 GetTextMetrics(hdc, &textMetric);
158 if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) {
159 return textMetric.tmLastChar;
162 // The 'maxp' table stores the number of glyphs at offset 4, in 2 bytes.
164 if (GDI_ERROR != GetFontData(hdc, SkOTTableMaximumProfile::TAG, 4, &glyphs, sizeof(glyphs))) {
165 return SkEndian_SwapBE16(glyphs);
168 // Binary search for glyph count.
169 static const MAT2 mat2 = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
170 int32_t max = SK_MaxU16 + 1;
174 int32_t mid = min + ((max - min) / 2);
175 if (GetGlyphOutlineW(hdc, mid, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0,
176 NULL, &mat2) == GDI_ERROR) {
182 SkASSERT(min == max);
186 static unsigned calculateUPEM(HDC hdc, const LOGFONT& lf) {
187 TEXTMETRIC textMetric;
188 if (0 == GetTextMetrics(hdc, &textMetric)) {
189 textMetric.tmPitchAndFamily = TMPF_VECTOR;
190 call_ensure_accessible(lf);
191 GetTextMetrics(hdc, &textMetric);
194 if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) {
195 return textMetric.tmMaxCharWidth;
198 OUTLINETEXTMETRIC otm;
199 unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
201 call_ensure_accessible(lf);
202 otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
205 return (0 == otmRet) ? 0 : otm.otmEMSquare;
208 class LogFontTypeface : public SkTypeface {
210 LogFontTypeface(const SkFontStyle& style, const LOGFONT& lf, bool serializeAsStream)
211 : SkTypeface(style, SkTypefaceCache::NewFontID(), false)
213 , fSerializeAsStream(serializeAsStream)
216 // If the font has cubic outlines, it will not be rendered with ClearType.
217 HFONT font = CreateFontIndirect(&lf);
219 HDC deviceContext = ::CreateCompatibleDC(NULL);
220 HFONT savefont = (HFONT)SelectObject(deviceContext, font);
222 TEXTMETRIC textMetric;
223 if (0 == GetTextMetrics(deviceContext, &textMetric)) {
224 call_ensure_accessible(lf);
225 if (0 == GetTextMetrics(deviceContext, &textMetric)) {
226 textMetric.tmPitchAndFamily = TMPF_TRUETYPE;
230 ::SelectObject(deviceContext, savefont);
231 ::DeleteDC(deviceContext);
234 ::DeleteObject(font);
237 // The fixed pitch bit is set if the font is *not* fixed pitch.
238 this->setIsFixedPitch((textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0);
240 // Used a logfont on a memory context, should never get a device font.
241 // Therefore all TMPF_DEVICE will be PostScript (cubic) fonts.
242 fCanBeLCD = !((textMetric.tmPitchAndFamily & TMPF_VECTOR) &&
243 (textMetric.tmPitchAndFamily & TMPF_DEVICE));
247 bool fSerializeAsStream;
250 static LogFontTypeface* Create(const LOGFONT& lf) {
251 return new LogFontTypeface(get_style(lf), lf, false);
254 static void EnsureAccessible(const SkTypeface* face) {
255 call_ensure_accessible(static_cast<const LogFontTypeface*>(face)->fLogFont);
259 virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE;
260 virtual SkScalerContext* onCreateScalerContext(const SkDescriptor*) const SK_OVERRIDE;
261 virtual void onFilterRec(SkScalerContextRec*) const SK_OVERRIDE;
262 virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics(
263 SkAdvancedTypefaceMetrics::PerGlyphInfo,
264 const uint32_t*, uint32_t) const SK_OVERRIDE;
265 virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE;
266 virtual int onCharsToGlyphs(const void* chars, Encoding encoding,
267 uint16_t glyphs[], int glyphCount) const SK_OVERRIDE;
268 virtual int onCountGlyphs() const SK_OVERRIDE;
269 virtual int onGetUPEM() const SK_OVERRIDE;
270 virtual void onGetFamilyName(SkString* familyName) const SK_OVERRIDE;
271 virtual SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const SK_OVERRIDE;
272 virtual int onGetTableTags(SkFontTableTag tags[]) const SK_OVERRIDE;
273 virtual size_t onGetTableData(SkFontTableTag, size_t offset,
274 size_t length, void* data) const SK_OVERRIDE;
277 class FontMemResourceTypeface : public LogFontTypeface {
280 * The created FontMemResourceTypeface takes ownership of fontMemResource.
282 static FontMemResourceTypeface* Create(const LOGFONT& lf, HANDLE fontMemResource) {
283 return new FontMemResourceTypeface(get_style(lf), lf, fontMemResource);
287 virtual void weak_dispose() const SK_OVERRIDE {
288 RemoveFontMemResourceEx(fFontMemResource);
289 //SkTypefaceCache::Remove(this);
290 INHERITED::weak_dispose();
295 * Takes ownership of fontMemResource.
297 FontMemResourceTypeface(const SkFontStyle& style, const LOGFONT& lf, HANDLE fontMemResource)
298 : LogFontTypeface(style, lf, true), fFontMemResource(fontMemResource)
301 HANDLE fFontMemResource;
303 typedef LogFontTypeface INHERITED;
306 static const LOGFONT& get_default_font() {
307 static LOGFONT gDefaultFont;
311 static bool FindByLogFont(SkTypeface* face, const SkFontStyle& requestedStyle, void* ctx) {
312 LogFontTypeface* lface = static_cast<LogFontTypeface*>(face);
313 const LOGFONT* lf = reinterpret_cast<const LOGFONT*>(ctx);
316 get_style(lface->fLogFont) == requestedStyle &&
317 !memcmp(&lface->fLogFont, lf, sizeof(LOGFONT));
321 * This guy is public. It first searches the cache, and if a match is not found,
322 * it creates a new face.
324 SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT& origLF) {
327 SkTypeface* face = SkTypefaceCache::FindByProcAndRef(FindByLogFont, &lf);
329 face = LogFontTypeface::Create(lf);
330 SkTypefaceCache::Add(face, get_style(lf));
336 * The created SkTypeface takes ownership of fontMemResource.
338 SkTypeface* SkCreateFontMemResourceTypefaceFromLOGFONT(const LOGFONT& origLF, HANDLE fontMemResource) {
341 // We'll never get a cache hit, so no point in putting this in SkTypefaceCache.
342 return FontMemResourceTypeface::Create(lf, fontMemResource);
348 void SkLOGFONTFromTypeface(const SkTypeface* face, LOGFONT* lf) {
350 *lf = get_default_font();
352 *lf = static_cast<const LogFontTypeface*>(face)->fLogFont;
356 // Construct Glyph to Unicode table.
357 // Unicode code points that require conjugate pairs in utf16 are not
359 // TODO(arthurhsu): Add support for conjugate pairs. It looks like that may
360 // require parsing the TTF cmap table (platform 4, encoding 12) directly instead
361 // of calling GetFontUnicodeRange().
362 static void populate_glyph_to_unicode(HDC fontHdc, const unsigned glyphCount,
363 SkTDArray<SkUnichar>* glyphToUnicode) {
364 DWORD glyphSetBufferSize = GetFontUnicodeRanges(fontHdc, NULL);
365 if (!glyphSetBufferSize) {
369 SkAutoTDeleteArray<BYTE> glyphSetBuffer(new BYTE[glyphSetBufferSize]);
371 reinterpret_cast<LPGLYPHSET>(glyphSetBuffer.get());
372 if (GetFontUnicodeRanges(fontHdc, glyphSet) != glyphSetBufferSize) {
376 glyphToUnicode->setCount(glyphCount);
377 memset(glyphToUnicode->begin(), 0, glyphCount * sizeof(SkUnichar));
378 for (DWORD i = 0; i < glyphSet->cRanges; ++i) {
379 // There is no guarantee that within a Unicode range, the corresponding
380 // glyph id in a font file are continuous. So, even if we have ranges,
381 // we can't just use the first and last entry of the range to compute
382 // result. We need to enumerate them one by one.
383 int count = glyphSet->ranges[i].cGlyphs;
384 SkAutoTArray<WCHAR> chars(count + 1);
385 chars[count] = 0; // termintate string
386 SkAutoTArray<WORD> glyph(count);
387 for (USHORT j = 0; j < count; ++j) {
388 chars[j] = glyphSet->ranges[i].wcLow + j;
390 GetGlyphIndicesW(fontHdc, chars.get(), count, glyph.get(),
391 GGI_MARK_NONEXISTING_GLYPHS);
392 // If the glyph ID is valid, and the glyph is not mapped, then we will
393 // fill in the char id into the vector. If the glyph is mapped already,
395 // TODO(arthurhsu): better improve this. e.g. Get all used char ids from
396 // font cache, then generate this mapping table from there. It's
397 // unlikely to have collisions since glyph reuse happens mostly for
398 // different Unicode pages.
399 for (USHORT j = 0; j < count; ++j) {
400 if (glyph[j] != 0xffff && glyph[j] < glyphCount &&
401 (*glyphToUnicode)[glyph[j]] == 0) {
402 (*glyphToUnicode)[glyph[j]] = chars[j];
408 //////////////////////////////////////////////////////////////////////////////////////
410 static int alignTo32(int n) {
411 return (n + 31) & ~31;
414 struct MyBitmapInfo : public BITMAPINFO {
415 RGBQUAD fMoreSpaceForColors[1];
425 fWidth = fHeight = 0;
438 void init(HFONT font, const XFORM& xform) {
443 const void* draw(const SkGlyph&, bool isBW, size_t* srcRBPtr);
450 void* fBits; // points into fBM
456 const void* HDCOffscreen::draw(const SkGlyph& glyph, bool isBW,
458 // Can we share the scalercontext's fDDC, so we don't need to create
459 // a separate fDC here?
461 fDC = CreateCompatibleDC(0);
465 SetGraphicsMode(fDC, GM_ADVANCED);
466 SetBkMode(fDC, TRANSPARENT);
467 SetTextAlign(fDC, TA_LEFT | TA_BASELINE);
468 SelectObject(fDC, fFont);
470 COLORREF color = 0x00FFFFFF;
471 SkDEBUGCODE(COLORREF prev =) SetTextColor(fDC, color);
472 SkASSERT(prev != CLR_INVALID);
475 if (fBM && (fIsBW != isBW || fWidth < glyph.fWidth || fHeight < glyph.fHeight)) {
481 fWidth = SkMax32(fWidth, glyph.fWidth);
482 fHeight = SkMax32(fHeight, glyph.fHeight);
484 int biWidth = isBW ? alignTo32(fWidth) : fWidth;
488 sk_bzero(&info, sizeof(info));
490 RGBQUAD blackQuad = { 0, 0, 0, 0 };
491 RGBQUAD whiteQuad = { 0xFF, 0xFF, 0xFF, 0 };
492 info.bmiColors[0] = blackQuad;
493 info.bmiColors[1] = whiteQuad;
495 info.bmiHeader.biSize = sizeof(info.bmiHeader);
496 info.bmiHeader.biWidth = biWidth;
497 info.bmiHeader.biHeight = fHeight;
498 info.bmiHeader.biPlanes = 1;
499 info.bmiHeader.biBitCount = isBW ? 1 : 32;
500 info.bmiHeader.biCompression = BI_RGB;
502 info.bmiHeader.biClrUsed = 2;
504 fBM = CreateDIBSection(fDC, &info, DIB_RGB_COLORS, &fBits, 0, 0);
508 SelectObject(fDC, fBM);
512 size_t srcRB = isBW ? (biWidth >> 3) : (fWidth << 2);
513 size_t size = fHeight * srcRB;
514 memset(fBits, 0, size);
516 XFORM xform = fXform;
517 xform.eDx = (float)-glyph.fLeft;
518 xform.eDy = (float)-glyph.fTop;
519 SetWorldTransform(fDC, &xform);
521 uint16_t glyphID = glyph.getGlyphID();
522 BOOL ret = ExtTextOutW(fDC, 0, 0, ETO_GLYPH_INDEX, NULL, reinterpret_cast<LPCWSTR>(&glyphID), 1, NULL);
528 // offset to the start of the image
529 return (const char*)fBits + (fHeight - glyph.fHeight) * srcRB;
532 //////////////////////////////////////////////////////////////////////////////
533 #define BUFFERSIZE (1 << 13)
535 class SkScalerContext_GDI : public SkScalerContext {
537 SkScalerContext_GDI(SkTypeface*, const SkDescriptor* desc);
538 virtual ~SkScalerContext_GDI();
540 // Returns true if the constructor was able to complete all of its
541 // initializations (which may include calling GDI).
542 bool isValid() const;
545 virtual unsigned generateGlyphCount() SK_OVERRIDE;
546 virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE;
547 virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE;
548 virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE;
549 virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE;
550 virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE;
551 virtual void generateFontMetrics(SkPaint::FontMetrics*) SK_OVERRIDE;
554 DWORD getGDIGlyphPath(const SkGlyph& glyph, UINT flags,
555 SkAutoSTMalloc<BUFFERSIZE, uint8_t>* glyphbuf);
557 HDCOffscreen fOffscreen;
558 /** fGsA is the non-rotational part of total matrix without the text height scale.
559 * Used to find the magnitude of advances.
562 /** The total matrix without the textSize. */
564 /** Scales font to EM size. */
572 /** The total matrix which also removes EM scale. */
573 SkMatrix fHiResMatrix;
574 /** fG_inv is the inverse of the rotational part of the total matrix.
575 * Used to set the direction of advances.
579 kTrueType_Type, kBitmap_Type, kLine_Type
584 static FIXED float2FIXED(float x) {
585 return SkFixedToFIXED(SkFloatToFixed(x));
588 static BYTE compute_quality(const SkScalerContext::Rec& rec) {
589 switch (rec.fMaskFormat) {
590 case SkMask::kBW_Format:
591 return NONANTIALIASED_QUALITY;
592 case SkMask::kLCD16_Format:
593 case SkMask::kLCD32_Format:
594 return CLEARTYPE_QUALITY;
596 if (rec.fFlags & SkScalerContext::kGenA8FromLCD_Flag) {
597 return CLEARTYPE_QUALITY;
599 return ANTIALIASED_QUALITY;
604 SkScalerContext_GDI::SkScalerContext_GDI(SkTypeface* rawTypeface,
605 const SkDescriptor* desc)
606 : SkScalerContext(rawTypeface, desc)
613 LogFontTypeface* typeface = reinterpret_cast<LogFontTypeface*>(rawTypeface);
615 fDDC = ::CreateCompatibleDC(NULL);
619 SetGraphicsMode(fDDC, GM_ADVANCED);
620 SetBkMode(fDDC, TRANSPARENT);
622 SkPoint h = SkPoint::Make(SK_Scalar1, 0);
623 // A is the total matrix.
625 fRec.getSingleMatrix(&A);
628 // G is the Givens Matrix for A (rotational matrix where GA[0][1] == 0).
630 SkComputeGivensRotation(h, &G);
632 // GA is the matrix A with rotation removed.
636 // realTextSize is the actual device size we want (as opposed to the size the user requested).
637 // gdiTextSize is the size we request from GDI.
638 // If the scale is negative, this means the matrix will do the flip anyway.
639 SkScalar realTextSize = SkScalarAbs(GA.get(SkMatrix::kMScaleY));
640 SkScalar gdiTextSize = SkScalarRoundToScalar(realTextSize);
641 if (gdiTextSize == 0) {
642 gdiTextSize = SK_Scalar1;
645 // When not hinting, remove only the gdiTextSize scale which will be applied by GDI.
646 // When GDI hinting, remove the entire Y scale to prevent 'subpixel' metrics.
647 SkScalar scale = (fRec.getHinting() == SkPaint::kNo_Hinting ||
648 fRec.getHinting() == SkPaint::kSlight_Hinting)
649 ? SkScalarInvert(gdiTextSize)
650 : SkScalarInvert(realTextSize);
652 // sA is the total matrix A without the textSize (so GDI knows the text size separately).
653 // When this matrix is used with GetGlyphOutline, no further processing is needed.
655 sA.preScale(scale, scale); //remove text size
657 // GsA is the non-rotational part of A without the text height scale.
658 // This is what is used to find the magnitude of advances.
660 GsA.preScale(scale, scale); //remove text size, G is rotational so reorders with the scale.
662 fGsA.eM11 = SkScalarToFIXED(GsA.get(SkMatrix::kMScaleX));
663 fGsA.eM12 = SkScalarToFIXED(-GsA.get(SkMatrix::kMSkewY)); // This should be ~0.
664 fGsA.eM21 = SkScalarToFIXED(-GsA.get(SkMatrix::kMSkewX));
665 fGsA.eM22 = SkScalarToFIXED(GsA.get(SkMatrix::kMScaleY));
667 // fG_inv is G inverse, which is fairly simple since G is 2x2 rotational.
668 fG_inv.setAll(G.get(SkMatrix::kMScaleX), -G.get(SkMatrix::kMSkewX), G.get(SkMatrix::kMTransX),
669 -G.get(SkMatrix::kMSkewY), G.get(SkMatrix::kMScaleY), G.get(SkMatrix::kMTransY),
670 G.get(SkMatrix::kMPersp0), G.get(SkMatrix::kMPersp1), G.get(SkMatrix::kMPersp2));
672 LOGFONT lf = typeface->fLogFont;
673 lf.lfHeight = -SkScalarTruncToInt(gdiTextSize);
674 lf.lfQuality = compute_quality(fRec);
675 fFont = CreateFontIndirect(&lf);
680 fSavefont = (HFONT)SelectObject(fDDC, fFont);
682 if (0 == GetTextMetrics(fDDC, &fTM)) {
683 call_ensure_accessible(lf);
684 if (0 == GetTextMetrics(fDDC, &fTM)) {
685 fTM.tmPitchAndFamily = TMPF_TRUETYPE;
690 if (fTM.tmPitchAndFamily & TMPF_VECTOR) {
691 // Used a logfont on a memory context, should never get a device font.
692 // Therefore all TMPF_DEVICE will be PostScript fonts.
694 // If TMPF_VECTOR is set, one of TMPF_TRUETYPE or TMPF_DEVICE means that
695 // we have an outline font. Otherwise we have a vector FON, which is
696 // scalable, but not an outline font.
697 // This was determined by testing with Type1 PFM/PFB and
698 // OpenTypeCFF OTF, as well as looking at Wine bugs and sources.
699 if (fTM.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_DEVICE)) {
700 // Truetype or PostScript.
701 fType = SkScalerContext_GDI::kTrueType_Type;
704 fType = SkScalerContext_GDI::kLine_Type;
707 // fPost2x2 is column-major, left handed (y down).
708 // XFORM 2x2 is row-major, left handed (y down).
709 xform.eM11 = SkScalarToFloat(sA.get(SkMatrix::kMScaleX));
710 xform.eM12 = SkScalarToFloat(sA.get(SkMatrix::kMSkewY));
711 xform.eM21 = SkScalarToFloat(sA.get(SkMatrix::kMSkewX));
712 xform.eM22 = SkScalarToFloat(sA.get(SkMatrix::kMScaleY));
716 // MAT2 is row major, right handed (y up).
717 fMat22.eM11 = float2FIXED(xform.eM11);
718 fMat22.eM12 = float2FIXED(-xform.eM12);
719 fMat22.eM21 = float2FIXED(-xform.eM21);
720 fMat22.eM22 = float2FIXED(xform.eM22);
722 if (needToRenderWithSkia(fRec)) {
723 this->forceGenerateImageFromPath();
726 // Create a hires matrix if we need linear metrics.
727 if (this->isSubpixel()) {
728 OUTLINETEXTMETRIC otm;
729 UINT success = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
731 call_ensure_accessible(lf);
732 success = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
735 SkScalar upem = SkIntToScalar(otm.otmEMSquare);
737 SkScalar gdiTextSizeToEMScale = upem / gdiTextSize;
738 fHighResMat22.eM11 = float2FIXED(gdiTextSizeToEMScale);
739 fHighResMat22.eM12 = float2FIXED(0);
740 fHighResMat22.eM21 = float2FIXED(0);
741 fHighResMat22.eM22 = float2FIXED(gdiTextSizeToEMScale);
743 SkScalar removeEMScale = SkScalarInvert(upem);
745 fHiResMatrix.preScale(removeEMScale, removeEMScale);
751 fType = SkScalerContext_GDI::kBitmap_Type;
760 // fPost2x2 is column-major, left handed (y down).
761 // MAT2 is row major, right handed (y up).
762 fMat22.eM11 = SkScalarToFIXED(fRec.fPost2x2[0][0]);
763 fMat22.eM12 = SkScalarToFIXED(-fRec.fPost2x2[1][0]);
764 fMat22.eM21 = SkScalarToFIXED(-fRec.fPost2x2[0][1]);
765 fMat22.eM22 = SkScalarToFIXED(fRec.fPost2x2[1][1]);
768 fOffscreen.init(fFont, xform);
771 SkScalerContext_GDI::~SkScalerContext_GDI() {
773 ::SelectObject(fDDC, fSavefont);
777 ::DeleteObject(fFont);
780 ::ScriptFreeCache(&fSC);
784 bool SkScalerContext_GDI::isValid() const {
785 return fDDC && fFont;
788 unsigned SkScalerContext_GDI::generateGlyphCount() {
789 if (fGlyphCount < 0) {
790 fGlyphCount = calculateGlyphCount(
791 fDDC, static_cast<const LogFontTypeface*>(this->getTypeface())->fLogFont);
796 uint16_t SkScalerContext_GDI::generateCharToGlyph(SkUnichar utf32) {
799 // TODO(ctguil): Support characters that generate more than one glyph.
800 if (SkUTF16_FromUnichar(utf32, (uint16_t*)utf16) == 1) {
801 // Type1 fonts fail with uniscribe API. Use GetGlyphIndices for plane 0.
803 /** Real documentation for GetGlyphIndiciesW:
805 * When GGI_MARK_NONEXISTING_GLYPHS is not specified and a character does not map to a
806 * glyph, then the 'default character's glyph is returned instead. The 'default character'
807 * is available in fTM.tmDefaultChar. FON fonts have a default character, and there exists
808 * a usDefaultChar in the 'OS/2' table, version 2 and later. If there is no
809 * 'default character' specified by the font, then often the first character found is used.
811 * When GGI_MARK_NONEXISTING_GLYPHS is specified and a character does not map to a glyph,
812 * then the glyph 0xFFFF is used. In Windows XP and earlier, Bitmap/Vector FON usually use
813 * glyph 0x1F instead ('Terminal' appears to be special, returning 0xFFFF).
814 * Type1 PFM/PFB, TT, OT TT, OT CFF all appear to use 0xFFFF, even on XP.
816 DWORD result = GetGlyphIndicesW(fDDC, utf16, 1, &index, GGI_MARK_NONEXISTING_GLYPHS);
817 if (result == GDI_ERROR
820 (fType == SkScalerContext_GDI::kBitmap_Type ||
821 fType == SkScalerContext_GDI::kLine_Type)
822 /*&& winVer < Vista */)
828 // Use uniscribe to detemine glyph index for non-BMP characters.
829 static const int numWCHAR = 2;
830 static const int maxItems = 2;
831 // MSDN states that this can be NULL, but some things don't work then.
832 SCRIPT_CONTROL sc = { 0 };
833 // Add extra item to SCRIPT_ITEM to work around a bug (now documented).
834 // https://bugzilla.mozilla.org/show_bug.cgi?id=366643
835 SCRIPT_ITEM si[maxItems + 1];
837 HRZM(ScriptItemize(utf16, numWCHAR, maxItems, &sc, NULL, si, &numItems),
838 "Could not itemize character.");
840 // Sometimes ScriptShape cannot find a glyph for a non-BMP and returns 2 space glyphs.
841 static const int maxGlyphs = 2;
842 SCRIPT_VISATTR vsa[maxGlyphs];
843 WORD outGlyphs[maxGlyphs];
844 WORD logClust[numWCHAR];
846 HRZM(ScriptShape(fDDC, &fSC, utf16, numWCHAR, maxGlyphs, &si[0].a,
847 outGlyphs, logClust, vsa, &numGlyphs),
848 "Could not shape character.");
849 if (1 == numGlyphs) {
850 index = outGlyphs[0];
856 void SkScalerContext_GDI::generateAdvance(SkGlyph* glyph) {
857 this->generateMetrics(glyph);
860 void SkScalerContext_GDI::generateMetrics(SkGlyph* glyph) {
863 if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) {
865 WORD glyphs = glyph->getGlyphID();
866 if (0 == GetTextExtentPointI(fDDC, &glyphs, 1, &size)) {
867 glyph->fWidth = SkToS16(fTM.tmMaxCharWidth);
869 glyph->fWidth = SkToS16(size.cx);
871 glyph->fHeight = SkToS16(size.cy);
873 glyph->fTop = SkToS16(-fTM.tmAscent);
874 // Bitmap FON cannot underhang, but vector FON may.
875 // There appears no means of determining underhang of vector FON.
876 glyph->fLeft = SkToS16(0);
877 glyph->fAdvanceX = SkIntToFixed(glyph->fWidth);
878 glyph->fAdvanceY = 0;
880 // Vector FON will transform nicely, but bitmap FON do not.
881 if (fType == SkScalerContext_GDI::kLine_Type) {
882 SkRect bounds = SkRect::MakeXYWH(glyph->fLeft, glyph->fTop,
883 glyph->fWidth, glyph->fHeight);
885 m.setAll(SkFIXEDToScalar(fMat22.eM11), -SkFIXEDToScalar(fMat22.eM21), 0,
886 -SkFIXEDToScalar(fMat22.eM12), SkFIXEDToScalar(fMat22.eM22), 0,
887 0, 0, SkScalarToPersp(SK_Scalar1));
890 glyph->fLeft = SkScalarTruncToInt(bounds.fLeft);
891 glyph->fTop = SkScalarTruncToInt(bounds.fTop);
892 glyph->fWidth = SkScalarTruncToInt(bounds.width());
893 glyph->fHeight = SkScalarTruncToInt(bounds.height());
896 // Apply matrix to advance.
897 glyph->fAdvanceY = SkFixedMul(-SkFIXEDToFixed(fMat22.eM12), glyph->fAdvanceX);
898 glyph->fAdvanceX = SkFixedMul(SkFIXEDToFixed(fMat22.eM11), glyph->fAdvanceX);
903 UINT glyphId = glyph->getGlyphID();
906 sk_bzero(&gm, sizeof(gm));
908 DWORD status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
909 if (GDI_ERROR == status) {
910 LogFontTypeface::EnsureAccessible(this->getTypeface());
911 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
912 if (GDI_ERROR == status) {
913 glyph->zeroMetrics();
919 // The black box is either the embedded bitmap size or the outline extent.
920 // It is 1x1 if nothing is to be drawn, but will also be 1x1 if something very small
921 // is to be drawn, like a '.'. We need to outset '.' but do not wish to outset ' '.
922 if (1 == gm.gmBlackBoxX && 1 == gm.gmBlackBoxY) {
923 // If GetGlyphOutline with GGO_NATIVE returns 0, we know there was no outline.
924 DWORD bufferSize = GetGlyphOutlineW(fDDC, glyphId, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
925 empty = (0 == bufferSize);
928 glyph->fTop = SkToS16(-gm.gmptGlyphOrigin.y);
929 glyph->fLeft = SkToS16(gm.gmptGlyphOrigin.x);
934 // Outset, since the image may bleed out of the black box.
935 // For embedded bitmaps the black box should be exact.
936 // For outlines we need to outset by 1 in all directions for bleed.
937 // For ClearType we need to outset by 2 for bleed.
938 glyph->fWidth = gm.gmBlackBoxX + 4;
939 glyph->fHeight = gm.gmBlackBoxY + 4;
943 glyph->fAdvanceX = SkIntToFixed(gm.gmCellIncX);
944 glyph->fAdvanceY = SkIntToFixed(gm.gmCellIncY);
945 glyph->fRsbDelta = 0;
946 glyph->fLsbDelta = 0;
948 if (this->isSubpixel()) {
949 sk_bzero(&gm, sizeof(gm));
950 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fHighResMat22);
951 if (GDI_ERROR != status) {
953 fHiResMatrix.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance);
954 glyph->fAdvanceX = SkScalarToFixed(advance.fX);
955 glyph->fAdvanceY = SkScalarToFixed(advance.fY);
957 } else if (!isAxisAligned(this->fRec)) {
958 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fGsA);
959 if (GDI_ERROR != status) {
961 fG_inv.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance);
962 glyph->fAdvanceX = SkScalarToFixed(advance.fX);
963 glyph->fAdvanceY = SkScalarToFixed(advance.fY);
968 static const MAT2 gMat2Identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
969 void SkScalerContext_GDI::generateFontMetrics(SkPaint::FontMetrics* metrics) {
970 if (NULL == metrics) {
973 sk_bzero(metrics, sizeof(*metrics));
977 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
978 if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) {
980 metrics->fTop = SkIntToScalar(-fTM.tmAscent);
981 metrics->fAscent = SkIntToScalar(-fTM.tmAscent);
982 metrics->fDescent = SkIntToScalar(fTM.tmDescent);
983 metrics->fBottom = SkIntToScalar(fTM.tmDescent);
984 metrics->fLeading = SkIntToScalar(fTM.tmExternalLeading);
985 metrics->fAvgCharWidth = SkIntToScalar(fTM.tmAveCharWidth);
986 metrics->fMaxCharWidth = SkIntToScalar(fTM.tmMaxCharWidth);
988 metrics->fXMax = metrics->fMaxCharWidth;
989 //metrics->fXHeight = 0;
990 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
995 OUTLINETEXTMETRIC otm;
997 uint32_t ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
999 LogFontTypeface::EnsureAccessible(this->getTypeface());
1000 ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
1006 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
1007 metrics->fTop = SkIntToScalar(-otm.otmrcFontBox.top);
1008 metrics->fAscent = SkIntToScalar(-otm.otmAscent);
1009 metrics->fDescent = SkIntToScalar(-otm.otmDescent);
1010 metrics->fBottom = SkIntToScalar(-otm.otmrcFontBox.bottom);
1011 metrics->fLeading = SkIntToScalar(otm.otmLineGap);
1012 metrics->fAvgCharWidth = SkIntToScalar(otm.otmTextMetrics.tmAveCharWidth);
1013 metrics->fMaxCharWidth = SkIntToScalar(otm.otmTextMetrics.tmMaxCharWidth);
1014 metrics->fXMin = SkIntToScalar(otm.otmrcFontBox.left);
1015 metrics->fXMax = SkIntToScalar(otm.otmrcFontBox.right);
1017 metrics->fUnderlineThickness = SkIntToScalar(otm.otmsUnderscoreSize);
1018 metrics->fUnderlinePosition = -SkIntToScalar(otm.otmsUnderscorePosition);
1020 metrics->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
1021 metrics->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
1023 metrics->fXHeight = SkIntToScalar(otm.otmsXHeight);
1025 sk_bzero(&gm, sizeof(gm));
1026 DWORD len = GetGlyphOutlineW(fDDC, 'x', GGO_METRICS, &gm, 0, 0, &gMat2Identity);
1027 if (len != GDI_ERROR && gm.gmBlackBoxY > 0) {
1028 metrics->fXHeight = SkIntToScalar(gm.gmBlackBoxY);
1032 ////////////////////////////////////////////////////////////////////////////////////////
1034 #define SK_SHOW_TEXT_BLIT_COVERAGE 0
1036 static void build_power_table(uint8_t table[], float ee) {
1037 for (int i = 0; i < 256; i++) {
1038 float x = i / 255.f;
1039 x = sk_float_pow(x, ee);
1040 int xx = SkScalarRoundToInt(x * 255);
1041 table[i] = SkToU8(xx);
1046 * This will invert the gamma applied by GDI (gray-scale antialiased), so we
1047 * can get linear values.
1049 * GDI grayscale appears to use a hard-coded gamma of 2.3.
1051 * GDI grayscale appears to draw using the black and white rasterizer at four
1052 * times the size and then downsamples to compute the coverage mask. As a
1053 * result there are only seventeen total grays. This lack of fidelity means
1054 * that shifting into other color spaces is imprecise.
1056 static const uint8_t* getInverseGammaTableGDI() {
1057 // Since build_power_table is idempotent, many threads can build gTableGdi
1060 // Microsoft Specific:
1061 // Making gInited volatile provides read-aquire and write-release in vc++.
1062 // In VS2012, see compiler option /volatile:(ms|iso).
1063 // Replace with C++11 atomics when possible.
1064 static volatile bool gInited;
1065 static uint8_t gTableGdi[256];
1067 // Need a L/L (read) barrier (full acquire not needed). If gInited is observed
1068 // true then gTableGdi is observable, but it must be requested.
1070 build_power_table(gTableGdi, 2.3f);
1071 // Need a S/S (write) barrier (full release not needed) here so that this
1072 // write to gInited becomes observable after gTableGdi.
1079 * This will invert the gamma applied by GDI ClearType, so we can get linear
1082 * GDI ClearType uses SPI_GETFONTSMOOTHINGCONTRAST / 1000 as the gamma value.
1083 * If this value is not specified, the default is a gamma of 1.4.
1085 static const uint8_t* getInverseGammaTableClearType() {
1086 // We don't expect SPI_GETFONTSMOOTHINGCONTRAST to ever change, so building
1087 // gTableClearType with build_power_table is effectively idempotent.
1089 // Microsoft Specific:
1090 // Making gInited volatile provides read-aquire and write-release in vc++.
1091 // In VS2012, see compiler option /volatile:(ms|iso).
1092 // Replace with C++11 atomics when possible.
1093 static volatile bool gInited;
1094 static uint8_t gTableClearType[256];
1096 // Need a L/L (read) barrier (acquire not needed). If gInited is observed
1097 // true then gTableClearType is observable, but it must be requested.
1100 if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &level, 0) || !level) {
1101 // can't get the data, so use a default
1104 build_power_table(gTableClearType, level / 1000.0f);
1105 // Need a S/S (write) barrier (release not needed) here so that this
1106 // write to gInited becomes observable after gTableClearType.
1109 return gTableClearType;
1112 #include "SkColorPriv.h"
1114 //Cannot assume that the input rgb is gray due to possible setting of kGenA8FromLCD_Flag.
1115 template<bool APPLY_PREBLEND>
1116 static inline uint8_t rgb_to_a8(SkGdiRGB rgb, const uint8_t* table8) {
1117 U8CPU r = (rgb >> 16) & 0xFF;
1118 U8CPU g = (rgb >> 8) & 0xFF;
1119 U8CPU b = (rgb >> 0) & 0xFF;
1120 return sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8);
1123 template<bool APPLY_PREBLEND>
1124 static inline uint16_t rgb_to_lcd16(SkGdiRGB rgb, const uint8_t* tableR,
1125 const uint8_t* tableG,
1126 const uint8_t* tableB) {
1127 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
1128 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG);
1129 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB);
1130 #if SK_SHOW_TEXT_BLIT_COVERAGE
1131 r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10);
1133 return SkPack888ToRGB16(r, g, b);
1136 template<bool APPLY_PREBLEND>
1137 static inline SkPMColor rgb_to_lcd32(SkGdiRGB rgb, const uint8_t* tableR,
1138 const uint8_t* tableG,
1139 const uint8_t* tableB) {
1140 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
1141 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG);
1142 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB);
1143 #if SK_SHOW_TEXT_BLIT_COVERAGE
1144 r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10);
1146 return SkPackARGB32(0xFF, r, g, b);
1149 // Is this GDI color neither black nor white? If so, we have to keep this
1150 // image as is, rather than smashing it down to a BW mask.
1152 // returns int instead of bool, since we don't want/have to pay to convert
1153 // the zero/non-zero value into a bool
1154 static int is_not_black_or_white(SkGdiRGB c) {
1155 // same as (but faster than)
1157 // return 0 == c || 0x00FFFFFF == c;
1158 return (c + (c & 1)) & 0x00FFFFFF;
1161 static bool is_rgb_really_bw(const SkGdiRGB* src, int width, int height, size_t srcRB) {
1162 for (int y = 0; y < height; ++y) {
1163 for (int x = 0; x < width; ++x) {
1164 if (is_not_black_or_white(src[x])) {
1168 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1173 // gdi's bitmap is upside-down, so we reverse dst walking in Y
1174 // whenever we copy it into skia's buffer
1175 static void rgb_to_bw(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
1176 const SkGlyph& glyph) {
1177 const int width = glyph.fWidth;
1178 const size_t dstRB = (width + 7) >> 3;
1179 uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1181 int byteCount = width >> 3;
1182 int bitCount = width & 7;
1184 // adjust srcRB to skip the values in our byteCount loop,
1185 // since we increment src locally there
1186 srcRB -= byteCount * 8 * sizeof(SkGdiRGB);
1188 for (int y = 0; y < glyph.fHeight; ++y) {
1189 if (byteCount > 0) {
1190 for (int i = 0; i < byteCount; ++i) {
1192 byte |= src[0] & (1 << 7);
1193 byte |= src[1] & (1 << 6);
1194 byte |= src[2] & (1 << 5);
1195 byte |= src[3] & (1 << 4);
1196 byte |= src[4] & (1 << 3);
1197 byte |= src[5] & (1 << 2);
1198 byte |= src[6] & (1 << 1);
1199 byte |= src[7] & (1 << 0);
1206 unsigned mask = 0x80;
1207 for (int i = 0; i < bitCount; i++) {
1208 byte |= src[i] & mask;
1211 dst[byteCount] = byte;
1213 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1216 #if SK_SHOW_TEXT_BLIT_COVERAGE
1217 if (glyph.fWidth > 0 && glyph.fHeight > 0) {
1218 uint8_t* first = (uint8_t*)glyph.fImage;
1219 uint8_t* last = (uint8_t*)((char*)glyph.fImage + glyph.fHeight * dstRB - 1);
1221 *last |= bitCount == 0 ? 1 : 1 << (8 - bitCount);
1226 template<bool APPLY_PREBLEND>
1227 static void rgb_to_a8(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
1228 const SkGlyph& glyph, const uint8_t* table8) {
1229 const size_t dstRB = glyph.rowBytes();
1230 const int width = glyph.fWidth;
1231 uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1233 for (int y = 0; y < glyph.fHeight; y++) {
1234 for (int i = 0; i < width; i++) {
1235 dst[i] = rgb_to_a8<APPLY_PREBLEND>(src[i], table8);
1236 #if SK_SHOW_TEXT_BLIT_COVERAGE
1237 dst[i] = SkMax32(dst[i], 10);
1240 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1245 template<bool APPLY_PREBLEND>
1246 static void rgb_to_lcd16(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph,
1247 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
1248 const size_t dstRB = glyph.rowBytes();
1249 const int width = glyph.fWidth;
1250 uint16_t* SK_RESTRICT dst = (uint16_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1252 for (int y = 0; y < glyph.fHeight; y++) {
1253 for (int i = 0; i < width; i++) {
1254 dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(src[i], tableR, tableG, tableB);
1256 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1257 dst = (uint16_t*)((char*)dst - dstRB);
1261 template<bool APPLY_PREBLEND>
1262 static void rgb_to_lcd32(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph,
1263 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
1264 const size_t dstRB = glyph.rowBytes();
1265 const int width = glyph.fWidth;
1266 uint32_t* SK_RESTRICT dst = (uint32_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1268 for (int y = 0; y < glyph.fHeight; y++) {
1269 for (int i = 0; i < width; i++) {
1270 dst[i] = rgb_to_lcd32<APPLY_PREBLEND>(src[i], tableR, tableG, tableB);
1272 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1273 dst = (uint32_t*)((char*)dst - dstRB);
1277 static inline unsigned clamp255(unsigned x) {
1279 return x - (x >> 8);
1282 void SkScalerContext_GDI::generateImage(const SkGlyph& glyph) {
1285 const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat;
1286 const bool isAA = !isLCD(fRec);
1289 const void* bits = fOffscreen.draw(glyph, isBW, &srcRB);
1291 LogFontTypeface::EnsureAccessible(this->getTypeface());
1292 bits = fOffscreen.draw(glyph, isBW, &srcRB);
1294 sk_bzero(glyph.fImage, glyph.computeImageSize());
1300 const uint8_t* table;
1301 //The offscreen contains a GDI blit if isAA and kGenA8FromLCD_Flag is not set.
1302 //Otherwise the offscreen contains a ClearType blit.
1303 if (isAA && !(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag)) {
1304 table = getInverseGammaTableGDI();
1306 table = getInverseGammaTableClearType();
1308 //Note that the following cannot really be integrated into the
1309 //pre-blend, since we may not be applying the pre-blend; when we aren't
1310 //applying the pre-blend it means that a filter wants linear anyway.
1311 //Other code may also be applying the pre-blend, so we'd need another
1312 //one with this and one without.
1313 SkGdiRGB* addr = (SkGdiRGB*)bits;
1314 for (int y = 0; y < glyph.fHeight; ++y) {
1315 for (int x = 0; x < glyph.fWidth; ++x) {
1316 int r = (addr[x] >> 16) & 0xFF;
1317 int g = (addr[x] >> 8) & 0xFF;
1318 int b = (addr[x] >> 0) & 0xFF;
1319 addr[x] = (table[r] << 16) | (table[g] << 8) | table[b];
1321 addr = SkTAddOffset<SkGdiRGB>(addr, srcRB);
1325 int width = glyph.fWidth;
1326 size_t dstRB = glyph.rowBytes();
1328 const uint8_t* src = (const uint8_t*)bits;
1329 uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1330 for (int y = 0; y < glyph.fHeight; y++) {
1331 memcpy(dst, src, dstRB);
1335 #if SK_SHOW_TEXT_BLIT_COVERAGE
1336 if (glyph.fWidth > 0 && glyph.fHeight > 0) {
1337 int bitCount = width & 7;
1338 uint8_t* first = (uint8_t*)glyph.fImage;
1339 uint8_t* last = (uint8_t*)((char*)glyph.fImage + glyph.fHeight * dstRB - 1);
1341 *last |= bitCount == 0 ? 1 : 1 << (8 - bitCount);
1345 // since the caller may require A8 for maskfilters, we can't check for BW
1346 // ... until we have the caller tell us that explicitly
1347 const SkGdiRGB* src = (const SkGdiRGB*)bits;
1348 if (fPreBlend.isApplicable()) {
1349 rgb_to_a8<true>(src, srcRB, glyph, fPreBlend.fG);
1351 rgb_to_a8<false>(src, srcRB, glyph, fPreBlend.fG);
1354 const SkGdiRGB* src = (const SkGdiRGB*)bits;
1355 if (is_rgb_really_bw(src, width, glyph.fHeight, srcRB)) {
1356 rgb_to_bw(src, srcRB, glyph);
1357 ((SkGlyph*)&glyph)->fMaskFormat = SkMask::kBW_Format;
1359 if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
1360 if (fPreBlend.isApplicable()) {
1361 rgb_to_lcd16<true>(src, srcRB, glyph,
1362 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1364 rgb_to_lcd16<false>(src, srcRB, glyph,
1365 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1368 SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat);
1369 if (fPreBlend.isApplicable()) {
1370 rgb_to_lcd32<true>(src, srcRB, glyph,
1371 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1373 rgb_to_lcd32<false>(src, srcRB, glyph,
1374 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1381 class GDIGlyphbufferPointIter {
1383 GDIGlyphbufferPointIter(const uint8_t* glyphbuf, DWORD total_size)
1384 : fHeaderIter(glyphbuf, total_size), fCurveIter(), fPointIter()
1387 POINTFX const * next() {
1389 if (!fCurveIter.isSet()) {
1390 const TTPOLYGONHEADER* header = fHeaderIter.next();
1391 if (NULL == header) {
1394 fCurveIter.set(header);
1395 const TTPOLYCURVE* curve = fCurveIter.next();
1396 if (NULL == curve) {
1399 fPointIter.set(curve);
1400 return &header->pfxStart;
1403 const POINTFX* nextPoint = fPointIter.next();
1404 if (NULL == nextPoint) {
1405 const TTPOLYCURVE* curve = fCurveIter.next();
1406 if (NULL == curve) {
1410 fPointIter.set(curve);
1412 nextPoint = fPointIter.next();
1417 WORD currentCurveType() {
1418 return fPointIter.fCurveType;
1422 /** Iterates over all of the polygon headers in a glyphbuf. */
1423 class GDIPolygonHeaderIter {
1425 GDIPolygonHeaderIter(const uint8_t* glyphbuf, DWORD total_size)
1426 : fCurPolygon(reinterpret_cast<const TTPOLYGONHEADER*>(glyphbuf))
1427 , fEndPolygon(SkTAddOffset<const TTPOLYGONHEADER>(glyphbuf, total_size))
1430 const TTPOLYGONHEADER* next() {
1431 if (fCurPolygon >= fEndPolygon) {
1434 const TTPOLYGONHEADER* thisPolygon = fCurPolygon;
1435 fCurPolygon = SkTAddOffset<const TTPOLYGONHEADER>(fCurPolygon, fCurPolygon->cb);
1439 const TTPOLYGONHEADER* fCurPolygon;
1440 const TTPOLYGONHEADER* fEndPolygon;
1443 /** Iterates over all of the polygon curves in a polygon header. */
1444 class GDIPolygonCurveIter {
1446 GDIPolygonCurveIter() : fCurCurve(NULL), fEndCurve(NULL) { }
1448 GDIPolygonCurveIter(const TTPOLYGONHEADER* curPolygon)
1449 : fCurCurve(SkTAddOffset<const TTPOLYCURVE>(curPolygon, sizeof(TTPOLYGONHEADER)))
1450 , fEndCurve(SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon->cb))
1453 bool isSet() { return fCurCurve != NULL; }
1455 void set(const TTPOLYGONHEADER* curPolygon) {
1456 fCurCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon, sizeof(TTPOLYGONHEADER));
1457 fEndCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon->cb);
1464 const TTPOLYCURVE* next() {
1465 if (fCurCurve >= fEndCurve) {
1468 const TTPOLYCURVE* thisCurve = fCurCurve;
1469 fCurCurve = SkTAddOffset<const TTPOLYCURVE>(fCurCurve, size_of_TTPOLYCURVE(*fCurCurve));
1473 size_t size_of_TTPOLYCURVE(const TTPOLYCURVE& curve) {
1474 return 2*sizeof(WORD) + curve.cpfx*sizeof(POINTFX);
1476 const TTPOLYCURVE* fCurCurve;
1477 const TTPOLYCURVE* fEndCurve;
1480 /** Iterates over all of the polygon points in a polygon curve. */
1481 class GDIPolygonCurvePointIter {
1483 GDIPolygonCurvePointIter() : fCurveType(0), fCurPoint(NULL), fEndPoint(NULL) { }
1485 GDIPolygonCurvePointIter(const TTPOLYCURVE* curPolygon)
1486 : fCurveType(curPolygon->wType)
1487 , fCurPoint(&curPolygon->apfx[0])
1488 , fEndPoint(&curPolygon->apfx[curPolygon->cpfx])
1491 bool isSet() { return fCurPoint != NULL; }
1493 void set(const TTPOLYCURVE* curPolygon) {
1494 fCurveType = curPolygon->wType;
1495 fCurPoint = &curPolygon->apfx[0];
1496 fEndPoint = &curPolygon->apfx[curPolygon->cpfx];
1503 const POINTFX* next() {
1504 if (fCurPoint >= fEndPoint) {
1507 const POINTFX* thisPoint = fCurPoint;
1514 const POINTFX* fCurPoint;
1515 const POINTFX* fEndPoint;
1518 GDIPolygonHeaderIter fHeaderIter;
1519 GDIPolygonCurveIter fCurveIter;
1520 GDIPolygonCurvePointIter fPointIter;
1523 static void sk_path_from_gdi_path(SkPath* path, const uint8_t* glyphbuf, DWORD total_size) {
1524 const uint8_t* cur_glyph = glyphbuf;
1525 const uint8_t* end_glyph = glyphbuf + total_size;
1527 while (cur_glyph < end_glyph) {
1528 const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
1530 const uint8_t* end_poly = cur_glyph + th->cb;
1531 const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
1533 path->moveTo(SkFixedToScalar( SkFIXEDToFixed(th->pfxStart.x)),
1534 SkFixedToScalar(-SkFIXEDToFixed(th->pfxStart.y)));
1536 while (cur_poly < end_poly) {
1537 const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
1539 if (pc->wType == TT_PRIM_LINE) {
1540 for (uint16_t i = 0; i < pc->cpfx; i++) {
1541 path->lineTo(SkFixedToScalar( SkFIXEDToFixed(pc->apfx[i].x)),
1542 SkFixedToScalar(-SkFIXEDToFixed(pc->apfx[i].y)));
1546 if (pc->wType == TT_PRIM_QSPLINE) {
1547 for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline
1548 POINTFX pnt_b = pc->apfx[u]; // B is always the current point
1549 POINTFX pnt_c = pc->apfx[u+1];
1551 if (u < pc->cpfx - 2) { // If not on last spline, compute C
1552 pnt_c.x = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.x),
1553 SkFIXEDToFixed(pnt_c.x)));
1554 pnt_c.y = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.y),
1555 SkFIXEDToFixed(pnt_c.y)));
1558 path->quadTo(SkFixedToScalar( SkFIXEDToFixed(pnt_b.x)),
1559 SkFixedToScalar(-SkFIXEDToFixed(pnt_b.y)),
1560 SkFixedToScalar( SkFIXEDToFixed(pnt_c.x)),
1561 SkFixedToScalar(-SkFIXEDToFixed(pnt_c.y)));
1564 // Advance past this TTPOLYCURVE.
1565 cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx;
1567 cur_glyph += th->cb;
1572 #define move_next_expected_hinted_point(iter, pElem) do {\
1573 pElem = iter.next(); \
1574 if (NULL == pElem) return false; \
1577 // It is possible for the hinted and unhinted versions of the same path to have
1578 // a different number of points due to GDI's handling of flipped points.
1579 // If this is detected, this will return false.
1580 static bool sk_path_from_gdi_paths(SkPath* path, const uint8_t* glyphbuf, DWORD total_size,
1581 GDIGlyphbufferPointIter hintedYs) {
1582 const uint8_t* cur_glyph = glyphbuf;
1583 const uint8_t* end_glyph = glyphbuf + total_size;
1585 POINTFX const * hintedPoint;
1587 while (cur_glyph < end_glyph) {
1588 const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
1590 const uint8_t* end_poly = cur_glyph + th->cb;
1591 const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
1593 move_next_expected_hinted_point(hintedYs, hintedPoint);
1594 path->moveTo(SkFixedToScalar( SkFIXEDToFixed(th->pfxStart.x)),
1595 SkFixedToScalar(-SkFIXEDToFixed(hintedPoint->y)));
1597 while (cur_poly < end_poly) {
1598 const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
1600 if (pc->wType == TT_PRIM_LINE) {
1601 for (uint16_t i = 0; i < pc->cpfx; i++) {
1602 move_next_expected_hinted_point(hintedYs, hintedPoint);
1603 path->lineTo(SkFixedToScalar( SkFIXEDToFixed(pc->apfx[i].x)),
1604 SkFixedToScalar(-SkFIXEDToFixed(hintedPoint->y)));
1608 if (pc->wType == TT_PRIM_QSPLINE) {
1609 POINTFX currentPoint = pc->apfx[0];
1610 move_next_expected_hinted_point(hintedYs, hintedPoint);
1611 // only take the hinted y if it wasn't flipped
1612 if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) {
1613 currentPoint.y = hintedPoint->y;
1615 for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline
1616 POINTFX pnt_b = currentPoint;//pc->apfx[u]; // B is always the current point
1617 POINTFX pnt_c = pc->apfx[u+1];
1618 move_next_expected_hinted_point(hintedYs, hintedPoint);
1619 // only take the hinted y if it wasn't flipped
1620 if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) {
1621 pnt_c.y = hintedPoint->y;
1623 currentPoint.x = pnt_c.x;
1624 currentPoint.y = pnt_c.y;
1626 if (u < pc->cpfx - 2) { // If not on last spline, compute C
1627 pnt_c.x = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.x),
1628 SkFIXEDToFixed(pnt_c.x)));
1629 pnt_c.y = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.y),
1630 SkFIXEDToFixed(pnt_c.y)));
1633 path->quadTo(SkFixedToScalar( SkFIXEDToFixed(pnt_b.x)),
1634 SkFixedToScalar(-SkFIXEDToFixed(pnt_b.y)),
1635 SkFixedToScalar( SkFIXEDToFixed(pnt_c.x)),
1636 SkFixedToScalar(-SkFIXEDToFixed(pnt_c.y)));
1639 // Advance past this TTPOLYCURVE.
1640 cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx;
1642 cur_glyph += th->cb;
1648 DWORD SkScalerContext_GDI::getGDIGlyphPath(const SkGlyph& glyph, UINT flags,
1649 SkAutoSTMalloc<BUFFERSIZE, uint8_t>* glyphbuf)
1653 DWORD total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, BUFFERSIZE, glyphbuf->get(), &fMat22);
1654 // Sometimes GetGlyphOutlineW returns a number larger than BUFFERSIZE even if BUFFERSIZE > 0.
1655 // It has been verified that this does not involve a buffer overrun.
1656 if (GDI_ERROR == total_size || total_size > BUFFERSIZE) {
1657 // GDI_ERROR because the BUFFERSIZE was too small, or because the data was not accessible.
1658 // When the data is not accessable GetGlyphOutlineW fails rather quickly,
1659 // so just try to get the size. If that fails then ensure the data is accessible.
1660 total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, 0, NULL, &fMat22);
1661 if (GDI_ERROR == total_size) {
1662 LogFontTypeface::EnsureAccessible(this->getTypeface());
1663 total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, 0, NULL, &fMat22);
1664 if (GDI_ERROR == total_size) {
1665 // GetGlyphOutlineW is known to fail for some characters, such as spaces.
1666 // In these cases, just return that the glyph does not have a shape.
1671 glyphbuf->reset(total_size);
1673 DWORD ret = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, total_size, glyphbuf->get(), &fMat22);
1674 if (GDI_ERROR == ret) {
1675 LogFontTypeface::EnsureAccessible(this->getTypeface());
1676 ret = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, total_size, glyphbuf->get(), &fMat22);
1677 if (GDI_ERROR == ret) {
1686 void SkScalerContext_GDI::generatePath(const SkGlyph& glyph, SkPath* path) {
1687 SkASSERT(&glyph && path);
1692 // Out of all the fonts on a typical Windows box,
1693 // 25% of glyphs require more than 2KB.
1694 // 1% of glyphs require more than 4KB.
1695 // 0.01% of glyphs require more than 8KB.
1696 // 8KB is less than 1% of the normal 1MB stack on Windows.
1697 // Note that some web fonts glyphs require more than 20KB.
1698 //static const DWORD BUFFERSIZE = (1 << 13);
1700 //GDI only uses hinted outlines when axis aligned.
1701 UINT format = GGO_NATIVE | GGO_GLYPH_INDEX;
1702 if (fRec.getHinting() == SkPaint::kNo_Hinting || fRec.getHinting() == SkPaint::kSlight_Hinting){
1703 format |= GGO_UNHINTED;
1705 SkAutoSTMalloc<BUFFERSIZE, uint8_t> glyphbuf(BUFFERSIZE);
1706 DWORD total_size = getGDIGlyphPath(glyph, format, &glyphbuf);
1707 if (0 == total_size) {
1711 if (fRec.getHinting() != SkPaint::kSlight_Hinting) {
1712 sk_path_from_gdi_path(path, glyphbuf, total_size);
1714 //GDI only uses hinted outlines when axis aligned.
1715 UINT format = GGO_NATIVE | GGO_GLYPH_INDEX;
1717 SkAutoSTMalloc<BUFFERSIZE, uint8_t> hintedGlyphbuf(BUFFERSIZE);
1718 DWORD hinted_total_size = getGDIGlyphPath(glyph, format, &hintedGlyphbuf);
1719 if (0 == hinted_total_size) {
1723 if (!sk_path_from_gdi_paths(path, glyphbuf, total_size,
1724 GDIGlyphbufferPointIter(hintedGlyphbuf, hinted_total_size)))
1727 sk_path_from_gdi_path(path, glyphbuf, total_size);
1732 static void logfont_for_name(const char* familyName, LOGFONT* lf) {
1733 sk_bzero(lf, sizeof(LOGFONT));
1735 // Get the buffer size needed first.
1736 size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName,
1738 // Allocate a buffer (str_len already has terminating null
1740 wchar_t *wideFamilyName = new wchar_t[str_len];
1741 // Now actually convert the string.
1742 ::MultiByteToWideChar(CP_UTF8, 0, familyName, -1,
1743 wideFamilyName, str_len);
1744 ::wcsncpy(lf->lfFaceName, wideFamilyName, LF_FACESIZE - 1);
1745 delete [] wideFamilyName;
1746 lf->lfFaceName[LF_FACESIZE-1] = L'\0';
1748 ::strncpy(lf->lfFaceName, familyName, LF_FACESIZE - 1);
1749 lf->lfFaceName[LF_FACESIZE - 1] = '\0';
1753 void LogFontTypeface::onGetFamilyName(SkString* familyName) const {
1754 // Get the actual name of the typeface. The logfont may not know this.
1755 HFONT font = CreateFontIndirect(&fLogFont);
1757 HDC deviceContext = ::CreateCompatibleDC(NULL);
1758 HFONT savefont = (HFONT)SelectObject(deviceContext, font);
1760 dcfontname_to_skstring(deviceContext, fLogFont, familyName);
1762 if (deviceContext) {
1763 ::SelectObject(deviceContext, savefont);
1764 ::DeleteDC(deviceContext);
1767 ::DeleteObject(font);
1771 void LogFontTypeface::onGetFontDescriptor(SkFontDescriptor* desc,
1772 bool* isLocalStream) const {
1773 SkString familyName;
1774 this->onGetFamilyName(&familyName);
1775 desc->setFamilyName(familyName.c_str());
1776 *isLocalStream = this->fSerializeAsStream;
1779 static bool getWidthAdvance(HDC hdc, int gId, int16_t* advance) {
1780 // Initialize the MAT2 structure to the identify transformation matrix.
1781 static const MAT2 mat2 = {SkScalarToFIXED(1), SkScalarToFIXED(0),
1782 SkScalarToFIXED(0), SkScalarToFIXED(1)};
1783 int flags = GGO_METRICS | GGO_GLYPH_INDEX;
1785 if (GDI_ERROR == GetGlyphOutline(hdc, gId, flags, &gm, 0, NULL, &mat2)) {
1789 *advance = gm.gmCellIncX;
1793 SkAdvancedTypefaceMetrics* LogFontTypeface::onGetAdvancedTypefaceMetrics(
1794 SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
1795 const uint32_t* glyphIDs,
1796 uint32_t glyphIDsCount) const {
1797 LOGFONT lf = fLogFont;
1798 SkAdvancedTypefaceMetrics* info = NULL;
1800 HDC hdc = CreateCompatibleDC(NULL);
1801 HFONT font = CreateFontIndirect(&lf);
1802 HFONT savefont = (HFONT)SelectObject(hdc, font);
1803 HFONT designFont = NULL;
1805 const char stem_chars[] = {'i', 'I', '!', '1'};
1807 unsigned glyphCount;
1809 // To request design units, create a logical font whose height is specified
1811 OUTLINETEXTMETRIC otm;
1812 unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
1814 call_ensure_accessible(lf);
1815 otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
1817 if (!otmRet || !GetTextFace(hdc, LF_FACESIZE, lf.lfFaceName)) {
1820 lf.lfHeight = -SkToS32(otm.otmEMSquare);
1821 designFont = CreateFontIndirect(&lf);
1822 SelectObject(hdc, designFont);
1823 if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm)) {
1826 glyphCount = calculateGlyphCount(hdc, fLogFont);
1828 info = new SkAdvancedTypefaceMetrics;
1829 info->fEmSize = otm.otmEMSquare;
1830 info->fLastGlyphID = SkToU16(glyphCount - 1);
1832 tchar_to_skstring(lf.lfFaceName, &info->fFontName);
1833 info->fFlags = SkAdvancedTypefaceMetrics::kEmpty_FontFlag;
1834 // If bit 1 is set, the font may not be embedded in a document.
1835 // If bit 1 is clear, the font can be embedded.
1836 // If bit 2 is set, the embedding is read-only.
1837 if (otm.otmfsType & 0x1) {
1838 info->fFlags = SkTBitOr<SkAdvancedTypefaceMetrics::FontFlags>(
1840 SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag);
1843 if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) {
1844 populate_glyph_to_unicode(hdc, glyphCount, &(info->fGlyphToUnicode));
1847 if (glyphCount > 0 &&
1848 (otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE)) {
1849 info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
1851 info->fType = SkAdvancedTypefaceMetrics::kOther_Font;
1852 info->fItalicAngle = 0;
1856 info->fCapHeight = 0;
1857 info->fBBox = SkIRect::MakeEmpty();
1861 // If this bit is clear the font is a fixed pitch font.
1862 if (!(otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
1863 info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
1865 if (otm.otmTextMetrics.tmItalic) {
1866 info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
1868 if (otm.otmTextMetrics.tmPitchAndFamily & FF_ROMAN) {
1869 info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
1870 } else if (otm.otmTextMetrics.tmPitchAndFamily & FF_SCRIPT) {
1871 info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
1874 // The main italic angle of the font, in tenths of a degree counterclockwise
1876 info->fItalicAngle = otm.otmItalicAngle / 10;
1877 info->fAscent = SkToS16(otm.otmTextMetrics.tmAscent);
1878 info->fDescent = SkToS16(-otm.otmTextMetrics.tmDescent);
1879 // TODO(ctguil): Use alternate cap height calculation.
1880 // MSDN says otmsCapEmHeight is not support but it is returning a value on
1882 info->fCapHeight = otm.otmsCapEmHeight;
1884 SkIRect::MakeLTRB(otm.otmrcFontBox.left, otm.otmrcFontBox.top,
1885 otm.otmrcFontBox.right, otm.otmrcFontBox.bottom);
1887 // Figure out a good guess for StemV - Min width of i, I, !, 1.
1888 // This probably isn't very good with an italic font.
1889 min_width = SHRT_MAX;
1891 for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) {
1893 if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) {
1894 int16_t width = abcWidths.abcB;
1895 if (width > 0 && width < min_width) {
1897 info->fStemV = min_width;
1902 if (perGlyphInfo & SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) {
1903 if (info->fStyle & SkAdvancedTypefaceMetrics::kFixedPitch_Style) {
1904 appendRange(&info->fGlyphWidths, 0);
1905 info->fGlyphWidths->fAdvance.append(1, &min_width);
1906 finishRange(info->fGlyphWidths.get(), 0,
1907 SkAdvancedTypefaceMetrics::WidthRange::kDefault);
1909 info->fGlyphWidths.reset(
1920 SelectObject(hdc, savefont);
1921 DeleteObject(designFont);
1928 //Dummy representation of a Base64 encoded GUID from create_unique_font_name.
1929 #define BASE64_GUID_ID "XXXXXXXXXXXXXXXXXXXXXXXX"
1930 //Length of GUID representation from create_id, including NULL terminator.
1931 #define BASE64_GUID_ID_LEN SK_ARRAY_COUNT(BASE64_GUID_ID)
1933 SK_COMPILE_ASSERT(BASE64_GUID_ID_LEN < LF_FACESIZE, GUID_longer_than_facesize);
1936 NameID 6 Postscript names cannot have the character '/'.
1937 It would be easier to hex encode the GUID, but that is 32 bytes,
1938 and many systems have issues with names longer than 28 bytes.
1939 The following need not be any standard base64 encoding.
1940 The encoded value is never decoded.
1942 static const char postscript_safe_base64_encode[] =
1943 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1944 "abcdefghijklmnopqrstuvwxyz"
1948 Formats a GUID into Base64 and places it into buffer.
1949 buffer should have space for at least BASE64_GUID_ID_LEN characters.
1950 The string will always be null terminated.
1951 XXXXXXXXXXXXXXXXXXXXXXXX0
1953 static void format_guid_b64(const GUID& guid, char* buffer, size_t bufferSize) {
1954 SkASSERT(bufferSize >= BASE64_GUID_ID_LEN);
1955 size_t written = SkBase64::Encode(&guid, sizeof(guid), buffer, postscript_safe_base64_encode);
1956 SkASSERT(written < LF_FACESIZE);
1957 buffer[written] = '\0';
1961 Creates a Base64 encoded GUID and places it into buffer.
1962 buffer should have space for at least BASE64_GUID_ID_LEN characters.
1963 The string will always be null terminated.
1964 XXXXXXXXXXXXXXXXXXXXXXXX0
1966 static HRESULT create_unique_font_name(char* buffer, size_t bufferSize) {
1968 if (FAILED(CoCreateGuid(&guid))) {
1969 return E_UNEXPECTED;
1971 format_guid_b64(guid, buffer, bufferSize);
1977 Introduces a font to GDI. On failure will return NULL. The returned handle
1978 should eventually be passed to RemoveFontMemResourceEx.
1980 static HANDLE activate_font(SkData* fontData) {
1982 //AddFontMemResourceEx just copies the data, but does not specify const.
1983 HANDLE fontHandle = AddFontMemResourceEx(const_cast<void*>(fontData->data()),
1984 static_cast<DWORD>(fontData->size()),
1988 if (fontHandle != NULL && numFonts < 1) {
1989 RemoveFontMemResourceEx(fontHandle);
1996 static SkTypeface* create_from_stream(SkStream* stream) {
1997 // Create a unique and unpredictable font name.
1998 // Avoids collisions and access from CSS.
1999 char familyName[BASE64_GUID_ID_LEN];
2000 const int familyNameSize = SK_ARRAY_COUNT(familyName);
2001 if (FAILED(create_unique_font_name(familyName, familyNameSize))) {
2005 // Change the name of the font.
2006 SkAutoTUnref<SkData> rewrittenFontData(SkOTUtils::RenameFont(stream, familyName, familyNameSize-1));
2007 if (NULL == rewrittenFontData.get()) {
2011 // Register the font with GDI.
2012 HANDLE fontReference = activate_font(rewrittenFontData.get());
2013 if (NULL == fontReference) {
2017 // Create the typeface.
2019 logfont_for_name(familyName, &lf);
2021 return SkCreateFontMemResourceTypefaceFromLOGFONT(lf, fontReference);
2024 SkStream* LogFontTypeface::onOpenStream(int* ttcIndex) const {
2027 const DWORD kTTCTag =
2028 SkEndian_SwapBE32(SkSetFourByteTag('t', 't', 'c', 'f'));
2029 LOGFONT lf = fLogFont;
2031 HDC hdc = ::CreateCompatibleDC(NULL);
2032 HFONT font = CreateFontIndirect(&lf);
2033 HFONT savefont = (HFONT)SelectObject(hdc, font);
2035 SkMemoryStream* stream = NULL;
2036 DWORD tables[2] = {kTTCTag, 0};
2037 for (int i = 0; i < SK_ARRAY_COUNT(tables); i++) {
2038 DWORD bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0);
2039 if (bufferSize == GDI_ERROR) {
2040 call_ensure_accessible(lf);
2041 bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0);
2043 if (bufferSize != GDI_ERROR) {
2044 stream = new SkMemoryStream(bufferSize);
2045 if (GetFontData(hdc, tables[i], 0, (void*)stream->getMemoryBase(), bufferSize)) {
2054 SelectObject(hdc, savefont);
2061 static void bmpCharsToGlyphs(HDC hdc, const WCHAR* bmpChars, int count, uint16_t* glyphs,
2064 DWORD result = GetGlyphIndicesW(hdc, bmpChars, count, glyphs, GGI_MARK_NONEXISTING_GLYPHS);
2065 if (GDI_ERROR == result) {
2066 for (int i = 0; i < count; ++i) {
2073 for (int i = 0; i < count; ++i) {
2074 if (0xFFFF == glyphs[i] || 0x1F == glyphs[i]) {
2079 for (int i = 0; i < count; ++i) {
2080 if (0xFFFF == glyphs[i]){
2087 static uint16_t nonBmpCharToGlyph(HDC hdc, SCRIPT_CACHE* scriptCache, const WCHAR utf16[2]) {
2089 // Use uniscribe to detemine glyph index for non-BMP characters.
2090 static const int numWCHAR = 2;
2091 static const int maxItems = 2;
2092 // MSDN states that this can be NULL, but some things don't work then.
2093 SCRIPT_CONTROL scriptControl = { 0 };
2094 // Add extra item to SCRIPT_ITEM to work around a bug (now documented).
2095 // https://bugzilla.mozilla.org/show_bug.cgi?id=366643
2096 SCRIPT_ITEM si[maxItems + 1];
2098 HRZM(ScriptItemize(utf16, numWCHAR, maxItems, &scriptControl, NULL, si, &numItems),
2099 "Could not itemize character.");
2101 // Sometimes ScriptShape cannot find a glyph for a non-BMP and returns 2 space glyphs.
2102 static const int maxGlyphs = 2;
2103 SCRIPT_VISATTR vsa[maxGlyphs];
2104 WORD outGlyphs[maxGlyphs];
2105 WORD logClust[numWCHAR];
2107 HRZM(ScriptShape(hdc, scriptCache, utf16, numWCHAR, maxGlyphs, &si[0].a,
2108 outGlyphs, logClust, vsa, &numGlyphs),
2109 "Could not shape character.");
2110 if (1 == numGlyphs) {
2111 index = outGlyphs[0];
2118 SkAutoHDC(const LOGFONT& lf)
2119 : fHdc(::CreateCompatibleDC(NULL))
2120 , fFont(::CreateFontIndirect(&lf))
2121 , fSavefont((HFONT)SelectObject(fHdc, fFont))
2124 SelectObject(fHdc, fSavefont);
2125 DeleteObject(fFont);
2128 operator HDC() { return fHdc; }
2134 #define SkAutoHDC(...) SK_REQUIRE_LOCAL_VAR(SkAutoHDC)
2136 int LogFontTypeface::onCharsToGlyphs(const void* chars, Encoding encoding,
2137 uint16_t userGlyphs[], int glyphCount) const
2139 SkAutoHDC hdc(fLogFont);
2142 if (0 == GetTextMetrics(hdc, &tm)) {
2143 call_ensure_accessible(fLogFont);
2144 if (0 == GetTextMetrics(hdc, &tm)) {
2145 tm.tmPitchAndFamily = TMPF_TRUETYPE;
2148 bool Ox1FHack = !(tm.tmPitchAndFamily & TMPF_VECTOR) /*&& winVer < Vista */;
2150 SkAutoSTMalloc<256, uint16_t> scratchGlyphs;
2152 if (userGlyphs != NULL) {
2153 glyphs = userGlyphs;
2155 glyphs = scratchGlyphs.reset(glyphCount);
2158 SCRIPT_CACHE sc = 0;
2160 case SkTypeface::kUTF8_Encoding: {
2161 static const int scratchCount = 256;
2162 WCHAR scratch[scratchCount];
2164 const char* currentUtf8 = reinterpret_cast<const char*>(chars);
2165 SkUnichar currentChar;
2167 currentChar = SkUTF8_NextUnichar(¤tUtf8);
2169 while (glyphIndex < glyphCount) {
2170 // Try a run of bmp.
2171 int glyphsLeft = SkTMin(glyphCount - glyphIndex, scratchCount);
2173 while (runLength < glyphsLeft && currentChar <= 0xFFFF) {
2174 scratch[runLength] = static_cast<WCHAR>(currentChar);
2176 if (runLength < glyphsLeft) {
2177 currentChar = SkUTF8_NextUnichar(¤tUtf8);
2181 bmpCharsToGlyphs(hdc, scratch, runLength, &glyphs[glyphIndex], Ox1FHack);
2182 glyphIndex += runLength;
2185 // Try a run of non-bmp.
2186 while (glyphIndex < glyphCount && currentChar > 0xFFFF) {
2187 SkUTF16_FromUnichar(currentChar, reinterpret_cast<uint16_t*>(scratch));
2188 glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, scratch);
2190 if (glyphIndex < glyphCount) {
2191 currentChar = SkUTF8_NextUnichar(¤tUtf8);
2197 case SkTypeface::kUTF16_Encoding: {
2199 const WCHAR* currentUtf16 = reinterpret_cast<const WCHAR*>(chars);
2200 while (glyphIndex < glyphCount) {
2201 // Try a run of bmp.
2202 int glyphsLeft = glyphCount - glyphIndex;
2204 while (runLength < glyphsLeft && !SkUTF16_IsHighSurrogate(currentUtf16[runLength])) {
2208 bmpCharsToGlyphs(hdc, currentUtf16, runLength, &glyphs[glyphIndex], Ox1FHack);
2209 glyphIndex += runLength;
2210 currentUtf16 += runLength;
2213 // Try a run of non-bmp.
2214 while (glyphIndex < glyphCount && SkUTF16_IsHighSurrogate(*currentUtf16)) {
2215 glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, currentUtf16);
2222 case SkTypeface::kUTF32_Encoding: {
2223 static const int scratchCount = 256;
2224 WCHAR scratch[scratchCount];
2226 const uint32_t* utf32 = reinterpret_cast<const uint32_t*>(chars);
2227 while (glyphIndex < glyphCount) {
2228 // Try a run of bmp.
2229 int glyphsLeft = SkTMin(glyphCount - glyphIndex, scratchCount);
2231 while (runLength < glyphsLeft && utf32[glyphIndex + runLength] <= 0xFFFF) {
2232 scratch[runLength] = static_cast<WCHAR>(utf32[glyphIndex + runLength]);
2236 bmpCharsToGlyphs(hdc, scratch, runLength, &glyphs[glyphIndex], Ox1FHack);
2237 glyphIndex += runLength;
2240 // Try a run of non-bmp.
2241 while (glyphIndex < glyphCount && utf32[glyphIndex] > 0xFFFF) {
2242 SkUTF16_FromUnichar(utf32[glyphIndex], reinterpret_cast<uint16_t*>(scratch));
2243 glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, scratch);
2254 ::ScriptFreeCache(&sc);
2257 for (int i = 0; i < glyphCount; ++i) {
2258 if (0 == glyphs[i]) {
2265 int LogFontTypeface::onCountGlyphs() const {
2266 HDC hdc = ::CreateCompatibleDC(NULL);
2267 HFONT font = CreateFontIndirect(&fLogFont);
2268 HFONT savefont = (HFONT)SelectObject(hdc, font);
2270 unsigned int glyphCount = calculateGlyphCount(hdc, fLogFont);
2272 SelectObject(hdc, savefont);
2279 int LogFontTypeface::onGetUPEM() const {
2280 HDC hdc = ::CreateCompatibleDC(NULL);
2281 HFONT font = CreateFontIndirect(&fLogFont);
2282 HFONT savefont = (HFONT)SelectObject(hdc, font);
2284 unsigned int upem = calculateUPEM(hdc, fLogFont);
2286 SelectObject(hdc, savefont);
2293 SkTypeface::LocalizedStrings* LogFontTypeface::onCreateFamilyNameIterator() const {
2294 SkTypeface::LocalizedStrings* nameIter =
2295 SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(*this);
2296 if (NULL == nameIter) {
2297 SkString familyName;
2298 this->getFamilyName(&familyName);
2299 SkString language("und"); //undetermined
2300 nameIter = new SkOTUtils::LocalizedStrings_SingleName(familyName, language);
2305 int LogFontTypeface::onGetTableTags(SkFontTableTag tags[]) const {
2306 SkSFNTHeader header;
2307 if (sizeof(header) != this->onGetTableData(0, 0, sizeof(header), &header)) {
2311 int numTables = SkEndian_SwapBE16(header.numTables);
2314 size_t size = numTables * sizeof(SkSFNTHeader::TableDirectoryEntry);
2315 SkAutoSTMalloc<0x20, SkSFNTHeader::TableDirectoryEntry> dir(numTables);
2316 if (size != this->onGetTableData(0, sizeof(header), size, dir.get())) {
2320 for (int i = 0; i < numTables; ++i) {
2321 tags[i] = SkEndian_SwapBE32(dir[i].tag);
2327 size_t LogFontTypeface::onGetTableData(SkFontTableTag tag, size_t offset,
2328 size_t length, void* data) const
2330 LOGFONT lf = fLogFont;
2332 HDC hdc = ::CreateCompatibleDC(NULL);
2333 HFONT font = CreateFontIndirect(&lf);
2334 HFONT savefont = (HFONT)SelectObject(hdc, font);
2336 tag = SkEndian_SwapBE32(tag);
2340 DWORD bufferSize = GetFontData(hdc, tag, (DWORD) offset, data, (DWORD) length);
2341 if (bufferSize == GDI_ERROR) {
2342 call_ensure_accessible(lf);
2343 bufferSize = GetFontData(hdc, tag, (DWORD) offset, data, (DWORD) length);
2346 SelectObject(hdc, savefont);
2350 return bufferSize == GDI_ERROR ? 0 : bufferSize;
2353 SkScalerContext* LogFontTypeface::onCreateScalerContext(const SkDescriptor* desc) const {
2354 SkScalerContext_GDI* ctx = SkNEW_ARGS(SkScalerContext_GDI,
2355 (const_cast<LogFontTypeface*>(this), desc));
2356 if (!ctx->isValid()) {
2363 void LogFontTypeface::onFilterRec(SkScalerContextRec* rec) const {
2364 if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag ||
2365 rec->fFlags & SkScalerContext::kLCD_Vertical_Flag)
2367 rec->fMaskFormat = SkMask::kA8_Format;
2368 rec->fFlags |= SkScalerContext::kGenA8FromLCD_Flag;
2371 unsigned flagsWeDontSupport = SkScalerContext::kVertical_Flag |
2372 SkScalerContext::kDevKernText_Flag |
2373 SkScalerContext::kForceAutohinting_Flag |
2374 SkScalerContext::kEmbeddedBitmapText_Flag |
2375 SkScalerContext::kEmbolden_Flag |
2376 SkScalerContext::kLCD_BGROrder_Flag |
2377 SkScalerContext::kLCD_Vertical_Flag;
2378 rec->fFlags &= ~flagsWeDontSupport;
2380 SkPaint::Hinting h = rec->getHinting();
2382 case SkPaint::kNo_Hinting:
2384 case SkPaint::kSlight_Hinting:
2385 // Only do slight hinting when axis aligned.
2386 // TODO: re-enable slight hinting when FontHostTest can pass.
2387 //if (!isAxisAligned(*rec)) {
2388 h = SkPaint::kNo_Hinting;
2391 case SkPaint::kNormal_Hinting:
2392 case SkPaint::kFull_Hinting:
2393 // TODO: need to be able to distinguish subpixel positioned glyphs
2394 // and linear metrics.
2395 //rec->fFlags &= ~SkScalerContext::kSubpixelPositioning_Flag;
2396 h = SkPaint::kNormal_Hinting;
2399 SkDEBUGFAIL("unknown hinting");
2401 //TODO: if this is a bitmap font, squash hinting and subpixel.
2404 // turn this off since GDI might turn A8 into BW! Need a bigger fix.
2406 // Disable LCD when rotated, since GDI's output is ugly
2407 if (isLCD(*rec) && !isAxisAligned(*rec)) {
2408 rec->fMaskFormat = SkMask::kA8_Format;
2412 if (!fCanBeLCD && isLCD(*rec)) {
2413 rec->fMaskFormat = SkMask::kA8_Format;
2414 rec->fFlags &= ~SkScalerContext::kGenA8FromLCD_Flag;
2418 ///////////////////////////////////////////////////////////////////////////////
2420 #include "SkFontMgr.h"
2421 #include "SkDataTable.h"
2423 static bool valid_logfont_for_enum(const LOGFONT& lf) {
2424 // TODO: Vector FON is unsupported and should not be listed.
2426 // Ignore implicit vertical variants.
2427 lf.lfFaceName[0] && lf.lfFaceName[0] != '@'
2429 // DEFAULT_CHARSET is used to get all fonts, but also implies all
2430 // character sets. Filter assuming all fonts support ANSI_CHARSET.
2431 && ANSI_CHARSET == lf.lfCharSet
2435 /** An EnumFontFamExProc implementation which interprets builderParam as
2436 * an SkTDArray<ENUMLOGFONTEX>* and appends logfonts which
2437 * pass the valid_logfont_for_enum predicate.
2439 static int CALLBACK enum_family_proc(const LOGFONT* lf, const TEXTMETRIC*,
2440 DWORD fontType, LPARAM builderParam) {
2441 if (valid_logfont_for_enum(*lf)) {
2442 SkTDArray<ENUMLOGFONTEX>* array = (SkTDArray<ENUMLOGFONTEX>*)builderParam;
2443 *array->append() = *(ENUMLOGFONTEX*)lf;
2445 return 1; // non-zero means continue
2448 class SkFontStyleSetGDI : public SkFontStyleSet {
2450 SkFontStyleSetGDI(const TCHAR familyName[]) {
2452 sk_bzero(&lf, sizeof(lf));
2453 lf.lfCharSet = DEFAULT_CHARSET;
2454 _tcscpy_s(lf.lfFaceName, familyName);
2456 HDC hdc = ::CreateCompatibleDC(NULL);
2457 ::EnumFontFamiliesEx(hdc, &lf, enum_family_proc, (LPARAM)&fArray, 0);
2461 virtual int count() SK_OVERRIDE {
2462 return fArray.count();
2465 virtual void getStyle(int index, SkFontStyle* fs, SkString* styleName) SK_OVERRIDE {
2467 *fs = get_style(fArray[index].elfLogFont);
2470 const ENUMLOGFONTEX& ref = fArray[index];
2471 // For some reason, ENUMLOGFONTEX and LOGFONT disagree on their type in the
2472 // non-unicode version.
2473 // ENUMLOGFONTEX uses BYTE
2474 // LOGFONT uses CHAR
2475 // Here we assert they that the style name is logically the same (size) as
2476 // a TCHAR, so we can use the same converter function.
2477 SkASSERT(sizeof(TCHAR) == sizeof(ref.elfStyle[0]));
2478 tchar_to_skstring((const TCHAR*)ref.elfStyle, styleName);
2482 virtual SkTypeface* createTypeface(int index) SK_OVERRIDE {
2483 return SkCreateTypefaceFromLOGFONT(fArray[index].elfLogFont);
2486 virtual SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE {
2488 return SkCreateTypefaceFromLOGFONT(fArray[0].elfLogFont);
2492 SkTDArray<ENUMLOGFONTEX> fArray;
2495 class SkFontMgrGDI : public SkFontMgr {
2499 sk_bzero(&lf, sizeof(lf));
2500 lf.lfCharSet = DEFAULT_CHARSET;
2502 HDC hdc = ::CreateCompatibleDC(NULL);
2503 ::EnumFontFamiliesEx(hdc, &lf, enum_family_proc, (LPARAM)&fLogFontArray, 0);
2508 virtual int onCountFamilies() const SK_OVERRIDE {
2509 return fLogFontArray.count();
2512 virtual void onGetFamilyName(int index, SkString* familyName) const SK_OVERRIDE {
2513 SkASSERT((unsigned)index < (unsigned)fLogFontArray.count());
2514 tchar_to_skstring(fLogFontArray[index].elfLogFont.lfFaceName, familyName);
2517 virtual SkFontStyleSet* onCreateStyleSet(int index) const SK_OVERRIDE {
2518 SkASSERT((unsigned)index < (unsigned)fLogFontArray.count());
2519 return SkNEW_ARGS(SkFontStyleSetGDI, (fLogFontArray[index].elfLogFont.lfFaceName));
2522 virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const SK_OVERRIDE {
2523 if (NULL == familyName) {
2524 familyName = ""; // do we need this check???
2527 logfont_for_name(familyName, &lf);
2528 return SkNEW_ARGS(SkFontStyleSetGDI, (lf.lfFaceName));
2531 virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
2532 const SkFontStyle& fontstyle) const SK_OVERRIDE {
2533 // could be in base impl
2534 SkAutoTUnref<SkFontStyleSet> sset(this->matchFamily(familyName));
2535 return sset->matchStyle(fontstyle);
2538 virtual SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember,
2539 const SkFontStyle& fontstyle) const SK_OVERRIDE {
2540 // could be in base impl
2541 SkString familyName;
2542 ((LogFontTypeface*)familyMember)->getFamilyName(&familyName);
2543 return this->matchFamilyStyle(familyName.c_str(), fontstyle);
2546 virtual SkTypeface* onCreateFromStream(SkStream* stream, int ttcIndex) const SK_OVERRIDE {
2547 return create_from_stream(stream);
2550 virtual SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const SK_OVERRIDE {
2551 // could be in base impl
2552 SkAutoTUnref<SkStream> stream(SkNEW_ARGS(SkMemoryStream, (data)));
2553 return this->createFromStream(stream);
2556 virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const SK_OVERRIDE {
2557 // could be in base impl
2558 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path));
2559 return this->createFromStream(stream);
2562 virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
2563 unsigned styleBits) const SK_OVERRIDE {
2565 if (NULL == familyName) {
2566 lf = get_default_font();
2568 logfont_for_name(familyName, &lf);
2571 SkTypeface::Style style = (SkTypeface::Style)styleBits;
2572 lf.lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL;
2573 lf.lfItalic = ((style & SkTypeface::kItalic) != 0);
2574 return SkCreateTypefaceFromLOGFONT(lf);
2578 SkTDArray<ENUMLOGFONTEX> fLogFontArray;
2581 ///////////////////////////////////////////////////////////////////////////////
2583 SkFontMgr* SkFontMgr_New_GDI() {
2584 return SkNEW(SkFontMgrGDI);