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 "SkOTTable_maxp.h"
20 #include "SkOTTable_name.h"
21 #include "SkOTUtils.h"
23 #include "SkSFNTHeader.h"
26 #include "SkTemplates.h"
28 #include "SkTypeface_win.h"
29 #include "SkTypefaceCache.h"
37 static void (*gEnsureLOGFONTAccessibleProc)(const LOGFONT&);
39 void SkTypeface_SetEnsureLOGFONTAccessibleProc(void (*proc)(const LOGFONT&)) {
40 gEnsureLOGFONTAccessibleProc = proc;
43 static void call_ensure_accessible(const LOGFONT& lf) {
44 if (gEnsureLOGFONTAccessibleProc) {
45 gEnsureLOGFONTAccessibleProc(lf);
49 ///////////////////////////////////////////////////////////////////////////////
51 // always packed xxRRGGBB
52 typedef uint32_t SkGdiRGB;
54 // define this in your Makefile or .gyp to enforce AA requests
55 // which GDI ignores at small sizes. This flag guarantees AA
56 // for rotated text, regardless of GDI's notions.
57 //#define SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
59 static bool isLCD(const SkScalerContext::Rec& rec) {
60 return SkMask::kLCD16_Format == rec.fMaskFormat ||
61 SkMask::kLCD32_Format == rec.fMaskFormat;
64 static bool bothZero(SkScalar a, SkScalar b) {
65 return 0 == a && 0 == b;
68 // returns false if there is any non-90-rotation or skew
69 static bool isAxisAligned(const SkScalerContext::Rec& rec) {
70 return 0 == rec.fPreSkewX &&
71 (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
72 bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
75 static bool needToRenderWithSkia(const SkScalerContext::Rec& rec) {
76 #ifdef SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
77 // What we really want to catch is when GDI will ignore the AA request and give
78 // us BW instead. Smallish rotated text is one heuristic, so this code is just
79 // an approximation. We shouldn't need to do this for larger sizes, but at those
80 // sizes, the quality difference gets less and less between our general
81 // scanconverter and GDI's.
82 if (SkMask::kA8_Format == rec.fMaskFormat && !isAxisAligned(rec)) {
86 return rec.getHinting() == SkPaint::kNo_Hinting || rec.getHinting() == SkPaint::kSlight_Hinting;
89 using namespace skia_advanced_typeface_metrics_utils;
91 static void tchar_to_skstring(const TCHAR t[], SkString* s) {
93 size_t sSize = WideCharToMultiByte(CP_UTF8, 0, t, -1, NULL, 0, NULL, NULL);
95 WideCharToMultiByte(CP_UTF8, 0, t, -1, s->writable_str(), sSize, NULL, NULL);
101 static void dcfontname_to_skstring(HDC deviceContext, const LOGFONT& lf, SkString* familyName) {
102 int fontNameLen; //length of fontName in TCHARS.
103 if (0 == (fontNameLen = GetTextFace(deviceContext, 0, NULL))) {
104 call_ensure_accessible(lf);
105 if (0 == (fontNameLen = GetTextFace(deviceContext, 0, NULL))) {
110 SkAutoSTArray<LF_FULLFACESIZE, TCHAR> fontName(fontNameLen+1);
111 if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) {
112 call_ensure_accessible(lf);
113 if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) {
118 tchar_to_skstring(fontName.get(), familyName);
121 static void make_canonical(LOGFONT* lf) {
123 lf->lfQuality = CLEARTYPE_QUALITY;//PROOF_QUALITY;
124 lf->lfCharSet = DEFAULT_CHARSET;
125 // lf->lfClipPrecision = 64;
128 static SkTypeface::Style get_style(const LOGFONT& lf) {
130 if (lf.lfWeight >= FW_BOLD) {
131 style |= SkTypeface::kBold;
134 style |= SkTypeface::kItalic;
136 return static_cast<SkTypeface::Style>(style);
139 static void setStyle(LOGFONT* lf, SkTypeface::Style style) {
140 lf->lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL ;
141 lf->lfItalic = ((style & SkTypeface::kItalic) != 0);
144 static inline FIXED SkFixedToFIXED(SkFixed x) {
145 return *(FIXED*)(&x);
147 static inline SkFixed SkFIXEDToFixed(FIXED x) {
148 return *(SkFixed*)(&x);
151 static inline FIXED SkScalarToFIXED(SkScalar x) {
152 return SkFixedToFIXED(SkScalarToFixed(x));
155 static inline SkScalar SkFIXEDToScalar(FIXED x) {
156 return SkFixedToScalar(SkFIXEDToFixed(x));
159 static unsigned calculateGlyphCount(HDC hdc, const LOGFONT& lf) {
160 TEXTMETRIC textMetric;
161 if (0 == GetTextMetrics(hdc, &textMetric)) {
162 textMetric.tmPitchAndFamily = TMPF_VECTOR;
163 call_ensure_accessible(lf);
164 GetTextMetrics(hdc, &textMetric);
167 if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) {
168 return textMetric.tmLastChar;
171 // The 'maxp' table stores the number of glyphs at offset 4, in 2 bytes.
173 if (GDI_ERROR != GetFontData(hdc, SkOTTableMaximumProfile::TAG, 4, &glyphs, sizeof(glyphs))) {
174 return SkEndian_SwapBE16(glyphs);
177 // Binary search for glyph count.
178 static const MAT2 mat2 = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
179 int32_t max = SK_MaxU16 + 1;
183 int32_t mid = min + ((max - min) / 2);
184 if (GetGlyphOutlineW(hdc, mid, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0,
185 NULL, &mat2) == GDI_ERROR) {
191 SkASSERT(min == max);
195 static unsigned calculateUPEM(HDC hdc, const LOGFONT& lf) {
196 TEXTMETRIC textMetric;
197 if (0 == GetTextMetrics(hdc, &textMetric)) {
198 textMetric.tmPitchAndFamily = TMPF_VECTOR;
199 call_ensure_accessible(lf);
200 GetTextMetrics(hdc, &textMetric);
203 if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) {
204 return textMetric.tmMaxCharWidth;
207 OUTLINETEXTMETRIC otm;
208 unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
210 call_ensure_accessible(lf);
211 otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
214 return (0 == otmRet) ? 0 : otm.otmEMSquare;
217 class LogFontTypeface : public SkTypeface {
219 LogFontTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf, bool serializeAsStream = false) :
220 SkTypeface(style, fontID, false), fLogFont(lf), fSerializeAsStream(serializeAsStream) {
222 // If the font has cubic outlines, it will not be rendered with ClearType.
223 HFONT font = CreateFontIndirect(&lf);
225 HDC deviceContext = ::CreateCompatibleDC(NULL);
226 HFONT savefont = (HFONT)SelectObject(deviceContext, font);
228 TEXTMETRIC textMetric;
229 if (0 == GetTextMetrics(deviceContext, &textMetric)) {
230 call_ensure_accessible(lf);
231 if (0 == GetTextMetrics(deviceContext, &textMetric)) {
232 textMetric.tmPitchAndFamily = TMPF_TRUETYPE;
236 ::SelectObject(deviceContext, savefont);
237 ::DeleteDC(deviceContext);
240 ::DeleteObject(font);
243 // The fixed pitch bit is set if the font is *not* fixed pitch.
244 this->setIsFixedPitch((textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0);
246 // Used a logfont on a memory context, should never get a device font.
247 // Therefore all TMPF_DEVICE will be PostScript (cubic) fonts.
248 fCanBeLCD = !((textMetric.tmPitchAndFamily & TMPF_VECTOR) &&
249 (textMetric.tmPitchAndFamily & TMPF_DEVICE));
253 bool fSerializeAsStream;
256 static LogFontTypeface* Create(const LOGFONT& lf) {
257 SkTypeface::Style style = get_style(lf);
258 SkFontID fontID = SkTypefaceCache::NewFontID();
259 return new LogFontTypeface(style, fontID, lf);
262 static void EnsureAccessible(const SkTypeface* face) {
263 call_ensure_accessible(static_cast<const LogFontTypeface*>(face)->fLogFont);
267 virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE;
268 virtual SkScalerContext* onCreateScalerContext(const SkDescriptor*) const SK_OVERRIDE;
269 virtual void onFilterRec(SkScalerContextRec*) const SK_OVERRIDE;
270 virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics(
271 SkAdvancedTypefaceMetrics::PerGlyphInfo,
272 const uint32_t*, uint32_t) const SK_OVERRIDE;
273 virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE;
274 virtual int onCharsToGlyphs(const void* chars, Encoding encoding,
275 uint16_t glyphs[], int glyphCount) const SK_OVERRIDE;
276 virtual int onCountGlyphs() const SK_OVERRIDE;
277 virtual int onGetUPEM() const SK_OVERRIDE;
278 virtual SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const SK_OVERRIDE;
279 virtual int onGetTableTags(SkFontTableTag tags[]) const SK_OVERRIDE;
280 virtual size_t onGetTableData(SkFontTableTag, size_t offset,
281 size_t length, void* data) const SK_OVERRIDE;
284 class FontMemResourceTypeface : public LogFontTypeface {
287 * Takes ownership of fontMemResource.
289 FontMemResourceTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf, HANDLE fontMemResource) :
290 LogFontTypeface(style, fontID, lf, true), fFontMemResource(fontMemResource) {
293 HANDLE fFontMemResource;
296 * The created FontMemResourceTypeface takes ownership of fontMemResource.
298 static FontMemResourceTypeface* Create(const LOGFONT& lf, HANDLE fontMemResource) {
299 SkTypeface::Style style = get_style(lf);
300 SkFontID fontID = SkTypefaceCache::NewFontID();
301 return new FontMemResourceTypeface(style, fontID, lf, fontMemResource);
305 virtual void weak_dispose() const SK_OVERRIDE {
306 RemoveFontMemResourceEx(fFontMemResource);
307 //SkTypefaceCache::Remove(this);
308 INHERITED::weak_dispose();
312 typedef LogFontTypeface INHERITED;
315 static const LOGFONT& get_default_font() {
316 static LOGFONT gDefaultFont;
320 static bool FindByLogFont(SkTypeface* face, SkTypeface::Style requestedStyle, void* ctx) {
321 LogFontTypeface* lface = static_cast<LogFontTypeface*>(face);
322 const LOGFONT* lf = reinterpret_cast<const LOGFONT*>(ctx);
325 get_style(lface->fLogFont) == requestedStyle &&
326 !memcmp(&lface->fLogFont, lf, sizeof(LOGFONT));
330 * This guy is public. It first searches the cache, and if a match is not found,
331 * it creates a new face.
333 SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT& origLF) {
336 SkTypeface* face = SkTypefaceCache::FindByProcAndRef(FindByLogFont, &lf);
338 face = LogFontTypeface::Create(lf);
339 SkTypefaceCache::Add(face, get_style(lf));
345 * The created SkTypeface takes ownership of fontMemResource.
347 SkTypeface* SkCreateFontMemResourceTypefaceFromLOGFONT(const LOGFONT& origLF, HANDLE fontMemResource) {
350 FontMemResourceTypeface* face = FontMemResourceTypeface::Create(lf, fontMemResource);
351 SkTypefaceCache::Add(face, get_style(lf), false);
358 void SkLOGFONTFromTypeface(const SkTypeface* face, LOGFONT* lf) {
360 *lf = get_default_font();
362 *lf = static_cast<const LogFontTypeface*>(face)->fLogFont;
366 // Construct Glyph to Unicode table.
367 // Unicode code points that require conjugate pairs in utf16 are not
369 // TODO(arthurhsu): Add support for conjugate pairs. It looks like that may
370 // require parsing the TTF cmap table (platform 4, encoding 12) directly instead
371 // of calling GetFontUnicodeRange().
372 static void populate_glyph_to_unicode(HDC fontHdc, const unsigned glyphCount,
373 SkTDArray<SkUnichar>* glyphToUnicode) {
374 DWORD glyphSetBufferSize = GetFontUnicodeRanges(fontHdc, NULL);
375 if (!glyphSetBufferSize) {
379 SkAutoTDeleteArray<BYTE> glyphSetBuffer(new BYTE[glyphSetBufferSize]);
381 reinterpret_cast<LPGLYPHSET>(glyphSetBuffer.get());
382 if (GetFontUnicodeRanges(fontHdc, glyphSet) != glyphSetBufferSize) {
386 glyphToUnicode->setCount(glyphCount);
387 memset(glyphToUnicode->begin(), 0, glyphCount * sizeof(SkUnichar));
388 for (DWORD i = 0; i < glyphSet->cRanges; ++i) {
389 // There is no guarantee that within a Unicode range, the corresponding
390 // glyph id in a font file are continuous. So, even if we have ranges,
391 // we can't just use the first and last entry of the range to compute
392 // result. We need to enumerate them one by one.
393 int count = glyphSet->ranges[i].cGlyphs;
394 SkAutoTArray<WCHAR> chars(count + 1);
395 chars[count] = 0; // termintate string
396 SkAutoTArray<WORD> glyph(count);
397 for (USHORT j = 0; j < count; ++j) {
398 chars[j] = glyphSet->ranges[i].wcLow + j;
400 GetGlyphIndicesW(fontHdc, chars.get(), count, glyph.get(),
401 GGI_MARK_NONEXISTING_GLYPHS);
402 // If the glyph ID is valid, and the glyph is not mapped, then we will
403 // fill in the char id into the vector. If the glyph is mapped already,
405 // TODO(arthurhsu): better improve this. e.g. Get all used char ids from
406 // font cache, then generate this mapping table from there. It's
407 // unlikely to have collisions since glyph reuse happens mostly for
408 // different Unicode pages.
409 for (USHORT j = 0; j < count; ++j) {
410 if (glyph[j] != 0xffff && glyph[j] < glyphCount &&
411 (*glyphToUnicode)[glyph[j]] == 0) {
412 (*glyphToUnicode)[glyph[j]] = chars[j];
418 //////////////////////////////////////////////////////////////////////////////////////
420 static int alignTo32(int n) {
421 return (n + 31) & ~31;
424 struct MyBitmapInfo : public BITMAPINFO {
425 RGBQUAD fMoreSpaceForColors[1];
435 fWidth = fHeight = 0;
448 void init(HFONT font, const XFORM& xform) {
453 const void* draw(const SkGlyph&, bool isBW, size_t* srcRBPtr);
460 void* fBits; // points into fBM
466 const void* HDCOffscreen::draw(const SkGlyph& glyph, bool isBW,
468 // Can we share the scalercontext's fDDC, so we don't need to create
469 // a separate fDC here?
471 fDC = CreateCompatibleDC(0);
475 SetGraphicsMode(fDC, GM_ADVANCED);
476 SetBkMode(fDC, TRANSPARENT);
477 SetTextAlign(fDC, TA_LEFT | TA_BASELINE);
478 SelectObject(fDC, fFont);
480 COLORREF color = 0x00FFFFFF;
481 SkDEBUGCODE(COLORREF prev =) SetTextColor(fDC, color);
482 SkASSERT(prev != CLR_INVALID);
485 if (fBM && (fIsBW != isBW || fWidth < glyph.fWidth || fHeight < glyph.fHeight)) {
491 fWidth = SkMax32(fWidth, glyph.fWidth);
492 fHeight = SkMax32(fHeight, glyph.fHeight);
494 int biWidth = isBW ? alignTo32(fWidth) : fWidth;
498 sk_bzero(&info, sizeof(info));
500 RGBQUAD blackQuad = { 0, 0, 0, 0 };
501 RGBQUAD whiteQuad = { 0xFF, 0xFF, 0xFF, 0 };
502 info.bmiColors[0] = blackQuad;
503 info.bmiColors[1] = whiteQuad;
505 info.bmiHeader.biSize = sizeof(info.bmiHeader);
506 info.bmiHeader.biWidth = biWidth;
507 info.bmiHeader.biHeight = fHeight;
508 info.bmiHeader.biPlanes = 1;
509 info.bmiHeader.biBitCount = isBW ? 1 : 32;
510 info.bmiHeader.biCompression = BI_RGB;
512 info.bmiHeader.biClrUsed = 2;
514 fBM = CreateDIBSection(fDC, &info, DIB_RGB_COLORS, &fBits, 0, 0);
518 SelectObject(fDC, fBM);
522 size_t srcRB = isBW ? (biWidth >> 3) : (fWidth << 2);
523 size_t size = fHeight * srcRB;
524 memset(fBits, 0, size);
526 XFORM xform = fXform;
527 xform.eDx = (float)-glyph.fLeft;
528 xform.eDy = (float)-glyph.fTop;
529 SetWorldTransform(fDC, &xform);
531 uint16_t glyphID = glyph.getGlyphID();
532 BOOL ret = ExtTextOutW(fDC, 0, 0, ETO_GLYPH_INDEX, NULL, reinterpret_cast<LPCWSTR>(&glyphID), 1, NULL);
538 // offset to the start of the image
539 return (const char*)fBits + (fHeight - glyph.fHeight) * srcRB;
542 //////////////////////////////////////////////////////////////////////////////
543 #define BUFFERSIZE (1 << 13)
545 class SkScalerContext_GDI : public SkScalerContext {
547 SkScalerContext_GDI(SkTypeface*, const SkDescriptor* desc);
548 virtual ~SkScalerContext_GDI();
550 // Returns true if the constructor was able to complete all of its
551 // initializations (which may include calling GDI).
552 bool isValid() const;
555 virtual unsigned generateGlyphCount() SK_OVERRIDE;
556 virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE;
557 virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE;
558 virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE;
559 virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE;
560 virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE;
561 virtual void generateFontMetrics(SkPaint::FontMetrics* mX,
562 SkPaint::FontMetrics* mY) SK_OVERRIDE;
565 DWORD getGDIGlyphPath(const SkGlyph& glyph, UINT flags,
566 SkAutoSTMalloc<BUFFERSIZE, uint8_t>* glyphbuf);
568 HDCOffscreen fOffscreen;
569 /** fGsA is the non-rotational part of total matrix without the text height scale.
570 * Used to find the magnitude of advances.
573 /** The total matrix without the textSize. */
575 /** Scales font to EM size. */
583 /** The total matrix which also removes EM scale. */
584 SkMatrix fHiResMatrix;
585 /** fG_inv is the inverse of the rotational part of the total matrix.
586 * Used to set the direction of advances.
590 kTrueType_Type, kBitmap_Type, kLine_Type
595 static FIXED float2FIXED(float x) {
596 return SkFixedToFIXED(SkFloatToFixed(x));
599 static BYTE compute_quality(const SkScalerContext::Rec& rec) {
600 switch (rec.fMaskFormat) {
601 case SkMask::kBW_Format:
602 return NONANTIALIASED_QUALITY;
603 case SkMask::kLCD16_Format:
604 case SkMask::kLCD32_Format:
605 return CLEARTYPE_QUALITY;
607 if (rec.fFlags & SkScalerContext::kGenA8FromLCD_Flag) {
608 return CLEARTYPE_QUALITY;
610 return ANTIALIASED_QUALITY;
615 SkScalerContext_GDI::SkScalerContext_GDI(SkTypeface* rawTypeface,
616 const SkDescriptor* desc)
617 : SkScalerContext(rawTypeface, desc)
624 LogFontTypeface* typeface = reinterpret_cast<LogFontTypeface*>(rawTypeface);
626 fDDC = ::CreateCompatibleDC(NULL);
630 SetGraphicsMode(fDDC, GM_ADVANCED);
631 SetBkMode(fDDC, TRANSPARENT);
633 SkPoint h = SkPoint::Make(SK_Scalar1, 0);
634 // A is the total matrix.
636 fRec.getSingleMatrix(&A);
639 // Find the Given's matrix [[c, -s],[s, c]] which rotates the baseline vector h
640 // (where the baseline is mapped to) to the positive horizontal axis.
641 const SkScalar& a = h.fX;
642 const SkScalar& b = h.fY;
645 c = SkDoubleToScalar(_copysign(SK_Scalar1, a));
649 s = SkDoubleToScalar(-_copysign(SK_Scalar1, b));
650 } else if (SkScalarAbs(b) > SkScalarAbs(a)) {
652 SkScalar u = SkDoubleToScalar(_copysign(SkScalarSqrt(SK_Scalar1 + t*t), b));
657 SkScalar u = SkDoubleToScalar(_copysign(SkScalarSqrt(SK_Scalar1 + t*t), a));
662 // G is the Given's Matrix for A (rotational matrix such that GA[0][1] == 0).
666 0, 0, SkScalarToPersp(SK_Scalar1));
668 // GA is the matrix A with rotation removed.
672 // realTextSize is the actual device size we want (as opposed to the size the user requested).
673 // gdiTextSide is the size we request from GDI.
674 // If the scale is negative, this means the matrix will do the flip anyway.
675 SkScalar realTextSize = SkScalarAbs(GA.get(SkMatrix::kMScaleY));
676 SkScalar gdiTextSize = SkScalarRoundToScalar(realTextSize);
677 if (gdiTextSize == 0) {
678 gdiTextSize = SK_Scalar1;
681 // When not hinting, remove only the gdiTextSize scale which will be applied by GDI.
682 // When GDI hinting, remove the entire Y scale to prevent 'subpixel' metrics.
683 SkScalar scale = (fRec.getHinting() == SkPaint::kNo_Hinting ||
684 fRec.getHinting() == SkPaint::kSlight_Hinting)
685 ? SkScalarInvert(gdiTextSize)
686 : SkScalarInvert(realTextSize);
688 // sA is the total matrix A without the textSize (so GDI knows the text size separately).
689 // When this matrix is used with GetGlyphOutline, no further processing is needed.
691 sA.preScale(scale, scale); //remove text size
693 // GsA is the non-rotational part of A without the text height scale.
694 // This is what is used to find the magnitude of advances.
696 GsA.preScale(scale, scale); //remove text size, G is rotational so reorders with the scale.
698 fGsA.eM11 = SkScalarToFIXED(GsA.get(SkMatrix::kMScaleX));
699 fGsA.eM12 = SkScalarToFIXED(-GsA.get(SkMatrix::kMSkewY)); // This should be ~0.
700 fGsA.eM21 = SkScalarToFIXED(-GsA.get(SkMatrix::kMSkewX));
701 fGsA.eM22 = SkScalarToFIXED(GsA.get(SkMatrix::kMScaleY));
703 // fG_inv is G inverse, which is fairly simple since G is 2x2 rotational.
704 fG_inv.setAll(G.get(SkMatrix::kMScaleX), -G.get(SkMatrix::kMSkewX), G.get(SkMatrix::kMTransX),
705 -G.get(SkMatrix::kMSkewY), G.get(SkMatrix::kMScaleY), G.get(SkMatrix::kMTransY),
706 G.get(SkMatrix::kMPersp0), G.get(SkMatrix::kMPersp1), G.get(SkMatrix::kMPersp2));
708 LOGFONT lf = typeface->fLogFont;
709 lf.lfHeight = -SkScalarTruncToInt(gdiTextSize);
710 lf.lfQuality = compute_quality(fRec);
711 fFont = CreateFontIndirect(&lf);
716 fSavefont = (HFONT)SelectObject(fDDC, fFont);
718 if (0 == GetTextMetrics(fDDC, &fTM)) {
719 call_ensure_accessible(lf);
720 if (0 == GetTextMetrics(fDDC, &fTM)) {
721 fTM.tmPitchAndFamily = TMPF_TRUETYPE;
726 if (fTM.tmPitchAndFamily & TMPF_VECTOR) {
727 // Used a logfont on a memory context, should never get a device font.
728 // Therefore all TMPF_DEVICE will be PostScript fonts.
730 // If TMPF_VECTOR is set, one of TMPF_TRUETYPE or TMPF_DEVICE means that
731 // we have an outline font. Otherwise we have a vector FON, which is
732 // scalable, but not an outline font.
733 // This was determined by testing with Type1 PFM/PFB and
734 // OpenTypeCFF OTF, as well as looking at Wine bugs and sources.
735 if (fTM.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_DEVICE)) {
736 // Truetype or PostScript.
737 fType = SkScalerContext_GDI::kTrueType_Type;
740 fType = SkScalerContext_GDI::kLine_Type;
743 // fPost2x2 is column-major, left handed (y down).
744 // XFORM 2x2 is row-major, left handed (y down).
745 xform.eM11 = SkScalarToFloat(sA.get(SkMatrix::kMScaleX));
746 xform.eM12 = SkScalarToFloat(sA.get(SkMatrix::kMSkewY));
747 xform.eM21 = SkScalarToFloat(sA.get(SkMatrix::kMSkewX));
748 xform.eM22 = SkScalarToFloat(sA.get(SkMatrix::kMScaleY));
752 // MAT2 is row major, right handed (y up).
753 fMat22.eM11 = float2FIXED(xform.eM11);
754 fMat22.eM12 = float2FIXED(-xform.eM12);
755 fMat22.eM21 = float2FIXED(-xform.eM21);
756 fMat22.eM22 = float2FIXED(xform.eM22);
758 if (needToRenderWithSkia(fRec)) {
759 this->forceGenerateImageFromPath();
762 // Create a hires matrix if we need linear metrics.
763 if (this->isSubpixel()) {
764 OUTLINETEXTMETRIC otm;
765 UINT success = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
767 call_ensure_accessible(lf);
768 success = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
771 SkScalar upem = SkIntToScalar(otm.otmEMSquare);
773 SkScalar gdiTextSizeToEMScale = upem / gdiTextSize;
774 fHighResMat22.eM11 = float2FIXED(gdiTextSizeToEMScale);
775 fHighResMat22.eM12 = float2FIXED(0);
776 fHighResMat22.eM21 = float2FIXED(0);
777 fHighResMat22.eM22 = float2FIXED(gdiTextSizeToEMScale);
779 SkScalar removeEMScale = SkScalarInvert(upem);
781 fHiResMatrix.preScale(removeEMScale, removeEMScale);
787 fType = SkScalerContext_GDI::kBitmap_Type;
796 // fPost2x2 is column-major, left handed (y down).
797 // MAT2 is row major, right handed (y up).
798 fMat22.eM11 = SkScalarToFIXED(fRec.fPost2x2[0][0]);
799 fMat22.eM12 = SkScalarToFIXED(-fRec.fPost2x2[1][0]);
800 fMat22.eM21 = SkScalarToFIXED(-fRec.fPost2x2[0][1]);
801 fMat22.eM22 = SkScalarToFIXED(fRec.fPost2x2[1][1]);
804 fOffscreen.init(fFont, xform);
807 SkScalerContext_GDI::~SkScalerContext_GDI() {
809 ::SelectObject(fDDC, fSavefont);
813 ::DeleteObject(fFont);
816 ::ScriptFreeCache(&fSC);
820 bool SkScalerContext_GDI::isValid() const {
821 return fDDC && fFont;
824 unsigned SkScalerContext_GDI::generateGlyphCount() {
825 if (fGlyphCount < 0) {
826 fGlyphCount = calculateGlyphCount(
827 fDDC, static_cast<const LogFontTypeface*>(this->getTypeface())->fLogFont);
832 uint16_t SkScalerContext_GDI::generateCharToGlyph(SkUnichar utf32) {
835 // TODO(ctguil): Support characters that generate more than one glyph.
836 if (SkUTF16_FromUnichar(utf32, (uint16_t*)utf16) == 1) {
837 // Type1 fonts fail with uniscribe API. Use GetGlyphIndices for plane 0.
839 /** Real documentation for GetGlyphIndiciesW:
841 * When GGI_MARK_NONEXISTING_GLYPHS is not specified and a character does not map to a
842 * glyph, then the 'default character's glyph is returned instead. The 'default character'
843 * is available in fTM.tmDefaultChar. FON fonts have a default character, and there exists
844 * a usDefaultChar in the 'OS/2' table, version 2 and later. If there is no
845 * 'default character' specified by the font, then often the first character found is used.
847 * When GGI_MARK_NONEXISTING_GLYPHS is specified and a character does not map to a glyph,
848 * then the glyph 0xFFFF is used. In Windows XP and earlier, Bitmap/Vector FON usually use
849 * glyph 0x1F instead ('Terminal' appears to be special, returning 0xFFFF).
850 * Type1 PFM/PFB, TT, OT TT, OT CFF all appear to use 0xFFFF, even on XP.
852 DWORD result = GetGlyphIndicesW(fDDC, utf16, 1, &index, GGI_MARK_NONEXISTING_GLYPHS);
853 if (result == GDI_ERROR
856 (fType == SkScalerContext_GDI::kBitmap_Type ||
857 fType == SkScalerContext_GDI::kLine_Type)
858 /*&& winVer < Vista */)
864 // Use uniscribe to detemine glyph index for non-BMP characters.
865 static const int numWCHAR = 2;
866 static const int maxItems = 2;
867 // MSDN states that this can be NULL, but some things don't work then.
868 SCRIPT_CONTROL sc = { 0 };
869 // Add extra item to SCRIPT_ITEM to work around a bug (now documented).
870 // https://bugzilla.mozilla.org/show_bug.cgi?id=366643
871 SCRIPT_ITEM si[maxItems + 1];
873 HRZM(ScriptItemize(utf16, numWCHAR, maxItems, &sc, NULL, si, &numItems),
874 "Could not itemize character.");
876 // Sometimes ScriptShape cannot find a glyph for a non-BMP and returns 2 space glyphs.
877 static const int maxGlyphs = 2;
878 SCRIPT_VISATTR vsa[maxGlyphs];
879 WORD outGlyphs[maxGlyphs];
880 WORD logClust[numWCHAR];
882 HRZM(ScriptShape(fDDC, &fSC, utf16, numWCHAR, maxGlyphs, &si[0].a,
883 outGlyphs, logClust, vsa, &numGlyphs),
884 "Could not shape character.");
885 if (1 == numGlyphs) {
886 index = outGlyphs[0];
892 void SkScalerContext_GDI::generateAdvance(SkGlyph* glyph) {
893 this->generateMetrics(glyph);
896 void SkScalerContext_GDI::generateMetrics(SkGlyph* glyph) {
899 if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) {
901 WORD glyphs = glyph->getGlyphID(0);
902 if (0 == GetTextExtentPointI(fDDC, &glyphs, 1, &size)) {
903 glyph->fWidth = SkToS16(fTM.tmMaxCharWidth);
905 glyph->fWidth = SkToS16(size.cx);
907 glyph->fHeight = SkToS16(size.cy);
909 glyph->fTop = SkToS16(-fTM.tmAscent);
910 // Bitmap FON cannot underhang, but vector FON may.
911 // There appears no means of determining underhang of vector FON.
912 glyph->fLeft = SkToS16(0);
913 glyph->fAdvanceX = SkIntToFixed(glyph->fWidth);
914 glyph->fAdvanceY = 0;
916 // Vector FON will transform nicely, but bitmap FON do not.
917 if (fType == SkScalerContext_GDI::kLine_Type) {
918 SkRect bounds = SkRect::MakeXYWH(glyph->fLeft, glyph->fTop,
919 glyph->fWidth, glyph->fHeight);
921 m.setAll(SkFIXEDToScalar(fMat22.eM11), -SkFIXEDToScalar(fMat22.eM21), 0,
922 -SkFIXEDToScalar(fMat22.eM12), SkFIXEDToScalar(fMat22.eM22), 0,
923 0, 0, SkScalarToPersp(SK_Scalar1));
926 glyph->fLeft = SkScalarTruncToInt(bounds.fLeft);
927 glyph->fTop = SkScalarTruncToInt(bounds.fTop);
928 glyph->fWidth = SkScalarTruncToInt(bounds.width());
929 glyph->fHeight = SkScalarTruncToInt(bounds.height());
932 // Apply matrix to advance.
933 glyph->fAdvanceY = SkFixedMul(-SkFIXEDToFixed(fMat22.eM12), glyph->fAdvanceX);
934 glyph->fAdvanceX = SkFixedMul(SkFIXEDToFixed(fMat22.eM11), glyph->fAdvanceX);
939 UINT glyphId = glyph->getGlyphID(0);
942 sk_bzero(&gm, sizeof(gm));
944 DWORD status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
945 if (GDI_ERROR == status) {
946 LogFontTypeface::EnsureAccessible(this->getTypeface());
947 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
948 if (GDI_ERROR == status) {
949 glyph->zeroMetrics();
955 // The black box is either the embedded bitmap size or the outline extent.
956 // It is 1x1 if nothing is to be drawn, but will also be 1x1 if something very small
957 // is to be drawn, like a '.'. We need to outset '.' but do not wish to outset ' '.
958 if (1 == gm.gmBlackBoxX && 1 == gm.gmBlackBoxY) {
959 // If GetGlyphOutline with GGO_NATIVE returns 0, we know there was no outline.
960 DWORD bufferSize = GetGlyphOutlineW(fDDC, glyphId, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
961 empty = (0 == bufferSize);
964 glyph->fTop = SkToS16(-gm.gmptGlyphOrigin.y);
965 glyph->fLeft = SkToS16(gm.gmptGlyphOrigin.x);
970 // Outset, since the image may bleed out of the black box.
971 // For embedded bitmaps the black box should be exact.
972 // For outlines we need to outset by 1 in all directions for bleed.
973 // For ClearType we need to outset by 2 for bleed.
974 glyph->fWidth = gm.gmBlackBoxX + 4;
975 glyph->fHeight = gm.gmBlackBoxY + 4;
979 glyph->fAdvanceX = SkIntToFixed(gm.gmCellIncX);
980 glyph->fAdvanceY = SkIntToFixed(gm.gmCellIncY);
981 glyph->fRsbDelta = 0;
982 glyph->fLsbDelta = 0;
984 if (this->isSubpixel()) {
985 sk_bzero(&gm, sizeof(gm));
986 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fHighResMat22);
987 if (GDI_ERROR != status) {
989 fHiResMatrix.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance);
990 glyph->fAdvanceX = SkScalarToFixed(advance.fX);
991 glyph->fAdvanceY = SkScalarToFixed(advance.fY);
993 } else if (!isAxisAligned(this->fRec)) {
994 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fGsA);
995 if (GDI_ERROR != status) {
997 fG_inv.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance);
998 glyph->fAdvanceX = SkScalarToFixed(advance.fX);
999 glyph->fAdvanceY = SkScalarToFixed(advance.fY);
1004 static const MAT2 gMat2Identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
1005 void SkScalerContext_GDI::generateFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my) {
1011 sk_bzero(mx, sizeof(*mx));
1014 sk_bzero(my, sizeof(*my));
1019 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
1020 if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) {
1023 mx->fTop = SkIntToScalar(-fTM.tmAscent);
1024 mx->fAscent = SkIntToScalar(-fTM.tmAscent);
1025 mx->fDescent = SkIntToScalar(fTM.tmDescent);
1026 mx->fBottom = SkIntToScalar(fTM.tmDescent);
1027 mx->fLeading = SkIntToScalar(fTM.tmExternalLeading);
1031 my->fTop = SkIntToScalar(-fTM.tmAscent);
1032 my->fAscent = SkIntToScalar(-fTM.tmAscent);
1033 my->fDescent = SkIntToScalar(fTM.tmDescent);
1034 my->fBottom = SkIntToScalar(fTM.tmDescent);
1035 my->fLeading = SkIntToScalar(fTM.tmExternalLeading);
1036 my->fAvgCharWidth = SkIntToScalar(fTM.tmAveCharWidth);
1037 my->fMaxCharWidth = SkIntToScalar(fTM.tmMaxCharWidth);
1039 my->fXMax = my->fMaxCharWidth;
1042 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
1047 OUTLINETEXTMETRIC otm;
1049 uint32_t ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
1051 LogFontTypeface::EnsureAccessible(this->getTypeface());
1052 ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
1059 mx->fTop = SkIntToScalar(-otm.otmrcFontBox.left);
1060 mx->fAscent = SkIntToScalar(-otm.otmAscent);
1061 mx->fDescent = SkIntToScalar(-otm.otmDescent);
1062 mx->fBottom = SkIntToScalar(otm.otmrcFontBox.right);
1063 mx->fLeading = SkIntToScalar(otm.otmLineGap);
1067 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
1068 my->fTop = SkIntToScalar(-otm.otmrcFontBox.top);
1069 my->fAscent = SkIntToScalar(-otm.otmAscent);
1070 my->fDescent = SkIntToScalar(-otm.otmDescent);
1071 my->fBottom = SkIntToScalar(-otm.otmrcFontBox.bottom);
1072 my->fLeading = SkIntToScalar(otm.otmLineGap);
1073 my->fAvgCharWidth = SkIntToScalar(otm.otmTextMetrics.tmAveCharWidth);
1074 my->fMaxCharWidth = SkIntToScalar(otm.otmTextMetrics.tmMaxCharWidth);
1075 my->fXMin = SkIntToScalar(otm.otmrcFontBox.left);
1076 my->fXMax = SkIntToScalar(otm.otmrcFontBox.right);
1078 my->fXHeight = SkIntToScalar(otm.otmsXHeight);
1081 sk_bzero(&gm, sizeof(gm));
1082 DWORD len = GetGlyphOutlineW(fDDC, 'x', GGO_METRICS, &gm, 0, 0, &gMat2Identity);
1083 if (len != GDI_ERROR && gm.gmBlackBoxY > 0) {
1084 my->fXHeight = SkIntToScalar(gm.gmBlackBoxY);
1089 ////////////////////////////////////////////////////////////////////////////////////////
1091 #define SK_SHOW_TEXT_BLIT_COVERAGE 0
1093 static void build_power_table(uint8_t table[], float ee) {
1094 for (int i = 0; i < 256; i++) {
1095 float x = i / 255.f;
1096 x = sk_float_pow(x, ee);
1097 int xx = SkScalarRoundToInt(x * 255);
1098 table[i] = SkToU8(xx);
1103 * This will invert the gamma applied by GDI (gray-scale antialiased), so we
1104 * can get linear values.
1106 * GDI grayscale appears to use a hard-coded gamma of 2.3.
1108 * GDI grayscale appears to draw using the black and white rasterizer at four
1109 * times the size and then downsamples to compute the coverage mask. As a
1110 * result there are only seventeen total grays. This lack of fidelity means
1111 * that shifting into other color spaces is imprecise.
1113 static const uint8_t* getInverseGammaTableGDI() {
1114 // Since build_power_table is idempotent, many threads can build gTableGdi
1117 // Microsoft Specific:
1118 // Making gInited volatile provides read-aquire and write-release in vc++.
1119 // In VS2012, see compiler option /volatile:(ms|iso).
1120 // Replace with C++11 atomics when possible.
1121 static volatile bool gInited;
1122 static uint8_t gTableGdi[256];
1124 // Need a L/L (read) barrier (full acquire not needed). If gInited is observed
1125 // true then gTableGdi is observable, but it must be requested.
1127 build_power_table(gTableGdi, 2.3f);
1128 // Need a S/S (write) barrier (full release not needed) here so that this
1129 // write to gInited becomes observable after gTableGdi.
1136 * This will invert the gamma applied by GDI ClearType, so we can get linear
1139 * GDI ClearType uses SPI_GETFONTSMOOTHINGCONTRAST / 1000 as the gamma value.
1140 * If this value is not specified, the default is a gamma of 1.4.
1142 static const uint8_t* getInverseGammaTableClearType() {
1143 // We don't expect SPI_GETFONTSMOOTHINGCONTRAST to ever change, so building
1144 // gTableClearType with build_power_table is effectively idempotent.
1146 // Microsoft Specific:
1147 // Making gInited volatile provides read-aquire and write-release in vc++.
1148 // In VS2012, see compiler option /volatile:(ms|iso).
1149 // Replace with C++11 atomics when possible.
1150 static volatile bool gInited;
1151 static uint8_t gTableClearType[256];
1153 // Need a L/L (read) barrier (acquire not needed). If gInited is observed
1154 // true then gTableClearType is observable, but it must be requested.
1157 if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &level, 0) || !level) {
1158 // can't get the data, so use a default
1161 build_power_table(gTableClearType, level / 1000.0f);
1162 // Need a S/S (write) barrier (release not needed) here so that this
1163 // write to gInited becomes observable after gTableClearType.
1166 return gTableClearType;
1169 #include "SkColorPriv.h"
1171 //Cannot assume that the input rgb is gray due to possible setting of kGenA8FromLCD_Flag.
1172 template<bool APPLY_PREBLEND>
1173 static inline uint8_t rgb_to_a8(SkGdiRGB rgb, const uint8_t* table8) {
1174 U8CPU r = (rgb >> 16) & 0xFF;
1175 U8CPU g = (rgb >> 8) & 0xFF;
1176 U8CPU b = (rgb >> 0) & 0xFF;
1177 return sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8);
1180 template<bool APPLY_PREBLEND>
1181 static inline uint16_t rgb_to_lcd16(SkGdiRGB rgb, const uint8_t* tableR,
1182 const uint8_t* tableG,
1183 const uint8_t* tableB) {
1184 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
1185 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG);
1186 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB);
1187 #if SK_SHOW_TEXT_BLIT_COVERAGE
1188 r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10);
1190 return SkPack888ToRGB16(r, g, b);
1193 template<bool APPLY_PREBLEND>
1194 static inline SkPMColor rgb_to_lcd32(SkGdiRGB rgb, const uint8_t* tableR,
1195 const uint8_t* tableG,
1196 const uint8_t* tableB) {
1197 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
1198 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG);
1199 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB);
1200 #if SK_SHOW_TEXT_BLIT_COVERAGE
1201 r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10);
1203 return SkPackARGB32(0xFF, r, g, b);
1206 // Is this GDI color neither black nor white? If so, we have to keep this
1207 // image as is, rather than smashing it down to a BW mask.
1209 // returns int instead of bool, since we don't want/have to pay to convert
1210 // the zero/non-zero value into a bool
1211 static int is_not_black_or_white(SkGdiRGB c) {
1212 // same as (but faster than)
1214 // return 0 == c || 0x00FFFFFF == c;
1215 return (c + (c & 1)) & 0x00FFFFFF;
1218 static bool is_rgb_really_bw(const SkGdiRGB* src, int width, int height, size_t srcRB) {
1219 for (int y = 0; y < height; ++y) {
1220 for (int x = 0; x < width; ++x) {
1221 if (is_not_black_or_white(src[x])) {
1225 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1230 // gdi's bitmap is upside-down, so we reverse dst walking in Y
1231 // whenever we copy it into skia's buffer
1232 static void rgb_to_bw(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
1233 const SkGlyph& glyph) {
1234 const int width = glyph.fWidth;
1235 const size_t dstRB = (width + 7) >> 3;
1236 uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1238 int byteCount = width >> 3;
1239 int bitCount = width & 7;
1241 // adjust srcRB to skip the values in our byteCount loop,
1242 // since we increment src locally there
1243 srcRB -= byteCount * 8 * sizeof(SkGdiRGB);
1245 for (int y = 0; y < glyph.fHeight; ++y) {
1246 if (byteCount > 0) {
1247 for (int i = 0; i < byteCount; ++i) {
1249 byte |= src[0] & (1 << 7);
1250 byte |= src[1] & (1 << 6);
1251 byte |= src[2] & (1 << 5);
1252 byte |= src[3] & (1 << 4);
1253 byte |= src[4] & (1 << 3);
1254 byte |= src[5] & (1 << 2);
1255 byte |= src[6] & (1 << 1);
1256 byte |= src[7] & (1 << 0);
1263 unsigned mask = 0x80;
1264 for (int i = 0; i < bitCount; i++) {
1265 byte |= src[i] & mask;
1268 dst[byteCount] = byte;
1270 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1273 #if SK_SHOW_TEXT_BLIT_COVERAGE
1274 if (glyph.fWidth > 0 && glyph.fHeight > 0) {
1275 uint8_t* first = (uint8_t*)glyph.fImage;
1276 uint8_t* last = (uint8_t*)((char*)glyph.fImage + glyph.fHeight * dstRB - 1);
1278 *last |= bitCount == 0 ? 1 : 1 << (8 - bitCount);
1283 template<bool APPLY_PREBLEND>
1284 static void rgb_to_a8(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
1285 const SkGlyph& glyph, const uint8_t* table8) {
1286 const size_t dstRB = glyph.rowBytes();
1287 const int width = glyph.fWidth;
1288 uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1290 for (int y = 0; y < glyph.fHeight; y++) {
1291 for (int i = 0; i < width; i++) {
1292 dst[i] = rgb_to_a8<APPLY_PREBLEND>(src[i], table8);
1293 #if SK_SHOW_TEXT_BLIT_COVERAGE
1294 dst[i] = SkMax32(dst[i], 10);
1297 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1302 template<bool APPLY_PREBLEND>
1303 static void rgb_to_lcd16(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph,
1304 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
1305 const size_t dstRB = glyph.rowBytes();
1306 const int width = glyph.fWidth;
1307 uint16_t* SK_RESTRICT dst = (uint16_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1309 for (int y = 0; y < glyph.fHeight; y++) {
1310 for (int i = 0; i < width; i++) {
1311 dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(src[i], tableR, tableG, tableB);
1313 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1314 dst = (uint16_t*)((char*)dst - dstRB);
1318 template<bool APPLY_PREBLEND>
1319 static void rgb_to_lcd32(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph,
1320 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
1321 const size_t dstRB = glyph.rowBytes();
1322 const int width = glyph.fWidth;
1323 uint32_t* SK_RESTRICT dst = (uint32_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1325 for (int y = 0; y < glyph.fHeight; y++) {
1326 for (int i = 0; i < width; i++) {
1327 dst[i] = rgb_to_lcd32<APPLY_PREBLEND>(src[i], tableR, tableG, tableB);
1329 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1330 dst = (uint32_t*)((char*)dst - dstRB);
1334 static inline unsigned clamp255(unsigned x) {
1336 return x - (x >> 8);
1339 void SkScalerContext_GDI::generateImage(const SkGlyph& glyph) {
1342 const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat;
1343 const bool isAA = !isLCD(fRec);
1346 const void* bits = fOffscreen.draw(glyph, isBW, &srcRB);
1348 LogFontTypeface::EnsureAccessible(this->getTypeface());
1349 bits = fOffscreen.draw(glyph, isBW, &srcRB);
1351 sk_bzero(glyph.fImage, glyph.computeImageSize());
1357 const uint8_t* table;
1358 //The offscreen contains a GDI blit if isAA and kGenA8FromLCD_Flag is not set.
1359 //Otherwise the offscreen contains a ClearType blit.
1360 if (isAA && !(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag)) {
1361 table = getInverseGammaTableGDI();
1363 table = getInverseGammaTableClearType();
1365 //Note that the following cannot really be integrated into the
1366 //pre-blend, since we may not be applying the pre-blend; when we aren't
1367 //applying the pre-blend it means that a filter wants linear anyway.
1368 //Other code may also be applying the pre-blend, so we'd need another
1369 //one with this and one without.
1370 SkGdiRGB* addr = (SkGdiRGB*)bits;
1371 for (int y = 0; y < glyph.fHeight; ++y) {
1372 for (int x = 0; x < glyph.fWidth; ++x) {
1373 int r = (addr[x] >> 16) & 0xFF;
1374 int g = (addr[x] >> 8) & 0xFF;
1375 int b = (addr[x] >> 0) & 0xFF;
1376 addr[x] = (table[r] << 16) | (table[g] << 8) | table[b];
1378 addr = SkTAddOffset<SkGdiRGB>(addr, srcRB);
1382 int width = glyph.fWidth;
1383 size_t dstRB = glyph.rowBytes();
1385 const uint8_t* src = (const uint8_t*)bits;
1386 uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1387 for (int y = 0; y < glyph.fHeight; y++) {
1388 memcpy(dst, src, dstRB);
1392 #if SK_SHOW_TEXT_BLIT_COVERAGE
1393 if (glyph.fWidth > 0 && glyph.fHeight > 0) {
1394 int bitCount = width & 7;
1395 uint8_t* first = (uint8_t*)glyph.fImage;
1396 uint8_t* last = (uint8_t*)((char*)glyph.fImage + glyph.fHeight * dstRB - 1);
1398 *last |= bitCount == 0 ? 1 : 1 << (8 - bitCount);
1402 // since the caller may require A8 for maskfilters, we can't check for BW
1403 // ... until we have the caller tell us that explicitly
1404 const SkGdiRGB* src = (const SkGdiRGB*)bits;
1405 if (fPreBlend.isApplicable()) {
1406 rgb_to_a8<true>(src, srcRB, glyph, fPreBlend.fG);
1408 rgb_to_a8<false>(src, srcRB, glyph, fPreBlend.fG);
1411 const SkGdiRGB* src = (const SkGdiRGB*)bits;
1412 if (is_rgb_really_bw(src, width, glyph.fHeight, srcRB)) {
1413 rgb_to_bw(src, srcRB, glyph);
1414 ((SkGlyph*)&glyph)->fMaskFormat = SkMask::kBW_Format;
1416 if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
1417 if (fPreBlend.isApplicable()) {
1418 rgb_to_lcd16<true>(src, srcRB, glyph,
1419 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1421 rgb_to_lcd16<false>(src, srcRB, glyph,
1422 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1425 SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat);
1426 if (fPreBlend.isApplicable()) {
1427 rgb_to_lcd32<true>(src, srcRB, glyph,
1428 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1430 rgb_to_lcd32<false>(src, srcRB, glyph,
1431 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1438 class GDIGlyphbufferPointIter {
1440 GDIGlyphbufferPointIter(const uint8_t* glyphbuf, DWORD total_size)
1441 : fHeaderIter(glyphbuf, total_size), fCurveIter(), fPointIter()
1444 POINTFX const * next() {
1446 if (!fCurveIter.isSet()) {
1447 const TTPOLYGONHEADER* header = fHeaderIter.next();
1448 if (NULL == header) {
1451 fCurveIter.set(header);
1452 const TTPOLYCURVE* curve = fCurveIter.next();
1453 if (NULL == curve) {
1456 fPointIter.set(curve);
1457 return &header->pfxStart;
1460 const POINTFX* nextPoint = fPointIter.next();
1461 if (NULL == nextPoint) {
1462 const TTPOLYCURVE* curve = fCurveIter.next();
1463 if (NULL == curve) {
1467 fPointIter.set(curve);
1469 nextPoint = fPointIter.next();
1474 WORD currentCurveType() {
1475 return fPointIter.fCurveType;
1479 /** Iterates over all of the polygon headers in a glyphbuf. */
1480 class GDIPolygonHeaderIter {
1482 GDIPolygonHeaderIter(const uint8_t* glyphbuf, DWORD total_size)
1483 : fCurPolygon(reinterpret_cast<const TTPOLYGONHEADER*>(glyphbuf))
1484 , fEndPolygon(SkTAddOffset<const TTPOLYGONHEADER>(glyphbuf, total_size))
1487 const TTPOLYGONHEADER* next() {
1488 if (fCurPolygon >= fEndPolygon) {
1491 const TTPOLYGONHEADER* thisPolygon = fCurPolygon;
1492 fCurPolygon = SkTAddOffset<const TTPOLYGONHEADER>(fCurPolygon, fCurPolygon->cb);
1496 const TTPOLYGONHEADER* fCurPolygon;
1497 const TTPOLYGONHEADER* fEndPolygon;
1500 /** Iterates over all of the polygon curves in a polygon header. */
1501 class GDIPolygonCurveIter {
1503 GDIPolygonCurveIter() : fCurCurve(NULL), fEndCurve(NULL) { }
1505 GDIPolygonCurveIter(const TTPOLYGONHEADER* curPolygon)
1506 : fCurCurve(SkTAddOffset<const TTPOLYCURVE>(curPolygon, sizeof(TTPOLYGONHEADER)))
1507 , fEndCurve(SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon->cb))
1510 bool isSet() { return fCurCurve != NULL; }
1512 void set(const TTPOLYGONHEADER* curPolygon) {
1513 fCurCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon, sizeof(TTPOLYGONHEADER));
1514 fEndCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon->cb);
1521 const TTPOLYCURVE* next() {
1522 if (fCurCurve >= fEndCurve) {
1525 const TTPOLYCURVE* thisCurve = fCurCurve;
1526 fCurCurve = SkTAddOffset<const TTPOLYCURVE>(fCurCurve, size_of_TTPOLYCURVE(*fCurCurve));
1530 size_t size_of_TTPOLYCURVE(const TTPOLYCURVE& curve) {
1531 return 2*sizeof(WORD) + curve.cpfx*sizeof(POINTFX);
1533 const TTPOLYCURVE* fCurCurve;
1534 const TTPOLYCURVE* fEndCurve;
1537 /** Iterates over all of the polygon points in a polygon curve. */
1538 class GDIPolygonCurvePointIter {
1540 GDIPolygonCurvePointIter() : fCurveType(0), fCurPoint(NULL), fEndPoint(NULL) { }
1542 GDIPolygonCurvePointIter(const TTPOLYCURVE* curPolygon)
1543 : fCurveType(curPolygon->wType)
1544 , fCurPoint(&curPolygon->apfx[0])
1545 , fEndPoint(&curPolygon->apfx[curPolygon->cpfx])
1548 bool isSet() { return fCurPoint != NULL; }
1550 void set(const TTPOLYCURVE* curPolygon) {
1551 fCurveType = curPolygon->wType;
1552 fCurPoint = &curPolygon->apfx[0];
1553 fEndPoint = &curPolygon->apfx[curPolygon->cpfx];
1560 const POINTFX* next() {
1561 if (fCurPoint >= fEndPoint) {
1564 const POINTFX* thisPoint = fCurPoint;
1571 const POINTFX* fCurPoint;
1572 const POINTFX* fEndPoint;
1575 GDIPolygonHeaderIter fHeaderIter;
1576 GDIPolygonCurveIter fCurveIter;
1577 GDIPolygonCurvePointIter fPointIter;
1580 static void sk_path_from_gdi_path(SkPath* path, const uint8_t* glyphbuf, DWORD total_size) {
1581 const uint8_t* cur_glyph = glyphbuf;
1582 const uint8_t* end_glyph = glyphbuf + total_size;
1584 while (cur_glyph < end_glyph) {
1585 const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
1587 const uint8_t* end_poly = cur_glyph + th->cb;
1588 const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
1590 path->moveTo(SkFixedToScalar( SkFIXEDToFixed(th->pfxStart.x)),
1591 SkFixedToScalar(-SkFIXEDToFixed(th->pfxStart.y)));
1593 while (cur_poly < end_poly) {
1594 const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
1596 if (pc->wType == TT_PRIM_LINE) {
1597 for (uint16_t i = 0; i < pc->cpfx; i++) {
1598 path->lineTo(SkFixedToScalar( SkFIXEDToFixed(pc->apfx[i].x)),
1599 SkFixedToScalar(-SkFIXEDToFixed(pc->apfx[i].y)));
1603 if (pc->wType == TT_PRIM_QSPLINE) {
1604 for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline
1605 POINTFX pnt_b = pc->apfx[u]; // B is always the current point
1606 POINTFX pnt_c = pc->apfx[u+1];
1608 if (u < pc->cpfx - 2) { // If not on last spline, compute C
1609 pnt_c.x = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.x),
1610 SkFIXEDToFixed(pnt_c.x)));
1611 pnt_c.y = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.y),
1612 SkFIXEDToFixed(pnt_c.y)));
1615 path->quadTo(SkFixedToScalar( SkFIXEDToFixed(pnt_b.x)),
1616 SkFixedToScalar(-SkFIXEDToFixed(pnt_b.y)),
1617 SkFixedToScalar( SkFIXEDToFixed(pnt_c.x)),
1618 SkFixedToScalar(-SkFIXEDToFixed(pnt_c.y)));
1621 // Advance past this TTPOLYCURVE.
1622 cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx;
1624 cur_glyph += th->cb;
1629 #define move_next_expected_hinted_point(iter, pElem) do {\
1630 pElem = iter.next(); \
1631 if (NULL == pElem) return false; \
1634 // It is possible for the hinted and unhinted versions of the same path to have
1635 // a different number of points due to GDI's handling of flipped points.
1636 // If this is detected, this will return false.
1637 static bool sk_path_from_gdi_paths(SkPath* path, const uint8_t* glyphbuf, DWORD total_size,
1638 GDIGlyphbufferPointIter hintedYs) {
1639 const uint8_t* cur_glyph = glyphbuf;
1640 const uint8_t* end_glyph = glyphbuf + total_size;
1642 POINTFX const * hintedPoint;
1644 while (cur_glyph < end_glyph) {
1645 const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
1647 const uint8_t* end_poly = cur_glyph + th->cb;
1648 const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
1650 move_next_expected_hinted_point(hintedYs, hintedPoint);
1651 path->moveTo(SkFixedToScalar( SkFIXEDToFixed(th->pfxStart.x)),
1652 SkFixedToScalar(-SkFIXEDToFixed(hintedPoint->y)));
1654 while (cur_poly < end_poly) {
1655 const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
1657 if (pc->wType == TT_PRIM_LINE) {
1658 for (uint16_t i = 0; i < pc->cpfx; i++) {
1659 move_next_expected_hinted_point(hintedYs, hintedPoint);
1660 path->lineTo(SkFixedToScalar( SkFIXEDToFixed(pc->apfx[i].x)),
1661 SkFixedToScalar(-SkFIXEDToFixed(hintedPoint->y)));
1665 if (pc->wType == TT_PRIM_QSPLINE) {
1666 POINTFX currentPoint = pc->apfx[0];
1667 move_next_expected_hinted_point(hintedYs, hintedPoint);
1668 // only take the hinted y if it wasn't flipped
1669 if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) {
1670 currentPoint.y = hintedPoint->y;
1672 for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline
1673 POINTFX pnt_b = currentPoint;//pc->apfx[u]; // B is always the current point
1674 POINTFX pnt_c = pc->apfx[u+1];
1675 move_next_expected_hinted_point(hintedYs, hintedPoint);
1676 // only take the hinted y if it wasn't flipped
1677 if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) {
1678 pnt_c.y = hintedPoint->y;
1680 currentPoint.x = pnt_c.x;
1681 currentPoint.y = pnt_c.y;
1683 if (u < pc->cpfx - 2) { // If not on last spline, compute C
1684 pnt_c.x = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.x),
1685 SkFIXEDToFixed(pnt_c.x)));
1686 pnt_c.y = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.y),
1687 SkFIXEDToFixed(pnt_c.y)));
1690 path->quadTo(SkFixedToScalar( SkFIXEDToFixed(pnt_b.x)),
1691 SkFixedToScalar(-SkFIXEDToFixed(pnt_b.y)),
1692 SkFixedToScalar( SkFIXEDToFixed(pnt_c.x)),
1693 SkFixedToScalar(-SkFIXEDToFixed(pnt_c.y)));
1696 // Advance past this TTPOLYCURVE.
1697 cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx;
1699 cur_glyph += th->cb;
1705 DWORD SkScalerContext_GDI::getGDIGlyphPath(const SkGlyph& glyph, UINT flags,
1706 SkAutoSTMalloc<BUFFERSIZE, uint8_t>* glyphbuf)
1710 DWORD total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, BUFFERSIZE, glyphbuf->get(), &fMat22);
1711 // Sometimes GetGlyphOutlineW returns a number larger than BUFFERSIZE even if BUFFERSIZE > 0.
1712 // It has been verified that this does not involve a buffer overrun.
1713 if (GDI_ERROR == total_size || total_size > BUFFERSIZE) {
1714 // GDI_ERROR because the BUFFERSIZE was too small, or because the data was not accessible.
1715 // When the data is not accessable GetGlyphOutlineW fails rather quickly,
1716 // so just try to get the size. If that fails then ensure the data is accessible.
1717 total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, 0, NULL, &fMat22);
1718 if (GDI_ERROR == total_size) {
1719 LogFontTypeface::EnsureAccessible(this->getTypeface());
1720 total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, 0, NULL, &fMat22);
1721 if (GDI_ERROR == total_size) {
1727 glyphbuf->reset(total_size);
1729 DWORD ret = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, total_size, glyphbuf->get(), &fMat22);
1730 if (GDI_ERROR == ret) {
1731 LogFontTypeface::EnsureAccessible(this->getTypeface());
1732 ret = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, total_size, glyphbuf->get(), &fMat22);
1733 if (GDI_ERROR == ret) {
1742 void SkScalerContext_GDI::generatePath(const SkGlyph& glyph, SkPath* path) {
1743 SkASSERT(&glyph && path);
1748 // Out of all the fonts on a typical Windows box,
1749 // 25% of glyphs require more than 2KB.
1750 // 1% of glyphs require more than 4KB.
1751 // 0.01% of glyphs require more than 8KB.
1752 // 8KB is less than 1% of the normal 1MB stack on Windows.
1753 // Note that some web fonts glyphs require more than 20KB.
1754 //static const DWORD BUFFERSIZE = (1 << 13);
1756 //GDI only uses hinted outlines when axis aligned.
1757 UINT format = GGO_NATIVE | GGO_GLYPH_INDEX;
1758 if (fRec.getHinting() == SkPaint::kNo_Hinting || fRec.getHinting() == SkPaint::kSlight_Hinting){
1759 format |= GGO_UNHINTED;
1761 SkAutoSTMalloc<BUFFERSIZE, uint8_t> glyphbuf(BUFFERSIZE);
1762 DWORD total_size = getGDIGlyphPath(glyph, format, &glyphbuf);
1763 if (0 == total_size) {
1767 if (fRec.getHinting() != SkPaint::kSlight_Hinting) {
1768 sk_path_from_gdi_path(path, glyphbuf, total_size);
1770 //GDI only uses hinted outlines when axis aligned.
1771 UINT format = GGO_NATIVE | GGO_GLYPH_INDEX;
1773 SkAutoSTMalloc<BUFFERSIZE, uint8_t> hintedGlyphbuf(BUFFERSIZE);
1774 DWORD hinted_total_size = getGDIGlyphPath(glyph, format, &hintedGlyphbuf);
1775 if (0 == hinted_total_size) {
1779 if (!sk_path_from_gdi_paths(path, glyphbuf, total_size,
1780 GDIGlyphbufferPointIter(hintedGlyphbuf, hinted_total_size)))
1783 sk_path_from_gdi_path(path, glyphbuf, total_size);
1788 static void logfont_for_name(const char* familyName, LOGFONT* lf) {
1789 sk_bzero(lf, sizeof(LOGFONT));
1791 // Get the buffer size needed first.
1792 size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName,
1794 // Allocate a buffer (str_len already has terminating null
1796 wchar_t *wideFamilyName = new wchar_t[str_len];
1797 // Now actually convert the string.
1798 ::MultiByteToWideChar(CP_UTF8, 0, familyName, -1,
1799 wideFamilyName, str_len);
1800 ::wcsncpy(lf->lfFaceName, wideFamilyName, LF_FACESIZE - 1);
1801 delete [] wideFamilyName;
1802 lf->lfFaceName[LF_FACESIZE-1] = L'\0';
1804 ::strncpy(lf->lfFaceName, familyName, LF_FACESIZE - 1);
1805 lf->lfFaceName[LF_FACESIZE - 1] = '\0';
1809 void LogFontTypeface::onGetFontDescriptor(SkFontDescriptor* desc,
1810 bool* isLocalStream) const {
1811 // Get the actual name of the typeface. The logfont may not know this.
1812 HFONT font = CreateFontIndirect(&fLogFont);
1814 HDC deviceContext = ::CreateCompatibleDC(NULL);
1815 HFONT savefont = (HFONT)SelectObject(deviceContext, font);
1817 SkString familyName;
1818 dcfontname_to_skstring(deviceContext, fLogFont, &familyName);
1820 if (deviceContext) {
1821 ::SelectObject(deviceContext, savefont);
1822 ::DeleteDC(deviceContext);
1825 ::DeleteObject(font);
1828 desc->setFamilyName(familyName.c_str());
1829 *isLocalStream = this->fSerializeAsStream;
1832 static bool getWidthAdvance(HDC hdc, int gId, int16_t* advance) {
1833 // Initialize the MAT2 structure to the identify transformation matrix.
1834 static const MAT2 mat2 = {SkScalarToFIXED(1), SkScalarToFIXED(0),
1835 SkScalarToFIXED(0), SkScalarToFIXED(1)};
1836 int flags = GGO_METRICS | GGO_GLYPH_INDEX;
1838 if (GDI_ERROR == GetGlyphOutline(hdc, gId, flags, &gm, 0, NULL, &mat2)) {
1842 *advance = gm.gmCellIncX;
1846 SkAdvancedTypefaceMetrics* LogFontTypeface::onGetAdvancedTypefaceMetrics(
1847 SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
1848 const uint32_t* glyphIDs,
1849 uint32_t glyphIDsCount) const {
1850 LOGFONT lf = fLogFont;
1851 SkAdvancedTypefaceMetrics* info = NULL;
1853 HDC hdc = CreateCompatibleDC(NULL);
1854 HFONT font = CreateFontIndirect(&lf);
1855 HFONT savefont = (HFONT)SelectObject(hdc, font);
1856 HFONT designFont = NULL;
1858 const char stem_chars[] = {'i', 'I', '!', '1'};
1860 unsigned glyphCount;
1862 // To request design units, create a logical font whose height is specified
1864 OUTLINETEXTMETRIC otm;
1865 unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
1867 call_ensure_accessible(lf);
1868 otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
1870 if (!otmRet || !GetTextFace(hdc, LF_FACESIZE, lf.lfFaceName)) {
1873 lf.lfHeight = -SkToS32(otm.otmEMSquare);
1874 designFont = CreateFontIndirect(&lf);
1875 SelectObject(hdc, designFont);
1876 if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm)) {
1879 glyphCount = calculateGlyphCount(hdc, fLogFont);
1881 info = new SkAdvancedTypefaceMetrics;
1882 info->fEmSize = otm.otmEMSquare;
1883 info->fMultiMaster = false;
1884 info->fLastGlyphID = SkToU16(glyphCount - 1);
1886 tchar_to_skstring(lf.lfFaceName, &info->fFontName);
1888 if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) {
1889 populate_glyph_to_unicode(hdc, glyphCount, &(info->fGlyphToUnicode));
1892 if (glyphCount > 0 &&
1893 (otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE)) {
1894 info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
1896 info->fType = SkAdvancedTypefaceMetrics::kOther_Font;
1897 info->fItalicAngle = 0;
1901 info->fCapHeight = 0;
1902 info->fBBox = SkIRect::MakeEmpty();
1906 // If this bit is clear the font is a fixed pitch font.
1907 if (!(otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
1908 info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
1910 if (otm.otmTextMetrics.tmItalic) {
1911 info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
1913 if (otm.otmTextMetrics.tmPitchAndFamily & FF_ROMAN) {
1914 info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
1915 } else if (otm.otmTextMetrics.tmPitchAndFamily & FF_SCRIPT) {
1916 info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
1919 // The main italic angle of the font, in tenths of a degree counterclockwise
1921 info->fItalicAngle = otm.otmItalicAngle / 10;
1922 info->fAscent = SkToS16(otm.otmTextMetrics.tmAscent);
1923 info->fDescent = SkToS16(-otm.otmTextMetrics.tmDescent);
1924 // TODO(ctguil): Use alternate cap height calculation.
1925 // MSDN says otmsCapEmHeight is not support but it is returning a value on
1927 info->fCapHeight = otm.otmsCapEmHeight;
1929 SkIRect::MakeLTRB(otm.otmrcFontBox.left, otm.otmrcFontBox.top,
1930 otm.otmrcFontBox.right, otm.otmrcFontBox.bottom);
1932 // Figure out a good guess for StemV - Min width of i, I, !, 1.
1933 // This probably isn't very good with an italic font.
1934 min_width = SHRT_MAX;
1936 for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) {
1938 if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) {
1939 int16_t width = abcWidths.abcB;
1940 if (width > 0 && width < min_width) {
1942 info->fStemV = min_width;
1947 // If bit 1 is set, the font may not be embedded in a document.
1948 // If bit 1 is clear, the font can be embedded.
1949 // If bit 2 is set, the embedding is read-only.
1950 if (otm.otmfsType & 0x1) {
1951 info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
1952 } else if (perGlyphInfo &
1953 SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) {
1954 if (info->fStyle & SkAdvancedTypefaceMetrics::kFixedPitch_Style) {
1955 appendRange(&info->fGlyphWidths, 0);
1956 info->fGlyphWidths->fAdvance.append(1, &min_width);
1957 finishRange(info->fGlyphWidths.get(), 0,
1958 SkAdvancedTypefaceMetrics::WidthRange::kDefault);
1960 info->fGlyphWidths.reset(
1971 SelectObject(hdc, savefont);
1972 DeleteObject(designFont);
1979 //Dummy representation of a Base64 encoded GUID from create_unique_font_name.
1980 #define BASE64_GUID_ID "XXXXXXXXXXXXXXXXXXXXXXXX"
1981 //Length of GUID representation from create_id, including NULL terminator.
1982 #define BASE64_GUID_ID_LEN SK_ARRAY_COUNT(BASE64_GUID_ID)
1984 SK_COMPILE_ASSERT(BASE64_GUID_ID_LEN < LF_FACESIZE, GUID_longer_than_facesize);
1987 NameID 6 Postscript names cannot have the character '/'.
1988 It would be easier to hex encode the GUID, but that is 32 bytes,
1989 and many systems have issues with names longer than 28 bytes.
1990 The following need not be any standard base64 encoding.
1991 The encoded value is never decoded.
1993 static const char postscript_safe_base64_encode[] =
1994 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1995 "abcdefghijklmnopqrstuvwxyz"
1999 Formats a GUID into Base64 and places it into buffer.
2000 buffer should have space for at least BASE64_GUID_ID_LEN characters.
2001 The string will always be null terminated.
2002 XXXXXXXXXXXXXXXXXXXXXXXX0
2004 static void format_guid_b64(const GUID& guid, char* buffer, size_t bufferSize) {
2005 SkASSERT(bufferSize >= BASE64_GUID_ID_LEN);
2006 size_t written = SkBase64::Encode(&guid, sizeof(guid), buffer, postscript_safe_base64_encode);
2007 SkASSERT(written < LF_FACESIZE);
2008 buffer[written] = '\0';
2012 Creates a Base64 encoded GUID and places it into buffer.
2013 buffer should have space for at least BASE64_GUID_ID_LEN characters.
2014 The string will always be null terminated.
2015 XXXXXXXXXXXXXXXXXXXXXXXX0
2017 static HRESULT create_unique_font_name(char* buffer, size_t bufferSize) {
2019 if (FAILED(CoCreateGuid(&guid))) {
2020 return E_UNEXPECTED;
2022 format_guid_b64(guid, buffer, bufferSize);
2028 Introduces a font to GDI. On failure will return NULL. The returned handle
2029 should eventually be passed to RemoveFontMemResourceEx.
2031 static HANDLE activate_font(SkData* fontData) {
2033 //AddFontMemResourceEx just copies the data, but does not specify const.
2034 HANDLE fontHandle = AddFontMemResourceEx(const_cast<void*>(fontData->data()),
2035 static_cast<DWORD>(fontData->size()),
2039 if (fontHandle != NULL && numFonts < 1) {
2040 RemoveFontMemResourceEx(fontHandle);
2047 static SkTypeface* create_from_stream(SkStream* stream) {
2048 // Create a unique and unpredictable font name.
2049 // Avoids collisions and access from CSS.
2050 char familyName[BASE64_GUID_ID_LEN];
2051 const int familyNameSize = SK_ARRAY_COUNT(familyName);
2052 if (FAILED(create_unique_font_name(familyName, familyNameSize))) {
2056 // Change the name of the font.
2057 SkAutoTUnref<SkData> rewrittenFontData(SkOTUtils::RenameFont(stream, familyName, familyNameSize-1));
2058 if (NULL == rewrittenFontData.get()) {
2062 // Register the font with GDI.
2063 HANDLE fontReference = activate_font(rewrittenFontData.get());
2064 if (NULL == fontReference) {
2068 // Create the typeface.
2070 logfont_for_name(familyName, &lf);
2072 return SkCreateFontMemResourceTypefaceFromLOGFONT(lf, fontReference);
2075 SkStream* LogFontTypeface::onOpenStream(int* ttcIndex) const {
2078 const DWORD kTTCTag =
2079 SkEndian_SwapBE32(SkSetFourByteTag('t', 't', 'c', 'f'));
2080 LOGFONT lf = fLogFont;
2082 HDC hdc = ::CreateCompatibleDC(NULL);
2083 HFONT font = CreateFontIndirect(&lf);
2084 HFONT savefont = (HFONT)SelectObject(hdc, font);
2086 SkMemoryStream* stream = NULL;
2087 DWORD tables[2] = {kTTCTag, 0};
2088 for (int i = 0; i < SK_ARRAY_COUNT(tables); i++) {
2089 DWORD bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0);
2090 if (bufferSize == GDI_ERROR) {
2091 call_ensure_accessible(lf);
2092 bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0);
2094 if (bufferSize != GDI_ERROR) {
2095 stream = new SkMemoryStream(bufferSize);
2096 if (GetFontData(hdc, tables[i], 0, (void*)stream->getMemoryBase(), bufferSize)) {
2105 SelectObject(hdc, savefont);
2112 static void bmpCharsToGlyphs(HDC hdc, const WCHAR* bmpChars, int count, uint16_t* glyphs,
2115 DWORD result = GetGlyphIndicesW(hdc, bmpChars, count, glyphs, GGI_MARK_NONEXISTING_GLYPHS);
2116 if (GDI_ERROR == result) {
2117 for (int i = 0; i < count; ++i) {
2124 for (int i = 0; i < count; ++i) {
2125 if (0xFFFF == glyphs[i] || 0x1F == glyphs[i]) {
2130 for (int i = 0; i < count; ++i) {
2131 if (0xFFFF == glyphs[i]){
2138 static uint16_t nonBmpCharToGlyph(HDC hdc, SCRIPT_CACHE* scriptCache, const WCHAR utf16[2]) {
2140 // Use uniscribe to detemine glyph index for non-BMP characters.
2141 static const int numWCHAR = 2;
2142 static const int maxItems = 2;
2143 // MSDN states that this can be NULL, but some things don't work then.
2144 SCRIPT_CONTROL scriptControl = { 0 };
2145 // Add extra item to SCRIPT_ITEM to work around a bug (now documented).
2146 // https://bugzilla.mozilla.org/show_bug.cgi?id=366643
2147 SCRIPT_ITEM si[maxItems + 1];
2149 HRZM(ScriptItemize(utf16, numWCHAR, maxItems, &scriptControl, NULL, si, &numItems),
2150 "Could not itemize character.");
2152 // Sometimes ScriptShape cannot find a glyph for a non-BMP and returns 2 space glyphs.
2153 static const int maxGlyphs = 2;
2154 SCRIPT_VISATTR vsa[maxGlyphs];
2155 WORD outGlyphs[maxGlyphs];
2156 WORD logClust[numWCHAR];
2158 HRZM(ScriptShape(hdc, scriptCache, utf16, numWCHAR, maxGlyphs, &si[0].a,
2159 outGlyphs, logClust, vsa, &numGlyphs),
2160 "Could not shape character.");
2161 if (1 == numGlyphs) {
2162 index = outGlyphs[0];
2169 SkAutoHDC(const LOGFONT& lf)
2170 : fHdc(::CreateCompatibleDC(NULL))
2171 , fFont(::CreateFontIndirect(&lf))
2172 , fSavefont((HFONT)SelectObject(fHdc, fFont))
2175 SelectObject(fHdc, fSavefont);
2176 DeleteObject(fFont);
2179 operator HDC() { return fHdc; }
2185 #define SkAutoHDC(...) SK_REQUIRE_LOCAL_VAR(SkAutoHDC)
2187 int LogFontTypeface::onCharsToGlyphs(const void* chars, Encoding encoding,
2188 uint16_t userGlyphs[], int glyphCount) const
2190 SkAutoHDC hdc(fLogFont);
2193 if (0 == GetTextMetrics(hdc, &tm)) {
2194 call_ensure_accessible(fLogFont);
2195 if (0 == GetTextMetrics(hdc, &tm)) {
2196 tm.tmPitchAndFamily = TMPF_TRUETYPE;
2199 bool Ox1FHack = !(tm.tmPitchAndFamily & TMPF_VECTOR) /*&& winVer < Vista */;
2201 SkAutoSTMalloc<256, uint16_t> scratchGlyphs;
2203 if (userGlyphs != NULL) {
2204 glyphs = userGlyphs;
2206 glyphs = scratchGlyphs.reset(glyphCount);
2209 SCRIPT_CACHE sc = 0;
2211 case SkTypeface::kUTF8_Encoding: {
2212 static const int scratchCount = 256;
2213 WCHAR scratch[scratchCount];
2215 const char* currentUtf8 = reinterpret_cast<const char*>(chars);
2216 SkUnichar currentChar;
2218 currentChar = SkUTF8_NextUnichar(¤tUtf8);
2220 while (glyphIndex < glyphCount) {
2221 // Try a run of bmp.
2222 int glyphsLeft = SkTMin(glyphCount - glyphIndex, scratchCount);
2224 while (runLength < glyphsLeft && currentChar <= 0xFFFF) {
2225 scratch[runLength] = static_cast<WCHAR>(currentChar);
2227 if (runLength < glyphsLeft) {
2228 currentChar = SkUTF8_NextUnichar(¤tUtf8);
2232 bmpCharsToGlyphs(hdc, scratch, runLength, &glyphs[glyphIndex], Ox1FHack);
2233 glyphIndex += runLength;
2236 // Try a run of non-bmp.
2237 while (glyphIndex < glyphCount && currentChar > 0xFFFF) {
2238 SkUTF16_FromUnichar(currentChar, reinterpret_cast<uint16_t*>(scratch));
2239 glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, scratch);
2241 if (glyphIndex < glyphCount) {
2242 currentChar = SkUTF8_NextUnichar(¤tUtf8);
2248 case SkTypeface::kUTF16_Encoding: {
2250 const WCHAR* currentUtf16 = reinterpret_cast<const WCHAR*>(chars);
2251 while (glyphIndex < glyphCount) {
2252 // Try a run of bmp.
2253 int glyphsLeft = glyphCount - glyphIndex;
2255 while (runLength < glyphsLeft && !SkUTF16_IsHighSurrogate(currentUtf16[runLength])) {
2259 bmpCharsToGlyphs(hdc, currentUtf16, runLength, &glyphs[glyphIndex], Ox1FHack);
2260 glyphIndex += runLength;
2261 currentUtf16 += runLength;
2264 // Try a run of non-bmp.
2265 while (glyphIndex < glyphCount && SkUTF16_IsHighSurrogate(*currentUtf16)) {
2266 glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, currentUtf16);
2273 case SkTypeface::kUTF32_Encoding: {
2274 static const int scratchCount = 256;
2275 WCHAR scratch[scratchCount];
2277 const uint32_t* utf32 = reinterpret_cast<const uint32_t*>(chars);
2278 while (glyphIndex < glyphCount) {
2279 // Try a run of bmp.
2280 int glyphsLeft = SkTMin(glyphCount - glyphIndex, scratchCount);
2282 while (runLength < glyphsLeft && utf32[glyphIndex + runLength] <= 0xFFFF) {
2283 scratch[runLength] = static_cast<WCHAR>(utf32[glyphIndex + runLength]);
2287 bmpCharsToGlyphs(hdc, scratch, runLength, &glyphs[glyphIndex], Ox1FHack);
2288 glyphIndex += runLength;
2291 // Try a run of non-bmp.
2292 while (glyphIndex < glyphCount && utf32[glyphIndex] > 0xFFFF) {
2293 SkUTF16_FromUnichar(utf32[glyphIndex], reinterpret_cast<uint16_t*>(scratch));
2294 glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, scratch);
2305 ::ScriptFreeCache(&sc);
2308 for (int i = 0; i < glyphCount; ++i) {
2309 if (0 == glyphs[i]) {
2316 int LogFontTypeface::onCountGlyphs() const {
2317 HDC hdc = ::CreateCompatibleDC(NULL);
2318 HFONT font = CreateFontIndirect(&fLogFont);
2319 HFONT savefont = (HFONT)SelectObject(hdc, font);
2321 unsigned int glyphCount = calculateGlyphCount(hdc, fLogFont);
2323 SelectObject(hdc, savefont);
2330 int LogFontTypeface::onGetUPEM() const {
2331 HDC hdc = ::CreateCompatibleDC(NULL);
2332 HFONT font = CreateFontIndirect(&fLogFont);
2333 HFONT savefont = (HFONT)SelectObject(hdc, font);
2335 unsigned int upem = calculateUPEM(hdc, fLogFont);
2337 SelectObject(hdc, savefont);
2344 SkTypeface::LocalizedStrings* LogFontTypeface::onCreateFamilyNameIterator() const {
2345 SkTypeface::LocalizedStrings* nameIter =
2346 SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(*this);
2347 if (NULL == nameIter) {
2348 SkString familyName;
2349 this->getFamilyName(&familyName);
2350 SkString language("und"); //undetermined
2351 nameIter = new SkOTUtils::LocalizedStrings_SingleName(familyName, language);
2356 int LogFontTypeface::onGetTableTags(SkFontTableTag tags[]) const {
2357 SkSFNTHeader header;
2358 if (sizeof(header) != this->onGetTableData(0, 0, sizeof(header), &header)) {
2362 int numTables = SkEndian_SwapBE16(header.numTables);
2365 size_t size = numTables * sizeof(SkSFNTHeader::TableDirectoryEntry);
2366 SkAutoSTMalloc<0x20, SkSFNTHeader::TableDirectoryEntry> dir(numTables);
2367 if (size != this->onGetTableData(0, sizeof(header), size, dir.get())) {
2371 for (int i = 0; i < numTables; ++i) {
2372 tags[i] = SkEndian_SwapBE32(dir[i].tag);
2378 size_t LogFontTypeface::onGetTableData(SkFontTableTag tag, size_t offset,
2379 size_t length, void* data) const
2381 LOGFONT lf = fLogFont;
2383 HDC hdc = ::CreateCompatibleDC(NULL);
2384 HFONT font = CreateFontIndirect(&lf);
2385 HFONT savefont = (HFONT)SelectObject(hdc, font);
2387 tag = SkEndian_SwapBE32(tag);
2391 DWORD bufferSize = GetFontData(hdc, tag, (DWORD) offset, data, (DWORD) length);
2392 if (bufferSize == GDI_ERROR) {
2393 call_ensure_accessible(lf);
2394 bufferSize = GetFontData(hdc, tag, (DWORD) offset, data, (DWORD) length);
2397 SelectObject(hdc, savefont);
2401 return bufferSize == GDI_ERROR ? 0 : bufferSize;
2404 SkScalerContext* LogFontTypeface::onCreateScalerContext(const SkDescriptor* desc) const {
2405 SkScalerContext_GDI* ctx = SkNEW_ARGS(SkScalerContext_GDI,
2406 (const_cast<LogFontTypeface*>(this), desc));
2407 if (!ctx->isValid()) {
2414 void LogFontTypeface::onFilterRec(SkScalerContextRec* rec) const {
2415 if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag ||
2416 rec->fFlags & SkScalerContext::kLCD_Vertical_Flag)
2418 rec->fMaskFormat = SkMask::kA8_Format;
2419 rec->fFlags |= SkScalerContext::kGenA8FromLCD_Flag;
2422 unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag |
2423 SkScalerContext::kForceAutohinting_Flag |
2424 SkScalerContext::kEmbeddedBitmapText_Flag |
2425 SkScalerContext::kEmbolden_Flag |
2426 SkScalerContext::kLCD_BGROrder_Flag |
2427 SkScalerContext::kLCD_Vertical_Flag;
2428 rec->fFlags &= ~flagsWeDontSupport;
2430 SkPaint::Hinting h = rec->getHinting();
2432 case SkPaint::kNo_Hinting:
2434 case SkPaint::kSlight_Hinting:
2435 // Only do slight hinting when axis aligned.
2436 // TODO: re-enable slight hinting when FontHostTest can pass.
2437 //if (!isAxisAligned(*rec)) {
2438 h = SkPaint::kNo_Hinting;
2441 case SkPaint::kNormal_Hinting:
2442 case SkPaint::kFull_Hinting:
2443 // TODO: need to be able to distinguish subpixel positioned glyphs
2444 // and linear metrics.
2445 //rec->fFlags &= ~SkScalerContext::kSubpixelPositioning_Flag;
2446 h = SkPaint::kNormal_Hinting;
2449 SkDEBUGFAIL("unknown hinting");
2451 //TODO: if this is a bitmap font, squash hinting and subpixel.
2454 // turn this off since GDI might turn A8 into BW! Need a bigger fix.
2456 // Disable LCD when rotated, since GDI's output is ugly
2457 if (isLCD(*rec) && !isAxisAligned(*rec)) {
2458 rec->fMaskFormat = SkMask::kA8_Format;
2462 if (!fCanBeLCD && isLCD(*rec)) {
2463 rec->fMaskFormat = SkMask::kA8_Format;
2464 rec->fFlags &= ~SkScalerContext::kGenA8FromLCD_Flag;
2468 ///////////////////////////////////////////////////////////////////////////////
2470 #include "SkFontMgr.h"
2471 #include "SkDataTable.h"
2473 static bool valid_logfont_for_enum(const LOGFONT& lf) {
2474 // TODO: Vector FON is unsupported and should not be listed.
2476 // Ignore implicit vertical variants.
2477 lf.lfFaceName[0] && lf.lfFaceName[0] != '@'
2479 // DEFAULT_CHARSET is used to get all fonts, but also implies all
2480 // character sets. Filter assuming all fonts support ANSI_CHARSET.
2481 && ANSI_CHARSET == lf.lfCharSet
2485 /** An EnumFontFamExProc implementation which interprets builderParam as
2486 * an SkTDArray<ENUMLOGFONTEX>* and appends logfonts which
2487 * pass the valid_logfont_for_enum predicate.
2489 static int CALLBACK enum_family_proc(const LOGFONT* lf, const TEXTMETRIC*,
2490 DWORD fontType, LPARAM builderParam) {
2491 if (valid_logfont_for_enum(*lf)) {
2492 SkTDArray<ENUMLOGFONTEX>* array = (SkTDArray<ENUMLOGFONTEX>*)builderParam;
2493 *array->append() = *(ENUMLOGFONTEX*)lf;
2495 return 1; // non-zero means continue
2498 static SkFontStyle compute_fontstyle(const LOGFONT& lf) {
2499 return SkFontStyle(lf.lfWeight, SkFontStyle::kNormal_Width,
2500 lf.lfItalic ? SkFontStyle::kItalic_Slant
2501 : SkFontStyle::kUpright_Slant);
2504 class SkFontStyleSetGDI : public SkFontStyleSet {
2506 SkFontStyleSetGDI(const TCHAR familyName[]) {
2508 sk_bzero(&lf, sizeof(lf));
2509 lf.lfCharSet = DEFAULT_CHARSET;
2510 _tcscpy_s(lf.lfFaceName, familyName);
2512 HDC hdc = ::CreateCompatibleDC(NULL);
2513 ::EnumFontFamiliesEx(hdc, &lf, enum_family_proc, (LPARAM)&fArray, 0);
2517 virtual int count() SK_OVERRIDE {
2518 return fArray.count();
2521 virtual void getStyle(int index, SkFontStyle* fs, SkString* styleName) SK_OVERRIDE {
2523 *fs = compute_fontstyle(fArray[index].elfLogFont);
2526 const ENUMLOGFONTEX& ref = fArray[index];
2527 // For some reason, ENUMLOGFONTEX and LOGFONT disagree on their type in the
2528 // non-unicode version.
2529 // ENUMLOGFONTEX uses BYTE
2530 // LOGFONT uses CHAR
2531 // Here we assert they that the style name is logically the same (size) as
2532 // a TCHAR, so we can use the same converter function.
2533 SkASSERT(sizeof(TCHAR) == sizeof(ref.elfStyle[0]));
2534 tchar_to_skstring((const TCHAR*)ref.elfStyle, styleName);
2538 virtual SkTypeface* createTypeface(int index) SK_OVERRIDE {
2539 return SkCreateTypefaceFromLOGFONT(fArray[index].elfLogFont);
2542 virtual SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE {
2544 return SkCreateTypefaceFromLOGFONT(fArray[0].elfLogFont);
2548 SkTDArray<ENUMLOGFONTEX> fArray;
2551 class SkFontMgrGDI : public SkFontMgr {
2555 sk_bzero(&lf, sizeof(lf));
2556 lf.lfCharSet = DEFAULT_CHARSET;
2558 HDC hdc = ::CreateCompatibleDC(NULL);
2559 ::EnumFontFamiliesEx(hdc, &lf, enum_family_proc, (LPARAM)&fLogFontArray, 0);
2564 virtual int onCountFamilies() const SK_OVERRIDE {
2565 return fLogFontArray.count();
2568 virtual void onGetFamilyName(int index, SkString* familyName) const SK_OVERRIDE {
2569 SkASSERT((unsigned)index < (unsigned)fLogFontArray.count());
2570 tchar_to_skstring(fLogFontArray[index].elfLogFont.lfFaceName, familyName);
2573 virtual SkFontStyleSet* onCreateStyleSet(int index) const SK_OVERRIDE {
2574 SkASSERT((unsigned)index < (unsigned)fLogFontArray.count());
2575 return SkNEW_ARGS(SkFontStyleSetGDI, (fLogFontArray[index].elfLogFont.lfFaceName));
2578 virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const SK_OVERRIDE {
2579 if (NULL == familyName) {
2580 familyName = ""; // do we need this check???
2583 logfont_for_name(familyName, &lf);
2584 return SkNEW_ARGS(SkFontStyleSetGDI, (lf.lfFaceName));
2587 virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
2588 const SkFontStyle& fontstyle) const SK_OVERRIDE {
2589 // could be in base impl
2590 SkAutoTUnref<SkFontStyleSet> sset(this->matchFamily(familyName));
2591 return sset->matchStyle(fontstyle);
2594 virtual SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember,
2595 const SkFontStyle& fontstyle) const SK_OVERRIDE {
2596 // could be in base impl
2597 SkString familyName;
2598 ((LogFontTypeface*)familyMember)->getFamilyName(&familyName);
2599 return this->matchFamilyStyle(familyName.c_str(), fontstyle);
2602 virtual SkTypeface* onCreateFromStream(SkStream* stream, int ttcIndex) const SK_OVERRIDE {
2603 return create_from_stream(stream);
2606 virtual SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const SK_OVERRIDE {
2607 // could be in base impl
2608 SkAutoTUnref<SkStream> stream(SkNEW_ARGS(SkMemoryStream, (data)));
2609 return this->createFromStream(stream);
2612 virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const SK_OVERRIDE {
2613 // could be in base impl
2614 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path));
2615 return this->createFromStream(stream);
2618 virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
2619 unsigned styleBits) const SK_OVERRIDE {
2621 if (NULL == familyName) {
2622 lf = get_default_font();
2624 logfont_for_name(familyName, &lf);
2626 setStyle(&lf, (SkTypeface::Style)styleBits);
2627 return SkCreateTypefaceFromLOGFONT(lf);
2631 SkTDArray<ENUMLOGFONTEX> fLogFontArray;
2634 ///////////////////////////////////////////////////////////////////////////////
2636 SkFontMgr* SkFontMgr_New_GDI() {
2637 return SkNEW(SkFontMgrGDI);