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"
16 #include "SkHRESULT.h"
17 #include "SkMaskGamma.h"
18 #include "SkMatrix22.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;
63 static bool bothZero(SkScalar a, SkScalar b) {
64 return 0 == a && 0 == b;
67 // returns false if there is any non-90-rotation or skew
68 static bool isAxisAligned(const SkScalerContext::Rec& rec) {
69 return 0 == rec.fPreSkewX &&
70 (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
71 bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
74 static bool needToRenderWithSkia(const SkScalerContext::Rec& rec) {
75 #ifdef SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
76 // What we really want to catch is when GDI will ignore the AA request and give
77 // us BW instead. Smallish rotated text is one heuristic, so this code is just
78 // an approximation. We shouldn't need to do this for larger sizes, but at those
79 // sizes, the quality difference gets less and less between our general
80 // scanconverter and GDI's.
81 if (SkMask::kA8_Format == rec.fMaskFormat && !isAxisAligned(rec)) {
85 return rec.getHinting() == SkPaint::kNo_Hinting || rec.getHinting() == SkPaint::kSlight_Hinting;
88 using namespace skia_advanced_typeface_metrics_utils;
90 static void tchar_to_skstring(const TCHAR t[], SkString* s) {
92 size_t sSize = WideCharToMultiByte(CP_UTF8, 0, t, -1, NULL, 0, NULL, NULL);
94 WideCharToMultiByte(CP_UTF8, 0, t, -1, s->writable_str(), sSize, NULL, NULL);
100 static void dcfontname_to_skstring(HDC deviceContext, const LOGFONT& lf, SkString* familyName) {
101 int fontNameLen; //length of fontName in TCHARS.
102 if (0 == (fontNameLen = GetTextFace(deviceContext, 0, NULL))) {
103 call_ensure_accessible(lf);
104 if (0 == (fontNameLen = GetTextFace(deviceContext, 0, NULL))) {
109 SkAutoSTArray<LF_FULLFACESIZE, TCHAR> fontName(fontNameLen+1);
110 if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) {
111 call_ensure_accessible(lf);
112 if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) {
117 tchar_to_skstring(fontName.get(), familyName);
120 static void make_canonical(LOGFONT* lf) {
122 lf->lfQuality = CLEARTYPE_QUALITY;//PROOF_QUALITY;
123 lf->lfCharSet = DEFAULT_CHARSET;
124 // lf->lfClipPrecision = 64;
127 static SkFontStyle get_style(const LOGFONT& lf) {
128 return SkFontStyle(lf.lfWeight,
130 lf.lfItalic ? SkFontStyle::kItalic_Slant : SkFontStyle::kUpright_Slant);
133 static inline FIXED SkFixedToFIXED(SkFixed x) {
134 return *(FIXED*)(&x);
136 static inline SkFixed SkFIXEDToFixed(FIXED x) {
137 return *(SkFixed*)(&x);
140 static inline FIXED SkScalarToFIXED(SkScalar x) {
141 return SkFixedToFIXED(SkScalarToFixed(x));
144 static inline SkScalar SkFIXEDToScalar(FIXED x) {
145 return SkFixedToScalar(SkFIXEDToFixed(x));
148 static unsigned calculateGlyphCount(HDC hdc, const LOGFONT& lf) {
149 TEXTMETRIC textMetric;
150 if (0 == GetTextMetrics(hdc, &textMetric)) {
151 textMetric.tmPitchAndFamily = TMPF_VECTOR;
152 call_ensure_accessible(lf);
153 GetTextMetrics(hdc, &textMetric);
156 if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) {
157 return textMetric.tmLastChar;
160 // The 'maxp' table stores the number of glyphs at offset 4, in 2 bytes.
162 if (GDI_ERROR != GetFontData(hdc, SkOTTableMaximumProfile::TAG, 4, &glyphs, sizeof(glyphs))) {
163 return SkEndian_SwapBE16(glyphs);
166 // Binary search for glyph count.
167 static const MAT2 mat2 = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
168 int32_t max = SK_MaxU16 + 1;
172 int32_t mid = min + ((max - min) / 2);
173 if (GetGlyphOutlineW(hdc, mid, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0,
174 NULL, &mat2) == GDI_ERROR) {
180 SkASSERT(min == max);
184 static unsigned calculateUPEM(HDC hdc, const LOGFONT& lf) {
185 TEXTMETRIC textMetric;
186 if (0 == GetTextMetrics(hdc, &textMetric)) {
187 textMetric.tmPitchAndFamily = TMPF_VECTOR;
188 call_ensure_accessible(lf);
189 GetTextMetrics(hdc, &textMetric);
192 if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) {
193 return textMetric.tmMaxCharWidth;
196 OUTLINETEXTMETRIC otm;
197 unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
199 call_ensure_accessible(lf);
200 otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
203 return (0 == otmRet) ? 0 : otm.otmEMSquare;
206 class LogFontTypeface : public SkTypeface {
208 LogFontTypeface(const SkFontStyle& style, const LOGFONT& lf, bool serializeAsStream)
209 : SkTypeface(style, SkTypefaceCache::NewFontID(), false)
211 , fSerializeAsStream(serializeAsStream)
214 // If the font has cubic outlines, it will not be rendered with ClearType.
215 HFONT font = CreateFontIndirect(&lf);
217 HDC deviceContext = ::CreateCompatibleDC(NULL);
218 HFONT savefont = (HFONT)SelectObject(deviceContext, font);
220 TEXTMETRIC textMetric;
221 if (0 == GetTextMetrics(deviceContext, &textMetric)) {
222 call_ensure_accessible(lf);
223 if (0 == GetTextMetrics(deviceContext, &textMetric)) {
224 textMetric.tmPitchAndFamily = TMPF_TRUETYPE;
228 ::SelectObject(deviceContext, savefont);
229 ::DeleteDC(deviceContext);
232 ::DeleteObject(font);
235 // The fixed pitch bit is set if the font is *not* fixed pitch.
236 this->setIsFixedPitch((textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0);
238 // Used a logfont on a memory context, should never get a device font.
239 // Therefore all TMPF_DEVICE will be PostScript (cubic) fonts.
240 fCanBeLCD = !((textMetric.tmPitchAndFamily & TMPF_VECTOR) &&
241 (textMetric.tmPitchAndFamily & TMPF_DEVICE));
245 bool fSerializeAsStream;
248 static LogFontTypeface* Create(const LOGFONT& lf) {
249 return new LogFontTypeface(get_style(lf), lf, false);
252 static void EnsureAccessible(const SkTypeface* face) {
253 call_ensure_accessible(static_cast<const LogFontTypeface*>(face)->fLogFont);
257 SkStreamAsset* onOpenStream(int* ttcIndex) const override;
258 SkScalerContext* onCreateScalerContext(const SkDescriptor*) const override;
259 void onFilterRec(SkScalerContextRec*) const override;
260 virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics(
261 SkAdvancedTypefaceMetrics::PerGlyphInfo,
262 const uint32_t*, uint32_t) const override;
263 void onGetFontDescriptor(SkFontDescriptor*, bool*) const override;
264 virtual int onCharsToGlyphs(const void* chars, Encoding encoding,
265 uint16_t glyphs[], int glyphCount) const override;
266 int onCountGlyphs() const override;
267 int onGetUPEM() const override;
268 void onGetFamilyName(SkString* familyName) const override;
269 SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override;
270 int onGetTableTags(SkFontTableTag tags[]) const override;
271 virtual size_t onGetTableData(SkFontTableTag, size_t offset,
272 size_t length, void* data) const override;
275 class FontMemResourceTypeface : public LogFontTypeface {
278 * The created FontMemResourceTypeface takes ownership of fontMemResource.
280 static FontMemResourceTypeface* Create(const LOGFONT& lf, HANDLE fontMemResource) {
281 return new FontMemResourceTypeface(get_style(lf), lf, fontMemResource);
285 void weak_dispose() const override {
286 RemoveFontMemResourceEx(fFontMemResource);
287 //SkTypefaceCache::Remove(this);
288 INHERITED::weak_dispose();
293 * Takes ownership of fontMemResource.
295 FontMemResourceTypeface(const SkFontStyle& style, const LOGFONT& lf, HANDLE fontMemResource)
296 : LogFontTypeface(style, lf, true), fFontMemResource(fontMemResource)
299 HANDLE fFontMemResource;
301 typedef LogFontTypeface INHERITED;
304 static const LOGFONT& get_default_font() {
305 static LOGFONT gDefaultFont;
309 static bool FindByLogFont(SkTypeface* face, const SkFontStyle& requestedStyle, void* ctx) {
310 LogFontTypeface* lface = static_cast<LogFontTypeface*>(face);
311 const LOGFONT* lf = reinterpret_cast<const LOGFONT*>(ctx);
314 get_style(lface->fLogFont) == requestedStyle &&
315 !memcmp(&lface->fLogFont, lf, sizeof(LOGFONT));
319 * This guy is public. It first searches the cache, and if a match is not found,
320 * it creates a new face.
322 SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT& origLF) {
325 SkTypeface* face = SkTypefaceCache::FindByProcAndRef(FindByLogFont, &lf);
327 face = LogFontTypeface::Create(lf);
328 SkTypefaceCache::Add(face, get_style(lf));
334 * The created SkTypeface takes ownership of fontMemResource.
336 SkTypeface* SkCreateFontMemResourceTypefaceFromLOGFONT(const LOGFONT& origLF, HANDLE fontMemResource) {
339 // We'll never get a cache hit, so no point in putting this in SkTypefaceCache.
340 return FontMemResourceTypeface::Create(lf, fontMemResource);
346 void SkLOGFONTFromTypeface(const SkTypeface* face, LOGFONT* lf) {
348 *lf = get_default_font();
350 *lf = static_cast<const LogFontTypeface*>(face)->fLogFont;
354 // Construct Glyph to Unicode table.
355 // Unicode code points that require conjugate pairs in utf16 are not
357 // TODO(arthurhsu): Add support for conjugate pairs. It looks like that may
358 // require parsing the TTF cmap table (platform 4, encoding 12) directly instead
359 // of calling GetFontUnicodeRange().
360 static void populate_glyph_to_unicode(HDC fontHdc, const unsigned glyphCount,
361 SkTDArray<SkUnichar>* glyphToUnicode) {
362 DWORD glyphSetBufferSize = GetFontUnicodeRanges(fontHdc, NULL);
363 if (!glyphSetBufferSize) {
367 SkAutoTDeleteArray<BYTE> glyphSetBuffer(new BYTE[glyphSetBufferSize]);
369 reinterpret_cast<LPGLYPHSET>(glyphSetBuffer.get());
370 if (GetFontUnicodeRanges(fontHdc, glyphSet) != glyphSetBufferSize) {
374 glyphToUnicode->setCount(glyphCount);
375 memset(glyphToUnicode->begin(), 0, glyphCount * sizeof(SkUnichar));
376 for (DWORD i = 0; i < glyphSet->cRanges; ++i) {
377 // There is no guarantee that within a Unicode range, the corresponding
378 // glyph id in a font file are continuous. So, even if we have ranges,
379 // we can't just use the first and last entry of the range to compute
380 // result. We need to enumerate them one by one.
381 int count = glyphSet->ranges[i].cGlyphs;
382 SkAutoTArray<WCHAR> chars(count + 1);
383 chars[count] = 0; // termintate string
384 SkAutoTArray<WORD> glyph(count);
385 for (USHORT j = 0; j < count; ++j) {
386 chars[j] = glyphSet->ranges[i].wcLow + j;
388 GetGlyphIndicesW(fontHdc, chars.get(), count, glyph.get(),
389 GGI_MARK_NONEXISTING_GLYPHS);
390 // If the glyph ID is valid, and the glyph is not mapped, then we will
391 // fill in the char id into the vector. If the glyph is mapped already,
393 // TODO(arthurhsu): better improve this. e.g. Get all used char ids from
394 // font cache, then generate this mapping table from there. It's
395 // unlikely to have collisions since glyph reuse happens mostly for
396 // different Unicode pages.
397 for (USHORT j = 0; j < count; ++j) {
398 if (glyph[j] != 0xffff && glyph[j] < glyphCount &&
399 (*glyphToUnicode)[glyph[j]] == 0) {
400 (*glyphToUnicode)[glyph[j]] = chars[j];
406 //////////////////////////////////////////////////////////////////////////////////////
408 static int alignTo32(int n) {
409 return (n + 31) & ~31;
412 struct MyBitmapInfo : public BITMAPINFO {
413 RGBQUAD fMoreSpaceForColors[1];
423 fWidth = fHeight = 0;
436 void init(HFONT font, const XFORM& xform) {
441 const void* draw(const SkGlyph&, bool isBW, size_t* srcRBPtr);
448 void* fBits; // points into fBM
454 const void* HDCOffscreen::draw(const SkGlyph& glyph, bool isBW,
456 // Can we share the scalercontext's fDDC, so we don't need to create
457 // a separate fDC here?
459 fDC = CreateCompatibleDC(0);
463 SetGraphicsMode(fDC, GM_ADVANCED);
464 SetBkMode(fDC, TRANSPARENT);
465 SetTextAlign(fDC, TA_LEFT | TA_BASELINE);
466 SelectObject(fDC, fFont);
468 COLORREF color = 0x00FFFFFF;
469 SkDEBUGCODE(COLORREF prev =) SetTextColor(fDC, color);
470 SkASSERT(prev != CLR_INVALID);
473 if (fBM && (fIsBW != isBW || fWidth < glyph.fWidth || fHeight < glyph.fHeight)) {
479 fWidth = SkMax32(fWidth, glyph.fWidth);
480 fHeight = SkMax32(fHeight, glyph.fHeight);
482 int biWidth = isBW ? alignTo32(fWidth) : fWidth;
486 sk_bzero(&info, sizeof(info));
488 RGBQUAD blackQuad = { 0, 0, 0, 0 };
489 RGBQUAD whiteQuad = { 0xFF, 0xFF, 0xFF, 0 };
490 info.bmiColors[0] = blackQuad;
491 info.bmiColors[1] = whiteQuad;
493 info.bmiHeader.biSize = sizeof(info.bmiHeader);
494 info.bmiHeader.biWidth = biWidth;
495 info.bmiHeader.biHeight = fHeight;
496 info.bmiHeader.biPlanes = 1;
497 info.bmiHeader.biBitCount = isBW ? 1 : 32;
498 info.bmiHeader.biCompression = BI_RGB;
500 info.bmiHeader.biClrUsed = 2;
502 fBM = CreateDIBSection(fDC, &info, DIB_RGB_COLORS, &fBits, 0, 0);
506 SelectObject(fDC, fBM);
510 size_t srcRB = isBW ? (biWidth >> 3) : (fWidth << 2);
511 size_t size = fHeight * srcRB;
512 memset(fBits, 0, size);
514 XFORM xform = fXform;
515 xform.eDx = (float)-glyph.fLeft;
516 xform.eDy = (float)-glyph.fTop;
517 SetWorldTransform(fDC, &xform);
519 uint16_t glyphID = glyph.getGlyphID();
520 BOOL ret = ExtTextOutW(fDC, 0, 0, ETO_GLYPH_INDEX, NULL, reinterpret_cast<LPCWSTR>(&glyphID), 1, NULL);
526 // offset to the start of the image
527 return (const char*)fBits + (fHeight - glyph.fHeight) * srcRB;
530 //////////////////////////////////////////////////////////////////////////////
531 #define BUFFERSIZE (1 << 13)
533 class SkScalerContext_GDI : public SkScalerContext {
535 SkScalerContext_GDI(SkTypeface*, const SkDescriptor* desc);
536 virtual ~SkScalerContext_GDI();
538 // Returns true if the constructor was able to complete all of its
539 // initializations (which may include calling GDI).
540 bool isValid() const;
543 unsigned generateGlyphCount() override;
544 uint16_t generateCharToGlyph(SkUnichar uni) override;
545 void generateAdvance(SkGlyph* glyph) override;
546 void generateMetrics(SkGlyph* glyph) override;
547 void generateImage(const SkGlyph& glyph) override;
548 void generatePath(const SkGlyph& glyph, SkPath* path) override;
549 void generateFontMetrics(SkPaint::FontMetrics*) override;
552 DWORD getGDIGlyphPath(const SkGlyph& glyph, UINT flags,
553 SkAutoSTMalloc<BUFFERSIZE, uint8_t>* glyphbuf);
555 HDCOffscreen fOffscreen;
556 /** fGsA is the non-rotational part of total matrix without the text height scale.
557 * Used to find the magnitude of advances.
560 /** The total matrix without the textSize. */
562 /** Scales font to EM size. */
570 /** The total matrix which also removes EM scale. */
571 SkMatrix fHiResMatrix;
572 /** fG_inv is the inverse of the rotational part of the total matrix.
573 * Used to set the direction of advances.
577 kTrueType_Type, kBitmap_Type, kLine_Type
582 static FIXED float2FIXED(float x) {
583 return SkFixedToFIXED(SkFloatToFixed(x));
586 static BYTE compute_quality(const SkScalerContext::Rec& rec) {
587 switch (rec.fMaskFormat) {
588 case SkMask::kBW_Format:
589 return NONANTIALIASED_QUALITY;
590 case SkMask::kLCD16_Format:
591 return CLEARTYPE_QUALITY;
593 if (rec.fFlags & SkScalerContext::kGenA8FromLCD_Flag) {
594 return CLEARTYPE_QUALITY;
596 return ANTIALIASED_QUALITY;
601 SkScalerContext_GDI::SkScalerContext_GDI(SkTypeface* rawTypeface,
602 const SkDescriptor* desc)
603 : SkScalerContext(rawTypeface, desc)
610 LogFontTypeface* typeface = reinterpret_cast<LogFontTypeface*>(rawTypeface);
612 fDDC = ::CreateCompatibleDC(NULL);
616 SetGraphicsMode(fDDC, GM_ADVANCED);
617 SetBkMode(fDDC, TRANSPARENT);
619 // When GDI hinting, remove the entire Y scale from sA and GsA. (Prevents 'linear' metrics.)
620 // When not hinting, remove only the integer Y scale from sA and GsA. (Applied by GDI.)
621 SkScalerContextRec::PreMatrixScale scaleConstraints =
622 (fRec.getHinting() == SkPaint::kNo_Hinting || fRec.getHinting() == SkPaint::kSlight_Hinting)
623 ? SkScalerContextRec::kVerticalInteger_PreMatrixScale
624 : SkScalerContextRec::kVertical_PreMatrixScale;
629 fRec.computeMatrices(scaleConstraints, &scale, &sA, &GsA, &fG_inv, &A);
631 fGsA.eM11 = SkScalarToFIXED(GsA.get(SkMatrix::kMScaleX));
632 fGsA.eM12 = SkScalarToFIXED(-GsA.get(SkMatrix::kMSkewY)); // This should be ~0.
633 fGsA.eM21 = SkScalarToFIXED(-GsA.get(SkMatrix::kMSkewX));
634 fGsA.eM22 = SkScalarToFIXED(GsA.get(SkMatrix::kMScaleY));
636 // When not hinting, scale was computed with kVerticalInteger, so is already an integer.
637 // The sA and GsA transforms will be used to create 'linear' metrics.
639 // When hinting, scale was computed with kVertical, stating that our port can handle
640 // non-integer scales. This is done so that sA and GsA are computed without any 'residual'
641 // scale in them, preventing 'linear' metrics. However, GDI cannot actually handle non-integer
642 // scales so we need to round in this case. This is fine, since all of the scale has been
643 // removed from sA and GsA, so GDI will be handling the scale completely.
644 SkScalar gdiTextSize = SkScalarRoundToScalar(scale.fY);
646 // GDI will not accept a size of zero, so round the range [0, 1] to 1.
647 // If the size was non-zero, the scale factors will also be non-zero and 1px tall text is drawn.
648 // If the size actually was zero, the scale factors will also be zero, so GDI will draw nothing.
649 if (gdiTextSize == 0) {
650 gdiTextSize = SK_Scalar1;
653 LOGFONT lf = typeface->fLogFont;
654 lf.lfHeight = -SkScalarTruncToInt(gdiTextSize);
655 lf.lfQuality = compute_quality(fRec);
656 fFont = CreateFontIndirect(&lf);
661 fSavefont = (HFONT)SelectObject(fDDC, fFont);
663 if (0 == GetTextMetrics(fDDC, &fTM)) {
664 call_ensure_accessible(lf);
665 if (0 == GetTextMetrics(fDDC, &fTM)) {
666 fTM.tmPitchAndFamily = TMPF_TRUETYPE;
671 if (fTM.tmPitchAndFamily & TMPF_VECTOR) {
672 // Used a logfont on a memory context, should never get a device font.
673 // Therefore all TMPF_DEVICE will be PostScript fonts.
675 // If TMPF_VECTOR is set, one of TMPF_TRUETYPE or TMPF_DEVICE means that
676 // we have an outline font. Otherwise we have a vector FON, which is
677 // scalable, but not an outline font.
678 // This was determined by testing with Type1 PFM/PFB and
679 // OpenTypeCFF OTF, as well as looking at Wine bugs and sources.
680 if (fTM.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_DEVICE)) {
681 // Truetype or PostScript.
682 fType = SkScalerContext_GDI::kTrueType_Type;
685 fType = SkScalerContext_GDI::kLine_Type;
688 // fPost2x2 is column-major, left handed (y down).
689 // XFORM 2x2 is row-major, left handed (y down).
690 xform.eM11 = SkScalarToFloat(sA.get(SkMatrix::kMScaleX));
691 xform.eM12 = SkScalarToFloat(sA.get(SkMatrix::kMSkewY));
692 xform.eM21 = SkScalarToFloat(sA.get(SkMatrix::kMSkewX));
693 xform.eM22 = SkScalarToFloat(sA.get(SkMatrix::kMScaleY));
697 // MAT2 is row major, right handed (y up).
698 fMat22.eM11 = float2FIXED(xform.eM11);
699 fMat22.eM12 = float2FIXED(-xform.eM12);
700 fMat22.eM21 = float2FIXED(-xform.eM21);
701 fMat22.eM22 = float2FIXED(xform.eM22);
703 if (needToRenderWithSkia(fRec)) {
704 this->forceGenerateImageFromPath();
707 // Create a hires matrix if we need linear metrics.
708 if (this->isSubpixel()) {
709 OUTLINETEXTMETRIC otm;
710 UINT success = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
712 call_ensure_accessible(lf);
713 success = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
716 SkScalar upem = SkIntToScalar(otm.otmEMSquare);
718 SkScalar gdiTextSizeToEMScale = upem / gdiTextSize;
719 fHighResMat22.eM11 = float2FIXED(gdiTextSizeToEMScale);
720 fHighResMat22.eM12 = float2FIXED(0);
721 fHighResMat22.eM21 = float2FIXED(0);
722 fHighResMat22.eM22 = float2FIXED(gdiTextSizeToEMScale);
724 SkScalar removeEMScale = SkScalarInvert(upem);
726 fHiResMatrix.preScale(removeEMScale, removeEMScale);
732 fType = SkScalerContext_GDI::kBitmap_Type;
741 // fPost2x2 is column-major, left handed (y down).
742 // MAT2 is row major, right handed (y up).
743 fMat22.eM11 = SkScalarToFIXED(fRec.fPost2x2[0][0]);
744 fMat22.eM12 = SkScalarToFIXED(-fRec.fPost2x2[1][0]);
745 fMat22.eM21 = SkScalarToFIXED(-fRec.fPost2x2[0][1]);
746 fMat22.eM22 = SkScalarToFIXED(fRec.fPost2x2[1][1]);
749 fOffscreen.init(fFont, xform);
752 SkScalerContext_GDI::~SkScalerContext_GDI() {
754 ::SelectObject(fDDC, fSavefont);
758 ::DeleteObject(fFont);
761 ::ScriptFreeCache(&fSC);
765 bool SkScalerContext_GDI::isValid() const {
766 return fDDC && fFont;
769 unsigned SkScalerContext_GDI::generateGlyphCount() {
770 if (fGlyphCount < 0) {
771 fGlyphCount = calculateGlyphCount(
772 fDDC, static_cast<const LogFontTypeface*>(this->getTypeface())->fLogFont);
777 uint16_t SkScalerContext_GDI::generateCharToGlyph(SkUnichar utf32) {
780 // TODO(ctguil): Support characters that generate more than one glyph.
781 if (SkUTF16_FromUnichar(utf32, (uint16_t*)utf16) == 1) {
782 // Type1 fonts fail with uniscribe API. Use GetGlyphIndices for plane 0.
784 /** Real documentation for GetGlyphIndiciesW:
786 * When GGI_MARK_NONEXISTING_GLYPHS is not specified and a character does not map to a
787 * glyph, then the 'default character's glyph is returned instead. The 'default character'
788 * is available in fTM.tmDefaultChar. FON fonts have a default character, and there exists
789 * a usDefaultChar in the 'OS/2' table, version 2 and later. If there is no
790 * 'default character' specified by the font, then often the first character found is used.
792 * When GGI_MARK_NONEXISTING_GLYPHS is specified and a character does not map to a glyph,
793 * then the glyph 0xFFFF is used. In Windows XP and earlier, Bitmap/Vector FON usually use
794 * glyph 0x1F instead ('Terminal' appears to be special, returning 0xFFFF).
795 * Type1 PFM/PFB, TT, OT TT, OT CFF all appear to use 0xFFFF, even on XP.
797 DWORD result = GetGlyphIndicesW(fDDC, utf16, 1, &index, GGI_MARK_NONEXISTING_GLYPHS);
798 if (result == GDI_ERROR
801 (fType == SkScalerContext_GDI::kBitmap_Type ||
802 fType == SkScalerContext_GDI::kLine_Type)
803 /*&& winVer < Vista */)
809 // Use uniscribe to detemine glyph index for non-BMP characters.
810 static const int numWCHAR = 2;
811 static const int maxItems = 2;
812 // MSDN states that this can be NULL, but some things don't work then.
813 SCRIPT_CONTROL sc = { 0 };
814 // Add extra item to SCRIPT_ITEM to work around a bug (now documented).
815 // https://bugzilla.mozilla.org/show_bug.cgi?id=366643
816 SCRIPT_ITEM si[maxItems + 1];
818 HRZM(ScriptItemize(utf16, numWCHAR, maxItems, &sc, NULL, si, &numItems),
819 "Could not itemize character.");
821 // Sometimes ScriptShape cannot find a glyph for a non-BMP and returns 2 space glyphs.
822 static const int maxGlyphs = 2;
823 SCRIPT_VISATTR vsa[maxGlyphs];
824 WORD outGlyphs[maxGlyphs];
825 WORD logClust[numWCHAR];
827 HRZM(ScriptShape(fDDC, &fSC, utf16, numWCHAR, maxGlyphs, &si[0].a,
828 outGlyphs, logClust, vsa, &numGlyphs),
829 "Could not shape character.");
830 if (1 == numGlyphs) {
831 index = outGlyphs[0];
837 void SkScalerContext_GDI::generateAdvance(SkGlyph* glyph) {
838 this->generateMetrics(glyph);
841 void SkScalerContext_GDI::generateMetrics(SkGlyph* glyph) {
844 if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) {
846 WORD glyphs = glyph->getGlyphID();
847 if (0 == GetTextExtentPointI(fDDC, &glyphs, 1, &size)) {
848 glyph->fWidth = SkToS16(fTM.tmMaxCharWidth);
850 glyph->fWidth = SkToS16(size.cx);
852 glyph->fHeight = SkToS16(size.cy);
854 glyph->fTop = SkToS16(-fTM.tmAscent);
855 // Bitmap FON cannot underhang, but vector FON may.
856 // There appears no means of determining underhang of vector FON.
857 glyph->fLeft = SkToS16(0);
858 glyph->fAdvanceX = SkIntToFixed(glyph->fWidth);
859 glyph->fAdvanceY = 0;
861 // Vector FON will transform nicely, but bitmap FON do not.
862 if (fType == SkScalerContext_GDI::kLine_Type) {
863 SkRect bounds = SkRect::MakeXYWH(glyph->fLeft, glyph->fTop,
864 glyph->fWidth, glyph->fHeight);
866 m.setAll(SkFIXEDToScalar(fMat22.eM11), -SkFIXEDToScalar(fMat22.eM21), 0,
867 -SkFIXEDToScalar(fMat22.eM12), SkFIXEDToScalar(fMat22.eM22), 0,
870 bounds.roundOut(&bounds);
871 glyph->fLeft = SkScalarTruncToInt(bounds.fLeft);
872 glyph->fTop = SkScalarTruncToInt(bounds.fTop);
873 glyph->fWidth = SkScalarTruncToInt(bounds.width());
874 glyph->fHeight = SkScalarTruncToInt(bounds.height());
877 // Apply matrix to advance.
878 glyph->fAdvanceY = SkFixedMul(-SkFIXEDToFixed(fMat22.eM12), glyph->fAdvanceX);
879 glyph->fAdvanceX = SkFixedMul(SkFIXEDToFixed(fMat22.eM11), glyph->fAdvanceX);
884 UINT glyphId = glyph->getGlyphID();
887 sk_bzero(&gm, sizeof(gm));
889 DWORD status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
890 if (GDI_ERROR == status) {
891 LogFontTypeface::EnsureAccessible(this->getTypeface());
892 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
893 if (GDI_ERROR == status) {
894 glyph->zeroMetrics();
900 // The black box is either the embedded bitmap size or the outline extent.
901 // It is 1x1 if nothing is to be drawn, but will also be 1x1 if something very small
902 // is to be drawn, like a '.'. We need to outset '.' but do not wish to outset ' '.
903 if (1 == gm.gmBlackBoxX && 1 == gm.gmBlackBoxY) {
904 // If GetGlyphOutline with GGO_NATIVE returns 0, we know there was no outline.
905 DWORD bufferSize = GetGlyphOutlineW(fDDC, glyphId, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
906 empty = (0 == bufferSize);
909 glyph->fTop = SkToS16(-gm.gmptGlyphOrigin.y);
910 glyph->fLeft = SkToS16(gm.gmptGlyphOrigin.x);
915 // Outset, since the image may bleed out of the black box.
916 // For embedded bitmaps the black box should be exact.
917 // For outlines we need to outset by 1 in all directions for bleed.
918 // For ClearType we need to outset by 2 for bleed.
919 glyph->fWidth = gm.gmBlackBoxX + 4;
920 glyph->fHeight = gm.gmBlackBoxY + 4;
924 glyph->fAdvanceX = SkIntToFixed(gm.gmCellIncX);
925 glyph->fAdvanceY = SkIntToFixed(gm.gmCellIncY);
926 glyph->fRsbDelta = 0;
927 glyph->fLsbDelta = 0;
929 if (this->isSubpixel()) {
930 sk_bzero(&gm, sizeof(gm));
931 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fHighResMat22);
932 if (GDI_ERROR != status) {
934 fHiResMatrix.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance);
935 glyph->fAdvanceX = SkScalarToFixed(advance.fX);
936 glyph->fAdvanceY = SkScalarToFixed(advance.fY);
938 } else if (!isAxisAligned(this->fRec)) {
939 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fGsA);
940 if (GDI_ERROR != status) {
942 fG_inv.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance);
943 glyph->fAdvanceX = SkScalarToFixed(advance.fX);
944 glyph->fAdvanceY = SkScalarToFixed(advance.fY);
949 static const MAT2 gMat2Identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
950 void SkScalerContext_GDI::generateFontMetrics(SkPaint::FontMetrics* metrics) {
951 if (NULL == metrics) {
954 sk_bzero(metrics, sizeof(*metrics));
958 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
959 if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) {
961 metrics->fTop = SkIntToScalar(-fTM.tmAscent);
962 metrics->fAscent = SkIntToScalar(-fTM.tmAscent);
963 metrics->fDescent = SkIntToScalar(fTM.tmDescent);
964 metrics->fBottom = SkIntToScalar(fTM.tmDescent);
965 metrics->fLeading = SkIntToScalar(fTM.tmExternalLeading);
966 metrics->fAvgCharWidth = SkIntToScalar(fTM.tmAveCharWidth);
967 metrics->fMaxCharWidth = SkIntToScalar(fTM.tmMaxCharWidth);
969 metrics->fXMax = metrics->fMaxCharWidth;
970 //metrics->fXHeight = 0;
971 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
976 OUTLINETEXTMETRIC otm;
978 uint32_t ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
980 LogFontTypeface::EnsureAccessible(this->getTypeface());
981 ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
987 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
988 metrics->fTop = SkIntToScalar(-otm.otmrcFontBox.top);
989 metrics->fAscent = SkIntToScalar(-otm.otmAscent);
990 metrics->fDescent = SkIntToScalar(-otm.otmDescent);
991 metrics->fBottom = SkIntToScalar(-otm.otmrcFontBox.bottom);
992 metrics->fLeading = SkIntToScalar(otm.otmLineGap);
993 metrics->fAvgCharWidth = SkIntToScalar(otm.otmTextMetrics.tmAveCharWidth);
994 metrics->fMaxCharWidth = SkIntToScalar(otm.otmTextMetrics.tmMaxCharWidth);
995 metrics->fXMin = SkIntToScalar(otm.otmrcFontBox.left);
996 metrics->fXMax = SkIntToScalar(otm.otmrcFontBox.right);
998 metrics->fUnderlineThickness = SkIntToScalar(otm.otmsUnderscoreSize);
999 metrics->fUnderlinePosition = -SkIntToScalar(otm.otmsUnderscorePosition);
1001 metrics->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
1002 metrics->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
1004 metrics->fXHeight = SkIntToScalar(otm.otmsXHeight);
1006 sk_bzero(&gm, sizeof(gm));
1007 DWORD len = GetGlyphOutlineW(fDDC, 'x', GGO_METRICS, &gm, 0, 0, &gMat2Identity);
1008 if (len != GDI_ERROR && gm.gmBlackBoxY > 0) {
1009 metrics->fXHeight = SkIntToScalar(gm.gmBlackBoxY);
1013 ////////////////////////////////////////////////////////////////////////////////////////
1015 #define SK_SHOW_TEXT_BLIT_COVERAGE 0
1017 static void build_power_table(uint8_t table[], float ee) {
1018 for (int i = 0; i < 256; i++) {
1019 float x = i / 255.f;
1020 x = sk_float_pow(x, ee);
1021 int xx = SkScalarRoundToInt(x * 255);
1022 table[i] = SkToU8(xx);
1027 * This will invert the gamma applied by GDI (gray-scale antialiased), so we
1028 * can get linear values.
1030 * GDI grayscale appears to use a hard-coded gamma of 2.3.
1032 * GDI grayscale appears to draw using the black and white rasterizer at four
1033 * times the size and then downsamples to compute the coverage mask. As a
1034 * result there are only seventeen total grays. This lack of fidelity means
1035 * that shifting into other color spaces is imprecise.
1037 static const uint8_t* getInverseGammaTableGDI() {
1038 // Since build_power_table is idempotent, many threads can build gTableGdi
1041 // Microsoft Specific:
1042 // Making gInited volatile provides read-aquire and write-release in vc++.
1043 // In VS2012, see compiler option /volatile:(ms|iso).
1044 // Replace with C++11 atomics when possible.
1045 static volatile bool gInited;
1046 static uint8_t gTableGdi[256];
1048 // Need a L/L (read) barrier (full acquire not needed). If gInited is observed
1049 // true then gTableGdi is observable, but it must be requested.
1051 build_power_table(gTableGdi, 2.3f);
1052 // Need a S/S (write) barrier (full release not needed) here so that this
1053 // write to gInited becomes observable after gTableGdi.
1060 * This will invert the gamma applied by GDI ClearType, so we can get linear
1063 * GDI ClearType uses SPI_GETFONTSMOOTHINGCONTRAST / 1000 as the gamma value.
1064 * If this value is not specified, the default is a gamma of 1.4.
1066 static const uint8_t* getInverseGammaTableClearType() {
1067 // We don't expect SPI_GETFONTSMOOTHINGCONTRAST to ever change, so building
1068 // gTableClearType with build_power_table is effectively idempotent.
1070 // Microsoft Specific:
1071 // Making gInited volatile provides read-aquire and write-release in vc++.
1072 // In VS2012, see compiler option /volatile:(ms|iso).
1073 // Replace with C++11 atomics when possible.
1074 static volatile bool gInited;
1075 static uint8_t gTableClearType[256];
1077 // Need a L/L (read) barrier (acquire not needed). If gInited is observed
1078 // true then gTableClearType is observable, but it must be requested.
1081 if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &level, 0) || !level) {
1082 // can't get the data, so use a default
1085 build_power_table(gTableClearType, level / 1000.0f);
1086 // Need a S/S (write) barrier (release not needed) here so that this
1087 // write to gInited becomes observable after gTableClearType.
1090 return gTableClearType;
1093 #include "SkColorPriv.h"
1095 //Cannot assume that the input rgb is gray due to possible setting of kGenA8FromLCD_Flag.
1096 template<bool APPLY_PREBLEND>
1097 static inline uint8_t rgb_to_a8(SkGdiRGB rgb, const uint8_t* table8) {
1098 U8CPU r = (rgb >> 16) & 0xFF;
1099 U8CPU g = (rgb >> 8) & 0xFF;
1100 U8CPU b = (rgb >> 0) & 0xFF;
1101 return sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8);
1104 template<bool APPLY_PREBLEND>
1105 static inline uint16_t rgb_to_lcd16(SkGdiRGB rgb, const uint8_t* tableR,
1106 const uint8_t* tableG,
1107 const uint8_t* tableB) {
1108 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
1109 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG);
1110 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB);
1111 #if SK_SHOW_TEXT_BLIT_COVERAGE
1112 r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10);
1114 return SkPack888ToRGB16(r, g, b);
1117 // Is this GDI color neither black nor white? If so, we have to keep this
1118 // image as is, rather than smashing it down to a BW mask.
1120 // returns int instead of bool, since we don't want/have to pay to convert
1121 // the zero/non-zero value into a bool
1122 static int is_not_black_or_white(SkGdiRGB c) {
1123 // same as (but faster than)
1125 // return 0 == c || 0x00FFFFFF == c;
1126 return (c + (c & 1)) & 0x00FFFFFF;
1129 static bool is_rgb_really_bw(const SkGdiRGB* src, int width, int height, size_t srcRB) {
1130 for (int y = 0; y < height; ++y) {
1131 for (int x = 0; x < width; ++x) {
1132 if (is_not_black_or_white(src[x])) {
1136 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1141 // gdi's bitmap is upside-down, so we reverse dst walking in Y
1142 // whenever we copy it into skia's buffer
1143 static void rgb_to_bw(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
1144 const SkGlyph& glyph) {
1145 const int width = glyph.fWidth;
1146 const size_t dstRB = (width + 7) >> 3;
1147 uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1149 int byteCount = width >> 3;
1150 int bitCount = width & 7;
1152 // adjust srcRB to skip the values in our byteCount loop,
1153 // since we increment src locally there
1154 srcRB -= byteCount * 8 * sizeof(SkGdiRGB);
1156 for (int y = 0; y < glyph.fHeight; ++y) {
1157 if (byteCount > 0) {
1158 for (int i = 0; i < byteCount; ++i) {
1160 byte |= src[0] & (1 << 7);
1161 byte |= src[1] & (1 << 6);
1162 byte |= src[2] & (1 << 5);
1163 byte |= src[3] & (1 << 4);
1164 byte |= src[4] & (1 << 3);
1165 byte |= src[5] & (1 << 2);
1166 byte |= src[6] & (1 << 1);
1167 byte |= src[7] & (1 << 0);
1174 unsigned mask = 0x80;
1175 for (int i = 0; i < bitCount; i++) {
1176 byte |= src[i] & mask;
1179 dst[byteCount] = byte;
1181 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1184 #if SK_SHOW_TEXT_BLIT_COVERAGE
1185 if (glyph.fWidth > 0 && glyph.fHeight > 0) {
1186 uint8_t* first = (uint8_t*)glyph.fImage;
1187 uint8_t* last = (uint8_t*)((char*)glyph.fImage + glyph.fHeight * dstRB - 1);
1189 *last |= bitCount == 0 ? 1 : 1 << (8 - bitCount);
1194 template<bool APPLY_PREBLEND>
1195 static void rgb_to_a8(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
1196 const SkGlyph& glyph, const uint8_t* table8) {
1197 const size_t dstRB = glyph.rowBytes();
1198 const int width = glyph.fWidth;
1199 uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1201 for (int y = 0; y < glyph.fHeight; y++) {
1202 for (int i = 0; i < width; i++) {
1203 dst[i] = rgb_to_a8<APPLY_PREBLEND>(src[i], table8);
1204 #if SK_SHOW_TEXT_BLIT_COVERAGE
1205 dst[i] = SkMax32(dst[i], 10);
1208 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1213 template<bool APPLY_PREBLEND>
1214 static void rgb_to_lcd16(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph,
1215 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
1216 const size_t dstRB = glyph.rowBytes();
1217 const int width = glyph.fWidth;
1218 uint16_t* SK_RESTRICT dst = (uint16_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1220 for (int y = 0; y < glyph.fHeight; y++) {
1221 for (int i = 0; i < width; i++) {
1222 dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(src[i], tableR, tableG, tableB);
1224 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
1225 dst = (uint16_t*)((char*)dst - dstRB);
1229 static inline unsigned clamp255(unsigned x) {
1231 return x - (x >> 8);
1234 void SkScalerContext_GDI::generateImage(const SkGlyph& glyph) {
1237 const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat;
1238 const bool isAA = !isLCD(fRec);
1241 const void* bits = fOffscreen.draw(glyph, isBW, &srcRB);
1243 LogFontTypeface::EnsureAccessible(this->getTypeface());
1244 bits = fOffscreen.draw(glyph, isBW, &srcRB);
1246 sk_bzero(glyph.fImage, glyph.computeImageSize());
1252 const uint8_t* table;
1253 //The offscreen contains a GDI blit if isAA and kGenA8FromLCD_Flag is not set.
1254 //Otherwise the offscreen contains a ClearType blit.
1255 if (isAA && !(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag)) {
1256 table = getInverseGammaTableGDI();
1258 table = getInverseGammaTableClearType();
1260 //Note that the following cannot really be integrated into the
1261 //pre-blend, since we may not be applying the pre-blend; when we aren't
1262 //applying the pre-blend it means that a filter wants linear anyway.
1263 //Other code may also be applying the pre-blend, so we'd need another
1264 //one with this and one without.
1265 SkGdiRGB* addr = (SkGdiRGB*)bits;
1266 for (int y = 0; y < glyph.fHeight; ++y) {
1267 for (int x = 0; x < glyph.fWidth; ++x) {
1268 int r = (addr[x] >> 16) & 0xFF;
1269 int g = (addr[x] >> 8) & 0xFF;
1270 int b = (addr[x] >> 0) & 0xFF;
1271 addr[x] = (table[r] << 16) | (table[g] << 8) | table[b];
1273 addr = SkTAddOffset<SkGdiRGB>(addr, srcRB);
1277 int width = glyph.fWidth;
1278 size_t dstRB = glyph.rowBytes();
1280 const uint8_t* src = (const uint8_t*)bits;
1281 uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1282 for (int y = 0; y < glyph.fHeight; y++) {
1283 memcpy(dst, src, dstRB);
1287 #if SK_SHOW_TEXT_BLIT_COVERAGE
1288 if (glyph.fWidth > 0 && glyph.fHeight > 0) {
1289 int bitCount = width & 7;
1290 uint8_t* first = (uint8_t*)glyph.fImage;
1291 uint8_t* last = (uint8_t*)((char*)glyph.fImage + glyph.fHeight * dstRB - 1);
1293 *last |= bitCount == 0 ? 1 : 1 << (8 - bitCount);
1297 // since the caller may require A8 for maskfilters, we can't check for BW
1298 // ... until we have the caller tell us that explicitly
1299 const SkGdiRGB* src = (const SkGdiRGB*)bits;
1300 if (fPreBlend.isApplicable()) {
1301 rgb_to_a8<true>(src, srcRB, glyph, fPreBlend.fG);
1303 rgb_to_a8<false>(src, srcRB, glyph, fPreBlend.fG);
1306 const SkGdiRGB* src = (const SkGdiRGB*)bits;
1307 if (is_rgb_really_bw(src, width, glyph.fHeight, srcRB)) {
1308 rgb_to_bw(src, srcRB, glyph);
1309 ((SkGlyph*)&glyph)->fMaskFormat = SkMask::kBW_Format;
1311 SkASSERT(SkMask::kLCD16_Format == glyph.fMaskFormat);
1312 if (fPreBlend.isApplicable()) {
1313 rgb_to_lcd16<true>(src, srcRB, glyph,
1314 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1316 rgb_to_lcd16<false>(src, srcRB, glyph,
1317 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
1323 class GDIGlyphbufferPointIter {
1325 GDIGlyphbufferPointIter(const uint8_t* glyphbuf, DWORD total_size)
1326 : fHeaderIter(glyphbuf, total_size), fCurveIter(), fPointIter()
1329 POINTFX const * next() {
1331 if (!fCurveIter.isSet()) {
1332 const TTPOLYGONHEADER* header = fHeaderIter.next();
1333 if (NULL == header) {
1336 fCurveIter.set(header);
1337 const TTPOLYCURVE* curve = fCurveIter.next();
1338 if (NULL == curve) {
1341 fPointIter.set(curve);
1342 return &header->pfxStart;
1345 const POINTFX* nextPoint = fPointIter.next();
1346 if (NULL == nextPoint) {
1347 const TTPOLYCURVE* curve = fCurveIter.next();
1348 if (NULL == curve) {
1352 fPointIter.set(curve);
1354 nextPoint = fPointIter.next();
1359 WORD currentCurveType() {
1360 return fPointIter.fCurveType;
1364 /** Iterates over all of the polygon headers in a glyphbuf. */
1365 class GDIPolygonHeaderIter {
1367 GDIPolygonHeaderIter(const uint8_t* glyphbuf, DWORD total_size)
1368 : fCurPolygon(reinterpret_cast<const TTPOLYGONHEADER*>(glyphbuf))
1369 , fEndPolygon(SkTAddOffset<const TTPOLYGONHEADER>(glyphbuf, total_size))
1372 const TTPOLYGONHEADER* next() {
1373 if (fCurPolygon >= fEndPolygon) {
1376 const TTPOLYGONHEADER* thisPolygon = fCurPolygon;
1377 fCurPolygon = SkTAddOffset<const TTPOLYGONHEADER>(fCurPolygon, fCurPolygon->cb);
1381 const TTPOLYGONHEADER* fCurPolygon;
1382 const TTPOLYGONHEADER* fEndPolygon;
1385 /** Iterates over all of the polygon curves in a polygon header. */
1386 class GDIPolygonCurveIter {
1388 GDIPolygonCurveIter() : fCurCurve(NULL), fEndCurve(NULL) { }
1390 GDIPolygonCurveIter(const TTPOLYGONHEADER* curPolygon)
1391 : fCurCurve(SkTAddOffset<const TTPOLYCURVE>(curPolygon, sizeof(TTPOLYGONHEADER)))
1392 , fEndCurve(SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon->cb))
1395 bool isSet() { return fCurCurve != NULL; }
1397 void set(const TTPOLYGONHEADER* curPolygon) {
1398 fCurCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon, sizeof(TTPOLYGONHEADER));
1399 fEndCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon->cb);
1406 const TTPOLYCURVE* next() {
1407 if (fCurCurve >= fEndCurve) {
1410 const TTPOLYCURVE* thisCurve = fCurCurve;
1411 fCurCurve = SkTAddOffset<const TTPOLYCURVE>(fCurCurve, size_of_TTPOLYCURVE(*fCurCurve));
1415 size_t size_of_TTPOLYCURVE(const TTPOLYCURVE& curve) {
1416 return 2*sizeof(WORD) + curve.cpfx*sizeof(POINTFX);
1418 const TTPOLYCURVE* fCurCurve;
1419 const TTPOLYCURVE* fEndCurve;
1422 /** Iterates over all of the polygon points in a polygon curve. */
1423 class GDIPolygonCurvePointIter {
1425 GDIPolygonCurvePointIter() : fCurveType(0), fCurPoint(NULL), fEndPoint(NULL) { }
1427 GDIPolygonCurvePointIter(const TTPOLYCURVE* curPolygon)
1428 : fCurveType(curPolygon->wType)
1429 , fCurPoint(&curPolygon->apfx[0])
1430 , fEndPoint(&curPolygon->apfx[curPolygon->cpfx])
1433 bool isSet() { return fCurPoint != NULL; }
1435 void set(const TTPOLYCURVE* curPolygon) {
1436 fCurveType = curPolygon->wType;
1437 fCurPoint = &curPolygon->apfx[0];
1438 fEndPoint = &curPolygon->apfx[curPolygon->cpfx];
1445 const POINTFX* next() {
1446 if (fCurPoint >= fEndPoint) {
1449 const POINTFX* thisPoint = fCurPoint;
1456 const POINTFX* fCurPoint;
1457 const POINTFX* fEndPoint;
1460 GDIPolygonHeaderIter fHeaderIter;
1461 GDIPolygonCurveIter fCurveIter;
1462 GDIPolygonCurvePointIter fPointIter;
1465 static void sk_path_from_gdi_path(SkPath* path, const uint8_t* glyphbuf, DWORD total_size) {
1466 const uint8_t* cur_glyph = glyphbuf;
1467 const uint8_t* end_glyph = glyphbuf + total_size;
1469 while (cur_glyph < end_glyph) {
1470 const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
1472 const uint8_t* end_poly = cur_glyph + th->cb;
1473 const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
1475 path->moveTo(SkFixedToScalar( SkFIXEDToFixed(th->pfxStart.x)),
1476 SkFixedToScalar(-SkFIXEDToFixed(th->pfxStart.y)));
1478 while (cur_poly < end_poly) {
1479 const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
1481 if (pc->wType == TT_PRIM_LINE) {
1482 for (uint16_t i = 0; i < pc->cpfx; i++) {
1483 path->lineTo(SkFixedToScalar( SkFIXEDToFixed(pc->apfx[i].x)),
1484 SkFixedToScalar(-SkFIXEDToFixed(pc->apfx[i].y)));
1488 if (pc->wType == TT_PRIM_QSPLINE) {
1489 for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline
1490 POINTFX pnt_b = pc->apfx[u]; // B is always the current point
1491 POINTFX pnt_c = pc->apfx[u+1];
1493 if (u < pc->cpfx - 2) { // If not on last spline, compute C
1494 pnt_c.x = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.x),
1495 SkFIXEDToFixed(pnt_c.x)));
1496 pnt_c.y = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.y),
1497 SkFIXEDToFixed(pnt_c.y)));
1500 path->quadTo(SkFixedToScalar( SkFIXEDToFixed(pnt_b.x)),
1501 SkFixedToScalar(-SkFIXEDToFixed(pnt_b.y)),
1502 SkFixedToScalar( SkFIXEDToFixed(pnt_c.x)),
1503 SkFixedToScalar(-SkFIXEDToFixed(pnt_c.y)));
1506 // Advance past this TTPOLYCURVE.
1507 cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx;
1509 cur_glyph += th->cb;
1514 #define move_next_expected_hinted_point(iter, pElem) do {\
1515 pElem = iter.next(); \
1516 if (NULL == pElem) return false; \
1519 // It is possible for the hinted and unhinted versions of the same path to have
1520 // a different number of points due to GDI's handling of flipped points.
1521 // If this is detected, this will return false.
1522 static bool sk_path_from_gdi_paths(SkPath* path, const uint8_t* glyphbuf, DWORD total_size,
1523 GDIGlyphbufferPointIter hintedYs) {
1524 const uint8_t* cur_glyph = glyphbuf;
1525 const uint8_t* end_glyph = glyphbuf + total_size;
1527 POINTFX const * hintedPoint;
1529 while (cur_glyph < end_glyph) {
1530 const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
1532 const uint8_t* end_poly = cur_glyph + th->cb;
1533 const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
1535 move_next_expected_hinted_point(hintedYs, hintedPoint);
1536 path->moveTo(SkFixedToScalar( SkFIXEDToFixed(th->pfxStart.x)),
1537 SkFixedToScalar(-SkFIXEDToFixed(hintedPoint->y)));
1539 while (cur_poly < end_poly) {
1540 const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
1542 if (pc->wType == TT_PRIM_LINE) {
1543 for (uint16_t i = 0; i < pc->cpfx; i++) {
1544 move_next_expected_hinted_point(hintedYs, hintedPoint);
1545 path->lineTo(SkFixedToScalar( SkFIXEDToFixed(pc->apfx[i].x)),
1546 SkFixedToScalar(-SkFIXEDToFixed(hintedPoint->y)));
1550 if (pc->wType == TT_PRIM_QSPLINE) {
1551 POINTFX currentPoint = pc->apfx[0];
1552 move_next_expected_hinted_point(hintedYs, hintedPoint);
1553 // only take the hinted y if it wasn't flipped
1554 if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) {
1555 currentPoint.y = hintedPoint->y;
1557 for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline
1558 POINTFX pnt_b = currentPoint;//pc->apfx[u]; // B is always the current point
1559 POINTFX pnt_c = pc->apfx[u+1];
1560 move_next_expected_hinted_point(hintedYs, hintedPoint);
1561 // only take the hinted y if it wasn't flipped
1562 if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) {
1563 pnt_c.y = hintedPoint->y;
1565 currentPoint.x = pnt_c.x;
1566 currentPoint.y = pnt_c.y;
1568 if (u < pc->cpfx - 2) { // If not on last spline, compute C
1569 pnt_c.x = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.x),
1570 SkFIXEDToFixed(pnt_c.x)));
1571 pnt_c.y = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.y),
1572 SkFIXEDToFixed(pnt_c.y)));
1575 path->quadTo(SkFixedToScalar( SkFIXEDToFixed(pnt_b.x)),
1576 SkFixedToScalar(-SkFIXEDToFixed(pnt_b.y)),
1577 SkFixedToScalar( SkFIXEDToFixed(pnt_c.x)),
1578 SkFixedToScalar(-SkFIXEDToFixed(pnt_c.y)));
1581 // Advance past this TTPOLYCURVE.
1582 cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx;
1584 cur_glyph += th->cb;
1590 DWORD SkScalerContext_GDI::getGDIGlyphPath(const SkGlyph& glyph, UINT flags,
1591 SkAutoSTMalloc<BUFFERSIZE, uint8_t>* glyphbuf)
1595 DWORD total_size = GetGlyphOutlineW(fDDC, glyph.getGlyphID(), flags, &gm, BUFFERSIZE, glyphbuf->get(), &fMat22);
1596 // Sometimes GetGlyphOutlineW returns a number larger than BUFFERSIZE even if BUFFERSIZE > 0.
1597 // It has been verified that this does not involve a buffer overrun.
1598 if (GDI_ERROR == total_size || total_size > BUFFERSIZE) {
1599 // GDI_ERROR because the BUFFERSIZE was too small, or because the data was not accessible.
1600 // When the data is not accessable GetGlyphOutlineW fails rather quickly,
1601 // so just try to get the size. If that fails then ensure the data is accessible.
1602 total_size = GetGlyphOutlineW(fDDC, glyph.getGlyphID(), flags, &gm, 0, NULL, &fMat22);
1603 if (GDI_ERROR == total_size) {
1604 LogFontTypeface::EnsureAccessible(this->getTypeface());
1605 total_size = GetGlyphOutlineW(fDDC, glyph.getGlyphID(), flags, &gm, 0, NULL, &fMat22);
1606 if (GDI_ERROR == total_size) {
1607 // GetGlyphOutlineW is known to fail for some characters, such as spaces.
1608 // In these cases, just return that the glyph does not have a shape.
1613 glyphbuf->reset(total_size);
1615 DWORD ret = GetGlyphOutlineW(fDDC, glyph.getGlyphID(), flags, &gm, total_size, glyphbuf->get(), &fMat22);
1616 if (GDI_ERROR == ret) {
1617 LogFontTypeface::EnsureAccessible(this->getTypeface());
1618 ret = GetGlyphOutlineW(fDDC, glyph.getGlyphID(), flags, &gm, total_size, glyphbuf->get(), &fMat22);
1619 if (GDI_ERROR == ret) {
1628 void SkScalerContext_GDI::generatePath(const SkGlyph& glyph, SkPath* path) {
1629 SkASSERT(&glyph && path);
1634 // Out of all the fonts on a typical Windows box,
1635 // 25% of glyphs require more than 2KB.
1636 // 1% of glyphs require more than 4KB.
1637 // 0.01% of glyphs require more than 8KB.
1638 // 8KB is less than 1% of the normal 1MB stack on Windows.
1639 // Note that some web fonts glyphs require more than 20KB.
1640 //static const DWORD BUFFERSIZE = (1 << 13);
1642 //GDI only uses hinted outlines when axis aligned.
1643 UINT format = GGO_NATIVE | GGO_GLYPH_INDEX;
1644 if (fRec.getHinting() == SkPaint::kNo_Hinting || fRec.getHinting() == SkPaint::kSlight_Hinting){
1645 format |= GGO_UNHINTED;
1647 SkAutoSTMalloc<BUFFERSIZE, uint8_t> glyphbuf(BUFFERSIZE);
1648 DWORD total_size = getGDIGlyphPath(glyph, format, &glyphbuf);
1649 if (0 == total_size) {
1653 if (fRec.getHinting() != SkPaint::kSlight_Hinting) {
1654 sk_path_from_gdi_path(path, glyphbuf, total_size);
1656 //GDI only uses hinted outlines when axis aligned.
1657 UINT format = GGO_NATIVE | GGO_GLYPH_INDEX;
1659 SkAutoSTMalloc<BUFFERSIZE, uint8_t> hintedGlyphbuf(BUFFERSIZE);
1660 DWORD hinted_total_size = getGDIGlyphPath(glyph, format, &hintedGlyphbuf);
1661 if (0 == hinted_total_size) {
1665 if (!sk_path_from_gdi_paths(path, glyphbuf, total_size,
1666 GDIGlyphbufferPointIter(hintedGlyphbuf, hinted_total_size)))
1669 sk_path_from_gdi_path(path, glyphbuf, total_size);
1674 static void logfont_for_name(const char* familyName, LOGFONT* lf) {
1675 sk_bzero(lf, sizeof(LOGFONT));
1677 // Get the buffer size needed first.
1678 size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName,
1680 // Allocate a buffer (str_len already has terminating null
1682 wchar_t *wideFamilyName = new wchar_t[str_len];
1683 // Now actually convert the string.
1684 ::MultiByteToWideChar(CP_UTF8, 0, familyName, -1,
1685 wideFamilyName, str_len);
1686 ::wcsncpy(lf->lfFaceName, wideFamilyName, LF_FACESIZE - 1);
1687 delete [] wideFamilyName;
1688 lf->lfFaceName[LF_FACESIZE-1] = L'\0';
1690 ::strncpy(lf->lfFaceName, familyName, LF_FACESIZE - 1);
1691 lf->lfFaceName[LF_FACESIZE - 1] = '\0';
1695 void LogFontTypeface::onGetFamilyName(SkString* familyName) const {
1696 // Get the actual name of the typeface. The logfont may not know this.
1697 HFONT font = CreateFontIndirect(&fLogFont);
1699 HDC deviceContext = ::CreateCompatibleDC(NULL);
1700 HFONT savefont = (HFONT)SelectObject(deviceContext, font);
1702 dcfontname_to_skstring(deviceContext, fLogFont, familyName);
1704 if (deviceContext) {
1705 ::SelectObject(deviceContext, savefont);
1706 ::DeleteDC(deviceContext);
1709 ::DeleteObject(font);
1713 void LogFontTypeface::onGetFontDescriptor(SkFontDescriptor* desc,
1714 bool* isLocalStream) const {
1715 SkString familyName;
1716 this->onGetFamilyName(&familyName);
1717 desc->setFamilyName(familyName.c_str());
1718 *isLocalStream = this->fSerializeAsStream;
1721 static bool getWidthAdvance(HDC hdc, int gId, int16_t* advance) {
1722 // Initialize the MAT2 structure to the identify transformation matrix.
1723 static const MAT2 mat2 = {SkScalarToFIXED(1), SkScalarToFIXED(0),
1724 SkScalarToFIXED(0), SkScalarToFIXED(1)};
1725 int flags = GGO_METRICS | GGO_GLYPH_INDEX;
1727 if (GDI_ERROR == GetGlyphOutline(hdc, gId, flags, &gm, 0, NULL, &mat2)) {
1731 *advance = gm.gmCellIncX;
1735 SkAdvancedTypefaceMetrics* LogFontTypeface::onGetAdvancedTypefaceMetrics(
1736 SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
1737 const uint32_t* glyphIDs,
1738 uint32_t glyphIDsCount) const {
1739 LOGFONT lf = fLogFont;
1740 SkAdvancedTypefaceMetrics* info = NULL;
1742 HDC hdc = CreateCompatibleDC(NULL);
1743 HFONT font = CreateFontIndirect(&lf);
1744 HFONT savefont = (HFONT)SelectObject(hdc, font);
1745 HFONT designFont = NULL;
1747 const char stem_chars[] = {'i', 'I', '!', '1'};
1749 unsigned glyphCount;
1751 // To request design units, create a logical font whose height is specified
1753 OUTLINETEXTMETRIC otm;
1754 unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
1756 call_ensure_accessible(lf);
1757 otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
1759 if (!otmRet || !GetTextFace(hdc, LF_FACESIZE, lf.lfFaceName)) {
1762 lf.lfHeight = -SkToS32(otm.otmEMSquare);
1763 designFont = CreateFontIndirect(&lf);
1764 SelectObject(hdc, designFont);
1765 if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm)) {
1768 glyphCount = calculateGlyphCount(hdc, fLogFont);
1770 info = new SkAdvancedTypefaceMetrics;
1771 info->fEmSize = otm.otmEMSquare;
1772 info->fLastGlyphID = SkToU16(glyphCount - 1);
1774 tchar_to_skstring(lf.lfFaceName, &info->fFontName);
1775 info->fFlags = SkAdvancedTypefaceMetrics::kEmpty_FontFlag;
1776 // If bit 1 is set, the font may not be embedded in a document.
1777 // If bit 1 is clear, the font can be embedded.
1778 // If bit 2 is set, the embedding is read-only.
1779 if (otm.otmfsType & 0x1) {
1780 info->fFlags = SkTBitOr<SkAdvancedTypefaceMetrics::FontFlags>(
1782 SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag);
1785 if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) {
1786 populate_glyph_to_unicode(hdc, glyphCount, &(info->fGlyphToUnicode));
1789 if (glyphCount > 0 &&
1790 (otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE)) {
1791 info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
1793 info->fType = SkAdvancedTypefaceMetrics::kOther_Font;
1794 info->fItalicAngle = 0;
1798 info->fCapHeight = 0;
1799 info->fBBox = SkIRect::MakeEmpty();
1803 // If this bit is clear the font is a fixed pitch font.
1804 if (!(otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
1805 info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
1807 if (otm.otmTextMetrics.tmItalic) {
1808 info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
1810 if (otm.otmTextMetrics.tmPitchAndFamily & FF_ROMAN) {
1811 info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
1812 } else if (otm.otmTextMetrics.tmPitchAndFamily & FF_SCRIPT) {
1813 info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
1816 // The main italic angle of the font, in tenths of a degree counterclockwise
1818 info->fItalicAngle = otm.otmItalicAngle / 10;
1819 info->fAscent = SkToS16(otm.otmTextMetrics.tmAscent);
1820 info->fDescent = SkToS16(-otm.otmTextMetrics.tmDescent);
1821 // TODO(ctguil): Use alternate cap height calculation.
1822 // MSDN says otmsCapEmHeight is not support but it is returning a value on
1824 info->fCapHeight = otm.otmsCapEmHeight;
1826 SkIRect::MakeLTRB(otm.otmrcFontBox.left, otm.otmrcFontBox.top,
1827 otm.otmrcFontBox.right, otm.otmrcFontBox.bottom);
1829 // Figure out a good guess for StemV - Min width of i, I, !, 1.
1830 // This probably isn't very good with an italic font.
1831 min_width = SHRT_MAX;
1833 for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) {
1835 if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) {
1836 int16_t width = abcWidths.abcB;
1837 if (width > 0 && width < min_width) {
1839 info->fStemV = min_width;
1844 if (perGlyphInfo & SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) {
1845 if (info->fStyle & SkAdvancedTypefaceMetrics::kFixedPitch_Style) {
1846 appendRange(&info->fGlyphWidths, 0);
1847 info->fGlyphWidths->fAdvance.append(1, &min_width);
1848 finishRange(info->fGlyphWidths.get(), 0,
1849 SkAdvancedTypefaceMetrics::WidthRange::kDefault);
1851 info->fGlyphWidths.reset(
1862 SelectObject(hdc, savefont);
1863 DeleteObject(designFont);
1870 //Dummy representation of a Base64 encoded GUID from create_unique_font_name.
1871 #define BASE64_GUID_ID "XXXXXXXXXXXXXXXXXXXXXXXX"
1872 //Length of GUID representation from create_id, including NULL terminator.
1873 #define BASE64_GUID_ID_LEN SK_ARRAY_COUNT(BASE64_GUID_ID)
1875 SK_COMPILE_ASSERT(BASE64_GUID_ID_LEN < LF_FACESIZE, GUID_longer_than_facesize);
1878 NameID 6 Postscript names cannot have the character '/'.
1879 It would be easier to hex encode the GUID, but that is 32 bytes,
1880 and many systems have issues with names longer than 28 bytes.
1881 The following need not be any standard base64 encoding.
1882 The encoded value is never decoded.
1884 static const char postscript_safe_base64_encode[] =
1885 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1886 "abcdefghijklmnopqrstuvwxyz"
1890 Formats a GUID into Base64 and places it into buffer.
1891 buffer should have space for at least BASE64_GUID_ID_LEN characters.
1892 The string will always be null terminated.
1893 XXXXXXXXXXXXXXXXXXXXXXXX0
1895 static void format_guid_b64(const GUID& guid, char* buffer, size_t bufferSize) {
1896 SkASSERT(bufferSize >= BASE64_GUID_ID_LEN);
1897 size_t written = SkBase64::Encode(&guid, sizeof(guid), buffer, postscript_safe_base64_encode);
1898 SkASSERT(written < LF_FACESIZE);
1899 buffer[written] = '\0';
1903 Creates a Base64 encoded GUID and places it into buffer.
1904 buffer should have space for at least BASE64_GUID_ID_LEN characters.
1905 The string will always be null terminated.
1906 XXXXXXXXXXXXXXXXXXXXXXXX0
1908 static HRESULT create_unique_font_name(char* buffer, size_t bufferSize) {
1910 if (FAILED(CoCreateGuid(&guid))) {
1911 return E_UNEXPECTED;
1913 format_guid_b64(guid, buffer, bufferSize);
1919 Introduces a font to GDI. On failure will return NULL. The returned handle
1920 should eventually be passed to RemoveFontMemResourceEx.
1922 static HANDLE activate_font(SkData* fontData) {
1924 //AddFontMemResourceEx just copies the data, but does not specify const.
1925 HANDLE fontHandle = AddFontMemResourceEx(const_cast<void*>(fontData->data()),
1926 static_cast<DWORD>(fontData->size()),
1930 if (fontHandle != NULL && numFonts < 1) {
1931 RemoveFontMemResourceEx(fontHandle);
1938 // Does not affect ownership of stream.
1939 static SkTypeface* create_from_stream(SkStreamAsset* stream) {
1940 // Create a unique and unpredictable font name.
1941 // Avoids collisions and access from CSS.
1942 char familyName[BASE64_GUID_ID_LEN];
1943 const int familyNameSize = SK_ARRAY_COUNT(familyName);
1944 if (FAILED(create_unique_font_name(familyName, familyNameSize))) {
1948 // Change the name of the font.
1949 SkAutoTUnref<SkData> rewrittenFontData(SkOTUtils::RenameFont(stream, familyName, familyNameSize-1));
1950 if (NULL == rewrittenFontData.get()) {
1954 // Register the font with GDI.
1955 HANDLE fontReference = activate_font(rewrittenFontData.get());
1956 if (NULL == fontReference) {
1960 // Create the typeface.
1962 logfont_for_name(familyName, &lf);
1964 return SkCreateFontMemResourceTypefaceFromLOGFONT(lf, fontReference);
1967 SkStreamAsset* LogFontTypeface::onOpenStream(int* ttcIndex) const {
1970 const DWORD kTTCTag =
1971 SkEndian_SwapBE32(SkSetFourByteTag('t', 't', 'c', 'f'));
1972 LOGFONT lf = fLogFont;
1974 HDC hdc = ::CreateCompatibleDC(NULL);
1975 HFONT font = CreateFontIndirect(&lf);
1976 HFONT savefont = (HFONT)SelectObject(hdc, font);
1978 SkMemoryStream* stream = NULL;
1979 DWORD tables[2] = {kTTCTag, 0};
1980 for (int i = 0; i < SK_ARRAY_COUNT(tables); i++) {
1981 DWORD bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0);
1982 if (bufferSize == GDI_ERROR) {
1983 call_ensure_accessible(lf);
1984 bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0);
1986 if (bufferSize != GDI_ERROR) {
1987 stream = new SkMemoryStream(bufferSize);
1988 if (GetFontData(hdc, tables[i], 0, (void*)stream->getMemoryBase(), bufferSize)) {
1997 SelectObject(hdc, savefont);
2004 static void bmpCharsToGlyphs(HDC hdc, const WCHAR* bmpChars, int count, uint16_t* glyphs,
2007 DWORD result = GetGlyphIndicesW(hdc, bmpChars, count, glyphs, GGI_MARK_NONEXISTING_GLYPHS);
2008 if (GDI_ERROR == result) {
2009 for (int i = 0; i < count; ++i) {
2016 for (int i = 0; i < count; ++i) {
2017 if (0xFFFF == glyphs[i] || 0x1F == glyphs[i]) {
2022 for (int i = 0; i < count; ++i) {
2023 if (0xFFFF == glyphs[i]){
2030 static uint16_t nonBmpCharToGlyph(HDC hdc, SCRIPT_CACHE* scriptCache, const WCHAR utf16[2]) {
2032 // Use uniscribe to detemine glyph index for non-BMP characters.
2033 static const int numWCHAR = 2;
2034 static const int maxItems = 2;
2035 // MSDN states that this can be NULL, but some things don't work then.
2036 SCRIPT_CONTROL scriptControl = { 0 };
2037 // Add extra item to SCRIPT_ITEM to work around a bug (now documented).
2038 // https://bugzilla.mozilla.org/show_bug.cgi?id=366643
2039 SCRIPT_ITEM si[maxItems + 1];
2041 HRZM(ScriptItemize(utf16, numWCHAR, maxItems, &scriptControl, NULL, si, &numItems),
2042 "Could not itemize character.");
2044 // Sometimes ScriptShape cannot find a glyph for a non-BMP and returns 2 space glyphs.
2045 static const int maxGlyphs = 2;
2046 SCRIPT_VISATTR vsa[maxGlyphs];
2047 WORD outGlyphs[maxGlyphs];
2048 WORD logClust[numWCHAR];
2050 HRZM(ScriptShape(hdc, scriptCache, utf16, numWCHAR, maxGlyphs, &si[0].a,
2051 outGlyphs, logClust, vsa, &numGlyphs),
2052 "Could not shape character.");
2053 if (1 == numGlyphs) {
2054 index = outGlyphs[0];
2061 SkAutoHDC(const LOGFONT& lf)
2062 : fHdc(::CreateCompatibleDC(NULL))
2063 , fFont(::CreateFontIndirect(&lf))
2064 , fSavefont((HFONT)SelectObject(fHdc, fFont))
2067 SelectObject(fHdc, fSavefont);
2068 DeleteObject(fFont);
2071 operator HDC() { return fHdc; }
2077 #define SkAutoHDC(...) SK_REQUIRE_LOCAL_VAR(SkAutoHDC)
2079 int LogFontTypeface::onCharsToGlyphs(const void* chars, Encoding encoding,
2080 uint16_t userGlyphs[], int glyphCount) const
2082 SkAutoHDC hdc(fLogFont);
2085 if (0 == GetTextMetrics(hdc, &tm)) {
2086 call_ensure_accessible(fLogFont);
2087 if (0 == GetTextMetrics(hdc, &tm)) {
2088 tm.tmPitchAndFamily = TMPF_TRUETYPE;
2091 bool Ox1FHack = !(tm.tmPitchAndFamily & TMPF_VECTOR) /*&& winVer < Vista */;
2093 SkAutoSTMalloc<256, uint16_t> scratchGlyphs;
2095 if (userGlyphs != NULL) {
2096 glyphs = userGlyphs;
2098 glyphs = scratchGlyphs.reset(glyphCount);
2101 SCRIPT_CACHE sc = 0;
2103 case SkTypeface::kUTF8_Encoding: {
2104 static const int scratchCount = 256;
2105 WCHAR scratch[scratchCount];
2107 const char* currentUtf8 = reinterpret_cast<const char*>(chars);
2108 SkUnichar currentChar;
2110 currentChar = SkUTF8_NextUnichar(¤tUtf8);
2112 while (glyphIndex < glyphCount) {
2113 // Try a run of bmp.
2114 int glyphsLeft = SkTMin(glyphCount - glyphIndex, scratchCount);
2116 while (runLength < glyphsLeft && currentChar <= 0xFFFF) {
2117 scratch[runLength] = static_cast<WCHAR>(currentChar);
2119 if (runLength < glyphsLeft) {
2120 currentChar = SkUTF8_NextUnichar(¤tUtf8);
2124 bmpCharsToGlyphs(hdc, scratch, runLength, &glyphs[glyphIndex], Ox1FHack);
2125 glyphIndex += runLength;
2128 // Try a run of non-bmp.
2129 while (glyphIndex < glyphCount && currentChar > 0xFFFF) {
2130 SkUTF16_FromUnichar(currentChar, reinterpret_cast<uint16_t*>(scratch));
2131 glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, scratch);
2133 if (glyphIndex < glyphCount) {
2134 currentChar = SkUTF8_NextUnichar(¤tUtf8);
2140 case SkTypeface::kUTF16_Encoding: {
2142 const WCHAR* currentUtf16 = reinterpret_cast<const WCHAR*>(chars);
2143 while (glyphIndex < glyphCount) {
2144 // Try a run of bmp.
2145 int glyphsLeft = glyphCount - glyphIndex;
2147 while (runLength < glyphsLeft && !SkUTF16_IsHighSurrogate(currentUtf16[runLength])) {
2151 bmpCharsToGlyphs(hdc, currentUtf16, runLength, &glyphs[glyphIndex], Ox1FHack);
2152 glyphIndex += runLength;
2153 currentUtf16 += runLength;
2156 // Try a run of non-bmp.
2157 while (glyphIndex < glyphCount && SkUTF16_IsHighSurrogate(*currentUtf16)) {
2158 glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, currentUtf16);
2165 case SkTypeface::kUTF32_Encoding: {
2166 static const int scratchCount = 256;
2167 WCHAR scratch[scratchCount];
2169 const uint32_t* utf32 = reinterpret_cast<const uint32_t*>(chars);
2170 while (glyphIndex < glyphCount) {
2171 // Try a run of bmp.
2172 int glyphsLeft = SkTMin(glyphCount - glyphIndex, scratchCount);
2174 while (runLength < glyphsLeft && utf32[glyphIndex + runLength] <= 0xFFFF) {
2175 scratch[runLength] = static_cast<WCHAR>(utf32[glyphIndex + runLength]);
2179 bmpCharsToGlyphs(hdc, scratch, runLength, &glyphs[glyphIndex], Ox1FHack);
2180 glyphIndex += runLength;
2183 // Try a run of non-bmp.
2184 while (glyphIndex < glyphCount && utf32[glyphIndex] > 0xFFFF) {
2185 SkUTF16_FromUnichar(utf32[glyphIndex], reinterpret_cast<uint16_t*>(scratch));
2186 glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, scratch);
2197 ::ScriptFreeCache(&sc);
2200 for (int i = 0; i < glyphCount; ++i) {
2201 if (0 == glyphs[i]) {
2208 int LogFontTypeface::onCountGlyphs() const {
2209 HDC hdc = ::CreateCompatibleDC(NULL);
2210 HFONT font = CreateFontIndirect(&fLogFont);
2211 HFONT savefont = (HFONT)SelectObject(hdc, font);
2213 unsigned int glyphCount = calculateGlyphCount(hdc, fLogFont);
2215 SelectObject(hdc, savefont);
2222 int LogFontTypeface::onGetUPEM() const {
2223 HDC hdc = ::CreateCompatibleDC(NULL);
2224 HFONT font = CreateFontIndirect(&fLogFont);
2225 HFONT savefont = (HFONT)SelectObject(hdc, font);
2227 unsigned int upem = calculateUPEM(hdc, fLogFont);
2229 SelectObject(hdc, savefont);
2236 SkTypeface::LocalizedStrings* LogFontTypeface::onCreateFamilyNameIterator() const {
2237 SkTypeface::LocalizedStrings* nameIter =
2238 SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(*this);
2239 if (NULL == nameIter) {
2240 SkString familyName;
2241 this->getFamilyName(&familyName);
2242 SkString language("und"); //undetermined
2243 nameIter = new SkOTUtils::LocalizedStrings_SingleName(familyName, language);
2248 int LogFontTypeface::onGetTableTags(SkFontTableTag tags[]) const {
2249 SkSFNTHeader header;
2250 if (sizeof(header) != this->onGetTableData(0, 0, sizeof(header), &header)) {
2254 int numTables = SkEndian_SwapBE16(header.numTables);
2257 size_t size = numTables * sizeof(SkSFNTHeader::TableDirectoryEntry);
2258 SkAutoSTMalloc<0x20, SkSFNTHeader::TableDirectoryEntry> dir(numTables);
2259 if (size != this->onGetTableData(0, sizeof(header), size, dir.get())) {
2263 for (int i = 0; i < numTables; ++i) {
2264 tags[i] = SkEndian_SwapBE32(dir[i].tag);
2270 size_t LogFontTypeface::onGetTableData(SkFontTableTag tag, size_t offset,
2271 size_t length, void* data) const
2273 LOGFONT lf = fLogFont;
2275 HDC hdc = ::CreateCompatibleDC(NULL);
2276 HFONT font = CreateFontIndirect(&lf);
2277 HFONT savefont = (HFONT)SelectObject(hdc, font);
2279 tag = SkEndian_SwapBE32(tag);
2283 DWORD bufferSize = GetFontData(hdc, tag, (DWORD) offset, data, (DWORD) length);
2284 if (bufferSize == GDI_ERROR) {
2285 call_ensure_accessible(lf);
2286 bufferSize = GetFontData(hdc, tag, (DWORD) offset, data, (DWORD) length);
2289 SelectObject(hdc, savefont);
2293 return bufferSize == GDI_ERROR ? 0 : bufferSize;
2296 SkScalerContext* LogFontTypeface::onCreateScalerContext(const SkDescriptor* desc) const {
2297 SkScalerContext_GDI* ctx = SkNEW_ARGS(SkScalerContext_GDI,
2298 (const_cast<LogFontTypeface*>(this), desc));
2299 if (!ctx->isValid()) {
2306 void LogFontTypeface::onFilterRec(SkScalerContextRec* rec) const {
2307 if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag ||
2308 rec->fFlags & SkScalerContext::kLCD_Vertical_Flag)
2310 rec->fMaskFormat = SkMask::kA8_Format;
2311 rec->fFlags |= SkScalerContext::kGenA8FromLCD_Flag;
2314 unsigned flagsWeDontSupport = SkScalerContext::kVertical_Flag |
2315 SkScalerContext::kDevKernText_Flag |
2316 SkScalerContext::kForceAutohinting_Flag |
2317 SkScalerContext::kEmbeddedBitmapText_Flag |
2318 SkScalerContext::kEmbolden_Flag |
2319 SkScalerContext::kLCD_BGROrder_Flag |
2320 SkScalerContext::kLCD_Vertical_Flag;
2321 rec->fFlags &= ~flagsWeDontSupport;
2323 SkPaint::Hinting h = rec->getHinting();
2325 case SkPaint::kNo_Hinting:
2327 case SkPaint::kSlight_Hinting:
2328 // Only do slight hinting when axis aligned.
2329 // TODO: re-enable slight hinting when FontHostTest can pass.
2330 //if (!isAxisAligned(*rec)) {
2331 h = SkPaint::kNo_Hinting;
2334 case SkPaint::kNormal_Hinting:
2335 case SkPaint::kFull_Hinting:
2336 // TODO: need to be able to distinguish subpixel positioned glyphs
2337 // and linear metrics.
2338 //rec->fFlags &= ~SkScalerContext::kSubpixelPositioning_Flag;
2339 h = SkPaint::kNormal_Hinting;
2342 SkDEBUGFAIL("unknown hinting");
2344 //TODO: if this is a bitmap font, squash hinting and subpixel.
2347 // turn this off since GDI might turn A8 into BW! Need a bigger fix.
2349 // Disable LCD when rotated, since GDI's output is ugly
2350 if (isLCD(*rec) && !isAxisAligned(*rec)) {
2351 rec->fMaskFormat = SkMask::kA8_Format;
2355 if (!fCanBeLCD && isLCD(*rec)) {
2356 rec->fMaskFormat = SkMask::kA8_Format;
2357 rec->fFlags &= ~SkScalerContext::kGenA8FromLCD_Flag;
2361 ///////////////////////////////////////////////////////////////////////////////
2363 #include "SkFontMgr.h"
2364 #include "SkDataTable.h"
2366 static bool valid_logfont_for_enum(const LOGFONT& lf) {
2367 // TODO: Vector FON is unsupported and should not be listed.
2369 // Ignore implicit vertical variants.
2370 lf.lfFaceName[0] && lf.lfFaceName[0] != '@'
2372 // DEFAULT_CHARSET is used to get all fonts, but also implies all
2373 // character sets. Filter assuming all fonts support ANSI_CHARSET.
2374 && ANSI_CHARSET == lf.lfCharSet
2378 /** An EnumFontFamExProc implementation which interprets builderParam as
2379 * an SkTDArray<ENUMLOGFONTEX>* and appends logfonts which
2380 * pass the valid_logfont_for_enum predicate.
2382 static int CALLBACK enum_family_proc(const LOGFONT* lf, const TEXTMETRIC*,
2383 DWORD fontType, LPARAM builderParam) {
2384 if (valid_logfont_for_enum(*lf)) {
2385 SkTDArray<ENUMLOGFONTEX>* array = (SkTDArray<ENUMLOGFONTEX>*)builderParam;
2386 *array->append() = *(ENUMLOGFONTEX*)lf;
2388 return 1; // non-zero means continue
2391 class SkFontStyleSetGDI : public SkFontStyleSet {
2393 SkFontStyleSetGDI(const TCHAR familyName[]) {
2395 sk_bzero(&lf, sizeof(lf));
2396 lf.lfCharSet = DEFAULT_CHARSET;
2397 _tcscpy_s(lf.lfFaceName, familyName);
2399 HDC hdc = ::CreateCompatibleDC(NULL);
2400 ::EnumFontFamiliesEx(hdc, &lf, enum_family_proc, (LPARAM)&fArray, 0);
2404 int count() override {
2405 return fArray.count();
2408 void getStyle(int index, SkFontStyle* fs, SkString* styleName) override {
2410 *fs = get_style(fArray[index].elfLogFont);
2413 const ENUMLOGFONTEX& ref = fArray[index];
2414 // For some reason, ENUMLOGFONTEX and LOGFONT disagree on their type in the
2415 // non-unicode version.
2416 // ENUMLOGFONTEX uses BYTE
2417 // LOGFONT uses CHAR
2418 // Here we assert they that the style name is logically the same (size) as
2419 // a TCHAR, so we can use the same converter function.
2420 SkASSERT(sizeof(TCHAR) == sizeof(ref.elfStyle[0]));
2421 tchar_to_skstring((const TCHAR*)ref.elfStyle, styleName);
2425 SkTypeface* createTypeface(int index) override {
2426 return SkCreateTypefaceFromLOGFONT(fArray[index].elfLogFont);
2429 SkTypeface* matchStyle(const SkFontStyle& pattern) override {
2431 return SkCreateTypefaceFromLOGFONT(fArray[0].elfLogFont);
2435 SkTDArray<ENUMLOGFONTEX> fArray;
2438 class SkFontMgrGDI : public SkFontMgr {
2442 sk_bzero(&lf, sizeof(lf));
2443 lf.lfCharSet = DEFAULT_CHARSET;
2445 HDC hdc = ::CreateCompatibleDC(NULL);
2446 ::EnumFontFamiliesEx(hdc, &lf, enum_family_proc, (LPARAM)&fLogFontArray, 0);
2451 int onCountFamilies() const override {
2452 return fLogFontArray.count();
2455 void onGetFamilyName(int index, SkString* familyName) const override {
2456 SkASSERT((unsigned)index < (unsigned)fLogFontArray.count());
2457 tchar_to_skstring(fLogFontArray[index].elfLogFont.lfFaceName, familyName);
2460 SkFontStyleSet* onCreateStyleSet(int index) const override {
2461 SkASSERT((unsigned)index < (unsigned)fLogFontArray.count());
2462 return SkNEW_ARGS(SkFontStyleSetGDI, (fLogFontArray[index].elfLogFont.lfFaceName));
2465 SkFontStyleSet* onMatchFamily(const char familyName[]) const override {
2466 if (NULL == familyName) {
2467 familyName = ""; // do we need this check???
2470 logfont_for_name(familyName, &lf);
2471 return SkNEW_ARGS(SkFontStyleSetGDI, (lf.lfFaceName));
2474 virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
2475 const SkFontStyle& fontstyle) const override {
2476 // could be in base impl
2477 SkAutoTUnref<SkFontStyleSet> sset(this->matchFamily(familyName));
2478 return sset->matchStyle(fontstyle);
2481 virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&,
2482 const char* bcp47[], int bcp47Count,
2483 SkUnichar character) const override {
2487 virtual SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember,
2488 const SkFontStyle& fontstyle) const override {
2489 // could be in base impl
2490 SkString familyName;
2491 ((LogFontTypeface*)familyMember)->getFamilyName(&familyName);
2492 return this->matchFamilyStyle(familyName.c_str(), fontstyle);
2495 SkTypeface* onCreateFromStream(SkStreamAsset* bareStream, int ttcIndex) const override {
2496 SkAutoTDelete<SkStreamAsset> stream(bareStream);
2497 return create_from_stream(stream);
2500 SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const override {
2501 // could be in base impl
2502 return this->createFromStream(SkNEW_ARGS(SkMemoryStream, (data)));
2505 SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override {
2506 // could be in base impl
2507 return this->createFromStream(SkStream::NewFromFile(path));
2510 virtual SkTypeface* onLegacyCreateTypeface(const char familyName[],
2511 unsigned styleBits) const override {
2513 if (NULL == familyName) {
2514 lf = get_default_font();
2516 logfont_for_name(familyName, &lf);
2519 SkTypeface::Style style = (SkTypeface::Style)styleBits;
2520 lf.lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL;
2521 lf.lfItalic = ((style & SkTypeface::kItalic) != 0);
2522 return SkCreateTypefaceFromLOGFONT(lf);
2526 SkTDArray<ENUMLOGFONTEX> fLogFontArray;
2529 ///////////////////////////////////////////////////////////////////////////////
2531 SkFontMgr* SkFontMgr_New_GDI() {
2532 return SkNEW(SkFontMgrGDI);