blob: 25c608878d28cffd7eabf1c02e3d6c384980b544 [file] [log] [blame]
reed@google.comac6b9792011-03-11 15:42:51 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@google.comac6b9792011-03-11 15:42:51 +00006 */
7
mtklein1ee76512015-11-02 10:20:27 -08008#include "SkTypes.h"
9#if defined(SK_BUILD_FOR_WIN32)
10
reed@google.comac6b9792011-03-11 15:42:51 +000011#include "SkAdvancedTypefaceMetrics.h"
bungeman@google.coma5501992012-05-18 19:06:41 +000012#include "SkBase64.h"
bungeman@google.com1bfe01d2012-08-28 16:02:42 +000013#include "SkColorPriv.h"
bungeman@google.coma5501992012-05-18 19:06:41 +000014#include "SkData.h"
15#include "SkDescriptor.h"
bungeman@google.come70f7982012-06-01 19:38:19 +000016#include "SkFontDescriptor.h"
bungeman@google.combbe50132012-07-24 20:33:21 +000017#include "SkGlyph.h"
bungeman@google.com27f74aa2013-10-08 21:32:15 +000018#include "SkHRESULT.h"
bungeman7cfd46a2016-10-20 16:06:52 -040019#include "SkMakeUnique.h"
bungeman@google.com97efada2012-07-30 20:40:50 +000020#include "SkMaskGamma.h"
bungeman@google.comd3fbd342014-04-15 15:52:07 +000021#include "SkMatrix22.h"
bungeman@google.com7bdd6142013-07-15 19:42:57 +000022#include "SkOTTable_maxp.h"
bungeman@google.coma9802692013-08-07 02:45:25 +000023#include "SkOTTable_name.h"
bungeman@google.coma5501992012-05-18 19:06:41 +000024#include "SkOTUtils.h"
reed@google.com27889872012-08-07 16:15:13 +000025#include "SkPath.h"
bungeman@google.comb10b51f2013-08-01 20:18:41 +000026#include "SkSFNTHeader.h"
reed@google.comac6b9792011-03-11 15:42:51 +000027#include "SkStream.h"
bungeman@google.coma5501992012-05-18 19:06:41 +000028#include "SkString.h"
bungeman@google.com05a729f2013-06-20 15:29:16 +000029#include "SkTemplates.h"
reed@google.comac6b9792011-03-11 15:42:51 +000030#include "SkTypeface_win.h"
reed@google.com59d2f632011-05-02 19:36:59 +000031#include "SkTypefaceCache.h"
reed@google.comac6b9792011-03-11 15:42:51 +000032#include "SkUtils.h"
33
bungeman@google.coma5501992012-05-18 19:06:41 +000034#include "SkTypes.h"
35#include <tchar.h>
36#include <usp10.h>
37#include <objbase.h>
reed@google.comac6b9792011-03-11 15:42:51 +000038
reed@google.comf210f502013-03-20 14:15:52 +000039static void (*gEnsureLOGFONTAccessibleProc)(const LOGFONT&);
40
41void SkTypeface_SetEnsureLOGFONTAccessibleProc(void (*proc)(const LOGFONT&)) {
42 gEnsureLOGFONTAccessibleProc = proc;
43}
44
reed@google.com055180c2013-03-21 18:46:35 +000045static void call_ensure_accessible(const LOGFONT& lf) {
46 if (gEnsureLOGFONTAccessibleProc) {
47 gEnsureLOGFONTAccessibleProc(lf);
48 }
49}
50
51///////////////////////////////////////////////////////////////////////////////
52
reed@google.com6f5df482011-09-28 20:33:24 +000053// always packed xxRRGGBB
54typedef uint32_t SkGdiRGB;
55
reed@google.coma767fa02011-08-05 21:40:26 +000056// define this in your Makefile or .gyp to enforce AA requests
57// which GDI ignores at small sizes. This flag guarantees AA
58// for rotated text, regardless of GDI's notions.
59//#define SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
60
reed@google.com82a34d82011-07-26 19:33:08 +000061static bool isLCD(const SkScalerContext::Rec& rec) {
reedd54d3fc2014-11-13 14:39:58 -080062 return SkMask::kLCD16_Format == rec.fMaskFormat;
reed@google.com82a34d82011-07-26 19:33:08 +000063}
64
reed@google.coma767fa02011-08-05 21:40:26 +000065static bool bothZero(SkScalar a, SkScalar b) {
66 return 0 == a && 0 == b;
67}
68
69// returns false if there is any non-90-rotation or skew
70static bool isAxisAligned(const SkScalerContext::Rec& rec) {
71 return 0 == rec.fPreSkewX &&
72 (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
73 bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
74}
75
76static bool needToRenderWithSkia(const SkScalerContext::Rec& rec) {
77#ifdef SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
78 // What we really want to catch is when GDI will ignore the AA request and give
79 // us BW instead. Smallish rotated text is one heuristic, so this code is just
80 // an approximation. We shouldn't need to do this for larger sizes, but at those
81 // sizes, the quality difference gets less and less between our general
82 // scanconverter and GDI's.
83 if (SkMask::kA8_Format == rec.fMaskFormat && !isAxisAligned(rec)) {
84 return true;
85 }
86#endif
bungeman@google.com0abbff92013-07-27 20:37:56 +000087 return rec.getHinting() == SkPaint::kNo_Hinting || rec.getHinting() == SkPaint::kSlight_Hinting;
reed@google.coma767fa02011-08-05 21:40:26 +000088}
89
reed@google.coma65a6812013-05-02 19:47:24 +000090static void tchar_to_skstring(const TCHAR t[], SkString* s) {
reed@google.com484f5bc2013-04-24 19:14:56 +000091#ifdef UNICODE
halcanary96fcdcc2015-08-27 07:41:13 -070092 size_t sSize = WideCharToMultiByte(CP_UTF8, 0, t, -1, nullptr, 0, nullptr, nullptr);
reed@google.com484f5bc2013-04-24 19:14:56 +000093 s->resize(sSize);
halcanary96fcdcc2015-08-27 07:41:13 -070094 WideCharToMultiByte(CP_UTF8, 0, t, -1, s->writable_str(), sSize, nullptr, nullptr);
reed@google.com484f5bc2013-04-24 19:14:56 +000095#else
96 s->set(t);
97#endif
98}
99
bungeman@google.coma9802692013-08-07 02:45:25 +0000100static void dcfontname_to_skstring(HDC deviceContext, const LOGFONT& lf, SkString* familyName) {
101 int fontNameLen; //length of fontName in TCHARS.
halcanary96fcdcc2015-08-27 07:41:13 -0700102 if (0 == (fontNameLen = GetTextFace(deviceContext, 0, nullptr))) {
bungeman@google.coma9802692013-08-07 02:45:25 +0000103 call_ensure_accessible(lf);
halcanary96fcdcc2015-08-27 07:41:13 -0700104 if (0 == (fontNameLen = GetTextFace(deviceContext, 0, nullptr))) {
bungeman@google.coma9802692013-08-07 02:45:25 +0000105 fontNameLen = 0;
106 }
107 }
108
109 SkAutoSTArray<LF_FULLFACESIZE, TCHAR> fontName(fontNameLen+1);
110 if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) {
111 call_ensure_accessible(lf);
112 if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) {
113 fontName[0] = 0;
114 }
115 }
116
117 tchar_to_skstring(fontName.get(), familyName);
118}
119
reed@google.comac6b9792011-03-11 15:42:51 +0000120static void make_canonical(LOGFONT* lf) {
bungeman@google.com53cbb0b2013-09-08 19:36:58 +0000121 lf->lfHeight = -64;
bungeman59f093d2016-03-22 10:59:09 -0700122 lf->lfWidth = 0; // lfWidth is related to lfHeight, not to the OS/2::usWidthClass.
reed@google.com59d2f632011-05-02 19:36:59 +0000123 lf->lfQuality = CLEARTYPE_QUALITY;//PROOF_QUALITY;
124 lf->lfCharSet = DEFAULT_CHARSET;
reed@google.com82a34d82011-07-26 19:33:08 +0000125// lf->lfClipPrecision = 64;
reed@google.com59d2f632011-05-02 19:36:59 +0000126}
127
bungemana4c4a2d2014-10-20 13:33:19 -0700128static SkFontStyle get_style(const LOGFONT& lf) {
129 return SkFontStyle(lf.lfWeight,
bungeman59f093d2016-03-22 10:59:09 -0700130 SkFontStyle::kNormal_Width,
bungemana4c4a2d2014-10-20 13:33:19 -0700131 lf.lfItalic ? SkFontStyle::kItalic_Slant : SkFontStyle::kUpright_Slant);
reed@google.comac6b9792011-03-11 15:42:51 +0000132}
133
134static inline FIXED SkFixedToFIXED(SkFixed x) {
135 return *(FIXED*)(&x);
136}
bungeman@google.coma0319f62012-04-18 15:40:50 +0000137static inline SkFixed SkFIXEDToFixed(FIXED x) {
138 return *(SkFixed*)(&x);
139}
reed@google.comac6b9792011-03-11 15:42:51 +0000140
141static inline FIXED SkScalarToFIXED(SkScalar x) {
142 return SkFixedToFIXED(SkScalarToFixed(x));
143}
144
bungeman@google.com4732df62014-01-23 15:22:42 +0000145static inline SkScalar SkFIXEDToScalar(FIXED x) {
146 return SkFixedToScalar(SkFIXEDToFixed(x));
147}
148
bungeman@google.com7bdd6142013-07-15 19:42:57 +0000149static unsigned calculateGlyphCount(HDC hdc, const LOGFONT& lf) {
150 TEXTMETRIC textMetric;
151 if (0 == GetTextMetrics(hdc, &textMetric)) {
152 textMetric.tmPitchAndFamily = TMPF_VECTOR;
153 call_ensure_accessible(lf);
154 GetTextMetrics(hdc, &textMetric);
155 }
156
157 if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) {
158 return textMetric.tmLastChar;
159 }
160
reed@google.comac6b9792011-03-11 15:42:51 +0000161 // The 'maxp' table stores the number of glyphs at offset 4, in 2 bytes.
reed@google.comac6b9792011-03-11 15:42:51 +0000162 uint16_t glyphs;
bungeman@google.com7bdd6142013-07-15 19:42:57 +0000163 if (GDI_ERROR != GetFontData(hdc, SkOTTableMaximumProfile::TAG, 4, &glyphs, sizeof(glyphs))) {
reed@google.comac6b9792011-03-11 15:42:51 +0000164 return SkEndian_SwapBE16(glyphs);
165 }
ctguil@chromium.org5aa937b2011-08-04 01:01:24 +0000166
reed@google.comac6b9792011-03-11 15:42:51 +0000167 // Binary search for glyph count.
168 static const MAT2 mat2 = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
169 int32_t max = SK_MaxU16 + 1;
170 int32_t min = 0;
171 GLYPHMETRICS gm;
172 while (min < max) {
173 int32_t mid = min + ((max - min) / 2);
174 if (GetGlyphOutlineW(hdc, mid, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0,
halcanary96fcdcc2015-08-27 07:41:13 -0700175 nullptr, &mat2) == GDI_ERROR) {
reed@google.comac6b9792011-03-11 15:42:51 +0000176 max = mid;
177 } else {
178 min = mid + 1;
179 }
180 }
181 SkASSERT(min == max);
182 return min;
183}
184
bungeman@google.com7bdd6142013-07-15 19:42:57 +0000185static unsigned calculateUPEM(HDC hdc, const LOGFONT& lf) {
186 TEXTMETRIC textMetric;
187 if (0 == GetTextMetrics(hdc, &textMetric)) {
188 textMetric.tmPitchAndFamily = TMPF_VECTOR;
189 call_ensure_accessible(lf);
190 GetTextMetrics(hdc, &textMetric);
191 }
192
193 if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) {
194 return textMetric.tmMaxCharWidth;
195 }
196
197 OUTLINETEXTMETRIC otm;
198 unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
199 if (0 == otmRet) {
200 call_ensure_accessible(lf);
201 otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
202 }
203
204 return (0 == otmRet) ? 0 : otm.otmEMSquare;
205}
206
reed@google.comac6b9792011-03-11 15:42:51 +0000207class LogFontTypeface : public SkTypeface {
reed@google.comac6b9792011-03-11 15:42:51 +0000208public:
bungemana4c4a2d2014-10-20 13:33:19 -0700209 LogFontTypeface(const SkFontStyle& style, const LOGFONT& lf, bool serializeAsStream)
bungemane3aea102016-07-13 05:16:58 -0700210 : SkTypeface(style, false)
bungemana4c4a2d2014-10-20 13:33:19 -0700211 , fLogFont(lf)
212 , fSerializeAsStream(serializeAsStream)
213 {
bungeman@google.comcb1bbb32012-10-12 18:48:35 +0000214 HFONT font = CreateFontIndirect(&lf);
215
halcanary96fcdcc2015-08-27 07:41:13 -0700216 HDC deviceContext = ::CreateCompatibleDC(nullptr);
bungeman@google.comcb1bbb32012-10-12 18:48:35 +0000217 HFONT savefont = (HFONT)SelectObject(deviceContext, font);
218
219 TEXTMETRIC textMetric;
220 if (0 == GetTextMetrics(deviceContext, &textMetric)) {
reed@google.com055180c2013-03-21 18:46:35 +0000221 call_ensure_accessible(lf);
bungeman@google.comcb1bbb32012-10-12 18:48:35 +0000222 if (0 == GetTextMetrics(deviceContext, &textMetric)) {
223 textMetric.tmPitchAndFamily = TMPF_TRUETYPE;
224 }
225 }
226 if (deviceContext) {
227 ::SelectObject(deviceContext, savefont);
228 ::DeleteDC(deviceContext);
229 }
230 if (font) {
231 ::DeleteObject(font);
232 }
233
bungeman@google.comfe747652013-03-25 19:36:11 +0000234 // The fixed pitch bit is set if the font is *not* fixed pitch.
235 this->setIsFixedPitch((textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0);
bungeman6e45bda2016-07-25 15:11:49 -0700236 this->setFontStyle(SkFontStyle(textMetric.tmWeight, style.width(), style.slant()));
bungeman@google.comfe747652013-03-25 19:36:11 +0000237
bungeman@google.comcb1bbb32012-10-12 18:48:35 +0000238 // Used a logfont on a memory context, should never get a device font.
239 // Therefore all TMPF_DEVICE will be PostScript (cubic) fonts.
bungeman6e45bda2016-07-25 15:11:49 -0700240 // If the font has cubic outlines, it will not be rendered with ClearType.
bungeman@google.comcb1bbb32012-10-12 18:48:35 +0000241 fCanBeLCD = !((textMetric.tmPitchAndFamily & TMPF_VECTOR) &&
242 (textMetric.tmPitchAndFamily & TMPF_DEVICE));
243 }
reed@google.comac6b9792011-03-11 15:42:51 +0000244
reed@google.com59d2f632011-05-02 19:36:59 +0000245 LOGFONT fLogFont;
bungeman@google.come70f7982012-06-01 19:38:19 +0000246 bool fSerializeAsStream;
bungeman@google.comcb1bbb32012-10-12 18:48:35 +0000247 bool fCanBeLCD;
reed@google.comac6b9792011-03-11 15:42:51 +0000248
reed@google.com59d2f632011-05-02 19:36:59 +0000249 static LogFontTypeface* Create(const LOGFONT& lf) {
bungemana4c4a2d2014-10-20 13:33:19 -0700250 return new LogFontTypeface(get_style(lf), lf, false);
reed@google.comac6b9792011-03-11 15:42:51 +0000251 }
reed@google.com0da48612013-03-19 16:06:52 +0000252
reed@google.com055180c2013-03-21 18:46:35 +0000253 static void EnsureAccessible(const SkTypeface* face) {
254 call_ensure_accessible(static_cast<const LogFontTypeface*>(face)->fLogFont);
255 }
256
reed@google.com0da48612013-03-19 16:06:52 +0000257protected:
mtklein36352bf2015-03-25 18:17:31 -0700258 SkStreamAsset* onOpenStream(int* ttcIndex) const override;
reeda9322c22016-04-12 06:47:05 -0700259 SkScalerContext* onCreateScalerContext(const SkScalerContextEffects&,
260 const SkDescriptor*) const override;
mtklein36352bf2015-03-25 18:17:31 -0700261 void onFilterRec(SkScalerContextRec*) const override;
reed39a9a502015-05-12 09:50:04 -0700262 SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics(
263 PerGlyphInfo, const uint32_t*, uint32_t) const override;
mtklein36352bf2015-03-25 18:17:31 -0700264 void onGetFontDescriptor(SkFontDescriptor*, bool*) const override;
Ben Wagnerfc497342017-02-24 11:15:26 -0500265 int onCharsToGlyphs(const void* chars, Encoding encoding,
266 uint16_t glyphs[], int glyphCount) const override;
mtklein36352bf2015-03-25 18:17:31 -0700267 int onCountGlyphs() const override;
268 int onGetUPEM() const override;
269 void onGetFamilyName(SkString* familyName) const override;
270 SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override;
Ben Wagnerfc497342017-02-24 11:15:26 -0500271 int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[],
272 int coordinateCount) const override
273 {
274 return -1;
275 }
mtklein36352bf2015-03-25 18:17:31 -0700276 int onGetTableTags(SkFontTableTag tags[]) const override;
Ben Wagnerfc497342017-02-24 11:15:26 -0500277 size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void* data) const override;
reed@google.comac6b9792011-03-11 15:42:51 +0000278};
279
bungeman@google.coma5501992012-05-18 19:06:41 +0000280class FontMemResourceTypeface : public LogFontTypeface {
281public:
282 /**
bungeman@google.coma5501992012-05-18 19:06:41 +0000283 * The created FontMemResourceTypeface takes ownership of fontMemResource.
284 */
285 static FontMemResourceTypeface* Create(const LOGFONT& lf, HANDLE fontMemResource) {
bungemana4c4a2d2014-10-20 13:33:19 -0700286 return new FontMemResourceTypeface(get_style(lf), lf, fontMemResource);
bungeman@google.coma5501992012-05-18 19:06:41 +0000287 }
288
289protected:
mtklein36352bf2015-03-25 18:17:31 -0700290 void weak_dispose() const override {
bungeman@google.coma5501992012-05-18 19:06:41 +0000291 RemoveFontMemResourceEx(fFontMemResource);
292 //SkTypefaceCache::Remove(this);
293 INHERITED::weak_dispose();
294 }
295
296private:
bungeman@google.com72cf4fc2014-03-21 22:48:32 +0000297 /**
298 * Takes ownership of fontMemResource.
299 */
bungemana4c4a2d2014-10-20 13:33:19 -0700300 FontMemResourceTypeface(const SkFontStyle& style, const LOGFONT& lf, HANDLE fontMemResource)
301 : LogFontTypeface(style, lf, true), fFontMemResource(fontMemResource)
302 { }
bungeman@google.com72cf4fc2014-03-21 22:48:32 +0000303
304 HANDLE fFontMemResource;
305
bungeman@google.coma5501992012-05-18 19:06:41 +0000306 typedef LogFontTypeface INHERITED;
307};
308
reed@google.comac6b9792011-03-11 15:42:51 +0000309static const LOGFONT& get_default_font() {
310 static LOGFONT gDefaultFont;
reed@google.comac6b9792011-03-11 15:42:51 +0000311 return gDefaultFont;
312}
313
bungeman82a455f2016-04-14 08:04:45 -0700314static bool FindByLogFont(SkTypeface* face, void* ctx) {
bungeman@google.coma5501992012-05-18 19:06:41 +0000315 LogFontTypeface* lface = static_cast<LogFontTypeface*>(face);
reed@google.com59d2f632011-05-02 19:36:59 +0000316 const LOGFONT* lf = reinterpret_cast<const LOGFONT*>(ctx);
reed@google.comac6b9792011-03-11 15:42:51 +0000317
bungeman82a455f2016-04-14 08:04:45 -0700318 return !memcmp(&lface->fLogFont, lf, sizeof(LOGFONT));
reed@google.com59d2f632011-05-02 19:36:59 +0000319}
320
321/**
322 * This guy is public. It first searches the cache, and if a match is not found,
323 * it creates a new face.
324 */
325SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT& origLF) {
326 LOGFONT lf = origLF;
327 make_canonical(&lf);
bungeman@google.comee51d1a2012-02-16 12:40:48 +0000328 SkTypeface* face = SkTypefaceCache::FindByProcAndRef(FindByLogFont, &lf);
halcanary96fcdcc2015-08-27 07:41:13 -0700329 if (nullptr == face) {
reed@google.com59d2f632011-05-02 19:36:59 +0000330 face = LogFontTypeface::Create(lf);
bungeman82a455f2016-04-14 08:04:45 -0700331 SkTypefaceCache::Add(face);
reed@google.com59d2f632011-05-02 19:36:59 +0000332 }
333 return face;
reed@google.comac6b9792011-03-11 15:42:51 +0000334}
335
reed@google.comdb77a6a2011-07-19 19:08:33 +0000336/**
bungeman@google.coma5501992012-05-18 19:06:41 +0000337 * The created SkTypeface takes ownership of fontMemResource.
338 */
339SkTypeface* SkCreateFontMemResourceTypefaceFromLOGFONT(const LOGFONT& origLF, HANDLE fontMemResource) {
340 LOGFONT lf = origLF;
341 make_canonical(&lf);
mtklein60b6e9d2014-10-24 10:43:15 -0700342 // We'll never get a cache hit, so no point in putting this in SkTypefaceCache.
343 return FontMemResourceTypeface::Create(lf, fontMemResource);
bungeman@google.coma5501992012-05-18 19:06:41 +0000344}
345
346/**
reed@google.comdb77a6a2011-07-19 19:08:33 +0000347 * This guy is public
348 */
349void SkLOGFONTFromTypeface(const SkTypeface* face, LOGFONT* lf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700350 if (nullptr == face) {
reed@google.comdb77a6a2011-07-19 19:08:33 +0000351 *lf = get_default_font();
352 } else {
bungeman@google.coma5501992012-05-18 19:06:41 +0000353 *lf = static_cast<const LogFontTypeface*>(face)->fLogFont;
reed@google.comdb77a6a2011-07-19 19:08:33 +0000354 }
355}
356
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000357// Construct Glyph to Unicode table.
358// Unicode code points that require conjugate pairs in utf16 are not
359// supported.
360// TODO(arthurhsu): Add support for conjugate pairs. It looks like that may
361// require parsing the TTF cmap table (platform 4, encoding 12) directly instead
362// of calling GetFontUnicodeRange().
363static void populate_glyph_to_unicode(HDC fontHdc, const unsigned glyphCount,
364 SkTDArray<SkUnichar>* glyphToUnicode) {
halcanary96fcdcc2015-08-27 07:41:13 -0700365 DWORD glyphSetBufferSize = GetFontUnicodeRanges(fontHdc, nullptr);
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000366 if (!glyphSetBufferSize) {
367 return;
368 }
369
Ben Wagner7ecc5962016-11-02 17:07:33 -0400370 std::unique_ptr<BYTE[]> glyphSetBuffer(new BYTE[glyphSetBufferSize]);
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000371 GLYPHSET* glyphSet =
372 reinterpret_cast<LPGLYPHSET>(glyphSetBuffer.get());
373 if (GetFontUnicodeRanges(fontHdc, glyphSet) != glyphSetBufferSize) {
374 return;
375 }
376
377 glyphToUnicode->setCount(glyphCount);
378 memset(glyphToUnicode->begin(), 0, glyphCount * sizeof(SkUnichar));
379 for (DWORD i = 0; i < glyphSet->cRanges; ++i) {
380 // There is no guarantee that within a Unicode range, the corresponding
381 // glyph id in a font file are continuous. So, even if we have ranges,
382 // we can't just use the first and last entry of the range to compute
383 // result. We need to enumerate them one by one.
384 int count = glyphSet->ranges[i].cGlyphs;
385 SkAutoTArray<WCHAR> chars(count + 1);
386 chars[count] = 0; // termintate string
387 SkAutoTArray<WORD> glyph(count);
388 for (USHORT j = 0; j < count; ++j) {
389 chars[j] = glyphSet->ranges[i].wcLow + j;
390 }
391 GetGlyphIndicesW(fontHdc, chars.get(), count, glyph.get(),
392 GGI_MARK_NONEXISTING_GLYPHS);
393 // If the glyph ID is valid, and the glyph is not mapped, then we will
394 // fill in the char id into the vector. If the glyph is mapped already,
395 // skip it.
396 // TODO(arthurhsu): better improve this. e.g. Get all used char ids from
397 // font cache, then generate this mapping table from there. It's
398 // unlikely to have collisions since glyph reuse happens mostly for
399 // different Unicode pages.
400 for (USHORT j = 0; j < count; ++j) {
401 if (glyph[j] != 0xffff && glyph[j] < glyphCount &&
402 (*glyphToUnicode)[glyph[j]] == 0) {
403 (*glyphToUnicode)[glyph[j]] = chars[j];
404 }
405 }
406 }
407}
408
reed@google.com99edd432011-09-09 14:59:59 +0000409//////////////////////////////////////////////////////////////////////////////////////
410
411static int alignTo32(int n) {
412 return (n + 31) & ~31;
413}
414
415struct MyBitmapInfo : public BITMAPINFO {
416 RGBQUAD fMoreSpaceForColors[1];
417};
418
419class HDCOffscreen {
420public:
421 HDCOffscreen() {
422 fFont = 0;
423 fDC = 0;
424 fBM = 0;
halcanary96fcdcc2015-08-27 07:41:13 -0700425 fBits = nullptr;
reed@google.com99edd432011-09-09 14:59:59 +0000426 fWidth = fHeight = 0;
427 fIsBW = false;
428 }
429
430 ~HDCOffscreen() {
431 if (fDC) {
432 DeleteDC(fDC);
433 }
434 if (fBM) {
435 DeleteObject(fBM);
436 }
437 }
438
439 void init(HFONT font, const XFORM& xform) {
440 fFont = font;
441 fXform = xform;
442 }
443
bungeman@google.com97efada2012-07-30 20:40:50 +0000444 const void* draw(const SkGlyph&, bool isBW, size_t* srcRBPtr);
reed@google.com99edd432011-09-09 14:59:59 +0000445
446private:
447 HDC fDC;
448 HBITMAP fBM;
449 HFONT fFont;
450 XFORM fXform;
451 void* fBits; // points into fBM
452 int fWidth;
453 int fHeight;
454 bool fIsBW;
455};
456
reed@google.com754e4eb2011-09-26 13:21:39 +0000457const void* HDCOffscreen::draw(const SkGlyph& glyph, bool isBW,
bungeman@google.com97efada2012-07-30 20:40:50 +0000458 size_t* srcRBPtr) {
reed@google.com84e22d82013-07-10 15:38:20 +0000459 // Can we share the scalercontext's fDDC, so we don't need to create
460 // a separate fDC here?
reed@google.com99edd432011-09-09 14:59:59 +0000461 if (0 == fDC) {
462 fDC = CreateCompatibleDC(0);
463 if (0 == fDC) {
halcanary96fcdcc2015-08-27 07:41:13 -0700464 return nullptr;
reed@google.com99edd432011-09-09 14:59:59 +0000465 }
466 SetGraphicsMode(fDC, GM_ADVANCED);
467 SetBkMode(fDC, TRANSPARENT);
468 SetTextAlign(fDC, TA_LEFT | TA_BASELINE);
469 SelectObject(fDC, fFont);
bungeman@google.com97efada2012-07-30 20:40:50 +0000470
471 COLORREF color = 0x00FFFFFF;
bsalomon@google.comb58a6392013-03-21 20:29:05 +0000472 SkDEBUGCODE(COLORREF prev =) SetTextColor(fDC, color);
bungeman@google.com97efada2012-07-30 20:40:50 +0000473 SkASSERT(prev != CLR_INVALID);
reed@google.com99edd432011-09-09 14:59:59 +0000474 }
475
476 if (fBM && (fIsBW != isBW || fWidth < glyph.fWidth || fHeight < glyph.fHeight)) {
477 DeleteObject(fBM);
478 fBM = 0;
479 }
reed@google.com754e4eb2011-09-26 13:21:39 +0000480 fIsBW = isBW;
reed@google.com99edd432011-09-09 14:59:59 +0000481
reed@google.com99edd432011-09-09 14:59:59 +0000482 fWidth = SkMax32(fWidth, glyph.fWidth);
483 fHeight = SkMax32(fHeight, glyph.fHeight);
484
485 int biWidth = isBW ? alignTo32(fWidth) : fWidth;
486
487 if (0 == fBM) {
488 MyBitmapInfo info;
489 sk_bzero(&info, sizeof(info));
490 if (isBW) {
491 RGBQUAD blackQuad = { 0, 0, 0, 0 };
492 RGBQUAD whiteQuad = { 0xFF, 0xFF, 0xFF, 0 };
493 info.bmiColors[0] = blackQuad;
494 info.bmiColors[1] = whiteQuad;
495 }
496 info.bmiHeader.biSize = sizeof(info.bmiHeader);
497 info.bmiHeader.biWidth = biWidth;
498 info.bmiHeader.biHeight = fHeight;
499 info.bmiHeader.biPlanes = 1;
500 info.bmiHeader.biBitCount = isBW ? 1 : 32;
501 info.bmiHeader.biCompression = BI_RGB;
502 if (isBW) {
503 info.bmiHeader.biClrUsed = 2;
504 }
505 fBM = CreateDIBSection(fDC, &info, DIB_RGB_COLORS, &fBits, 0, 0);
506 if (0 == fBM) {
halcanary96fcdcc2015-08-27 07:41:13 -0700507 return nullptr;
reed@google.com99edd432011-09-09 14:59:59 +0000508 }
509 SelectObject(fDC, fBM);
510 }
511
512 // erase
513 size_t srcRB = isBW ? (biWidth >> 3) : (fWidth << 2);
514 size_t size = fHeight * srcRB;
bungeman@google.com97efada2012-07-30 20:40:50 +0000515 memset(fBits, 0, size);
reed@google.com99edd432011-09-09 14:59:59 +0000516
517 XFORM xform = fXform;
518 xform.eDx = (float)-glyph.fLeft;
519 xform.eDy = (float)-glyph.fTop;
520 SetWorldTransform(fDC, &xform);
521
522 uint16_t glyphID = glyph.getGlyphID();
halcanary96fcdcc2015-08-27 07:41:13 -0700523 BOOL ret = ExtTextOutW(fDC, 0, 0, ETO_GLYPH_INDEX, nullptr, reinterpret_cast<LPCWSTR>(&glyphID), 1, nullptr);
reed@google.com99edd432011-09-09 14:59:59 +0000524 GdiFlush();
bungeman@google.com39698b12011-11-15 22:26:41 +0000525 if (0 == ret) {
halcanary96fcdcc2015-08-27 07:41:13 -0700526 return nullptr;
bungeman@google.com39698b12011-11-15 22:26:41 +0000527 }
reed@google.com99edd432011-09-09 14:59:59 +0000528 *srcRBPtr = srcRB;
529 // offset to the start of the image
530 return (const char*)fBits + (fHeight - glyph.fHeight) * srcRB;
531}
532
reed@google.comb8a5c612012-06-13 20:01:44 +0000533//////////////////////////////////////////////////////////////////////////////
bungeman@google.com0abbff92013-07-27 20:37:56 +0000534#define BUFFERSIZE (1 << 13)
reed@google.com59d2f632011-05-02 19:36:59 +0000535
reed@google.com30ddd612013-07-30 17:47:39 +0000536class SkScalerContext_GDI : public SkScalerContext {
reed@google.comac6b9792011-03-11 15:42:51 +0000537public:
bungeman7cfd46a2016-10-20 16:06:52 -0400538 SkScalerContext_GDI(sk_sp<LogFontTypeface>,
539 const SkScalerContextEffects&,
540 const SkDescriptor* desc);
reed@google.com30ddd612013-07-30 17:47:39 +0000541 virtual ~SkScalerContext_GDI();
reed@google.comac6b9792011-03-11 15:42:51 +0000542
reed@google.com84e22d82013-07-10 15:38:20 +0000543 // Returns true if the constructor was able to complete all of its
544 // initializations (which may include calling GDI).
545 bool isValid() const;
546
reed@google.comac6b9792011-03-11 15:42:51 +0000547protected:
mtklein36352bf2015-03-25 18:17:31 -0700548 unsigned generateGlyphCount() override;
549 uint16_t generateCharToGlyph(SkUnichar uni) override;
550 void generateAdvance(SkGlyph* glyph) override;
551 void generateMetrics(SkGlyph* glyph) override;
552 void generateImage(const SkGlyph& glyph) override;
Ben Wagner6e9ac122016-11-11 14:31:06 -0500553 void generatePath(SkGlyphID glyph, SkPath* path) override;
mtklein36352bf2015-03-25 18:17:31 -0700554 void generateFontMetrics(SkPaint::FontMetrics*) override;
reed@google.com99edd432011-09-09 14:59:59 +0000555
reed@google.comac6b9792011-03-11 15:42:51 +0000556private:
Ben Wagner6e9ac122016-11-11 14:31:06 -0500557 DWORD getGDIGlyphPath(SkGlyphID glyph, UINT flags,
bungeman@google.com0abbff92013-07-27 20:37:56 +0000558 SkAutoSTMalloc<BUFFERSIZE, uint8_t>* glyphbuf);
559
reed@google.com99edd432011-09-09 14:59:59 +0000560 HDCOffscreen fOffscreen;
bungeman@google.com0abbff92013-07-27 20:37:56 +0000561 /** fGsA is the non-rotational part of total matrix without the text height scale.
562 * Used to find the magnitude of advances.
563 */
564 MAT2 fGsA;
bungeman@google.com6a774a12013-07-30 01:07:48 +0000565 /** The total matrix without the textSize. */
reed@google.comac6b9792011-03-11 15:42:51 +0000566 MAT2 fMat22;
bungeman@google.com6a774a12013-07-30 01:07:48 +0000567 /** Scales font to EM size. */
568 MAT2 fHighResMat22;
reed@google.comac6b9792011-03-11 15:42:51 +0000569 HDC fDDC;
570 HFONT fSavefont;
571 HFONT fFont;
572 SCRIPT_CACHE fSC;
573 int fGlyphCount;
reed@google.com1dd17a12011-05-17 14:04:41 +0000574
bungeman@google.com6a774a12013-07-30 01:07:48 +0000575 /** The total matrix which also removes EM scale. */
reed@google.com1dd17a12011-05-17 14:04:41 +0000576 SkMatrix fHiResMatrix;
bungeman@google.com0abbff92013-07-27 20:37:56 +0000577 /** fG_inv is the inverse of the rotational part of the total matrix.
578 * Used to set the direction of advances.
579 */
580 SkMatrix fG_inv;
bungeman@google.coma0319f62012-04-18 15:40:50 +0000581 enum Type {
bungeman@google.com4732df62014-01-23 15:22:42 +0000582 kTrueType_Type, kBitmap_Type, kLine_Type
bungeman@google.coma0319f62012-04-18 15:40:50 +0000583 } fType;
584 TEXTMETRIC fTM;
reed@google.comac6b9792011-03-11 15:42:51 +0000585};
586
reed@google.comac6b9792011-03-11 15:42:51 +0000587static FIXED float2FIXED(float x) {
588 return SkFixedToFIXED(SkFloatToFixed(x));
589}
590
benjaminwagner6b3eacb2016-03-24 19:07:58 -0700591static inline float FIXED2float(FIXED x) {
592 return SkFixedToFloat(SkFIXEDToFixed(x));
593}
594
reed@google.com82a34d82011-07-26 19:33:08 +0000595static BYTE compute_quality(const SkScalerContext::Rec& rec) {
596 switch (rec.fMaskFormat) {
597 case SkMask::kBW_Format:
598 return NONANTIALIASED_QUALITY;
599 case SkMask::kLCD16_Format:
reed@google.com82a34d82011-07-26 19:33:08 +0000600 return CLEARTYPE_QUALITY;
601 default:
reed@google.com8351aab2012-01-18 17:06:35 +0000602 if (rec.fFlags & SkScalerContext::kGenA8FromLCD_Flag) {
603 return CLEARTYPE_QUALITY;
604 } else {
605 return ANTIALIASED_QUALITY;
606 }
reed@google.com82a34d82011-07-26 19:33:08 +0000607 }
608}
609
bungeman7cfd46a2016-10-20 16:06:52 -0400610SkScalerContext_GDI::SkScalerContext_GDI(sk_sp<LogFontTypeface> rawTypeface,
reeda9322c22016-04-12 06:47:05 -0700611 const SkScalerContextEffects& effects,
612 const SkDescriptor* desc)
bungeman7cfd46a2016-10-20 16:06:52 -0400613 : SkScalerContext(std::move(rawTypeface), effects, desc)
reed@google.com055180c2013-03-21 18:46:35 +0000614 , fDDC(0)
reed@google.com055180c2013-03-21 18:46:35 +0000615 , fSavefont(0)
reed@google.com84e22d82013-07-10 15:38:20 +0000616 , fFont(0)
reed@google.com055180c2013-03-21 18:46:35 +0000617 , fSC(0)
bungeman@google.com05a729f2013-06-20 15:29:16 +0000618 , fGlyphCount(-1)
619{
bungeman7cfd46a2016-10-20 16:06:52 -0400620 LogFontTypeface* typeface = static_cast<LogFontTypeface*>(this->getTypeface());
reed@google.com055180c2013-03-21 18:46:35 +0000621
halcanary96fcdcc2015-08-27 07:41:13 -0700622 fDDC = ::CreateCompatibleDC(nullptr);
reed@google.com84e22d82013-07-10 15:38:20 +0000623 if (!fDDC) {
624 return;
625 }
reed@google.com1dd17a12011-05-17 14:04:41 +0000626 SetGraphicsMode(fDDC, GM_ADVANCED);
reed@google.comac6b9792011-03-11 15:42:51 +0000627 SetBkMode(fDDC, TRANSPARENT);
skia.committer@gmail.com27e21fe2013-07-28 07:01:03 +0000628
bungeman6f940762015-03-18 08:25:43 -0700629 // When GDI hinting, remove the entire Y scale from sA and GsA. (Prevents 'linear' metrics.)
630 // When not hinting, remove only the integer Y scale from sA and GsA. (Applied by GDI.)
bungeman5f14c5e2014-12-05 12:26:44 -0800631 SkScalerContextRec::PreMatrixScale scaleConstraints =
632 (fRec.getHinting() == SkPaint::kNo_Hinting || fRec.getHinting() == SkPaint::kSlight_Hinting)
633 ? SkScalerContextRec::kVerticalInteger_PreMatrixScale
634 : SkScalerContextRec::kVertical_PreMatrixScale;
635 SkVector scale;
636 SkMatrix sA;
637 SkMatrix GsA;
638 SkMatrix A;
639 fRec.computeMatrices(scaleConstraints, &scale, &sA, &GsA, &fG_inv, &A);
bungeman@google.com0abbff92013-07-27 20:37:56 +0000640
641 fGsA.eM11 = SkScalarToFIXED(GsA.get(SkMatrix::kMScaleX));
642 fGsA.eM12 = SkScalarToFIXED(-GsA.get(SkMatrix::kMSkewY)); // This should be ~0.
643 fGsA.eM21 = SkScalarToFIXED(-GsA.get(SkMatrix::kMSkewX));
644 fGsA.eM22 = SkScalarToFIXED(GsA.get(SkMatrix::kMScaleY));
645
bungeman6f940762015-03-18 08:25:43 -0700646 // When not hinting, scale was computed with kVerticalInteger, so is already an integer.
647 // The sA and GsA transforms will be used to create 'linear' metrics.
648
649 // When hinting, scale was computed with kVertical, stating that our port can handle
650 // non-integer scales. This is done so that sA and GsA are computed without any 'residual'
651 // scale in them, preventing 'linear' metrics. However, GDI cannot actually handle non-integer
652 // scales so we need to round in this case. This is fine, since all of the scale has been
653 // removed from sA and GsA, so GDI will be handling the scale completely.
654 SkScalar gdiTextSize = SkScalarRoundToScalar(scale.fY);
655
656 // GDI will not accept a size of zero, so round the range [0, 1] to 1.
657 // If the size was non-zero, the scale factors will also be non-zero and 1px tall text is drawn.
658 // If the size actually was zero, the scale factors will also be zero, so GDI will draw nothing.
bungeman5f14c5e2014-12-05 12:26:44 -0800659 if (gdiTextSize == 0) {
660 gdiTextSize = SK_Scalar1;
661 }
bungeman@google.com0abbff92013-07-27 20:37:56 +0000662
reed@google.com055180c2013-03-21 18:46:35 +0000663 LOGFONT lf = typeface->fLogFont;
bungeman@google.com11ba3192013-10-03 20:17:51 +0000664 lf.lfHeight = -SkScalarTruncToInt(gdiTextSize);
reed@google.com82a34d82011-07-26 19:33:08 +0000665 lf.lfQuality = compute_quality(fRec);
reed@google.comac6b9792011-03-11 15:42:51 +0000666 fFont = CreateFontIndirect(&lf);
reed@google.com84e22d82013-07-10 15:38:20 +0000667 if (!fFont) {
668 return;
669 }
reed@google.com1dd17a12011-05-17 14:04:41 +0000670
reed@google.comac6b9792011-03-11 15:42:51 +0000671 fSavefont = (HFONT)SelectObject(fDDC, fFont);
reed@google.coma767fa02011-08-05 21:40:26 +0000672
bungeman@google.coma0319f62012-04-18 15:40:50 +0000673 if (0 == GetTextMetrics(fDDC, &fTM)) {
reed@google.com055180c2013-03-21 18:46:35 +0000674 call_ensure_accessible(lf);
bungeman@google.coma0319f62012-04-18 15:40:50 +0000675 if (0 == GetTextMetrics(fDDC, &fTM)) {
676 fTM.tmPitchAndFamily = TMPF_TRUETYPE;
677 }
678 }
bungeman@google.com90b7e382012-04-20 15:26:28 +0000679
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000680 XFORM xform;
bungeman@google.com90b7e382012-04-20 15:26:28 +0000681 if (fTM.tmPitchAndFamily & TMPF_VECTOR) {
bungeman@google.com4732df62014-01-23 15:22:42 +0000682 // Used a logfont on a memory context, should never get a device font.
683 // Therefore all TMPF_DEVICE will be PostScript fonts.
684
685 // If TMPF_VECTOR is set, one of TMPF_TRUETYPE or TMPF_DEVICE means that
686 // we have an outline font. Otherwise we have a vector FON, which is
687 // scalable, but not an outline font.
688 // This was determined by testing with Type1 PFM/PFB and
689 // OpenTypeCFF OTF, as well as looking at Wine bugs and sources.
690 if (fTM.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_DEVICE)) {
691 // Truetype or PostScript.
692 fType = SkScalerContext_GDI::kTrueType_Type;
693 } else {
694 // Stroked FON.
695 fType = SkScalerContext_GDI::kLine_Type;
696 }
bungeman@google.coma0319f62012-04-18 15:40:50 +0000697
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000698 // fPost2x2 is column-major, left handed (y down).
699 // XFORM 2x2 is row-major, left handed (y down).
bungeman@google.com0abbff92013-07-27 20:37:56 +0000700 xform.eM11 = SkScalarToFloat(sA.get(SkMatrix::kMScaleX));
701 xform.eM12 = SkScalarToFloat(sA.get(SkMatrix::kMSkewY));
702 xform.eM21 = SkScalarToFloat(sA.get(SkMatrix::kMSkewX));
703 xform.eM22 = SkScalarToFloat(sA.get(SkMatrix::kMScaleY));
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000704 xform.eDx = 0;
705 xform.eDy = 0;
bungeman@google.coma0319f62012-04-18 15:40:50 +0000706
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000707 // MAT2 is row major, right handed (y up).
708 fMat22.eM11 = float2FIXED(xform.eM11);
709 fMat22.eM12 = float2FIXED(-xform.eM12);
710 fMat22.eM21 = float2FIXED(-xform.eM21);
711 fMat22.eM22 = float2FIXED(xform.eM22);
bungeman@google.coma0319f62012-04-18 15:40:50 +0000712
713 if (needToRenderWithSkia(fRec)) {
714 this->forceGenerateImageFromPath();
715 }
716
bungeman@google.com11ba3192013-10-03 20:17:51 +0000717 // Create a hires matrix if we need linear metrics.
bungeman@google.com0abbff92013-07-27 20:37:56 +0000718 if (this->isSubpixel()) {
719 OUTLINETEXTMETRIC otm;
720 UINT success = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
721 if (0 == success) {
722 call_ensure_accessible(lf);
723 success = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
724 }
725 if (0 != success) {
bungeman@google.com11ba3192013-10-03 20:17:51 +0000726 SkScalar upem = SkIntToScalar(otm.otmEMSquare);
bungeman@google.com0abbff92013-07-27 20:37:56 +0000727
bungeman@google.com11ba3192013-10-03 20:17:51 +0000728 SkScalar gdiTextSizeToEMScale = upem / gdiTextSize;
729 fHighResMat22.eM11 = float2FIXED(gdiTextSizeToEMScale);
bungeman@google.com6a774a12013-07-30 01:07:48 +0000730 fHighResMat22.eM12 = float2FIXED(0);
731 fHighResMat22.eM21 = float2FIXED(0);
bungeman@google.com11ba3192013-10-03 20:17:51 +0000732 fHighResMat22.eM22 = float2FIXED(gdiTextSizeToEMScale);
bungeman@google.com6a774a12013-07-30 01:07:48 +0000733
bungeman@google.com11ba3192013-10-03 20:17:51 +0000734 SkScalar removeEMScale = SkScalarInvert(upem);
bungeman@google.com6a774a12013-07-30 01:07:48 +0000735 fHiResMatrix = A;
bungeman@google.com11ba3192013-10-03 20:17:51 +0000736 fHiResMatrix.preScale(removeEMScale, removeEMScale);
bungeman@google.com0abbff92013-07-27 20:37:56 +0000737 }
738 }
739
bungeman@google.coma0319f62012-04-18 15:40:50 +0000740 } else {
741 // Assume bitmap
reed@google.com30ddd612013-07-30 17:47:39 +0000742 fType = SkScalerContext_GDI::kBitmap_Type;
bungeman@google.coma0319f62012-04-18 15:40:50 +0000743
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000744 xform.eM11 = 1.0f;
745 xform.eM12 = 0.0f;
746 xform.eM21 = 0.0f;
747 xform.eM22 = 1.0f;
748 xform.eDx = 0.0f;
749 xform.eDy = 0.0f;
bungeman@google.coma0319f62012-04-18 15:40:50 +0000750
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000751 // fPost2x2 is column-major, left handed (y down).
752 // MAT2 is row major, right handed (y up).
bungeman@google.coma0319f62012-04-18 15:40:50 +0000753 fMat22.eM11 = SkScalarToFIXED(fRec.fPost2x2[0][0]);
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000754 fMat22.eM12 = SkScalarToFIXED(-fRec.fPost2x2[1][0]);
bungeman@google.coma0319f62012-04-18 15:40:50 +0000755 fMat22.eM21 = SkScalarToFIXED(-fRec.fPost2x2[0][1]);
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000756 fMat22.eM22 = SkScalarToFIXED(fRec.fPost2x2[1][1]);
reed@google.coma767fa02011-08-05 21:40:26 +0000757 }
reed@google.com99edd432011-09-09 14:59:59 +0000758
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000759 fOffscreen.init(fFont, xform);
reed@google.comac6b9792011-03-11 15:42:51 +0000760}
761
reed@google.com30ddd612013-07-30 17:47:39 +0000762SkScalerContext_GDI::~SkScalerContext_GDI() {
reed@google.comac6b9792011-03-11 15:42:51 +0000763 if (fDDC) {
764 ::SelectObject(fDDC, fSavefont);
765 ::DeleteDC(fDDC);
766 }
767 if (fFont) {
768 ::DeleteObject(fFont);
769 }
770 if (fSC) {
771 ::ScriptFreeCache(&fSC);
772 }
773}
774
reed@google.com30ddd612013-07-30 17:47:39 +0000775bool SkScalerContext_GDI::isValid() const {
reed@google.com84e22d82013-07-10 15:38:20 +0000776 return fDDC && fFont;
777}
778
reed@google.com30ddd612013-07-30 17:47:39 +0000779unsigned SkScalerContext_GDI::generateGlyphCount() {
reed@google.comac6b9792011-03-11 15:42:51 +0000780 if (fGlyphCount < 0) {
bungeman@google.com7bdd6142013-07-15 19:42:57 +0000781 fGlyphCount = calculateGlyphCount(
782 fDDC, static_cast<const LogFontTypeface*>(this->getTypeface())->fLogFont);
reed@google.comac6b9792011-03-11 15:42:51 +0000783 }
784 return fGlyphCount;
785}
786
bungeman@google.com33346482013-08-27 19:05:32 +0000787uint16_t SkScalerContext_GDI::generateCharToGlyph(SkUnichar utf32) {
reed@google.comac6b9792011-03-11 15:42:51 +0000788 uint16_t index = 0;
bungeman@google.com33346482013-08-27 19:05:32 +0000789 WCHAR utf16[2];
reed@google.comac6b9792011-03-11 15:42:51 +0000790 // TODO(ctguil): Support characters that generate more than one glyph.
bungeman@google.com33346482013-08-27 19:05:32 +0000791 if (SkUTF16_FromUnichar(utf32, (uint16_t*)utf16) == 1) {
reed@google.comac6b9792011-03-11 15:42:51 +0000792 // Type1 fonts fail with uniscribe API. Use GetGlyphIndices for plane 0.
skia.committer@gmail.com7bd141d2013-08-28 07:01:18 +0000793
bungeman@google.com33346482013-08-27 19:05:32 +0000794 /** Real documentation for GetGlyphIndiciesW:
795 *
796 * When GGI_MARK_NONEXISTING_GLYPHS is not specified and a character does not map to a
797 * glyph, then the 'default character's glyph is returned instead. The 'default character'
bungeman@google.com4732df62014-01-23 15:22:42 +0000798 * is available in fTM.tmDefaultChar. FON fonts have a default character, and there exists
799 * a usDefaultChar in the 'OS/2' table, version 2 and later. If there is no
bungeman@google.com33346482013-08-27 19:05:32 +0000800 * 'default character' specified by the font, then often the first character found is used.
801 *
802 * When GGI_MARK_NONEXISTING_GLYPHS is specified and a character does not map to a glyph,
803 * then the glyph 0xFFFF is used. In Windows XP and earlier, Bitmap/Vector FON usually use
804 * glyph 0x1F instead ('Terminal' appears to be special, returning 0xFFFF).
805 * Type1 PFM/PFB, TT, OT TT, OT CFF all appear to use 0xFFFF, even on XP.
806 */
807 DWORD result = GetGlyphIndicesW(fDDC, utf16, 1, &index, GGI_MARK_NONEXISTING_GLYPHS);
808 if (result == GDI_ERROR
809 || 0xFFFF == index
bungeman@google.com4732df62014-01-23 15:22:42 +0000810 || (0x1F == index &&
811 (fType == SkScalerContext_GDI::kBitmap_Type ||
812 fType == SkScalerContext_GDI::kLine_Type)
813 /*&& winVer < Vista */)
814 )
bungeman@google.com33346482013-08-27 19:05:32 +0000815 {
816 index = 0;
817 }
reed@google.comac6b9792011-03-11 15:42:51 +0000818 } else {
819 // Use uniscribe to detemine glyph index for non-BMP characters.
bungeman@google.com27f74aa2013-10-08 21:32:15 +0000820 static const int numWCHAR = 2;
821 static const int maxItems = 2;
halcanary96fcdcc2015-08-27 07:41:13 -0700822 // MSDN states that this can be nullptr, but some things don't work then.
bungeman@google.com27f74aa2013-10-08 21:32:15 +0000823 SCRIPT_CONTROL sc = { 0 };
824 // Add extra item to SCRIPT_ITEM to work around a bug (now documented).
825 // https://bugzilla.mozilla.org/show_bug.cgi?id=366643
826 SCRIPT_ITEM si[maxItems + 1];
827 int numItems;
halcanary96fcdcc2015-08-27 07:41:13 -0700828 HRZM(ScriptItemize(utf16, numWCHAR, maxItems, &sc, nullptr, si, &numItems),
bungeman@google.com27f74aa2013-10-08 21:32:15 +0000829 "Could not itemize character.");
reed@google.comac6b9792011-03-11 15:42:51 +0000830
bungeman@google.com27f74aa2013-10-08 21:32:15 +0000831 // Sometimes ScriptShape cannot find a glyph for a non-BMP and returns 2 space glyphs.
832 static const int maxGlyphs = 2;
833 SCRIPT_VISATTR vsa[maxGlyphs];
834 WORD outGlyphs[maxGlyphs];
835 WORD logClust[numWCHAR];
836 int numGlyphs;
837 HRZM(ScriptShape(fDDC, &fSC, utf16, numWCHAR, maxGlyphs, &si[0].a,
838 outGlyphs, logClust, vsa, &numGlyphs),
839 "Could not shape character.");
840 if (1 == numGlyphs) {
841 index = outGlyphs[0];
842 }
reed@google.comac6b9792011-03-11 15:42:51 +0000843 }
844 return index;
845}
846
reed@google.com30ddd612013-07-30 17:47:39 +0000847void SkScalerContext_GDI::generateAdvance(SkGlyph* glyph) {
reed@google.comac6b9792011-03-11 15:42:51 +0000848 this->generateMetrics(glyph);
849}
850
reed@google.com30ddd612013-07-30 17:47:39 +0000851void SkScalerContext_GDI::generateMetrics(SkGlyph* glyph) {
reed@google.comac6b9792011-03-11 15:42:51 +0000852 SkASSERT(fDDC);
853
bungeman@google.com4732df62014-01-23 15:22:42 +0000854 if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) {
bungeman@google.coma0319f62012-04-18 15:40:50 +0000855 SIZE size;
djsollen1b277042014-08-06 06:58:06 -0700856 WORD glyphs = glyph->getGlyphID();
bungeman@google.coma0319f62012-04-18 15:40:50 +0000857 if (0 == GetTextExtentPointI(fDDC, &glyphs, 1, &size)) {
858 glyph->fWidth = SkToS16(fTM.tmMaxCharWidth);
859 } else {
860 glyph->fWidth = SkToS16(size.cx);
861 }
862 glyph->fHeight = SkToS16(size.cy);
863
864 glyph->fTop = SkToS16(-fTM.tmAscent);
bungeman@google.com4732df62014-01-23 15:22:42 +0000865 // Bitmap FON cannot underhang, but vector FON may.
866 // There appears no means of determining underhang of vector FON.
bungeman@google.coma0319f62012-04-18 15:40:50 +0000867 glyph->fLeft = SkToS16(0);
benjaminwagner6b3eacb2016-03-24 19:07:58 -0700868 glyph->fAdvanceX = glyph->fWidth;
bungeman@google.coma0319f62012-04-18 15:40:50 +0000869 glyph->fAdvanceY = 0;
870
bungeman@google.com4732df62014-01-23 15:22:42 +0000871 // Vector FON will transform nicely, but bitmap FON do not.
872 if (fType == SkScalerContext_GDI::kLine_Type) {
873 SkRect bounds = SkRect::MakeXYWH(glyph->fLeft, glyph->fTop,
874 glyph->fWidth, glyph->fHeight);
875 SkMatrix m;
876 m.setAll(SkFIXEDToScalar(fMat22.eM11), -SkFIXEDToScalar(fMat22.eM21), 0,
877 -SkFIXEDToScalar(fMat22.eM12), SkFIXEDToScalar(fMat22.eM22), 0,
reed3f43f8a2015-01-20 19:58:36 -0800878 0, 0, 1);
bungeman@google.com4732df62014-01-23 15:22:42 +0000879 m.mapRect(&bounds);
reedd02cf262014-11-18 18:06:45 -0800880 bounds.roundOut(&bounds);
bungeman@google.com4732df62014-01-23 15:22:42 +0000881 glyph->fLeft = SkScalarTruncToInt(bounds.fLeft);
882 glyph->fTop = SkScalarTruncToInt(bounds.fTop);
883 glyph->fWidth = SkScalarTruncToInt(bounds.width());
884 glyph->fHeight = SkScalarTruncToInt(bounds.height());
885 }
886
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000887 // Apply matrix to advance.
benjaminwagner6b3eacb2016-03-24 19:07:58 -0700888 glyph->fAdvanceY = -FIXED2float(fMat22.eM12) * glyph->fAdvanceX;
889 glyph->fAdvanceX *= FIXED2float(fMat22.eM11);
bungeman@google.coma0319f62012-04-18 15:40:50 +0000890
891 return;
892 }
893
djsollen1b277042014-08-06 06:58:06 -0700894 UINT glyphId = glyph->getGlyphID();
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000895
reed@google.comac6b9792011-03-11 15:42:51 +0000896 GLYPHMETRICS gm;
reed@google.com1dd17a12011-05-17 14:04:41 +0000897 sk_bzero(&gm, sizeof(gm));
reed@google.comac6b9792011-03-11 15:42:51 +0000898
halcanary96fcdcc2015-08-27 07:41:13 -0700899 DWORD status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, nullptr, &fMat22);
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000900 if (GDI_ERROR == status) {
reed@google.com055180c2013-03-21 18:46:35 +0000901 LogFontTypeface::EnsureAccessible(this->getTypeface());
halcanary96fcdcc2015-08-27 07:41:13 -0700902 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, nullptr, &fMat22);
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000903 if (GDI_ERROR == status) {
904 glyph->zeroMetrics();
905 return;
906 }
907 }
908
909 bool empty = false;
910 // The black box is either the embedded bitmap size or the outline extent.
911 // It is 1x1 if nothing is to be drawn, but will also be 1x1 if something very small
912 // is to be drawn, like a '.'. We need to outset '.' but do not wish to outset ' '.
913 if (1 == gm.gmBlackBoxX && 1 == gm.gmBlackBoxY) {
914 // If GetGlyphOutline with GGO_NATIVE returns 0, we know there was no outline.
halcanary96fcdcc2015-08-27 07:41:13 -0700915 DWORD bufferSize = GetGlyphOutlineW(fDDC, glyphId, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, 0, nullptr, &fMat22);
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000916 empty = (0 == bufferSize);
917 }
918
919 glyph->fTop = SkToS16(-gm.gmptGlyphOrigin.y);
920 glyph->fLeft = SkToS16(gm.gmptGlyphOrigin.x);
921 if (empty) {
922 glyph->fWidth = 0;
923 glyph->fHeight = 0;
924 } else {
925 // Outset, since the image may bleed out of the black box.
926 // For embedded bitmaps the black box should be exact.
927 // For outlines we need to outset by 1 in all directions for bleed.
928 // For ClearType we need to outset by 2 for bleed.
929 glyph->fWidth = gm.gmBlackBoxX + 4;
930 glyph->fHeight = gm.gmBlackBoxY + 4;
931 glyph->fTop -= 2;
932 glyph->fLeft -= 2;
933 }
benjaminwagner6b3eacb2016-03-24 19:07:58 -0700934 // TODO(benjaminwagner): What is the type of gm.gmCellInc[XY]?
935 glyph->fAdvanceX = (float)((int)gm.gmCellIncX);
936 glyph->fAdvanceY = (float)((int)gm.gmCellIncY);
reed@google.comac6b9792011-03-11 15:42:51 +0000937 glyph->fRsbDelta = 0;
938 glyph->fLsbDelta = 0;
939
bungeman@google.com6a774a12013-07-30 01:07:48 +0000940 if (this->isSubpixel()) {
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000941 sk_bzero(&gm, sizeof(gm));
halcanary96fcdcc2015-08-27 07:41:13 -0700942 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, nullptr, &fHighResMat22);
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000943 if (GDI_ERROR != status) {
944 SkPoint advance;
945 fHiResMatrix.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance);
benjaminwagner6b3eacb2016-03-24 19:07:58 -0700946 glyph->fAdvanceX = SkScalarToFloat(advance.fX);
947 glyph->fAdvanceY = SkScalarToFloat(advance.fY);
reed@google.comac6b9792011-03-11 15:42:51 +0000948 }
bungeman@google.com0abbff92013-07-27 20:37:56 +0000949 } else if (!isAxisAligned(this->fRec)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700950 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, nullptr, &fGsA);
bungeman@google.com0abbff92013-07-27 20:37:56 +0000951 if (GDI_ERROR != status) {
952 SkPoint advance;
953 fG_inv.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance);
benjaminwagner6b3eacb2016-03-24 19:07:58 -0700954 glyph->fAdvanceX = SkScalarToFloat(advance.fX);
955 glyph->fAdvanceY = SkScalarToFloat(advance.fY);
bungeman@google.com0abbff92013-07-27 20:37:56 +0000956 }
reed@google.comac6b9792011-03-11 15:42:51 +0000957 }
958}
959
bungeman@google.com6a774a12013-07-30 01:07:48 +0000960static const MAT2 gMat2Identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
bungeman41078062014-07-07 08:16:37 -0700961void SkScalerContext_GDI::generateFontMetrics(SkPaint::FontMetrics* metrics) {
halcanary96fcdcc2015-08-27 07:41:13 -0700962 if (nullptr == metrics) {
bungeman41078062014-07-07 08:16:37 -0700963 return;
reed@google.com60af92c2013-05-08 14:11:28 +0000964 }
bungeman41078062014-07-07 08:16:37 -0700965 sk_bzero(metrics, sizeof(*metrics));
reed@google.comac6b9792011-03-11 15:42:51 +0000966
967 SkASSERT(fDDC);
968
bungeman@google.come9d83192013-06-21 05:31:38 +0000969#ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
bungeman@google.com4732df62014-01-23 15:22:42 +0000970 if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) {
bungeman@google.come9d83192013-06-21 05:31:38 +0000971#endif
bungeman41078062014-07-07 08:16:37 -0700972 metrics->fTop = SkIntToScalar(-fTM.tmAscent);
973 metrics->fAscent = SkIntToScalar(-fTM.tmAscent);
974 metrics->fDescent = SkIntToScalar(fTM.tmDescent);
975 metrics->fBottom = SkIntToScalar(fTM.tmDescent);
976 metrics->fLeading = SkIntToScalar(fTM.tmExternalLeading);
977 metrics->fAvgCharWidth = SkIntToScalar(fTM.tmAveCharWidth);
978 metrics->fMaxCharWidth = SkIntToScalar(fTM.tmMaxCharWidth);
979 metrics->fXMin = 0;
980 metrics->fXMax = metrics->fMaxCharWidth;
981 //metrics->fXHeight = 0;
bungeman@google.come9d83192013-06-21 05:31:38 +0000982#ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
bungeman@google.coma0319f62012-04-18 15:40:50 +0000983 return;
984 }
bungeman@google.come9d83192013-06-21 05:31:38 +0000985#endif
bungeman@google.coma0319f62012-04-18 15:40:50 +0000986
reed@google.comac6b9792011-03-11 15:42:51 +0000987 OUTLINETEXTMETRIC otm;
988
989 uint32_t ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
bungeman@google.com0abbff92013-07-27 20:37:56 +0000990 if (0 == ret) {
reed@google.com055180c2013-03-21 18:46:35 +0000991 LogFontTypeface::EnsureAccessible(this->getTypeface());
bungeman@google.com39698b12011-11-15 22:26:41 +0000992 ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
993 }
bungeman@google.com0abbff92013-07-27 20:37:56 +0000994 if (0 == ret) {
bungeman@google.coma0319f62012-04-18 15:40:50 +0000995 return;
reed@google.comac6b9792011-03-11 15:42:51 +0000996 }
997
bungeman@google.come9d83192013-06-21 05:31:38 +0000998#ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
bungeman41078062014-07-07 08:16:37 -0700999 metrics->fTop = SkIntToScalar(-otm.otmrcFontBox.top);
1000 metrics->fAscent = SkIntToScalar(-otm.otmAscent);
1001 metrics->fDescent = SkIntToScalar(-otm.otmDescent);
1002 metrics->fBottom = SkIntToScalar(-otm.otmrcFontBox.bottom);
1003 metrics->fLeading = SkIntToScalar(otm.otmLineGap);
1004 metrics->fAvgCharWidth = SkIntToScalar(otm.otmTextMetrics.tmAveCharWidth);
1005 metrics->fMaxCharWidth = SkIntToScalar(otm.otmTextMetrics.tmMaxCharWidth);
1006 metrics->fXMin = SkIntToScalar(otm.otmrcFontBox.left);
1007 metrics->fXMax = SkIntToScalar(otm.otmrcFontBox.right);
commit-bot@chromium.orgd3031aa2014-05-14 14:54:51 +00001008#endif
bungeman41078062014-07-07 08:16:37 -07001009 metrics->fUnderlineThickness = SkIntToScalar(otm.otmsUnderscoreSize);
1010 metrics->fUnderlinePosition = -SkIntToScalar(otm.otmsUnderscorePosition);
commit-bot@chromium.org0bc406d2014-03-01 20:12:26 +00001011
Ben Wagner3318da52017-03-23 14:01:22 -04001012 metrics->fFlags |= SkPaint::FontMetrics::kUnderlineThicknessIsValid_Flag;
bungeman41078062014-07-07 08:16:37 -07001013 metrics->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
bungeman@google.com4a867a62014-05-22 17:59:21 +00001014
bungeman41078062014-07-07 08:16:37 -07001015 metrics->fXHeight = SkIntToScalar(otm.otmsXHeight);
1016 GLYPHMETRICS gm;
1017 sk_bzero(&gm, sizeof(gm));
1018 DWORD len = GetGlyphOutlineW(fDDC, 'x', GGO_METRICS, &gm, 0, 0, &gMat2Identity);
1019 if (len != GDI_ERROR && gm.gmBlackBoxY > 0) {
1020 metrics->fXHeight = SkIntToScalar(gm.gmBlackBoxY);
reed@google.comac6b9792011-03-11 15:42:51 +00001021 }
1022}
1023
reed@google.com7430a332011-10-03 14:37:38 +00001024////////////////////////////////////////////////////////////////////////////////////////
1025
bungeman@google.com0abbff92013-07-27 20:37:56 +00001026#define SK_SHOW_TEXT_BLIT_COVERAGE 0
1027
reed@google.com7430a332011-10-03 14:37:38 +00001028static void build_power_table(uint8_t table[], float ee) {
1029 for (int i = 0; i < 256; i++) {
1030 float x = i / 255.f;
bungeman@google.com97efada2012-07-30 20:40:50 +00001031 x = sk_float_pow(x, ee);
reed@google.come1ca7052013-12-17 19:22:07 +00001032 int xx = SkScalarRoundToInt(x * 255);
reed@google.com7430a332011-10-03 14:37:38 +00001033 table[i] = SkToU8(xx);
1034 }
1035}
1036
bungeman@google.com97efada2012-07-30 20:40:50 +00001037/**
1038 * This will invert the gamma applied by GDI (gray-scale antialiased), so we
1039 * can get linear values.
1040 *
1041 * GDI grayscale appears to use a hard-coded gamma of 2.3.
1042 *
1043 * GDI grayscale appears to draw using the black and white rasterizer at four
1044 * times the size and then downsamples to compute the coverage mask. As a
1045 * result there are only seventeen total grays. This lack of fidelity means
1046 * that shifting into other color spaces is imprecise.
1047 */
1048static const uint8_t* getInverseGammaTableGDI() {
bungeman@google.com05a729f2013-06-20 15:29:16 +00001049 // Since build_power_table is idempotent, many threads can build gTableGdi
1050 // simultaneously.
1051
1052 // Microsoft Specific:
1053 // Making gInited volatile provides read-aquire and write-release in vc++.
1054 // In VS2012, see compiler option /volatile:(ms|iso).
1055 // Replace with C++11 atomics when possible.
1056 static volatile bool gInited;
bungeman@google.com97efada2012-07-30 20:40:50 +00001057 static uint8_t gTableGdi[256];
bungeman@google.com05a729f2013-06-20 15:29:16 +00001058 if (gInited) {
1059 // Need a L/L (read) barrier (full acquire not needed). If gInited is observed
1060 // true then gTableGdi is observable, but it must be requested.
1061 } else {
bungeman@google.com97efada2012-07-30 20:40:50 +00001062 build_power_table(gTableGdi, 2.3f);
bungeman@google.com05a729f2013-06-20 15:29:16 +00001063 // Need a S/S (write) barrier (full release not needed) here so that this
1064 // write to gInited becomes observable after gTableGdi.
bungeman@google.com97efada2012-07-30 20:40:50 +00001065 gInited = true;
1066 }
1067 return gTableGdi;
1068}
1069
1070/**
1071 * This will invert the gamma applied by GDI ClearType, so we can get linear
1072 * values.
1073 *
1074 * GDI ClearType uses SPI_GETFONTSMOOTHINGCONTRAST / 1000 as the gamma value.
1075 * If this value is not specified, the default is a gamma of 1.4.
1076 */
1077static const uint8_t* getInverseGammaTableClearType() {
bungeman@google.com05a729f2013-06-20 15:29:16 +00001078 // We don't expect SPI_GETFONTSMOOTHINGCONTRAST to ever change, so building
1079 // gTableClearType with build_power_table is effectively idempotent.
1080
1081 // Microsoft Specific:
1082 // Making gInited volatile provides read-aquire and write-release in vc++.
1083 // In VS2012, see compiler option /volatile:(ms|iso).
1084 // Replace with C++11 atomics when possible.
1085 static volatile bool gInited;
bungeman@google.com97efada2012-07-30 20:40:50 +00001086 static uint8_t gTableClearType[256];
bungeman@google.com05a729f2013-06-20 15:29:16 +00001087 if (gInited) {
1088 // Need a L/L (read) barrier (acquire not needed). If gInited is observed
1089 // true then gTableClearType is observable, but it must be requested.
1090 } else {
reed@google.com7430a332011-10-03 14:37:38 +00001091 UINT level = 0;
1092 if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &level, 0) || !level) {
1093 // can't get the data, so use a default
1094 level = 1400;
1095 }
bungeman@google.com97efada2012-07-30 20:40:50 +00001096 build_power_table(gTableClearType, level / 1000.0f);
bungeman@google.com05a729f2013-06-20 15:29:16 +00001097 // Need a S/S (write) barrier (release not needed) here so that this
1098 // write to gInited becomes observable after gTableClearType.
reed@google.com7430a332011-10-03 14:37:38 +00001099 gInited = true;
1100 }
bungeman@google.com97efada2012-07-30 20:40:50 +00001101 return gTableClearType;
reed@google.com7430a332011-10-03 14:37:38 +00001102}
1103
reed@google.comac6b9792011-03-11 15:42:51 +00001104#include "SkColorPriv.h"
1105
bungeman@google.com63853142012-08-01 15:36:46 +00001106//Cannot assume that the input rgb is gray due to possible setting of kGenA8FromLCD_Flag.
bungeman@google.com97efada2012-07-30 20:40:50 +00001107template<bool APPLY_PREBLEND>
1108static inline uint8_t rgb_to_a8(SkGdiRGB rgb, const uint8_t* table8) {
bungeman@google.com63853142012-08-01 15:36:46 +00001109 U8CPU r = (rgb >> 16) & 0xFF;
1110 U8CPU g = (rgb >> 8) & 0xFF;
1111 U8CPU b = (rgb >> 0) & 0xFF;
bungeman@google.com1bfe01d2012-08-28 16:02:42 +00001112 return sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8);
reed@google.com8351aab2012-01-18 17:06:35 +00001113}
1114
bungeman@google.com97efada2012-07-30 20:40:50 +00001115template<bool APPLY_PREBLEND>
1116static inline uint16_t rgb_to_lcd16(SkGdiRGB rgb, const uint8_t* tableR,
1117 const uint8_t* tableG,
1118 const uint8_t* tableB) {
1119 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
1120 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG);
1121 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB);
bungeman@google.com0abbff92013-07-27 20:37:56 +00001122#if SK_SHOW_TEXT_BLIT_COVERAGE
1123 r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10);
1124#endif
bungeman@google.com97efada2012-07-30 20:40:50 +00001125 return SkPack888ToRGB16(r, g, b);
reed@google.com82a34d82011-07-26 19:33:08 +00001126}
1127
reed@google.com82cff022011-09-22 14:33:40 +00001128// Is this GDI color neither black nor white? If so, we have to keep this
1129// image as is, rather than smashing it down to a BW mask.
1130//
1131// returns int instead of bool, since we don't want/have to pay to convert
1132// the zero/non-zero value into a bool
1133static int is_not_black_or_white(SkGdiRGB c) {
1134 // same as (but faster than)
1135 // c &= 0x00FFFFFF;
1136 // return 0 == c || 0x00FFFFFF == c;
1137 return (c + (c & 1)) & 0x00FFFFFF;
reed@google.com5e2df642011-09-21 18:42:09 +00001138}
1139
bungeman@google.com4b18f572013-07-22 15:21:23 +00001140static bool is_rgb_really_bw(const SkGdiRGB* src, int width, int height, size_t srcRB) {
reed@google.com5e2df642011-09-21 18:42:09 +00001141 for (int y = 0; y < height; ++y) {
1142 for (int x = 0; x < width; ++x) {
reed@google.com82cff022011-09-22 14:33:40 +00001143 if (is_not_black_or_white(src[x])) {
reed@google.com5e2df642011-09-21 18:42:09 +00001144 return false;
1145 }
1146 }
bungeman@google.com05a729f2013-06-20 15:29:16 +00001147 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
reed@google.com5e2df642011-09-21 18:42:09 +00001148 }
1149 return true;
1150}
1151
bungeman@google.com97efada2012-07-30 20:40:50 +00001152// gdi's bitmap is upside-down, so we reverse dst walking in Y
1153// whenever we copy it into skia's buffer
reed@google.com5e2df642011-09-21 18:42:09 +00001154static void rgb_to_bw(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
bungeman@google.com97efada2012-07-30 20:40:50 +00001155 const SkGlyph& glyph) {
reed@google.com5e2df642011-09-21 18:42:09 +00001156 const int width = glyph.fWidth;
1157 const size_t dstRB = (width + 7) >> 3;
1158 uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1159
1160 int byteCount = width >> 3;
1161 int bitCount = width & 7;
1162
1163 // adjust srcRB to skip the values in our byteCount loop,
1164 // since we increment src locally there
1165 srcRB -= byteCount * 8 * sizeof(SkGdiRGB);
1166
1167 for (int y = 0; y < glyph.fHeight; ++y) {
1168 if (byteCount > 0) {
reed@google.com5e2df642011-09-21 18:42:09 +00001169 for (int i = 0; i < byteCount; ++i) {
reed@google.com7a230142011-09-27 14:07:21 +00001170 unsigned byte = 0;
bungeman@google.com97efada2012-07-30 20:40:50 +00001171 byte |= src[0] & (1 << 7);
1172 byte |= src[1] & (1 << 6);
1173 byte |= src[2] & (1 << 5);
1174 byte |= src[3] & (1 << 4);
1175 byte |= src[4] & (1 << 3);
1176 byte |= src[5] & (1 << 2);
1177 byte |= src[6] & (1 << 1);
1178 byte |= src[7] & (1 << 0);
reed@google.com6a8f14d2011-09-27 12:54:24 +00001179 dst[i] = byte;
reed@google.com5e2df642011-09-21 18:42:09 +00001180 src += 8;
1181 }
1182 }
1183 if (bitCount > 0) {
1184 unsigned byte = 0;
1185 unsigned mask = 0x80;
1186 for (int i = 0; i < bitCount; i++) {
bungeman@google.com97efada2012-07-30 20:40:50 +00001187 byte |= src[i] & mask;
reed@google.com5e2df642011-09-21 18:42:09 +00001188 mask >>= 1;
1189 }
1190 dst[byteCount] = byte;
1191 }
bungeman@google.com05a729f2013-06-20 15:29:16 +00001192 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
reed@google.com5e2df642011-09-21 18:42:09 +00001193 dst -= dstRB;
1194 }
bungeman@google.com0abbff92013-07-27 20:37:56 +00001195#if SK_SHOW_TEXT_BLIT_COVERAGE
1196 if (glyph.fWidth > 0 && glyph.fHeight > 0) {
1197 uint8_t* first = (uint8_t*)glyph.fImage;
1198 uint8_t* last = (uint8_t*)((char*)glyph.fImage + glyph.fHeight * dstRB - 1);
1199 *first |= 1 << 7;
1200 *last |= bitCount == 0 ? 1 : 1 << (8 - bitCount);
1201 }
1202#endif
reed@google.com5e2df642011-09-21 18:42:09 +00001203}
1204
bungeman@google.com97efada2012-07-30 20:40:50 +00001205template<bool APPLY_PREBLEND>
reed@google.com5e2df642011-09-21 18:42:09 +00001206static void rgb_to_a8(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
bungeman@google.com97efada2012-07-30 20:40:50 +00001207 const SkGlyph& glyph, const uint8_t* table8) {
reed@google.com5e2df642011-09-21 18:42:09 +00001208 const size_t dstRB = glyph.rowBytes();
1209 const int width = glyph.fWidth;
1210 uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1211
1212 for (int y = 0; y < glyph.fHeight; y++) {
1213 for (int i = 0; i < width; i++) {
bungeman@google.com97efada2012-07-30 20:40:50 +00001214 dst[i] = rgb_to_a8<APPLY_PREBLEND>(src[i], table8);
bungeman@google.com0abbff92013-07-27 20:37:56 +00001215#if SK_SHOW_TEXT_BLIT_COVERAGE
1216 dst[i] = SkMax32(dst[i], 10);
1217#endif
reed@google.com5e2df642011-09-21 18:42:09 +00001218 }
bungeman@google.com05a729f2013-06-20 15:29:16 +00001219 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
reed@google.com5e2df642011-09-21 18:42:09 +00001220 dst -= dstRB;
1221 }
1222}
1223
bungeman@google.com97efada2012-07-30 20:40:50 +00001224template<bool APPLY_PREBLEND>
1225static void rgb_to_lcd16(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph,
1226 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
reed@google.com5e2df642011-09-21 18:42:09 +00001227 const size_t dstRB = glyph.rowBytes();
1228 const int width = glyph.fWidth;
1229 uint16_t* SK_RESTRICT dst = (uint16_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1230
1231 for (int y = 0; y < glyph.fHeight; y++) {
1232 for (int i = 0; i < width; i++) {
bungeman@google.com97efada2012-07-30 20:40:50 +00001233 dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(src[i], tableR, tableG, tableB);
reed@google.com5e2df642011-09-21 18:42:09 +00001234 }
bungeman@google.com05a729f2013-06-20 15:29:16 +00001235 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
reed@google.com5e2df642011-09-21 18:42:09 +00001236 dst = (uint16_t*)((char*)dst - dstRB);
1237 }
1238}
1239
reed@google.com30ddd612013-07-30 17:47:39 +00001240void SkScalerContext_GDI::generateImage(const SkGlyph& glyph) {
reed@google.comac6b9792011-03-11 15:42:51 +00001241 SkASSERT(fDDC);
1242
reed@google.com62711172011-05-18 15:08:10 +00001243 const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat;
reed@google.com82a34d82011-07-26 19:33:08 +00001244 const bool isAA = !isLCD(fRec);
reed@google.comac6b9792011-03-11 15:42:51 +00001245
reed@google.com99edd432011-09-09 14:59:59 +00001246 size_t srcRB;
bungeman@google.com97efada2012-07-30 20:40:50 +00001247 const void* bits = fOffscreen.draw(glyph, isBW, &srcRB);
halcanary96fcdcc2015-08-27 07:41:13 -07001248 if (nullptr == bits) {
reed@google.com055180c2013-03-21 18:46:35 +00001249 LogFontTypeface::EnsureAccessible(this->getTypeface());
bungeman@google.com97efada2012-07-30 20:40:50 +00001250 bits = fOffscreen.draw(glyph, isBW, &srcRB);
halcanary96fcdcc2015-08-27 07:41:13 -07001251 if (nullptr == bits) {
bungeman@google.com39698b12011-11-15 22:26:41 +00001252 sk_bzero(glyph.fImage, glyph.computeImageSize());
1253 return;
1254 }
reed@google.com82a34d82011-07-26 19:33:08 +00001255 }
reed@google.comac6b9792011-03-11 15:42:51 +00001256
bungeman@google.com97efada2012-07-30 20:40:50 +00001257 if (!isBW) {
bungeman@google.com1bd2d672012-08-13 20:01:51 +00001258 const uint8_t* table;
1259 //The offscreen contains a GDI blit if isAA and kGenA8FromLCD_Flag is not set.
1260 //Otherwise the offscreen contains a ClearType blit.
1261 if (isAA && !(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag)) {
1262 table = getInverseGammaTableGDI();
1263 } else {
1264 table = getInverseGammaTableClearType();
bungeman@google.com97efada2012-07-30 20:40:50 +00001265 }
1266 //Note that the following cannot really be integrated into the
1267 //pre-blend, since we may not be applying the pre-blend; when we aren't
1268 //applying the pre-blend it means that a filter wants linear anyway.
1269 //Other code may also be applying the pre-blend, so we'd need another
1270 //one with this and one without.
reed@google.com6f5df482011-09-28 20:33:24 +00001271 SkGdiRGB* addr = (SkGdiRGB*)bits;
1272 for (int y = 0; y < glyph.fHeight; ++y) {
1273 for (int x = 0; x < glyph.fWidth; ++x) {
1274 int r = (addr[x] >> 16) & 0xFF;
1275 int g = (addr[x] >> 8) & 0xFF;
1276 int b = (addr[x] >> 0) & 0xFF;
reed@google.com7430a332011-10-03 14:37:38 +00001277 addr[x] = (table[r] << 16) | (table[g] << 8) | table[b];
reed@google.com6f5df482011-09-28 20:33:24 +00001278 }
bungeman@google.com05a729f2013-06-20 15:29:16 +00001279 addr = SkTAddOffset<SkGdiRGB>(addr, srcRB);
reed@google.com6f5df482011-09-28 20:33:24 +00001280 }
1281 }
1282
reed@google.com82a34d82011-07-26 19:33:08 +00001283 int width = glyph.fWidth;
1284 size_t dstRB = glyph.rowBytes();
1285 if (isBW) {
1286 const uint8_t* src = (const uint8_t*)bits;
reed@google.com82a34d82011-07-26 19:33:08 +00001287 uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1288 for (int y = 0; y < glyph.fHeight; y++) {
1289 memcpy(dst, src, dstRB);
1290 src += srcRB;
1291 dst -= dstRB;
reed@google.comac6b9792011-03-11 15:42:51 +00001292 }
bungeman@google.com0abbff92013-07-27 20:37:56 +00001293#if SK_SHOW_TEXT_BLIT_COVERAGE
1294 if (glyph.fWidth > 0 && glyph.fHeight > 0) {
1295 int bitCount = width & 7;
1296 uint8_t* first = (uint8_t*)glyph.fImage;
1297 uint8_t* last = (uint8_t*)((char*)glyph.fImage + glyph.fHeight * dstRB - 1);
1298 *first |= 1 << 7;
1299 *last |= bitCount == 0 ? 1 : 1 << (8 - bitCount);
1300 }
1301#endif
reed@google.com82a34d82011-07-26 19:33:08 +00001302 } else if (isAA) {
reed@google.com6f5df482011-09-28 20:33:24 +00001303 // since the caller may require A8 for maskfilters, we can't check for BW
1304 // ... until we have the caller tell us that explicitly
reed@google.com5e2df642011-09-21 18:42:09 +00001305 const SkGdiRGB* src = (const SkGdiRGB*)bits;
bungeman@google.coma76de722012-10-26 19:35:54 +00001306 if (fPreBlend.isApplicable()) {
1307 rgb_to_a8<true>(src, srcRB, glyph, fPreBlend.fG);
bungeman@google.com97efada2012-07-30 20:40:50 +00001308 } else {
bungeman@google.coma76de722012-10-26 19:35:54 +00001309 rgb_to_a8<false>(src, srcRB, glyph, fPreBlend.fG);
bungeman@google.com97efada2012-07-30 20:40:50 +00001310 }
reed@google.com82a34d82011-07-26 19:33:08 +00001311 } else { // LCD16
reed@google.com5e2df642011-09-21 18:42:09 +00001312 const SkGdiRGB* src = (const SkGdiRGB*)bits;
1313 if (is_rgb_really_bw(src, width, glyph.fHeight, srcRB)) {
bungeman@google.com97efada2012-07-30 20:40:50 +00001314 rgb_to_bw(src, srcRB, glyph);
reed@google.com5e2df642011-09-21 18:42:09 +00001315 ((SkGlyph*)&glyph)->fMaskFormat = SkMask::kBW_Format;
1316 } else {
reedd54d3fc2014-11-13 14:39:58 -08001317 SkASSERT(SkMask::kLCD16_Format == glyph.fMaskFormat);
1318 if (fPreBlend.isApplicable()) {
1319 rgb_to_lcd16<true>(src, srcRB, glyph,
1320 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
reed@google.com754e4eb2011-09-26 13:21:39 +00001321 } else {
reedd54d3fc2014-11-13 14:39:58 -08001322 rgb_to_lcd16<false>(src, srcRB, glyph,
1323 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
reed@google.com754e4eb2011-09-26 13:21:39 +00001324 }
reed@google.comac6b9792011-03-11 15:42:51 +00001325 }
1326 }
reed@google.comac6b9792011-03-11 15:42:51 +00001327}
1328
bungeman@google.com0abbff92013-07-27 20:37:56 +00001329class GDIGlyphbufferPointIter {
1330public:
skia.committer@gmail.com27e21fe2013-07-28 07:01:03 +00001331 GDIGlyphbufferPointIter(const uint8_t* glyphbuf, DWORD total_size)
bungeman@google.com0abbff92013-07-27 20:37:56 +00001332 : fHeaderIter(glyphbuf, total_size), fCurveIter(), fPointIter()
1333 { }
reed@google.comac6b9792011-03-11 15:42:51 +00001334
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001335 POINTFX const * next() {
bungeman@google.com0abbff92013-07-27 20:37:56 +00001336nextHeader:
1337 if (!fCurveIter.isSet()) {
1338 const TTPOLYGONHEADER* header = fHeaderIter.next();
halcanary96fcdcc2015-08-27 07:41:13 -07001339 if (nullptr == header) {
1340 return nullptr;
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001341 }
bungeman@google.com0abbff92013-07-27 20:37:56 +00001342 fCurveIter.set(header);
1343 const TTPOLYCURVE* curve = fCurveIter.next();
halcanary96fcdcc2015-08-27 07:41:13 -07001344 if (nullptr == curve) {
1345 return nullptr;
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001346 }
bungeman@google.com0abbff92013-07-27 20:37:56 +00001347 fPointIter.set(curve);
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001348 return &header->pfxStart;
bungeman@google.com05a729f2013-06-20 15:29:16 +00001349 }
1350
bungeman@google.com0abbff92013-07-27 20:37:56 +00001351 const POINTFX* nextPoint = fPointIter.next();
halcanary96fcdcc2015-08-27 07:41:13 -07001352 if (nullptr == nextPoint) {
bungeman@google.com0abbff92013-07-27 20:37:56 +00001353 const TTPOLYCURVE* curve = fCurveIter.next();
halcanary96fcdcc2015-08-27 07:41:13 -07001354 if (nullptr == curve) {
bungeman@google.com0abbff92013-07-27 20:37:56 +00001355 fCurveIter.set();
1356 goto nextHeader;
1357 } else {
1358 fPointIter.set(curve);
bungeman@google.com05a729f2013-06-20 15:29:16 +00001359 }
bungeman@google.com0abbff92013-07-27 20:37:56 +00001360 nextPoint = fPointIter.next();
reed@google.comac6b9792011-03-11 15:42:51 +00001361 }
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001362 return nextPoint;
reed@google.comac6b9792011-03-11 15:42:51 +00001363 }
bungeman@google.comd1c7f712013-03-11 18:51:19 +00001364
bungeman@google.com0abbff92013-07-27 20:37:56 +00001365 WORD currentCurveType() {
1366 return fPointIter.fCurveType;
1367 }
1368
1369private:
1370 /** Iterates over all of the polygon headers in a glyphbuf. */
1371 class GDIPolygonHeaderIter {
1372 public:
skia.committer@gmail.com27e21fe2013-07-28 07:01:03 +00001373 GDIPolygonHeaderIter(const uint8_t* glyphbuf, DWORD total_size)
bungeman@google.com0abbff92013-07-27 20:37:56 +00001374 : fCurPolygon(reinterpret_cast<const TTPOLYGONHEADER*>(glyphbuf))
1375 , fEndPolygon(SkTAddOffset<const TTPOLYGONHEADER>(glyphbuf, total_size))
1376 { }
1377
1378 const TTPOLYGONHEADER* next() {
1379 if (fCurPolygon >= fEndPolygon) {
halcanary96fcdcc2015-08-27 07:41:13 -07001380 return nullptr;
bungeman@google.com0abbff92013-07-27 20:37:56 +00001381 }
1382 const TTPOLYGONHEADER* thisPolygon = fCurPolygon;
1383 fCurPolygon = SkTAddOffset<const TTPOLYGONHEADER>(fCurPolygon, fCurPolygon->cb);
1384 return thisPolygon;
1385 }
1386 private:
1387 const TTPOLYGONHEADER* fCurPolygon;
1388 const TTPOLYGONHEADER* fEndPolygon;
1389 };
1390
1391 /** Iterates over all of the polygon curves in a polygon header. */
1392 class GDIPolygonCurveIter {
1393 public:
halcanary96fcdcc2015-08-27 07:41:13 -07001394 GDIPolygonCurveIter() : fCurCurve(nullptr), fEndCurve(nullptr) { }
bungeman@google.com0abbff92013-07-27 20:37:56 +00001395
1396 GDIPolygonCurveIter(const TTPOLYGONHEADER* curPolygon)
1397 : fCurCurve(SkTAddOffset<const TTPOLYCURVE>(curPolygon, sizeof(TTPOLYGONHEADER)))
1398 , fEndCurve(SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon->cb))
1399 { }
1400
halcanary96fcdcc2015-08-27 07:41:13 -07001401 bool isSet() { return fCurCurve != nullptr; }
bungeman@google.com0abbff92013-07-27 20:37:56 +00001402
1403 void set(const TTPOLYGONHEADER* curPolygon) {
1404 fCurCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon, sizeof(TTPOLYGONHEADER));
1405 fEndCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon->cb);
1406 }
1407 void set() {
halcanary96fcdcc2015-08-27 07:41:13 -07001408 fCurCurve = nullptr;
1409 fEndCurve = nullptr;
bungeman@google.com0abbff92013-07-27 20:37:56 +00001410 }
1411
1412 const TTPOLYCURVE* next() {
1413 if (fCurCurve >= fEndCurve) {
halcanary96fcdcc2015-08-27 07:41:13 -07001414 return nullptr;
bungeman@google.com0abbff92013-07-27 20:37:56 +00001415 }
1416 const TTPOLYCURVE* thisCurve = fCurCurve;
1417 fCurCurve = SkTAddOffset<const TTPOLYCURVE>(fCurCurve, size_of_TTPOLYCURVE(*fCurCurve));
1418 return thisCurve;
1419 }
1420 private:
1421 size_t size_of_TTPOLYCURVE(const TTPOLYCURVE& curve) {
1422 return 2*sizeof(WORD) + curve.cpfx*sizeof(POINTFX);
1423 }
1424 const TTPOLYCURVE* fCurCurve;
1425 const TTPOLYCURVE* fEndCurve;
1426 };
1427
1428 /** Iterates over all of the polygon points in a polygon curve. */
1429 class GDIPolygonCurvePointIter {
1430 public:
halcanary96fcdcc2015-08-27 07:41:13 -07001431 GDIPolygonCurvePointIter() : fCurveType(0), fCurPoint(nullptr), fEndPoint(nullptr) { }
bungeman@google.com0abbff92013-07-27 20:37:56 +00001432
1433 GDIPolygonCurvePointIter(const TTPOLYCURVE* curPolygon)
1434 : fCurveType(curPolygon->wType)
1435 , fCurPoint(&curPolygon->apfx[0])
1436 , fEndPoint(&curPolygon->apfx[curPolygon->cpfx])
1437 { }
1438
halcanary96fcdcc2015-08-27 07:41:13 -07001439 bool isSet() { return fCurPoint != nullptr; }
bungeman@google.com0abbff92013-07-27 20:37:56 +00001440
1441 void set(const TTPOLYCURVE* curPolygon) {
1442 fCurveType = curPolygon->wType;
1443 fCurPoint = &curPolygon->apfx[0];
1444 fEndPoint = &curPolygon->apfx[curPolygon->cpfx];
1445 }
1446 void set() {
halcanary96fcdcc2015-08-27 07:41:13 -07001447 fCurPoint = nullptr;
1448 fEndPoint = nullptr;
bungeman@google.com0abbff92013-07-27 20:37:56 +00001449 }
1450
1451 const POINTFX* next() {
1452 if (fCurPoint >= fEndPoint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001453 return nullptr;
bungeman@google.com0abbff92013-07-27 20:37:56 +00001454 }
1455 const POINTFX* thisPoint = fCurPoint;
1456 ++fCurPoint;
1457 return thisPoint;
1458 }
1459
1460 WORD fCurveType;
1461 private:
1462 const POINTFX* fCurPoint;
1463 const POINTFX* fEndPoint;
1464 };
1465
1466 GDIPolygonHeaderIter fHeaderIter;
1467 GDIPolygonCurveIter fCurveIter;
1468 GDIPolygonCurvePointIter fPointIter;
1469};
1470
1471static void sk_path_from_gdi_path(SkPath* path, const uint8_t* glyphbuf, DWORD total_size) {
bungeman@google.comd1c7f712013-03-11 18:51:19 +00001472 const uint8_t* cur_glyph = glyphbuf;
1473 const uint8_t* end_glyph = glyphbuf + total_size;
1474
1475 while (cur_glyph < end_glyph) {
1476 const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
1477
1478 const uint8_t* end_poly = cur_glyph + th->cb;
1479 const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
1480
1481 path->moveTo(SkFixedToScalar( SkFIXEDToFixed(th->pfxStart.x)),
1482 SkFixedToScalar(-SkFIXEDToFixed(th->pfxStart.y)));
1483
1484 while (cur_poly < end_poly) {
1485 const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
1486
1487 if (pc->wType == TT_PRIM_LINE) {
1488 for (uint16_t i = 0; i < pc->cpfx; i++) {
1489 path->lineTo(SkFixedToScalar( SkFIXEDToFixed(pc->apfx[i].x)),
1490 SkFixedToScalar(-SkFIXEDToFixed(pc->apfx[i].y)));
1491 }
1492 }
1493
1494 if (pc->wType == TT_PRIM_QSPLINE) {
1495 for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline
1496 POINTFX pnt_b = pc->apfx[u]; // B is always the current point
1497 POINTFX pnt_c = pc->apfx[u+1];
1498
1499 if (u < pc->cpfx - 2) { // If not on last spline, compute C
1500 pnt_c.x = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.x),
1501 SkFIXEDToFixed(pnt_c.x)));
1502 pnt_c.y = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.y),
1503 SkFIXEDToFixed(pnt_c.y)));
1504 }
1505
1506 path->quadTo(SkFixedToScalar( SkFIXEDToFixed(pnt_b.x)),
1507 SkFixedToScalar(-SkFIXEDToFixed(pnt_b.y)),
1508 SkFixedToScalar( SkFIXEDToFixed(pnt_c.x)),
1509 SkFixedToScalar(-SkFIXEDToFixed(pnt_c.y)));
1510 }
1511 }
1512 // Advance past this TTPOLYCURVE.
1513 cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx;
1514 }
1515 cur_glyph += th->cb;
1516 path->close();
reed@google.comac6b9792011-03-11 15:42:51 +00001517 }
reed@google.comac6b9792011-03-11 15:42:51 +00001518}
1519
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001520#define move_next_expected_hinted_point(iter, pElem) do {\
1521 pElem = iter.next(); \
halcanary96fcdcc2015-08-27 07:41:13 -07001522 if (nullptr == pElem) return false; \
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001523} while(0)
1524
1525// It is possible for the hinted and unhinted versions of the same path to have
1526// a different number of points due to GDI's handling of flipped points.
1527// If this is detected, this will return false.
1528static bool sk_path_from_gdi_paths(SkPath* path, const uint8_t* glyphbuf, DWORD total_size,
bungeman@google.com0abbff92013-07-27 20:37:56 +00001529 GDIGlyphbufferPointIter hintedYs) {
1530 const uint8_t* cur_glyph = glyphbuf;
1531 const uint8_t* end_glyph = glyphbuf + total_size;
1532
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001533 POINTFX const * hintedPoint;
1534
bungeman@google.com0abbff92013-07-27 20:37:56 +00001535 while (cur_glyph < end_glyph) {
1536 const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
1537
1538 const uint8_t* end_poly = cur_glyph + th->cb;
1539 const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
1540
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001541 move_next_expected_hinted_point(hintedYs, hintedPoint);
bungeman@google.com0abbff92013-07-27 20:37:56 +00001542 path->moveTo(SkFixedToScalar( SkFIXEDToFixed(th->pfxStart.x)),
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001543 SkFixedToScalar(-SkFIXEDToFixed(hintedPoint->y)));
bungeman@google.com0abbff92013-07-27 20:37:56 +00001544
1545 while (cur_poly < end_poly) {
1546 const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
1547
1548 if (pc->wType == TT_PRIM_LINE) {
1549 for (uint16_t i = 0; i < pc->cpfx; i++) {
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001550 move_next_expected_hinted_point(hintedYs, hintedPoint);
bungeman@google.com0abbff92013-07-27 20:37:56 +00001551 path->lineTo(SkFixedToScalar( SkFIXEDToFixed(pc->apfx[i].x)),
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001552 SkFixedToScalar(-SkFIXEDToFixed(hintedPoint->y)));
bungeman@google.com0abbff92013-07-27 20:37:56 +00001553 }
1554 }
1555
1556 if (pc->wType == TT_PRIM_QSPLINE) {
1557 POINTFX currentPoint = pc->apfx[0];
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001558 move_next_expected_hinted_point(hintedYs, hintedPoint);
bungeman@google.com0abbff92013-07-27 20:37:56 +00001559 // only take the hinted y if it wasn't flipped
1560 if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) {
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001561 currentPoint.y = hintedPoint->y;
bungeman@google.com0abbff92013-07-27 20:37:56 +00001562 }
1563 for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline
1564 POINTFX pnt_b = currentPoint;//pc->apfx[u]; // B is always the current point
1565 POINTFX pnt_c = pc->apfx[u+1];
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001566 move_next_expected_hinted_point(hintedYs, hintedPoint);
bungeman@google.com0abbff92013-07-27 20:37:56 +00001567 // only take the hinted y if it wasn't flipped
1568 if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) {
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001569 pnt_c.y = hintedPoint->y;
bungeman@google.com0abbff92013-07-27 20:37:56 +00001570 }
1571 currentPoint.x = pnt_c.x;
1572 currentPoint.y = pnt_c.y;
1573
1574 if (u < pc->cpfx - 2) { // If not on last spline, compute C
1575 pnt_c.x = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.x),
1576 SkFIXEDToFixed(pnt_c.x)));
1577 pnt_c.y = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.y),
1578 SkFIXEDToFixed(pnt_c.y)));
1579 }
1580
1581 path->quadTo(SkFixedToScalar( SkFIXEDToFixed(pnt_b.x)),
1582 SkFixedToScalar(-SkFIXEDToFixed(pnt_b.y)),
1583 SkFixedToScalar( SkFIXEDToFixed(pnt_c.x)),
1584 SkFixedToScalar(-SkFIXEDToFixed(pnt_c.y)));
1585 }
1586 }
1587 // Advance past this TTPOLYCURVE.
1588 cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx;
1589 }
1590 cur_glyph += th->cb;
1591 path->close();
1592 }
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001593 return true;
bungeman@google.com0abbff92013-07-27 20:37:56 +00001594}
1595
Ben Wagner6e9ac122016-11-11 14:31:06 -05001596DWORD SkScalerContext_GDI::getGDIGlyphPath(SkGlyphID glyph, UINT flags,
1597 SkAutoSTMalloc<BUFFERSIZE, uint8_t>* glyphbuf)
bungeman@google.com0abbff92013-07-27 20:37:56 +00001598{
1599 GLYPHMETRICS gm;
1600
Ben Wagner6e9ac122016-11-11 14:31:06 -05001601 DWORD total_size = GetGlyphOutlineW(fDDC, glyph, flags, &gm, BUFFERSIZE, glyphbuf->get(), &fMat22);
bungeman@google.com0abbff92013-07-27 20:37:56 +00001602 // Sometimes GetGlyphOutlineW returns a number larger than BUFFERSIZE even if BUFFERSIZE > 0.
1603 // It has been verified that this does not involve a buffer overrun.
1604 if (GDI_ERROR == total_size || total_size > BUFFERSIZE) {
1605 // GDI_ERROR because the BUFFERSIZE was too small, or because the data was not accessible.
1606 // When the data is not accessable GetGlyphOutlineW fails rather quickly,
1607 // so just try to get the size. If that fails then ensure the data is accessible.
Ben Wagner6e9ac122016-11-11 14:31:06 -05001608 total_size = GetGlyphOutlineW(fDDC, glyph, flags, &gm, 0, nullptr, &fMat22);
bungeman@google.com0abbff92013-07-27 20:37:56 +00001609 if (GDI_ERROR == total_size) {
1610 LogFontTypeface::EnsureAccessible(this->getTypeface());
Ben Wagner6e9ac122016-11-11 14:31:06 -05001611 total_size = GetGlyphOutlineW(fDDC, glyph, flags, &gm, 0, nullptr, &fMat22);
bungeman@google.com0abbff92013-07-27 20:37:56 +00001612 if (GDI_ERROR == total_size) {
kkinnunenc6cb56f2014-06-24 00:12:27 -07001613 // GetGlyphOutlineW is known to fail for some characters, such as spaces.
1614 // In these cases, just return that the glyph does not have a shape.
bungeman@google.com0abbff92013-07-27 20:37:56 +00001615 return 0;
1616 }
1617 }
1618
1619 glyphbuf->reset(total_size);
1620
Ben Wagner6e9ac122016-11-11 14:31:06 -05001621 DWORD ret = GetGlyphOutlineW(fDDC, glyph, flags, &gm, total_size, glyphbuf->get(), &fMat22);
bungeman@google.com0abbff92013-07-27 20:37:56 +00001622 if (GDI_ERROR == ret) {
1623 LogFontTypeface::EnsureAccessible(this->getTypeface());
Ben Wagner6e9ac122016-11-11 14:31:06 -05001624 ret = GetGlyphOutlineW(fDDC, glyph, flags, &gm, total_size, glyphbuf->get(), &fMat22);
bungeman@google.com0abbff92013-07-27 20:37:56 +00001625 if (GDI_ERROR == ret) {
1626 SkASSERT(false);
1627 return 0;
1628 }
1629 }
1630 }
1631 return total_size;
1632}
1633
Ben Wagner6e9ac122016-11-11 14:31:06 -05001634void SkScalerContext_GDI::generatePath(SkGlyphID glyph, SkPath* path) {
dcheng3ba043f2015-07-08 13:25:23 -07001635 SkASSERT(path);
bungeman@google.com0abbff92013-07-27 20:37:56 +00001636 SkASSERT(fDDC);
1637
1638 path->reset();
1639
1640 // Out of all the fonts on a typical Windows box,
1641 // 25% of glyphs require more than 2KB.
1642 // 1% of glyphs require more than 4KB.
1643 // 0.01% of glyphs require more than 8KB.
1644 // 8KB is less than 1% of the normal 1MB stack on Windows.
1645 // Note that some web fonts glyphs require more than 20KB.
1646 //static const DWORD BUFFERSIZE = (1 << 13);
1647
1648 //GDI only uses hinted outlines when axis aligned.
1649 UINT format = GGO_NATIVE | GGO_GLYPH_INDEX;
1650 if (fRec.getHinting() == SkPaint::kNo_Hinting || fRec.getHinting() == SkPaint::kSlight_Hinting){
1651 format |= GGO_UNHINTED;
1652 }
1653 SkAutoSTMalloc<BUFFERSIZE, uint8_t> glyphbuf(BUFFERSIZE);
1654 DWORD total_size = getGDIGlyphPath(glyph, format, &glyphbuf);
1655 if (0 == total_size) {
1656 return;
1657 }
1658
1659 if (fRec.getHinting() != SkPaint::kSlight_Hinting) {
1660 sk_path_from_gdi_path(path, glyphbuf, total_size);
1661 } else {
1662 //GDI only uses hinted outlines when axis aligned.
1663 UINT format = GGO_NATIVE | GGO_GLYPH_INDEX;
1664
1665 SkAutoSTMalloc<BUFFERSIZE, uint8_t> hintedGlyphbuf(BUFFERSIZE);
1666 DWORD hinted_total_size = getGDIGlyphPath(glyph, format, &hintedGlyphbuf);
1667 if (0 == hinted_total_size) {
1668 return;
1669 }
1670
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001671 if (!sk_path_from_gdi_paths(path, glyphbuf, total_size,
1672 GDIGlyphbufferPointIter(hintedGlyphbuf, hinted_total_size)))
1673 {
1674 path->reset();
1675 sk_path_from_gdi_path(path, glyphbuf, total_size);
1676 }
bungeman@google.com0abbff92013-07-27 20:37:56 +00001677 }
1678}
1679
reed@google.com484f5bc2013-04-24 19:14:56 +00001680static void logfont_for_name(const char* familyName, LOGFONT* lf) {
1681 sk_bzero(lf, sizeof(LOGFONT));
bungeman@google.come70f7982012-06-01 19:38:19 +00001682#ifdef UNICODE
reed@google.com484f5bc2013-04-24 19:14:56 +00001683 // Get the buffer size needed first.
1684 size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName,
halcanary96fcdcc2015-08-27 07:41:13 -07001685 -1, nullptr, 0);
reed@google.com484f5bc2013-04-24 19:14:56 +00001686 // Allocate a buffer (str_len already has terminating null
1687 // accounted for).
1688 wchar_t *wideFamilyName = new wchar_t[str_len];
1689 // Now actually convert the string.
1690 ::MultiByteToWideChar(CP_UTF8, 0, familyName, -1,
1691 wideFamilyName, str_len);
1692 ::wcsncpy(lf->lfFaceName, wideFamilyName, LF_FACESIZE - 1);
1693 delete [] wideFamilyName;
1694 lf->lfFaceName[LF_FACESIZE-1] = L'\0';
bungeman@google.come70f7982012-06-01 19:38:19 +00001695#else
reed@google.com484f5bc2013-04-24 19:14:56 +00001696 ::strncpy(lf->lfFaceName, familyName, LF_FACESIZE - 1);
1697 lf->lfFaceName[LF_FACESIZE - 1] = '\0';
bungeman@google.come70f7982012-06-01 19:38:19 +00001698#endif
1699}
1700
bungemanb374d6a2014-09-17 07:48:59 -07001701void LogFontTypeface::onGetFamilyName(SkString* familyName) const {
bungeman@google.com7103f182012-10-31 20:53:49 +00001702 // Get the actual name of the typeface. The logfont may not know this.
reed@google.com5526ede2013-03-25 13:03:37 +00001703 HFONT font = CreateFontIndirect(&fLogFont);
bungeman@google.com7103f182012-10-31 20:53:49 +00001704
halcanary96fcdcc2015-08-27 07:41:13 -07001705 HDC deviceContext = ::CreateCompatibleDC(nullptr);
bungeman@google.com7103f182012-10-31 20:53:49 +00001706 HFONT savefont = (HFONT)SelectObject(deviceContext, font);
1707
bungemanb374d6a2014-09-17 07:48:59 -07001708 dcfontname_to_skstring(deviceContext, fLogFont, familyName);
bungeman@google.com7103f182012-10-31 20:53:49 +00001709
1710 if (deviceContext) {
1711 ::SelectObject(deviceContext, savefont);
1712 ::DeleteDC(deviceContext);
1713 }
1714 if (font) {
1715 ::DeleteObject(font);
1716 }
bungemanb374d6a2014-09-17 07:48:59 -07001717}
bungeman@google.com7103f182012-10-31 20:53:49 +00001718
bungemanb374d6a2014-09-17 07:48:59 -07001719void LogFontTypeface::onGetFontDescriptor(SkFontDescriptor* desc,
1720 bool* isLocalStream) const {
1721 SkString familyName;
1722 this->onGetFamilyName(&familyName);
reed@google.com5526ede2013-03-25 13:03:37 +00001723 desc->setFamilyName(familyName.c_str());
bungemanb8113782016-07-25 16:54:59 -07001724 desc->setStyle(this->fontStyle());
reed@google.com5526ede2013-03-25 13:03:37 +00001725 *isLocalStream = this->fSerializeAsStream;
reed@google.comac6b9792011-03-11 15:42:51 +00001726}
1727
reed@google.com2689f612013-03-20 20:01:47 +00001728SkAdvancedTypefaceMetrics* LogFontTypeface::onGetAdvancedTypefaceMetrics(
reed39a9a502015-05-12 09:50:04 -07001729 PerGlyphInfo perGlyphInfo,
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +00001730 const uint32_t* glyphIDs,
reed@google.com2689f612013-03-20 20:01:47 +00001731 uint32_t glyphIDsCount) const {
1732 LOGFONT lf = fLogFont;
halcanary96fcdcc2015-08-27 07:41:13 -07001733 SkAdvancedTypefaceMetrics* info = nullptr;
reed@google.comac6b9792011-03-11 15:42:51 +00001734
halcanary96fcdcc2015-08-27 07:41:13 -07001735 HDC hdc = CreateCompatibleDC(nullptr);
reed@google.comac6b9792011-03-11 15:42:51 +00001736 HFONT font = CreateFontIndirect(&lf);
1737 HFONT savefont = (HFONT)SelectObject(hdc, font);
halcanary96fcdcc2015-08-27 07:41:13 -07001738 HFONT designFont = nullptr;
reed@google.comac6b9792011-03-11 15:42:51 +00001739
reed@google.com05b6f3a2011-11-28 15:30:28 +00001740 const char stem_chars[] = {'i', 'I', '!', '1'};
1741 int16_t min_width;
1742 unsigned glyphCount;
1743
reed@google.comac6b9792011-03-11 15:42:51 +00001744 // To request design units, create a logical font whose height is specified
1745 // as unitsPerEm.
1746 OUTLINETEXTMETRIC otm;
bungeman@google.com39698b12011-11-15 22:26:41 +00001747 unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
1748 if (0 == otmRet) {
reed@google.com055180c2013-03-21 18:46:35 +00001749 call_ensure_accessible(lf);
bungeman@google.com39698b12011-11-15 22:26:41 +00001750 otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
1751 }
1752 if (!otmRet || !GetTextFace(hdc, LF_FACESIZE, lf.lfFaceName)) {
reed@google.comac6b9792011-03-11 15:42:51 +00001753 goto Error;
1754 }
1755 lf.lfHeight = -SkToS32(otm.otmEMSquare);
1756 designFont = CreateFontIndirect(&lf);
1757 SelectObject(hdc, designFont);
1758 if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm)) {
1759 goto Error;
1760 }
bungeman@google.com7bdd6142013-07-15 19:42:57 +00001761 glyphCount = calculateGlyphCount(hdc, fLogFont);
reed@google.comac6b9792011-03-11 15:42:51 +00001762
1763 info = new SkAdvancedTypefaceMetrics;
bungeman@google.com7103f182012-10-31 20:53:49 +00001764 tchar_to_skstring(lf.lfFaceName, &info->fFontName);
vandebo0f9bad02014-06-19 11:05:39 -07001765 // If bit 1 is set, the font may not be embedded in a document.
1766 // If bit 1 is clear, the font can be embedded.
1767 // If bit 2 is set, the embedding is read-only.
1768 if (otm.otmfsType & 0x1) {
halcanary32875882016-08-16 09:36:23 -07001769 info->fFlags |= SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag;
vandebo0f9bad02014-06-19 11:05:39 -07001770 }
reed@google.comac6b9792011-03-11 15:42:51 +00001771
reed39a9a502015-05-12 09:50:04 -07001772 if (perGlyphInfo & kToUnicode_PerGlyphInfo) {
vandebo@chromium.org6744d492011-05-09 18:13:47 +00001773 populate_glyph_to_unicode(hdc, glyphCount, &(info->fGlyphToUnicode));
1774 }
1775
vandebo@chromium.orgd41e70d2012-03-08 19:41:01 +00001776 if (glyphCount > 0 &&
1777 (otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE)) {
reed@google.comac6b9792011-03-11 15:42:51 +00001778 info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
1779 } else {
edisonn@google.com390c6d72013-04-06 20:26:15 +00001780 goto ReturnInfo;
reed@google.comac6b9792011-03-11 15:42:51 +00001781 }
ctguil@chromium.org5aa937b2011-08-04 01:01:24 +00001782
reed@google.comac6b9792011-03-11 15:42:51 +00001783 // If this bit is clear the font is a fixed pitch font.
1784 if (!(otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
1785 info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
1786 }
1787 if (otm.otmTextMetrics.tmItalic) {
1788 info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
1789 }
reed@google.comac6b9792011-03-11 15:42:51 +00001790 if (otm.otmTextMetrics.tmPitchAndFamily & FF_ROMAN) {
1791 info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
1792 } else if (otm.otmTextMetrics.tmPitchAndFamily & FF_SCRIPT) {
1793 info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
1794 }
1795
1796 // The main italic angle of the font, in tenths of a degree counterclockwise
1797 // from vertical.
1798 info->fItalicAngle = otm.otmItalicAngle / 10;
1799 info->fAscent = SkToS16(otm.otmTextMetrics.tmAscent);
1800 info->fDescent = SkToS16(-otm.otmTextMetrics.tmDescent);
1801 // TODO(ctguil): Use alternate cap height calculation.
1802 // MSDN says otmsCapEmHeight is not support but it is returning a value on
1803 // my Win7 box.
1804 info->fCapHeight = otm.otmsCapEmHeight;
1805 info->fBBox =
1806 SkIRect::MakeLTRB(otm.otmrcFontBox.left, otm.otmrcFontBox.top,
1807 otm.otmrcFontBox.right, otm.otmrcFontBox.bottom);
1808
1809 // Figure out a good guess for StemV - Min width of i, I, !, 1.
1810 // This probably isn't very good with an italic font.
reed@google.com05b6f3a2011-11-28 15:30:28 +00001811 min_width = SHRT_MAX;
reed@google.comac6b9792011-03-11 15:42:51 +00001812 info->fStemV = 0;
reed@google.comac6b9792011-03-11 15:42:51 +00001813 for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) {
1814 ABC abcWidths;
1815 if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) {
1816 int16_t width = abcWidths.abcB;
1817 if (width > 0 && width < min_width) {
1818 min_width = width;
1819 info->fStemV = min_width;
1820 }
1821 }
1822 }
1823
reed@google.comac6b9792011-03-11 15:42:51 +00001824Error:
edisonn@google.com390c6d72013-04-06 20:26:15 +00001825ReturnInfo:
reed@google.comac6b9792011-03-11 15:42:51 +00001826 SelectObject(hdc, savefont);
1827 DeleteObject(designFont);
1828 DeleteObject(font);
1829 DeleteDC(hdc);
1830
1831 return info;
1832}
1833
bungeman@google.coma5501992012-05-18 19:06:41 +00001834//Dummy representation of a Base64 encoded GUID from create_unique_font_name.
1835#define BASE64_GUID_ID "XXXXXXXXXXXXXXXXXXXXXXXX"
halcanary96fcdcc2015-08-27 07:41:13 -07001836//Length of GUID representation from create_id, including nullptr terminator.
bungeman@google.coma5501992012-05-18 19:06:41 +00001837#define BASE64_GUID_ID_LEN SK_ARRAY_COUNT(BASE64_GUID_ID)
reed@google.comac6b9792011-03-11 15:42:51 +00001838
bungeman99fe8222015-08-20 07:57:51 -07001839static_assert(BASE64_GUID_ID_LEN < LF_FACESIZE, "GUID_longer_than_facesize");
bungeman@google.coma5501992012-05-18 19:06:41 +00001840
1841/**
1842 NameID 6 Postscript names cannot have the character '/'.
1843 It would be easier to hex encode the GUID, but that is 32 bytes,
1844 and many systems have issues with names longer than 28 bytes.
1845 The following need not be any standard base64 encoding.
1846 The encoded value is never decoded.
1847*/
rmistry@google.comd6176b02012-08-23 18:14:13 +00001848static const char postscript_safe_base64_encode[] =
bungeman@google.coma5501992012-05-18 19:06:41 +00001849 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1850 "abcdefghijklmnopqrstuvwxyz"
1851 "0123456789-_=";
1852
1853/**
1854 Formats a GUID into Base64 and places it into buffer.
1855 buffer should have space for at least BASE64_GUID_ID_LEN characters.
1856 The string will always be null terminated.
1857 XXXXXXXXXXXXXXXXXXXXXXXX0
1858 */
1859static void format_guid_b64(const GUID& guid, char* buffer, size_t bufferSize) {
1860 SkASSERT(bufferSize >= BASE64_GUID_ID_LEN);
1861 size_t written = SkBase64::Encode(&guid, sizeof(guid), buffer, postscript_safe_base64_encode);
1862 SkASSERT(written < LF_FACESIZE);
1863 buffer[written] = '\0';
1864}
1865
1866/**
1867 Creates a Base64 encoded GUID and places it into buffer.
1868 buffer should have space for at least BASE64_GUID_ID_LEN characters.
1869 The string will always be null terminated.
1870 XXXXXXXXXXXXXXXXXXXXXXXX0
1871 */
1872static HRESULT create_unique_font_name(char* buffer, size_t bufferSize) {
1873 GUID guid = {};
1874 if (FAILED(CoCreateGuid(&guid))) {
1875 return E_UNEXPECTED;
1876 }
1877 format_guid_b64(guid, buffer, bufferSize);
1878
1879 return S_OK;
1880}
1881
1882/**
halcanary96fcdcc2015-08-27 07:41:13 -07001883 Introduces a font to GDI. On failure will return nullptr. The returned handle
bungeman@google.coma5501992012-05-18 19:06:41 +00001884 should eventually be passed to RemoveFontMemResourceEx.
1885*/
1886static HANDLE activate_font(SkData* fontData) {
1887 DWORD numFonts = 0;
1888 //AddFontMemResourceEx just copies the data, but does not specify const.
1889 HANDLE fontHandle = AddFontMemResourceEx(const_cast<void*>(fontData->data()),
bungeman@google.com4b18f572013-07-22 15:21:23 +00001890 static_cast<DWORD>(fontData->size()),
bungeman@google.coma5501992012-05-18 19:06:41 +00001891 0,
1892 &numFonts);
1893
halcanary96fcdcc2015-08-27 07:41:13 -07001894 if (fontHandle != nullptr && numFonts < 1) {
bungeman@google.coma5501992012-05-18 19:06:41 +00001895 RemoveFontMemResourceEx(fontHandle);
halcanary96fcdcc2015-08-27 07:41:13 -07001896 return nullptr;
bungeman@google.coma5501992012-05-18 19:06:41 +00001897 }
1898
1899 return fontHandle;
1900}
1901
scroggoa1193e42015-01-21 12:09:53 -08001902// Does not affect ownership of stream.
bungeman5f213d92015-01-27 05:39:10 -08001903static SkTypeface* create_from_stream(SkStreamAsset* stream) {
bungeman@google.coma5501992012-05-18 19:06:41 +00001904 // Create a unique and unpredictable font name.
1905 // Avoids collisions and access from CSS.
1906 char familyName[BASE64_GUID_ID_LEN];
1907 const int familyNameSize = SK_ARRAY_COUNT(familyName);
1908 if (FAILED(create_unique_font_name(familyName, familyNameSize))) {
halcanary96fcdcc2015-08-27 07:41:13 -07001909 return nullptr;
bungeman@google.coma5501992012-05-18 19:06:41 +00001910 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001911
bungeman@google.coma5501992012-05-18 19:06:41 +00001912 // Change the name of the font.
bungemanffae30d2016-08-03 13:32:32 -07001913 sk_sp<SkData> rewrittenFontData(SkOTUtils::RenameFont(stream, familyName, familyNameSize-1));
halcanary96fcdcc2015-08-27 07:41:13 -07001914 if (nullptr == rewrittenFontData.get()) {
1915 return nullptr;
bungeman@google.coma5501992012-05-18 19:06:41 +00001916 }
bungeman@google.coma5501992012-05-18 19:06:41 +00001917
1918 // Register the font with GDI.
bungeman@google.come9bbee32012-05-21 13:46:13 +00001919 HANDLE fontReference = activate_font(rewrittenFontData.get());
halcanary96fcdcc2015-08-27 07:41:13 -07001920 if (nullptr == fontReference) {
1921 return nullptr;
bungeman@google.coma5501992012-05-18 19:06:41 +00001922 }
1923
1924 // Create the typeface.
1925 LOGFONT lf;
reed@google.com484f5bc2013-04-24 19:14:56 +00001926 logfont_for_name(familyName, &lf);
bungeman@google.coma5501992012-05-18 19:06:41 +00001927
1928 return SkCreateFontMemResourceTypefaceFromLOGFONT(lf, fontReference);
reed@google.comac6b9792011-03-11 15:42:51 +00001929}
1930
bungeman5f213d92015-01-27 05:39:10 -08001931SkStreamAsset* LogFontTypeface::onOpenStream(int* ttcIndex) const {
reed@google.com0042b9c2013-03-21 20:16:04 +00001932 *ttcIndex = 0;
1933
ctguil@chromium.orgf4c26222011-05-16 22:00:05 +00001934 const DWORD kTTCTag =
1935 SkEndian_SwapBE32(SkSetFourByteTag('t', 't', 'c', 'f'));
reed@google.com0042b9c2013-03-21 20:16:04 +00001936 LOGFONT lf = fLogFont;
reed@google.comac6b9792011-03-11 15:42:51 +00001937
halcanary96fcdcc2015-08-27 07:41:13 -07001938 HDC hdc = ::CreateCompatibleDC(nullptr);
reed@google.com59d2f632011-05-02 19:36:59 +00001939 HFONT font = CreateFontIndirect(&lf);
reed@google.comac6b9792011-03-11 15:42:51 +00001940 HFONT savefont = (HFONT)SelectObject(hdc, font);
1941
halcanary96fcdcc2015-08-27 07:41:13 -07001942 SkMemoryStream* stream = nullptr;
vandebo@chromium.orgd6044812011-05-13 03:41:29 +00001943 DWORD tables[2] = {kTTCTag, 0};
1944 for (int i = 0; i < SK_ARRAY_COUNT(tables); i++) {
halcanary96fcdcc2015-08-27 07:41:13 -07001945 DWORD bufferSize = GetFontData(hdc, tables[i], 0, nullptr, 0);
bungeman@google.com39698b12011-11-15 22:26:41 +00001946 if (bufferSize == GDI_ERROR) {
reed@google.com055180c2013-03-21 18:46:35 +00001947 call_ensure_accessible(lf);
halcanary96fcdcc2015-08-27 07:41:13 -07001948 bufferSize = GetFontData(hdc, tables[i], 0, nullptr, 0);
bungeman@google.com39698b12011-11-15 22:26:41 +00001949 }
vandebo@chromium.orgd6044812011-05-13 03:41:29 +00001950 if (bufferSize != GDI_ERROR) {
1951 stream = new SkMemoryStream(bufferSize);
bungeman@google.com4b18f572013-07-22 15:21:23 +00001952 if (GetFontData(hdc, tables[i], 0, (void*)stream->getMemoryBase(), bufferSize)) {
vandebo@chromium.orgd6044812011-05-13 03:41:29 +00001953 break;
1954 } else {
1955 delete stream;
halcanary96fcdcc2015-08-27 07:41:13 -07001956 stream = nullptr;
vandebo@chromium.orgd6044812011-05-13 03:41:29 +00001957 }
1958 }
reed@google.comac6b9792011-03-11 15:42:51 +00001959 }
1960
1961 SelectObject(hdc, savefont);
1962 DeleteObject(font);
1963 DeleteDC(hdc);
1964
1965 return stream;
1966}
1967
bungeman@google.com3c996f82013-10-24 21:39:35 +00001968static void bmpCharsToGlyphs(HDC hdc, const WCHAR* bmpChars, int count, uint16_t* glyphs,
1969 bool Ox1FHack)
1970{
1971 DWORD result = GetGlyphIndicesW(hdc, bmpChars, count, glyphs, GGI_MARK_NONEXISTING_GLYPHS);
1972 if (GDI_ERROR == result) {
1973 for (int i = 0; i < count; ++i) {
1974 glyphs[i] = 0;
1975 }
1976 return;
1977 }
1978
1979 if (Ox1FHack) {
1980 for (int i = 0; i < count; ++i) {
1981 if (0xFFFF == glyphs[i] || 0x1F == glyphs[i]) {
1982 glyphs[i] = 0;
1983 }
1984 }
1985 } else {
1986 for (int i = 0; i < count; ++i) {
1987 if (0xFFFF == glyphs[i]){
1988 glyphs[i] = 0;
1989 }
1990 }
1991 }
1992}
1993
1994static uint16_t nonBmpCharToGlyph(HDC hdc, SCRIPT_CACHE* scriptCache, const WCHAR utf16[2]) {
1995 uint16_t index = 0;
1996 // Use uniscribe to detemine glyph index for non-BMP characters.
1997 static const int numWCHAR = 2;
1998 static const int maxItems = 2;
halcanary96fcdcc2015-08-27 07:41:13 -07001999 // MSDN states that this can be nullptr, but some things don't work then.
bungeman@google.com3c996f82013-10-24 21:39:35 +00002000 SCRIPT_CONTROL scriptControl = { 0 };
2001 // Add extra item to SCRIPT_ITEM to work around a bug (now documented).
2002 // https://bugzilla.mozilla.org/show_bug.cgi?id=366643
2003 SCRIPT_ITEM si[maxItems + 1];
2004 int numItems;
halcanary96fcdcc2015-08-27 07:41:13 -07002005 HRZM(ScriptItemize(utf16, numWCHAR, maxItems, &scriptControl, nullptr, si, &numItems),
bungeman@google.com3c996f82013-10-24 21:39:35 +00002006 "Could not itemize character.");
2007
2008 // Sometimes ScriptShape cannot find a glyph for a non-BMP and returns 2 space glyphs.
2009 static const int maxGlyphs = 2;
2010 SCRIPT_VISATTR vsa[maxGlyphs];
2011 WORD outGlyphs[maxGlyphs];
2012 WORD logClust[numWCHAR];
2013 int numGlyphs;
2014 HRZM(ScriptShape(hdc, scriptCache, utf16, numWCHAR, maxGlyphs, &si[0].a,
2015 outGlyphs, logClust, vsa, &numGlyphs),
2016 "Could not shape character.");
2017 if (1 == numGlyphs) {
2018 index = outGlyphs[0];
2019 }
2020 return index;
2021}
2022
2023class SkAutoHDC {
2024public:
2025 SkAutoHDC(const LOGFONT& lf)
halcanary96fcdcc2015-08-27 07:41:13 -07002026 : fHdc(::CreateCompatibleDC(nullptr))
bungeman@google.com3c996f82013-10-24 21:39:35 +00002027 , fFont(::CreateFontIndirect(&lf))
2028 , fSavefont((HFONT)SelectObject(fHdc, fFont))
2029 { }
2030 ~SkAutoHDC() {
2031 SelectObject(fHdc, fSavefont);
2032 DeleteObject(fFont);
2033 DeleteDC(fHdc);
2034 }
2035 operator HDC() { return fHdc; }
2036private:
2037 HDC fHdc;
2038 HFONT fFont;
2039 HFONT fSavefont;
2040};
commit-bot@chromium.orge61a86c2013-11-18 16:03:59 +00002041#define SkAutoHDC(...) SK_REQUIRE_LOCAL_VAR(SkAutoHDC)
bungeman@google.com3c996f82013-10-24 21:39:35 +00002042
2043int LogFontTypeface::onCharsToGlyphs(const void* chars, Encoding encoding,
2044 uint16_t userGlyphs[], int glyphCount) const
2045{
2046 SkAutoHDC hdc(fLogFont);
2047
2048 TEXTMETRIC tm;
2049 if (0 == GetTextMetrics(hdc, &tm)) {
2050 call_ensure_accessible(fLogFont);
2051 if (0 == GetTextMetrics(hdc, &tm)) {
2052 tm.tmPitchAndFamily = TMPF_TRUETYPE;
2053 }
2054 }
2055 bool Ox1FHack = !(tm.tmPitchAndFamily & TMPF_VECTOR) /*&& winVer < Vista */;
2056
2057 SkAutoSTMalloc<256, uint16_t> scratchGlyphs;
2058 uint16_t* glyphs;
halcanary96fcdcc2015-08-27 07:41:13 -07002059 if (userGlyphs != nullptr) {
bungeman@google.com3c996f82013-10-24 21:39:35 +00002060 glyphs = userGlyphs;
2061 } else {
2062 glyphs = scratchGlyphs.reset(glyphCount);
2063 }
2064
2065 SCRIPT_CACHE sc = 0;
2066 switch (encoding) {
2067 case SkTypeface::kUTF8_Encoding: {
2068 static const int scratchCount = 256;
2069 WCHAR scratch[scratchCount];
2070 int glyphIndex = 0;
2071 const char* currentUtf8 = reinterpret_cast<const char*>(chars);
2072 SkUnichar currentChar;
2073 if (glyphCount) {
2074 currentChar = SkUTF8_NextUnichar(&currentUtf8);
2075 }
2076 while (glyphIndex < glyphCount) {
2077 // Try a run of bmp.
2078 int glyphsLeft = SkTMin(glyphCount - glyphIndex, scratchCount);
2079 int runLength = 0;
2080 while (runLength < glyphsLeft && currentChar <= 0xFFFF) {
2081 scratch[runLength] = static_cast<WCHAR>(currentChar);
2082 ++runLength;
2083 if (runLength < glyphsLeft) {
2084 currentChar = SkUTF8_NextUnichar(&currentUtf8);
2085 }
2086 }
2087 if (runLength) {
2088 bmpCharsToGlyphs(hdc, scratch, runLength, &glyphs[glyphIndex], Ox1FHack);
2089 glyphIndex += runLength;
2090 }
2091
2092 // Try a run of non-bmp.
2093 while (glyphIndex < glyphCount && currentChar > 0xFFFF) {
2094 SkUTF16_FromUnichar(currentChar, reinterpret_cast<uint16_t*>(scratch));
2095 glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, scratch);
2096 ++glyphIndex;
2097 if (glyphIndex < glyphCount) {
2098 currentChar = SkUTF8_NextUnichar(&currentUtf8);
2099 }
2100 }
2101 }
2102 break;
2103 }
2104 case SkTypeface::kUTF16_Encoding: {
2105 int glyphIndex = 0;
2106 const WCHAR* currentUtf16 = reinterpret_cast<const WCHAR*>(chars);
2107 while (glyphIndex < glyphCount) {
2108 // Try a run of bmp.
2109 int glyphsLeft = glyphCount - glyphIndex;
2110 int runLength = 0;
2111 while (runLength < glyphsLeft && !SkUTF16_IsHighSurrogate(currentUtf16[runLength])) {
2112 ++runLength;
2113 }
2114 if (runLength) {
2115 bmpCharsToGlyphs(hdc, currentUtf16, runLength, &glyphs[glyphIndex], Ox1FHack);
2116 glyphIndex += runLength;
2117 currentUtf16 += runLength;
2118 }
2119
2120 // Try a run of non-bmp.
2121 while (glyphIndex < glyphCount && SkUTF16_IsHighSurrogate(*currentUtf16)) {
2122 glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, currentUtf16);
2123 ++glyphIndex;
2124 currentUtf16 += 2;
2125 }
2126 }
2127 break;
2128 }
2129 case SkTypeface::kUTF32_Encoding: {
2130 static const int scratchCount = 256;
2131 WCHAR scratch[scratchCount];
2132 int glyphIndex = 0;
2133 const uint32_t* utf32 = reinterpret_cast<const uint32_t*>(chars);
2134 while (glyphIndex < glyphCount) {
2135 // Try a run of bmp.
2136 int glyphsLeft = SkTMin(glyphCount - glyphIndex, scratchCount);
2137 int runLength = 0;
2138 while (runLength < glyphsLeft && utf32[glyphIndex + runLength] <= 0xFFFF) {
2139 scratch[runLength] = static_cast<WCHAR>(utf32[glyphIndex + runLength]);
2140 ++runLength;
2141 }
2142 if (runLength) {
2143 bmpCharsToGlyphs(hdc, scratch, runLength, &glyphs[glyphIndex], Ox1FHack);
2144 glyphIndex += runLength;
2145 }
2146
2147 // Try a run of non-bmp.
2148 while (glyphIndex < glyphCount && utf32[glyphIndex] > 0xFFFF) {
2149 SkUTF16_FromUnichar(utf32[glyphIndex], reinterpret_cast<uint16_t*>(scratch));
2150 glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, scratch);
2151 ++glyphIndex;
2152 }
2153 }
2154 break;
2155 }
2156 default:
djsollenf2b340f2016-01-29 08:51:04 -08002157 SK_ABORT("Invalid Text Encoding");
bungeman@google.com3c996f82013-10-24 21:39:35 +00002158 }
2159
2160 if (sc) {
2161 ::ScriptFreeCache(&sc);
2162 }
2163
2164 for (int i = 0; i < glyphCount; ++i) {
2165 if (0 == glyphs[i]) {
2166 return i;
2167 }
2168 }
2169 return glyphCount;
2170}
2171
bungeman@google.com7bdd6142013-07-15 19:42:57 +00002172int LogFontTypeface::onCountGlyphs() const {
halcanary96fcdcc2015-08-27 07:41:13 -07002173 HDC hdc = ::CreateCompatibleDC(nullptr);
bungeman@google.com7bdd6142013-07-15 19:42:57 +00002174 HFONT font = CreateFontIndirect(&fLogFont);
2175 HFONT savefont = (HFONT)SelectObject(hdc, font);
2176
2177 unsigned int glyphCount = calculateGlyphCount(hdc, fLogFont);
2178
2179 SelectObject(hdc, savefont);
2180 DeleteObject(font);
2181 DeleteDC(hdc);
2182
2183 return glyphCount;
2184}
2185
2186int LogFontTypeface::onGetUPEM() const {
halcanary96fcdcc2015-08-27 07:41:13 -07002187 HDC hdc = ::CreateCompatibleDC(nullptr);
bungeman@google.com7bdd6142013-07-15 19:42:57 +00002188 HFONT font = CreateFontIndirect(&fLogFont);
2189 HFONT savefont = (HFONT)SelectObject(hdc, font);
2190
2191 unsigned int upem = calculateUPEM(hdc, fLogFont);
2192
2193 SelectObject(hdc, savefont);
2194 DeleteObject(font);
2195 DeleteDC(hdc);
2196
2197 return upem;
2198}
2199
bungeman@google.com839702b2013-08-07 17:09:22 +00002200SkTypeface::LocalizedStrings* LogFontTypeface::onCreateFamilyNameIterator() const {
bungeman@google.coma9802692013-08-07 02:45:25 +00002201 SkTypeface::LocalizedStrings* nameIter =
2202 SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(*this);
halcanary96fcdcc2015-08-27 07:41:13 -07002203 if (nullptr == nameIter) {
bungeman@google.coma9802692013-08-07 02:45:25 +00002204 SkString familyName;
2205 this->getFamilyName(&familyName);
2206 SkString language("und"); //undetermined
2207 nameIter = new SkOTUtils::LocalizedStrings_SingleName(familyName, language);
2208 }
2209 return nameIter;
2210}
2211
bungeman@google.comb10b51f2013-08-01 20:18:41 +00002212int LogFontTypeface::onGetTableTags(SkFontTableTag tags[]) const {
2213 SkSFNTHeader header;
2214 if (sizeof(header) != this->onGetTableData(0, 0, sizeof(header), &header)) {
2215 return 0;
2216 }
2217
2218 int numTables = SkEndian_SwapBE16(header.numTables);
2219
2220 if (tags) {
2221 size_t size = numTables * sizeof(SkSFNTHeader::TableDirectoryEntry);
2222 SkAutoSTMalloc<0x20, SkSFNTHeader::TableDirectoryEntry> dir(numTables);
2223 if (size != this->onGetTableData(0, sizeof(header), size, dir.get())) {
2224 return 0;
2225 }
2226
2227 for (int i = 0; i < numTables; ++i) {
2228 tags[i] = SkEndian_SwapBE32(dir[i].tag);
2229 }
2230 }
2231 return numTables;
2232}
2233
2234size_t LogFontTypeface::onGetTableData(SkFontTableTag tag, size_t offset,
2235 size_t length, void* data) const
2236{
2237 LOGFONT lf = fLogFont;
2238
halcanary96fcdcc2015-08-27 07:41:13 -07002239 HDC hdc = ::CreateCompatibleDC(nullptr);
bungeman@google.comb10b51f2013-08-01 20:18:41 +00002240 HFONT font = CreateFontIndirect(&lf);
2241 HFONT savefont = (HFONT)SelectObject(hdc, font);
2242
2243 tag = SkEndian_SwapBE32(tag);
halcanary96fcdcc2015-08-27 07:41:13 -07002244 if (nullptr == data) {
bungeman@google.comb10b51f2013-08-01 20:18:41 +00002245 length = 0;
2246 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00002247 DWORD bufferSize = GetFontData(hdc, tag, (DWORD) offset, data, (DWORD) length);
bungeman@google.comb10b51f2013-08-01 20:18:41 +00002248 if (bufferSize == GDI_ERROR) {
2249 call_ensure_accessible(lf);
robertphillips@google.com8b169312013-10-15 17:47:36 +00002250 bufferSize = GetFontData(hdc, tag, (DWORD) offset, data, (DWORD) length);
bungeman@google.comb10b51f2013-08-01 20:18:41 +00002251 }
2252
2253 SelectObject(hdc, savefont);
2254 DeleteObject(font);
2255 DeleteDC(hdc);
2256
2257 return bufferSize == GDI_ERROR ? 0 : bufferSize;
2258}
2259
reeda9322c22016-04-12 06:47:05 -07002260SkScalerContext* LogFontTypeface::onCreateScalerContext(const SkScalerContextEffects& effects,
2261 const SkDescriptor* desc) const {
bungeman7cfd46a2016-10-20 16:06:52 -04002262 auto ctx = skstd::make_unique<SkScalerContext_GDI>(
2263 sk_ref_sp(const_cast<LogFontTypeface*>(this)), effects, desc);
reed@google.com84e22d82013-07-10 15:38:20 +00002264 if (!ctx->isValid()) {
Ben Wagnerc05b2bf2016-11-03 16:51:26 -04002265 return nullptr;
reed@google.com84e22d82013-07-10 15:38:20 +00002266 }
bungeman7cfd46a2016-10-20 16:06:52 -04002267 return ctx.release();
reed@google.comac6b9792011-03-11 15:42:51 +00002268}
2269
reed@google.com0da48612013-03-19 16:06:52 +00002270void LogFontTypeface::onFilterRec(SkScalerContextRec* rec) const {
commit-bot@chromium.orgc5fd4612013-05-06 22:23:08 +00002271 if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag ||
2272 rec->fFlags & SkScalerContext::kLCD_Vertical_Flag)
2273 {
2274 rec->fMaskFormat = SkMask::kA8_Format;
2275 rec->fFlags |= SkScalerContext::kGenA8FromLCD_Flag;
2276 }
2277
bungeman41078062014-07-07 08:16:37 -07002278 unsigned flagsWeDontSupport = SkScalerContext::kVertical_Flag |
2279 SkScalerContext::kDevKernText_Flag |
bungeman@google.comf6f56872014-01-23 19:01:36 +00002280 SkScalerContext::kForceAutohinting_Flag |
reed@google.come8fab012011-07-13 15:25:33 +00002281 SkScalerContext::kEmbeddedBitmapText_Flag |
2282 SkScalerContext::kEmbolden_Flag |
2283 SkScalerContext::kLCD_BGROrder_Flag |
2284 SkScalerContext::kLCD_Vertical_Flag;
2285 rec->fFlags &= ~flagsWeDontSupport;
2286
reed@google.come8fab012011-07-13 15:25:33 +00002287 SkPaint::Hinting h = rec->getHinting();
2288 switch (h) {
2289 case SkPaint::kNo_Hinting:
bungeman@google.com0abbff92013-07-27 20:37:56 +00002290 break;
reed@google.come8fab012011-07-13 15:25:33 +00002291 case SkPaint::kSlight_Hinting:
bungeman@google.com0abbff92013-07-27 20:37:56 +00002292 // Only do slight hinting when axis aligned.
bungeman@google.com7c86d8e2013-07-27 21:42:21 +00002293 // TODO: re-enable slight hinting when FontHostTest can pass.
2294 //if (!isAxisAligned(*rec)) {
bungeman@google.com0abbff92013-07-27 20:37:56 +00002295 h = SkPaint::kNo_Hinting;
bungeman@google.com7c86d8e2013-07-27 21:42:21 +00002296 //}
reed@google.come8fab012011-07-13 15:25:33 +00002297 break;
2298 case SkPaint::kNormal_Hinting:
2299 case SkPaint::kFull_Hinting:
bungeman@google.com0abbff92013-07-27 20:37:56 +00002300 // TODO: need to be able to distinguish subpixel positioned glyphs
2301 // and linear metrics.
2302 //rec->fFlags &= ~SkScalerContext::kSubpixelPositioning_Flag;
reed@google.come8fab012011-07-13 15:25:33 +00002303 h = SkPaint::kNormal_Hinting;
2304 break;
2305 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00002306 SkDEBUGFAIL("unknown hinting");
reed@google.come8fab012011-07-13 15:25:33 +00002307 }
bungeman@google.com0abbff92013-07-27 20:37:56 +00002308 //TODO: if this is a bitmap font, squash hinting and subpixel.
reed@google.come8fab012011-07-13 15:25:33 +00002309 rec->setHinting(h);
reed@google.comda440672011-07-13 18:02:28 +00002310
reed@google.com9181aa82011-08-05 14:28:31 +00002311// turn this off since GDI might turn A8 into BW! Need a bigger fix.
2312#if 0
reed@google.comda440672011-07-13 18:02:28 +00002313 // Disable LCD when rotated, since GDI's output is ugly
2314 if (isLCD(*rec) && !isAxisAligned(*rec)) {
2315 rec->fMaskFormat = SkMask::kA8_Format;
2316 }
reed@google.com9181aa82011-08-05 14:28:31 +00002317#endif
reed@google.com754e4eb2011-09-26 13:21:39 +00002318
reed@google.com0da48612013-03-19 16:06:52 +00002319 if (!fCanBeLCD && isLCD(*rec)) {
bungeman@google.comcb1bbb32012-10-12 18:48:35 +00002320 rec->fMaskFormat = SkMask::kA8_Format;
2321 rec->fFlags &= ~SkScalerContext::kGenA8FromLCD_Flag;
reed@google.com754e4eb2011-09-26 13:21:39 +00002322 }
reed@google.com754e4eb2011-09-26 13:21:39 +00002323}
reed@google.com070da5e2013-03-27 20:01:49 +00002324
2325///////////////////////////////////////////////////////////////////////////////
2326
2327#include "SkFontMgr.h"
reed@google.com484f5bc2013-04-24 19:14:56 +00002328#include "SkDataTable.h"
2329
bungeman@google.coma9802692013-08-07 02:45:25 +00002330static bool valid_logfont_for_enum(const LOGFONT& lf) {
2331 // TODO: Vector FON is unsupported and should not be listed.
2332 return
2333 // Ignore implicit vertical variants.
2334 lf.lfFaceName[0] && lf.lfFaceName[0] != '@'
2335
2336 // DEFAULT_CHARSET is used to get all fonts, but also implies all
2337 // character sets. Filter assuming all fonts support ANSI_CHARSET.
2338 && ANSI_CHARSET == lf.lfCharSet
2339 ;
reed@google.com484f5bc2013-04-24 19:14:56 +00002340}
2341
bungeman@google.coma9802692013-08-07 02:45:25 +00002342/** An EnumFontFamExProc implementation which interprets builderParam as
2343 * an SkTDArray<ENUMLOGFONTEX>* and appends logfonts which
2344 * pass the valid_logfont_for_enum predicate.
2345 */
2346static int CALLBACK enum_family_proc(const LOGFONT* lf, const TEXTMETRIC*,
2347 DWORD fontType, LPARAM builderParam) {
2348 if (valid_logfont_for_enum(*lf)) {
reed@google.coma65a6812013-05-02 19:47:24 +00002349 SkTDArray<ENUMLOGFONTEX>* array = (SkTDArray<ENUMLOGFONTEX>*)builderParam;
2350 *array->append() = *(ENUMLOGFONTEX*)lf;
reed@google.com484f5bc2013-04-24 19:14:56 +00002351 }
2352 return 1; // non-zero means continue
2353}
2354
reed@google.com484f5bc2013-04-24 19:14:56 +00002355class SkFontStyleSetGDI : public SkFontStyleSet {
2356public:
reed@google.coma65a6812013-05-02 19:47:24 +00002357 SkFontStyleSetGDI(const TCHAR familyName[]) {
bungeman@google.coma9802692013-08-07 02:45:25 +00002358 LOGFONT lf;
2359 sk_bzero(&lf, sizeof(lf));
2360 lf.lfCharSet = DEFAULT_CHARSET;
2361 _tcscpy_s(lf.lfFaceName, familyName);
2362
halcanary96fcdcc2015-08-27 07:41:13 -07002363 HDC hdc = ::CreateCompatibleDC(nullptr);
bungeman@google.coma9802692013-08-07 02:45:25 +00002364 ::EnumFontFamiliesEx(hdc, &lf, enum_family_proc, (LPARAM)&fArray, 0);
reed@google.com484f5bc2013-04-24 19:14:56 +00002365 ::DeleteDC(hdc);
2366 }
2367
mtklein36352bf2015-03-25 18:17:31 -07002368 int count() override {
reed@google.com484f5bc2013-04-24 19:14:56 +00002369 return fArray.count();
2370 }
2371
mtklein36352bf2015-03-25 18:17:31 -07002372 void getStyle(int index, SkFontStyle* fs, SkString* styleName) override {
reed@google.com484f5bc2013-04-24 19:14:56 +00002373 if (fs) {
bungemana4c4a2d2014-10-20 13:33:19 -07002374 *fs = get_style(fArray[index].elfLogFont);
reed@google.com484f5bc2013-04-24 19:14:56 +00002375 }
reed@google.coma65a6812013-05-02 19:47:24 +00002376 if (styleName) {
2377 const ENUMLOGFONTEX& ref = fArray[index];
2378 // For some reason, ENUMLOGFONTEX and LOGFONT disagree on their type in the
2379 // non-unicode version.
2380 // ENUMLOGFONTEX uses BYTE
2381 // LOGFONT uses CHAR
2382 // Here we assert they that the style name is logically the same (size) as
2383 // a TCHAR, so we can use the same converter function.
2384 SkASSERT(sizeof(TCHAR) == sizeof(ref.elfStyle[0]));
2385 tchar_to_skstring((const TCHAR*)ref.elfStyle, styleName);
2386 }
reed@google.com484f5bc2013-04-24 19:14:56 +00002387 }
2388
mtklein36352bf2015-03-25 18:17:31 -07002389 SkTypeface* createTypeface(int index) override {
reed@google.coma65a6812013-05-02 19:47:24 +00002390 return SkCreateTypefaceFromLOGFONT(fArray[index].elfLogFont);
reed@google.com484f5bc2013-04-24 19:14:56 +00002391 }
2392
mtklein36352bf2015-03-25 18:17:31 -07002393 SkTypeface* matchStyle(const SkFontStyle& pattern) override {
bungeman147ea2f2015-11-12 09:50:08 -08002394 return this->matchStyleCSS3(pattern);
reed@google.com484f5bc2013-04-24 19:14:56 +00002395 }
2396
2397private:
reed@google.coma65a6812013-05-02 19:47:24 +00002398 SkTDArray<ENUMLOGFONTEX> fArray;
reed@google.com484f5bc2013-04-24 19:14:56 +00002399};
2400
reed@google.com484f5bc2013-04-24 19:14:56 +00002401class SkFontMgrGDI : public SkFontMgr {
bungeman@google.coma9802692013-08-07 02:45:25 +00002402public:
2403 SkFontMgrGDI() {
reed@google.com484f5bc2013-04-24 19:14:56 +00002404 LOGFONT lf;
2405 sk_bzero(&lf, sizeof(lf));
2406 lf.lfCharSet = DEFAULT_CHARSET;
2407
halcanary96fcdcc2015-08-27 07:41:13 -07002408 HDC hdc = ::CreateCompatibleDC(nullptr);
reed@google.com484f5bc2013-04-24 19:14:56 +00002409 ::EnumFontFamiliesEx(hdc, &lf, enum_family_proc, (LPARAM)&fLogFontArray, 0);
2410 ::DeleteDC(hdc);
2411 }
2412
reed@google.com484f5bc2013-04-24 19:14:56 +00002413protected:
mtklein36352bf2015-03-25 18:17:31 -07002414 int onCountFamilies() const override {
reed@google.com484f5bc2013-04-24 19:14:56 +00002415 return fLogFontArray.count();
2416 }
2417
mtklein36352bf2015-03-25 18:17:31 -07002418 void onGetFamilyName(int index, SkString* familyName) const override {
reed@google.com484f5bc2013-04-24 19:14:56 +00002419 SkASSERT((unsigned)index < (unsigned)fLogFontArray.count());
reed@google.coma65a6812013-05-02 19:47:24 +00002420 tchar_to_skstring(fLogFontArray[index].elfLogFont.lfFaceName, familyName);
reed@google.com484f5bc2013-04-24 19:14:56 +00002421 }
2422
mtklein36352bf2015-03-25 18:17:31 -07002423 SkFontStyleSet* onCreateStyleSet(int index) const override {
reed@google.com484f5bc2013-04-24 19:14:56 +00002424 SkASSERT((unsigned)index < (unsigned)fLogFontArray.count());
halcanary385fe4d2015-08-26 13:07:48 -07002425 return new SkFontStyleSetGDI(fLogFontArray[index].elfLogFont.lfFaceName);
reed@google.com484f5bc2013-04-24 19:14:56 +00002426 }
2427
mtklein36352bf2015-03-25 18:17:31 -07002428 SkFontStyleSet* onMatchFamily(const char familyName[]) const override {
halcanary96fcdcc2015-08-27 07:41:13 -07002429 if (nullptr == familyName) {
reed@google.com484f5bc2013-04-24 19:14:56 +00002430 familyName = ""; // do we need this check???
2431 }
2432 LOGFONT lf;
2433 logfont_for_name(familyName, &lf);
halcanary385fe4d2015-08-26 13:07:48 -07002434 return new SkFontStyleSetGDI(lf.lfFaceName);
reed@google.com484f5bc2013-04-24 19:14:56 +00002435 }
2436
reed@google.com484f5bc2013-04-24 19:14:56 +00002437 virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
mtklein36352bf2015-03-25 18:17:31 -07002438 const SkFontStyle& fontstyle) const override {
reed@google.com437eea12013-04-25 20:40:02 +00002439 // could be in base impl
Hal Canary67b39de2016-11-07 11:47:44 -05002440 sk_sp<SkFontStyleSet> sset(this->matchFamily(familyName));
reed@google.com484f5bc2013-04-24 19:14:56 +00002441 return sset->matchStyle(fontstyle);
2442 }
2443
djsollen33068c12014-11-14 10:52:53 -08002444 virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&,
2445 const char* bcp47[], int bcp47Count,
mtklein36352bf2015-03-25 18:17:31 -07002446 SkUnichar character) const override {
halcanary96fcdcc2015-08-27 07:41:13 -07002447 return nullptr;
djsollen33068c12014-11-14 10:52:53 -08002448 }
2449
reed@google.com484f5bc2013-04-24 19:14:56 +00002450 virtual SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember,
mtklein36352bf2015-03-25 18:17:31 -07002451 const SkFontStyle& fontstyle) const override {
reed@google.com437eea12013-04-25 20:40:02 +00002452 // could be in base impl
reed@google.com484f5bc2013-04-24 19:14:56 +00002453 SkString familyName;
2454 ((LogFontTypeface*)familyMember)->getFamilyName(&familyName);
2455 return this->matchFamilyStyle(familyName.c_str(), fontstyle);
2456 }
2457
mtklein36352bf2015-03-25 18:17:31 -07002458 SkTypeface* onCreateFromStream(SkStreamAsset* bareStream, int ttcIndex) const override {
Ben Wagner145dbcd2016-11-03 14:40:50 -04002459 std::unique_ptr<SkStreamAsset> stream(bareStream);
Ben Wagnerfc497342017-02-24 11:15:26 -05002460 if (ttcIndex != 0) {
2461 return nullptr;
2462 }
Ben Wagner145dbcd2016-11-03 14:40:50 -04002463 return create_from_stream(stream.get());
reed@google.com484f5bc2013-04-24 19:14:56 +00002464 }
reed@google.com437eea12013-04-25 20:40:02 +00002465
mtklein36352bf2015-03-25 18:17:31 -07002466 SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const override {
reed@google.com437eea12013-04-25 20:40:02 +00002467 // could be in base impl
Ben Wagnerfc497342017-02-24 11:15:26 -05002468 return this->createFromStream(new SkMemoryStream(sk_ref_sp(data)), ttcIndex);
reed@google.com484f5bc2013-04-24 19:14:56 +00002469 }
reed@google.com437eea12013-04-25 20:40:02 +00002470
mtklein36352bf2015-03-25 18:17:31 -07002471 SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override {
reed@google.com437eea12013-04-25 20:40:02 +00002472 // could be in base impl
Ben Wagnerfc497342017-02-24 11:15:26 -05002473 return this->createFromStream(SkStream::MakeFromFile(path).release(), ttcIndex);
reed@google.com484f5bc2013-04-24 19:14:56 +00002474 }
2475
bungeman11a77c62016-04-12 13:45:06 -07002476 SkTypeface* onLegacyCreateTypeface(const char familyName[], SkFontStyle style) const override {
bungeman@google.comf7159bb2013-11-20 15:11:05 +00002477 LOGFONT lf;
halcanary96fcdcc2015-08-27 07:41:13 -07002478 if (nullptr == familyName) {
bungeman@google.comf7159bb2013-11-20 15:11:05 +00002479 lf = get_default_font();
2480 } else {
2481 logfont_for_name(familyName, &lf);
2482 }
bungemana4c4a2d2014-10-20 13:33:19 -07002483
bungeman11a77c62016-04-12 13:45:06 -07002484 lf.lfWeight = style.weight();
bungemanb4bb7d82016-04-27 10:21:04 -07002485 lf.lfItalic = style.slant() == SkFontStyle::kUpright_Slant ? FALSE : TRUE;
bungeman@google.comf7159bb2013-11-20 15:11:05 +00002486 return SkCreateTypefaceFromLOGFONT(lf);
reed@google.com30ddd612013-07-30 17:47:39 +00002487 }
2488
reed@google.com484f5bc2013-04-24 19:14:56 +00002489private:
reed@google.coma65a6812013-05-02 19:47:24 +00002490 SkTDArray<ENUMLOGFONTEX> fLogFontArray;
reed@google.com484f5bc2013-04-24 19:14:56 +00002491};
reed@google.com070da5e2013-03-27 20:01:49 +00002492
reed@google.com30ddd612013-07-30 17:47:39 +00002493///////////////////////////////////////////////////////////////////////////////
2494
Ben Wagner3546ff12017-01-03 13:32:36 -05002495sk_sp<SkFontMgr> SkFontMgr_New_GDI() { return sk_make_sp<SkFontMgrGDI>(); }
mtklein1ee76512015-11-02 10:20:27 -08002496
2497#endif//defined(SK_BUILD_FOR_WIN32)