1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/ports/SkFontHost_win.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2648 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2006 The Android Open Source Project 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 +#include "SkAdvancedTypefaceMetrics.h" 1.13 +#include "SkBase64.h" 1.14 +#include "SkColorPriv.h" 1.15 +#include "SkData.h" 1.16 +#include "SkDescriptor.h" 1.17 +#include "SkFontDescriptor.h" 1.18 +#include "SkFontHost.h" 1.19 +#include "SkGlyph.h" 1.20 +#include "SkHRESULT.h" 1.21 +#include "SkMaskGamma.h" 1.22 +#include "SkOTTable_maxp.h" 1.23 +#include "SkOTTable_name.h" 1.24 +#include "SkOTUtils.h" 1.25 +#include "SkPath.h" 1.26 +#include "SkSFNTHeader.h" 1.27 +#include "SkStream.h" 1.28 +#include "SkString.h" 1.29 +#include "SkTemplates.h" 1.30 +#include "SkThread.h" 1.31 +#include "SkTypeface_win.h" 1.32 +#include "SkTypefaceCache.h" 1.33 +#include "SkUtils.h" 1.34 + 1.35 +#include "SkTypes.h" 1.36 +#include <tchar.h> 1.37 +#include <usp10.h> 1.38 +#include <objbase.h> 1.39 + 1.40 +static void (*gEnsureLOGFONTAccessibleProc)(const LOGFONT&); 1.41 + 1.42 +void SkTypeface_SetEnsureLOGFONTAccessibleProc(void (*proc)(const LOGFONT&)) { 1.43 + gEnsureLOGFONTAccessibleProc = proc; 1.44 +} 1.45 + 1.46 +static void call_ensure_accessible(const LOGFONT& lf) { 1.47 + if (gEnsureLOGFONTAccessibleProc) { 1.48 + gEnsureLOGFONTAccessibleProc(lf); 1.49 + } 1.50 +} 1.51 + 1.52 +/////////////////////////////////////////////////////////////////////////////// 1.53 + 1.54 +// always packed xxRRGGBB 1.55 +typedef uint32_t SkGdiRGB; 1.56 + 1.57 +// define this in your Makefile or .gyp to enforce AA requests 1.58 +// which GDI ignores at small sizes. This flag guarantees AA 1.59 +// for rotated text, regardless of GDI's notions. 1.60 +//#define SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS 1.61 + 1.62 +static bool isLCD(const SkScalerContext::Rec& rec) { 1.63 + return SkMask::kLCD16_Format == rec.fMaskFormat || 1.64 + SkMask::kLCD32_Format == rec.fMaskFormat; 1.65 +} 1.66 + 1.67 +static bool bothZero(SkScalar a, SkScalar b) { 1.68 + return 0 == a && 0 == b; 1.69 +} 1.70 + 1.71 +// returns false if there is any non-90-rotation or skew 1.72 +static bool isAxisAligned(const SkScalerContext::Rec& rec) { 1.73 + return 0 == rec.fPreSkewX && 1.74 + (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) || 1.75 + bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1])); 1.76 +} 1.77 + 1.78 +static bool needToRenderWithSkia(const SkScalerContext::Rec& rec) { 1.79 +#ifdef SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS 1.80 + // What we really want to catch is when GDI will ignore the AA request and give 1.81 + // us BW instead. Smallish rotated text is one heuristic, so this code is just 1.82 + // an approximation. We shouldn't need to do this for larger sizes, but at those 1.83 + // sizes, the quality difference gets less and less between our general 1.84 + // scanconverter and GDI's. 1.85 + if (SkMask::kA8_Format == rec.fMaskFormat && !isAxisAligned(rec)) { 1.86 + return true; 1.87 + } 1.88 +#endif 1.89 + return rec.getHinting() == SkPaint::kNo_Hinting || rec.getHinting() == SkPaint::kSlight_Hinting; 1.90 +} 1.91 + 1.92 +using namespace skia_advanced_typeface_metrics_utils; 1.93 + 1.94 +static void tchar_to_skstring(const TCHAR t[], SkString* s) { 1.95 +#ifdef UNICODE 1.96 + size_t sSize = WideCharToMultiByte(CP_UTF8, 0, t, -1, NULL, 0, NULL, NULL); 1.97 + s->resize(sSize); 1.98 + WideCharToMultiByte(CP_UTF8, 0, t, -1, s->writable_str(), sSize, NULL, NULL); 1.99 +#else 1.100 + s->set(t); 1.101 +#endif 1.102 +} 1.103 + 1.104 +static void dcfontname_to_skstring(HDC deviceContext, const LOGFONT& lf, SkString* familyName) { 1.105 + int fontNameLen; //length of fontName in TCHARS. 1.106 + if (0 == (fontNameLen = GetTextFace(deviceContext, 0, NULL))) { 1.107 + call_ensure_accessible(lf); 1.108 + if (0 == (fontNameLen = GetTextFace(deviceContext, 0, NULL))) { 1.109 + fontNameLen = 0; 1.110 + } 1.111 + } 1.112 + 1.113 + SkAutoSTArray<LF_FULLFACESIZE, TCHAR> fontName(fontNameLen+1); 1.114 + if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) { 1.115 + call_ensure_accessible(lf); 1.116 + if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) { 1.117 + fontName[0] = 0; 1.118 + } 1.119 + } 1.120 + 1.121 + tchar_to_skstring(fontName.get(), familyName); 1.122 +} 1.123 + 1.124 +static void make_canonical(LOGFONT* lf) { 1.125 + lf->lfHeight = -64; 1.126 + lf->lfQuality = CLEARTYPE_QUALITY;//PROOF_QUALITY; 1.127 + lf->lfCharSet = DEFAULT_CHARSET; 1.128 +// lf->lfClipPrecision = 64; 1.129 +} 1.130 + 1.131 +static SkTypeface::Style get_style(const LOGFONT& lf) { 1.132 + unsigned style = 0; 1.133 + if (lf.lfWeight >= FW_BOLD) { 1.134 + style |= SkTypeface::kBold; 1.135 + } 1.136 + if (lf.lfItalic) { 1.137 + style |= SkTypeface::kItalic; 1.138 + } 1.139 + return static_cast<SkTypeface::Style>(style); 1.140 +} 1.141 + 1.142 +static void setStyle(LOGFONT* lf, SkTypeface::Style style) { 1.143 + lf->lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL ; 1.144 + lf->lfItalic = ((style & SkTypeface::kItalic) != 0); 1.145 +} 1.146 + 1.147 +static inline FIXED SkFixedToFIXED(SkFixed x) { 1.148 + return *(FIXED*)(&x); 1.149 +} 1.150 +static inline SkFixed SkFIXEDToFixed(FIXED x) { 1.151 + return *(SkFixed*)(&x); 1.152 +} 1.153 + 1.154 +static inline FIXED SkScalarToFIXED(SkScalar x) { 1.155 + return SkFixedToFIXED(SkScalarToFixed(x)); 1.156 +} 1.157 + 1.158 +static inline SkScalar SkFIXEDToScalar(FIXED x) { 1.159 + return SkFixedToScalar(SkFIXEDToFixed(x)); 1.160 +} 1.161 + 1.162 +static unsigned calculateGlyphCount(HDC hdc, const LOGFONT& lf) { 1.163 + TEXTMETRIC textMetric; 1.164 + if (0 == GetTextMetrics(hdc, &textMetric)) { 1.165 + textMetric.tmPitchAndFamily = TMPF_VECTOR; 1.166 + call_ensure_accessible(lf); 1.167 + GetTextMetrics(hdc, &textMetric); 1.168 + } 1.169 + 1.170 + if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) { 1.171 + return textMetric.tmLastChar; 1.172 + } 1.173 + 1.174 + // The 'maxp' table stores the number of glyphs at offset 4, in 2 bytes. 1.175 + uint16_t glyphs; 1.176 + if (GDI_ERROR != GetFontData(hdc, SkOTTableMaximumProfile::TAG, 4, &glyphs, sizeof(glyphs))) { 1.177 + return SkEndian_SwapBE16(glyphs); 1.178 + } 1.179 + 1.180 + // Binary search for glyph count. 1.181 + static const MAT2 mat2 = {{0, 1}, {0, 0}, {0, 0}, {0, 1}}; 1.182 + int32_t max = SK_MaxU16 + 1; 1.183 + int32_t min = 0; 1.184 + GLYPHMETRICS gm; 1.185 + while (min < max) { 1.186 + int32_t mid = min + ((max - min) / 2); 1.187 + if (GetGlyphOutlineW(hdc, mid, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, 1.188 + NULL, &mat2) == GDI_ERROR) { 1.189 + max = mid; 1.190 + } else { 1.191 + min = mid + 1; 1.192 + } 1.193 + } 1.194 + SkASSERT(min == max); 1.195 + return min; 1.196 +} 1.197 + 1.198 +static unsigned calculateUPEM(HDC hdc, const LOGFONT& lf) { 1.199 + TEXTMETRIC textMetric; 1.200 + if (0 == GetTextMetrics(hdc, &textMetric)) { 1.201 + textMetric.tmPitchAndFamily = TMPF_VECTOR; 1.202 + call_ensure_accessible(lf); 1.203 + GetTextMetrics(hdc, &textMetric); 1.204 + } 1.205 + 1.206 + if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) { 1.207 + return textMetric.tmMaxCharWidth; 1.208 + } 1.209 + 1.210 + OUTLINETEXTMETRIC otm; 1.211 + unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm); 1.212 + if (0 == otmRet) { 1.213 + call_ensure_accessible(lf); 1.214 + otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm); 1.215 + } 1.216 + 1.217 + return (0 == otmRet) ? 0 : otm.otmEMSquare; 1.218 +} 1.219 + 1.220 +class LogFontTypeface : public SkTypeface { 1.221 +public: 1.222 + LogFontTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf, bool serializeAsStream = false) : 1.223 + SkTypeface(style, fontID, false), fLogFont(lf), fSerializeAsStream(serializeAsStream) { 1.224 + 1.225 + // If the font has cubic outlines, it will not be rendered with ClearType. 1.226 + HFONT font = CreateFontIndirect(&lf); 1.227 + 1.228 + HDC deviceContext = ::CreateCompatibleDC(NULL); 1.229 + HFONT savefont = (HFONT)SelectObject(deviceContext, font); 1.230 + 1.231 + TEXTMETRIC textMetric; 1.232 + if (0 == GetTextMetrics(deviceContext, &textMetric)) { 1.233 + call_ensure_accessible(lf); 1.234 + if (0 == GetTextMetrics(deviceContext, &textMetric)) { 1.235 + textMetric.tmPitchAndFamily = TMPF_TRUETYPE; 1.236 + } 1.237 + } 1.238 + if (deviceContext) { 1.239 + ::SelectObject(deviceContext, savefont); 1.240 + ::DeleteDC(deviceContext); 1.241 + } 1.242 + if (font) { 1.243 + ::DeleteObject(font); 1.244 + } 1.245 + 1.246 + // The fixed pitch bit is set if the font is *not* fixed pitch. 1.247 + this->setIsFixedPitch((textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0); 1.248 + 1.249 + // Used a logfont on a memory context, should never get a device font. 1.250 + // Therefore all TMPF_DEVICE will be PostScript (cubic) fonts. 1.251 + fCanBeLCD = !((textMetric.tmPitchAndFamily & TMPF_VECTOR) && 1.252 + (textMetric.tmPitchAndFamily & TMPF_DEVICE)); 1.253 + } 1.254 + 1.255 + LOGFONT fLogFont; 1.256 + bool fSerializeAsStream; 1.257 + bool fCanBeLCD; 1.258 + 1.259 + static LogFontTypeface* Create(const LOGFONT& lf) { 1.260 + SkTypeface::Style style = get_style(lf); 1.261 + SkFontID fontID = SkTypefaceCache::NewFontID(); 1.262 + return new LogFontTypeface(style, fontID, lf); 1.263 + } 1.264 + 1.265 + static void EnsureAccessible(const SkTypeface* face) { 1.266 + call_ensure_accessible(static_cast<const LogFontTypeface*>(face)->fLogFont); 1.267 + } 1.268 + 1.269 +protected: 1.270 + virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE; 1.271 + virtual SkScalerContext* onCreateScalerContext(const SkDescriptor*) const SK_OVERRIDE; 1.272 + virtual void onFilterRec(SkScalerContextRec*) const SK_OVERRIDE; 1.273 + virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics( 1.274 + SkAdvancedTypefaceMetrics::PerGlyphInfo, 1.275 + const uint32_t*, uint32_t) const SK_OVERRIDE; 1.276 + virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE; 1.277 + virtual int onCharsToGlyphs(const void* chars, Encoding encoding, 1.278 + uint16_t glyphs[], int glyphCount) const SK_OVERRIDE; 1.279 + virtual int onCountGlyphs() const SK_OVERRIDE; 1.280 + virtual int onGetUPEM() const SK_OVERRIDE; 1.281 + virtual SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const SK_OVERRIDE; 1.282 + virtual int onGetTableTags(SkFontTableTag tags[]) const SK_OVERRIDE; 1.283 + virtual size_t onGetTableData(SkFontTableTag, size_t offset, 1.284 + size_t length, void* data) const SK_OVERRIDE; 1.285 +}; 1.286 + 1.287 +class FontMemResourceTypeface : public LogFontTypeface { 1.288 +public: 1.289 + /** 1.290 + * Takes ownership of fontMemResource. 1.291 + */ 1.292 + FontMemResourceTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf, HANDLE fontMemResource) : 1.293 + LogFontTypeface(style, fontID, lf, true), fFontMemResource(fontMemResource) { 1.294 + } 1.295 + 1.296 + HANDLE fFontMemResource; 1.297 + 1.298 + /** 1.299 + * The created FontMemResourceTypeface takes ownership of fontMemResource. 1.300 + */ 1.301 + static FontMemResourceTypeface* Create(const LOGFONT& lf, HANDLE fontMemResource) { 1.302 + SkTypeface::Style style = get_style(lf); 1.303 + SkFontID fontID = SkTypefaceCache::NewFontID(); 1.304 + return new FontMemResourceTypeface(style, fontID, lf, fontMemResource); 1.305 + } 1.306 + 1.307 +protected: 1.308 + virtual void weak_dispose() const SK_OVERRIDE { 1.309 + RemoveFontMemResourceEx(fFontMemResource); 1.310 + //SkTypefaceCache::Remove(this); 1.311 + INHERITED::weak_dispose(); 1.312 + } 1.313 + 1.314 +private: 1.315 + typedef LogFontTypeface INHERITED; 1.316 +}; 1.317 + 1.318 +static const LOGFONT& get_default_font() { 1.319 + static LOGFONT gDefaultFont; 1.320 + return gDefaultFont; 1.321 +} 1.322 + 1.323 +static bool FindByLogFont(SkTypeface* face, SkTypeface::Style requestedStyle, void* ctx) { 1.324 + LogFontTypeface* lface = static_cast<LogFontTypeface*>(face); 1.325 + const LOGFONT* lf = reinterpret_cast<const LOGFONT*>(ctx); 1.326 + 1.327 + return lface && 1.328 + get_style(lface->fLogFont) == requestedStyle && 1.329 + !memcmp(&lface->fLogFont, lf, sizeof(LOGFONT)); 1.330 +} 1.331 + 1.332 +/** 1.333 + * This guy is public. It first searches the cache, and if a match is not found, 1.334 + * it creates a new face. 1.335 + */ 1.336 +SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT& origLF) { 1.337 + LOGFONT lf = origLF; 1.338 + make_canonical(&lf); 1.339 + SkTypeface* face = SkTypefaceCache::FindByProcAndRef(FindByLogFont, &lf); 1.340 + if (NULL == face) { 1.341 + face = LogFontTypeface::Create(lf); 1.342 + SkTypefaceCache::Add(face, get_style(lf)); 1.343 + } 1.344 + return face; 1.345 +} 1.346 + 1.347 +/** 1.348 + * The created SkTypeface takes ownership of fontMemResource. 1.349 + */ 1.350 +SkTypeface* SkCreateFontMemResourceTypefaceFromLOGFONT(const LOGFONT& origLF, HANDLE fontMemResource) { 1.351 + LOGFONT lf = origLF; 1.352 + make_canonical(&lf); 1.353 + FontMemResourceTypeface* face = FontMemResourceTypeface::Create(lf, fontMemResource); 1.354 + SkTypefaceCache::Add(face, get_style(lf), false); 1.355 + return face; 1.356 +} 1.357 + 1.358 +/** 1.359 + * This guy is public 1.360 + */ 1.361 +void SkLOGFONTFromTypeface(const SkTypeface* face, LOGFONT* lf) { 1.362 + if (NULL == face) { 1.363 + *lf = get_default_font(); 1.364 + } else { 1.365 + *lf = static_cast<const LogFontTypeface*>(face)->fLogFont; 1.366 + } 1.367 +} 1.368 + 1.369 +// Construct Glyph to Unicode table. 1.370 +// Unicode code points that require conjugate pairs in utf16 are not 1.371 +// supported. 1.372 +// TODO(arthurhsu): Add support for conjugate pairs. It looks like that may 1.373 +// require parsing the TTF cmap table (platform 4, encoding 12) directly instead 1.374 +// of calling GetFontUnicodeRange(). 1.375 +static void populate_glyph_to_unicode(HDC fontHdc, const unsigned glyphCount, 1.376 + SkTDArray<SkUnichar>* glyphToUnicode) { 1.377 + DWORD glyphSetBufferSize = GetFontUnicodeRanges(fontHdc, NULL); 1.378 + if (!glyphSetBufferSize) { 1.379 + return; 1.380 + } 1.381 + 1.382 + SkAutoTDeleteArray<BYTE> glyphSetBuffer(new BYTE[glyphSetBufferSize]); 1.383 + GLYPHSET* glyphSet = 1.384 + reinterpret_cast<LPGLYPHSET>(glyphSetBuffer.get()); 1.385 + if (GetFontUnicodeRanges(fontHdc, glyphSet) != glyphSetBufferSize) { 1.386 + return; 1.387 + } 1.388 + 1.389 + glyphToUnicode->setCount(glyphCount); 1.390 + memset(glyphToUnicode->begin(), 0, glyphCount * sizeof(SkUnichar)); 1.391 + for (DWORD i = 0; i < glyphSet->cRanges; ++i) { 1.392 + // There is no guarantee that within a Unicode range, the corresponding 1.393 + // glyph id in a font file are continuous. So, even if we have ranges, 1.394 + // we can't just use the first and last entry of the range to compute 1.395 + // result. We need to enumerate them one by one. 1.396 + int count = glyphSet->ranges[i].cGlyphs; 1.397 + SkAutoTArray<WCHAR> chars(count + 1); 1.398 + chars[count] = 0; // termintate string 1.399 + SkAutoTArray<WORD> glyph(count); 1.400 + for (USHORT j = 0; j < count; ++j) { 1.401 + chars[j] = glyphSet->ranges[i].wcLow + j; 1.402 + } 1.403 + GetGlyphIndicesW(fontHdc, chars.get(), count, glyph.get(), 1.404 + GGI_MARK_NONEXISTING_GLYPHS); 1.405 + // If the glyph ID is valid, and the glyph is not mapped, then we will 1.406 + // fill in the char id into the vector. If the glyph is mapped already, 1.407 + // skip it. 1.408 + // TODO(arthurhsu): better improve this. e.g. Get all used char ids from 1.409 + // font cache, then generate this mapping table from there. It's 1.410 + // unlikely to have collisions since glyph reuse happens mostly for 1.411 + // different Unicode pages. 1.412 + for (USHORT j = 0; j < count; ++j) { 1.413 + if (glyph[j] != 0xffff && glyph[j] < glyphCount && 1.414 + (*glyphToUnicode)[glyph[j]] == 0) { 1.415 + (*glyphToUnicode)[glyph[j]] = chars[j]; 1.416 + } 1.417 + } 1.418 + } 1.419 +} 1.420 + 1.421 +////////////////////////////////////////////////////////////////////////////////////// 1.422 + 1.423 +static int alignTo32(int n) { 1.424 + return (n + 31) & ~31; 1.425 +} 1.426 + 1.427 +struct MyBitmapInfo : public BITMAPINFO { 1.428 + RGBQUAD fMoreSpaceForColors[1]; 1.429 +}; 1.430 + 1.431 +class HDCOffscreen { 1.432 +public: 1.433 + HDCOffscreen() { 1.434 + fFont = 0; 1.435 + fDC = 0; 1.436 + fBM = 0; 1.437 + fBits = NULL; 1.438 + fWidth = fHeight = 0; 1.439 + fIsBW = false; 1.440 + } 1.441 + 1.442 + ~HDCOffscreen() { 1.443 + if (fDC) { 1.444 + DeleteDC(fDC); 1.445 + } 1.446 + if (fBM) { 1.447 + DeleteObject(fBM); 1.448 + } 1.449 + } 1.450 + 1.451 + void init(HFONT font, const XFORM& xform) { 1.452 + fFont = font; 1.453 + fXform = xform; 1.454 + } 1.455 + 1.456 + const void* draw(const SkGlyph&, bool isBW, size_t* srcRBPtr); 1.457 + 1.458 +private: 1.459 + HDC fDC; 1.460 + HBITMAP fBM; 1.461 + HFONT fFont; 1.462 + XFORM fXform; 1.463 + void* fBits; // points into fBM 1.464 + int fWidth; 1.465 + int fHeight; 1.466 + bool fIsBW; 1.467 +}; 1.468 + 1.469 +const void* HDCOffscreen::draw(const SkGlyph& glyph, bool isBW, 1.470 + size_t* srcRBPtr) { 1.471 + // Can we share the scalercontext's fDDC, so we don't need to create 1.472 + // a separate fDC here? 1.473 + if (0 == fDC) { 1.474 + fDC = CreateCompatibleDC(0); 1.475 + if (0 == fDC) { 1.476 + return NULL; 1.477 + } 1.478 + SetGraphicsMode(fDC, GM_ADVANCED); 1.479 + SetBkMode(fDC, TRANSPARENT); 1.480 + SetTextAlign(fDC, TA_LEFT | TA_BASELINE); 1.481 + SelectObject(fDC, fFont); 1.482 + 1.483 + COLORREF color = 0x00FFFFFF; 1.484 + SkDEBUGCODE(COLORREF prev =) SetTextColor(fDC, color); 1.485 + SkASSERT(prev != CLR_INVALID); 1.486 + } 1.487 + 1.488 + if (fBM && (fIsBW != isBW || fWidth < glyph.fWidth || fHeight < glyph.fHeight)) { 1.489 + DeleteObject(fBM); 1.490 + fBM = 0; 1.491 + } 1.492 + fIsBW = isBW; 1.493 + 1.494 + fWidth = SkMax32(fWidth, glyph.fWidth); 1.495 + fHeight = SkMax32(fHeight, glyph.fHeight); 1.496 + 1.497 + int biWidth = isBW ? alignTo32(fWidth) : fWidth; 1.498 + 1.499 + if (0 == fBM) { 1.500 + MyBitmapInfo info; 1.501 + sk_bzero(&info, sizeof(info)); 1.502 + if (isBW) { 1.503 + RGBQUAD blackQuad = { 0, 0, 0, 0 }; 1.504 + RGBQUAD whiteQuad = { 0xFF, 0xFF, 0xFF, 0 }; 1.505 + info.bmiColors[0] = blackQuad; 1.506 + info.bmiColors[1] = whiteQuad; 1.507 + } 1.508 + info.bmiHeader.biSize = sizeof(info.bmiHeader); 1.509 + info.bmiHeader.biWidth = biWidth; 1.510 + info.bmiHeader.biHeight = fHeight; 1.511 + info.bmiHeader.biPlanes = 1; 1.512 + info.bmiHeader.biBitCount = isBW ? 1 : 32; 1.513 + info.bmiHeader.biCompression = BI_RGB; 1.514 + if (isBW) { 1.515 + info.bmiHeader.biClrUsed = 2; 1.516 + } 1.517 + fBM = CreateDIBSection(fDC, &info, DIB_RGB_COLORS, &fBits, 0, 0); 1.518 + if (0 == fBM) { 1.519 + return NULL; 1.520 + } 1.521 + SelectObject(fDC, fBM); 1.522 + } 1.523 + 1.524 + // erase 1.525 + size_t srcRB = isBW ? (biWidth >> 3) : (fWidth << 2); 1.526 + size_t size = fHeight * srcRB; 1.527 + memset(fBits, 0, size); 1.528 + 1.529 + XFORM xform = fXform; 1.530 + xform.eDx = (float)-glyph.fLeft; 1.531 + xform.eDy = (float)-glyph.fTop; 1.532 + SetWorldTransform(fDC, &xform); 1.533 + 1.534 + uint16_t glyphID = glyph.getGlyphID(); 1.535 + BOOL ret = ExtTextOutW(fDC, 0, 0, ETO_GLYPH_INDEX, NULL, reinterpret_cast<LPCWSTR>(&glyphID), 1, NULL); 1.536 + GdiFlush(); 1.537 + if (0 == ret) { 1.538 + return NULL; 1.539 + } 1.540 + *srcRBPtr = srcRB; 1.541 + // offset to the start of the image 1.542 + return (const char*)fBits + (fHeight - glyph.fHeight) * srcRB; 1.543 +} 1.544 + 1.545 +////////////////////////////////////////////////////////////////////////////// 1.546 +#define BUFFERSIZE (1 << 13) 1.547 + 1.548 +class SkScalerContext_GDI : public SkScalerContext { 1.549 +public: 1.550 + SkScalerContext_GDI(SkTypeface*, const SkDescriptor* desc); 1.551 + virtual ~SkScalerContext_GDI(); 1.552 + 1.553 + // Returns true if the constructor was able to complete all of its 1.554 + // initializations (which may include calling GDI). 1.555 + bool isValid() const; 1.556 + 1.557 +protected: 1.558 + virtual unsigned generateGlyphCount() SK_OVERRIDE; 1.559 + virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE; 1.560 + virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE; 1.561 + virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE; 1.562 + virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE; 1.563 + virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE; 1.564 + virtual void generateFontMetrics(SkPaint::FontMetrics* mX, 1.565 + SkPaint::FontMetrics* mY) SK_OVERRIDE; 1.566 + 1.567 +private: 1.568 + DWORD getGDIGlyphPath(const SkGlyph& glyph, UINT flags, 1.569 + SkAutoSTMalloc<BUFFERSIZE, uint8_t>* glyphbuf); 1.570 + 1.571 + HDCOffscreen fOffscreen; 1.572 + /** fGsA is the non-rotational part of total matrix without the text height scale. 1.573 + * Used to find the magnitude of advances. 1.574 + */ 1.575 + MAT2 fGsA; 1.576 + /** The total matrix without the textSize. */ 1.577 + MAT2 fMat22; 1.578 + /** Scales font to EM size. */ 1.579 + MAT2 fHighResMat22; 1.580 + HDC fDDC; 1.581 + HFONT fSavefont; 1.582 + HFONT fFont; 1.583 + SCRIPT_CACHE fSC; 1.584 + int fGlyphCount; 1.585 + 1.586 + /** The total matrix which also removes EM scale. */ 1.587 + SkMatrix fHiResMatrix; 1.588 + /** fG_inv is the inverse of the rotational part of the total matrix. 1.589 + * Used to set the direction of advances. 1.590 + */ 1.591 + SkMatrix fG_inv; 1.592 + enum Type { 1.593 + kTrueType_Type, kBitmap_Type, kLine_Type 1.594 + } fType; 1.595 + TEXTMETRIC fTM; 1.596 +}; 1.597 + 1.598 +static FIXED float2FIXED(float x) { 1.599 + return SkFixedToFIXED(SkFloatToFixed(x)); 1.600 +} 1.601 + 1.602 +static BYTE compute_quality(const SkScalerContext::Rec& rec) { 1.603 + switch (rec.fMaskFormat) { 1.604 + case SkMask::kBW_Format: 1.605 + return NONANTIALIASED_QUALITY; 1.606 + case SkMask::kLCD16_Format: 1.607 + case SkMask::kLCD32_Format: 1.608 + return CLEARTYPE_QUALITY; 1.609 + default: 1.610 + if (rec.fFlags & SkScalerContext::kGenA8FromLCD_Flag) { 1.611 + return CLEARTYPE_QUALITY; 1.612 + } else { 1.613 + return ANTIALIASED_QUALITY; 1.614 + } 1.615 + } 1.616 +} 1.617 + 1.618 +SkScalerContext_GDI::SkScalerContext_GDI(SkTypeface* rawTypeface, 1.619 + const SkDescriptor* desc) 1.620 + : SkScalerContext(rawTypeface, desc) 1.621 + , fDDC(0) 1.622 + , fSavefont(0) 1.623 + , fFont(0) 1.624 + , fSC(0) 1.625 + , fGlyphCount(-1) 1.626 +{ 1.627 + LogFontTypeface* typeface = reinterpret_cast<LogFontTypeface*>(rawTypeface); 1.628 + 1.629 + fDDC = ::CreateCompatibleDC(NULL); 1.630 + if (!fDDC) { 1.631 + return; 1.632 + } 1.633 + SetGraphicsMode(fDDC, GM_ADVANCED); 1.634 + SetBkMode(fDDC, TRANSPARENT); 1.635 + 1.636 + SkPoint h = SkPoint::Make(SK_Scalar1, 0); 1.637 + // A is the total matrix. 1.638 + SkMatrix A; 1.639 + fRec.getSingleMatrix(&A); 1.640 + A.mapPoints(&h, 1); 1.641 + 1.642 + // Find the Given's matrix [[c, -s],[s, c]] which rotates the baseline vector h 1.643 + // (where the baseline is mapped to) to the positive horizontal axis. 1.644 + const SkScalar& a = h.fX; 1.645 + const SkScalar& b = h.fY; 1.646 + SkScalar c, s; 1.647 + if (0 == b) { 1.648 + c = SkDoubleToScalar(_copysign(SK_Scalar1, a)); 1.649 + s = 0; 1.650 + } else if (0 == a) { 1.651 + c = 0; 1.652 + s = SkDoubleToScalar(-_copysign(SK_Scalar1, b)); 1.653 + } else if (SkScalarAbs(b) > SkScalarAbs(a)) { 1.654 + SkScalar t = a / b; 1.655 + SkScalar u = SkDoubleToScalar(_copysign(SkScalarSqrt(SK_Scalar1 + t*t), b)); 1.656 + s = -1 / u; 1.657 + c = -s * t; 1.658 + } else { 1.659 + SkScalar t = b / a; 1.660 + SkScalar u = SkDoubleToScalar(_copysign(SkScalarSqrt(SK_Scalar1 + t*t), a)); 1.661 + c = 1 / u; 1.662 + s = -c * t; 1.663 + } 1.664 + 1.665 + // G is the Given's Matrix for A (rotational matrix such that GA[0][1] == 0). 1.666 + SkMatrix G; 1.667 + G.setAll(c, -s, 0, 1.668 + s, c, 0, 1.669 + 0, 0, SkScalarToPersp(SK_Scalar1)); 1.670 + 1.671 + // GA is the matrix A with rotation removed. 1.672 + SkMatrix GA(G); 1.673 + GA.preConcat(A); 1.674 + 1.675 + // realTextSize is the actual device size we want (as opposed to the size the user requested). 1.676 + // gdiTextSide is the size we request from GDI. 1.677 + // If the scale is negative, this means the matrix will do the flip anyway. 1.678 + SkScalar realTextSize = SkScalarAbs(GA.get(SkMatrix::kMScaleY)); 1.679 + SkScalar gdiTextSize = SkScalarRoundToScalar(realTextSize); 1.680 + if (gdiTextSize == 0) { 1.681 + gdiTextSize = SK_Scalar1; 1.682 + } 1.683 + 1.684 + // When not hinting, remove only the gdiTextSize scale which will be applied by GDI. 1.685 + // When GDI hinting, remove the entire Y scale to prevent 'subpixel' metrics. 1.686 + SkScalar scale = (fRec.getHinting() == SkPaint::kNo_Hinting || 1.687 + fRec.getHinting() == SkPaint::kSlight_Hinting) 1.688 + ? SkScalarInvert(gdiTextSize) 1.689 + : SkScalarInvert(realTextSize); 1.690 + 1.691 + // sA is the total matrix A without the textSize (so GDI knows the text size separately). 1.692 + // When this matrix is used with GetGlyphOutline, no further processing is needed. 1.693 + SkMatrix sA(A); 1.694 + sA.preScale(scale, scale); //remove text size 1.695 + 1.696 + // GsA is the non-rotational part of A without the text height scale. 1.697 + // This is what is used to find the magnitude of advances. 1.698 + SkMatrix GsA(GA); 1.699 + GsA.preScale(scale, scale); //remove text size, G is rotational so reorders with the scale. 1.700 + 1.701 + fGsA.eM11 = SkScalarToFIXED(GsA.get(SkMatrix::kMScaleX)); 1.702 + fGsA.eM12 = SkScalarToFIXED(-GsA.get(SkMatrix::kMSkewY)); // This should be ~0. 1.703 + fGsA.eM21 = SkScalarToFIXED(-GsA.get(SkMatrix::kMSkewX)); 1.704 + fGsA.eM22 = SkScalarToFIXED(GsA.get(SkMatrix::kMScaleY)); 1.705 + 1.706 + // fG_inv is G inverse, which is fairly simple since G is 2x2 rotational. 1.707 + fG_inv.setAll(G.get(SkMatrix::kMScaleX), -G.get(SkMatrix::kMSkewX), G.get(SkMatrix::kMTransX), 1.708 + -G.get(SkMatrix::kMSkewY), G.get(SkMatrix::kMScaleY), G.get(SkMatrix::kMTransY), 1.709 + G.get(SkMatrix::kMPersp0), G.get(SkMatrix::kMPersp1), G.get(SkMatrix::kMPersp2)); 1.710 + 1.711 + LOGFONT lf = typeface->fLogFont; 1.712 + lf.lfHeight = -SkScalarTruncToInt(gdiTextSize); 1.713 + lf.lfQuality = compute_quality(fRec); 1.714 + fFont = CreateFontIndirect(&lf); 1.715 + if (!fFont) { 1.716 + return; 1.717 + } 1.718 + 1.719 + fSavefont = (HFONT)SelectObject(fDDC, fFont); 1.720 + 1.721 + if (0 == GetTextMetrics(fDDC, &fTM)) { 1.722 + call_ensure_accessible(lf); 1.723 + if (0 == GetTextMetrics(fDDC, &fTM)) { 1.724 + fTM.tmPitchAndFamily = TMPF_TRUETYPE; 1.725 + } 1.726 + } 1.727 + 1.728 + XFORM xform; 1.729 + if (fTM.tmPitchAndFamily & TMPF_VECTOR) { 1.730 + // Used a logfont on a memory context, should never get a device font. 1.731 + // Therefore all TMPF_DEVICE will be PostScript fonts. 1.732 + 1.733 + // If TMPF_VECTOR is set, one of TMPF_TRUETYPE or TMPF_DEVICE means that 1.734 + // we have an outline font. Otherwise we have a vector FON, which is 1.735 + // scalable, but not an outline font. 1.736 + // This was determined by testing with Type1 PFM/PFB and 1.737 + // OpenTypeCFF OTF, as well as looking at Wine bugs and sources. 1.738 + if (fTM.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_DEVICE)) { 1.739 + // Truetype or PostScript. 1.740 + fType = SkScalerContext_GDI::kTrueType_Type; 1.741 + } else { 1.742 + // Stroked FON. 1.743 + fType = SkScalerContext_GDI::kLine_Type; 1.744 + } 1.745 + 1.746 + // fPost2x2 is column-major, left handed (y down). 1.747 + // XFORM 2x2 is row-major, left handed (y down). 1.748 + xform.eM11 = SkScalarToFloat(sA.get(SkMatrix::kMScaleX)); 1.749 + xform.eM12 = SkScalarToFloat(sA.get(SkMatrix::kMSkewY)); 1.750 + xform.eM21 = SkScalarToFloat(sA.get(SkMatrix::kMSkewX)); 1.751 + xform.eM22 = SkScalarToFloat(sA.get(SkMatrix::kMScaleY)); 1.752 + xform.eDx = 0; 1.753 + xform.eDy = 0; 1.754 + 1.755 + // MAT2 is row major, right handed (y up). 1.756 + fMat22.eM11 = float2FIXED(xform.eM11); 1.757 + fMat22.eM12 = float2FIXED(-xform.eM12); 1.758 + fMat22.eM21 = float2FIXED(-xform.eM21); 1.759 + fMat22.eM22 = float2FIXED(xform.eM22); 1.760 + 1.761 + if (needToRenderWithSkia(fRec)) { 1.762 + this->forceGenerateImageFromPath(); 1.763 + } 1.764 + 1.765 + // Create a hires matrix if we need linear metrics. 1.766 + if (this->isSubpixel()) { 1.767 + OUTLINETEXTMETRIC otm; 1.768 + UINT success = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm); 1.769 + if (0 == success) { 1.770 + call_ensure_accessible(lf); 1.771 + success = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm); 1.772 + } 1.773 + if (0 != success) { 1.774 + SkScalar upem = SkIntToScalar(otm.otmEMSquare); 1.775 + 1.776 + SkScalar gdiTextSizeToEMScale = upem / gdiTextSize; 1.777 + fHighResMat22.eM11 = float2FIXED(gdiTextSizeToEMScale); 1.778 + fHighResMat22.eM12 = float2FIXED(0); 1.779 + fHighResMat22.eM21 = float2FIXED(0); 1.780 + fHighResMat22.eM22 = float2FIXED(gdiTextSizeToEMScale); 1.781 + 1.782 + SkScalar removeEMScale = SkScalarInvert(upem); 1.783 + fHiResMatrix = A; 1.784 + fHiResMatrix.preScale(removeEMScale, removeEMScale); 1.785 + } 1.786 + } 1.787 + 1.788 + } else { 1.789 + // Assume bitmap 1.790 + fType = SkScalerContext_GDI::kBitmap_Type; 1.791 + 1.792 + xform.eM11 = 1.0f; 1.793 + xform.eM12 = 0.0f; 1.794 + xform.eM21 = 0.0f; 1.795 + xform.eM22 = 1.0f; 1.796 + xform.eDx = 0.0f; 1.797 + xform.eDy = 0.0f; 1.798 + 1.799 + // fPost2x2 is column-major, left handed (y down). 1.800 + // MAT2 is row major, right handed (y up). 1.801 + fMat22.eM11 = SkScalarToFIXED(fRec.fPost2x2[0][0]); 1.802 + fMat22.eM12 = SkScalarToFIXED(-fRec.fPost2x2[1][0]); 1.803 + fMat22.eM21 = SkScalarToFIXED(-fRec.fPost2x2[0][1]); 1.804 + fMat22.eM22 = SkScalarToFIXED(fRec.fPost2x2[1][1]); 1.805 + } 1.806 + 1.807 + fOffscreen.init(fFont, xform); 1.808 +} 1.809 + 1.810 +SkScalerContext_GDI::~SkScalerContext_GDI() { 1.811 + if (fDDC) { 1.812 + ::SelectObject(fDDC, fSavefont); 1.813 + ::DeleteDC(fDDC); 1.814 + } 1.815 + if (fFont) { 1.816 + ::DeleteObject(fFont); 1.817 + } 1.818 + if (fSC) { 1.819 + ::ScriptFreeCache(&fSC); 1.820 + } 1.821 +} 1.822 + 1.823 +bool SkScalerContext_GDI::isValid() const { 1.824 + return fDDC && fFont; 1.825 +} 1.826 + 1.827 +unsigned SkScalerContext_GDI::generateGlyphCount() { 1.828 + if (fGlyphCount < 0) { 1.829 + fGlyphCount = calculateGlyphCount( 1.830 + fDDC, static_cast<const LogFontTypeface*>(this->getTypeface())->fLogFont); 1.831 + } 1.832 + return fGlyphCount; 1.833 +} 1.834 + 1.835 +uint16_t SkScalerContext_GDI::generateCharToGlyph(SkUnichar utf32) { 1.836 + uint16_t index = 0; 1.837 + WCHAR utf16[2]; 1.838 + // TODO(ctguil): Support characters that generate more than one glyph. 1.839 + if (SkUTF16_FromUnichar(utf32, (uint16_t*)utf16) == 1) { 1.840 + // Type1 fonts fail with uniscribe API. Use GetGlyphIndices for plane 0. 1.841 + 1.842 + /** Real documentation for GetGlyphIndiciesW: 1.843 + * 1.844 + * When GGI_MARK_NONEXISTING_GLYPHS is not specified and a character does not map to a 1.845 + * glyph, then the 'default character's glyph is returned instead. The 'default character' 1.846 + * is available in fTM.tmDefaultChar. FON fonts have a default character, and there exists 1.847 + * a usDefaultChar in the 'OS/2' table, version 2 and later. If there is no 1.848 + * 'default character' specified by the font, then often the first character found is used. 1.849 + * 1.850 + * When GGI_MARK_NONEXISTING_GLYPHS is specified and a character does not map to a glyph, 1.851 + * then the glyph 0xFFFF is used. In Windows XP and earlier, Bitmap/Vector FON usually use 1.852 + * glyph 0x1F instead ('Terminal' appears to be special, returning 0xFFFF). 1.853 + * Type1 PFM/PFB, TT, OT TT, OT CFF all appear to use 0xFFFF, even on XP. 1.854 + */ 1.855 + DWORD result = GetGlyphIndicesW(fDDC, utf16, 1, &index, GGI_MARK_NONEXISTING_GLYPHS); 1.856 + if (result == GDI_ERROR 1.857 + || 0xFFFF == index 1.858 + || (0x1F == index && 1.859 + (fType == SkScalerContext_GDI::kBitmap_Type || 1.860 + fType == SkScalerContext_GDI::kLine_Type) 1.861 + /*&& winVer < Vista */) 1.862 + ) 1.863 + { 1.864 + index = 0; 1.865 + } 1.866 + } else { 1.867 + // Use uniscribe to detemine glyph index for non-BMP characters. 1.868 + static const int numWCHAR = 2; 1.869 + static const int maxItems = 2; 1.870 + // MSDN states that this can be NULL, but some things don't work then. 1.871 + SCRIPT_CONTROL sc = { 0 }; 1.872 + // Add extra item to SCRIPT_ITEM to work around a bug (now documented). 1.873 + // https://bugzilla.mozilla.org/show_bug.cgi?id=366643 1.874 + SCRIPT_ITEM si[maxItems + 1]; 1.875 + int numItems; 1.876 + HRZM(ScriptItemize(utf16, numWCHAR, maxItems, &sc, NULL, si, &numItems), 1.877 + "Could not itemize character."); 1.878 + 1.879 + // Sometimes ScriptShape cannot find a glyph for a non-BMP and returns 2 space glyphs. 1.880 + static const int maxGlyphs = 2; 1.881 + SCRIPT_VISATTR vsa[maxGlyphs]; 1.882 + WORD outGlyphs[maxGlyphs]; 1.883 + WORD logClust[numWCHAR]; 1.884 + int numGlyphs; 1.885 + HRZM(ScriptShape(fDDC, &fSC, utf16, numWCHAR, maxGlyphs, &si[0].a, 1.886 + outGlyphs, logClust, vsa, &numGlyphs), 1.887 + "Could not shape character."); 1.888 + if (1 == numGlyphs) { 1.889 + index = outGlyphs[0]; 1.890 + } 1.891 + } 1.892 + return index; 1.893 +} 1.894 + 1.895 +void SkScalerContext_GDI::generateAdvance(SkGlyph* glyph) { 1.896 + this->generateMetrics(glyph); 1.897 +} 1.898 + 1.899 +void SkScalerContext_GDI::generateMetrics(SkGlyph* glyph) { 1.900 + SkASSERT(fDDC); 1.901 + 1.902 + if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) { 1.903 + SIZE size; 1.904 + WORD glyphs = glyph->getGlyphID(0); 1.905 + if (0 == GetTextExtentPointI(fDDC, &glyphs, 1, &size)) { 1.906 + glyph->fWidth = SkToS16(fTM.tmMaxCharWidth); 1.907 + } else { 1.908 + glyph->fWidth = SkToS16(size.cx); 1.909 + } 1.910 + glyph->fHeight = SkToS16(size.cy); 1.911 + 1.912 + glyph->fTop = SkToS16(-fTM.tmAscent); 1.913 + // Bitmap FON cannot underhang, but vector FON may. 1.914 + // There appears no means of determining underhang of vector FON. 1.915 + glyph->fLeft = SkToS16(0); 1.916 + glyph->fAdvanceX = SkIntToFixed(glyph->fWidth); 1.917 + glyph->fAdvanceY = 0; 1.918 + 1.919 + // Vector FON will transform nicely, but bitmap FON do not. 1.920 + if (fType == SkScalerContext_GDI::kLine_Type) { 1.921 + SkRect bounds = SkRect::MakeXYWH(glyph->fLeft, glyph->fTop, 1.922 + glyph->fWidth, glyph->fHeight); 1.923 + SkMatrix m; 1.924 + m.setAll(SkFIXEDToScalar(fMat22.eM11), -SkFIXEDToScalar(fMat22.eM21), 0, 1.925 + -SkFIXEDToScalar(fMat22.eM12), SkFIXEDToScalar(fMat22.eM22), 0, 1.926 + 0, 0, SkScalarToPersp(SK_Scalar1)); 1.927 + m.mapRect(&bounds); 1.928 + bounds.roundOut(); 1.929 + glyph->fLeft = SkScalarTruncToInt(bounds.fLeft); 1.930 + glyph->fTop = SkScalarTruncToInt(bounds.fTop); 1.931 + glyph->fWidth = SkScalarTruncToInt(bounds.width()); 1.932 + glyph->fHeight = SkScalarTruncToInt(bounds.height()); 1.933 + } 1.934 + 1.935 + // Apply matrix to advance. 1.936 + glyph->fAdvanceY = SkFixedMul(-SkFIXEDToFixed(fMat22.eM12), glyph->fAdvanceX); 1.937 + glyph->fAdvanceX = SkFixedMul(SkFIXEDToFixed(fMat22.eM11), glyph->fAdvanceX); 1.938 + 1.939 + return; 1.940 + } 1.941 + 1.942 + UINT glyphId = glyph->getGlyphID(0); 1.943 + 1.944 + GLYPHMETRICS gm; 1.945 + sk_bzero(&gm, sizeof(gm)); 1.946 + 1.947 + DWORD status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22); 1.948 + if (GDI_ERROR == status) { 1.949 + LogFontTypeface::EnsureAccessible(this->getTypeface()); 1.950 + status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22); 1.951 + if (GDI_ERROR == status) { 1.952 + glyph->zeroMetrics(); 1.953 + return; 1.954 + } 1.955 + } 1.956 + 1.957 + bool empty = false; 1.958 + // The black box is either the embedded bitmap size or the outline extent. 1.959 + // It is 1x1 if nothing is to be drawn, but will also be 1x1 if something very small 1.960 + // is to be drawn, like a '.'. We need to outset '.' but do not wish to outset ' '. 1.961 + if (1 == gm.gmBlackBoxX && 1 == gm.gmBlackBoxY) { 1.962 + // If GetGlyphOutline with GGO_NATIVE returns 0, we know there was no outline. 1.963 + DWORD bufferSize = GetGlyphOutlineW(fDDC, glyphId, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22); 1.964 + empty = (0 == bufferSize); 1.965 + } 1.966 + 1.967 + glyph->fTop = SkToS16(-gm.gmptGlyphOrigin.y); 1.968 + glyph->fLeft = SkToS16(gm.gmptGlyphOrigin.x); 1.969 + if (empty) { 1.970 + glyph->fWidth = 0; 1.971 + glyph->fHeight = 0; 1.972 + } else { 1.973 + // Outset, since the image may bleed out of the black box. 1.974 + // For embedded bitmaps the black box should be exact. 1.975 + // For outlines we need to outset by 1 in all directions for bleed. 1.976 + // For ClearType we need to outset by 2 for bleed. 1.977 + glyph->fWidth = gm.gmBlackBoxX + 4; 1.978 + glyph->fHeight = gm.gmBlackBoxY + 4; 1.979 + glyph->fTop -= 2; 1.980 + glyph->fLeft -= 2; 1.981 + } 1.982 + glyph->fAdvanceX = SkIntToFixed(gm.gmCellIncX); 1.983 + glyph->fAdvanceY = SkIntToFixed(gm.gmCellIncY); 1.984 + glyph->fRsbDelta = 0; 1.985 + glyph->fLsbDelta = 0; 1.986 + 1.987 + if (this->isSubpixel()) { 1.988 + sk_bzero(&gm, sizeof(gm)); 1.989 + status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fHighResMat22); 1.990 + if (GDI_ERROR != status) { 1.991 + SkPoint advance; 1.992 + fHiResMatrix.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance); 1.993 + glyph->fAdvanceX = SkScalarToFixed(advance.fX); 1.994 + glyph->fAdvanceY = SkScalarToFixed(advance.fY); 1.995 + } 1.996 + } else if (!isAxisAligned(this->fRec)) { 1.997 + status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fGsA); 1.998 + if (GDI_ERROR != status) { 1.999 + SkPoint advance; 1.1000 + fG_inv.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance); 1.1001 + glyph->fAdvanceX = SkScalarToFixed(advance.fX); 1.1002 + glyph->fAdvanceY = SkScalarToFixed(advance.fY); 1.1003 + } 1.1004 + } 1.1005 +} 1.1006 + 1.1007 +static const MAT2 gMat2Identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}}; 1.1008 +void SkScalerContext_GDI::generateFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my) { 1.1009 + if (!(mx || my)) { 1.1010 + return; 1.1011 + } 1.1012 + 1.1013 + if (mx) { 1.1014 + sk_bzero(mx, sizeof(*mx)); 1.1015 + } 1.1016 + if (my) { 1.1017 + sk_bzero(my, sizeof(*my)); 1.1018 + } 1.1019 + 1.1020 + SkASSERT(fDDC); 1.1021 + 1.1022 +#ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS 1.1023 + if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) { 1.1024 +#endif 1.1025 + if (mx) { 1.1026 + mx->fTop = SkIntToScalar(-fTM.tmAscent); 1.1027 + mx->fAscent = SkIntToScalar(-fTM.tmAscent); 1.1028 + mx->fDescent = SkIntToScalar(fTM.tmDescent); 1.1029 + mx->fBottom = SkIntToScalar(fTM.tmDescent); 1.1030 + mx->fLeading = SkIntToScalar(fTM.tmExternalLeading); 1.1031 + } 1.1032 + 1.1033 + if (my) { 1.1034 + my->fTop = SkIntToScalar(-fTM.tmAscent); 1.1035 + my->fAscent = SkIntToScalar(-fTM.tmAscent); 1.1036 + my->fDescent = SkIntToScalar(fTM.tmDescent); 1.1037 + my->fBottom = SkIntToScalar(fTM.tmDescent); 1.1038 + my->fLeading = SkIntToScalar(fTM.tmExternalLeading); 1.1039 + my->fAvgCharWidth = SkIntToScalar(fTM.tmAveCharWidth); 1.1040 + my->fMaxCharWidth = SkIntToScalar(fTM.tmMaxCharWidth); 1.1041 + my->fXMin = 0; 1.1042 + my->fXMax = my->fMaxCharWidth; 1.1043 + //my->fXHeight = 0; 1.1044 + } 1.1045 +#ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS 1.1046 + return; 1.1047 + } 1.1048 +#endif 1.1049 + 1.1050 + OUTLINETEXTMETRIC otm; 1.1051 + 1.1052 + uint32_t ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm); 1.1053 + if (0 == ret) { 1.1054 + LogFontTypeface::EnsureAccessible(this->getTypeface()); 1.1055 + ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm); 1.1056 + } 1.1057 + if (0 == ret) { 1.1058 + return; 1.1059 + } 1.1060 + 1.1061 + if (mx) { 1.1062 + mx->fTop = SkIntToScalar(-otm.otmrcFontBox.left); 1.1063 + mx->fAscent = SkIntToScalar(-otm.otmAscent); 1.1064 + mx->fDescent = SkIntToScalar(-otm.otmDescent); 1.1065 + mx->fBottom = SkIntToScalar(otm.otmrcFontBox.right); 1.1066 + mx->fLeading = SkIntToScalar(otm.otmLineGap); 1.1067 + mx->fUnderlineThickness = SkIntToScalar(otm.otmsUnderscoreSize); 1.1068 + mx->fUnderlinePosition = -SkIntToScalar(otm.otmsUnderscorePosition); 1.1069 + 1.1070 + mx->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag; 1.1071 + mx->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag; 1.1072 + } 1.1073 + 1.1074 + if (my) { 1.1075 +#ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS 1.1076 + my->fTop = SkIntToScalar(-otm.otmrcFontBox.top); 1.1077 + my->fAscent = SkIntToScalar(-otm.otmAscent); 1.1078 + my->fDescent = SkIntToScalar(-otm.otmDescent); 1.1079 + my->fBottom = SkIntToScalar(-otm.otmrcFontBox.bottom); 1.1080 + my->fLeading = SkIntToScalar(otm.otmLineGap); 1.1081 + my->fAvgCharWidth = SkIntToScalar(otm.otmTextMetrics.tmAveCharWidth); 1.1082 + my->fMaxCharWidth = SkIntToScalar(otm.otmTextMetrics.tmMaxCharWidth); 1.1083 + my->fXMin = SkIntToScalar(otm.otmrcFontBox.left); 1.1084 + my->fXMax = SkIntToScalar(otm.otmrcFontBox.right); 1.1085 + my->fUnderlineThickness = SkIntToScalar(otm.otmsUnderscoreSize); 1.1086 + my->fUnderlinePosition = -SkIntToScalar(otm.otmsUnderscorePosition); 1.1087 + 1.1088 + my->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag; 1.1089 + my->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag; 1.1090 +#endif 1.1091 + my->fXHeight = SkIntToScalar(otm.otmsXHeight); 1.1092 + 1.1093 + GLYPHMETRICS gm; 1.1094 + sk_bzero(&gm, sizeof(gm)); 1.1095 + DWORD len = GetGlyphOutlineW(fDDC, 'x', GGO_METRICS, &gm, 0, 0, &gMat2Identity); 1.1096 + if (len != GDI_ERROR && gm.gmBlackBoxY > 0) { 1.1097 + my->fXHeight = SkIntToScalar(gm.gmBlackBoxY); 1.1098 + } 1.1099 + } 1.1100 +} 1.1101 + 1.1102 +//////////////////////////////////////////////////////////////////////////////////////// 1.1103 + 1.1104 +#define SK_SHOW_TEXT_BLIT_COVERAGE 0 1.1105 + 1.1106 +static void build_power_table(uint8_t table[], float ee) { 1.1107 + for (int i = 0; i < 256; i++) { 1.1108 + float x = i / 255.f; 1.1109 + x = sk_float_pow(x, ee); 1.1110 + int xx = SkScalarRoundToInt(x * 255); 1.1111 + table[i] = SkToU8(xx); 1.1112 + } 1.1113 +} 1.1114 + 1.1115 +/** 1.1116 + * This will invert the gamma applied by GDI (gray-scale antialiased), so we 1.1117 + * can get linear values. 1.1118 + * 1.1119 + * GDI grayscale appears to use a hard-coded gamma of 2.3. 1.1120 + * 1.1121 + * GDI grayscale appears to draw using the black and white rasterizer at four 1.1122 + * times the size and then downsamples to compute the coverage mask. As a 1.1123 + * result there are only seventeen total grays. This lack of fidelity means 1.1124 + * that shifting into other color spaces is imprecise. 1.1125 + */ 1.1126 +static const uint8_t* getInverseGammaTableGDI() { 1.1127 + // Since build_power_table is idempotent, many threads can build gTableGdi 1.1128 + // simultaneously. 1.1129 + 1.1130 + // Microsoft Specific: 1.1131 + // Making gInited volatile provides read-aquire and write-release in vc++. 1.1132 + // In VS2012, see compiler option /volatile:(ms|iso). 1.1133 + // Replace with C++11 atomics when possible. 1.1134 + static volatile bool gInited; 1.1135 + static uint8_t gTableGdi[256]; 1.1136 + if (gInited) { 1.1137 + // Need a L/L (read) barrier (full acquire not needed). If gInited is observed 1.1138 + // true then gTableGdi is observable, but it must be requested. 1.1139 + } else { 1.1140 + build_power_table(gTableGdi, 2.3f); 1.1141 + // Need a S/S (write) barrier (full release not needed) here so that this 1.1142 + // write to gInited becomes observable after gTableGdi. 1.1143 + gInited = true; 1.1144 + } 1.1145 + return gTableGdi; 1.1146 +} 1.1147 + 1.1148 +/** 1.1149 + * This will invert the gamma applied by GDI ClearType, so we can get linear 1.1150 + * values. 1.1151 + * 1.1152 + * GDI ClearType uses SPI_GETFONTSMOOTHINGCONTRAST / 1000 as the gamma value. 1.1153 + * If this value is not specified, the default is a gamma of 1.4. 1.1154 + */ 1.1155 +static const uint8_t* getInverseGammaTableClearType() { 1.1156 + // We don't expect SPI_GETFONTSMOOTHINGCONTRAST to ever change, so building 1.1157 + // gTableClearType with build_power_table is effectively idempotent. 1.1158 + 1.1159 + // Microsoft Specific: 1.1160 + // Making gInited volatile provides read-aquire and write-release in vc++. 1.1161 + // In VS2012, see compiler option /volatile:(ms|iso). 1.1162 + // Replace with C++11 atomics when possible. 1.1163 + static volatile bool gInited; 1.1164 + static uint8_t gTableClearType[256]; 1.1165 + if (gInited) { 1.1166 + // Need a L/L (read) barrier (acquire not needed). If gInited is observed 1.1167 + // true then gTableClearType is observable, but it must be requested. 1.1168 + } else { 1.1169 + UINT level = 0; 1.1170 + if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &level, 0) || !level) { 1.1171 + // can't get the data, so use a default 1.1172 + level = 1400; 1.1173 + } 1.1174 + build_power_table(gTableClearType, level / 1000.0f); 1.1175 + // Need a S/S (write) barrier (release not needed) here so that this 1.1176 + // write to gInited becomes observable after gTableClearType. 1.1177 + gInited = true; 1.1178 + } 1.1179 + return gTableClearType; 1.1180 +} 1.1181 + 1.1182 +#include "SkColorPriv.h" 1.1183 + 1.1184 +//Cannot assume that the input rgb is gray due to possible setting of kGenA8FromLCD_Flag. 1.1185 +template<bool APPLY_PREBLEND> 1.1186 +static inline uint8_t rgb_to_a8(SkGdiRGB rgb, const uint8_t* table8) { 1.1187 + U8CPU r = (rgb >> 16) & 0xFF; 1.1188 + U8CPU g = (rgb >> 8) & 0xFF; 1.1189 + U8CPU b = (rgb >> 0) & 0xFF; 1.1190 + return sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8); 1.1191 +} 1.1192 + 1.1193 +template<bool APPLY_PREBLEND> 1.1194 +static inline uint16_t rgb_to_lcd16(SkGdiRGB rgb, const uint8_t* tableR, 1.1195 + const uint8_t* tableG, 1.1196 + const uint8_t* tableB) { 1.1197 + U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR); 1.1198 + U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG); 1.1199 + U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB); 1.1200 +#if SK_SHOW_TEXT_BLIT_COVERAGE 1.1201 + r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10); 1.1202 +#endif 1.1203 + return SkPack888ToRGB16(r, g, b); 1.1204 +} 1.1205 + 1.1206 +template<bool APPLY_PREBLEND> 1.1207 +static inline SkPMColor rgb_to_lcd32(SkGdiRGB rgb, const uint8_t* tableR, 1.1208 + const uint8_t* tableG, 1.1209 + const uint8_t* tableB) { 1.1210 + U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR); 1.1211 + U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG); 1.1212 + U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB); 1.1213 +#if SK_SHOW_TEXT_BLIT_COVERAGE 1.1214 + r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10); 1.1215 +#endif 1.1216 + return SkPackARGB32(0xFF, r, g, b); 1.1217 +} 1.1218 + 1.1219 +// Is this GDI color neither black nor white? If so, we have to keep this 1.1220 +// image as is, rather than smashing it down to a BW mask. 1.1221 +// 1.1222 +// returns int instead of bool, since we don't want/have to pay to convert 1.1223 +// the zero/non-zero value into a bool 1.1224 +static int is_not_black_or_white(SkGdiRGB c) { 1.1225 + // same as (but faster than) 1.1226 + // c &= 0x00FFFFFF; 1.1227 + // return 0 == c || 0x00FFFFFF == c; 1.1228 + return (c + (c & 1)) & 0x00FFFFFF; 1.1229 +} 1.1230 + 1.1231 +static bool is_rgb_really_bw(const SkGdiRGB* src, int width, int height, size_t srcRB) { 1.1232 + for (int y = 0; y < height; ++y) { 1.1233 + for (int x = 0; x < width; ++x) { 1.1234 + if (is_not_black_or_white(src[x])) { 1.1235 + return false; 1.1236 + } 1.1237 + } 1.1238 + src = SkTAddOffset<const SkGdiRGB>(src, srcRB); 1.1239 + } 1.1240 + return true; 1.1241 +} 1.1242 + 1.1243 +// gdi's bitmap is upside-down, so we reverse dst walking in Y 1.1244 +// whenever we copy it into skia's buffer 1.1245 +static void rgb_to_bw(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, 1.1246 + const SkGlyph& glyph) { 1.1247 + const int width = glyph.fWidth; 1.1248 + const size_t dstRB = (width + 7) >> 3; 1.1249 + uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); 1.1250 + 1.1251 + int byteCount = width >> 3; 1.1252 + int bitCount = width & 7; 1.1253 + 1.1254 + // adjust srcRB to skip the values in our byteCount loop, 1.1255 + // since we increment src locally there 1.1256 + srcRB -= byteCount * 8 * sizeof(SkGdiRGB); 1.1257 + 1.1258 + for (int y = 0; y < glyph.fHeight; ++y) { 1.1259 + if (byteCount > 0) { 1.1260 + for (int i = 0; i < byteCount; ++i) { 1.1261 + unsigned byte = 0; 1.1262 + byte |= src[0] & (1 << 7); 1.1263 + byte |= src[1] & (1 << 6); 1.1264 + byte |= src[2] & (1 << 5); 1.1265 + byte |= src[3] & (1 << 4); 1.1266 + byte |= src[4] & (1 << 3); 1.1267 + byte |= src[5] & (1 << 2); 1.1268 + byte |= src[6] & (1 << 1); 1.1269 + byte |= src[7] & (1 << 0); 1.1270 + dst[i] = byte; 1.1271 + src += 8; 1.1272 + } 1.1273 + } 1.1274 + if (bitCount > 0) { 1.1275 + unsigned byte = 0; 1.1276 + unsigned mask = 0x80; 1.1277 + for (int i = 0; i < bitCount; i++) { 1.1278 + byte |= src[i] & mask; 1.1279 + mask >>= 1; 1.1280 + } 1.1281 + dst[byteCount] = byte; 1.1282 + } 1.1283 + src = SkTAddOffset<const SkGdiRGB>(src, srcRB); 1.1284 + dst -= dstRB; 1.1285 + } 1.1286 +#if SK_SHOW_TEXT_BLIT_COVERAGE 1.1287 + if (glyph.fWidth > 0 && glyph.fHeight > 0) { 1.1288 + uint8_t* first = (uint8_t*)glyph.fImage; 1.1289 + uint8_t* last = (uint8_t*)((char*)glyph.fImage + glyph.fHeight * dstRB - 1); 1.1290 + *first |= 1 << 7; 1.1291 + *last |= bitCount == 0 ? 1 : 1 << (8 - bitCount); 1.1292 + } 1.1293 +#endif 1.1294 +} 1.1295 + 1.1296 +template<bool APPLY_PREBLEND> 1.1297 +static void rgb_to_a8(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, 1.1298 + const SkGlyph& glyph, const uint8_t* table8) { 1.1299 + const size_t dstRB = glyph.rowBytes(); 1.1300 + const int width = glyph.fWidth; 1.1301 + uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); 1.1302 + 1.1303 + for (int y = 0; y < glyph.fHeight; y++) { 1.1304 + for (int i = 0; i < width; i++) { 1.1305 + dst[i] = rgb_to_a8<APPLY_PREBLEND>(src[i], table8); 1.1306 +#if SK_SHOW_TEXT_BLIT_COVERAGE 1.1307 + dst[i] = SkMax32(dst[i], 10); 1.1308 +#endif 1.1309 + } 1.1310 + src = SkTAddOffset<const SkGdiRGB>(src, srcRB); 1.1311 + dst -= dstRB; 1.1312 + } 1.1313 +} 1.1314 + 1.1315 +template<bool APPLY_PREBLEND> 1.1316 +static void rgb_to_lcd16(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph, 1.1317 + const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) { 1.1318 + const size_t dstRB = glyph.rowBytes(); 1.1319 + const int width = glyph.fWidth; 1.1320 + uint16_t* SK_RESTRICT dst = (uint16_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); 1.1321 + 1.1322 + for (int y = 0; y < glyph.fHeight; y++) { 1.1323 + for (int i = 0; i < width; i++) { 1.1324 + dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(src[i], tableR, tableG, tableB); 1.1325 + } 1.1326 + src = SkTAddOffset<const SkGdiRGB>(src, srcRB); 1.1327 + dst = (uint16_t*)((char*)dst - dstRB); 1.1328 + } 1.1329 +} 1.1330 + 1.1331 +template<bool APPLY_PREBLEND> 1.1332 +static void rgb_to_lcd32(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph, 1.1333 + const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) { 1.1334 + const size_t dstRB = glyph.rowBytes(); 1.1335 + const int width = glyph.fWidth; 1.1336 + uint32_t* SK_RESTRICT dst = (uint32_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); 1.1337 + 1.1338 + for (int y = 0; y < glyph.fHeight; y++) { 1.1339 + for (int i = 0; i < width; i++) { 1.1340 + dst[i] = rgb_to_lcd32<APPLY_PREBLEND>(src[i], tableR, tableG, tableB); 1.1341 + } 1.1342 + src = SkTAddOffset<const SkGdiRGB>(src, srcRB); 1.1343 + dst = (uint32_t*)((char*)dst - dstRB); 1.1344 + } 1.1345 +} 1.1346 + 1.1347 +static inline unsigned clamp255(unsigned x) { 1.1348 + SkASSERT(x <= 256); 1.1349 + return x - (x >> 8); 1.1350 +} 1.1351 + 1.1352 +void SkScalerContext_GDI::generateImage(const SkGlyph& glyph) { 1.1353 + SkASSERT(fDDC); 1.1354 + 1.1355 + const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat; 1.1356 + const bool isAA = !isLCD(fRec); 1.1357 + 1.1358 + size_t srcRB; 1.1359 + const void* bits = fOffscreen.draw(glyph, isBW, &srcRB); 1.1360 + if (NULL == bits) { 1.1361 + LogFontTypeface::EnsureAccessible(this->getTypeface()); 1.1362 + bits = fOffscreen.draw(glyph, isBW, &srcRB); 1.1363 + if (NULL == bits) { 1.1364 + sk_bzero(glyph.fImage, glyph.computeImageSize()); 1.1365 + return; 1.1366 + } 1.1367 + } 1.1368 + 1.1369 + if (!isBW) { 1.1370 + const uint8_t* table; 1.1371 + //The offscreen contains a GDI blit if isAA and kGenA8FromLCD_Flag is not set. 1.1372 + //Otherwise the offscreen contains a ClearType blit. 1.1373 + if (isAA && !(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag)) { 1.1374 + table = getInverseGammaTableGDI(); 1.1375 + } else { 1.1376 + table = getInverseGammaTableClearType(); 1.1377 + } 1.1378 + //Note that the following cannot really be integrated into the 1.1379 + //pre-blend, since we may not be applying the pre-blend; when we aren't 1.1380 + //applying the pre-blend it means that a filter wants linear anyway. 1.1381 + //Other code may also be applying the pre-blend, so we'd need another 1.1382 + //one with this and one without. 1.1383 + SkGdiRGB* addr = (SkGdiRGB*)bits; 1.1384 + for (int y = 0; y < glyph.fHeight; ++y) { 1.1385 + for (int x = 0; x < glyph.fWidth; ++x) { 1.1386 + int r = (addr[x] >> 16) & 0xFF; 1.1387 + int g = (addr[x] >> 8) & 0xFF; 1.1388 + int b = (addr[x] >> 0) & 0xFF; 1.1389 + addr[x] = (table[r] << 16) | (table[g] << 8) | table[b]; 1.1390 + } 1.1391 + addr = SkTAddOffset<SkGdiRGB>(addr, srcRB); 1.1392 + } 1.1393 + } 1.1394 + 1.1395 + int width = glyph.fWidth; 1.1396 + size_t dstRB = glyph.rowBytes(); 1.1397 + if (isBW) { 1.1398 + const uint8_t* src = (const uint8_t*)bits; 1.1399 + uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); 1.1400 + for (int y = 0; y < glyph.fHeight; y++) { 1.1401 + memcpy(dst, src, dstRB); 1.1402 + src += srcRB; 1.1403 + dst -= dstRB; 1.1404 + } 1.1405 +#if SK_SHOW_TEXT_BLIT_COVERAGE 1.1406 + if (glyph.fWidth > 0 && glyph.fHeight > 0) { 1.1407 + int bitCount = width & 7; 1.1408 + uint8_t* first = (uint8_t*)glyph.fImage; 1.1409 + uint8_t* last = (uint8_t*)((char*)glyph.fImage + glyph.fHeight * dstRB - 1); 1.1410 + *first |= 1 << 7; 1.1411 + *last |= bitCount == 0 ? 1 : 1 << (8 - bitCount); 1.1412 + } 1.1413 +#endif 1.1414 + } else if (isAA) { 1.1415 + // since the caller may require A8 for maskfilters, we can't check for BW 1.1416 + // ... until we have the caller tell us that explicitly 1.1417 + const SkGdiRGB* src = (const SkGdiRGB*)bits; 1.1418 + if (fPreBlend.isApplicable()) { 1.1419 + rgb_to_a8<true>(src, srcRB, glyph, fPreBlend.fG); 1.1420 + } else { 1.1421 + rgb_to_a8<false>(src, srcRB, glyph, fPreBlend.fG); 1.1422 + } 1.1423 + } else { // LCD16 1.1424 + const SkGdiRGB* src = (const SkGdiRGB*)bits; 1.1425 + if (is_rgb_really_bw(src, width, glyph.fHeight, srcRB)) { 1.1426 + rgb_to_bw(src, srcRB, glyph); 1.1427 + ((SkGlyph*)&glyph)->fMaskFormat = SkMask::kBW_Format; 1.1428 + } else { 1.1429 + if (SkMask::kLCD16_Format == glyph.fMaskFormat) { 1.1430 + if (fPreBlend.isApplicable()) { 1.1431 + rgb_to_lcd16<true>(src, srcRB, glyph, 1.1432 + fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 1.1433 + } else { 1.1434 + rgb_to_lcd16<false>(src, srcRB, glyph, 1.1435 + fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 1.1436 + } 1.1437 + } else { 1.1438 + SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat); 1.1439 + if (fPreBlend.isApplicable()) { 1.1440 + rgb_to_lcd32<true>(src, srcRB, glyph, 1.1441 + fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 1.1442 + } else { 1.1443 + rgb_to_lcd32<false>(src, srcRB, glyph, 1.1444 + fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); 1.1445 + } 1.1446 + } 1.1447 + } 1.1448 + } 1.1449 +} 1.1450 + 1.1451 +class GDIGlyphbufferPointIter { 1.1452 +public: 1.1453 + GDIGlyphbufferPointIter(const uint8_t* glyphbuf, DWORD total_size) 1.1454 + : fHeaderIter(glyphbuf, total_size), fCurveIter(), fPointIter() 1.1455 + { } 1.1456 + 1.1457 + POINTFX const * next() { 1.1458 +nextHeader: 1.1459 + if (!fCurveIter.isSet()) { 1.1460 + const TTPOLYGONHEADER* header = fHeaderIter.next(); 1.1461 + if (NULL == header) { 1.1462 + return NULL; 1.1463 + } 1.1464 + fCurveIter.set(header); 1.1465 + const TTPOLYCURVE* curve = fCurveIter.next(); 1.1466 + if (NULL == curve) { 1.1467 + return NULL; 1.1468 + } 1.1469 + fPointIter.set(curve); 1.1470 + return &header->pfxStart; 1.1471 + } 1.1472 + 1.1473 + const POINTFX* nextPoint = fPointIter.next(); 1.1474 + if (NULL == nextPoint) { 1.1475 + const TTPOLYCURVE* curve = fCurveIter.next(); 1.1476 + if (NULL == curve) { 1.1477 + fCurveIter.set(); 1.1478 + goto nextHeader; 1.1479 + } else { 1.1480 + fPointIter.set(curve); 1.1481 + } 1.1482 + nextPoint = fPointIter.next(); 1.1483 + } 1.1484 + return nextPoint; 1.1485 + } 1.1486 + 1.1487 + WORD currentCurveType() { 1.1488 + return fPointIter.fCurveType; 1.1489 + } 1.1490 + 1.1491 +private: 1.1492 + /** Iterates over all of the polygon headers in a glyphbuf. */ 1.1493 + class GDIPolygonHeaderIter { 1.1494 + public: 1.1495 + GDIPolygonHeaderIter(const uint8_t* glyphbuf, DWORD total_size) 1.1496 + : fCurPolygon(reinterpret_cast<const TTPOLYGONHEADER*>(glyphbuf)) 1.1497 + , fEndPolygon(SkTAddOffset<const TTPOLYGONHEADER>(glyphbuf, total_size)) 1.1498 + { } 1.1499 + 1.1500 + const TTPOLYGONHEADER* next() { 1.1501 + if (fCurPolygon >= fEndPolygon) { 1.1502 + return NULL; 1.1503 + } 1.1504 + const TTPOLYGONHEADER* thisPolygon = fCurPolygon; 1.1505 + fCurPolygon = SkTAddOffset<const TTPOLYGONHEADER>(fCurPolygon, fCurPolygon->cb); 1.1506 + return thisPolygon; 1.1507 + } 1.1508 + private: 1.1509 + const TTPOLYGONHEADER* fCurPolygon; 1.1510 + const TTPOLYGONHEADER* fEndPolygon; 1.1511 + }; 1.1512 + 1.1513 + /** Iterates over all of the polygon curves in a polygon header. */ 1.1514 + class GDIPolygonCurveIter { 1.1515 + public: 1.1516 + GDIPolygonCurveIter() : fCurCurve(NULL), fEndCurve(NULL) { } 1.1517 + 1.1518 + GDIPolygonCurveIter(const TTPOLYGONHEADER* curPolygon) 1.1519 + : fCurCurve(SkTAddOffset<const TTPOLYCURVE>(curPolygon, sizeof(TTPOLYGONHEADER))) 1.1520 + , fEndCurve(SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon->cb)) 1.1521 + { } 1.1522 + 1.1523 + bool isSet() { return fCurCurve != NULL; } 1.1524 + 1.1525 + void set(const TTPOLYGONHEADER* curPolygon) { 1.1526 + fCurCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon, sizeof(TTPOLYGONHEADER)); 1.1527 + fEndCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon->cb); 1.1528 + } 1.1529 + void set() { 1.1530 + fCurCurve = NULL; 1.1531 + fEndCurve = NULL; 1.1532 + } 1.1533 + 1.1534 + const TTPOLYCURVE* next() { 1.1535 + if (fCurCurve >= fEndCurve) { 1.1536 + return NULL; 1.1537 + } 1.1538 + const TTPOLYCURVE* thisCurve = fCurCurve; 1.1539 + fCurCurve = SkTAddOffset<const TTPOLYCURVE>(fCurCurve, size_of_TTPOLYCURVE(*fCurCurve)); 1.1540 + return thisCurve; 1.1541 + } 1.1542 + private: 1.1543 + size_t size_of_TTPOLYCURVE(const TTPOLYCURVE& curve) { 1.1544 + return 2*sizeof(WORD) + curve.cpfx*sizeof(POINTFX); 1.1545 + } 1.1546 + const TTPOLYCURVE* fCurCurve; 1.1547 + const TTPOLYCURVE* fEndCurve; 1.1548 + }; 1.1549 + 1.1550 + /** Iterates over all of the polygon points in a polygon curve. */ 1.1551 + class GDIPolygonCurvePointIter { 1.1552 + public: 1.1553 + GDIPolygonCurvePointIter() : fCurveType(0), fCurPoint(NULL), fEndPoint(NULL) { } 1.1554 + 1.1555 + GDIPolygonCurvePointIter(const TTPOLYCURVE* curPolygon) 1.1556 + : fCurveType(curPolygon->wType) 1.1557 + , fCurPoint(&curPolygon->apfx[0]) 1.1558 + , fEndPoint(&curPolygon->apfx[curPolygon->cpfx]) 1.1559 + { } 1.1560 + 1.1561 + bool isSet() { return fCurPoint != NULL; } 1.1562 + 1.1563 + void set(const TTPOLYCURVE* curPolygon) { 1.1564 + fCurveType = curPolygon->wType; 1.1565 + fCurPoint = &curPolygon->apfx[0]; 1.1566 + fEndPoint = &curPolygon->apfx[curPolygon->cpfx]; 1.1567 + } 1.1568 + void set() { 1.1569 + fCurPoint = NULL; 1.1570 + fEndPoint = NULL; 1.1571 + } 1.1572 + 1.1573 + const POINTFX* next() { 1.1574 + if (fCurPoint >= fEndPoint) { 1.1575 + return NULL; 1.1576 + } 1.1577 + const POINTFX* thisPoint = fCurPoint; 1.1578 + ++fCurPoint; 1.1579 + return thisPoint; 1.1580 + } 1.1581 + 1.1582 + WORD fCurveType; 1.1583 + private: 1.1584 + const POINTFX* fCurPoint; 1.1585 + const POINTFX* fEndPoint; 1.1586 + }; 1.1587 + 1.1588 + GDIPolygonHeaderIter fHeaderIter; 1.1589 + GDIPolygonCurveIter fCurveIter; 1.1590 + GDIPolygonCurvePointIter fPointIter; 1.1591 +}; 1.1592 + 1.1593 +static void sk_path_from_gdi_path(SkPath* path, const uint8_t* glyphbuf, DWORD total_size) { 1.1594 + const uint8_t* cur_glyph = glyphbuf; 1.1595 + const uint8_t* end_glyph = glyphbuf + total_size; 1.1596 + 1.1597 + while (cur_glyph < end_glyph) { 1.1598 + const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph; 1.1599 + 1.1600 + const uint8_t* end_poly = cur_glyph + th->cb; 1.1601 + const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER); 1.1602 + 1.1603 + path->moveTo(SkFixedToScalar( SkFIXEDToFixed(th->pfxStart.x)), 1.1604 + SkFixedToScalar(-SkFIXEDToFixed(th->pfxStart.y))); 1.1605 + 1.1606 + while (cur_poly < end_poly) { 1.1607 + const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly; 1.1608 + 1.1609 + if (pc->wType == TT_PRIM_LINE) { 1.1610 + for (uint16_t i = 0; i < pc->cpfx; i++) { 1.1611 + path->lineTo(SkFixedToScalar( SkFIXEDToFixed(pc->apfx[i].x)), 1.1612 + SkFixedToScalar(-SkFIXEDToFixed(pc->apfx[i].y))); 1.1613 + } 1.1614 + } 1.1615 + 1.1616 + if (pc->wType == TT_PRIM_QSPLINE) { 1.1617 + for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline 1.1618 + POINTFX pnt_b = pc->apfx[u]; // B is always the current point 1.1619 + POINTFX pnt_c = pc->apfx[u+1]; 1.1620 + 1.1621 + if (u < pc->cpfx - 2) { // If not on last spline, compute C 1.1622 + pnt_c.x = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.x), 1.1623 + SkFIXEDToFixed(pnt_c.x))); 1.1624 + pnt_c.y = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.y), 1.1625 + SkFIXEDToFixed(pnt_c.y))); 1.1626 + } 1.1627 + 1.1628 + path->quadTo(SkFixedToScalar( SkFIXEDToFixed(pnt_b.x)), 1.1629 + SkFixedToScalar(-SkFIXEDToFixed(pnt_b.y)), 1.1630 + SkFixedToScalar( SkFIXEDToFixed(pnt_c.x)), 1.1631 + SkFixedToScalar(-SkFIXEDToFixed(pnt_c.y))); 1.1632 + } 1.1633 + } 1.1634 + // Advance past this TTPOLYCURVE. 1.1635 + cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx; 1.1636 + } 1.1637 + cur_glyph += th->cb; 1.1638 + path->close(); 1.1639 + } 1.1640 +} 1.1641 + 1.1642 +#define move_next_expected_hinted_point(iter, pElem) do {\ 1.1643 + pElem = iter.next(); \ 1.1644 + if (NULL == pElem) return false; \ 1.1645 +} while(0) 1.1646 + 1.1647 +// It is possible for the hinted and unhinted versions of the same path to have 1.1648 +// a different number of points due to GDI's handling of flipped points. 1.1649 +// If this is detected, this will return false. 1.1650 +static bool sk_path_from_gdi_paths(SkPath* path, const uint8_t* glyphbuf, DWORD total_size, 1.1651 + GDIGlyphbufferPointIter hintedYs) { 1.1652 + const uint8_t* cur_glyph = glyphbuf; 1.1653 + const uint8_t* end_glyph = glyphbuf + total_size; 1.1654 + 1.1655 + POINTFX const * hintedPoint; 1.1656 + 1.1657 + while (cur_glyph < end_glyph) { 1.1658 + const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph; 1.1659 + 1.1660 + const uint8_t* end_poly = cur_glyph + th->cb; 1.1661 + const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER); 1.1662 + 1.1663 + move_next_expected_hinted_point(hintedYs, hintedPoint); 1.1664 + path->moveTo(SkFixedToScalar( SkFIXEDToFixed(th->pfxStart.x)), 1.1665 + SkFixedToScalar(-SkFIXEDToFixed(hintedPoint->y))); 1.1666 + 1.1667 + while (cur_poly < end_poly) { 1.1668 + const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly; 1.1669 + 1.1670 + if (pc->wType == TT_PRIM_LINE) { 1.1671 + for (uint16_t i = 0; i < pc->cpfx; i++) { 1.1672 + move_next_expected_hinted_point(hintedYs, hintedPoint); 1.1673 + path->lineTo(SkFixedToScalar( SkFIXEDToFixed(pc->apfx[i].x)), 1.1674 + SkFixedToScalar(-SkFIXEDToFixed(hintedPoint->y))); 1.1675 + } 1.1676 + } 1.1677 + 1.1678 + if (pc->wType == TT_PRIM_QSPLINE) { 1.1679 + POINTFX currentPoint = pc->apfx[0]; 1.1680 + move_next_expected_hinted_point(hintedYs, hintedPoint); 1.1681 + // only take the hinted y if it wasn't flipped 1.1682 + if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) { 1.1683 + currentPoint.y = hintedPoint->y; 1.1684 + } 1.1685 + for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline 1.1686 + POINTFX pnt_b = currentPoint;//pc->apfx[u]; // B is always the current point 1.1687 + POINTFX pnt_c = pc->apfx[u+1]; 1.1688 + move_next_expected_hinted_point(hintedYs, hintedPoint); 1.1689 + // only take the hinted y if it wasn't flipped 1.1690 + if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) { 1.1691 + pnt_c.y = hintedPoint->y; 1.1692 + } 1.1693 + currentPoint.x = pnt_c.x; 1.1694 + currentPoint.y = pnt_c.y; 1.1695 + 1.1696 + if (u < pc->cpfx - 2) { // If not on last spline, compute C 1.1697 + pnt_c.x = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.x), 1.1698 + SkFIXEDToFixed(pnt_c.x))); 1.1699 + pnt_c.y = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.y), 1.1700 + SkFIXEDToFixed(pnt_c.y))); 1.1701 + } 1.1702 + 1.1703 + path->quadTo(SkFixedToScalar( SkFIXEDToFixed(pnt_b.x)), 1.1704 + SkFixedToScalar(-SkFIXEDToFixed(pnt_b.y)), 1.1705 + SkFixedToScalar( SkFIXEDToFixed(pnt_c.x)), 1.1706 + SkFixedToScalar(-SkFIXEDToFixed(pnt_c.y))); 1.1707 + } 1.1708 + } 1.1709 + // Advance past this TTPOLYCURVE. 1.1710 + cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx; 1.1711 + } 1.1712 + cur_glyph += th->cb; 1.1713 + path->close(); 1.1714 + } 1.1715 + return true; 1.1716 +} 1.1717 + 1.1718 +DWORD SkScalerContext_GDI::getGDIGlyphPath(const SkGlyph& glyph, UINT flags, 1.1719 + SkAutoSTMalloc<BUFFERSIZE, uint8_t>* glyphbuf) 1.1720 +{ 1.1721 + GLYPHMETRICS gm; 1.1722 + 1.1723 + DWORD total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, BUFFERSIZE, glyphbuf->get(), &fMat22); 1.1724 + // Sometimes GetGlyphOutlineW returns a number larger than BUFFERSIZE even if BUFFERSIZE > 0. 1.1725 + // It has been verified that this does not involve a buffer overrun. 1.1726 + if (GDI_ERROR == total_size || total_size > BUFFERSIZE) { 1.1727 + // GDI_ERROR because the BUFFERSIZE was too small, or because the data was not accessible. 1.1728 + // When the data is not accessable GetGlyphOutlineW fails rather quickly, 1.1729 + // so just try to get the size. If that fails then ensure the data is accessible. 1.1730 + total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, 0, NULL, &fMat22); 1.1731 + if (GDI_ERROR == total_size) { 1.1732 + LogFontTypeface::EnsureAccessible(this->getTypeface()); 1.1733 + total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, 0, NULL, &fMat22); 1.1734 + if (GDI_ERROR == total_size) { 1.1735 + SkASSERT(false); 1.1736 + return 0; 1.1737 + } 1.1738 + } 1.1739 + 1.1740 + glyphbuf->reset(total_size); 1.1741 + 1.1742 + DWORD ret = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, total_size, glyphbuf->get(), &fMat22); 1.1743 + if (GDI_ERROR == ret) { 1.1744 + LogFontTypeface::EnsureAccessible(this->getTypeface()); 1.1745 + ret = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, total_size, glyphbuf->get(), &fMat22); 1.1746 + if (GDI_ERROR == ret) { 1.1747 + SkASSERT(false); 1.1748 + return 0; 1.1749 + } 1.1750 + } 1.1751 + } 1.1752 + return total_size; 1.1753 +} 1.1754 + 1.1755 +void SkScalerContext_GDI::generatePath(const SkGlyph& glyph, SkPath* path) { 1.1756 + SkASSERT(&glyph && path); 1.1757 + SkASSERT(fDDC); 1.1758 + 1.1759 + path->reset(); 1.1760 + 1.1761 + // Out of all the fonts on a typical Windows box, 1.1762 + // 25% of glyphs require more than 2KB. 1.1763 + // 1% of glyphs require more than 4KB. 1.1764 + // 0.01% of glyphs require more than 8KB. 1.1765 + // 8KB is less than 1% of the normal 1MB stack on Windows. 1.1766 + // Note that some web fonts glyphs require more than 20KB. 1.1767 + //static const DWORD BUFFERSIZE = (1 << 13); 1.1768 + 1.1769 + //GDI only uses hinted outlines when axis aligned. 1.1770 + UINT format = GGO_NATIVE | GGO_GLYPH_INDEX; 1.1771 + if (fRec.getHinting() == SkPaint::kNo_Hinting || fRec.getHinting() == SkPaint::kSlight_Hinting){ 1.1772 + format |= GGO_UNHINTED; 1.1773 + } 1.1774 + SkAutoSTMalloc<BUFFERSIZE, uint8_t> glyphbuf(BUFFERSIZE); 1.1775 + DWORD total_size = getGDIGlyphPath(glyph, format, &glyphbuf); 1.1776 + if (0 == total_size) { 1.1777 + return; 1.1778 + } 1.1779 + 1.1780 + if (fRec.getHinting() != SkPaint::kSlight_Hinting) { 1.1781 + sk_path_from_gdi_path(path, glyphbuf, total_size); 1.1782 + } else { 1.1783 + //GDI only uses hinted outlines when axis aligned. 1.1784 + UINT format = GGO_NATIVE | GGO_GLYPH_INDEX; 1.1785 + 1.1786 + SkAutoSTMalloc<BUFFERSIZE, uint8_t> hintedGlyphbuf(BUFFERSIZE); 1.1787 + DWORD hinted_total_size = getGDIGlyphPath(glyph, format, &hintedGlyphbuf); 1.1788 + if (0 == hinted_total_size) { 1.1789 + return; 1.1790 + } 1.1791 + 1.1792 + if (!sk_path_from_gdi_paths(path, glyphbuf, total_size, 1.1793 + GDIGlyphbufferPointIter(hintedGlyphbuf, hinted_total_size))) 1.1794 + { 1.1795 + path->reset(); 1.1796 + sk_path_from_gdi_path(path, glyphbuf, total_size); 1.1797 + } 1.1798 + } 1.1799 +} 1.1800 + 1.1801 +static void logfont_for_name(const char* familyName, LOGFONT* lf) { 1.1802 + sk_bzero(lf, sizeof(LOGFONT)); 1.1803 +#ifdef UNICODE 1.1804 + // Get the buffer size needed first. 1.1805 + size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName, 1.1806 + -1, NULL, 0); 1.1807 + // Allocate a buffer (str_len already has terminating null 1.1808 + // accounted for). 1.1809 + wchar_t *wideFamilyName = new wchar_t[str_len]; 1.1810 + // Now actually convert the string. 1.1811 + ::MultiByteToWideChar(CP_UTF8, 0, familyName, -1, 1.1812 + wideFamilyName, str_len); 1.1813 + ::wcsncpy(lf->lfFaceName, wideFamilyName, LF_FACESIZE - 1); 1.1814 + delete [] wideFamilyName; 1.1815 + lf->lfFaceName[LF_FACESIZE-1] = L'\0'; 1.1816 +#else 1.1817 + ::strncpy(lf->lfFaceName, familyName, LF_FACESIZE - 1); 1.1818 + lf->lfFaceName[LF_FACESIZE - 1] = '\0'; 1.1819 +#endif 1.1820 +} 1.1821 + 1.1822 +void LogFontTypeface::onGetFontDescriptor(SkFontDescriptor* desc, 1.1823 + bool* isLocalStream) const { 1.1824 + // Get the actual name of the typeface. The logfont may not know this. 1.1825 + HFONT font = CreateFontIndirect(&fLogFont); 1.1826 + 1.1827 + HDC deviceContext = ::CreateCompatibleDC(NULL); 1.1828 + HFONT savefont = (HFONT)SelectObject(deviceContext, font); 1.1829 + 1.1830 + SkString familyName; 1.1831 + dcfontname_to_skstring(deviceContext, fLogFont, &familyName); 1.1832 + 1.1833 + if (deviceContext) { 1.1834 + ::SelectObject(deviceContext, savefont); 1.1835 + ::DeleteDC(deviceContext); 1.1836 + } 1.1837 + if (font) { 1.1838 + ::DeleteObject(font); 1.1839 + } 1.1840 + 1.1841 + desc->setFamilyName(familyName.c_str()); 1.1842 + *isLocalStream = this->fSerializeAsStream; 1.1843 +} 1.1844 + 1.1845 +static bool getWidthAdvance(HDC hdc, int gId, int16_t* advance) { 1.1846 + // Initialize the MAT2 structure to the identify transformation matrix. 1.1847 + static const MAT2 mat2 = {SkScalarToFIXED(1), SkScalarToFIXED(0), 1.1848 + SkScalarToFIXED(0), SkScalarToFIXED(1)}; 1.1849 + int flags = GGO_METRICS | GGO_GLYPH_INDEX; 1.1850 + GLYPHMETRICS gm; 1.1851 + if (GDI_ERROR == GetGlyphOutline(hdc, gId, flags, &gm, 0, NULL, &mat2)) { 1.1852 + return false; 1.1853 + } 1.1854 + SkASSERT(advance); 1.1855 + *advance = gm.gmCellIncX; 1.1856 + return true; 1.1857 +} 1.1858 + 1.1859 +SkAdvancedTypefaceMetrics* LogFontTypeface::onGetAdvancedTypefaceMetrics( 1.1860 + SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo, 1.1861 + const uint32_t* glyphIDs, 1.1862 + uint32_t glyphIDsCount) const { 1.1863 + LOGFONT lf = fLogFont; 1.1864 + SkAdvancedTypefaceMetrics* info = NULL; 1.1865 + 1.1866 + HDC hdc = CreateCompatibleDC(NULL); 1.1867 + HFONT font = CreateFontIndirect(&lf); 1.1868 + HFONT savefont = (HFONT)SelectObject(hdc, font); 1.1869 + HFONT designFont = NULL; 1.1870 + 1.1871 + const char stem_chars[] = {'i', 'I', '!', '1'}; 1.1872 + int16_t min_width; 1.1873 + unsigned glyphCount; 1.1874 + 1.1875 + // To request design units, create a logical font whose height is specified 1.1876 + // as unitsPerEm. 1.1877 + OUTLINETEXTMETRIC otm; 1.1878 + unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm); 1.1879 + if (0 == otmRet) { 1.1880 + call_ensure_accessible(lf); 1.1881 + otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm); 1.1882 + } 1.1883 + if (!otmRet || !GetTextFace(hdc, LF_FACESIZE, lf.lfFaceName)) { 1.1884 + goto Error; 1.1885 + } 1.1886 + lf.lfHeight = -SkToS32(otm.otmEMSquare); 1.1887 + designFont = CreateFontIndirect(&lf); 1.1888 + SelectObject(hdc, designFont); 1.1889 + if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm)) { 1.1890 + goto Error; 1.1891 + } 1.1892 + glyphCount = calculateGlyphCount(hdc, fLogFont); 1.1893 + 1.1894 + info = new SkAdvancedTypefaceMetrics; 1.1895 + info->fEmSize = otm.otmEMSquare; 1.1896 + info->fMultiMaster = false; 1.1897 + info->fLastGlyphID = SkToU16(glyphCount - 1); 1.1898 + info->fStyle = 0; 1.1899 + tchar_to_skstring(lf.lfFaceName, &info->fFontName); 1.1900 + 1.1901 + if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) { 1.1902 + populate_glyph_to_unicode(hdc, glyphCount, &(info->fGlyphToUnicode)); 1.1903 + } 1.1904 + 1.1905 + if (glyphCount > 0 && 1.1906 + (otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE)) { 1.1907 + info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font; 1.1908 + } else { 1.1909 + info->fType = SkAdvancedTypefaceMetrics::kOther_Font; 1.1910 + info->fItalicAngle = 0; 1.1911 + info->fAscent = 0; 1.1912 + info->fDescent = 0; 1.1913 + info->fStemV = 0; 1.1914 + info->fCapHeight = 0; 1.1915 + info->fBBox = SkIRect::MakeEmpty(); 1.1916 + goto ReturnInfo; 1.1917 + } 1.1918 + 1.1919 + // If this bit is clear the font is a fixed pitch font. 1.1920 + if (!(otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) { 1.1921 + info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style; 1.1922 + } 1.1923 + if (otm.otmTextMetrics.tmItalic) { 1.1924 + info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style; 1.1925 + } 1.1926 + if (otm.otmTextMetrics.tmPitchAndFamily & FF_ROMAN) { 1.1927 + info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style; 1.1928 + } else if (otm.otmTextMetrics.tmPitchAndFamily & FF_SCRIPT) { 1.1929 + info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style; 1.1930 + } 1.1931 + 1.1932 + // The main italic angle of the font, in tenths of a degree counterclockwise 1.1933 + // from vertical. 1.1934 + info->fItalicAngle = otm.otmItalicAngle / 10; 1.1935 + info->fAscent = SkToS16(otm.otmTextMetrics.tmAscent); 1.1936 + info->fDescent = SkToS16(-otm.otmTextMetrics.tmDescent); 1.1937 + // TODO(ctguil): Use alternate cap height calculation. 1.1938 + // MSDN says otmsCapEmHeight is not support but it is returning a value on 1.1939 + // my Win7 box. 1.1940 + info->fCapHeight = otm.otmsCapEmHeight; 1.1941 + info->fBBox = 1.1942 + SkIRect::MakeLTRB(otm.otmrcFontBox.left, otm.otmrcFontBox.top, 1.1943 + otm.otmrcFontBox.right, otm.otmrcFontBox.bottom); 1.1944 + 1.1945 + // Figure out a good guess for StemV - Min width of i, I, !, 1. 1.1946 + // This probably isn't very good with an italic font. 1.1947 + min_width = SHRT_MAX; 1.1948 + info->fStemV = 0; 1.1949 + for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) { 1.1950 + ABC abcWidths; 1.1951 + if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) { 1.1952 + int16_t width = abcWidths.abcB; 1.1953 + if (width > 0 && width < min_width) { 1.1954 + min_width = width; 1.1955 + info->fStemV = min_width; 1.1956 + } 1.1957 + } 1.1958 + } 1.1959 + 1.1960 + // If bit 1 is set, the font may not be embedded in a document. 1.1961 + // If bit 1 is clear, the font can be embedded. 1.1962 + // If bit 2 is set, the embedding is read-only. 1.1963 + if (otm.otmfsType & 0x1) { 1.1964 + info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font; 1.1965 + } else if (perGlyphInfo & 1.1966 + SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) { 1.1967 + if (info->fStyle & SkAdvancedTypefaceMetrics::kFixedPitch_Style) { 1.1968 + appendRange(&info->fGlyphWidths, 0); 1.1969 + info->fGlyphWidths->fAdvance.append(1, &min_width); 1.1970 + finishRange(info->fGlyphWidths.get(), 0, 1.1971 + SkAdvancedTypefaceMetrics::WidthRange::kDefault); 1.1972 + } else { 1.1973 + info->fGlyphWidths.reset( 1.1974 + getAdvanceData(hdc, 1.1975 + glyphCount, 1.1976 + glyphIDs, 1.1977 + glyphIDsCount, 1.1978 + &getWidthAdvance)); 1.1979 + } 1.1980 + } 1.1981 + 1.1982 +Error: 1.1983 +ReturnInfo: 1.1984 + SelectObject(hdc, savefont); 1.1985 + DeleteObject(designFont); 1.1986 + DeleteObject(font); 1.1987 + DeleteDC(hdc); 1.1988 + 1.1989 + return info; 1.1990 +} 1.1991 + 1.1992 +//Dummy representation of a Base64 encoded GUID from create_unique_font_name. 1.1993 +#define BASE64_GUID_ID "XXXXXXXXXXXXXXXXXXXXXXXX" 1.1994 +//Length of GUID representation from create_id, including NULL terminator. 1.1995 +#define BASE64_GUID_ID_LEN SK_ARRAY_COUNT(BASE64_GUID_ID) 1.1996 + 1.1997 +SK_COMPILE_ASSERT(BASE64_GUID_ID_LEN < LF_FACESIZE, GUID_longer_than_facesize); 1.1998 + 1.1999 +/** 1.2000 + NameID 6 Postscript names cannot have the character '/'. 1.2001 + It would be easier to hex encode the GUID, but that is 32 bytes, 1.2002 + and many systems have issues with names longer than 28 bytes. 1.2003 + The following need not be any standard base64 encoding. 1.2004 + The encoded value is never decoded. 1.2005 +*/ 1.2006 +static const char postscript_safe_base64_encode[] = 1.2007 + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 1.2008 + "abcdefghijklmnopqrstuvwxyz" 1.2009 + "0123456789-_="; 1.2010 + 1.2011 +/** 1.2012 + Formats a GUID into Base64 and places it into buffer. 1.2013 + buffer should have space for at least BASE64_GUID_ID_LEN characters. 1.2014 + The string will always be null terminated. 1.2015 + XXXXXXXXXXXXXXXXXXXXXXXX0 1.2016 + */ 1.2017 +static void format_guid_b64(const GUID& guid, char* buffer, size_t bufferSize) { 1.2018 + SkASSERT(bufferSize >= BASE64_GUID_ID_LEN); 1.2019 + size_t written = SkBase64::Encode(&guid, sizeof(guid), buffer, postscript_safe_base64_encode); 1.2020 + SkASSERT(written < LF_FACESIZE); 1.2021 + buffer[written] = '\0'; 1.2022 +} 1.2023 + 1.2024 +/** 1.2025 + Creates a Base64 encoded GUID and places it into buffer. 1.2026 + buffer should have space for at least BASE64_GUID_ID_LEN characters. 1.2027 + The string will always be null terminated. 1.2028 + XXXXXXXXXXXXXXXXXXXXXXXX0 1.2029 + */ 1.2030 +static HRESULT create_unique_font_name(char* buffer, size_t bufferSize) { 1.2031 + GUID guid = {}; 1.2032 + if (FAILED(CoCreateGuid(&guid))) { 1.2033 + return E_UNEXPECTED; 1.2034 + } 1.2035 + format_guid_b64(guid, buffer, bufferSize); 1.2036 + 1.2037 + return S_OK; 1.2038 +} 1.2039 + 1.2040 +/** 1.2041 + Introduces a font to GDI. On failure will return NULL. The returned handle 1.2042 + should eventually be passed to RemoveFontMemResourceEx. 1.2043 +*/ 1.2044 +static HANDLE activate_font(SkData* fontData) { 1.2045 + DWORD numFonts = 0; 1.2046 + //AddFontMemResourceEx just copies the data, but does not specify const. 1.2047 + HANDLE fontHandle = AddFontMemResourceEx(const_cast<void*>(fontData->data()), 1.2048 + static_cast<DWORD>(fontData->size()), 1.2049 + 0, 1.2050 + &numFonts); 1.2051 + 1.2052 + if (fontHandle != NULL && numFonts < 1) { 1.2053 + RemoveFontMemResourceEx(fontHandle); 1.2054 + return NULL; 1.2055 + } 1.2056 + 1.2057 + return fontHandle; 1.2058 +} 1.2059 + 1.2060 +static SkTypeface* create_from_stream(SkStream* stream) { 1.2061 + // Create a unique and unpredictable font name. 1.2062 + // Avoids collisions and access from CSS. 1.2063 + char familyName[BASE64_GUID_ID_LEN]; 1.2064 + const int familyNameSize = SK_ARRAY_COUNT(familyName); 1.2065 + if (FAILED(create_unique_font_name(familyName, familyNameSize))) { 1.2066 + return NULL; 1.2067 + } 1.2068 + 1.2069 + // Change the name of the font. 1.2070 + SkAutoTUnref<SkData> rewrittenFontData(SkOTUtils::RenameFont(stream, familyName, familyNameSize-1)); 1.2071 + if (NULL == rewrittenFontData.get()) { 1.2072 + return NULL; 1.2073 + } 1.2074 + 1.2075 + // Register the font with GDI. 1.2076 + HANDLE fontReference = activate_font(rewrittenFontData.get()); 1.2077 + if (NULL == fontReference) { 1.2078 + return NULL; 1.2079 + } 1.2080 + 1.2081 + // Create the typeface. 1.2082 + LOGFONT lf; 1.2083 + logfont_for_name(familyName, &lf); 1.2084 + 1.2085 + return SkCreateFontMemResourceTypefaceFromLOGFONT(lf, fontReference); 1.2086 +} 1.2087 + 1.2088 +SkStream* LogFontTypeface::onOpenStream(int* ttcIndex) const { 1.2089 + *ttcIndex = 0; 1.2090 + 1.2091 + const DWORD kTTCTag = 1.2092 + SkEndian_SwapBE32(SkSetFourByteTag('t', 't', 'c', 'f')); 1.2093 + LOGFONT lf = fLogFont; 1.2094 + 1.2095 + HDC hdc = ::CreateCompatibleDC(NULL); 1.2096 + HFONT font = CreateFontIndirect(&lf); 1.2097 + HFONT savefont = (HFONT)SelectObject(hdc, font); 1.2098 + 1.2099 + SkMemoryStream* stream = NULL; 1.2100 + DWORD tables[2] = {kTTCTag, 0}; 1.2101 + for (int i = 0; i < SK_ARRAY_COUNT(tables); i++) { 1.2102 + DWORD bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0); 1.2103 + if (bufferSize == GDI_ERROR) { 1.2104 + call_ensure_accessible(lf); 1.2105 + bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0); 1.2106 + } 1.2107 + if (bufferSize != GDI_ERROR) { 1.2108 + stream = new SkMemoryStream(bufferSize); 1.2109 + if (GetFontData(hdc, tables[i], 0, (void*)stream->getMemoryBase(), bufferSize)) { 1.2110 + break; 1.2111 + } else { 1.2112 + delete stream; 1.2113 + stream = NULL; 1.2114 + } 1.2115 + } 1.2116 + } 1.2117 + 1.2118 + SelectObject(hdc, savefont); 1.2119 + DeleteObject(font); 1.2120 + DeleteDC(hdc); 1.2121 + 1.2122 + return stream; 1.2123 +} 1.2124 + 1.2125 +static void bmpCharsToGlyphs(HDC hdc, const WCHAR* bmpChars, int count, uint16_t* glyphs, 1.2126 + bool Ox1FHack) 1.2127 +{ 1.2128 + DWORD result = GetGlyphIndicesW(hdc, bmpChars, count, glyphs, GGI_MARK_NONEXISTING_GLYPHS); 1.2129 + if (GDI_ERROR == result) { 1.2130 + for (int i = 0; i < count; ++i) { 1.2131 + glyphs[i] = 0; 1.2132 + } 1.2133 + return; 1.2134 + } 1.2135 + 1.2136 + if (Ox1FHack) { 1.2137 + for (int i = 0; i < count; ++i) { 1.2138 + if (0xFFFF == glyphs[i] || 0x1F == glyphs[i]) { 1.2139 + glyphs[i] = 0; 1.2140 + } 1.2141 + } 1.2142 + } else { 1.2143 + for (int i = 0; i < count; ++i) { 1.2144 + if (0xFFFF == glyphs[i]){ 1.2145 + glyphs[i] = 0; 1.2146 + } 1.2147 + } 1.2148 + } 1.2149 +} 1.2150 + 1.2151 +static uint16_t nonBmpCharToGlyph(HDC hdc, SCRIPT_CACHE* scriptCache, const WCHAR utf16[2]) { 1.2152 + uint16_t index = 0; 1.2153 + // Use uniscribe to detemine glyph index for non-BMP characters. 1.2154 + static const int numWCHAR = 2; 1.2155 + static const int maxItems = 2; 1.2156 + // MSDN states that this can be NULL, but some things don't work then. 1.2157 + SCRIPT_CONTROL scriptControl = { 0 }; 1.2158 + // Add extra item to SCRIPT_ITEM to work around a bug (now documented). 1.2159 + // https://bugzilla.mozilla.org/show_bug.cgi?id=366643 1.2160 + SCRIPT_ITEM si[maxItems + 1]; 1.2161 + int numItems; 1.2162 + HRZM(ScriptItemize(utf16, numWCHAR, maxItems, &scriptControl, NULL, si, &numItems), 1.2163 + "Could not itemize character."); 1.2164 + 1.2165 + // Sometimes ScriptShape cannot find a glyph for a non-BMP and returns 2 space glyphs. 1.2166 + static const int maxGlyphs = 2; 1.2167 + SCRIPT_VISATTR vsa[maxGlyphs]; 1.2168 + WORD outGlyphs[maxGlyphs]; 1.2169 + WORD logClust[numWCHAR]; 1.2170 + int numGlyphs; 1.2171 + HRZM(ScriptShape(hdc, scriptCache, utf16, numWCHAR, maxGlyphs, &si[0].a, 1.2172 + outGlyphs, logClust, vsa, &numGlyphs), 1.2173 + "Could not shape character."); 1.2174 + if (1 == numGlyphs) { 1.2175 + index = outGlyphs[0]; 1.2176 + } 1.2177 + return index; 1.2178 +} 1.2179 + 1.2180 +class SkAutoHDC { 1.2181 +public: 1.2182 + SkAutoHDC(const LOGFONT& lf) 1.2183 + : fHdc(::CreateCompatibleDC(NULL)) 1.2184 + , fFont(::CreateFontIndirect(&lf)) 1.2185 + , fSavefont((HFONT)SelectObject(fHdc, fFont)) 1.2186 + { } 1.2187 + ~SkAutoHDC() { 1.2188 + SelectObject(fHdc, fSavefont); 1.2189 + DeleteObject(fFont); 1.2190 + DeleteDC(fHdc); 1.2191 + } 1.2192 + operator HDC() { return fHdc; } 1.2193 +private: 1.2194 + HDC fHdc; 1.2195 + HFONT fFont; 1.2196 + HFONT fSavefont; 1.2197 +}; 1.2198 +#define SkAutoHDC(...) SK_REQUIRE_LOCAL_VAR(SkAutoHDC) 1.2199 + 1.2200 +int LogFontTypeface::onCharsToGlyphs(const void* chars, Encoding encoding, 1.2201 + uint16_t userGlyphs[], int glyphCount) const 1.2202 +{ 1.2203 + SkAutoHDC hdc(fLogFont); 1.2204 + 1.2205 + TEXTMETRIC tm; 1.2206 + if (0 == GetTextMetrics(hdc, &tm)) { 1.2207 + call_ensure_accessible(fLogFont); 1.2208 + if (0 == GetTextMetrics(hdc, &tm)) { 1.2209 + tm.tmPitchAndFamily = TMPF_TRUETYPE; 1.2210 + } 1.2211 + } 1.2212 + bool Ox1FHack = !(tm.tmPitchAndFamily & TMPF_VECTOR) /*&& winVer < Vista */; 1.2213 + 1.2214 + SkAutoSTMalloc<256, uint16_t> scratchGlyphs; 1.2215 + uint16_t* glyphs; 1.2216 + if (userGlyphs != NULL) { 1.2217 + glyphs = userGlyphs; 1.2218 + } else { 1.2219 + glyphs = scratchGlyphs.reset(glyphCount); 1.2220 + } 1.2221 + 1.2222 + SCRIPT_CACHE sc = 0; 1.2223 + switch (encoding) { 1.2224 + case SkTypeface::kUTF8_Encoding: { 1.2225 + static const int scratchCount = 256; 1.2226 + WCHAR scratch[scratchCount]; 1.2227 + int glyphIndex = 0; 1.2228 + const char* currentUtf8 = reinterpret_cast<const char*>(chars); 1.2229 + SkUnichar currentChar; 1.2230 + if (glyphCount) { 1.2231 + currentChar = SkUTF8_NextUnichar(¤tUtf8); 1.2232 + } 1.2233 + while (glyphIndex < glyphCount) { 1.2234 + // Try a run of bmp. 1.2235 + int glyphsLeft = SkTMin(glyphCount - glyphIndex, scratchCount); 1.2236 + int runLength = 0; 1.2237 + while (runLength < glyphsLeft && currentChar <= 0xFFFF) { 1.2238 + scratch[runLength] = static_cast<WCHAR>(currentChar); 1.2239 + ++runLength; 1.2240 + if (runLength < glyphsLeft) { 1.2241 + currentChar = SkUTF8_NextUnichar(¤tUtf8); 1.2242 + } 1.2243 + } 1.2244 + if (runLength) { 1.2245 + bmpCharsToGlyphs(hdc, scratch, runLength, &glyphs[glyphIndex], Ox1FHack); 1.2246 + glyphIndex += runLength; 1.2247 + } 1.2248 + 1.2249 + // Try a run of non-bmp. 1.2250 + while (glyphIndex < glyphCount && currentChar > 0xFFFF) { 1.2251 + SkUTF16_FromUnichar(currentChar, reinterpret_cast<uint16_t*>(scratch)); 1.2252 + glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, scratch); 1.2253 + ++glyphIndex; 1.2254 + if (glyphIndex < glyphCount) { 1.2255 + currentChar = SkUTF8_NextUnichar(¤tUtf8); 1.2256 + } 1.2257 + } 1.2258 + } 1.2259 + break; 1.2260 + } 1.2261 + case SkTypeface::kUTF16_Encoding: { 1.2262 + int glyphIndex = 0; 1.2263 + const WCHAR* currentUtf16 = reinterpret_cast<const WCHAR*>(chars); 1.2264 + while (glyphIndex < glyphCount) { 1.2265 + // Try a run of bmp. 1.2266 + int glyphsLeft = glyphCount - glyphIndex; 1.2267 + int runLength = 0; 1.2268 + while (runLength < glyphsLeft && !SkUTF16_IsHighSurrogate(currentUtf16[runLength])) { 1.2269 + ++runLength; 1.2270 + } 1.2271 + if (runLength) { 1.2272 + bmpCharsToGlyphs(hdc, currentUtf16, runLength, &glyphs[glyphIndex], Ox1FHack); 1.2273 + glyphIndex += runLength; 1.2274 + currentUtf16 += runLength; 1.2275 + } 1.2276 + 1.2277 + // Try a run of non-bmp. 1.2278 + while (glyphIndex < glyphCount && SkUTF16_IsHighSurrogate(*currentUtf16)) { 1.2279 + glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, currentUtf16); 1.2280 + ++glyphIndex; 1.2281 + currentUtf16 += 2; 1.2282 + } 1.2283 + } 1.2284 + break; 1.2285 + } 1.2286 + case SkTypeface::kUTF32_Encoding: { 1.2287 + static const int scratchCount = 256; 1.2288 + WCHAR scratch[scratchCount]; 1.2289 + int glyphIndex = 0; 1.2290 + const uint32_t* utf32 = reinterpret_cast<const uint32_t*>(chars); 1.2291 + while (glyphIndex < glyphCount) { 1.2292 + // Try a run of bmp. 1.2293 + int glyphsLeft = SkTMin(glyphCount - glyphIndex, scratchCount); 1.2294 + int runLength = 0; 1.2295 + while (runLength < glyphsLeft && utf32[glyphIndex + runLength] <= 0xFFFF) { 1.2296 + scratch[runLength] = static_cast<WCHAR>(utf32[glyphIndex + runLength]); 1.2297 + ++runLength; 1.2298 + } 1.2299 + if (runLength) { 1.2300 + bmpCharsToGlyphs(hdc, scratch, runLength, &glyphs[glyphIndex], Ox1FHack); 1.2301 + glyphIndex += runLength; 1.2302 + } 1.2303 + 1.2304 + // Try a run of non-bmp. 1.2305 + while (glyphIndex < glyphCount && utf32[glyphIndex] > 0xFFFF) { 1.2306 + SkUTF16_FromUnichar(utf32[glyphIndex], reinterpret_cast<uint16_t*>(scratch)); 1.2307 + glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, scratch); 1.2308 + ++glyphIndex; 1.2309 + } 1.2310 + } 1.2311 + break; 1.2312 + } 1.2313 + default: 1.2314 + SK_CRASH(); 1.2315 + } 1.2316 + 1.2317 + if (sc) { 1.2318 + ::ScriptFreeCache(&sc); 1.2319 + } 1.2320 + 1.2321 + for (int i = 0; i < glyphCount; ++i) { 1.2322 + if (0 == glyphs[i]) { 1.2323 + return i; 1.2324 + } 1.2325 + } 1.2326 + return glyphCount; 1.2327 +} 1.2328 + 1.2329 +int LogFontTypeface::onCountGlyphs() const { 1.2330 + HDC hdc = ::CreateCompatibleDC(NULL); 1.2331 + HFONT font = CreateFontIndirect(&fLogFont); 1.2332 + HFONT savefont = (HFONT)SelectObject(hdc, font); 1.2333 + 1.2334 + unsigned int glyphCount = calculateGlyphCount(hdc, fLogFont); 1.2335 + 1.2336 + SelectObject(hdc, savefont); 1.2337 + DeleteObject(font); 1.2338 + DeleteDC(hdc); 1.2339 + 1.2340 + return glyphCount; 1.2341 +} 1.2342 + 1.2343 +int LogFontTypeface::onGetUPEM() const { 1.2344 + HDC hdc = ::CreateCompatibleDC(NULL); 1.2345 + HFONT font = CreateFontIndirect(&fLogFont); 1.2346 + HFONT savefont = (HFONT)SelectObject(hdc, font); 1.2347 + 1.2348 + unsigned int upem = calculateUPEM(hdc, fLogFont); 1.2349 + 1.2350 + SelectObject(hdc, savefont); 1.2351 + DeleteObject(font); 1.2352 + DeleteDC(hdc); 1.2353 + 1.2354 + return upem; 1.2355 +} 1.2356 + 1.2357 +SkTypeface::LocalizedStrings* LogFontTypeface::onCreateFamilyNameIterator() const { 1.2358 + SkTypeface::LocalizedStrings* nameIter = 1.2359 + SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(*this); 1.2360 + if (NULL == nameIter) { 1.2361 + SkString familyName; 1.2362 + this->getFamilyName(&familyName); 1.2363 + SkString language("und"); //undetermined 1.2364 + nameIter = new SkOTUtils::LocalizedStrings_SingleName(familyName, language); 1.2365 + } 1.2366 + return nameIter; 1.2367 +} 1.2368 + 1.2369 +int LogFontTypeface::onGetTableTags(SkFontTableTag tags[]) const { 1.2370 + SkSFNTHeader header; 1.2371 + if (sizeof(header) != this->onGetTableData(0, 0, sizeof(header), &header)) { 1.2372 + return 0; 1.2373 + } 1.2374 + 1.2375 + int numTables = SkEndian_SwapBE16(header.numTables); 1.2376 + 1.2377 + if (tags) { 1.2378 + size_t size = numTables * sizeof(SkSFNTHeader::TableDirectoryEntry); 1.2379 + SkAutoSTMalloc<0x20, SkSFNTHeader::TableDirectoryEntry> dir(numTables); 1.2380 + if (size != this->onGetTableData(0, sizeof(header), size, dir.get())) { 1.2381 + return 0; 1.2382 + } 1.2383 + 1.2384 + for (int i = 0; i < numTables; ++i) { 1.2385 + tags[i] = SkEndian_SwapBE32(dir[i].tag); 1.2386 + } 1.2387 + } 1.2388 + return numTables; 1.2389 +} 1.2390 + 1.2391 +size_t LogFontTypeface::onGetTableData(SkFontTableTag tag, size_t offset, 1.2392 + size_t length, void* data) const 1.2393 +{ 1.2394 + LOGFONT lf = fLogFont; 1.2395 + 1.2396 + HDC hdc = ::CreateCompatibleDC(NULL); 1.2397 + HFONT font = CreateFontIndirect(&lf); 1.2398 + HFONT savefont = (HFONT)SelectObject(hdc, font); 1.2399 + 1.2400 + tag = SkEndian_SwapBE32(tag); 1.2401 + if (NULL == data) { 1.2402 + length = 0; 1.2403 + } 1.2404 + DWORD bufferSize = GetFontData(hdc, tag, (DWORD) offset, data, (DWORD) length); 1.2405 + if (bufferSize == GDI_ERROR) { 1.2406 + call_ensure_accessible(lf); 1.2407 + bufferSize = GetFontData(hdc, tag, (DWORD) offset, data, (DWORD) length); 1.2408 + } 1.2409 + 1.2410 + SelectObject(hdc, savefont); 1.2411 + DeleteObject(font); 1.2412 + DeleteDC(hdc); 1.2413 + 1.2414 + return bufferSize == GDI_ERROR ? 0 : bufferSize; 1.2415 +} 1.2416 + 1.2417 +SkScalerContext* LogFontTypeface::onCreateScalerContext(const SkDescriptor* desc) const { 1.2418 + SkScalerContext_GDI* ctx = SkNEW_ARGS(SkScalerContext_GDI, 1.2419 + (const_cast<LogFontTypeface*>(this), desc)); 1.2420 + if (!ctx->isValid()) { 1.2421 + SkDELETE(ctx); 1.2422 + ctx = NULL; 1.2423 + } 1.2424 + return ctx; 1.2425 +} 1.2426 + 1.2427 +void LogFontTypeface::onFilterRec(SkScalerContextRec* rec) const { 1.2428 + if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag || 1.2429 + rec->fFlags & SkScalerContext::kLCD_Vertical_Flag) 1.2430 + { 1.2431 + rec->fMaskFormat = SkMask::kA8_Format; 1.2432 + rec->fFlags |= SkScalerContext::kGenA8FromLCD_Flag; 1.2433 + } 1.2434 + 1.2435 + unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag | 1.2436 + SkScalerContext::kForceAutohinting_Flag | 1.2437 + SkScalerContext::kEmbeddedBitmapText_Flag | 1.2438 + SkScalerContext::kEmbolden_Flag | 1.2439 + SkScalerContext::kLCD_BGROrder_Flag | 1.2440 + SkScalerContext::kLCD_Vertical_Flag; 1.2441 + rec->fFlags &= ~flagsWeDontSupport; 1.2442 + 1.2443 + SkPaint::Hinting h = rec->getHinting(); 1.2444 + switch (h) { 1.2445 + case SkPaint::kNo_Hinting: 1.2446 + break; 1.2447 + case SkPaint::kSlight_Hinting: 1.2448 + // Only do slight hinting when axis aligned. 1.2449 + // TODO: re-enable slight hinting when FontHostTest can pass. 1.2450 + //if (!isAxisAligned(*rec)) { 1.2451 + h = SkPaint::kNo_Hinting; 1.2452 + //} 1.2453 + break; 1.2454 + case SkPaint::kNormal_Hinting: 1.2455 + case SkPaint::kFull_Hinting: 1.2456 + // TODO: need to be able to distinguish subpixel positioned glyphs 1.2457 + // and linear metrics. 1.2458 + //rec->fFlags &= ~SkScalerContext::kSubpixelPositioning_Flag; 1.2459 + h = SkPaint::kNormal_Hinting; 1.2460 + break; 1.2461 + default: 1.2462 + SkDEBUGFAIL("unknown hinting"); 1.2463 + } 1.2464 + //TODO: if this is a bitmap font, squash hinting and subpixel. 1.2465 + rec->setHinting(h); 1.2466 + 1.2467 +// turn this off since GDI might turn A8 into BW! Need a bigger fix. 1.2468 +#if 0 1.2469 + // Disable LCD when rotated, since GDI's output is ugly 1.2470 + if (isLCD(*rec) && !isAxisAligned(*rec)) { 1.2471 + rec->fMaskFormat = SkMask::kA8_Format; 1.2472 + } 1.2473 +#endif 1.2474 + 1.2475 + if (!fCanBeLCD && isLCD(*rec)) { 1.2476 + rec->fMaskFormat = SkMask::kA8_Format; 1.2477 + rec->fFlags &= ~SkScalerContext::kGenA8FromLCD_Flag; 1.2478 + } 1.2479 +} 1.2480 + 1.2481 +/////////////////////////////////////////////////////////////////////////////// 1.2482 + 1.2483 +#include "SkFontMgr.h" 1.2484 +#include "SkDataTable.h" 1.2485 + 1.2486 +static bool valid_logfont_for_enum(const LOGFONT& lf) { 1.2487 + // TODO: Vector FON is unsupported and should not be listed. 1.2488 + return 1.2489 + // Ignore implicit vertical variants. 1.2490 + lf.lfFaceName[0] && lf.lfFaceName[0] != '@' 1.2491 + 1.2492 + // DEFAULT_CHARSET is used to get all fonts, but also implies all 1.2493 + // character sets. Filter assuming all fonts support ANSI_CHARSET. 1.2494 + && ANSI_CHARSET == lf.lfCharSet 1.2495 + ; 1.2496 +} 1.2497 + 1.2498 +/** An EnumFontFamExProc implementation which interprets builderParam as 1.2499 + * an SkTDArray<ENUMLOGFONTEX>* and appends logfonts which 1.2500 + * pass the valid_logfont_for_enum predicate. 1.2501 + */ 1.2502 +static int CALLBACK enum_family_proc(const LOGFONT* lf, const TEXTMETRIC*, 1.2503 + DWORD fontType, LPARAM builderParam) { 1.2504 + if (valid_logfont_for_enum(*lf)) { 1.2505 + SkTDArray<ENUMLOGFONTEX>* array = (SkTDArray<ENUMLOGFONTEX>*)builderParam; 1.2506 + *array->append() = *(ENUMLOGFONTEX*)lf; 1.2507 + } 1.2508 + return 1; // non-zero means continue 1.2509 +} 1.2510 + 1.2511 +static SkFontStyle compute_fontstyle(const LOGFONT& lf) { 1.2512 + return SkFontStyle(lf.lfWeight, SkFontStyle::kNormal_Width, 1.2513 + lf.lfItalic ? SkFontStyle::kItalic_Slant 1.2514 + : SkFontStyle::kUpright_Slant); 1.2515 +} 1.2516 + 1.2517 +class SkFontStyleSetGDI : public SkFontStyleSet { 1.2518 +public: 1.2519 + SkFontStyleSetGDI(const TCHAR familyName[]) { 1.2520 + LOGFONT lf; 1.2521 + sk_bzero(&lf, sizeof(lf)); 1.2522 + lf.lfCharSet = DEFAULT_CHARSET; 1.2523 + _tcscpy_s(lf.lfFaceName, familyName); 1.2524 + 1.2525 + HDC hdc = ::CreateCompatibleDC(NULL); 1.2526 + ::EnumFontFamiliesEx(hdc, &lf, enum_family_proc, (LPARAM)&fArray, 0); 1.2527 + ::DeleteDC(hdc); 1.2528 + } 1.2529 + 1.2530 + virtual int count() SK_OVERRIDE { 1.2531 + return fArray.count(); 1.2532 + } 1.2533 + 1.2534 + virtual void getStyle(int index, SkFontStyle* fs, SkString* styleName) SK_OVERRIDE { 1.2535 + if (fs) { 1.2536 + *fs = compute_fontstyle(fArray[index].elfLogFont); 1.2537 + } 1.2538 + if (styleName) { 1.2539 + const ENUMLOGFONTEX& ref = fArray[index]; 1.2540 + // For some reason, ENUMLOGFONTEX and LOGFONT disagree on their type in the 1.2541 + // non-unicode version. 1.2542 + // ENUMLOGFONTEX uses BYTE 1.2543 + // LOGFONT uses CHAR 1.2544 + // Here we assert they that the style name is logically the same (size) as 1.2545 + // a TCHAR, so we can use the same converter function. 1.2546 + SkASSERT(sizeof(TCHAR) == sizeof(ref.elfStyle[0])); 1.2547 + tchar_to_skstring((const TCHAR*)ref.elfStyle, styleName); 1.2548 + } 1.2549 + } 1.2550 + 1.2551 + virtual SkTypeface* createTypeface(int index) SK_OVERRIDE { 1.2552 + return SkCreateTypefaceFromLOGFONT(fArray[index].elfLogFont); 1.2553 + } 1.2554 + 1.2555 + virtual SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE { 1.2556 + // todo: 1.2557 + return SkCreateTypefaceFromLOGFONT(fArray[0].elfLogFont); 1.2558 + } 1.2559 + 1.2560 +private: 1.2561 + SkTDArray<ENUMLOGFONTEX> fArray; 1.2562 +}; 1.2563 + 1.2564 +class SkFontMgrGDI : public SkFontMgr { 1.2565 +public: 1.2566 + SkFontMgrGDI() { 1.2567 + LOGFONT lf; 1.2568 + sk_bzero(&lf, sizeof(lf)); 1.2569 + lf.lfCharSet = DEFAULT_CHARSET; 1.2570 + 1.2571 + HDC hdc = ::CreateCompatibleDC(NULL); 1.2572 + ::EnumFontFamiliesEx(hdc, &lf, enum_family_proc, (LPARAM)&fLogFontArray, 0); 1.2573 + ::DeleteDC(hdc); 1.2574 + } 1.2575 + 1.2576 +protected: 1.2577 + virtual int onCountFamilies() const SK_OVERRIDE { 1.2578 + return fLogFontArray.count(); 1.2579 + } 1.2580 + 1.2581 + virtual void onGetFamilyName(int index, SkString* familyName) const SK_OVERRIDE { 1.2582 + SkASSERT((unsigned)index < (unsigned)fLogFontArray.count()); 1.2583 + tchar_to_skstring(fLogFontArray[index].elfLogFont.lfFaceName, familyName); 1.2584 + } 1.2585 + 1.2586 + virtual SkFontStyleSet* onCreateStyleSet(int index) const SK_OVERRIDE { 1.2587 + SkASSERT((unsigned)index < (unsigned)fLogFontArray.count()); 1.2588 + return SkNEW_ARGS(SkFontStyleSetGDI, (fLogFontArray[index].elfLogFont.lfFaceName)); 1.2589 + } 1.2590 + 1.2591 + virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const SK_OVERRIDE { 1.2592 + if (NULL == familyName) { 1.2593 + familyName = ""; // do we need this check??? 1.2594 + } 1.2595 + LOGFONT lf; 1.2596 + logfont_for_name(familyName, &lf); 1.2597 + return SkNEW_ARGS(SkFontStyleSetGDI, (lf.lfFaceName)); 1.2598 + } 1.2599 + 1.2600 + virtual SkTypeface* onMatchFamilyStyle(const char familyName[], 1.2601 + const SkFontStyle& fontstyle) const SK_OVERRIDE { 1.2602 + // could be in base impl 1.2603 + SkAutoTUnref<SkFontStyleSet> sset(this->matchFamily(familyName)); 1.2604 + return sset->matchStyle(fontstyle); 1.2605 + } 1.2606 + 1.2607 + virtual SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember, 1.2608 + const SkFontStyle& fontstyle) const SK_OVERRIDE { 1.2609 + // could be in base impl 1.2610 + SkString familyName; 1.2611 + ((LogFontTypeface*)familyMember)->getFamilyName(&familyName); 1.2612 + return this->matchFamilyStyle(familyName.c_str(), fontstyle); 1.2613 + } 1.2614 + 1.2615 + virtual SkTypeface* onCreateFromStream(SkStream* stream, int ttcIndex) const SK_OVERRIDE { 1.2616 + return create_from_stream(stream); 1.2617 + } 1.2618 + 1.2619 + virtual SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const SK_OVERRIDE { 1.2620 + // could be in base impl 1.2621 + SkAutoTUnref<SkStream> stream(SkNEW_ARGS(SkMemoryStream, (data))); 1.2622 + return this->createFromStream(stream); 1.2623 + } 1.2624 + 1.2625 + virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const SK_OVERRIDE { 1.2626 + // could be in base impl 1.2627 + SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path)); 1.2628 + return this->createFromStream(stream); 1.2629 + } 1.2630 + 1.2631 + virtual SkTypeface* onLegacyCreateTypeface(const char familyName[], 1.2632 + unsigned styleBits) const SK_OVERRIDE { 1.2633 + LOGFONT lf; 1.2634 + if (NULL == familyName) { 1.2635 + lf = get_default_font(); 1.2636 + } else { 1.2637 + logfont_for_name(familyName, &lf); 1.2638 + } 1.2639 + setStyle(&lf, (SkTypeface::Style)styleBits); 1.2640 + return SkCreateTypefaceFromLOGFONT(lf); 1.2641 + } 1.2642 + 1.2643 +private: 1.2644 + SkTDArray<ENUMLOGFONTEX> fLogFontArray; 1.2645 +}; 1.2646 + 1.2647 +/////////////////////////////////////////////////////////////////////////////// 1.2648 + 1.2649 +SkFontMgr* SkFontMgr_New_GDI() { 1.2650 + return SkNEW(SkFontMgrGDI); 1.2651 +}