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 SkTypeface::Style get_style(const LOGFONT& lf) {
131 if (lf.lfWeight >= FW_BOLD) {
132 style |= SkTypeface::kBold;
135 style |= SkTypeface::kItalic;
137 return static_cast<SkTypeface::Style>(style);
140 static void setStyle(LOGFONT* lf, SkTypeface::Style style) {
141 lf->lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL ;
142 lf->lfItalic = ((style & SkTypeface::kItalic) != 0);
145 static inline FIXED SkFixedToFIXED(SkFixed x) {
146 return *(FIXED*)(&x);
148 static inline SkFixed SkFIXEDToFixed(FIXED x) {
149 return *(SkFixed*)(&x);
152 static inline FIXED SkScalarToFIXED(SkScalar x) {
153 return SkFixedToFIXED(SkScalarToFixed(x));
156 static inline SkScalar SkFIXEDToScalar(FIXED x) {
157 return SkFixedToScalar(SkFIXEDToFixed(x));
160 static unsigned calculateGlyphCount(HDC hdc, const LOGFONT& lf) {
161 TEXTMETRIC textMetric;
162 if (0 == GetTextMetrics(hdc, &textMetric)) {
163 textMetric.tmPitchAndFamily = TMPF_VECTOR;
164 call_ensure_accessible(lf);
165 GetTextMetrics(hdc, &textMetric);
168 if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) {
169 return textMetric.tmLastChar;
172 // The 'maxp' table stores the number of glyphs at offset 4, in 2 bytes.
174 if (GDI_ERROR != GetFontData(hdc, SkOTTableMaximumProfile::TAG, 4, &glyphs, sizeof(glyphs))) {
175 return SkEndian_SwapBE16(glyphs);
178 // Binary search for glyph count.
179 static const MAT2 mat2 = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
180 int32_t max = SK_MaxU16 + 1;
184 int32_t mid = min + ((max - min) / 2);
185 if (GetGlyphOutlineW(hdc, mid, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0,
186 NULL, &mat2) == GDI_ERROR) {
192 SkASSERT(min == max);
196 static unsigned calculateUPEM(HDC hdc, const LOGFONT& lf) {
197 TEXTMETRIC textMetric;
198 if (0 == GetTextMetrics(hdc, &textMetric)) {
199 textMetric.tmPitchAndFamily = TMPF_VECTOR;
200 call_ensure_accessible(lf);
201 GetTextMetrics(hdc, &textMetric);
204 if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) {
205 return textMetric.tmMaxCharWidth;
208 OUTLINETEXTMETRIC otm;
209 unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
211 call_ensure_accessible(lf);
212 otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
215 return (0 == otmRet) ? 0 : otm.otmEMSquare;
218 class LogFontTypeface : public SkTypeface {
220 LogFontTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf, bool serializeAsStream = false) :
221 SkTypeface(style, fontID, false), fLogFont(lf), fSerializeAsStream(serializeAsStream) {
223 // If the font has cubic outlines, it will not be rendered with ClearType.
224 HFONT font = CreateFontIndirect(&lf);
226 HDC deviceContext = ::CreateCompatibleDC(NULL);
227 HFONT savefont = (HFONT)SelectObject(deviceContext, font);
229 TEXTMETRIC textMetric;
230 if (0 == GetTextMetrics(deviceContext, &textMetric)) {
231 call_ensure_accessible(lf);
232 if (0 == GetTextMetrics(deviceContext, &textMetric)) {
233 textMetric.tmPitchAndFamily = TMPF_TRUETYPE;
237 ::SelectObject(deviceContext, savefont);
238 ::DeleteDC(deviceContext);
241 ::DeleteObject(font);
244 // The fixed pitch bit is set if the font is *not* fixed pitch.
245 this->setIsFixedPitch((textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0);
247 // Used a logfont on a memory context, should never get a device font.
248 // Therefore all TMPF_DEVICE will be PostScript (cubic) fonts.
249 fCanBeLCD = !((textMetric.tmPitchAndFamily & TMPF_VECTOR) &&
250 (textMetric.tmPitchAndFamily & TMPF_DEVICE));
254 bool fSerializeAsStream;
257 static LogFontTypeface* Create(const LOGFONT& lf) {
258 SkTypeface::Style style = get_style(lf);
259 SkFontID fontID = SkTypefaceCache::NewFontID();
260 return new LogFontTypeface(style, fontID, lf);
263 static void EnsureAccessible(const SkTypeface* face) {
264 call_ensure_accessible(static_cast<const LogFontTypeface*>(face)->fLogFont);
268 virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE;
269 virtual SkScalerContext* onCreateScalerContext(const SkDescriptor*) const SK_OVERRIDE;
270 virtual void onFilterRec(SkScalerContextRec*) const SK_OVERRIDE;
271 virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics(
272 SkAdvancedTypefaceMetrics::PerGlyphInfo,
273 const uint32_t*, uint32_t) const SK_OVERRIDE;
274 virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE;
275 virtual int onCharsToGlyphs(const void* chars, Encoding encoding,
276 uint16_t glyphs[], int glyphCount) const SK_OVERRIDE;
277 virtual int onCountGlyphs() const SK_OVERRIDE;
278 virtual int onGetUPEM() const SK_OVERRIDE;
279 virtual SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const SK_OVERRIDE;
280 virtual int onGetTableTags(SkFontTableTag tags[]) const SK_OVERRIDE;
281 virtual size_t onGetTableData(SkFontTableTag, size_t offset,
282 size_t length, void* data) const SK_OVERRIDE;
285 class FontMemResourceTypeface : public LogFontTypeface {
288 * The created FontMemResourceTypeface takes ownership of fontMemResource.
290 static FontMemResourceTypeface* Create(const LOGFONT& lf, HANDLE fontMemResource) {
291 SkTypeface::Style style = get_style(lf);
292 SkFontID fontID = SkTypefaceCache::NewFontID();
293 return new FontMemResourceTypeface(style, fontID, lf, fontMemResource);
297 virtual void weak_dispose() const SK_OVERRIDE {
298 RemoveFontMemResourceEx(fFontMemResource);
299 //SkTypefaceCache::Remove(this);
300 INHERITED::weak_dispose();
305 * Takes ownership of fontMemResource.
307 FontMemResourceTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf, HANDLE fontMemResource) :
308 LogFontTypeface(style, fontID, lf, true), fFontMemResource(fontMemResource) {
311 HANDLE fFontMemResource;
313 typedef LogFontTypeface INHERITED;
316 static const LOGFONT& get_default_font() {
317 static LOGFONT gDefaultFont;
321 static bool FindByLogFont(SkTypeface* face, SkTypeface::Style requestedStyle, void* ctx) {
322 LogFontTypeface* lface = static_cast<LogFontTypeface*>(face);
323 const LOGFONT* lf = reinterpret_cast<const LOGFONT*>(ctx);
326 get_style(lface->fLogFont) == requestedStyle &&
327 !memcmp(&lface->fLogFont, lf, sizeof(LOGFONT));
331 * This guy is public. It first searches the cache, and if a match is not found,
332 * it creates a new face.
334 SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT& origLF) {
337 SkTypeface* face = SkTypefaceCache::FindByProcAndRef(FindByLogFont, &lf);
339 face = LogFontTypeface::Create(lf);
340 SkTypefaceCache::Add(face, get_style(lf));
346 * The created SkTypeface takes ownership of fontMemResource.
348 SkTypeface* SkCreateFontMemResourceTypefaceFromLOGFONT(const LOGFONT& origLF, HANDLE fontMemResource) {
351 FontMemResourceTypeface* face = FontMemResourceTypeface::Create(lf, fontMemResource);
352 SkTypefaceCache::Add(face, get_style(lf), false);
359 void SkLOGFONTFromTypeface(const SkTypeface* face, LOGFONT* lf) {
361 *lf = get_default_font();
363 *lf = static_cast<const LogFontTypeface*>(face)->fLogFont;
367 // Construct Glyph to Unicode table.
368 // Unicode code points that require conjugate pairs in utf16 are not
370 // TODO(arthurhsu): Add support for conjugate pairs. It looks like that may
371 // require parsing the TTF cmap table (platform 4, encoding 12) directly instead
372 // of calling GetFontUnicodeRange().
373 static void populate_glyph_to_unicode(HDC fontHdc, const unsigned glyphCount,
374 SkTDArray<SkUnichar>* glyphToUnicode) {
375 DWORD glyphSetBufferSize = GetFontUnicodeRanges(fontHdc, NULL);
376 if (!glyphSetBufferSize) {
380 SkAutoTDeleteArray<BYTE> glyphSetBuffer(new BYTE[glyphSetBufferSize]);
382 reinterpret_cast<LPGLYPHSET>(glyphSetBuffer.get());
383 if (GetFontUnicodeRanges(fontHdc, glyphSet) != glyphSetBufferSize) {
387 glyphToUnicode->setCount(glyphCount);
388 memset(glyphToUnicode->begin(), 0, glyphCount * sizeof(SkUnichar));
389 for (DWORD i = 0; i < glyphSet->cRanges; ++i) {
390 // There is no guarantee that within a Unicode range, the corresponding
391 // glyph id in a font file are continuous. So, even if we have ranges,
392 // we can't just use the first and last entry of the range to compute
393 // result. We need to enumerate them one by one.
394 int count = glyphSet->ranges[i].cGlyphs;
395 SkAutoTArray<WCHAR> chars(count + 1);
396 chars[count] = 0; // termintate string
397 SkAutoTArray<WORD> glyph(count);
398 for (USHORT j = 0; j < count; ++j) {
399 chars[j] = glyphSet->ranges[i].wcLow + j;
401 GetGlyphIndicesW(fontHdc, chars.get(), count, glyph.get(),
402 GGI_MARK_NONEXISTING_GLYPHS);
403 // If the glyph ID is valid, and the glyph is not mapped, then we will
404 // fill in the char id into the vector. If the glyph is mapped already,
406 // TODO(arthurhsu): better improve this. e.g. Get all used char ids from
407 // font cache, then generate this mapping table from there. It's
408 // unlikely to have collisions since glyph reuse happens mostly for
409 // different Unicode pages.
410 for (USHORT j = 0; j < count; ++j) {
411 if (glyph[j] != 0xffff && glyph[j] < glyphCount &&
412 (*glyphToUnicode)[glyph[j]] == 0) {
413 (*glyphToUnicode)[glyph[j]] = chars[j];
419 //////////////////////////////////////////////////////////////////////////////////////
421 static int alignTo32(int n) {
422 return (n + 31) & ~31;
425 struct MyBitmapInfo : public BITMAPINFO {
426 RGBQUAD fMoreSpaceForColors[1];
436 fWidth = fHeight = 0;
449 void init(HFONT font, const XFORM& xform) {
454 const void* draw(const SkGlyph&, bool isBW, size_t* srcRBPtr);
461 void* fBits; // points into fBM
467 const void* HDCOffscreen::draw(const SkGlyph& glyph, bool isBW,
469 // Can we share the scalercontext's fDDC, so we don't need to create
470 // a separate fDC here?
472 fDC = CreateCompatibleDC(0);
476 SetGraphicsMode(fDC, GM_ADVANCED);
477 SetBkMode(fDC, TRANSPARENT);
478 SetTextAlign(fDC, TA_LEFT | TA_BASELINE);
479 SelectObject(fDC, fFont);
481 COLORREF color = 0x00FFFFFF;
482 SkDEBUGCODE(COLORREF prev =) SetTextColor(fDC, color);
483 SkASSERT(prev != CLR_INVALID);
486 if (fBM && (fIsBW != isBW || fWidth < glyph.fWidth || fHeight < glyph.fHeight)) {
492 fWidth = SkMax32(fWidth, glyph.fWidth);
493 fHeight = SkMax32(fHeight, glyph.fHeight);
495 int biWidth = isBW ? alignTo32(fWidth) : fWidth;
499 sk_bzero(&info, sizeof(info));
501 RGBQUAD blackQuad = { 0, 0, 0, 0 };
502 RGBQUAD whiteQuad = { 0xFF, 0xFF, 0xFF, 0 };
503 info.bmiColors[0] = blackQuad;
504 info.bmiColors[1] = whiteQuad;
506 info.bmiHeader.biSize = sizeof(info.bmiHeader);
507 info.bmiHeader.biWidth = biWidth;
508 info.bmiHeader.biHeight = fHeight;
509 info.bmiHeader.biPlanes = 1;
510 info.bmiHeader.biBitCount = isBW ? 1 : 32;
511 info.bmiHeader.biCompression = BI_RGB;
513 info.bmiHeader.biClrUsed = 2;
515 fBM = CreateDIBSection(fDC, &info, DIB_RGB_COLORS, &fBits, 0, 0);
519 SelectObject(fDC, fBM);
523 size_t srcRB = isBW ? (biWidth >> 3) : (fWidth << 2);
524 size_t size = fHeight * srcRB;
525 memset(fBits, 0, size);
527 XFORM xform = fXform;
528 xform.eDx = (float)-glyph.fLeft;
529 xform.eDy = (float)-glyph.fTop;
530 SetWorldTransform(fDC, &xform);
532 uint16_t glyphID = glyph.getGlyphID();
533 BOOL ret = ExtTextOutW(fDC, 0, 0, ETO_GLYPH_INDEX, NULL, reinterpret_cast<LPCWSTR>(&glyphID), 1, NULL);
539 // offset to the start of the image
540 return (const char*)fBits + (fHeight - glyph.fHeight) * srcRB;
543 //////////////////////////////////////////////////////////////////////////////
544 #define BUFFERSIZE (1 << 13)
546 class SkScalerContext_GDI : public SkScalerContext {
548 SkScalerContext_GDI(SkTypeface*, const SkDescriptor* desc);
549 virtual ~SkScalerContext_GDI();
551 // Returns true if the constructor was able to complete all of its
552 // initializations (which may include calling GDI).
553 bool isValid() const;
556 virtual unsigned generateGlyphCount() SK_OVERRIDE;
557 virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE;
558 virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE;
559 virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE;
560 virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE;
561 virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE;
562 virtual void generateFontMetrics(SkPaint::FontMetrics* mX,
563 SkPaint::FontMetrics* mY) SK_OVERRIDE;
566 DWORD getGDIGlyphPath(const SkGlyph& glyph, UINT flags,
567 SkAutoSTMalloc<BUFFERSIZE, uint8_t>* glyphbuf);
569 HDCOffscreen fOffscreen;
570 /** fGsA is the non-rotational part of total matrix without the text height scale.
571 * Used to find the magnitude of advances.
574 /** The total matrix without the textSize. */
576 /** Scales font to EM size. */
584 /** The total matrix which also removes EM scale. */
585 SkMatrix fHiResMatrix;
586 /** fG_inv is the inverse of the rotational part of the total matrix.
587 * Used to set the direction of advances.
591 kTrueType_Type, kBitmap_Type, kLine_Type
596 static FIXED float2FIXED(float x) {
597 return SkFixedToFIXED(SkFloatToFixed(x));
600 static BYTE compute_quality(const SkScalerContext::Rec& rec) {
601 switch (rec.fMaskFormat) {
602 case SkMask::kBW_Format:
603 return NONANTIALIASED_QUALITY;
604 case SkMask::kLCD16_Format:
605 case SkMask::kLCD32_Format:
606 return CLEARTYPE_QUALITY;
608 if (rec.fFlags & SkScalerContext::kGenA8FromLCD_Flag) {
609 return CLEARTYPE_QUALITY;
611 return ANTIALIASED_QUALITY;
616 SkScalerContext_GDI::SkScalerContext_GDI(SkTypeface* rawTypeface,
617 const SkDescriptor* desc)
618 : SkScalerContext(rawTypeface, desc)
625 LogFontTypeface* typeface = reinterpret_cast<LogFontTypeface*>(rawTypeface);
627 fDDC = ::CreateCompatibleDC(NULL);
631 SetGraphicsMode(fDDC, GM_ADVANCED);
632 SetBkMode(fDDC, TRANSPARENT);
634 SkPoint h = SkPoint::Make(SK_Scalar1, 0);
635 // A is the total matrix.
637 fRec.getSingleMatrix(&A);
640 // G is the Givens Matrix for A (rotational matrix where GA[0][1] == 0).
642 SkComputeGivensRotation(h, &G);
644 // GA is the matrix A with rotation removed.
648 // realTextSize is the actual device size we want (as opposed to the size the user requested).
649 // gdiTextSide is the size we request from GDI.
650 // If the scale is negative, this means the matrix will do the flip anyway.
651 SkScalar realTextSize = SkScalarAbs(GA.get(SkMatrix::kMScaleY));
652 SkScalar gdiTextSize = SkScalarRoundToScalar(realTextSize);
653 if (gdiTextSize == 0) {
654 gdiTextSize = SK_Scalar1;
657 // When not hinting, remove only the gdiTextSize scale which will be applied by GDI.
658 // When GDI hinting, remove the entire Y scale to prevent 'subpixel' metrics.
659 SkScalar scale = (fRec.getHinting() == SkPaint::kNo_Hinting ||
660 fRec.getHinting() == SkPaint::kSlight_Hinting)
661 ? SkScalarInvert(gdiTextSize)
662 : SkScalarInvert(realTextSize);
664 // sA is the total matrix A without the textSize (so GDI knows the text size separately).
665 // When this matrix is used with GetGlyphOutline, no further processing is needed.
667 sA.preScale(scale, scale); //remove text size
669 // GsA is the non-rotational part of A without the text height scale.
670 // This is what is used to find the magnitude of advances.
672 GsA.preScale(scale, scale); //remove text size, G is rotational so reorders with the scale.
674 fGsA.eM11 = SkScalarToFIXED(GsA.get(SkMatrix::kMScaleX));
675 fGsA.eM12 = SkScalarToFIXED(-GsA.get(SkMatrix::kMSkewY)); // This should be ~0.
676 fGsA.eM21 = SkScalarToFIXED(-GsA.get(SkMatrix::kMSkewX));
677 fGsA.eM22 = SkScalarToFIXED(GsA.get(SkMatrix::kMScaleY));
679 // fG_inv is G inverse, which is fairly simple since G is 2x2 rotational.
680 fG_inv.setAll(G.get(SkMatrix::kMScaleX), -G.get(SkMatrix::kMSkewX), G.get(SkMatrix::kMTransX),
681 -G.get(SkMatrix::kMSkewY), G.get(SkMatrix::kMScaleY), G.get(SkMatrix::kMTransY),
682 G.get(SkMatrix::kMPersp0), G.get(SkMatrix::kMPersp1), G.get(SkMatrix::kMPersp2));
684 LOGFONT lf = typeface->fLogFont;
685 lf.lfHeight = -SkScalarTruncToInt(gdiTextSize);
686 lf.lfQuality = compute_quality(fRec);
687 fFont = CreateFontIndirect(&lf);
692 fSavefont = (HFONT)SelectObject(fDDC, fFont);
694 if (0 == GetTextMetrics(fDDC, &fTM)) {
695 call_ensure_accessible(lf);
696 if (0 == GetTextMetrics(fDDC, &fTM)) {
697 fTM.tmPitchAndFamily = TMPF_TRUETYPE;
702 if (fTM.tmPitchAndFamily & TMPF_VECTOR) {
703 // Used a logfont on a memory context, should never get a device font.
704 // Therefore all TMPF_DEVICE will be PostScript fonts.
706 // If TMPF_VECTOR is set, one of TMPF_TRUETYPE or TMPF_DEVICE means that
707 // we have an outline font. Otherwise we have a vector FON, which is
708 // scalable, but not an outline font.
709 // This was determined by testing with Type1 PFM/PFB and
710 // OpenTypeCFF OTF, as well as looking at Wine bugs and sources.
711 if (fTM.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_DEVICE)) {
712 // Truetype or PostScript.
713 fType = SkScalerContext_GDI::kTrueType_Type;
716 fType = SkScalerContext_GDI::kLine_Type;
719 // fPost2x2 is column-major, left handed (y down).
720 // XFORM 2x2 is row-major, left handed (y down).
721 xform.eM11 = SkScalarToFloat(sA.get(SkMatrix::kMScaleX));
722 xform.eM12 = SkScalarToFloat(sA.get(SkMatrix::kMSkewY));
723 xform.eM21 = SkScalarToFloat(sA.get(SkMatrix::kMSkewX));
724 xform.eM22 = SkScalarToFloat(sA.get(SkMatrix::kMScaleY));
728 // MAT2 is row major, right handed (y up).
729 fMat22.eM11 = float2FIXED(xform.eM11);
730 fMat22.eM12 = float2FIXED(-xform.eM12);
731 fMat22.eM21 = float2FIXED(-xform.eM21);
732 fMat22.eM22 = float2FIXED(xform.eM22);
734 if (needToRenderWithSkia(fRec)) {
735 this->forceGenerateImageFromPath();
738 // Create a hires matrix if we need linear metrics.
739 if (this->isSubpixel()) {
740 OUTLINETEXTMETRIC otm;
741 UINT success = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
743 call_ensure_accessible(lf);
744 success = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
747 SkScalar upem = SkIntToScalar(otm.otmEMSquare);
749 SkScalar gdiTextSizeToEMScale = upem / gdiTextSize;
750 fHighResMat22.eM11 = float2FIXED(gdiTextSizeToEMScale);
751 fHighResMat22.eM12 = float2FIXED(0);
752 fHighResMat22.eM21 = float2FIXED(0);
753 fHighResMat22.eM22 = float2FIXED(gdiTextSizeToEMScale);
755 SkScalar removeEMScale = SkScalarInvert(upem);
757 fHiResMatrix.preScale(removeEMScale, removeEMScale);
763 fType = SkScalerContext_GDI::kBitmap_Type;
772 // fPost2x2 is column-major, left handed (y down).
773 // MAT2 is row major, right handed (y up).
774 fMat22.eM11 = SkScalarToFIXED(fRec.fPost2x2[0][0]);
775 fMat22.eM12 = SkScalarToFIXED(-fRec.fPost2x2[1][0]);
776 fMat22.eM21 = SkScalarToFIXED(-fRec.fPost2x2[0][1]);
777 fMat22.eM22 = SkScalarToFIXED(fRec.fPost2x2[1][1]);
780 fOffscreen.init(fFont, xform);
783 SkScalerContext_GDI::~SkScalerContext_GDI() {
785 ::SelectObject(fDDC, fSavefont);
789 ::DeleteObject(fFont);
792 ::ScriptFreeCache(&fSC);
796 bool SkScalerContext_GDI::isValid() const {
797 return fDDC && fFont;
800 unsigned SkScalerContext_GDI::generateGlyphCount() {
801 if (fGlyphCount < 0) {
802 fGlyphCount = calculateGlyphCount(
803 fDDC, static_cast<const LogFontTypeface*>(this->getTypeface())->fLogFont);
808 uint16_t SkScalerContext_GDI::generateCharToGlyph(SkUnichar utf32) {
811 // TODO(ctguil): Support characters that generate more than one glyph.
812 if (SkUTF16_FromUnichar(utf32, (uint16_t*)utf16) == 1) {
813 // Type1 fonts fail with uniscribe API. Use GetGlyphIndices for plane 0.
815 /** Real documentation for GetGlyphIndiciesW:
817 * When GGI_MARK_NONEXISTING_GLYPHS is not specified and a character does not map to a
818 * glyph, then the 'default character's glyph is returned instead. The 'default character'
819 * is available in fTM.tmDefaultChar. FON fonts have a default character, and there exists
820 * a usDefaultChar in the 'OS/2' table, version 2 and later. If there is no
821 * 'default character' specified by the font, then often the first character found is used.
823 * When GGI_MARK_NONEXISTING_GLYPHS is specified and a character does not map to a glyph,
824 * then the glyph 0xFFFF is used. In Windows XP and earlier, Bitmap/Vector FON usually use
825 * glyph 0x1F instead ('Terminal' appears to be special, returning 0xFFFF).
826 * Type1 PFM/PFB, TT, OT TT, OT CFF all appear to use 0xFFFF, even on XP.
828 DWORD result = GetGlyphIndicesW(fDDC, utf16, 1, &index, GGI_MARK_NONEXISTING_GLYPHS);
829 if (result == GDI_ERROR
832 (fType == SkScalerContext_GDI::kBitmap_Type ||
833 fType == SkScalerContext_GDI::kLine_Type)
834 /*&& winVer < Vista */)
840 // Use uniscribe to detemine glyph index for non-BMP characters.
841 static const int numWCHAR = 2;
842 static const int maxItems = 2;
843 // MSDN states that this can be NULL, but some things don't work then.
844 SCRIPT_CONTROL sc = { 0 };
845 // Add extra item to SCRIPT_ITEM to work around a bug (now documented).
846 // https://bugzilla.mozilla.org/show_bug.cgi?id=366643
847 SCRIPT_ITEM si[maxItems + 1];
849 HRZM(ScriptItemize(utf16, numWCHAR, maxItems, &sc, NULL, si, &numItems),
850 "Could not itemize character.");
852 // Sometimes ScriptShape cannot find a glyph for a non-BMP and returns 2 space glyphs.
853 static const int maxGlyphs = 2;
854 SCRIPT_VISATTR vsa[maxGlyphs];
855 WORD outGlyphs[maxGlyphs];
856 WORD logClust[numWCHAR];
858 HRZM(ScriptShape(fDDC, &fSC, utf16, numWCHAR, maxGlyphs, &si[0].a,
859 outGlyphs, logClust, vsa, &numGlyphs),
860 "Could not shape character.");
861 if (1 == numGlyphs) {
862 index = outGlyphs[0];
868 void SkScalerContext_GDI::generateAdvance(SkGlyph* glyph) {
869 this->generateMetrics(glyph);
872 void SkScalerContext_GDI::generateMetrics(SkGlyph* glyph) {
875 if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) {
877 WORD glyphs = glyph->getGlyphID(0);
878 if (0 == GetTextExtentPointI(fDDC, &glyphs, 1, &size)) {
879 glyph->fWidth = SkToS16(fTM.tmMaxCharWidth);
881 glyph->fWidth = SkToS16(size.cx);
883 glyph->fHeight = SkToS16(size.cy);
885 glyph->fTop = SkToS16(-fTM.tmAscent);
886 // Bitmap FON cannot underhang, but vector FON may.
887 // There appears no means of determining underhang of vector FON.
888 glyph->fLeft = SkToS16(0);
889 glyph->fAdvanceX = SkIntToFixed(glyph->fWidth);
890 glyph->fAdvanceY = 0;
892 // Vector FON will transform nicely, but bitmap FON do not.
893 if (fType == SkScalerContext_GDI::kLine_Type) {
894 SkRect bounds = SkRect::MakeXYWH(glyph->fLeft, glyph->fTop,
895 glyph->fWidth, glyph->fHeight);
897 m.setAll(SkFIXEDToScalar(fMat22.eM11), -SkFIXEDToScalar(fMat22.eM21), 0,
898 -SkFIXEDToScalar(fMat22.eM12), SkFIXEDToScalar(fMat22.eM22), 0,
899 0, 0, SkScalarToPersp(SK_Scalar1));
902 glyph->fLeft = SkScalarTruncToInt(bounds.fLeft);
903 glyph->fTop = SkScalarTruncToInt(bounds.fTop);
904 glyph->fWidth = SkScalarTruncToInt(bounds.width());
905 glyph->fHeight = SkScalarTruncToInt(bounds.height());
908 // Apply matrix to advance.
909 glyph->fAdvanceY = SkFixedMul(-SkFIXEDToFixed(fMat22.eM12), glyph->fAdvanceX);
910 glyph->fAdvanceX = SkFixedMul(SkFIXEDToFixed(fMat22.eM11), glyph->fAdvanceX);
915 UINT glyphId = glyph->getGlyphID(0);
918 sk_bzero(&gm, sizeof(gm));
920 DWORD status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
921 if (GDI_ERROR == status) {
922 LogFontTypeface::EnsureAccessible(this->getTypeface());
923 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
924 if (GDI_ERROR == status) {
925 glyph->zeroMetrics();
931 // The black box is either the embedded bitmap size or the outline extent.
932 // It is 1x1 if nothing is to be drawn, but will also be 1x1 if something very small
933 // is to be drawn, like a '.'. We need to outset '.' but do not wish to outset ' '.
934 if (1 == gm.gmBlackBoxX && 1 == gm.gmBlackBoxY) {
935 // If GetGlyphOutline with GGO_NATIVE returns 0, we know there was no outline.
936 DWORD bufferSize = GetGlyphOutlineW(fDDC, glyphId, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
937 empty = (0 == bufferSize);
940 glyph->fTop = SkToS16(-gm.gmptGlyphOrigin.y);
941 glyph->fLeft = SkToS16(gm.gmptGlyphOrigin.x);
946 // Outset, since the image may bleed out of the black box.
947 // For embedded bitmaps the black box should be exact.
948 // For outlines we need to outset by 1 in all directions for bleed.
949 // For ClearType we need to outset by 2 for bleed.
950 glyph->fWidth = gm.gmBlackBoxX + 4;
951 glyph->fHeight = gm.gmBlackBoxY + 4;
955 glyph->fAdvanceX = SkIntToFixed(gm.gmCellIncX);
956 glyph->fAdvanceY = SkIntToFixed(gm.gmCellIncY);
957 glyph->fRsbDelta = 0;
958 glyph->fLsbDelta = 0;
960 if (this->isSubpixel()) {
961 sk_bzero(&gm, sizeof(gm));
962 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fHighResMat22);
963 if (GDI_ERROR != status) {
965 fHiResMatrix.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance);
966 glyph->fAdvanceX = SkScalarToFixed(advance.fX);
967 glyph->fAdvanceY = SkScalarToFixed(advance.fY);
969 } else if (!isAxisAligned(this->fRec)) {
970 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fGsA);
971 if (GDI_ERROR != status) {
973 fG_inv.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance);
974 glyph->fAdvanceX = SkScalarToFixed(advance.fX);
975 glyph->fAdvanceY = SkScalarToFixed(advance.fY);
980 static const MAT2 gMat2Identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
981 void SkScalerContext_GDI::generateFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my) {
987 sk_bzero(mx, sizeof(*mx));
990 sk_bzero(my, sizeof(*my));
995 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
996 if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) {
999 mx->fTop = SkIntToScalar(-fTM.tmAscent);
1000 mx->fAscent = SkIntToScalar(-fTM.tmAscent);
1001 mx->fDescent = SkIntToScalar(fTM.tmDescent);
1002 mx->fBottom = SkIntToScalar(fTM.tmDescent);
1003 mx->fLeading = SkIntToScalar(fTM.tmExternalLeading);
1007 my->fTop = SkIntToScalar(-fTM.tmAscent);
1008 my->fAscent = SkIntToScalar(-fTM.tmAscent);
1009 my->fDescent = SkIntToScalar(fTM.tmDescent);
1010 my->fBottom = SkIntToScalar(fTM.tmDescent);
1011 my->fLeading = SkIntToScalar(fTM.tmExternalLeading);
1012 my->fAvgCharWidth = SkIntToScalar(fTM.tmAveCharWidth);
1013 my->fMaxCharWidth = SkIntToScalar(fTM.tmMaxCharWidth);
1015 my->fXMax = my->fMaxCharWidth;
1018 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
1023 OUTLINETEXTMETRIC otm;
1025 uint32_t ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
1027 LogFontTypeface::EnsureAccessible(this->getTypeface());
1028 ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
1035 mx->fTop = SkIntToScalar(-otm.otmrcFontBox.left);
1036 mx->fAscent = SkIntToScalar(-otm.otmAscent);
1037 mx->fDescent = SkIntToScalar(-otm.otmDescent);
1038 mx->fBottom = SkIntToScalar(otm.otmrcFontBox.right);
1039 mx->fLeading = SkIntToScalar(otm.otmLineGap);
1040 mx->fUnderlineThickness = SkIntToScalar(otm.otmsUnderscoreSize);
1041 mx->fUnderlinePosition = -SkIntToScalar(otm.otmsUnderscorePosition);
1043 mx->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
1044 mx->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
1048 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
1049 my->fTop = SkIntToScalar(-otm.otmrcFontBox.top);
1050 my->fAscent = SkIntToScalar(-otm.otmAscent);
1051 my->fDescent = SkIntToScalar(-otm.otmDescent);
1052 my->fBottom = SkIntToScalar(-otm.otmrcFontBox.bottom);
1053 my->fLeading = SkIntToScalar(otm.otmLineGap);
1054 my->fAvgCharWidth = SkIntToScalar(otm.otmTextMetrics.tmAveCharWidth);
1055 my->fMaxCharWidth = SkIntToScalar(otm.otmTextMetrics.tmMaxCharWidth);
1056 my->fXMin = SkIntToScalar(otm.otmrcFontBox.left);
1057 my->fXMax = SkIntToScalar(otm.otmrcFontBox.right);
1058 my->fUnderlineThickness = SkIntToScalar(otm.otmsUnderscoreSize);
1059 my->fUnderlinePosition = -SkIntToScalar(otm.otmsUnderscorePosition);
1061 my->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
1062 my->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
1064 my->fXHeight = SkIntToScalar(otm.otmsXHeight);
1067 sk_bzero(&gm, sizeof(gm));
1068 DWORD len = GetGlyphOutlineW(fDDC, 'x', GGO_METRICS, &gm, 0, 0, &gMat2Identity);
1069 if (len != GDI_ERROR && gm.gmBlackBoxY > 0) {
1070 my->fXHeight = SkIntToScalar(gm.gmBlackBoxY);
1075 ////////////////////////////////////////////////////////////////////////////////////////
1077 #define SK_SHOW_TEXT_BLIT_COVERAGE 0
1079 static void build_power_table(uint8_t table[], float ee) {
1080 for (int i = 0; i < 256; i++) {
1081 float x = i / 255.f;
1082 x = sk_float_pow(x, ee);
1083 int xx = SkScalarRoundToInt(x * 255);
1084 table[i] = SkToU8(xx);
1089 * This will invert the gamma applied by GDI (gray-scale antialiased), so we
1090 * can get linear values.
1092 * GDI grayscale appears to use a hard-coded gamma of 2.3.
1094 * GDI grayscale appears to draw using the black and white rasterizer at four
1095 * times the size and then downsamples to compute the coverage mask. As a
1096 * result there are only seventeen total grays. This lack of fidelity means
1097 * that shifting into other color spaces is imprecise.
1099 static const uint8_t* getInverseGammaTableGDI() {
1100 // Since build_power_table is idempotent, many threads can build gTableGdi
1103 // Microsoft Specific:
1104 // Making gInited volatile provides read-aquire and write-release in vc++.
1105 // In VS2012, see compiler option /volatile:(ms|iso).
1106 // Replace with C++11 atomics when possible.
1107 static volatile bool gInited;
1108 static uint8_t gTableGdi[256];
1110 // Need a L/L (read) barrier (full acquire not needed). If gInited is observed
1111 // true then gTableGdi is observable, but it must be requested.
1113 build_power_table(gTableGdi, 2.3f);
1114 // Need a S/S (write) barrier (full release not needed) here so that this
1115 // write to gInited becomes observable after gTableGdi.
1122 * This will invert the gamma applied by GDI ClearType, so we can get linear
1125 * GDI ClearType uses SPI_GETFONTSMOOTHINGCONTRAST / 1000 as the gamma value.
1126 * If this value is not specified, the default is a gamma of 1.4.
1128 static const uint8_t* getInverseGammaTableClearType() {
1129 // We don't expect SPI_GETFONTSMOOTHINGCONTRAST to ever change, so building
1130 // gTableClearType with build_power_table is effectively idempotent.
1132 // Microsoft Specific:
1133 // Making gInited volatile provides read-aquire and write-release in vc++.
1134 // In VS2012, see compiler option /volatile:(ms|iso).
1135 // Replace with C++11 atomics when possible.
1136 static volatile bool gInited;
1137 static uint8_t gTableClearType[256];
1139 // Need a L/L (read) barrier (acquire not needed). If gInited is observed
1140 // true then gTableClearType is observable, but it must be requested.
1143 if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &level, 0) || !level) {
1144 // can't get the data, so use a default
1147 build_power_table(gTableClearType, level / 1000.0f);
1148 // Need a S/S (write) barrier (release not needed) here so that this
1149 // write to gInited becomes observable after gTableClearType.
1152 return gTableClearType;
1155 #include "SkColorPriv.h"
1157 //Cannot assume that the input rgb is gray due to possible setting of kGenA8FromLCD_Flag.
1158 template<bool APPLY_PREBLEND>
1159 static inline uint8_t rgb_to_a8(SkGdiRGB rgb, const uint8_t* table8) {
1160 U8CPU r = (rgb >> 16) & 0xFF;
1161 U8CPU g = (rgb >> 8) & 0xFF;
1162 U8CPU b = (rgb >> 0) & 0xFF;
1163 return sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8);
1166 template<bool APPLY_PREBLEND>
1167 static inline uint16_t rgb_to_lcd16(SkGdiRGB rgb, const uint8_t* tableR,
1168 const uint8_t* tableG,
1169 const uint8_t* tableB) {
1170 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
1171 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG);
1172 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB);
1173 #if SK_SHOW_TEXT_BLIT_COVERAGE
1174 r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10);
1176 return SkPack888ToRGB16(r, g, b);
1179 template<bool APPLY_PREBLEND>
1180 static inline SkPMColor rgb_to_lcd32(SkGdiRGB rgb, const uint8_t* tableR,
1181 const uint8_t* tableG,
1182 const uint8_t* tableB) {
1183 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
1184 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG);
1185 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB);
1186 #if SK_SHOW_TEXT_BLIT_COVERAGE
1187 r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10);
1189 return SkPackARGB32(0xFF, r, g, b);
1192 // Is this GDI color neither black nor white? If so, we have to keep this
1193 // image as is, rather than smashing it down to a BW mask.
1195 // returns int instead of bool, since we don't want/have to pay to convert
1196 // the zero/non-zero value into a bool
1197 static int is_not_black_or_white(SkGdiRGB c) {
1198 // same as (but faster than)
1200 // return 0 == c || 0x00FFFFFF == c;
1201 return (c + (c & 1)) & 0x00FFFFFF;
1204 static bool is_rgb_really_bw(const SkGdiRGB* src, int width, int height, size_t srcRB) {
1205 for (int y = 0; y < height; ++y) {
1206 for (int x = 0; x < width; ++x) {
1207 if (is_not_black_or_white(src[x])) {
1211 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1216 // gdi's bitmap is upside-down, so we reverse dst walking in Y
1217 // whenever we copy it into skia's buffer
1218 static void rgb_to_bw(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
1219 const SkGlyph& glyph) {
1220 const int width = glyph.fWidth;
1221 const size_t dstRB = (width + 7) >> 3;
1222 uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1224 int byteCount = width >> 3;
1225 int bitCount = width & 7;
1227 // adjust srcRB to skip the values in our byteCount loop,
1228 // since we increment src locally there
1229 srcRB -= byteCount * 8 * sizeof(SkGdiRGB);
1231 for (int y = 0; y < glyph.fHeight; ++y) {
1232 if (byteCount > 0) {
1233 for (int i = 0; i < byteCount; ++i) {
1235 byte |= src[0] & (1 << 7);
1236 byte |= src[1] & (1 << 6);
1237 byte |= src[2] & (1 << 5);
1238 byte |= src[3] & (1 << 4);
1239 byte |= src[4] & (1 << 3);
1240 byte |= src[5] & (1 << 2);
1241 byte |= src[6] & (1 << 1);
1242 byte |= src[7] & (1 << 0);
1249 unsigned mask = 0x80;
1250 for (int i = 0; i < bitCount; i++) {
1251 byte |= src[i] & mask;
1254 dst[byteCount] = byte;
1256 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1259 #if SK_SHOW_TEXT_BLIT_COVERAGE
1260 if (glyph.fWidth > 0 && glyph.fHeight > 0) {
1261 uint8_t* first = (uint8_t*)glyph.fImage;
1262 uint8_t* last = (uint8_t*)((char*)glyph.fImage + glyph.fHeight * dstRB - 1);
1264 *last |= bitCount == 0 ? 1 : 1 << (8 - bitCount);
1269 template<bool APPLY_PREBLEND>
1270 static void rgb_to_a8(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
1271 const SkGlyph& glyph, const uint8_t* table8) {
1272 const size_t dstRB = glyph.rowBytes();
1273 const int width = glyph.fWidth;
1274 uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1276 for (int y = 0; y < glyph.fHeight; y++) {
1277 for (int i = 0; i < width; i++) {
1278 dst[i] = rgb_to_a8<APPLY_PREBLEND>(src[i], table8);
1279 #if SK_SHOW_TEXT_BLIT_COVERAGE
1280 dst[i] = SkMax32(dst[i], 10);
1283 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1288 template<bool APPLY_PREBLEND>
1289 static void rgb_to_lcd16(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph,
1290 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
1291 const size_t dstRB = glyph.rowBytes();
1292 const int width = glyph.fWidth;
1293 uint16_t* SK_RESTRICT dst = (uint16_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1295 for (int y = 0; y < glyph.fHeight; y++) {
1296 for (int i = 0; i < width; i++) {
1297 dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(src[i], tableR, tableG, tableB);
1299 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1300 dst = (uint16_t*)((char*)dst - dstRB);
1304 template<bool APPLY_PREBLEND>
1305 static void rgb_to_lcd32(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph,
1306 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
1307 const size_t dstRB = glyph.rowBytes();
1308 const int width = glyph.fWidth;
1309 uint32_t* SK_RESTRICT dst = (uint32_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1311 for (int y = 0; y < glyph.fHeight; y++) {
1312 for (int i = 0; i < width; i++) {
1313 dst[i] = rgb_to_lcd32<APPLY_PREBLEND>(src[i], tableR, tableG, tableB);
1315 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1316 dst = (uint32_t*)((char*)dst - dstRB);
1320 static inline unsigned clamp255(unsigned x) {
1322 return x - (x >> 8);
1325 void SkScalerContext_GDI::generateImage(const SkGlyph& glyph) {
1328 const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat;
1329 const bool isAA = !isLCD(fRec);
1332 const void* bits = fOffscreen.draw(glyph, isBW, &srcRB);
1334 LogFontTypeface::EnsureAccessible(this->getTypeface());
1335 bits = fOffscreen.draw(glyph, isBW, &srcRB);
1337 sk_bzero(glyph.fImage, glyph.computeImageSize());
1343 const uint8_t* table;
1344 //The offscreen contains a GDI blit if isAA and kGenA8FromLCD_Flag is not set.
1345 //Otherwise the offscreen contains a ClearType blit.
1346 if (isAA && !(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag)) {
1347 table = getInverseGammaTableGDI();
1349 table = getInverseGammaTableClearType();
1351 //Note that the following cannot really be integrated into the
1352 //pre-blend, since we may not be applying the pre-blend; when we aren't
1353 //applying the pre-blend it means that a filter wants linear anyway.
1354 //Other code may also be applying the pre-blend, so we'd need another
1355 //one with this and one without.
1356 SkGdiRGB* addr = (SkGdiRGB*)bits;
1357 for (int y = 0; y < glyph.fHeight; ++y) {
1358 for (int x = 0; x < glyph.fWidth; ++x) {
1359 int r = (addr[x] >> 16) & 0xFF;
1360 int g = (addr[x] >> 8) & 0xFF;
1361 int b = (addr[x] >> 0) & 0xFF;
1362 addr[x] = (table[r] << 16) | (table[g] << 8) | table[b];
1364 addr = SkTAddOffset<SkGdiRGB>(addr, srcRB);
1368 int width = glyph.fWidth;
1369 size_t dstRB = glyph.rowBytes();
1371 const uint8_t* src = (const uint8_t*)bits;
1372 uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1373 for (int y = 0; y < glyph.fHeight; y++) {
1374 memcpy(dst, src, dstRB);
1378 #if SK_SHOW_TEXT_BLIT_COVERAGE
1379 if (glyph.fWidth > 0 && glyph.fHeight > 0) {
1380 int bitCount = width & 7;
1381 uint8_t* first = (uint8_t*)glyph.fImage;
1382 uint8_t* last = (uint8_t*)((char*)glyph.fImage + glyph.fHeight * dstRB - 1);
1384 *last |= bitCount == 0 ? 1 : 1 << (8 - bitCount);
1388 // since the caller may require A8 for maskfilters, we can't check for BW
1389 // ... until we have the caller tell us that explicitly
1390 const SkGdiRGB* src = (const SkGdiRGB*)bits;
1391 if (fPreBlend.isApplicable()) {
1392 rgb_to_a8<true>(src, srcRB, glyph, fPreBlend.fG);
1394 rgb_to_a8<false>(src, srcRB, glyph, fPreBlend.fG);
1397 const SkGdiRGB* src = (const SkGdiRGB*)bits;
1398 if (is_rgb_really_bw(src, width, glyph.fHeight, srcRB)) {
1399 rgb_to_bw(src, srcRB, glyph);
1400 ((SkGlyph*)&glyph)->fMaskFormat = SkMask::kBW_Format;
1402 if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
1403 if (fPreBlend.isApplicable()) {
1404 rgb_to_lcd16<true>(src, srcRB, glyph,
1405 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1407 rgb_to_lcd16<false>(src, srcRB, glyph,
1408 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1411 SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat);
1412 if (fPreBlend.isApplicable()) {
1413 rgb_to_lcd32<true>(src, srcRB, glyph,
1414 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1416 rgb_to_lcd32<false>(src, srcRB, glyph,
1417 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1424 class GDIGlyphbufferPointIter {
1426 GDIGlyphbufferPointIter(const uint8_t* glyphbuf, DWORD total_size)
1427 : fHeaderIter(glyphbuf, total_size), fCurveIter(), fPointIter()
1430 POINTFX const * next() {
1432 if (!fCurveIter.isSet()) {
1433 const TTPOLYGONHEADER* header = fHeaderIter.next();
1434 if (NULL == header) {
1437 fCurveIter.set(header);
1438 const TTPOLYCURVE* curve = fCurveIter.next();
1439 if (NULL == curve) {
1442 fPointIter.set(curve);
1443 return &header->pfxStart;
1446 const POINTFX* nextPoint = fPointIter.next();
1447 if (NULL == nextPoint) {
1448 const TTPOLYCURVE* curve = fCurveIter.next();
1449 if (NULL == curve) {
1453 fPointIter.set(curve);
1455 nextPoint = fPointIter.next();
1460 WORD currentCurveType() {
1461 return fPointIter.fCurveType;
1465 /** Iterates over all of the polygon headers in a glyphbuf. */
1466 class GDIPolygonHeaderIter {
1468 GDIPolygonHeaderIter(const uint8_t* glyphbuf, DWORD total_size)
1469 : fCurPolygon(reinterpret_cast<const TTPOLYGONHEADER*>(glyphbuf))
1470 , fEndPolygon(SkTAddOffset<const TTPOLYGONHEADER>(glyphbuf, total_size))
1473 const TTPOLYGONHEADER* next() {
1474 if (fCurPolygon >= fEndPolygon) {
1477 const TTPOLYGONHEADER* thisPolygon = fCurPolygon;
1478 fCurPolygon = SkTAddOffset<const TTPOLYGONHEADER>(fCurPolygon, fCurPolygon->cb);
1482 const TTPOLYGONHEADER* fCurPolygon;
1483 const TTPOLYGONHEADER* fEndPolygon;
1486 /** Iterates over all of the polygon curves in a polygon header. */
1487 class GDIPolygonCurveIter {
1489 GDIPolygonCurveIter() : fCurCurve(NULL), fEndCurve(NULL) { }
1491 GDIPolygonCurveIter(const TTPOLYGONHEADER* curPolygon)
1492 : fCurCurve(SkTAddOffset<const TTPOLYCURVE>(curPolygon, sizeof(TTPOLYGONHEADER)))
1493 , fEndCurve(SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon->cb))
1496 bool isSet() { return fCurCurve != NULL; }
1498 void set(const TTPOLYGONHEADER* curPolygon) {
1499 fCurCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon, sizeof(TTPOLYGONHEADER));
1500 fEndCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon->cb);
1507 const TTPOLYCURVE* next() {
1508 if (fCurCurve >= fEndCurve) {
1511 const TTPOLYCURVE* thisCurve = fCurCurve;
1512 fCurCurve = SkTAddOffset<const TTPOLYCURVE>(fCurCurve, size_of_TTPOLYCURVE(*fCurCurve));
1516 size_t size_of_TTPOLYCURVE(const TTPOLYCURVE& curve) {
1517 return 2*sizeof(WORD) + curve.cpfx*sizeof(POINTFX);
1519 const TTPOLYCURVE* fCurCurve;
1520 const TTPOLYCURVE* fEndCurve;
1523 /** Iterates over all of the polygon points in a polygon curve. */
1524 class GDIPolygonCurvePointIter {
1526 GDIPolygonCurvePointIter() : fCurveType(0), fCurPoint(NULL), fEndPoint(NULL) { }
1528 GDIPolygonCurvePointIter(const TTPOLYCURVE* curPolygon)
1529 : fCurveType(curPolygon->wType)
1530 , fCurPoint(&curPolygon->apfx[0])
1531 , fEndPoint(&curPolygon->apfx[curPolygon->cpfx])
1534 bool isSet() { return fCurPoint != NULL; }
1536 void set(const TTPOLYCURVE* curPolygon) {
1537 fCurveType = curPolygon->wType;
1538 fCurPoint = &curPolygon->apfx[0];
1539 fEndPoint = &curPolygon->apfx[curPolygon->cpfx];
1546 const POINTFX* next() {
1547 if (fCurPoint >= fEndPoint) {
1550 const POINTFX* thisPoint = fCurPoint;
1557 const POINTFX* fCurPoint;
1558 const POINTFX* fEndPoint;
1561 GDIPolygonHeaderIter fHeaderIter;
1562 GDIPolygonCurveIter fCurveIter;
1563 GDIPolygonCurvePointIter fPointIter;
1566 static void sk_path_from_gdi_path(SkPath* path, const uint8_t* glyphbuf, DWORD total_size) {
1567 const uint8_t* cur_glyph = glyphbuf;
1568 const uint8_t* end_glyph = glyphbuf + total_size;
1570 while (cur_glyph < end_glyph) {
1571 const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
1573 const uint8_t* end_poly = cur_glyph + th->cb;
1574 const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
1576 path->moveTo(SkFixedToScalar( SkFIXEDToFixed(th->pfxStart.x)),
1577 SkFixedToScalar(-SkFIXEDToFixed(th->pfxStart.y)));
1579 while (cur_poly < end_poly) {
1580 const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
1582 if (pc->wType == TT_PRIM_LINE) {
1583 for (uint16_t i = 0; i < pc->cpfx; i++) {
1584 path->lineTo(SkFixedToScalar( SkFIXEDToFixed(pc->apfx[i].x)),
1585 SkFixedToScalar(-SkFIXEDToFixed(pc->apfx[i].y)));
1589 if (pc->wType == TT_PRIM_QSPLINE) {
1590 for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline
1591 POINTFX pnt_b = pc->apfx[u]; // B is always the current point
1592 POINTFX pnt_c = pc->apfx[u+1];
1594 if (u < pc->cpfx - 2) { // If not on last spline, compute C
1595 pnt_c.x = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.x),
1596 SkFIXEDToFixed(pnt_c.x)));
1597 pnt_c.y = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.y),
1598 SkFIXEDToFixed(pnt_c.y)));
1601 path->quadTo(SkFixedToScalar( SkFIXEDToFixed(pnt_b.x)),
1602 SkFixedToScalar(-SkFIXEDToFixed(pnt_b.y)),
1603 SkFixedToScalar( SkFIXEDToFixed(pnt_c.x)),
1604 SkFixedToScalar(-SkFIXEDToFixed(pnt_c.y)));
1607 // Advance past this TTPOLYCURVE.
1608 cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx;
1610 cur_glyph += th->cb;
1615 #define move_next_expected_hinted_point(iter, pElem) do {\
1616 pElem = iter.next(); \
1617 if (NULL == pElem) return false; \
1620 // It is possible for the hinted and unhinted versions of the same path to have
1621 // a different number of points due to GDI's handling of flipped points.
1622 // If this is detected, this will return false.
1623 static bool sk_path_from_gdi_paths(SkPath* path, const uint8_t* glyphbuf, DWORD total_size,
1624 GDIGlyphbufferPointIter hintedYs) {
1625 const uint8_t* cur_glyph = glyphbuf;
1626 const uint8_t* end_glyph = glyphbuf + total_size;
1628 POINTFX const * hintedPoint;
1630 while (cur_glyph < end_glyph) {
1631 const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
1633 const uint8_t* end_poly = cur_glyph + th->cb;
1634 const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
1636 move_next_expected_hinted_point(hintedYs, hintedPoint);
1637 path->moveTo(SkFixedToScalar( SkFIXEDToFixed(th->pfxStart.x)),
1638 SkFixedToScalar(-SkFIXEDToFixed(hintedPoint->y)));
1640 while (cur_poly < end_poly) {
1641 const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
1643 if (pc->wType == TT_PRIM_LINE) {
1644 for (uint16_t i = 0; i < pc->cpfx; i++) {
1645 move_next_expected_hinted_point(hintedYs, hintedPoint);
1646 path->lineTo(SkFixedToScalar( SkFIXEDToFixed(pc->apfx[i].x)),
1647 SkFixedToScalar(-SkFIXEDToFixed(hintedPoint->y)));
1651 if (pc->wType == TT_PRIM_QSPLINE) {
1652 POINTFX currentPoint = pc->apfx[0];
1653 move_next_expected_hinted_point(hintedYs, hintedPoint);
1654 // only take the hinted y if it wasn't flipped
1655 if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) {
1656 currentPoint.y = hintedPoint->y;
1658 for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline
1659 POINTFX pnt_b = currentPoint;//pc->apfx[u]; // B is always the current point
1660 POINTFX pnt_c = pc->apfx[u+1];
1661 move_next_expected_hinted_point(hintedYs, hintedPoint);
1662 // only take the hinted y if it wasn't flipped
1663 if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) {
1664 pnt_c.y = hintedPoint->y;
1666 currentPoint.x = pnt_c.x;
1667 currentPoint.y = pnt_c.y;
1669 if (u < pc->cpfx - 2) { // If not on last spline, compute C
1670 pnt_c.x = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.x),
1671 SkFIXEDToFixed(pnt_c.x)));
1672 pnt_c.y = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.y),
1673 SkFIXEDToFixed(pnt_c.y)));
1676 path->quadTo(SkFixedToScalar( SkFIXEDToFixed(pnt_b.x)),
1677 SkFixedToScalar(-SkFIXEDToFixed(pnt_b.y)),
1678 SkFixedToScalar( SkFIXEDToFixed(pnt_c.x)),
1679 SkFixedToScalar(-SkFIXEDToFixed(pnt_c.y)));
1682 // Advance past this TTPOLYCURVE.
1683 cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx;
1685 cur_glyph += th->cb;
1691 DWORD SkScalerContext_GDI::getGDIGlyphPath(const SkGlyph& glyph, UINT flags,
1692 SkAutoSTMalloc<BUFFERSIZE, uint8_t>* glyphbuf)
1696 DWORD total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, BUFFERSIZE, glyphbuf->get(), &fMat22);
1697 // Sometimes GetGlyphOutlineW returns a number larger than BUFFERSIZE even if BUFFERSIZE > 0.
1698 // It has been verified that this does not involve a buffer overrun.
1699 if (GDI_ERROR == total_size || total_size > BUFFERSIZE) {
1700 // GDI_ERROR because the BUFFERSIZE was too small, or because the data was not accessible.
1701 // When the data is not accessable GetGlyphOutlineW fails rather quickly,
1702 // so just try to get the size. If that fails then ensure the data is accessible.
1703 total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, 0, NULL, &fMat22);
1704 if (GDI_ERROR == total_size) {
1705 LogFontTypeface::EnsureAccessible(this->getTypeface());
1706 total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, 0, NULL, &fMat22);
1707 if (GDI_ERROR == total_size) {
1713 glyphbuf->reset(total_size);
1715 DWORD ret = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, total_size, glyphbuf->get(), &fMat22);
1716 if (GDI_ERROR == ret) {
1717 LogFontTypeface::EnsureAccessible(this->getTypeface());
1718 ret = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, total_size, glyphbuf->get(), &fMat22);
1719 if (GDI_ERROR == ret) {
1728 void SkScalerContext_GDI::generatePath(const SkGlyph& glyph, SkPath* path) {
1729 SkASSERT(&glyph && path);
1734 // Out of all the fonts on a typical Windows box,
1735 // 25% of glyphs require more than 2KB.
1736 // 1% of glyphs require more than 4KB.
1737 // 0.01% of glyphs require more than 8KB.
1738 // 8KB is less than 1% of the normal 1MB stack on Windows.
1739 // Note that some web fonts glyphs require more than 20KB.
1740 //static const DWORD BUFFERSIZE = (1 << 13);
1742 //GDI only uses hinted outlines when axis aligned.
1743 UINT format = GGO_NATIVE | GGO_GLYPH_INDEX;
1744 if (fRec.getHinting() == SkPaint::kNo_Hinting || fRec.getHinting() == SkPaint::kSlight_Hinting){
1745 format |= GGO_UNHINTED;
1747 SkAutoSTMalloc<BUFFERSIZE, uint8_t> glyphbuf(BUFFERSIZE);
1748 DWORD total_size = getGDIGlyphPath(glyph, format, &glyphbuf);
1749 if (0 == total_size) {
1753 if (fRec.getHinting() != SkPaint::kSlight_Hinting) {
1754 sk_path_from_gdi_path(path, glyphbuf, total_size);
1756 //GDI only uses hinted outlines when axis aligned.
1757 UINT format = GGO_NATIVE | GGO_GLYPH_INDEX;
1759 SkAutoSTMalloc<BUFFERSIZE, uint8_t> hintedGlyphbuf(BUFFERSIZE);
1760 DWORD hinted_total_size = getGDIGlyphPath(glyph, format, &hintedGlyphbuf);
1761 if (0 == hinted_total_size) {
1765 if (!sk_path_from_gdi_paths(path, glyphbuf, total_size,
1766 GDIGlyphbufferPointIter(hintedGlyphbuf, hinted_total_size)))
1769 sk_path_from_gdi_path(path, glyphbuf, total_size);
1774 static void logfont_for_name(const char* familyName, LOGFONT* lf) {
1775 sk_bzero(lf, sizeof(LOGFONT));
1777 // Get the buffer size needed first.
1778 size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName,
1780 // Allocate a buffer (str_len already has terminating null
1782 wchar_t *wideFamilyName = new wchar_t[str_len];
1783 // Now actually convert the string.
1784 ::MultiByteToWideChar(CP_UTF8, 0, familyName, -1,
1785 wideFamilyName, str_len);
1786 ::wcsncpy(lf->lfFaceName, wideFamilyName, LF_FACESIZE - 1);
1787 delete [] wideFamilyName;
1788 lf->lfFaceName[LF_FACESIZE-1] = L'\0';
1790 ::strncpy(lf->lfFaceName, familyName, LF_FACESIZE - 1);
1791 lf->lfFaceName[LF_FACESIZE - 1] = '\0';
1795 void LogFontTypeface::onGetFontDescriptor(SkFontDescriptor* desc,
1796 bool* isLocalStream) const {
1797 // Get the actual name of the typeface. The logfont may not know this.
1798 HFONT font = CreateFontIndirect(&fLogFont);
1800 HDC deviceContext = ::CreateCompatibleDC(NULL);
1801 HFONT savefont = (HFONT)SelectObject(deviceContext, font);
1803 SkString familyName;
1804 dcfontname_to_skstring(deviceContext, fLogFont, &familyName);
1806 if (deviceContext) {
1807 ::SelectObject(deviceContext, savefont);
1808 ::DeleteDC(deviceContext);
1811 ::DeleteObject(font);
1814 desc->setFamilyName(familyName.c_str());
1815 *isLocalStream = this->fSerializeAsStream;
1818 static bool getWidthAdvance(HDC hdc, int gId, int16_t* advance) {
1819 // Initialize the MAT2 structure to the identify transformation matrix.
1820 static const MAT2 mat2 = {SkScalarToFIXED(1), SkScalarToFIXED(0),
1821 SkScalarToFIXED(0), SkScalarToFIXED(1)};
1822 int flags = GGO_METRICS | GGO_GLYPH_INDEX;
1824 if (GDI_ERROR == GetGlyphOutline(hdc, gId, flags, &gm, 0, NULL, &mat2)) {
1828 *advance = gm.gmCellIncX;
1832 SkAdvancedTypefaceMetrics* LogFontTypeface::onGetAdvancedTypefaceMetrics(
1833 SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
1834 const uint32_t* glyphIDs,
1835 uint32_t glyphIDsCount) const {
1836 LOGFONT lf = fLogFont;
1837 SkAdvancedTypefaceMetrics* info = NULL;
1839 HDC hdc = CreateCompatibleDC(NULL);
1840 HFONT font = CreateFontIndirect(&lf);
1841 HFONT savefont = (HFONT)SelectObject(hdc, font);
1842 HFONT designFont = NULL;
1844 const char stem_chars[] = {'i', 'I', '!', '1'};
1846 unsigned glyphCount;
1848 // To request design units, create a logical font whose height is specified
1850 OUTLINETEXTMETRIC otm;
1851 unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
1853 call_ensure_accessible(lf);
1854 otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
1856 if (!otmRet || !GetTextFace(hdc, LF_FACESIZE, lf.lfFaceName)) {
1859 lf.lfHeight = -SkToS32(otm.otmEMSquare);
1860 designFont = CreateFontIndirect(&lf);
1861 SelectObject(hdc, designFont);
1862 if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm)) {
1865 glyphCount = calculateGlyphCount(hdc, fLogFont);
1867 info = new SkAdvancedTypefaceMetrics;
1868 info->fEmSize = otm.otmEMSquare;
1869 info->fMultiMaster = false;
1870 info->fLastGlyphID = SkToU16(glyphCount - 1);
1872 tchar_to_skstring(lf.lfFaceName, &info->fFontName);
1874 if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) {
1875 populate_glyph_to_unicode(hdc, glyphCount, &(info->fGlyphToUnicode));
1878 if (glyphCount > 0 &&
1879 (otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE)) {
1880 info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
1882 info->fType = SkAdvancedTypefaceMetrics::kOther_Font;
1883 info->fItalicAngle = 0;
1887 info->fCapHeight = 0;
1888 info->fBBox = SkIRect::MakeEmpty();
1892 // If this bit is clear the font is a fixed pitch font.
1893 if (!(otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
1894 info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
1896 if (otm.otmTextMetrics.tmItalic) {
1897 info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
1899 if (otm.otmTextMetrics.tmPitchAndFamily & FF_ROMAN) {
1900 info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
1901 } else if (otm.otmTextMetrics.tmPitchAndFamily & FF_SCRIPT) {
1902 info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
1905 // The main italic angle of the font, in tenths of a degree counterclockwise
1907 info->fItalicAngle = otm.otmItalicAngle / 10;
1908 info->fAscent = SkToS16(otm.otmTextMetrics.tmAscent);
1909 info->fDescent = SkToS16(-otm.otmTextMetrics.tmDescent);
1910 // TODO(ctguil): Use alternate cap height calculation.
1911 // MSDN says otmsCapEmHeight is not support but it is returning a value on
1913 info->fCapHeight = otm.otmsCapEmHeight;
1915 SkIRect::MakeLTRB(otm.otmrcFontBox.left, otm.otmrcFontBox.top,
1916 otm.otmrcFontBox.right, otm.otmrcFontBox.bottom);
1918 // Figure out a good guess for StemV - Min width of i, I, !, 1.
1919 // This probably isn't very good with an italic font.
1920 min_width = SHRT_MAX;
1922 for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) {
1924 if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) {
1925 int16_t width = abcWidths.abcB;
1926 if (width > 0 && width < min_width) {
1928 info->fStemV = min_width;
1933 // If bit 1 is set, the font may not be embedded in a document.
1934 // If bit 1 is clear, the font can be embedded.
1935 // If bit 2 is set, the embedding is read-only.
1936 if (otm.otmfsType & 0x1) {
1937 info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
1938 } else if (perGlyphInfo &
1939 SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) {
1940 if (info->fStyle & SkAdvancedTypefaceMetrics::kFixedPitch_Style) {
1941 appendRange(&info->fGlyphWidths, 0);
1942 info->fGlyphWidths->fAdvance.append(1, &min_width);
1943 finishRange(info->fGlyphWidths.get(), 0,
1944 SkAdvancedTypefaceMetrics::WidthRange::kDefault);
1946 info->fGlyphWidths.reset(
1957 SelectObject(hdc, savefont);
1958 DeleteObject(designFont);
1965 //Dummy representation of a Base64 encoded GUID from create_unique_font_name.
1966 #define BASE64_GUID_ID "XXXXXXXXXXXXXXXXXXXXXXXX"
1967 //Length of GUID representation from create_id, including NULL terminator.
1968 #define BASE64_GUID_ID_LEN SK_ARRAY_COUNT(BASE64_GUID_ID)
1970 SK_COMPILE_ASSERT(BASE64_GUID_ID_LEN < LF_FACESIZE, GUID_longer_than_facesize);
1973 NameID 6 Postscript names cannot have the character '/'.
1974 It would be easier to hex encode the GUID, but that is 32 bytes,
1975 and many systems have issues with names longer than 28 bytes.
1976 The following need not be any standard base64 encoding.
1977 The encoded value is never decoded.
1979 static const char postscript_safe_base64_encode[] =
1980 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1981 "abcdefghijklmnopqrstuvwxyz"
1985 Formats a GUID into Base64 and places it into buffer.
1986 buffer should have space for at least BASE64_GUID_ID_LEN characters.
1987 The string will always be null terminated.
1988 XXXXXXXXXXXXXXXXXXXXXXXX0
1990 static void format_guid_b64(const GUID& guid, char* buffer, size_t bufferSize) {
1991 SkASSERT(bufferSize >= BASE64_GUID_ID_LEN);
1992 size_t written = SkBase64::Encode(&guid, sizeof(guid), buffer, postscript_safe_base64_encode);
1993 SkASSERT(written < LF_FACESIZE);
1994 buffer[written] = '\0';
1998 Creates a Base64 encoded GUID and places it into buffer.
1999 buffer should have space for at least BASE64_GUID_ID_LEN characters.
2000 The string will always be null terminated.
2001 XXXXXXXXXXXXXXXXXXXXXXXX0
2003 static HRESULT create_unique_font_name(char* buffer, size_t bufferSize) {
2005 if (FAILED(CoCreateGuid(&guid))) {
2006 return E_UNEXPECTED;
2008 format_guid_b64(guid, buffer, bufferSize);
2014 Introduces a font to GDI. On failure will return NULL. The returned handle
2015 should eventually be passed to RemoveFontMemResourceEx.
2017 static HANDLE activate_font(SkData* fontData) {
2019 //AddFontMemResourceEx just copies the data, but does not specify const.
2020 HANDLE fontHandle = AddFontMemResourceEx(const_cast<void*>(fontData->data()),
2021 static_cast<DWORD>(fontData->size()),
2025 if (fontHandle != NULL && numFonts < 1) {
2026 RemoveFontMemResourceEx(fontHandle);
2033 static SkTypeface* create_from_stream(SkStream* stream) {
2034 // Create a unique and unpredictable font name.
2035 // Avoids collisions and access from CSS.
2036 char familyName[BASE64_GUID_ID_LEN];
2037 const int familyNameSize = SK_ARRAY_COUNT(familyName);
2038 if (FAILED(create_unique_font_name(familyName, familyNameSize))) {
2042 // Change the name of the font.
2043 SkAutoTUnref<SkData> rewrittenFontData(SkOTUtils::RenameFont(stream, familyName, familyNameSize-1));
2044 if (NULL == rewrittenFontData.get()) {
2048 // Register the font with GDI.
2049 HANDLE fontReference = activate_font(rewrittenFontData.get());
2050 if (NULL == fontReference) {
2054 // Create the typeface.
2056 logfont_for_name(familyName, &lf);
2058 return SkCreateFontMemResourceTypefaceFromLOGFONT(lf, fontReference);
2061 SkStream* LogFontTypeface::onOpenStream(int* ttcIndex) const {
2064 const DWORD kTTCTag =
2065 SkEndian_SwapBE32(SkSetFourByteTag('t', 't', 'c', 'f'));
2066 LOGFONT lf = fLogFont;
2068 HDC hdc = ::CreateCompatibleDC(NULL);
2069 HFONT font = CreateFontIndirect(&lf);
2070 HFONT savefont = (HFONT)SelectObject(hdc, font);
2072 SkMemoryStream* stream = NULL;
2073 DWORD tables[2] = {kTTCTag, 0};
2074 for (int i = 0; i < SK_ARRAY_COUNT(tables); i++) {
2075 DWORD bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0);
2076 if (bufferSize == GDI_ERROR) {
2077 call_ensure_accessible(lf);
2078 bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0);
2080 if (bufferSize != GDI_ERROR) {
2081 stream = new SkMemoryStream(bufferSize);
2082 if (GetFontData(hdc, tables[i], 0, (void*)stream->getMemoryBase(), bufferSize)) {
2091 SelectObject(hdc, savefont);
2098 static void bmpCharsToGlyphs(HDC hdc, const WCHAR* bmpChars, int count, uint16_t* glyphs,
2101 DWORD result = GetGlyphIndicesW(hdc, bmpChars, count, glyphs, GGI_MARK_NONEXISTING_GLYPHS);
2102 if (GDI_ERROR == result) {
2103 for (int i = 0; i < count; ++i) {
2110 for (int i = 0; i < count; ++i) {
2111 if (0xFFFF == glyphs[i] || 0x1F == glyphs[i]) {
2116 for (int i = 0; i < count; ++i) {
2117 if (0xFFFF == glyphs[i]){
2124 static uint16_t nonBmpCharToGlyph(HDC hdc, SCRIPT_CACHE* scriptCache, const WCHAR utf16[2]) {
2126 // Use uniscribe to detemine glyph index for non-BMP characters.
2127 static const int numWCHAR = 2;
2128 static const int maxItems = 2;
2129 // MSDN states that this can be NULL, but some things don't work then.
2130 SCRIPT_CONTROL scriptControl = { 0 };
2131 // Add extra item to SCRIPT_ITEM to work around a bug (now documented).
2132 // https://bugzilla.mozilla.org/show_bug.cgi?id=366643
2133 SCRIPT_ITEM si[maxItems + 1];
2135 HRZM(ScriptItemize(utf16, numWCHAR, maxItems, &scriptControl, NULL, si, &numItems),
2136 "Could not itemize character.");
2138 // Sometimes ScriptShape cannot find a glyph for a non-BMP and returns 2 space glyphs.
2139 static const int maxGlyphs = 2;
2140 SCRIPT_VISATTR vsa[maxGlyphs];
2141 WORD outGlyphs[maxGlyphs];
2142 WORD logClust[numWCHAR];
2144 HRZM(ScriptShape(hdc, scriptCache, utf16, numWCHAR, maxGlyphs, &si[0].a,
2145 outGlyphs, logClust, vsa, &numGlyphs),
2146 "Could not shape character.");
2147 if (1 == numGlyphs) {
2148 index = outGlyphs[0];
2155 SkAutoHDC(const LOGFONT& lf)
2156 : fHdc(::CreateCompatibleDC(NULL))
2157 , fFont(::CreateFontIndirect(&lf))
2158 , fSavefont((HFONT)SelectObject(fHdc, fFont))
2161 SelectObject(fHdc, fSavefont);
2162 DeleteObject(fFont);
2165 operator HDC() { return fHdc; }
2171 #define SkAutoHDC(...) SK_REQUIRE_LOCAL_VAR(SkAutoHDC)
2173 int LogFontTypeface::onCharsToGlyphs(const void* chars, Encoding encoding,
2174 uint16_t userGlyphs[], int glyphCount) const
2176 SkAutoHDC hdc(fLogFont);
2179 if (0 == GetTextMetrics(hdc, &tm)) {
2180 call_ensure_accessible(fLogFont);
2181 if (0 == GetTextMetrics(hdc, &tm)) {
2182 tm.tmPitchAndFamily = TMPF_TRUETYPE;
2185 bool Ox1FHack = !(tm.tmPitchAndFamily & TMPF_VECTOR) /*&& winVer < Vista */;
2187 SkAutoSTMalloc<256, uint16_t> scratchGlyphs;
2189 if (userGlyphs != NULL) {
2190 glyphs = userGlyphs;
2192 glyphs = scratchGlyphs.reset(glyphCount);
2195 SCRIPT_CACHE sc = 0;
2197 case SkTypeface::kUTF8_Encoding: {
2198 static const int scratchCount = 256;
2199 WCHAR scratch[scratchCount];
2201 const char* currentUtf8 = reinterpret_cast<const char*>(chars);
2202 SkUnichar currentChar;
2204 currentChar = SkUTF8_NextUnichar(¤tUtf8);
2206 while (glyphIndex < glyphCount) {
2207 // Try a run of bmp.
2208 int glyphsLeft = SkTMin(glyphCount - glyphIndex, scratchCount);
2210 while (runLength < glyphsLeft && currentChar <= 0xFFFF) {
2211 scratch[runLength] = static_cast<WCHAR>(currentChar);
2213 if (runLength < glyphsLeft) {
2214 currentChar = SkUTF8_NextUnichar(¤tUtf8);
2218 bmpCharsToGlyphs(hdc, scratch, runLength, &glyphs[glyphIndex], Ox1FHack);
2219 glyphIndex += runLength;
2222 // Try a run of non-bmp.
2223 while (glyphIndex < glyphCount && currentChar > 0xFFFF) {
2224 SkUTF16_FromUnichar(currentChar, reinterpret_cast<uint16_t*>(scratch));
2225 glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, scratch);
2227 if (glyphIndex < glyphCount) {
2228 currentChar = SkUTF8_NextUnichar(¤tUtf8);
2234 case SkTypeface::kUTF16_Encoding: {
2236 const WCHAR* currentUtf16 = reinterpret_cast<const WCHAR*>(chars);
2237 while (glyphIndex < glyphCount) {
2238 // Try a run of bmp.
2239 int glyphsLeft = glyphCount - glyphIndex;
2241 while (runLength < glyphsLeft && !SkUTF16_IsHighSurrogate(currentUtf16[runLength])) {
2245 bmpCharsToGlyphs(hdc, currentUtf16, runLength, &glyphs[glyphIndex], Ox1FHack);
2246 glyphIndex += runLength;
2247 currentUtf16 += runLength;
2250 // Try a run of non-bmp.
2251 while (glyphIndex < glyphCount && SkUTF16_IsHighSurrogate(*currentUtf16)) {
2252 glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, currentUtf16);
2259 case SkTypeface::kUTF32_Encoding: {
2260 static const int scratchCount = 256;
2261 WCHAR scratch[scratchCount];
2263 const uint32_t* utf32 = reinterpret_cast<const uint32_t*>(chars);
2264 while (glyphIndex < glyphCount) {
2265 // Try a run of bmp.
2266 int glyphsLeft = SkTMin(glyphCount - glyphIndex, scratchCount);
2268 while (runLength < glyphsLeft && utf32[glyphIndex + runLength] <= 0xFFFF) {
2269 scratch[runLength] = static_cast<WCHAR>(utf32[glyphIndex + runLength]);
2273 bmpCharsToGlyphs(hdc, scratch, runLength, &glyphs[glyphIndex], Ox1FHack);
2274 glyphIndex += runLength;
2277 // Try a run of non-bmp.
2278 while (glyphIndex < glyphCount && utf32[glyphIndex] > 0xFFFF) {
2279 SkUTF16_FromUnichar(utf32[glyphIndex], reinterpret_cast<uint16_t*>(scratch));
2280 glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, scratch);
2291 ::ScriptFreeCache(&sc);
2294 for (int i = 0; i < glyphCount; ++i) {
2295 if (0 == glyphs[i]) {
2302 int LogFontTypeface::onCountGlyphs() const {
2303 HDC hdc = ::CreateCompatibleDC(NULL);
2304 HFONT font = CreateFontIndirect(&fLogFont);
2305 HFONT savefont = (HFONT)SelectObject(hdc, font);
2307 unsigned int glyphCount = calculateGlyphCount(hdc, fLogFont);
2309 SelectObject(hdc, savefont);
2316 int LogFontTypeface::onGetUPEM() const {
2317 HDC hdc = ::CreateCompatibleDC(NULL);
2318 HFONT font = CreateFontIndirect(&fLogFont);
2319 HFONT savefont = (HFONT)SelectObject(hdc, font);
2321 unsigned int upem = calculateUPEM(hdc, fLogFont);
2323 SelectObject(hdc, savefont);
2330 SkTypeface::LocalizedStrings* LogFontTypeface::onCreateFamilyNameIterator() const {
2331 SkTypeface::LocalizedStrings* nameIter =
2332 SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(*this);
2333 if (NULL == nameIter) {
2334 SkString familyName;
2335 this->getFamilyName(&familyName);
2336 SkString language("und"); //undetermined
2337 nameIter = new SkOTUtils::LocalizedStrings_SingleName(familyName, language);
2342 int LogFontTypeface::onGetTableTags(SkFontTableTag tags[]) const {
2343 SkSFNTHeader header;
2344 if (sizeof(header) != this->onGetTableData(0, 0, sizeof(header), &header)) {
2348 int numTables = SkEndian_SwapBE16(header.numTables);
2351 size_t size = numTables * sizeof(SkSFNTHeader::TableDirectoryEntry);
2352 SkAutoSTMalloc<0x20, SkSFNTHeader::TableDirectoryEntry> dir(numTables);
2353 if (size != this->onGetTableData(0, sizeof(header), size, dir.get())) {
2357 for (int i = 0; i < numTables; ++i) {
2358 tags[i] = SkEndian_SwapBE32(dir[i].tag);
2364 size_t LogFontTypeface::onGetTableData(SkFontTableTag tag, size_t offset,
2365 size_t length, void* data) const
2367 LOGFONT lf = fLogFont;
2369 HDC hdc = ::CreateCompatibleDC(NULL);
2370 HFONT font = CreateFontIndirect(&lf);
2371 HFONT savefont = (HFONT)SelectObject(hdc, font);
2373 tag = SkEndian_SwapBE32(tag);
2377 DWORD bufferSize = GetFontData(hdc, tag, (DWORD) offset, data, (DWORD) length);
2378 if (bufferSize == GDI_ERROR) {
2379 call_ensure_accessible(lf);
2380 bufferSize = GetFontData(hdc, tag, (DWORD) offset, data, (DWORD) length);
2383 SelectObject(hdc, savefont);
2387 return bufferSize == GDI_ERROR ? 0 : bufferSize;
2390 SkScalerContext* LogFontTypeface::onCreateScalerContext(const SkDescriptor* desc) const {
2391 SkScalerContext_GDI* ctx = SkNEW_ARGS(SkScalerContext_GDI,
2392 (const_cast<LogFontTypeface*>(this), desc));
2393 if (!ctx->isValid()) {
2400 void LogFontTypeface::onFilterRec(SkScalerContextRec* rec) const {
2401 if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag ||
2402 rec->fFlags & SkScalerContext::kLCD_Vertical_Flag)
2404 rec->fMaskFormat = SkMask::kA8_Format;
2405 rec->fFlags |= SkScalerContext::kGenA8FromLCD_Flag;
2408 unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag |
2409 SkScalerContext::kForceAutohinting_Flag |
2410 SkScalerContext::kEmbeddedBitmapText_Flag |
2411 SkScalerContext::kEmbolden_Flag |
2412 SkScalerContext::kLCD_BGROrder_Flag |
2413 SkScalerContext::kLCD_Vertical_Flag;
2414 rec->fFlags &= ~flagsWeDontSupport;
2416 SkPaint::Hinting h = rec->getHinting();
2418 case SkPaint::kNo_Hinting:
2420 case SkPaint::kSlight_Hinting:
2421 // Only do slight hinting when axis aligned.
2422 // TODO: re-enable slight hinting when FontHostTest can pass.
2423 //if (!isAxisAligned(*rec)) {
2424 h = SkPaint::kNo_Hinting;
2427 case SkPaint::kNormal_Hinting:
2428 case SkPaint::kFull_Hinting:
2429 // TODO: need to be able to distinguish subpixel positioned glyphs
2430 // and linear metrics.
2431 //rec->fFlags &= ~SkScalerContext::kSubpixelPositioning_Flag;
2432 h = SkPaint::kNormal_Hinting;
2435 SkDEBUGFAIL("unknown hinting");
2437 //TODO: if this is a bitmap font, squash hinting and subpixel.
2440 // turn this off since GDI might turn A8 into BW! Need a bigger fix.
2442 // Disable LCD when rotated, since GDI's output is ugly
2443 if (isLCD(*rec) && !isAxisAligned(*rec)) {
2444 rec->fMaskFormat = SkMask::kA8_Format;
2448 if (!fCanBeLCD && isLCD(*rec)) {
2449 rec->fMaskFormat = SkMask::kA8_Format;
2450 rec->fFlags &= ~SkScalerContext::kGenA8FromLCD_Flag;
2454 ///////////////////////////////////////////////////////////////////////////////
2456 #include "SkFontMgr.h"
2457 #include "SkDataTable.h"
2459 static bool valid_logfont_for_enum(const LOGFONT& lf) {
2460 // TODO: Vector FON is unsupported and should not be listed.
2462 // Ignore implicit vertical variants.
2463 lf.lfFaceName[0] && lf.lfFaceName[0] != '@'
2465 // DEFAULT_CHARSET is used to get all fonts, but also implies all
2466 // character sets. Filter assuming all fonts support ANSI_CHARSET.
2467 && ANSI_CHARSET == lf.lfCharSet
2471 /** An EnumFontFamExProc implementation which interprets builderParam as
2472 * an SkTDArray<ENUMLOGFONTEX>* and appends logfonts which
2473 * pass the valid_logfont_for_enum predicate.
2475 static int CALLBACK enum_family_proc(const LOGFONT* lf, const TEXTMETRIC*,
2476 DWORD fontType, LPARAM builderParam) {
2477 if (valid_logfont_for_enum(*lf)) {
2478 SkTDArray<ENUMLOGFONTEX>* array = (SkTDArray<ENUMLOGFONTEX>*)builderParam;
2479 *array->append() = *(ENUMLOGFONTEX*)lf;
2481 return 1; // non-zero means continue
2484 static SkFontStyle compute_fontstyle(const LOGFONT& lf) {
2485 return SkFontStyle(lf.lfWeight, SkFontStyle::kNormal_Width,
2486 lf.lfItalic ? SkFontStyle::kItalic_Slant
2487 : SkFontStyle::kUpright_Slant);
2490 class SkFontStyleSetGDI : public SkFontStyleSet {
2492 SkFontStyleSetGDI(const TCHAR familyName[]) {
2494 sk_bzero(&lf, sizeof(lf));
2495 lf.lfCharSet = DEFAULT_CHARSET;
2496 _tcscpy_s(lf.lfFaceName, familyName);
2498 HDC hdc = ::CreateCompatibleDC(NULL);
2499 ::EnumFontFamiliesEx(hdc, &lf, enum_family_proc, (LPARAM)&fArray, 0);
2503 virtual int count() SK_OVERRIDE {
2504 return fArray.count();
2507 virtual void getStyle(int index, SkFontStyle* fs, SkString* styleName) SK_OVERRIDE {
2509 *fs = compute_fontstyle(fArray[index].elfLogFont);
2512 const ENUMLOGFONTEX& ref = fArray[index];
2513 // For some reason, ENUMLOGFONTEX and LOGFONT disagree on their type in the
2514 // non-unicode version.
2515 // ENUMLOGFONTEX uses BYTE
2516 // LOGFONT uses CHAR
2517 // Here we assert they that the style name is logically the same (size) as
2518 // a TCHAR, so we can use the same converter function.
2519 SkASSERT(sizeof(TCHAR) == sizeof(ref.elfStyle[0]));
2520 tchar_to_skstring((const TCHAR*)ref.elfStyle, styleName);
2524 virtual SkTypeface* createTypeface(int index) SK_OVERRIDE {
2525 return SkCreateTypefaceFromLOGFONT(fArray[index].elfLogFont);
2528 virtual SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE {
2530 return SkCreateTypefaceFromLOGFONT(fArray[0].elfLogFont);
2534 SkTDArray<ENUMLOGFONTEX> fArray;
2537 class SkFontMgrGDI : public SkFontMgr {
2541 sk_bzero(&lf, sizeof(lf));
2542 lf.lfCharSet = DEFAULT_CHARSET;
2544 HDC hdc = ::CreateCompatibleDC(NULL);
2545 ::EnumFontFamiliesEx(hdc, &lf, enum_family_proc, (LPARAM)&fLogFontArray, 0);
2550 virtual int onCountFamilies() const SK_OVERRIDE {
2551 return fLogFontArray.count();
2554 virtual void onGetFamilyName(int index, SkString* familyName) const SK_OVERRIDE {
2555 SkASSERT((unsigned)index < (unsigned)fLogFontArray.count());
2556 tchar_to_skstring(fLogFontArray[index].elfLogFont.lfFaceName, familyName);
2559 virtual SkFontStyleSet* onCreateStyleSet(int index) const SK_OVERRIDE {
2560 SkASSERT((unsigned)index < (unsigned)fLogFontArray.count());
2561 return SkNEW_ARGS(SkFontStyleSetGDI, (fLogFontArray[index].elfLogFont.lfFaceName));
2564 virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const SK_OVERRIDE {
2565 if (NULL == familyName) {
2566 familyName = ""; // do we need this check???
2569 logfont_for_name(familyName, &lf);
2570 return SkNEW_ARGS(SkFontStyleSetGDI, (lf.lfFaceName));
2573 virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
2574 const SkFontStyle& fontstyle) const SK_OVERRIDE {
2575 // could be in base impl
2576 SkAutoTUnref<SkFontStyleSet> sset(this->matchFamily(familyName));
2577 return sset->matchStyle(fontstyle);
2580 virtual SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember,
2581 const SkFontStyle& fontstyle) const SK_OVERRIDE {
2582 // could be in base impl
2583 SkString familyName;
2584 ((LogFontTypeface*)familyMember)->getFamilyName(&familyName);
2585 return this->matchFamilyStyle(familyName.c_str(), fontstyle);
2588 virtual SkTypeface* onCreateFromStream(SkStream* stream, int ttcIndex) const SK_OVERRIDE {
2589 return create_from_stream(stream);
2592 virtual SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const SK_OVERRIDE {
2593 // could be in base impl
2594 SkAutoTUnref<SkStream> stream(SkNEW_ARGS(SkMemoryStream, (data)));
2595 return this->createFromStream(stream);
2598 virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const SK_OVERRIDE {
2599 // could be in base impl
2600 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path));
2601 return this->createFromStream(stream);
2604 virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
2605 unsigned styleBits) const SK_OVERRIDE {
2607 if (NULL == familyName) {
2608 lf = get_default_font();
2610 logfont_for_name(familyName, &lf);
2612 setStyle(&lf, (SkTypeface::Style)styleBits);
2613 return SkCreateTypefaceFromLOGFONT(lf);
2617 SkTDArray<ENUMLOGFONTEX> fLogFontArray;
2620 ///////////////////////////////////////////////////////////////////////////////
2622 SkFontMgr* SkFontMgr_New_GDI() {
2623 return SkNEW(SkFontMgrGDI);