blob: fa5c9722b81b8aca73e82c48e28b37298f54bc01 [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"
bungeman@google.com97efada2012-07-30 20:40:50 +000019#include "SkMaskGamma.h"
bungeman@google.comd3fbd342014-04-15 15:52:07 +000020#include "SkMatrix22.h"
bungeman@google.com7bdd6142013-07-15 19:42:57 +000021#include "SkOTTable_maxp.h"
bungeman@google.coma9802692013-08-07 02:45:25 +000022#include "SkOTTable_name.h"
bungeman@google.coma5501992012-05-18 19:06:41 +000023#include "SkOTUtils.h"
reed@google.com27889872012-08-07 16:15:13 +000024#include "SkPath.h"
bungeman@google.comb10b51f2013-08-01 20:18:41 +000025#include "SkSFNTHeader.h"
reed@google.comac6b9792011-03-11 15:42:51 +000026#include "SkStream.h"
bungeman@google.coma5501992012-05-18 19:06:41 +000027#include "SkString.h"
bungeman@google.com05a729f2013-06-20 15:29:16 +000028#include "SkTemplates.h"
reed@google.comac6b9792011-03-11 15:42:51 +000029#include "SkTypeface_win.h"
reed@google.com59d2f632011-05-02 19:36:59 +000030#include "SkTypefaceCache.h"
reed@google.comac6b9792011-03-11 15:42:51 +000031#include "SkUtils.h"
32
bungeman@google.coma5501992012-05-18 19:06:41 +000033#include "SkTypes.h"
34#include <tchar.h>
35#include <usp10.h>
36#include <objbase.h>
reed@google.comac6b9792011-03-11 15:42:51 +000037
reed@google.comf210f502013-03-20 14:15:52 +000038static void (*gEnsureLOGFONTAccessibleProc)(const LOGFONT&);
39
40void SkTypeface_SetEnsureLOGFONTAccessibleProc(void (*proc)(const LOGFONT&)) {
41 gEnsureLOGFONTAccessibleProc = proc;
42}
43
reed@google.com055180c2013-03-21 18:46:35 +000044static void call_ensure_accessible(const LOGFONT& lf) {
45 if (gEnsureLOGFONTAccessibleProc) {
46 gEnsureLOGFONTAccessibleProc(lf);
47 }
48}
49
50///////////////////////////////////////////////////////////////////////////////
51
reed@google.com6f5df482011-09-28 20:33:24 +000052// always packed xxRRGGBB
53typedef uint32_t SkGdiRGB;
54
reed@google.coma767fa02011-08-05 21:40:26 +000055// define this in your Makefile or .gyp to enforce AA requests
56// which GDI ignores at small sizes. This flag guarantees AA
57// for rotated text, regardless of GDI's notions.
58//#define SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
59
reed@google.com82a34d82011-07-26 19:33:08 +000060static bool isLCD(const SkScalerContext::Rec& rec) {
reedd54d3fc2014-11-13 14:39:58 -080061 return SkMask::kLCD16_Format == rec.fMaskFormat;
reed@google.com82a34d82011-07-26 19:33:08 +000062}
63
reed@google.coma767fa02011-08-05 21:40:26 +000064static bool bothZero(SkScalar a, SkScalar b) {
65 return 0 == a && 0 == b;
66}
67
68// returns false if there is any non-90-rotation or skew
69static bool isAxisAligned(const SkScalerContext::Rec& rec) {
70 return 0 == rec.fPreSkewX &&
71 (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
72 bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
73}
74
75static bool needToRenderWithSkia(const SkScalerContext::Rec& rec) {
76#ifdef SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
77 // What we really want to catch is when GDI will ignore the AA request and give
78 // us BW instead. Smallish rotated text is one heuristic, so this code is just
79 // an approximation. We shouldn't need to do this for larger sizes, but at those
80 // sizes, the quality difference gets less and less between our general
81 // scanconverter and GDI's.
82 if (SkMask::kA8_Format == rec.fMaskFormat && !isAxisAligned(rec)) {
83 return true;
84 }
85#endif
bungeman@google.com0abbff92013-07-27 20:37:56 +000086 return rec.getHinting() == SkPaint::kNo_Hinting || rec.getHinting() == SkPaint::kSlight_Hinting;
reed@google.coma767fa02011-08-05 21:40:26 +000087}
88
reed@google.coma65a6812013-05-02 19:47:24 +000089static void tchar_to_skstring(const TCHAR t[], SkString* s) {
reed@google.com484f5bc2013-04-24 19:14:56 +000090#ifdef UNICODE
halcanary96fcdcc2015-08-27 07:41:13 -070091 size_t sSize = WideCharToMultiByte(CP_UTF8, 0, t, -1, nullptr, 0, nullptr, nullptr);
reed@google.com484f5bc2013-04-24 19:14:56 +000092 s->resize(sSize);
halcanary96fcdcc2015-08-27 07:41:13 -070093 WideCharToMultiByte(CP_UTF8, 0, t, -1, s->writable_str(), sSize, nullptr, nullptr);
reed@google.com484f5bc2013-04-24 19:14:56 +000094#else
95 s->set(t);
96#endif
97}
98
bungeman@google.coma9802692013-08-07 02:45:25 +000099static void dcfontname_to_skstring(HDC deviceContext, const LOGFONT& lf, SkString* familyName) {
100 int fontNameLen; //length of fontName in TCHARS.
halcanary96fcdcc2015-08-27 07:41:13 -0700101 if (0 == (fontNameLen = GetTextFace(deviceContext, 0, nullptr))) {
bungeman@google.coma9802692013-08-07 02:45:25 +0000102 call_ensure_accessible(lf);
halcanary96fcdcc2015-08-27 07:41:13 -0700103 if (0 == (fontNameLen = GetTextFace(deviceContext, 0, nullptr))) {
bungeman@google.coma9802692013-08-07 02:45:25 +0000104 fontNameLen = 0;
105 }
106 }
107
108 SkAutoSTArray<LF_FULLFACESIZE, TCHAR> fontName(fontNameLen+1);
109 if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) {
110 call_ensure_accessible(lf);
111 if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) {
112 fontName[0] = 0;
113 }
114 }
115
116 tchar_to_skstring(fontName.get(), familyName);
117}
118
reed@google.comac6b9792011-03-11 15:42:51 +0000119static void make_canonical(LOGFONT* lf) {
bungeman@google.com53cbb0b2013-09-08 19:36:58 +0000120 lf->lfHeight = -64;
bungeman59f093d2016-03-22 10:59:09 -0700121 lf->lfWidth = 0; // lfWidth is related to lfHeight, not to the OS/2::usWidthClass.
reed@google.com59d2f632011-05-02 19:36:59 +0000122 lf->lfQuality = CLEARTYPE_QUALITY;//PROOF_QUALITY;
123 lf->lfCharSet = DEFAULT_CHARSET;
reed@google.com82a34d82011-07-26 19:33:08 +0000124// lf->lfClipPrecision = 64;
reed@google.com59d2f632011-05-02 19:36:59 +0000125}
126
bungemana4c4a2d2014-10-20 13:33:19 -0700127static SkFontStyle get_style(const LOGFONT& lf) {
128 return SkFontStyle(lf.lfWeight,
bungeman59f093d2016-03-22 10:59:09 -0700129 SkFontStyle::kNormal_Width,
bungemana4c4a2d2014-10-20 13:33:19 -0700130 lf.lfItalic ? SkFontStyle::kItalic_Slant : SkFontStyle::kUpright_Slant);
reed@google.comac6b9792011-03-11 15:42:51 +0000131}
132
133static inline FIXED SkFixedToFIXED(SkFixed x) {
134 return *(FIXED*)(&x);
135}
bungeman@google.coma0319f62012-04-18 15:40:50 +0000136static inline SkFixed SkFIXEDToFixed(FIXED x) {
137 return *(SkFixed*)(&x);
138}
reed@google.comac6b9792011-03-11 15:42:51 +0000139
140static inline FIXED SkScalarToFIXED(SkScalar x) {
141 return SkFixedToFIXED(SkScalarToFixed(x));
142}
143
bungeman@google.com4732df62014-01-23 15:22:42 +0000144static inline SkScalar SkFIXEDToScalar(FIXED x) {
145 return SkFixedToScalar(SkFIXEDToFixed(x));
146}
147
bungeman@google.com7bdd6142013-07-15 19:42:57 +0000148static unsigned calculateGlyphCount(HDC hdc, const LOGFONT& lf) {
149 TEXTMETRIC textMetric;
150 if (0 == GetTextMetrics(hdc, &textMetric)) {
151 textMetric.tmPitchAndFamily = TMPF_VECTOR;
152 call_ensure_accessible(lf);
153 GetTextMetrics(hdc, &textMetric);
154 }
155
156 if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) {
157 return textMetric.tmLastChar;
158 }
159
reed@google.comac6b9792011-03-11 15:42:51 +0000160 // The 'maxp' table stores the number of glyphs at offset 4, in 2 bytes.
reed@google.comac6b9792011-03-11 15:42:51 +0000161 uint16_t glyphs;
bungeman@google.com7bdd6142013-07-15 19:42:57 +0000162 if (GDI_ERROR != GetFontData(hdc, SkOTTableMaximumProfile::TAG, 4, &glyphs, sizeof(glyphs))) {
reed@google.comac6b9792011-03-11 15:42:51 +0000163 return SkEndian_SwapBE16(glyphs);
164 }
ctguil@chromium.org5aa937b2011-08-04 01:01:24 +0000165
reed@google.comac6b9792011-03-11 15:42:51 +0000166 // Binary search for glyph count.
167 static const MAT2 mat2 = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
168 int32_t max = SK_MaxU16 + 1;
169 int32_t min = 0;
170 GLYPHMETRICS gm;
171 while (min < max) {
172 int32_t mid = min + ((max - min) / 2);
173 if (GetGlyphOutlineW(hdc, mid, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0,
halcanary96fcdcc2015-08-27 07:41:13 -0700174 nullptr, &mat2) == GDI_ERROR) {
reed@google.comac6b9792011-03-11 15:42:51 +0000175 max = mid;
176 } else {
177 min = mid + 1;
178 }
179 }
180 SkASSERT(min == max);
181 return min;
182}
183
bungeman@google.com7bdd6142013-07-15 19:42:57 +0000184static unsigned calculateUPEM(HDC hdc, const LOGFONT& lf) {
185 TEXTMETRIC textMetric;
186 if (0 == GetTextMetrics(hdc, &textMetric)) {
187 textMetric.tmPitchAndFamily = TMPF_VECTOR;
188 call_ensure_accessible(lf);
189 GetTextMetrics(hdc, &textMetric);
190 }
191
192 if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) {
193 return textMetric.tmMaxCharWidth;
194 }
195
196 OUTLINETEXTMETRIC otm;
197 unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
198 if (0 == otmRet) {
199 call_ensure_accessible(lf);
200 otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
201 }
202
203 return (0 == otmRet) ? 0 : otm.otmEMSquare;
204}
205
reed@google.comac6b9792011-03-11 15:42:51 +0000206class LogFontTypeface : public SkTypeface {
reed@google.comac6b9792011-03-11 15:42:51 +0000207public:
bungemana4c4a2d2014-10-20 13:33:19 -0700208 LogFontTypeface(const SkFontStyle& style, const LOGFONT& lf, bool serializeAsStream)
bungemane3aea102016-07-13 05:16:58 -0700209 : SkTypeface(style, false)
bungemana4c4a2d2014-10-20 13:33:19 -0700210 , fLogFont(lf)
211 , fSerializeAsStream(serializeAsStream)
212 {
bungeman@google.comcb1bbb32012-10-12 18:48:35 +0000213 HFONT font = CreateFontIndirect(&lf);
214
halcanary96fcdcc2015-08-27 07:41:13 -0700215 HDC deviceContext = ::CreateCompatibleDC(nullptr);
bungeman@google.comcb1bbb32012-10-12 18:48:35 +0000216 HFONT savefont = (HFONT)SelectObject(deviceContext, font);
217
218 TEXTMETRIC textMetric;
219 if (0 == GetTextMetrics(deviceContext, &textMetric)) {
reed@google.com055180c2013-03-21 18:46:35 +0000220 call_ensure_accessible(lf);
bungeman@google.comcb1bbb32012-10-12 18:48:35 +0000221 if (0 == GetTextMetrics(deviceContext, &textMetric)) {
222 textMetric.tmPitchAndFamily = TMPF_TRUETYPE;
223 }
224 }
225 if (deviceContext) {
226 ::SelectObject(deviceContext, savefont);
227 ::DeleteDC(deviceContext);
228 }
229 if (font) {
230 ::DeleteObject(font);
231 }
232
bungeman@google.comfe747652013-03-25 19:36:11 +0000233 // The fixed pitch bit is set if the font is *not* fixed pitch.
234 this->setIsFixedPitch((textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0);
bungeman6e45bda2016-07-25 15:11:49 -0700235 this->setFontStyle(SkFontStyle(textMetric.tmWeight, style.width(), style.slant()));
bungeman@google.comfe747652013-03-25 19:36:11 +0000236
bungeman@google.comcb1bbb32012-10-12 18:48:35 +0000237 // Used a logfont on a memory context, should never get a device font.
238 // Therefore all TMPF_DEVICE will be PostScript (cubic) fonts.
bungeman6e45bda2016-07-25 15:11:49 -0700239 // If the font has cubic outlines, it will not be rendered with ClearType.
bungeman@google.comcb1bbb32012-10-12 18:48:35 +0000240 fCanBeLCD = !((textMetric.tmPitchAndFamily & TMPF_VECTOR) &&
241 (textMetric.tmPitchAndFamily & TMPF_DEVICE));
242 }
reed@google.comac6b9792011-03-11 15:42:51 +0000243
reed@google.com59d2f632011-05-02 19:36:59 +0000244 LOGFONT fLogFont;
bungeman@google.come70f7982012-06-01 19:38:19 +0000245 bool fSerializeAsStream;
bungeman@google.comcb1bbb32012-10-12 18:48:35 +0000246 bool fCanBeLCD;
reed@google.comac6b9792011-03-11 15:42:51 +0000247
reed@google.com59d2f632011-05-02 19:36:59 +0000248 static LogFontTypeface* Create(const LOGFONT& lf) {
bungemana4c4a2d2014-10-20 13:33:19 -0700249 return new LogFontTypeface(get_style(lf), lf, false);
reed@google.comac6b9792011-03-11 15:42:51 +0000250 }
reed@google.com0da48612013-03-19 16:06:52 +0000251
reed@google.com055180c2013-03-21 18:46:35 +0000252 static void EnsureAccessible(const SkTypeface* face) {
253 call_ensure_accessible(static_cast<const LogFontTypeface*>(face)->fLogFont);
254 }
255
reed@google.com0da48612013-03-19 16:06:52 +0000256protected:
mtklein36352bf2015-03-25 18:17:31 -0700257 SkStreamAsset* onOpenStream(int* ttcIndex) const override;
reeda9322c22016-04-12 06:47:05 -0700258 SkScalerContext* onCreateScalerContext(const SkScalerContextEffects&,
259 const SkDescriptor*) const override;
mtklein36352bf2015-03-25 18:17:31 -0700260 void onFilterRec(SkScalerContextRec*) const override;
reed39a9a502015-05-12 09:50:04 -0700261 SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics(
262 PerGlyphInfo, const uint32_t*, uint32_t) const override;
mtklein36352bf2015-03-25 18:17:31 -0700263 void onGetFontDescriptor(SkFontDescriptor*, bool*) const override;
bungeman@google.com3c996f82013-10-24 21:39:35 +0000264 virtual int onCharsToGlyphs(const void* chars, Encoding encoding,
mtklein36352bf2015-03-25 18:17:31 -0700265 uint16_t glyphs[], int glyphCount) const override;
266 int onCountGlyphs() const override;
267 int onGetUPEM() const override;
268 void onGetFamilyName(SkString* familyName) const override;
269 SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override;
270 int onGetTableTags(SkFontTableTag tags[]) const override;
bungeman@google.comb10b51f2013-08-01 20:18:41 +0000271 virtual size_t onGetTableData(SkFontTableTag, size_t offset,
mtklein36352bf2015-03-25 18:17:31 -0700272 size_t length, void* data) const override;
reed@google.comac6b9792011-03-11 15:42:51 +0000273};
274
bungeman@google.coma5501992012-05-18 19:06:41 +0000275class FontMemResourceTypeface : public LogFontTypeface {
276public:
277 /**
bungeman@google.coma5501992012-05-18 19:06:41 +0000278 * The created FontMemResourceTypeface takes ownership of fontMemResource.
279 */
280 static FontMemResourceTypeface* Create(const LOGFONT& lf, HANDLE fontMemResource) {
bungemana4c4a2d2014-10-20 13:33:19 -0700281 return new FontMemResourceTypeface(get_style(lf), lf, fontMemResource);
bungeman@google.coma5501992012-05-18 19:06:41 +0000282 }
283
284protected:
mtklein36352bf2015-03-25 18:17:31 -0700285 void weak_dispose() const override {
bungeman@google.coma5501992012-05-18 19:06:41 +0000286 RemoveFontMemResourceEx(fFontMemResource);
287 //SkTypefaceCache::Remove(this);
288 INHERITED::weak_dispose();
289 }
290
291private:
bungeman@google.com72cf4fc2014-03-21 22:48:32 +0000292 /**
293 * Takes ownership of fontMemResource.
294 */
bungemana4c4a2d2014-10-20 13:33:19 -0700295 FontMemResourceTypeface(const SkFontStyle& style, const LOGFONT& lf, HANDLE fontMemResource)
296 : LogFontTypeface(style, lf, true), fFontMemResource(fontMemResource)
297 { }
bungeman@google.com72cf4fc2014-03-21 22:48:32 +0000298
299 HANDLE fFontMemResource;
300
bungeman@google.coma5501992012-05-18 19:06:41 +0000301 typedef LogFontTypeface INHERITED;
302};
303
reed@google.comac6b9792011-03-11 15:42:51 +0000304static const LOGFONT& get_default_font() {
305 static LOGFONT gDefaultFont;
reed@google.comac6b9792011-03-11 15:42:51 +0000306 return gDefaultFont;
307}
308
bungeman82a455f2016-04-14 08:04:45 -0700309static bool FindByLogFont(SkTypeface* face, void* ctx) {
bungeman@google.coma5501992012-05-18 19:06:41 +0000310 LogFontTypeface* lface = static_cast<LogFontTypeface*>(face);
reed@google.com59d2f632011-05-02 19:36:59 +0000311 const LOGFONT* lf = reinterpret_cast<const LOGFONT*>(ctx);
reed@google.comac6b9792011-03-11 15:42:51 +0000312
bungeman82a455f2016-04-14 08:04:45 -0700313 return !memcmp(&lface->fLogFont, lf, sizeof(LOGFONT));
reed@google.com59d2f632011-05-02 19:36:59 +0000314}
315
316/**
317 * This guy is public. It first searches the cache, and if a match is not found,
318 * it creates a new face.
319 */
320SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT& origLF) {
321 LOGFONT lf = origLF;
322 make_canonical(&lf);
bungeman@google.comee51d1a2012-02-16 12:40:48 +0000323 SkTypeface* face = SkTypefaceCache::FindByProcAndRef(FindByLogFont, &lf);
halcanary96fcdcc2015-08-27 07:41:13 -0700324 if (nullptr == face) {
reed@google.com59d2f632011-05-02 19:36:59 +0000325 face = LogFontTypeface::Create(lf);
bungeman82a455f2016-04-14 08:04:45 -0700326 SkTypefaceCache::Add(face);
reed@google.com59d2f632011-05-02 19:36:59 +0000327 }
328 return face;
reed@google.comac6b9792011-03-11 15:42:51 +0000329}
330
reed@google.comdb77a6a2011-07-19 19:08:33 +0000331/**
bungeman@google.coma5501992012-05-18 19:06:41 +0000332 * The created SkTypeface takes ownership of fontMemResource.
333 */
334SkTypeface* SkCreateFontMemResourceTypefaceFromLOGFONT(const LOGFONT& origLF, HANDLE fontMemResource) {
335 LOGFONT lf = origLF;
336 make_canonical(&lf);
mtklein60b6e9d2014-10-24 10:43:15 -0700337 // We'll never get a cache hit, so no point in putting this in SkTypefaceCache.
338 return FontMemResourceTypeface::Create(lf, fontMemResource);
bungeman@google.coma5501992012-05-18 19:06:41 +0000339}
340
341/**
reed@google.comdb77a6a2011-07-19 19:08:33 +0000342 * This guy is public
343 */
344void SkLOGFONTFromTypeface(const SkTypeface* face, LOGFONT* lf) {
halcanary96fcdcc2015-08-27 07:41:13 -0700345 if (nullptr == face) {
reed@google.comdb77a6a2011-07-19 19:08:33 +0000346 *lf = get_default_font();
347 } else {
bungeman@google.coma5501992012-05-18 19:06:41 +0000348 *lf = static_cast<const LogFontTypeface*>(face)->fLogFont;
reed@google.comdb77a6a2011-07-19 19:08:33 +0000349 }
350}
351
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000352// Construct Glyph to Unicode table.
353// Unicode code points that require conjugate pairs in utf16 are not
354// supported.
355// TODO(arthurhsu): Add support for conjugate pairs. It looks like that may
356// require parsing the TTF cmap table (platform 4, encoding 12) directly instead
357// of calling GetFontUnicodeRange().
358static void populate_glyph_to_unicode(HDC fontHdc, const unsigned glyphCount,
359 SkTDArray<SkUnichar>* glyphToUnicode) {
halcanary96fcdcc2015-08-27 07:41:13 -0700360 DWORD glyphSetBufferSize = GetFontUnicodeRanges(fontHdc, nullptr);
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000361 if (!glyphSetBufferSize) {
362 return;
363 }
364
365 SkAutoTDeleteArray<BYTE> glyphSetBuffer(new BYTE[glyphSetBufferSize]);
366 GLYPHSET* glyphSet =
367 reinterpret_cast<LPGLYPHSET>(glyphSetBuffer.get());
368 if (GetFontUnicodeRanges(fontHdc, glyphSet) != glyphSetBufferSize) {
369 return;
370 }
371
372 glyphToUnicode->setCount(glyphCount);
373 memset(glyphToUnicode->begin(), 0, glyphCount * sizeof(SkUnichar));
374 for (DWORD i = 0; i < glyphSet->cRanges; ++i) {
375 // There is no guarantee that within a Unicode range, the corresponding
376 // glyph id in a font file are continuous. So, even if we have ranges,
377 // we can't just use the first and last entry of the range to compute
378 // result. We need to enumerate them one by one.
379 int count = glyphSet->ranges[i].cGlyphs;
380 SkAutoTArray<WCHAR> chars(count + 1);
381 chars[count] = 0; // termintate string
382 SkAutoTArray<WORD> glyph(count);
383 for (USHORT j = 0; j < count; ++j) {
384 chars[j] = glyphSet->ranges[i].wcLow + j;
385 }
386 GetGlyphIndicesW(fontHdc, chars.get(), count, glyph.get(),
387 GGI_MARK_NONEXISTING_GLYPHS);
388 // If the glyph ID is valid, and the glyph is not mapped, then we will
389 // fill in the char id into the vector. If the glyph is mapped already,
390 // skip it.
391 // TODO(arthurhsu): better improve this. e.g. Get all used char ids from
392 // font cache, then generate this mapping table from there. It's
393 // unlikely to have collisions since glyph reuse happens mostly for
394 // different Unicode pages.
395 for (USHORT j = 0; j < count; ++j) {
396 if (glyph[j] != 0xffff && glyph[j] < glyphCount &&
397 (*glyphToUnicode)[glyph[j]] == 0) {
398 (*glyphToUnicode)[glyph[j]] = chars[j];
399 }
400 }
401 }
402}
403
reed@google.com99edd432011-09-09 14:59:59 +0000404//////////////////////////////////////////////////////////////////////////////////////
405
406static int alignTo32(int n) {
407 return (n + 31) & ~31;
408}
409
410struct MyBitmapInfo : public BITMAPINFO {
411 RGBQUAD fMoreSpaceForColors[1];
412};
413
414class HDCOffscreen {
415public:
416 HDCOffscreen() {
417 fFont = 0;
418 fDC = 0;
419 fBM = 0;
halcanary96fcdcc2015-08-27 07:41:13 -0700420 fBits = nullptr;
reed@google.com99edd432011-09-09 14:59:59 +0000421 fWidth = fHeight = 0;
422 fIsBW = false;
423 }
424
425 ~HDCOffscreen() {
426 if (fDC) {
427 DeleteDC(fDC);
428 }
429 if (fBM) {
430 DeleteObject(fBM);
431 }
432 }
433
434 void init(HFONT font, const XFORM& xform) {
435 fFont = font;
436 fXform = xform;
437 }
438
bungeman@google.com97efada2012-07-30 20:40:50 +0000439 const void* draw(const SkGlyph&, bool isBW, size_t* srcRBPtr);
reed@google.com99edd432011-09-09 14:59:59 +0000440
441private:
442 HDC fDC;
443 HBITMAP fBM;
444 HFONT fFont;
445 XFORM fXform;
446 void* fBits; // points into fBM
447 int fWidth;
448 int fHeight;
449 bool fIsBW;
450};
451
reed@google.com754e4eb2011-09-26 13:21:39 +0000452const void* HDCOffscreen::draw(const SkGlyph& glyph, bool isBW,
bungeman@google.com97efada2012-07-30 20:40:50 +0000453 size_t* srcRBPtr) {
reed@google.com84e22d82013-07-10 15:38:20 +0000454 // Can we share the scalercontext's fDDC, so we don't need to create
455 // a separate fDC here?
reed@google.com99edd432011-09-09 14:59:59 +0000456 if (0 == fDC) {
457 fDC = CreateCompatibleDC(0);
458 if (0 == fDC) {
halcanary96fcdcc2015-08-27 07:41:13 -0700459 return nullptr;
reed@google.com99edd432011-09-09 14:59:59 +0000460 }
461 SetGraphicsMode(fDC, GM_ADVANCED);
462 SetBkMode(fDC, TRANSPARENT);
463 SetTextAlign(fDC, TA_LEFT | TA_BASELINE);
464 SelectObject(fDC, fFont);
bungeman@google.com97efada2012-07-30 20:40:50 +0000465
466 COLORREF color = 0x00FFFFFF;
bsalomon@google.comb58a6392013-03-21 20:29:05 +0000467 SkDEBUGCODE(COLORREF prev =) SetTextColor(fDC, color);
bungeman@google.com97efada2012-07-30 20:40:50 +0000468 SkASSERT(prev != CLR_INVALID);
reed@google.com99edd432011-09-09 14:59:59 +0000469 }
470
471 if (fBM && (fIsBW != isBW || fWidth < glyph.fWidth || fHeight < glyph.fHeight)) {
472 DeleteObject(fBM);
473 fBM = 0;
474 }
reed@google.com754e4eb2011-09-26 13:21:39 +0000475 fIsBW = isBW;
reed@google.com99edd432011-09-09 14:59:59 +0000476
reed@google.com99edd432011-09-09 14:59:59 +0000477 fWidth = SkMax32(fWidth, glyph.fWidth);
478 fHeight = SkMax32(fHeight, glyph.fHeight);
479
480 int biWidth = isBW ? alignTo32(fWidth) : fWidth;
481
482 if (0 == fBM) {
483 MyBitmapInfo info;
484 sk_bzero(&info, sizeof(info));
485 if (isBW) {
486 RGBQUAD blackQuad = { 0, 0, 0, 0 };
487 RGBQUAD whiteQuad = { 0xFF, 0xFF, 0xFF, 0 };
488 info.bmiColors[0] = blackQuad;
489 info.bmiColors[1] = whiteQuad;
490 }
491 info.bmiHeader.biSize = sizeof(info.bmiHeader);
492 info.bmiHeader.biWidth = biWidth;
493 info.bmiHeader.biHeight = fHeight;
494 info.bmiHeader.biPlanes = 1;
495 info.bmiHeader.biBitCount = isBW ? 1 : 32;
496 info.bmiHeader.biCompression = BI_RGB;
497 if (isBW) {
498 info.bmiHeader.biClrUsed = 2;
499 }
500 fBM = CreateDIBSection(fDC, &info, DIB_RGB_COLORS, &fBits, 0, 0);
501 if (0 == fBM) {
halcanary96fcdcc2015-08-27 07:41:13 -0700502 return nullptr;
reed@google.com99edd432011-09-09 14:59:59 +0000503 }
504 SelectObject(fDC, fBM);
505 }
506
507 // erase
508 size_t srcRB = isBW ? (biWidth >> 3) : (fWidth << 2);
509 size_t size = fHeight * srcRB;
bungeman@google.com97efada2012-07-30 20:40:50 +0000510 memset(fBits, 0, size);
reed@google.com99edd432011-09-09 14:59:59 +0000511
512 XFORM xform = fXform;
513 xform.eDx = (float)-glyph.fLeft;
514 xform.eDy = (float)-glyph.fTop;
515 SetWorldTransform(fDC, &xform);
516
517 uint16_t glyphID = glyph.getGlyphID();
halcanary96fcdcc2015-08-27 07:41:13 -0700518 BOOL ret = ExtTextOutW(fDC, 0, 0, ETO_GLYPH_INDEX, nullptr, reinterpret_cast<LPCWSTR>(&glyphID), 1, nullptr);
reed@google.com99edd432011-09-09 14:59:59 +0000519 GdiFlush();
bungeman@google.com39698b12011-11-15 22:26:41 +0000520 if (0 == ret) {
halcanary96fcdcc2015-08-27 07:41:13 -0700521 return nullptr;
bungeman@google.com39698b12011-11-15 22:26:41 +0000522 }
reed@google.com99edd432011-09-09 14:59:59 +0000523 *srcRBPtr = srcRB;
524 // offset to the start of the image
525 return (const char*)fBits + (fHeight - glyph.fHeight) * srcRB;
526}
527
reed@google.comb8a5c612012-06-13 20:01:44 +0000528//////////////////////////////////////////////////////////////////////////////
bungeman@google.com0abbff92013-07-27 20:37:56 +0000529#define BUFFERSIZE (1 << 13)
reed@google.com59d2f632011-05-02 19:36:59 +0000530
reed@google.com30ddd612013-07-30 17:47:39 +0000531class SkScalerContext_GDI : public SkScalerContext {
reed@google.comac6b9792011-03-11 15:42:51 +0000532public:
reeda9322c22016-04-12 06:47:05 -0700533 SkScalerContext_GDI(SkTypeface*, const SkScalerContextEffects&, const SkDescriptor* desc);
reed@google.com30ddd612013-07-30 17:47:39 +0000534 virtual ~SkScalerContext_GDI();
reed@google.comac6b9792011-03-11 15:42:51 +0000535
reed@google.com84e22d82013-07-10 15:38:20 +0000536 // Returns true if the constructor was able to complete all of its
537 // initializations (which may include calling GDI).
538 bool isValid() const;
539
reed@google.comac6b9792011-03-11 15:42:51 +0000540protected:
mtklein36352bf2015-03-25 18:17:31 -0700541 unsigned generateGlyphCount() override;
542 uint16_t generateCharToGlyph(SkUnichar uni) override;
543 void generateAdvance(SkGlyph* glyph) override;
544 void generateMetrics(SkGlyph* glyph) override;
545 void generateImage(const SkGlyph& glyph) override;
546 void generatePath(const SkGlyph& glyph, SkPath* path) override;
547 void generateFontMetrics(SkPaint::FontMetrics*) override;
reed@google.com99edd432011-09-09 14:59:59 +0000548
reed@google.comac6b9792011-03-11 15:42:51 +0000549private:
bungeman@google.com0abbff92013-07-27 20:37:56 +0000550 DWORD getGDIGlyphPath(const SkGlyph& glyph, UINT flags,
551 SkAutoSTMalloc<BUFFERSIZE, uint8_t>* glyphbuf);
552
reed@google.com99edd432011-09-09 14:59:59 +0000553 HDCOffscreen fOffscreen;
bungeman@google.com0abbff92013-07-27 20:37:56 +0000554 /** fGsA is the non-rotational part of total matrix without the text height scale.
555 * Used to find the magnitude of advances.
556 */
557 MAT2 fGsA;
bungeman@google.com6a774a12013-07-30 01:07:48 +0000558 /** The total matrix without the textSize. */
reed@google.comac6b9792011-03-11 15:42:51 +0000559 MAT2 fMat22;
bungeman@google.com6a774a12013-07-30 01:07:48 +0000560 /** Scales font to EM size. */
561 MAT2 fHighResMat22;
reed@google.comac6b9792011-03-11 15:42:51 +0000562 HDC fDDC;
563 HFONT fSavefont;
564 HFONT fFont;
565 SCRIPT_CACHE fSC;
566 int fGlyphCount;
reed@google.com1dd17a12011-05-17 14:04:41 +0000567
bungeman@google.com6a774a12013-07-30 01:07:48 +0000568 /** The total matrix which also removes EM scale. */
reed@google.com1dd17a12011-05-17 14:04:41 +0000569 SkMatrix fHiResMatrix;
bungeman@google.com0abbff92013-07-27 20:37:56 +0000570 /** fG_inv is the inverse of the rotational part of the total matrix.
571 * Used to set the direction of advances.
572 */
573 SkMatrix fG_inv;
bungeman@google.coma0319f62012-04-18 15:40:50 +0000574 enum Type {
bungeman@google.com4732df62014-01-23 15:22:42 +0000575 kTrueType_Type, kBitmap_Type, kLine_Type
bungeman@google.coma0319f62012-04-18 15:40:50 +0000576 } fType;
577 TEXTMETRIC fTM;
reed@google.comac6b9792011-03-11 15:42:51 +0000578};
579
reed@google.comac6b9792011-03-11 15:42:51 +0000580static FIXED float2FIXED(float x) {
581 return SkFixedToFIXED(SkFloatToFixed(x));
582}
583
benjaminwagner6b3eacb2016-03-24 19:07:58 -0700584static inline float FIXED2float(FIXED x) {
585 return SkFixedToFloat(SkFIXEDToFixed(x));
586}
587
reed@google.com82a34d82011-07-26 19:33:08 +0000588static BYTE compute_quality(const SkScalerContext::Rec& rec) {
589 switch (rec.fMaskFormat) {
590 case SkMask::kBW_Format:
591 return NONANTIALIASED_QUALITY;
592 case SkMask::kLCD16_Format:
reed@google.com82a34d82011-07-26 19:33:08 +0000593 return CLEARTYPE_QUALITY;
594 default:
reed@google.com8351aab2012-01-18 17:06:35 +0000595 if (rec.fFlags & SkScalerContext::kGenA8FromLCD_Flag) {
596 return CLEARTYPE_QUALITY;
597 } else {
598 return ANTIALIASED_QUALITY;
599 }
reed@google.com82a34d82011-07-26 19:33:08 +0000600 }
601}
602
reed@google.com30ddd612013-07-30 17:47:39 +0000603SkScalerContext_GDI::SkScalerContext_GDI(SkTypeface* rawTypeface,
reeda9322c22016-04-12 06:47:05 -0700604 const SkScalerContextEffects& effects,
605 const SkDescriptor* desc)
606 : SkScalerContext(rawTypeface, effects, desc)
reed@google.com055180c2013-03-21 18:46:35 +0000607 , fDDC(0)
reed@google.com055180c2013-03-21 18:46:35 +0000608 , fSavefont(0)
reed@google.com84e22d82013-07-10 15:38:20 +0000609 , fFont(0)
reed@google.com055180c2013-03-21 18:46:35 +0000610 , fSC(0)
bungeman@google.com05a729f2013-06-20 15:29:16 +0000611 , fGlyphCount(-1)
612{
reed@google.com055180c2013-03-21 18:46:35 +0000613 LogFontTypeface* typeface = reinterpret_cast<LogFontTypeface*>(rawTypeface);
614
halcanary96fcdcc2015-08-27 07:41:13 -0700615 fDDC = ::CreateCompatibleDC(nullptr);
reed@google.com84e22d82013-07-10 15:38:20 +0000616 if (!fDDC) {
617 return;
618 }
reed@google.com1dd17a12011-05-17 14:04:41 +0000619 SetGraphicsMode(fDDC, GM_ADVANCED);
reed@google.comac6b9792011-03-11 15:42:51 +0000620 SetBkMode(fDDC, TRANSPARENT);
skia.committer@gmail.com27e21fe2013-07-28 07:01:03 +0000621
bungeman6f940762015-03-18 08:25:43 -0700622 // When GDI hinting, remove the entire Y scale from sA and GsA. (Prevents 'linear' metrics.)
623 // When not hinting, remove only the integer Y scale from sA and GsA. (Applied by GDI.)
bungeman5f14c5e2014-12-05 12:26:44 -0800624 SkScalerContextRec::PreMatrixScale scaleConstraints =
625 (fRec.getHinting() == SkPaint::kNo_Hinting || fRec.getHinting() == SkPaint::kSlight_Hinting)
626 ? SkScalerContextRec::kVerticalInteger_PreMatrixScale
627 : SkScalerContextRec::kVertical_PreMatrixScale;
628 SkVector scale;
629 SkMatrix sA;
630 SkMatrix GsA;
631 SkMatrix A;
632 fRec.computeMatrices(scaleConstraints, &scale, &sA, &GsA, &fG_inv, &A);
bungeman@google.com0abbff92013-07-27 20:37:56 +0000633
634 fGsA.eM11 = SkScalarToFIXED(GsA.get(SkMatrix::kMScaleX));
635 fGsA.eM12 = SkScalarToFIXED(-GsA.get(SkMatrix::kMSkewY)); // This should be ~0.
636 fGsA.eM21 = SkScalarToFIXED(-GsA.get(SkMatrix::kMSkewX));
637 fGsA.eM22 = SkScalarToFIXED(GsA.get(SkMatrix::kMScaleY));
638
bungeman6f940762015-03-18 08:25:43 -0700639 // When not hinting, scale was computed with kVerticalInteger, so is already an integer.
640 // The sA and GsA transforms will be used to create 'linear' metrics.
641
642 // When hinting, scale was computed with kVertical, stating that our port can handle
643 // non-integer scales. This is done so that sA and GsA are computed without any 'residual'
644 // scale in them, preventing 'linear' metrics. However, GDI cannot actually handle non-integer
645 // scales so we need to round in this case. This is fine, since all of the scale has been
646 // removed from sA and GsA, so GDI will be handling the scale completely.
647 SkScalar gdiTextSize = SkScalarRoundToScalar(scale.fY);
648
649 // GDI will not accept a size of zero, so round the range [0, 1] to 1.
650 // If the size was non-zero, the scale factors will also be non-zero and 1px tall text is drawn.
651 // If the size actually was zero, the scale factors will also be zero, so GDI will draw nothing.
bungeman5f14c5e2014-12-05 12:26:44 -0800652 if (gdiTextSize == 0) {
653 gdiTextSize = SK_Scalar1;
654 }
bungeman@google.com0abbff92013-07-27 20:37:56 +0000655
reed@google.com055180c2013-03-21 18:46:35 +0000656 LOGFONT lf = typeface->fLogFont;
bungeman@google.com11ba3192013-10-03 20:17:51 +0000657 lf.lfHeight = -SkScalarTruncToInt(gdiTextSize);
reed@google.com82a34d82011-07-26 19:33:08 +0000658 lf.lfQuality = compute_quality(fRec);
reed@google.comac6b9792011-03-11 15:42:51 +0000659 fFont = CreateFontIndirect(&lf);
reed@google.com84e22d82013-07-10 15:38:20 +0000660 if (!fFont) {
661 return;
662 }
reed@google.com1dd17a12011-05-17 14:04:41 +0000663
reed@google.comac6b9792011-03-11 15:42:51 +0000664 fSavefont = (HFONT)SelectObject(fDDC, fFont);
reed@google.coma767fa02011-08-05 21:40:26 +0000665
bungeman@google.coma0319f62012-04-18 15:40:50 +0000666 if (0 == GetTextMetrics(fDDC, &fTM)) {
reed@google.com055180c2013-03-21 18:46:35 +0000667 call_ensure_accessible(lf);
bungeman@google.coma0319f62012-04-18 15:40:50 +0000668 if (0 == GetTextMetrics(fDDC, &fTM)) {
669 fTM.tmPitchAndFamily = TMPF_TRUETYPE;
670 }
671 }
bungeman@google.com90b7e382012-04-20 15:26:28 +0000672
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000673 XFORM xform;
bungeman@google.com90b7e382012-04-20 15:26:28 +0000674 if (fTM.tmPitchAndFamily & TMPF_VECTOR) {
bungeman@google.com4732df62014-01-23 15:22:42 +0000675 // Used a logfont on a memory context, should never get a device font.
676 // Therefore all TMPF_DEVICE will be PostScript fonts.
677
678 // If TMPF_VECTOR is set, one of TMPF_TRUETYPE or TMPF_DEVICE means that
679 // we have an outline font. Otherwise we have a vector FON, which is
680 // scalable, but not an outline font.
681 // This was determined by testing with Type1 PFM/PFB and
682 // OpenTypeCFF OTF, as well as looking at Wine bugs and sources.
683 if (fTM.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_DEVICE)) {
684 // Truetype or PostScript.
685 fType = SkScalerContext_GDI::kTrueType_Type;
686 } else {
687 // Stroked FON.
688 fType = SkScalerContext_GDI::kLine_Type;
689 }
bungeman@google.coma0319f62012-04-18 15:40:50 +0000690
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000691 // fPost2x2 is column-major, left handed (y down).
692 // XFORM 2x2 is row-major, left handed (y down).
bungeman@google.com0abbff92013-07-27 20:37:56 +0000693 xform.eM11 = SkScalarToFloat(sA.get(SkMatrix::kMScaleX));
694 xform.eM12 = SkScalarToFloat(sA.get(SkMatrix::kMSkewY));
695 xform.eM21 = SkScalarToFloat(sA.get(SkMatrix::kMSkewX));
696 xform.eM22 = SkScalarToFloat(sA.get(SkMatrix::kMScaleY));
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000697 xform.eDx = 0;
698 xform.eDy = 0;
bungeman@google.coma0319f62012-04-18 15:40:50 +0000699
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000700 // MAT2 is row major, right handed (y up).
701 fMat22.eM11 = float2FIXED(xform.eM11);
702 fMat22.eM12 = float2FIXED(-xform.eM12);
703 fMat22.eM21 = float2FIXED(-xform.eM21);
704 fMat22.eM22 = float2FIXED(xform.eM22);
bungeman@google.coma0319f62012-04-18 15:40:50 +0000705
706 if (needToRenderWithSkia(fRec)) {
707 this->forceGenerateImageFromPath();
708 }
709
bungeman@google.com11ba3192013-10-03 20:17:51 +0000710 // Create a hires matrix if we need linear metrics.
bungeman@google.com0abbff92013-07-27 20:37:56 +0000711 if (this->isSubpixel()) {
712 OUTLINETEXTMETRIC otm;
713 UINT success = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
714 if (0 == success) {
715 call_ensure_accessible(lf);
716 success = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
717 }
718 if (0 != success) {
bungeman@google.com11ba3192013-10-03 20:17:51 +0000719 SkScalar upem = SkIntToScalar(otm.otmEMSquare);
bungeman@google.com0abbff92013-07-27 20:37:56 +0000720
bungeman@google.com11ba3192013-10-03 20:17:51 +0000721 SkScalar gdiTextSizeToEMScale = upem / gdiTextSize;
722 fHighResMat22.eM11 = float2FIXED(gdiTextSizeToEMScale);
bungeman@google.com6a774a12013-07-30 01:07:48 +0000723 fHighResMat22.eM12 = float2FIXED(0);
724 fHighResMat22.eM21 = float2FIXED(0);
bungeman@google.com11ba3192013-10-03 20:17:51 +0000725 fHighResMat22.eM22 = float2FIXED(gdiTextSizeToEMScale);
bungeman@google.com6a774a12013-07-30 01:07:48 +0000726
bungeman@google.com11ba3192013-10-03 20:17:51 +0000727 SkScalar removeEMScale = SkScalarInvert(upem);
bungeman@google.com6a774a12013-07-30 01:07:48 +0000728 fHiResMatrix = A;
bungeman@google.com11ba3192013-10-03 20:17:51 +0000729 fHiResMatrix.preScale(removeEMScale, removeEMScale);
bungeman@google.com0abbff92013-07-27 20:37:56 +0000730 }
731 }
732
bungeman@google.coma0319f62012-04-18 15:40:50 +0000733 } else {
734 // Assume bitmap
reed@google.com30ddd612013-07-30 17:47:39 +0000735 fType = SkScalerContext_GDI::kBitmap_Type;
bungeman@google.coma0319f62012-04-18 15:40:50 +0000736
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000737 xform.eM11 = 1.0f;
738 xform.eM12 = 0.0f;
739 xform.eM21 = 0.0f;
740 xform.eM22 = 1.0f;
741 xform.eDx = 0.0f;
742 xform.eDy = 0.0f;
bungeman@google.coma0319f62012-04-18 15:40:50 +0000743
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000744 // fPost2x2 is column-major, left handed (y down).
745 // MAT2 is row major, right handed (y up).
bungeman@google.coma0319f62012-04-18 15:40:50 +0000746 fMat22.eM11 = SkScalarToFIXED(fRec.fPost2x2[0][0]);
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000747 fMat22.eM12 = SkScalarToFIXED(-fRec.fPost2x2[1][0]);
bungeman@google.coma0319f62012-04-18 15:40:50 +0000748 fMat22.eM21 = SkScalarToFIXED(-fRec.fPost2x2[0][1]);
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000749 fMat22.eM22 = SkScalarToFIXED(fRec.fPost2x2[1][1]);
reed@google.coma767fa02011-08-05 21:40:26 +0000750 }
reed@google.com99edd432011-09-09 14:59:59 +0000751
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000752 fOffscreen.init(fFont, xform);
reed@google.comac6b9792011-03-11 15:42:51 +0000753}
754
reed@google.com30ddd612013-07-30 17:47:39 +0000755SkScalerContext_GDI::~SkScalerContext_GDI() {
reed@google.comac6b9792011-03-11 15:42:51 +0000756 if (fDDC) {
757 ::SelectObject(fDDC, fSavefont);
758 ::DeleteDC(fDDC);
759 }
760 if (fFont) {
761 ::DeleteObject(fFont);
762 }
763 if (fSC) {
764 ::ScriptFreeCache(&fSC);
765 }
766}
767
reed@google.com30ddd612013-07-30 17:47:39 +0000768bool SkScalerContext_GDI::isValid() const {
reed@google.com84e22d82013-07-10 15:38:20 +0000769 return fDDC && fFont;
770}
771
reed@google.com30ddd612013-07-30 17:47:39 +0000772unsigned SkScalerContext_GDI::generateGlyphCount() {
reed@google.comac6b9792011-03-11 15:42:51 +0000773 if (fGlyphCount < 0) {
bungeman@google.com7bdd6142013-07-15 19:42:57 +0000774 fGlyphCount = calculateGlyphCount(
775 fDDC, static_cast<const LogFontTypeface*>(this->getTypeface())->fLogFont);
reed@google.comac6b9792011-03-11 15:42:51 +0000776 }
777 return fGlyphCount;
778}
779
bungeman@google.com33346482013-08-27 19:05:32 +0000780uint16_t SkScalerContext_GDI::generateCharToGlyph(SkUnichar utf32) {
reed@google.comac6b9792011-03-11 15:42:51 +0000781 uint16_t index = 0;
bungeman@google.com33346482013-08-27 19:05:32 +0000782 WCHAR utf16[2];
reed@google.comac6b9792011-03-11 15:42:51 +0000783 // TODO(ctguil): Support characters that generate more than one glyph.
bungeman@google.com33346482013-08-27 19:05:32 +0000784 if (SkUTF16_FromUnichar(utf32, (uint16_t*)utf16) == 1) {
reed@google.comac6b9792011-03-11 15:42:51 +0000785 // Type1 fonts fail with uniscribe API. Use GetGlyphIndices for plane 0.
skia.committer@gmail.com7bd141d2013-08-28 07:01:18 +0000786
bungeman@google.com33346482013-08-27 19:05:32 +0000787 /** Real documentation for GetGlyphIndiciesW:
788 *
789 * When GGI_MARK_NONEXISTING_GLYPHS is not specified and a character does not map to a
790 * glyph, then the 'default character's glyph is returned instead. The 'default character'
bungeman@google.com4732df62014-01-23 15:22:42 +0000791 * is available in fTM.tmDefaultChar. FON fonts have a default character, and there exists
792 * a usDefaultChar in the 'OS/2' table, version 2 and later. If there is no
bungeman@google.com33346482013-08-27 19:05:32 +0000793 * 'default character' specified by the font, then often the first character found is used.
794 *
795 * When GGI_MARK_NONEXISTING_GLYPHS is specified and a character does not map to a glyph,
796 * then the glyph 0xFFFF is used. In Windows XP and earlier, Bitmap/Vector FON usually use
797 * glyph 0x1F instead ('Terminal' appears to be special, returning 0xFFFF).
798 * Type1 PFM/PFB, TT, OT TT, OT CFF all appear to use 0xFFFF, even on XP.
799 */
800 DWORD result = GetGlyphIndicesW(fDDC, utf16, 1, &index, GGI_MARK_NONEXISTING_GLYPHS);
801 if (result == GDI_ERROR
802 || 0xFFFF == index
bungeman@google.com4732df62014-01-23 15:22:42 +0000803 || (0x1F == index &&
804 (fType == SkScalerContext_GDI::kBitmap_Type ||
805 fType == SkScalerContext_GDI::kLine_Type)
806 /*&& winVer < Vista */)
807 )
bungeman@google.com33346482013-08-27 19:05:32 +0000808 {
809 index = 0;
810 }
reed@google.comac6b9792011-03-11 15:42:51 +0000811 } else {
812 // Use uniscribe to detemine glyph index for non-BMP characters.
bungeman@google.com27f74aa2013-10-08 21:32:15 +0000813 static const int numWCHAR = 2;
814 static const int maxItems = 2;
halcanary96fcdcc2015-08-27 07:41:13 -0700815 // MSDN states that this can be nullptr, but some things don't work then.
bungeman@google.com27f74aa2013-10-08 21:32:15 +0000816 SCRIPT_CONTROL sc = { 0 };
817 // Add extra item to SCRIPT_ITEM to work around a bug (now documented).
818 // https://bugzilla.mozilla.org/show_bug.cgi?id=366643
819 SCRIPT_ITEM si[maxItems + 1];
820 int numItems;
halcanary96fcdcc2015-08-27 07:41:13 -0700821 HRZM(ScriptItemize(utf16, numWCHAR, maxItems, &sc, nullptr, si, &numItems),
bungeman@google.com27f74aa2013-10-08 21:32:15 +0000822 "Could not itemize character.");
reed@google.comac6b9792011-03-11 15:42:51 +0000823
bungeman@google.com27f74aa2013-10-08 21:32:15 +0000824 // Sometimes ScriptShape cannot find a glyph for a non-BMP and returns 2 space glyphs.
825 static const int maxGlyphs = 2;
826 SCRIPT_VISATTR vsa[maxGlyphs];
827 WORD outGlyphs[maxGlyphs];
828 WORD logClust[numWCHAR];
829 int numGlyphs;
830 HRZM(ScriptShape(fDDC, &fSC, utf16, numWCHAR, maxGlyphs, &si[0].a,
831 outGlyphs, logClust, vsa, &numGlyphs),
832 "Could not shape character.");
833 if (1 == numGlyphs) {
834 index = outGlyphs[0];
835 }
reed@google.comac6b9792011-03-11 15:42:51 +0000836 }
837 return index;
838}
839
reed@google.com30ddd612013-07-30 17:47:39 +0000840void SkScalerContext_GDI::generateAdvance(SkGlyph* glyph) {
reed@google.comac6b9792011-03-11 15:42:51 +0000841 this->generateMetrics(glyph);
842}
843
reed@google.com30ddd612013-07-30 17:47:39 +0000844void SkScalerContext_GDI::generateMetrics(SkGlyph* glyph) {
reed@google.comac6b9792011-03-11 15:42:51 +0000845 SkASSERT(fDDC);
846
bungeman@google.com4732df62014-01-23 15:22:42 +0000847 if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) {
bungeman@google.coma0319f62012-04-18 15:40:50 +0000848 SIZE size;
djsollen1b277042014-08-06 06:58:06 -0700849 WORD glyphs = glyph->getGlyphID();
bungeman@google.coma0319f62012-04-18 15:40:50 +0000850 if (0 == GetTextExtentPointI(fDDC, &glyphs, 1, &size)) {
851 glyph->fWidth = SkToS16(fTM.tmMaxCharWidth);
852 } else {
853 glyph->fWidth = SkToS16(size.cx);
854 }
855 glyph->fHeight = SkToS16(size.cy);
856
857 glyph->fTop = SkToS16(-fTM.tmAscent);
bungeman@google.com4732df62014-01-23 15:22:42 +0000858 // Bitmap FON cannot underhang, but vector FON may.
859 // There appears no means of determining underhang of vector FON.
bungeman@google.coma0319f62012-04-18 15:40:50 +0000860 glyph->fLeft = SkToS16(0);
benjaminwagner6b3eacb2016-03-24 19:07:58 -0700861 glyph->fAdvanceX = glyph->fWidth;
bungeman@google.coma0319f62012-04-18 15:40:50 +0000862 glyph->fAdvanceY = 0;
863
bungeman@google.com4732df62014-01-23 15:22:42 +0000864 // Vector FON will transform nicely, but bitmap FON do not.
865 if (fType == SkScalerContext_GDI::kLine_Type) {
866 SkRect bounds = SkRect::MakeXYWH(glyph->fLeft, glyph->fTop,
867 glyph->fWidth, glyph->fHeight);
868 SkMatrix m;
869 m.setAll(SkFIXEDToScalar(fMat22.eM11), -SkFIXEDToScalar(fMat22.eM21), 0,
870 -SkFIXEDToScalar(fMat22.eM12), SkFIXEDToScalar(fMat22.eM22), 0,
reed3f43f8a2015-01-20 19:58:36 -0800871 0, 0, 1);
bungeman@google.com4732df62014-01-23 15:22:42 +0000872 m.mapRect(&bounds);
reedd02cf262014-11-18 18:06:45 -0800873 bounds.roundOut(&bounds);
bungeman@google.com4732df62014-01-23 15:22:42 +0000874 glyph->fLeft = SkScalarTruncToInt(bounds.fLeft);
875 glyph->fTop = SkScalarTruncToInt(bounds.fTop);
876 glyph->fWidth = SkScalarTruncToInt(bounds.width());
877 glyph->fHeight = SkScalarTruncToInt(bounds.height());
878 }
879
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000880 // Apply matrix to advance.
benjaminwagner6b3eacb2016-03-24 19:07:58 -0700881 glyph->fAdvanceY = -FIXED2float(fMat22.eM12) * glyph->fAdvanceX;
882 glyph->fAdvanceX *= FIXED2float(fMat22.eM11);
bungeman@google.coma0319f62012-04-18 15:40:50 +0000883
884 return;
885 }
886
djsollen1b277042014-08-06 06:58:06 -0700887 UINT glyphId = glyph->getGlyphID();
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000888
reed@google.comac6b9792011-03-11 15:42:51 +0000889 GLYPHMETRICS gm;
reed@google.com1dd17a12011-05-17 14:04:41 +0000890 sk_bzero(&gm, sizeof(gm));
reed@google.comac6b9792011-03-11 15:42:51 +0000891
halcanary96fcdcc2015-08-27 07:41:13 -0700892 DWORD status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, nullptr, &fMat22);
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000893 if (GDI_ERROR == status) {
reed@google.com055180c2013-03-21 18:46:35 +0000894 LogFontTypeface::EnsureAccessible(this->getTypeface());
halcanary96fcdcc2015-08-27 07:41:13 -0700895 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, nullptr, &fMat22);
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000896 if (GDI_ERROR == status) {
897 glyph->zeroMetrics();
898 return;
899 }
900 }
901
902 bool empty = false;
903 // The black box is either the embedded bitmap size or the outline extent.
904 // It is 1x1 if nothing is to be drawn, but will also be 1x1 if something very small
905 // is to be drawn, like a '.'. We need to outset '.' but do not wish to outset ' '.
906 if (1 == gm.gmBlackBoxX && 1 == gm.gmBlackBoxY) {
907 // If GetGlyphOutline with GGO_NATIVE returns 0, we know there was no outline.
halcanary96fcdcc2015-08-27 07:41:13 -0700908 DWORD bufferSize = GetGlyphOutlineW(fDDC, glyphId, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, 0, nullptr, &fMat22);
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000909 empty = (0 == bufferSize);
910 }
911
912 glyph->fTop = SkToS16(-gm.gmptGlyphOrigin.y);
913 glyph->fLeft = SkToS16(gm.gmptGlyphOrigin.x);
914 if (empty) {
915 glyph->fWidth = 0;
916 glyph->fHeight = 0;
917 } else {
918 // Outset, since the image may bleed out of the black box.
919 // For embedded bitmaps the black box should be exact.
920 // For outlines we need to outset by 1 in all directions for bleed.
921 // For ClearType we need to outset by 2 for bleed.
922 glyph->fWidth = gm.gmBlackBoxX + 4;
923 glyph->fHeight = gm.gmBlackBoxY + 4;
924 glyph->fTop -= 2;
925 glyph->fLeft -= 2;
926 }
benjaminwagner6b3eacb2016-03-24 19:07:58 -0700927 // TODO(benjaminwagner): What is the type of gm.gmCellInc[XY]?
928 glyph->fAdvanceX = (float)((int)gm.gmCellIncX);
929 glyph->fAdvanceY = (float)((int)gm.gmCellIncY);
reed@google.comac6b9792011-03-11 15:42:51 +0000930 glyph->fRsbDelta = 0;
931 glyph->fLsbDelta = 0;
932
bungeman@google.com6a774a12013-07-30 01:07:48 +0000933 if (this->isSubpixel()) {
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000934 sk_bzero(&gm, sizeof(gm));
halcanary96fcdcc2015-08-27 07:41:13 -0700935 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, nullptr, &fHighResMat22);
bungeman@google.comd1c7f712013-03-11 18:51:19 +0000936 if (GDI_ERROR != status) {
937 SkPoint advance;
938 fHiResMatrix.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance);
benjaminwagner6b3eacb2016-03-24 19:07:58 -0700939 glyph->fAdvanceX = SkScalarToFloat(advance.fX);
940 glyph->fAdvanceY = SkScalarToFloat(advance.fY);
reed@google.comac6b9792011-03-11 15:42:51 +0000941 }
bungeman@google.com0abbff92013-07-27 20:37:56 +0000942 } else if (!isAxisAligned(this->fRec)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700943 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, nullptr, &fGsA);
bungeman@google.com0abbff92013-07-27 20:37:56 +0000944 if (GDI_ERROR != status) {
945 SkPoint advance;
946 fG_inv.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance);
benjaminwagner6b3eacb2016-03-24 19:07:58 -0700947 glyph->fAdvanceX = SkScalarToFloat(advance.fX);
948 glyph->fAdvanceY = SkScalarToFloat(advance.fY);
bungeman@google.com0abbff92013-07-27 20:37:56 +0000949 }
reed@google.comac6b9792011-03-11 15:42:51 +0000950 }
951}
952
bungeman@google.com6a774a12013-07-30 01:07:48 +0000953static const MAT2 gMat2Identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
bungeman41078062014-07-07 08:16:37 -0700954void SkScalerContext_GDI::generateFontMetrics(SkPaint::FontMetrics* metrics) {
halcanary96fcdcc2015-08-27 07:41:13 -0700955 if (nullptr == metrics) {
bungeman41078062014-07-07 08:16:37 -0700956 return;
reed@google.com60af92c2013-05-08 14:11:28 +0000957 }
bungeman41078062014-07-07 08:16:37 -0700958 sk_bzero(metrics, sizeof(*metrics));
reed@google.comac6b9792011-03-11 15:42:51 +0000959
960 SkASSERT(fDDC);
961
bungeman@google.come9d83192013-06-21 05:31:38 +0000962#ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
bungeman@google.com4732df62014-01-23 15:22:42 +0000963 if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) {
bungeman@google.come9d83192013-06-21 05:31:38 +0000964#endif
bungeman41078062014-07-07 08:16:37 -0700965 metrics->fTop = SkIntToScalar(-fTM.tmAscent);
966 metrics->fAscent = SkIntToScalar(-fTM.tmAscent);
967 metrics->fDescent = SkIntToScalar(fTM.tmDescent);
968 metrics->fBottom = SkIntToScalar(fTM.tmDescent);
969 metrics->fLeading = SkIntToScalar(fTM.tmExternalLeading);
970 metrics->fAvgCharWidth = SkIntToScalar(fTM.tmAveCharWidth);
971 metrics->fMaxCharWidth = SkIntToScalar(fTM.tmMaxCharWidth);
972 metrics->fXMin = 0;
973 metrics->fXMax = metrics->fMaxCharWidth;
974 //metrics->fXHeight = 0;
bungeman@google.come9d83192013-06-21 05:31:38 +0000975#ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
bungeman@google.coma0319f62012-04-18 15:40:50 +0000976 return;
977 }
bungeman@google.come9d83192013-06-21 05:31:38 +0000978#endif
bungeman@google.coma0319f62012-04-18 15:40:50 +0000979
reed@google.comac6b9792011-03-11 15:42:51 +0000980 OUTLINETEXTMETRIC otm;
981
982 uint32_t ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
bungeman@google.com0abbff92013-07-27 20:37:56 +0000983 if (0 == ret) {
reed@google.com055180c2013-03-21 18:46:35 +0000984 LogFontTypeface::EnsureAccessible(this->getTypeface());
bungeman@google.com39698b12011-11-15 22:26:41 +0000985 ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
986 }
bungeman@google.com0abbff92013-07-27 20:37:56 +0000987 if (0 == ret) {
bungeman@google.coma0319f62012-04-18 15:40:50 +0000988 return;
reed@google.comac6b9792011-03-11 15:42:51 +0000989 }
990
bungeman@google.come9d83192013-06-21 05:31:38 +0000991#ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS
bungeman41078062014-07-07 08:16:37 -0700992 metrics->fTop = SkIntToScalar(-otm.otmrcFontBox.top);
993 metrics->fAscent = SkIntToScalar(-otm.otmAscent);
994 metrics->fDescent = SkIntToScalar(-otm.otmDescent);
995 metrics->fBottom = SkIntToScalar(-otm.otmrcFontBox.bottom);
996 metrics->fLeading = SkIntToScalar(otm.otmLineGap);
997 metrics->fAvgCharWidth = SkIntToScalar(otm.otmTextMetrics.tmAveCharWidth);
998 metrics->fMaxCharWidth = SkIntToScalar(otm.otmTextMetrics.tmMaxCharWidth);
999 metrics->fXMin = SkIntToScalar(otm.otmrcFontBox.left);
1000 metrics->fXMax = SkIntToScalar(otm.otmrcFontBox.right);
commit-bot@chromium.orgd3031aa2014-05-14 14:54:51 +00001001#endif
bungeman41078062014-07-07 08:16:37 -07001002 metrics->fUnderlineThickness = SkIntToScalar(otm.otmsUnderscoreSize);
1003 metrics->fUnderlinePosition = -SkIntToScalar(otm.otmsUnderscorePosition);
commit-bot@chromium.org0bc406d2014-03-01 20:12:26 +00001004
bungeman41078062014-07-07 08:16:37 -07001005 metrics->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag;
1006 metrics->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag;
bungeman@google.com4a867a62014-05-22 17:59:21 +00001007
bungeman41078062014-07-07 08:16:37 -07001008 metrics->fXHeight = SkIntToScalar(otm.otmsXHeight);
1009 GLYPHMETRICS gm;
1010 sk_bzero(&gm, sizeof(gm));
1011 DWORD len = GetGlyphOutlineW(fDDC, 'x', GGO_METRICS, &gm, 0, 0, &gMat2Identity);
1012 if (len != GDI_ERROR && gm.gmBlackBoxY > 0) {
1013 metrics->fXHeight = SkIntToScalar(gm.gmBlackBoxY);
reed@google.comac6b9792011-03-11 15:42:51 +00001014 }
1015}
1016
reed@google.com7430a332011-10-03 14:37:38 +00001017////////////////////////////////////////////////////////////////////////////////////////
1018
bungeman@google.com0abbff92013-07-27 20:37:56 +00001019#define SK_SHOW_TEXT_BLIT_COVERAGE 0
1020
reed@google.com7430a332011-10-03 14:37:38 +00001021static void build_power_table(uint8_t table[], float ee) {
1022 for (int i = 0; i < 256; i++) {
1023 float x = i / 255.f;
bungeman@google.com97efada2012-07-30 20:40:50 +00001024 x = sk_float_pow(x, ee);
reed@google.come1ca7052013-12-17 19:22:07 +00001025 int xx = SkScalarRoundToInt(x * 255);
reed@google.com7430a332011-10-03 14:37:38 +00001026 table[i] = SkToU8(xx);
1027 }
1028}
1029
bungeman@google.com97efada2012-07-30 20:40:50 +00001030/**
1031 * This will invert the gamma applied by GDI (gray-scale antialiased), so we
1032 * can get linear values.
1033 *
1034 * GDI grayscale appears to use a hard-coded gamma of 2.3.
1035 *
1036 * GDI grayscale appears to draw using the black and white rasterizer at four
1037 * times the size and then downsamples to compute the coverage mask. As a
1038 * result there are only seventeen total grays. This lack of fidelity means
1039 * that shifting into other color spaces is imprecise.
1040 */
1041static const uint8_t* getInverseGammaTableGDI() {
bungeman@google.com05a729f2013-06-20 15:29:16 +00001042 // Since build_power_table is idempotent, many threads can build gTableGdi
1043 // simultaneously.
1044
1045 // Microsoft Specific:
1046 // Making gInited volatile provides read-aquire and write-release in vc++.
1047 // In VS2012, see compiler option /volatile:(ms|iso).
1048 // Replace with C++11 atomics when possible.
1049 static volatile bool gInited;
bungeman@google.com97efada2012-07-30 20:40:50 +00001050 static uint8_t gTableGdi[256];
bungeman@google.com05a729f2013-06-20 15:29:16 +00001051 if (gInited) {
1052 // Need a L/L (read) barrier (full acquire not needed). If gInited is observed
1053 // true then gTableGdi is observable, but it must be requested.
1054 } else {
bungeman@google.com97efada2012-07-30 20:40:50 +00001055 build_power_table(gTableGdi, 2.3f);
bungeman@google.com05a729f2013-06-20 15:29:16 +00001056 // Need a S/S (write) barrier (full release not needed) here so that this
1057 // write to gInited becomes observable after gTableGdi.
bungeman@google.com97efada2012-07-30 20:40:50 +00001058 gInited = true;
1059 }
1060 return gTableGdi;
1061}
1062
1063/**
1064 * This will invert the gamma applied by GDI ClearType, so we can get linear
1065 * values.
1066 *
1067 * GDI ClearType uses SPI_GETFONTSMOOTHINGCONTRAST / 1000 as the gamma value.
1068 * If this value is not specified, the default is a gamma of 1.4.
1069 */
1070static const uint8_t* getInverseGammaTableClearType() {
bungeman@google.com05a729f2013-06-20 15:29:16 +00001071 // We don't expect SPI_GETFONTSMOOTHINGCONTRAST to ever change, so building
1072 // gTableClearType with build_power_table is effectively idempotent.
1073
1074 // Microsoft Specific:
1075 // Making gInited volatile provides read-aquire and write-release in vc++.
1076 // In VS2012, see compiler option /volatile:(ms|iso).
1077 // Replace with C++11 atomics when possible.
1078 static volatile bool gInited;
bungeman@google.com97efada2012-07-30 20:40:50 +00001079 static uint8_t gTableClearType[256];
bungeman@google.com05a729f2013-06-20 15:29:16 +00001080 if (gInited) {
1081 // Need a L/L (read) barrier (acquire not needed). If gInited is observed
1082 // true then gTableClearType is observable, but it must be requested.
1083 } else {
reed@google.com7430a332011-10-03 14:37:38 +00001084 UINT level = 0;
1085 if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &level, 0) || !level) {
1086 // can't get the data, so use a default
1087 level = 1400;
1088 }
bungeman@google.com97efada2012-07-30 20:40:50 +00001089 build_power_table(gTableClearType, level / 1000.0f);
bungeman@google.com05a729f2013-06-20 15:29:16 +00001090 // Need a S/S (write) barrier (release not needed) here so that this
1091 // write to gInited becomes observable after gTableClearType.
reed@google.com7430a332011-10-03 14:37:38 +00001092 gInited = true;
1093 }
bungeman@google.com97efada2012-07-30 20:40:50 +00001094 return gTableClearType;
reed@google.com7430a332011-10-03 14:37:38 +00001095}
1096
reed@google.comac6b9792011-03-11 15:42:51 +00001097#include "SkColorPriv.h"
1098
bungeman@google.com63853142012-08-01 15:36:46 +00001099//Cannot assume that the input rgb is gray due to possible setting of kGenA8FromLCD_Flag.
bungeman@google.com97efada2012-07-30 20:40:50 +00001100template<bool APPLY_PREBLEND>
1101static inline uint8_t rgb_to_a8(SkGdiRGB rgb, const uint8_t* table8) {
bungeman@google.com63853142012-08-01 15:36:46 +00001102 U8CPU r = (rgb >> 16) & 0xFF;
1103 U8CPU g = (rgb >> 8) & 0xFF;
1104 U8CPU b = (rgb >> 0) & 0xFF;
bungeman@google.com1bfe01d2012-08-28 16:02:42 +00001105 return sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8);
reed@google.com8351aab2012-01-18 17:06:35 +00001106}
1107
bungeman@google.com97efada2012-07-30 20:40:50 +00001108template<bool APPLY_PREBLEND>
1109static inline uint16_t rgb_to_lcd16(SkGdiRGB rgb, const uint8_t* tableR,
1110 const uint8_t* tableG,
1111 const uint8_t* tableB) {
1112 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
1113 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG);
1114 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB);
bungeman@google.com0abbff92013-07-27 20:37:56 +00001115#if SK_SHOW_TEXT_BLIT_COVERAGE
1116 r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10);
1117#endif
bungeman@google.com97efada2012-07-30 20:40:50 +00001118 return SkPack888ToRGB16(r, g, b);
reed@google.com82a34d82011-07-26 19:33:08 +00001119}
1120
reed@google.com82cff022011-09-22 14:33:40 +00001121// Is this GDI color neither black nor white? If so, we have to keep this
1122// image as is, rather than smashing it down to a BW mask.
1123//
1124// returns int instead of bool, since we don't want/have to pay to convert
1125// the zero/non-zero value into a bool
1126static int is_not_black_or_white(SkGdiRGB c) {
1127 // same as (but faster than)
1128 // c &= 0x00FFFFFF;
1129 // return 0 == c || 0x00FFFFFF == c;
1130 return (c + (c & 1)) & 0x00FFFFFF;
reed@google.com5e2df642011-09-21 18:42:09 +00001131}
1132
bungeman@google.com4b18f572013-07-22 15:21:23 +00001133static bool is_rgb_really_bw(const SkGdiRGB* src, int width, int height, size_t srcRB) {
reed@google.com5e2df642011-09-21 18:42:09 +00001134 for (int y = 0; y < height; ++y) {
1135 for (int x = 0; x < width; ++x) {
reed@google.com82cff022011-09-22 14:33:40 +00001136 if (is_not_black_or_white(src[x])) {
reed@google.com5e2df642011-09-21 18:42:09 +00001137 return false;
1138 }
1139 }
bungeman@google.com05a729f2013-06-20 15:29:16 +00001140 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
reed@google.com5e2df642011-09-21 18:42:09 +00001141 }
1142 return true;
1143}
1144
bungeman@google.com97efada2012-07-30 20:40:50 +00001145// gdi's bitmap is upside-down, so we reverse dst walking in Y
1146// whenever we copy it into skia's buffer
reed@google.com5e2df642011-09-21 18:42:09 +00001147static void rgb_to_bw(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
bungeman@google.com97efada2012-07-30 20:40:50 +00001148 const SkGlyph& glyph) {
reed@google.com5e2df642011-09-21 18:42:09 +00001149 const int width = glyph.fWidth;
1150 const size_t dstRB = (width + 7) >> 3;
1151 uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1152
1153 int byteCount = width >> 3;
1154 int bitCount = width & 7;
1155
1156 // adjust srcRB to skip the values in our byteCount loop,
1157 // since we increment src locally there
1158 srcRB -= byteCount * 8 * sizeof(SkGdiRGB);
1159
1160 for (int y = 0; y < glyph.fHeight; ++y) {
1161 if (byteCount > 0) {
reed@google.com5e2df642011-09-21 18:42:09 +00001162 for (int i = 0; i < byteCount; ++i) {
reed@google.com7a230142011-09-27 14:07:21 +00001163 unsigned byte = 0;
bungeman@google.com97efada2012-07-30 20:40:50 +00001164 byte |= src[0] & (1 << 7);
1165 byte |= src[1] & (1 << 6);
1166 byte |= src[2] & (1 << 5);
1167 byte |= src[3] & (1 << 4);
1168 byte |= src[4] & (1 << 3);
1169 byte |= src[5] & (1 << 2);
1170 byte |= src[6] & (1 << 1);
1171 byte |= src[7] & (1 << 0);
reed@google.com6a8f14d2011-09-27 12:54:24 +00001172 dst[i] = byte;
reed@google.com5e2df642011-09-21 18:42:09 +00001173 src += 8;
1174 }
1175 }
1176 if (bitCount > 0) {
1177 unsigned byte = 0;
1178 unsigned mask = 0x80;
1179 for (int i = 0; i < bitCount; i++) {
bungeman@google.com97efada2012-07-30 20:40:50 +00001180 byte |= src[i] & mask;
reed@google.com5e2df642011-09-21 18:42:09 +00001181 mask >>= 1;
1182 }
1183 dst[byteCount] = byte;
1184 }
bungeman@google.com05a729f2013-06-20 15:29:16 +00001185 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
reed@google.com5e2df642011-09-21 18:42:09 +00001186 dst -= dstRB;
1187 }
bungeman@google.com0abbff92013-07-27 20:37:56 +00001188#if SK_SHOW_TEXT_BLIT_COVERAGE
1189 if (glyph.fWidth > 0 && glyph.fHeight > 0) {
1190 uint8_t* first = (uint8_t*)glyph.fImage;
1191 uint8_t* last = (uint8_t*)((char*)glyph.fImage + glyph.fHeight * dstRB - 1);
1192 *first |= 1 << 7;
1193 *last |= bitCount == 0 ? 1 : 1 << (8 - bitCount);
1194 }
1195#endif
reed@google.com5e2df642011-09-21 18:42:09 +00001196}
1197
bungeman@google.com97efada2012-07-30 20:40:50 +00001198template<bool APPLY_PREBLEND>
reed@google.com5e2df642011-09-21 18:42:09 +00001199static void rgb_to_a8(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
bungeman@google.com97efada2012-07-30 20:40:50 +00001200 const SkGlyph& glyph, const uint8_t* table8) {
reed@google.com5e2df642011-09-21 18:42:09 +00001201 const size_t dstRB = glyph.rowBytes();
1202 const int width = glyph.fWidth;
1203 uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1204
1205 for (int y = 0; y < glyph.fHeight; y++) {
1206 for (int i = 0; i < width; i++) {
bungeman@google.com97efada2012-07-30 20:40:50 +00001207 dst[i] = rgb_to_a8<APPLY_PREBLEND>(src[i], table8);
bungeman@google.com0abbff92013-07-27 20:37:56 +00001208#if SK_SHOW_TEXT_BLIT_COVERAGE
1209 dst[i] = SkMax32(dst[i], 10);
1210#endif
reed@google.com5e2df642011-09-21 18:42:09 +00001211 }
bungeman@google.com05a729f2013-06-20 15:29:16 +00001212 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
reed@google.com5e2df642011-09-21 18:42:09 +00001213 dst -= dstRB;
1214 }
1215}
1216
bungeman@google.com97efada2012-07-30 20:40:50 +00001217template<bool APPLY_PREBLEND>
1218static void rgb_to_lcd16(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph,
1219 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
reed@google.com5e2df642011-09-21 18:42:09 +00001220 const size_t dstRB = glyph.rowBytes();
1221 const int width = glyph.fWidth;
1222 uint16_t* SK_RESTRICT dst = (uint16_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1223
1224 for (int y = 0; y < glyph.fHeight; y++) {
1225 for (int i = 0; i < width; i++) {
bungeman@google.com97efada2012-07-30 20:40:50 +00001226 dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(src[i], tableR, tableG, tableB);
reed@google.com5e2df642011-09-21 18:42:09 +00001227 }
bungeman@google.com05a729f2013-06-20 15:29:16 +00001228 src = SkTAddOffset<const SkGdiRGB>(src, srcRB);
reed@google.com5e2df642011-09-21 18:42:09 +00001229 dst = (uint16_t*)((char*)dst - dstRB);
1230 }
1231}
1232
reed@google.com30ddd612013-07-30 17:47:39 +00001233void SkScalerContext_GDI::generateImage(const SkGlyph& glyph) {
reed@google.comac6b9792011-03-11 15:42:51 +00001234 SkASSERT(fDDC);
1235
reed@google.com62711172011-05-18 15:08:10 +00001236 const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat;
reed@google.com82a34d82011-07-26 19:33:08 +00001237 const bool isAA = !isLCD(fRec);
reed@google.comac6b9792011-03-11 15:42:51 +00001238
reed@google.com99edd432011-09-09 14:59:59 +00001239 size_t srcRB;
bungeman@google.com97efada2012-07-30 20:40:50 +00001240 const void* bits = fOffscreen.draw(glyph, isBW, &srcRB);
halcanary96fcdcc2015-08-27 07:41:13 -07001241 if (nullptr == bits) {
reed@google.com055180c2013-03-21 18:46:35 +00001242 LogFontTypeface::EnsureAccessible(this->getTypeface());
bungeman@google.com97efada2012-07-30 20:40:50 +00001243 bits = fOffscreen.draw(glyph, isBW, &srcRB);
halcanary96fcdcc2015-08-27 07:41:13 -07001244 if (nullptr == bits) {
bungeman@google.com39698b12011-11-15 22:26:41 +00001245 sk_bzero(glyph.fImage, glyph.computeImageSize());
1246 return;
1247 }
reed@google.com82a34d82011-07-26 19:33:08 +00001248 }
reed@google.comac6b9792011-03-11 15:42:51 +00001249
bungeman@google.com97efada2012-07-30 20:40:50 +00001250 if (!isBW) {
bungeman@google.com1bd2d672012-08-13 20:01:51 +00001251 const uint8_t* table;
1252 //The offscreen contains a GDI blit if isAA and kGenA8FromLCD_Flag is not set.
1253 //Otherwise the offscreen contains a ClearType blit.
1254 if (isAA && !(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag)) {
1255 table = getInverseGammaTableGDI();
1256 } else {
1257 table = getInverseGammaTableClearType();
bungeman@google.com97efada2012-07-30 20:40:50 +00001258 }
1259 //Note that the following cannot really be integrated into the
1260 //pre-blend, since we may not be applying the pre-blend; when we aren't
1261 //applying the pre-blend it means that a filter wants linear anyway.
1262 //Other code may also be applying the pre-blend, so we'd need another
1263 //one with this and one without.
reed@google.com6f5df482011-09-28 20:33:24 +00001264 SkGdiRGB* addr = (SkGdiRGB*)bits;
1265 for (int y = 0; y < glyph.fHeight; ++y) {
1266 for (int x = 0; x < glyph.fWidth; ++x) {
1267 int r = (addr[x] >> 16) & 0xFF;
1268 int g = (addr[x] >> 8) & 0xFF;
1269 int b = (addr[x] >> 0) & 0xFF;
reed@google.com7430a332011-10-03 14:37:38 +00001270 addr[x] = (table[r] << 16) | (table[g] << 8) | table[b];
reed@google.com6f5df482011-09-28 20:33:24 +00001271 }
bungeman@google.com05a729f2013-06-20 15:29:16 +00001272 addr = SkTAddOffset<SkGdiRGB>(addr, srcRB);
reed@google.com6f5df482011-09-28 20:33:24 +00001273 }
1274 }
1275
reed@google.com82a34d82011-07-26 19:33:08 +00001276 int width = glyph.fWidth;
1277 size_t dstRB = glyph.rowBytes();
1278 if (isBW) {
1279 const uint8_t* src = (const uint8_t*)bits;
reed@google.com82a34d82011-07-26 19:33:08 +00001280 uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1281 for (int y = 0; y < glyph.fHeight; y++) {
1282 memcpy(dst, src, dstRB);
1283 src += srcRB;
1284 dst -= dstRB;
reed@google.comac6b9792011-03-11 15:42:51 +00001285 }
bungeman@google.com0abbff92013-07-27 20:37:56 +00001286#if SK_SHOW_TEXT_BLIT_COVERAGE
1287 if (glyph.fWidth > 0 && glyph.fHeight > 0) {
1288 int bitCount = width & 7;
1289 uint8_t* first = (uint8_t*)glyph.fImage;
1290 uint8_t* last = (uint8_t*)((char*)glyph.fImage + glyph.fHeight * dstRB - 1);
1291 *first |= 1 << 7;
1292 *last |= bitCount == 0 ? 1 : 1 << (8 - bitCount);
1293 }
1294#endif
reed@google.com82a34d82011-07-26 19:33:08 +00001295 } else if (isAA) {
reed@google.com6f5df482011-09-28 20:33:24 +00001296 // since the caller may require A8 for maskfilters, we can't check for BW
1297 // ... until we have the caller tell us that explicitly
reed@google.com5e2df642011-09-21 18:42:09 +00001298 const SkGdiRGB* src = (const SkGdiRGB*)bits;
bungeman@google.coma76de722012-10-26 19:35:54 +00001299 if (fPreBlend.isApplicable()) {
1300 rgb_to_a8<true>(src, srcRB, glyph, fPreBlend.fG);
bungeman@google.com97efada2012-07-30 20:40:50 +00001301 } else {
bungeman@google.coma76de722012-10-26 19:35:54 +00001302 rgb_to_a8<false>(src, srcRB, glyph, fPreBlend.fG);
bungeman@google.com97efada2012-07-30 20:40:50 +00001303 }
reed@google.com82a34d82011-07-26 19:33:08 +00001304 } else { // LCD16
reed@google.com5e2df642011-09-21 18:42:09 +00001305 const SkGdiRGB* src = (const SkGdiRGB*)bits;
1306 if (is_rgb_really_bw(src, width, glyph.fHeight, srcRB)) {
bungeman@google.com97efada2012-07-30 20:40:50 +00001307 rgb_to_bw(src, srcRB, glyph);
reed@google.com5e2df642011-09-21 18:42:09 +00001308 ((SkGlyph*)&glyph)->fMaskFormat = SkMask::kBW_Format;
1309 } else {
reedd54d3fc2014-11-13 14:39:58 -08001310 SkASSERT(SkMask::kLCD16_Format == glyph.fMaskFormat);
1311 if (fPreBlend.isApplicable()) {
1312 rgb_to_lcd16<true>(src, srcRB, glyph,
1313 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
reed@google.com754e4eb2011-09-26 13:21:39 +00001314 } else {
reedd54d3fc2014-11-13 14:39:58 -08001315 rgb_to_lcd16<false>(src, srcRB, glyph,
1316 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
reed@google.com754e4eb2011-09-26 13:21:39 +00001317 }
reed@google.comac6b9792011-03-11 15:42:51 +00001318 }
1319 }
reed@google.comac6b9792011-03-11 15:42:51 +00001320}
1321
bungeman@google.com0abbff92013-07-27 20:37:56 +00001322class GDIGlyphbufferPointIter {
1323public:
skia.committer@gmail.com27e21fe2013-07-28 07:01:03 +00001324 GDIGlyphbufferPointIter(const uint8_t* glyphbuf, DWORD total_size)
bungeman@google.com0abbff92013-07-27 20:37:56 +00001325 : fHeaderIter(glyphbuf, total_size), fCurveIter(), fPointIter()
1326 { }
reed@google.comac6b9792011-03-11 15:42:51 +00001327
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001328 POINTFX const * next() {
bungeman@google.com0abbff92013-07-27 20:37:56 +00001329nextHeader:
1330 if (!fCurveIter.isSet()) {
1331 const TTPOLYGONHEADER* header = fHeaderIter.next();
halcanary96fcdcc2015-08-27 07:41:13 -07001332 if (nullptr == header) {
1333 return nullptr;
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001334 }
bungeman@google.com0abbff92013-07-27 20:37:56 +00001335 fCurveIter.set(header);
1336 const TTPOLYCURVE* curve = fCurveIter.next();
halcanary96fcdcc2015-08-27 07:41:13 -07001337 if (nullptr == curve) {
1338 return nullptr;
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001339 }
bungeman@google.com0abbff92013-07-27 20:37:56 +00001340 fPointIter.set(curve);
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001341 return &header->pfxStart;
bungeman@google.com05a729f2013-06-20 15:29:16 +00001342 }
1343
bungeman@google.com0abbff92013-07-27 20:37:56 +00001344 const POINTFX* nextPoint = fPointIter.next();
halcanary96fcdcc2015-08-27 07:41:13 -07001345 if (nullptr == nextPoint) {
bungeman@google.com0abbff92013-07-27 20:37:56 +00001346 const TTPOLYCURVE* curve = fCurveIter.next();
halcanary96fcdcc2015-08-27 07:41:13 -07001347 if (nullptr == curve) {
bungeman@google.com0abbff92013-07-27 20:37:56 +00001348 fCurveIter.set();
1349 goto nextHeader;
1350 } else {
1351 fPointIter.set(curve);
bungeman@google.com05a729f2013-06-20 15:29:16 +00001352 }
bungeman@google.com0abbff92013-07-27 20:37:56 +00001353 nextPoint = fPointIter.next();
reed@google.comac6b9792011-03-11 15:42:51 +00001354 }
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001355 return nextPoint;
reed@google.comac6b9792011-03-11 15:42:51 +00001356 }
bungeman@google.comd1c7f712013-03-11 18:51:19 +00001357
bungeman@google.com0abbff92013-07-27 20:37:56 +00001358 WORD currentCurveType() {
1359 return fPointIter.fCurveType;
1360 }
1361
1362private:
1363 /** Iterates over all of the polygon headers in a glyphbuf. */
1364 class GDIPolygonHeaderIter {
1365 public:
skia.committer@gmail.com27e21fe2013-07-28 07:01:03 +00001366 GDIPolygonHeaderIter(const uint8_t* glyphbuf, DWORD total_size)
bungeman@google.com0abbff92013-07-27 20:37:56 +00001367 : fCurPolygon(reinterpret_cast<const TTPOLYGONHEADER*>(glyphbuf))
1368 , fEndPolygon(SkTAddOffset<const TTPOLYGONHEADER>(glyphbuf, total_size))
1369 { }
1370
1371 const TTPOLYGONHEADER* next() {
1372 if (fCurPolygon >= fEndPolygon) {
halcanary96fcdcc2015-08-27 07:41:13 -07001373 return nullptr;
bungeman@google.com0abbff92013-07-27 20:37:56 +00001374 }
1375 const TTPOLYGONHEADER* thisPolygon = fCurPolygon;
1376 fCurPolygon = SkTAddOffset<const TTPOLYGONHEADER>(fCurPolygon, fCurPolygon->cb);
1377 return thisPolygon;
1378 }
1379 private:
1380 const TTPOLYGONHEADER* fCurPolygon;
1381 const TTPOLYGONHEADER* fEndPolygon;
1382 };
1383
1384 /** Iterates over all of the polygon curves in a polygon header. */
1385 class GDIPolygonCurveIter {
1386 public:
halcanary96fcdcc2015-08-27 07:41:13 -07001387 GDIPolygonCurveIter() : fCurCurve(nullptr), fEndCurve(nullptr) { }
bungeman@google.com0abbff92013-07-27 20:37:56 +00001388
1389 GDIPolygonCurveIter(const TTPOLYGONHEADER* curPolygon)
1390 : fCurCurve(SkTAddOffset<const TTPOLYCURVE>(curPolygon, sizeof(TTPOLYGONHEADER)))
1391 , fEndCurve(SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon->cb))
1392 { }
1393
halcanary96fcdcc2015-08-27 07:41:13 -07001394 bool isSet() { return fCurCurve != nullptr; }
bungeman@google.com0abbff92013-07-27 20:37:56 +00001395
1396 void set(const TTPOLYGONHEADER* curPolygon) {
1397 fCurCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon, sizeof(TTPOLYGONHEADER));
1398 fEndCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon->cb);
1399 }
1400 void set() {
halcanary96fcdcc2015-08-27 07:41:13 -07001401 fCurCurve = nullptr;
1402 fEndCurve = nullptr;
bungeman@google.com0abbff92013-07-27 20:37:56 +00001403 }
1404
1405 const TTPOLYCURVE* next() {
1406 if (fCurCurve >= fEndCurve) {
halcanary96fcdcc2015-08-27 07:41:13 -07001407 return nullptr;
bungeman@google.com0abbff92013-07-27 20:37:56 +00001408 }
1409 const TTPOLYCURVE* thisCurve = fCurCurve;
1410 fCurCurve = SkTAddOffset<const TTPOLYCURVE>(fCurCurve, size_of_TTPOLYCURVE(*fCurCurve));
1411 return thisCurve;
1412 }
1413 private:
1414 size_t size_of_TTPOLYCURVE(const TTPOLYCURVE& curve) {
1415 return 2*sizeof(WORD) + curve.cpfx*sizeof(POINTFX);
1416 }
1417 const TTPOLYCURVE* fCurCurve;
1418 const TTPOLYCURVE* fEndCurve;
1419 };
1420
1421 /** Iterates over all of the polygon points in a polygon curve. */
1422 class GDIPolygonCurvePointIter {
1423 public:
halcanary96fcdcc2015-08-27 07:41:13 -07001424 GDIPolygonCurvePointIter() : fCurveType(0), fCurPoint(nullptr), fEndPoint(nullptr) { }
bungeman@google.com0abbff92013-07-27 20:37:56 +00001425
1426 GDIPolygonCurvePointIter(const TTPOLYCURVE* curPolygon)
1427 : fCurveType(curPolygon->wType)
1428 , fCurPoint(&curPolygon->apfx[0])
1429 , fEndPoint(&curPolygon->apfx[curPolygon->cpfx])
1430 { }
1431
halcanary96fcdcc2015-08-27 07:41:13 -07001432 bool isSet() { return fCurPoint != nullptr; }
bungeman@google.com0abbff92013-07-27 20:37:56 +00001433
1434 void set(const TTPOLYCURVE* curPolygon) {
1435 fCurveType = curPolygon->wType;
1436 fCurPoint = &curPolygon->apfx[0];
1437 fEndPoint = &curPolygon->apfx[curPolygon->cpfx];
1438 }
1439 void set() {
halcanary96fcdcc2015-08-27 07:41:13 -07001440 fCurPoint = nullptr;
1441 fEndPoint = nullptr;
bungeman@google.com0abbff92013-07-27 20:37:56 +00001442 }
1443
1444 const POINTFX* next() {
1445 if (fCurPoint >= fEndPoint) {
halcanary96fcdcc2015-08-27 07:41:13 -07001446 return nullptr;
bungeman@google.com0abbff92013-07-27 20:37:56 +00001447 }
1448 const POINTFX* thisPoint = fCurPoint;
1449 ++fCurPoint;
1450 return thisPoint;
1451 }
1452
1453 WORD fCurveType;
1454 private:
1455 const POINTFX* fCurPoint;
1456 const POINTFX* fEndPoint;
1457 };
1458
1459 GDIPolygonHeaderIter fHeaderIter;
1460 GDIPolygonCurveIter fCurveIter;
1461 GDIPolygonCurvePointIter fPointIter;
1462};
1463
1464static void sk_path_from_gdi_path(SkPath* path, const uint8_t* glyphbuf, DWORD total_size) {
bungeman@google.comd1c7f712013-03-11 18:51:19 +00001465 const uint8_t* cur_glyph = glyphbuf;
1466 const uint8_t* end_glyph = glyphbuf + total_size;
1467
1468 while (cur_glyph < end_glyph) {
1469 const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
1470
1471 const uint8_t* end_poly = cur_glyph + th->cb;
1472 const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
1473
1474 path->moveTo(SkFixedToScalar( SkFIXEDToFixed(th->pfxStart.x)),
1475 SkFixedToScalar(-SkFIXEDToFixed(th->pfxStart.y)));
1476
1477 while (cur_poly < end_poly) {
1478 const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
1479
1480 if (pc->wType == TT_PRIM_LINE) {
1481 for (uint16_t i = 0; i < pc->cpfx; i++) {
1482 path->lineTo(SkFixedToScalar( SkFIXEDToFixed(pc->apfx[i].x)),
1483 SkFixedToScalar(-SkFIXEDToFixed(pc->apfx[i].y)));
1484 }
1485 }
1486
1487 if (pc->wType == TT_PRIM_QSPLINE) {
1488 for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline
1489 POINTFX pnt_b = pc->apfx[u]; // B is always the current point
1490 POINTFX pnt_c = pc->apfx[u+1];
1491
1492 if (u < pc->cpfx - 2) { // If not on last spline, compute C
1493 pnt_c.x = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.x),
1494 SkFIXEDToFixed(pnt_c.x)));
1495 pnt_c.y = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.y),
1496 SkFIXEDToFixed(pnt_c.y)));
1497 }
1498
1499 path->quadTo(SkFixedToScalar( SkFIXEDToFixed(pnt_b.x)),
1500 SkFixedToScalar(-SkFIXEDToFixed(pnt_b.y)),
1501 SkFixedToScalar( SkFIXEDToFixed(pnt_c.x)),
1502 SkFixedToScalar(-SkFIXEDToFixed(pnt_c.y)));
1503 }
1504 }
1505 // Advance past this TTPOLYCURVE.
1506 cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx;
1507 }
1508 cur_glyph += th->cb;
1509 path->close();
reed@google.comac6b9792011-03-11 15:42:51 +00001510 }
reed@google.comac6b9792011-03-11 15:42:51 +00001511}
1512
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001513#define move_next_expected_hinted_point(iter, pElem) do {\
1514 pElem = iter.next(); \
halcanary96fcdcc2015-08-27 07:41:13 -07001515 if (nullptr == pElem) return false; \
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001516} while(0)
1517
1518// It is possible for the hinted and unhinted versions of the same path to have
1519// a different number of points due to GDI's handling of flipped points.
1520// If this is detected, this will return false.
1521static bool sk_path_from_gdi_paths(SkPath* path, const uint8_t* glyphbuf, DWORD total_size,
bungeman@google.com0abbff92013-07-27 20:37:56 +00001522 GDIGlyphbufferPointIter hintedYs) {
1523 const uint8_t* cur_glyph = glyphbuf;
1524 const uint8_t* end_glyph = glyphbuf + total_size;
1525
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001526 POINTFX const * hintedPoint;
1527
bungeman@google.com0abbff92013-07-27 20:37:56 +00001528 while (cur_glyph < end_glyph) {
1529 const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
1530
1531 const uint8_t* end_poly = cur_glyph + th->cb;
1532 const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
1533
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001534 move_next_expected_hinted_point(hintedYs, hintedPoint);
bungeman@google.com0abbff92013-07-27 20:37:56 +00001535 path->moveTo(SkFixedToScalar( SkFIXEDToFixed(th->pfxStart.x)),
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001536 SkFixedToScalar(-SkFIXEDToFixed(hintedPoint->y)));
bungeman@google.com0abbff92013-07-27 20:37:56 +00001537
1538 while (cur_poly < end_poly) {
1539 const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
1540
1541 if (pc->wType == TT_PRIM_LINE) {
1542 for (uint16_t i = 0; i < pc->cpfx; i++) {
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001543 move_next_expected_hinted_point(hintedYs, hintedPoint);
bungeman@google.com0abbff92013-07-27 20:37:56 +00001544 path->lineTo(SkFixedToScalar( SkFIXEDToFixed(pc->apfx[i].x)),
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001545 SkFixedToScalar(-SkFIXEDToFixed(hintedPoint->y)));
bungeman@google.com0abbff92013-07-27 20:37:56 +00001546 }
1547 }
1548
1549 if (pc->wType == TT_PRIM_QSPLINE) {
1550 POINTFX currentPoint = pc->apfx[0];
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001551 move_next_expected_hinted_point(hintedYs, hintedPoint);
bungeman@google.com0abbff92013-07-27 20:37:56 +00001552 // only take the hinted y if it wasn't flipped
1553 if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) {
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001554 currentPoint.y = hintedPoint->y;
bungeman@google.com0abbff92013-07-27 20:37:56 +00001555 }
1556 for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline
1557 POINTFX pnt_b = currentPoint;//pc->apfx[u]; // B is always the current point
1558 POINTFX pnt_c = pc->apfx[u+1];
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001559 move_next_expected_hinted_point(hintedYs, hintedPoint);
bungeman@google.com0abbff92013-07-27 20:37:56 +00001560 // only take the hinted y if it wasn't flipped
1561 if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) {
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001562 pnt_c.y = hintedPoint->y;
bungeman@google.com0abbff92013-07-27 20:37:56 +00001563 }
1564 currentPoint.x = pnt_c.x;
1565 currentPoint.y = pnt_c.y;
1566
1567 if (u < pc->cpfx - 2) { // If not on last spline, compute C
1568 pnt_c.x = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.x),
1569 SkFIXEDToFixed(pnt_c.x)));
1570 pnt_c.y = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.y),
1571 SkFIXEDToFixed(pnt_c.y)));
1572 }
1573
1574 path->quadTo(SkFixedToScalar( SkFIXEDToFixed(pnt_b.x)),
1575 SkFixedToScalar(-SkFIXEDToFixed(pnt_b.y)),
1576 SkFixedToScalar( SkFIXEDToFixed(pnt_c.x)),
1577 SkFixedToScalar(-SkFIXEDToFixed(pnt_c.y)));
1578 }
1579 }
1580 // Advance past this TTPOLYCURVE.
1581 cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx;
1582 }
1583 cur_glyph += th->cb;
1584 path->close();
1585 }
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001586 return true;
bungeman@google.com0abbff92013-07-27 20:37:56 +00001587}
1588
reed@google.com30ddd612013-07-30 17:47:39 +00001589DWORD SkScalerContext_GDI::getGDIGlyphPath(const SkGlyph& glyph, UINT flags,
bungeman@google.com0abbff92013-07-27 20:37:56 +00001590 SkAutoSTMalloc<BUFFERSIZE, uint8_t>* glyphbuf)
1591{
1592 GLYPHMETRICS gm;
1593
herbb69d0e02015-02-25 06:47:06 -08001594 DWORD total_size = GetGlyphOutlineW(fDDC, glyph.getGlyphID(), flags, &gm, BUFFERSIZE, glyphbuf->get(), &fMat22);
bungeman@google.com0abbff92013-07-27 20:37:56 +00001595 // Sometimes GetGlyphOutlineW returns a number larger than BUFFERSIZE even if BUFFERSIZE > 0.
1596 // It has been verified that this does not involve a buffer overrun.
1597 if (GDI_ERROR == total_size || total_size > BUFFERSIZE) {
1598 // GDI_ERROR because the BUFFERSIZE was too small, or because the data was not accessible.
1599 // When the data is not accessable GetGlyphOutlineW fails rather quickly,
1600 // so just try to get the size. If that fails then ensure the data is accessible.
halcanary96fcdcc2015-08-27 07:41:13 -07001601 total_size = GetGlyphOutlineW(fDDC, glyph.getGlyphID(), flags, &gm, 0, nullptr, &fMat22);
bungeman@google.com0abbff92013-07-27 20:37:56 +00001602 if (GDI_ERROR == total_size) {
1603 LogFontTypeface::EnsureAccessible(this->getTypeface());
halcanary96fcdcc2015-08-27 07:41:13 -07001604 total_size = GetGlyphOutlineW(fDDC, glyph.getGlyphID(), flags, &gm, 0, nullptr, &fMat22);
bungeman@google.com0abbff92013-07-27 20:37:56 +00001605 if (GDI_ERROR == total_size) {
kkinnunenc6cb56f2014-06-24 00:12:27 -07001606 // GetGlyphOutlineW is known to fail for some characters, such as spaces.
1607 // In these cases, just return that the glyph does not have a shape.
bungeman@google.com0abbff92013-07-27 20:37:56 +00001608 return 0;
1609 }
1610 }
1611
1612 glyphbuf->reset(total_size);
1613
herbb69d0e02015-02-25 06:47:06 -08001614 DWORD ret = GetGlyphOutlineW(fDDC, glyph.getGlyphID(), flags, &gm, total_size, glyphbuf->get(), &fMat22);
bungeman@google.com0abbff92013-07-27 20:37:56 +00001615 if (GDI_ERROR == ret) {
1616 LogFontTypeface::EnsureAccessible(this->getTypeface());
herbb69d0e02015-02-25 06:47:06 -08001617 ret = GetGlyphOutlineW(fDDC, glyph.getGlyphID(), flags, &gm, total_size, glyphbuf->get(), &fMat22);
bungeman@google.com0abbff92013-07-27 20:37:56 +00001618 if (GDI_ERROR == ret) {
1619 SkASSERT(false);
1620 return 0;
1621 }
1622 }
1623 }
1624 return total_size;
1625}
1626
reed@google.com30ddd612013-07-30 17:47:39 +00001627void SkScalerContext_GDI::generatePath(const SkGlyph& glyph, SkPath* path) {
dcheng3ba043f2015-07-08 13:25:23 -07001628 SkASSERT(path);
bungeman@google.com0abbff92013-07-27 20:37:56 +00001629 SkASSERT(fDDC);
1630
1631 path->reset();
1632
1633 // Out of all the fonts on a typical Windows box,
1634 // 25% of glyphs require more than 2KB.
1635 // 1% of glyphs require more than 4KB.
1636 // 0.01% of glyphs require more than 8KB.
1637 // 8KB is less than 1% of the normal 1MB stack on Windows.
1638 // Note that some web fonts glyphs require more than 20KB.
1639 //static const DWORD BUFFERSIZE = (1 << 13);
1640
1641 //GDI only uses hinted outlines when axis aligned.
1642 UINT format = GGO_NATIVE | GGO_GLYPH_INDEX;
1643 if (fRec.getHinting() == SkPaint::kNo_Hinting || fRec.getHinting() == SkPaint::kSlight_Hinting){
1644 format |= GGO_UNHINTED;
1645 }
1646 SkAutoSTMalloc<BUFFERSIZE, uint8_t> glyphbuf(BUFFERSIZE);
1647 DWORD total_size = getGDIGlyphPath(glyph, format, &glyphbuf);
1648 if (0 == total_size) {
1649 return;
1650 }
1651
1652 if (fRec.getHinting() != SkPaint::kSlight_Hinting) {
1653 sk_path_from_gdi_path(path, glyphbuf, total_size);
1654 } else {
1655 //GDI only uses hinted outlines when axis aligned.
1656 UINT format = GGO_NATIVE | GGO_GLYPH_INDEX;
1657
1658 SkAutoSTMalloc<BUFFERSIZE, uint8_t> hintedGlyphbuf(BUFFERSIZE);
1659 DWORD hinted_total_size = getGDIGlyphPath(glyph, format, &hintedGlyphbuf);
1660 if (0 == hinted_total_size) {
1661 return;
1662 }
1663
bungeman@google.comdd88ecc2013-09-20 17:25:31 +00001664 if (!sk_path_from_gdi_paths(path, glyphbuf, total_size,
1665 GDIGlyphbufferPointIter(hintedGlyphbuf, hinted_total_size)))
1666 {
1667 path->reset();
1668 sk_path_from_gdi_path(path, glyphbuf, total_size);
1669 }
bungeman@google.com0abbff92013-07-27 20:37:56 +00001670 }
1671}
1672
reed@google.com484f5bc2013-04-24 19:14:56 +00001673static void logfont_for_name(const char* familyName, LOGFONT* lf) {
1674 sk_bzero(lf, sizeof(LOGFONT));
bungeman@google.come70f7982012-06-01 19:38:19 +00001675#ifdef UNICODE
reed@google.com484f5bc2013-04-24 19:14:56 +00001676 // Get the buffer size needed first.
1677 size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName,
halcanary96fcdcc2015-08-27 07:41:13 -07001678 -1, nullptr, 0);
reed@google.com484f5bc2013-04-24 19:14:56 +00001679 // Allocate a buffer (str_len already has terminating null
1680 // accounted for).
1681 wchar_t *wideFamilyName = new wchar_t[str_len];
1682 // Now actually convert the string.
1683 ::MultiByteToWideChar(CP_UTF8, 0, familyName, -1,
1684 wideFamilyName, str_len);
1685 ::wcsncpy(lf->lfFaceName, wideFamilyName, LF_FACESIZE - 1);
1686 delete [] wideFamilyName;
1687 lf->lfFaceName[LF_FACESIZE-1] = L'\0';
bungeman@google.come70f7982012-06-01 19:38:19 +00001688#else
reed@google.com484f5bc2013-04-24 19:14:56 +00001689 ::strncpy(lf->lfFaceName, familyName, LF_FACESIZE - 1);
1690 lf->lfFaceName[LF_FACESIZE - 1] = '\0';
bungeman@google.come70f7982012-06-01 19:38:19 +00001691#endif
1692}
1693
bungemanb374d6a2014-09-17 07:48:59 -07001694void LogFontTypeface::onGetFamilyName(SkString* familyName) const {
bungeman@google.com7103f182012-10-31 20:53:49 +00001695 // Get the actual name of the typeface. The logfont may not know this.
reed@google.com5526ede2013-03-25 13:03:37 +00001696 HFONT font = CreateFontIndirect(&fLogFont);
bungeman@google.com7103f182012-10-31 20:53:49 +00001697
halcanary96fcdcc2015-08-27 07:41:13 -07001698 HDC deviceContext = ::CreateCompatibleDC(nullptr);
bungeman@google.com7103f182012-10-31 20:53:49 +00001699 HFONT savefont = (HFONT)SelectObject(deviceContext, font);
1700
bungemanb374d6a2014-09-17 07:48:59 -07001701 dcfontname_to_skstring(deviceContext, fLogFont, familyName);
bungeman@google.com7103f182012-10-31 20:53:49 +00001702
1703 if (deviceContext) {
1704 ::SelectObject(deviceContext, savefont);
1705 ::DeleteDC(deviceContext);
1706 }
1707 if (font) {
1708 ::DeleteObject(font);
1709 }
bungemanb374d6a2014-09-17 07:48:59 -07001710}
bungeman@google.com7103f182012-10-31 20:53:49 +00001711
bungemanb374d6a2014-09-17 07:48:59 -07001712void LogFontTypeface::onGetFontDescriptor(SkFontDescriptor* desc,
1713 bool* isLocalStream) const {
1714 SkString familyName;
1715 this->onGetFamilyName(&familyName);
reed@google.com5526ede2013-03-25 13:03:37 +00001716 desc->setFamilyName(familyName.c_str());
bungemanb8113782016-07-25 16:54:59 -07001717 desc->setStyle(this->fontStyle());
reed@google.com5526ede2013-03-25 13:03:37 +00001718 *isLocalStream = this->fSerializeAsStream;
reed@google.comac6b9792011-03-11 15:42:51 +00001719}
1720
reed@google.com2689f612013-03-20 20:01:47 +00001721SkAdvancedTypefaceMetrics* LogFontTypeface::onGetAdvancedTypefaceMetrics(
reed39a9a502015-05-12 09:50:04 -07001722 PerGlyphInfo perGlyphInfo,
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +00001723 const uint32_t* glyphIDs,
reed@google.com2689f612013-03-20 20:01:47 +00001724 uint32_t glyphIDsCount) const {
1725 LOGFONT lf = fLogFont;
halcanary96fcdcc2015-08-27 07:41:13 -07001726 SkAdvancedTypefaceMetrics* info = nullptr;
reed@google.comac6b9792011-03-11 15:42:51 +00001727
halcanary96fcdcc2015-08-27 07:41:13 -07001728 HDC hdc = CreateCompatibleDC(nullptr);
reed@google.comac6b9792011-03-11 15:42:51 +00001729 HFONT font = CreateFontIndirect(&lf);
1730 HFONT savefont = (HFONT)SelectObject(hdc, font);
halcanary96fcdcc2015-08-27 07:41:13 -07001731 HFONT designFont = nullptr;
reed@google.comac6b9792011-03-11 15:42:51 +00001732
reed@google.com05b6f3a2011-11-28 15:30:28 +00001733 const char stem_chars[] = {'i', 'I', '!', '1'};
1734 int16_t min_width;
1735 unsigned glyphCount;
1736
reed@google.comac6b9792011-03-11 15:42:51 +00001737 // To request design units, create a logical font whose height is specified
1738 // as unitsPerEm.
1739 OUTLINETEXTMETRIC otm;
bungeman@google.com39698b12011-11-15 22:26:41 +00001740 unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
1741 if (0 == otmRet) {
reed@google.com055180c2013-03-21 18:46:35 +00001742 call_ensure_accessible(lf);
bungeman@google.com39698b12011-11-15 22:26:41 +00001743 otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
1744 }
1745 if (!otmRet || !GetTextFace(hdc, LF_FACESIZE, lf.lfFaceName)) {
reed@google.comac6b9792011-03-11 15:42:51 +00001746 goto Error;
1747 }
1748 lf.lfHeight = -SkToS32(otm.otmEMSquare);
1749 designFont = CreateFontIndirect(&lf);
1750 SelectObject(hdc, designFont);
1751 if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm)) {
1752 goto Error;
1753 }
bungeman@google.com7bdd6142013-07-15 19:42:57 +00001754 glyphCount = calculateGlyphCount(hdc, fLogFont);
reed@google.comac6b9792011-03-11 15:42:51 +00001755
1756 info = new SkAdvancedTypefaceMetrics;
1757 info->fEmSize = otm.otmEMSquare;
reed@google.comac6b9792011-03-11 15:42:51 +00001758 info->fLastGlyphID = SkToU16(glyphCount - 1);
bungeman@google.com7103f182012-10-31 20:53:49 +00001759 tchar_to_skstring(lf.lfFaceName, &info->fFontName);
vandebo0f9bad02014-06-19 11:05:39 -07001760 // If bit 1 is set, the font may not be embedded in a document.
1761 // If bit 1 is clear, the font can be embedded.
1762 // If bit 2 is set, the embedding is read-only.
1763 if (otm.otmfsType & 0x1) {
1764 info->fFlags = SkTBitOr<SkAdvancedTypefaceMetrics::FontFlags>(
1765 info->fFlags,
1766 SkAdvancedTypefaceMetrics::kNotEmbeddable_FontFlag);
1767 }
reed@google.comac6b9792011-03-11 15:42:51 +00001768
reed39a9a502015-05-12 09:50:04 -07001769 if (perGlyphInfo & kToUnicode_PerGlyphInfo) {
vandebo@chromium.org6744d492011-05-09 18:13:47 +00001770 populate_glyph_to_unicode(hdc, glyphCount, &(info->fGlyphToUnicode));
1771 }
1772
vandebo@chromium.orgd41e70d2012-03-08 19:41:01 +00001773 if (glyphCount > 0 &&
1774 (otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE)) {
reed@google.comac6b9792011-03-11 15:42:51 +00001775 info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
1776 } else {
edisonn@google.com390c6d72013-04-06 20:26:15 +00001777 goto ReturnInfo;
reed@google.comac6b9792011-03-11 15:42:51 +00001778 }
ctguil@chromium.org5aa937b2011-08-04 01:01:24 +00001779
reed@google.comac6b9792011-03-11 15:42:51 +00001780 // If this bit is clear the font is a fixed pitch font.
1781 if (!(otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
1782 info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
1783 }
1784 if (otm.otmTextMetrics.tmItalic) {
1785 info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
1786 }
reed@google.comac6b9792011-03-11 15:42:51 +00001787 if (otm.otmTextMetrics.tmPitchAndFamily & FF_ROMAN) {
1788 info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
1789 } else if (otm.otmTextMetrics.tmPitchAndFamily & FF_SCRIPT) {
1790 info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
1791 }
1792
1793 // The main italic angle of the font, in tenths of a degree counterclockwise
1794 // from vertical.
1795 info->fItalicAngle = otm.otmItalicAngle / 10;
1796 info->fAscent = SkToS16(otm.otmTextMetrics.tmAscent);
1797 info->fDescent = SkToS16(-otm.otmTextMetrics.tmDescent);
1798 // TODO(ctguil): Use alternate cap height calculation.
1799 // MSDN says otmsCapEmHeight is not support but it is returning a value on
1800 // my Win7 box.
1801 info->fCapHeight = otm.otmsCapEmHeight;
1802 info->fBBox =
1803 SkIRect::MakeLTRB(otm.otmrcFontBox.left, otm.otmrcFontBox.top,
1804 otm.otmrcFontBox.right, otm.otmrcFontBox.bottom);
1805
1806 // Figure out a good guess for StemV - Min width of i, I, !, 1.
1807 // This probably isn't very good with an italic font.
reed@google.com05b6f3a2011-11-28 15:30:28 +00001808 min_width = SHRT_MAX;
reed@google.comac6b9792011-03-11 15:42:51 +00001809 info->fStemV = 0;
reed@google.comac6b9792011-03-11 15:42:51 +00001810 for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) {
1811 ABC abcWidths;
1812 if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) {
1813 int16_t width = abcWidths.abcB;
1814 if (width > 0 && width < min_width) {
1815 min_width = width;
1816 info->fStemV = min_width;
1817 }
1818 }
1819 }
1820
reed39a9a502015-05-12 09:50:04 -07001821 if (perGlyphInfo & kHAdvance_PerGlyphInfo) {
bungemanf1491692016-07-22 11:19:24 -07001822 info->setGlyphWidths(
1823 glyphCount,
1824 glyphIDs,
1825 glyphIDsCount,
1826 SkAdvancedTypefaceMetrics::GetAdvance([hdc](int gId, int16_t* advance) {
1827 // Initialize the MAT2 structure to
1828 // the identify transformation matrix.
1829 static const MAT2 mat2 = {
1830 SkScalarToFIXED(1), SkScalarToFIXED(0),
1831 SkScalarToFIXED(0), SkScalarToFIXED(1)};
1832 int flags = GGO_METRICS | GGO_GLYPH_INDEX;
1833 GLYPHMETRICS gm;
1834 if (GDI_ERROR == GetGlyphOutline(hdc, gId, flags, &gm, 0, nullptr, &mat2)) {
1835 return false;
1836 }
1837 SkASSERT(advance);
1838 *advance = gm.gmCellIncX;
1839 return true;
1840 })
1841 );
reed@google.comac6b9792011-03-11 15:42:51 +00001842 }
1843
1844Error:
edisonn@google.com390c6d72013-04-06 20:26:15 +00001845ReturnInfo:
reed@google.comac6b9792011-03-11 15:42:51 +00001846 SelectObject(hdc, savefont);
1847 DeleteObject(designFont);
1848 DeleteObject(font);
1849 DeleteDC(hdc);
1850
1851 return info;
1852}
1853
bungeman@google.coma5501992012-05-18 19:06:41 +00001854//Dummy representation of a Base64 encoded GUID from create_unique_font_name.
1855#define BASE64_GUID_ID "XXXXXXXXXXXXXXXXXXXXXXXX"
halcanary96fcdcc2015-08-27 07:41:13 -07001856//Length of GUID representation from create_id, including nullptr terminator.
bungeman@google.coma5501992012-05-18 19:06:41 +00001857#define BASE64_GUID_ID_LEN SK_ARRAY_COUNT(BASE64_GUID_ID)
reed@google.comac6b9792011-03-11 15:42:51 +00001858
bungeman99fe8222015-08-20 07:57:51 -07001859static_assert(BASE64_GUID_ID_LEN < LF_FACESIZE, "GUID_longer_than_facesize");
bungeman@google.coma5501992012-05-18 19:06:41 +00001860
1861/**
1862 NameID 6 Postscript names cannot have the character '/'.
1863 It would be easier to hex encode the GUID, but that is 32 bytes,
1864 and many systems have issues with names longer than 28 bytes.
1865 The following need not be any standard base64 encoding.
1866 The encoded value is never decoded.
1867*/
rmistry@google.comd6176b02012-08-23 18:14:13 +00001868static const char postscript_safe_base64_encode[] =
bungeman@google.coma5501992012-05-18 19:06:41 +00001869 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1870 "abcdefghijklmnopqrstuvwxyz"
1871 "0123456789-_=";
1872
1873/**
1874 Formats a GUID into Base64 and places it into buffer.
1875 buffer should have space for at least BASE64_GUID_ID_LEN characters.
1876 The string will always be null terminated.
1877 XXXXXXXXXXXXXXXXXXXXXXXX0
1878 */
1879static void format_guid_b64(const GUID& guid, char* buffer, size_t bufferSize) {
1880 SkASSERT(bufferSize >= BASE64_GUID_ID_LEN);
1881 size_t written = SkBase64::Encode(&guid, sizeof(guid), buffer, postscript_safe_base64_encode);
1882 SkASSERT(written < LF_FACESIZE);
1883 buffer[written] = '\0';
1884}
1885
1886/**
1887 Creates a Base64 encoded GUID and places it into buffer.
1888 buffer should have space for at least BASE64_GUID_ID_LEN characters.
1889 The string will always be null terminated.
1890 XXXXXXXXXXXXXXXXXXXXXXXX0
1891 */
1892static HRESULT create_unique_font_name(char* buffer, size_t bufferSize) {
1893 GUID guid = {};
1894 if (FAILED(CoCreateGuid(&guid))) {
1895 return E_UNEXPECTED;
1896 }
1897 format_guid_b64(guid, buffer, bufferSize);
1898
1899 return S_OK;
1900}
1901
1902/**
halcanary96fcdcc2015-08-27 07:41:13 -07001903 Introduces a font to GDI. On failure will return nullptr. The returned handle
bungeman@google.coma5501992012-05-18 19:06:41 +00001904 should eventually be passed to RemoveFontMemResourceEx.
1905*/
1906static HANDLE activate_font(SkData* fontData) {
1907 DWORD numFonts = 0;
1908 //AddFontMemResourceEx just copies the data, but does not specify const.
1909 HANDLE fontHandle = AddFontMemResourceEx(const_cast<void*>(fontData->data()),
bungeman@google.com4b18f572013-07-22 15:21:23 +00001910 static_cast<DWORD>(fontData->size()),
bungeman@google.coma5501992012-05-18 19:06:41 +00001911 0,
1912 &numFonts);
1913
halcanary96fcdcc2015-08-27 07:41:13 -07001914 if (fontHandle != nullptr && numFonts < 1) {
bungeman@google.coma5501992012-05-18 19:06:41 +00001915 RemoveFontMemResourceEx(fontHandle);
halcanary96fcdcc2015-08-27 07:41:13 -07001916 return nullptr;
bungeman@google.coma5501992012-05-18 19:06:41 +00001917 }
1918
1919 return fontHandle;
1920}
1921
scroggoa1193e42015-01-21 12:09:53 -08001922// Does not affect ownership of stream.
bungeman5f213d92015-01-27 05:39:10 -08001923static SkTypeface* create_from_stream(SkStreamAsset* stream) {
bungeman@google.coma5501992012-05-18 19:06:41 +00001924 // Create a unique and unpredictable font name.
1925 // Avoids collisions and access from CSS.
1926 char familyName[BASE64_GUID_ID_LEN];
1927 const int familyNameSize = SK_ARRAY_COUNT(familyName);
1928 if (FAILED(create_unique_font_name(familyName, familyNameSize))) {
halcanary96fcdcc2015-08-27 07:41:13 -07001929 return nullptr;
bungeman@google.coma5501992012-05-18 19:06:41 +00001930 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001931
bungeman@google.coma5501992012-05-18 19:06:41 +00001932 // Change the name of the font.
bungemanffae30d2016-08-03 13:32:32 -07001933 sk_sp<SkData> rewrittenFontData(SkOTUtils::RenameFont(stream, familyName, familyNameSize-1));
halcanary96fcdcc2015-08-27 07:41:13 -07001934 if (nullptr == rewrittenFontData.get()) {
1935 return nullptr;
bungeman@google.coma5501992012-05-18 19:06:41 +00001936 }
bungeman@google.coma5501992012-05-18 19:06:41 +00001937
1938 // Register the font with GDI.
bungeman@google.come9bbee32012-05-21 13:46:13 +00001939 HANDLE fontReference = activate_font(rewrittenFontData.get());
halcanary96fcdcc2015-08-27 07:41:13 -07001940 if (nullptr == fontReference) {
1941 return nullptr;
bungeman@google.coma5501992012-05-18 19:06:41 +00001942 }
1943
1944 // Create the typeface.
1945 LOGFONT lf;
reed@google.com484f5bc2013-04-24 19:14:56 +00001946 logfont_for_name(familyName, &lf);
bungeman@google.coma5501992012-05-18 19:06:41 +00001947
1948 return SkCreateFontMemResourceTypefaceFromLOGFONT(lf, fontReference);
reed@google.comac6b9792011-03-11 15:42:51 +00001949}
1950
bungeman5f213d92015-01-27 05:39:10 -08001951SkStreamAsset* LogFontTypeface::onOpenStream(int* ttcIndex) const {
reed@google.com0042b9c2013-03-21 20:16:04 +00001952 *ttcIndex = 0;
1953
ctguil@chromium.orgf4c26222011-05-16 22:00:05 +00001954 const DWORD kTTCTag =
1955 SkEndian_SwapBE32(SkSetFourByteTag('t', 't', 'c', 'f'));
reed@google.com0042b9c2013-03-21 20:16:04 +00001956 LOGFONT lf = fLogFont;
reed@google.comac6b9792011-03-11 15:42:51 +00001957
halcanary96fcdcc2015-08-27 07:41:13 -07001958 HDC hdc = ::CreateCompatibleDC(nullptr);
reed@google.com59d2f632011-05-02 19:36:59 +00001959 HFONT font = CreateFontIndirect(&lf);
reed@google.comac6b9792011-03-11 15:42:51 +00001960 HFONT savefont = (HFONT)SelectObject(hdc, font);
1961
halcanary96fcdcc2015-08-27 07:41:13 -07001962 SkMemoryStream* stream = nullptr;
vandebo@chromium.orgd6044812011-05-13 03:41:29 +00001963 DWORD tables[2] = {kTTCTag, 0};
1964 for (int i = 0; i < SK_ARRAY_COUNT(tables); i++) {
halcanary96fcdcc2015-08-27 07:41:13 -07001965 DWORD bufferSize = GetFontData(hdc, tables[i], 0, nullptr, 0);
bungeman@google.com39698b12011-11-15 22:26:41 +00001966 if (bufferSize == GDI_ERROR) {
reed@google.com055180c2013-03-21 18:46:35 +00001967 call_ensure_accessible(lf);
halcanary96fcdcc2015-08-27 07:41:13 -07001968 bufferSize = GetFontData(hdc, tables[i], 0, nullptr, 0);
bungeman@google.com39698b12011-11-15 22:26:41 +00001969 }
vandebo@chromium.orgd6044812011-05-13 03:41:29 +00001970 if (bufferSize != GDI_ERROR) {
1971 stream = new SkMemoryStream(bufferSize);
bungeman@google.com4b18f572013-07-22 15:21:23 +00001972 if (GetFontData(hdc, tables[i], 0, (void*)stream->getMemoryBase(), bufferSize)) {
vandebo@chromium.orgd6044812011-05-13 03:41:29 +00001973 break;
1974 } else {
1975 delete stream;
halcanary96fcdcc2015-08-27 07:41:13 -07001976 stream = nullptr;
vandebo@chromium.orgd6044812011-05-13 03:41:29 +00001977 }
1978 }
reed@google.comac6b9792011-03-11 15:42:51 +00001979 }
1980
1981 SelectObject(hdc, savefont);
1982 DeleteObject(font);
1983 DeleteDC(hdc);
1984
1985 return stream;
1986}
1987
bungeman@google.com3c996f82013-10-24 21:39:35 +00001988static void bmpCharsToGlyphs(HDC hdc, const WCHAR* bmpChars, int count, uint16_t* glyphs,
1989 bool Ox1FHack)
1990{
1991 DWORD result = GetGlyphIndicesW(hdc, bmpChars, count, glyphs, GGI_MARK_NONEXISTING_GLYPHS);
1992 if (GDI_ERROR == result) {
1993 for (int i = 0; i < count; ++i) {
1994 glyphs[i] = 0;
1995 }
1996 return;
1997 }
1998
1999 if (Ox1FHack) {
2000 for (int i = 0; i < count; ++i) {
2001 if (0xFFFF == glyphs[i] || 0x1F == glyphs[i]) {
2002 glyphs[i] = 0;
2003 }
2004 }
2005 } else {
2006 for (int i = 0; i < count; ++i) {
2007 if (0xFFFF == glyphs[i]){
2008 glyphs[i] = 0;
2009 }
2010 }
2011 }
2012}
2013
2014static uint16_t nonBmpCharToGlyph(HDC hdc, SCRIPT_CACHE* scriptCache, const WCHAR utf16[2]) {
2015 uint16_t index = 0;
2016 // Use uniscribe to detemine glyph index for non-BMP characters.
2017 static const int numWCHAR = 2;
2018 static const int maxItems = 2;
halcanary96fcdcc2015-08-27 07:41:13 -07002019 // MSDN states that this can be nullptr, but some things don't work then.
bungeman@google.com3c996f82013-10-24 21:39:35 +00002020 SCRIPT_CONTROL scriptControl = { 0 };
2021 // Add extra item to SCRIPT_ITEM to work around a bug (now documented).
2022 // https://bugzilla.mozilla.org/show_bug.cgi?id=366643
2023 SCRIPT_ITEM si[maxItems + 1];
2024 int numItems;
halcanary96fcdcc2015-08-27 07:41:13 -07002025 HRZM(ScriptItemize(utf16, numWCHAR, maxItems, &scriptControl, nullptr, si, &numItems),
bungeman@google.com3c996f82013-10-24 21:39:35 +00002026 "Could not itemize character.");
2027
2028 // Sometimes ScriptShape cannot find a glyph for a non-BMP and returns 2 space glyphs.
2029 static const int maxGlyphs = 2;
2030 SCRIPT_VISATTR vsa[maxGlyphs];
2031 WORD outGlyphs[maxGlyphs];
2032 WORD logClust[numWCHAR];
2033 int numGlyphs;
2034 HRZM(ScriptShape(hdc, scriptCache, utf16, numWCHAR, maxGlyphs, &si[0].a,
2035 outGlyphs, logClust, vsa, &numGlyphs),
2036 "Could not shape character.");
2037 if (1 == numGlyphs) {
2038 index = outGlyphs[0];
2039 }
2040 return index;
2041}
2042
2043class SkAutoHDC {
2044public:
2045 SkAutoHDC(const LOGFONT& lf)
halcanary96fcdcc2015-08-27 07:41:13 -07002046 : fHdc(::CreateCompatibleDC(nullptr))
bungeman@google.com3c996f82013-10-24 21:39:35 +00002047 , fFont(::CreateFontIndirect(&lf))
2048 , fSavefont((HFONT)SelectObject(fHdc, fFont))
2049 { }
2050 ~SkAutoHDC() {
2051 SelectObject(fHdc, fSavefont);
2052 DeleteObject(fFont);
2053 DeleteDC(fHdc);
2054 }
2055 operator HDC() { return fHdc; }
2056private:
2057 HDC fHdc;
2058 HFONT fFont;
2059 HFONT fSavefont;
2060};
commit-bot@chromium.orge61a86c2013-11-18 16:03:59 +00002061#define SkAutoHDC(...) SK_REQUIRE_LOCAL_VAR(SkAutoHDC)
bungeman@google.com3c996f82013-10-24 21:39:35 +00002062
2063int LogFontTypeface::onCharsToGlyphs(const void* chars, Encoding encoding,
2064 uint16_t userGlyphs[], int glyphCount) const
2065{
2066 SkAutoHDC hdc(fLogFont);
2067
2068 TEXTMETRIC tm;
2069 if (0 == GetTextMetrics(hdc, &tm)) {
2070 call_ensure_accessible(fLogFont);
2071 if (0 == GetTextMetrics(hdc, &tm)) {
2072 tm.tmPitchAndFamily = TMPF_TRUETYPE;
2073 }
2074 }
2075 bool Ox1FHack = !(tm.tmPitchAndFamily & TMPF_VECTOR) /*&& winVer < Vista */;
2076
2077 SkAutoSTMalloc<256, uint16_t> scratchGlyphs;
2078 uint16_t* glyphs;
halcanary96fcdcc2015-08-27 07:41:13 -07002079 if (userGlyphs != nullptr) {
bungeman@google.com3c996f82013-10-24 21:39:35 +00002080 glyphs = userGlyphs;
2081 } else {
2082 glyphs = scratchGlyphs.reset(glyphCount);
2083 }
2084
2085 SCRIPT_CACHE sc = 0;
2086 switch (encoding) {
2087 case SkTypeface::kUTF8_Encoding: {
2088 static const int scratchCount = 256;
2089 WCHAR scratch[scratchCount];
2090 int glyphIndex = 0;
2091 const char* currentUtf8 = reinterpret_cast<const char*>(chars);
2092 SkUnichar currentChar;
2093 if (glyphCount) {
2094 currentChar = SkUTF8_NextUnichar(&currentUtf8);
2095 }
2096 while (glyphIndex < glyphCount) {
2097 // Try a run of bmp.
2098 int glyphsLeft = SkTMin(glyphCount - glyphIndex, scratchCount);
2099 int runLength = 0;
2100 while (runLength < glyphsLeft && currentChar <= 0xFFFF) {
2101 scratch[runLength] = static_cast<WCHAR>(currentChar);
2102 ++runLength;
2103 if (runLength < glyphsLeft) {
2104 currentChar = SkUTF8_NextUnichar(&currentUtf8);
2105 }
2106 }
2107 if (runLength) {
2108 bmpCharsToGlyphs(hdc, scratch, runLength, &glyphs[glyphIndex], Ox1FHack);
2109 glyphIndex += runLength;
2110 }
2111
2112 // Try a run of non-bmp.
2113 while (glyphIndex < glyphCount && currentChar > 0xFFFF) {
2114 SkUTF16_FromUnichar(currentChar, reinterpret_cast<uint16_t*>(scratch));
2115 glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, scratch);
2116 ++glyphIndex;
2117 if (glyphIndex < glyphCount) {
2118 currentChar = SkUTF8_NextUnichar(&currentUtf8);
2119 }
2120 }
2121 }
2122 break;
2123 }
2124 case SkTypeface::kUTF16_Encoding: {
2125 int glyphIndex = 0;
2126 const WCHAR* currentUtf16 = reinterpret_cast<const WCHAR*>(chars);
2127 while (glyphIndex < glyphCount) {
2128 // Try a run of bmp.
2129 int glyphsLeft = glyphCount - glyphIndex;
2130 int runLength = 0;
2131 while (runLength < glyphsLeft && !SkUTF16_IsHighSurrogate(currentUtf16[runLength])) {
2132 ++runLength;
2133 }
2134 if (runLength) {
2135 bmpCharsToGlyphs(hdc, currentUtf16, runLength, &glyphs[glyphIndex], Ox1FHack);
2136 glyphIndex += runLength;
2137 currentUtf16 += runLength;
2138 }
2139
2140 // Try a run of non-bmp.
2141 while (glyphIndex < glyphCount && SkUTF16_IsHighSurrogate(*currentUtf16)) {
2142 glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, currentUtf16);
2143 ++glyphIndex;
2144 currentUtf16 += 2;
2145 }
2146 }
2147 break;
2148 }
2149 case SkTypeface::kUTF32_Encoding: {
2150 static const int scratchCount = 256;
2151 WCHAR scratch[scratchCount];
2152 int glyphIndex = 0;
2153 const uint32_t* utf32 = reinterpret_cast<const uint32_t*>(chars);
2154 while (glyphIndex < glyphCount) {
2155 // Try a run of bmp.
2156 int glyphsLeft = SkTMin(glyphCount - glyphIndex, scratchCount);
2157 int runLength = 0;
2158 while (runLength < glyphsLeft && utf32[glyphIndex + runLength] <= 0xFFFF) {
2159 scratch[runLength] = static_cast<WCHAR>(utf32[glyphIndex + runLength]);
2160 ++runLength;
2161 }
2162 if (runLength) {
2163 bmpCharsToGlyphs(hdc, scratch, runLength, &glyphs[glyphIndex], Ox1FHack);
2164 glyphIndex += runLength;
2165 }
2166
2167 // Try a run of non-bmp.
2168 while (glyphIndex < glyphCount && utf32[glyphIndex] > 0xFFFF) {
2169 SkUTF16_FromUnichar(utf32[glyphIndex], reinterpret_cast<uint16_t*>(scratch));
2170 glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, scratch);
2171 ++glyphIndex;
2172 }
2173 }
2174 break;
2175 }
2176 default:
djsollenf2b340f2016-01-29 08:51:04 -08002177 SK_ABORT("Invalid Text Encoding");
bungeman@google.com3c996f82013-10-24 21:39:35 +00002178 }
2179
2180 if (sc) {
2181 ::ScriptFreeCache(&sc);
2182 }
2183
2184 for (int i = 0; i < glyphCount; ++i) {
2185 if (0 == glyphs[i]) {
2186 return i;
2187 }
2188 }
2189 return glyphCount;
2190}
2191
bungeman@google.com7bdd6142013-07-15 19:42:57 +00002192int LogFontTypeface::onCountGlyphs() const {
halcanary96fcdcc2015-08-27 07:41:13 -07002193 HDC hdc = ::CreateCompatibleDC(nullptr);
bungeman@google.com7bdd6142013-07-15 19:42:57 +00002194 HFONT font = CreateFontIndirect(&fLogFont);
2195 HFONT savefont = (HFONT)SelectObject(hdc, font);
2196
2197 unsigned int glyphCount = calculateGlyphCount(hdc, fLogFont);
2198
2199 SelectObject(hdc, savefont);
2200 DeleteObject(font);
2201 DeleteDC(hdc);
2202
2203 return glyphCount;
2204}
2205
2206int LogFontTypeface::onGetUPEM() const {
halcanary96fcdcc2015-08-27 07:41:13 -07002207 HDC hdc = ::CreateCompatibleDC(nullptr);
bungeman@google.com7bdd6142013-07-15 19:42:57 +00002208 HFONT font = CreateFontIndirect(&fLogFont);
2209 HFONT savefont = (HFONT)SelectObject(hdc, font);
2210
2211 unsigned int upem = calculateUPEM(hdc, fLogFont);
2212
2213 SelectObject(hdc, savefont);
2214 DeleteObject(font);
2215 DeleteDC(hdc);
2216
2217 return upem;
2218}
2219
bungeman@google.com839702b2013-08-07 17:09:22 +00002220SkTypeface::LocalizedStrings* LogFontTypeface::onCreateFamilyNameIterator() const {
bungeman@google.coma9802692013-08-07 02:45:25 +00002221 SkTypeface::LocalizedStrings* nameIter =
2222 SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(*this);
halcanary96fcdcc2015-08-27 07:41:13 -07002223 if (nullptr == nameIter) {
bungeman@google.coma9802692013-08-07 02:45:25 +00002224 SkString familyName;
2225 this->getFamilyName(&familyName);
2226 SkString language("und"); //undetermined
2227 nameIter = new SkOTUtils::LocalizedStrings_SingleName(familyName, language);
2228 }
2229 return nameIter;
2230}
2231
bungeman@google.comb10b51f2013-08-01 20:18:41 +00002232int LogFontTypeface::onGetTableTags(SkFontTableTag tags[]) const {
2233 SkSFNTHeader header;
2234 if (sizeof(header) != this->onGetTableData(0, 0, sizeof(header), &header)) {
2235 return 0;
2236 }
2237
2238 int numTables = SkEndian_SwapBE16(header.numTables);
2239
2240 if (tags) {
2241 size_t size = numTables * sizeof(SkSFNTHeader::TableDirectoryEntry);
2242 SkAutoSTMalloc<0x20, SkSFNTHeader::TableDirectoryEntry> dir(numTables);
2243 if (size != this->onGetTableData(0, sizeof(header), size, dir.get())) {
2244 return 0;
2245 }
2246
2247 for (int i = 0; i < numTables; ++i) {
2248 tags[i] = SkEndian_SwapBE32(dir[i].tag);
2249 }
2250 }
2251 return numTables;
2252}
2253
2254size_t LogFontTypeface::onGetTableData(SkFontTableTag tag, size_t offset,
2255 size_t length, void* data) const
2256{
2257 LOGFONT lf = fLogFont;
2258
halcanary96fcdcc2015-08-27 07:41:13 -07002259 HDC hdc = ::CreateCompatibleDC(nullptr);
bungeman@google.comb10b51f2013-08-01 20:18:41 +00002260 HFONT font = CreateFontIndirect(&lf);
2261 HFONT savefont = (HFONT)SelectObject(hdc, font);
2262
2263 tag = SkEndian_SwapBE32(tag);
halcanary96fcdcc2015-08-27 07:41:13 -07002264 if (nullptr == data) {
bungeman@google.comb10b51f2013-08-01 20:18:41 +00002265 length = 0;
2266 }
robertphillips@google.com8b169312013-10-15 17:47:36 +00002267 DWORD bufferSize = GetFontData(hdc, tag, (DWORD) offset, data, (DWORD) length);
bungeman@google.comb10b51f2013-08-01 20:18:41 +00002268 if (bufferSize == GDI_ERROR) {
2269 call_ensure_accessible(lf);
robertphillips@google.com8b169312013-10-15 17:47:36 +00002270 bufferSize = GetFontData(hdc, tag, (DWORD) offset, data, (DWORD) length);
bungeman@google.comb10b51f2013-08-01 20:18:41 +00002271 }
2272
2273 SelectObject(hdc, savefont);
2274 DeleteObject(font);
2275 DeleteDC(hdc);
2276
2277 return bufferSize == GDI_ERROR ? 0 : bufferSize;
2278}
2279
reeda9322c22016-04-12 06:47:05 -07002280SkScalerContext* LogFontTypeface::onCreateScalerContext(const SkScalerContextEffects& effects,
2281 const SkDescriptor* desc) const {
2282 SkScalerContext_GDI* ctx = new SkScalerContext_GDI(const_cast<LogFontTypeface*>(this),
2283 effects, desc);
reed@google.com84e22d82013-07-10 15:38:20 +00002284 if (!ctx->isValid()) {
halcanary385fe4d2015-08-26 13:07:48 -07002285 delete ctx;
halcanary96fcdcc2015-08-27 07:41:13 -07002286 ctx = nullptr;
reed@google.com84e22d82013-07-10 15:38:20 +00002287 }
2288 return ctx;
reed@google.comac6b9792011-03-11 15:42:51 +00002289}
2290
reed@google.com0da48612013-03-19 16:06:52 +00002291void LogFontTypeface::onFilterRec(SkScalerContextRec* rec) const {
commit-bot@chromium.orgc5fd4612013-05-06 22:23:08 +00002292 if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag ||
2293 rec->fFlags & SkScalerContext::kLCD_Vertical_Flag)
2294 {
2295 rec->fMaskFormat = SkMask::kA8_Format;
2296 rec->fFlags |= SkScalerContext::kGenA8FromLCD_Flag;
2297 }
2298
bungeman41078062014-07-07 08:16:37 -07002299 unsigned flagsWeDontSupport = SkScalerContext::kVertical_Flag |
2300 SkScalerContext::kDevKernText_Flag |
bungeman@google.comf6f56872014-01-23 19:01:36 +00002301 SkScalerContext::kForceAutohinting_Flag |
reed@google.come8fab012011-07-13 15:25:33 +00002302 SkScalerContext::kEmbeddedBitmapText_Flag |
2303 SkScalerContext::kEmbolden_Flag |
2304 SkScalerContext::kLCD_BGROrder_Flag |
2305 SkScalerContext::kLCD_Vertical_Flag;
2306 rec->fFlags &= ~flagsWeDontSupport;
2307
reed@google.come8fab012011-07-13 15:25:33 +00002308 SkPaint::Hinting h = rec->getHinting();
2309 switch (h) {
2310 case SkPaint::kNo_Hinting:
bungeman@google.com0abbff92013-07-27 20:37:56 +00002311 break;
reed@google.come8fab012011-07-13 15:25:33 +00002312 case SkPaint::kSlight_Hinting:
bungeman@google.com0abbff92013-07-27 20:37:56 +00002313 // Only do slight hinting when axis aligned.
bungeman@google.com7c86d8e2013-07-27 21:42:21 +00002314 // TODO: re-enable slight hinting when FontHostTest can pass.
2315 //if (!isAxisAligned(*rec)) {
bungeman@google.com0abbff92013-07-27 20:37:56 +00002316 h = SkPaint::kNo_Hinting;
bungeman@google.com7c86d8e2013-07-27 21:42:21 +00002317 //}
reed@google.come8fab012011-07-13 15:25:33 +00002318 break;
2319 case SkPaint::kNormal_Hinting:
2320 case SkPaint::kFull_Hinting:
bungeman@google.com0abbff92013-07-27 20:37:56 +00002321 // TODO: need to be able to distinguish subpixel positioned glyphs
2322 // and linear metrics.
2323 //rec->fFlags &= ~SkScalerContext::kSubpixelPositioning_Flag;
reed@google.come8fab012011-07-13 15:25:33 +00002324 h = SkPaint::kNormal_Hinting;
2325 break;
2326 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00002327 SkDEBUGFAIL("unknown hinting");
reed@google.come8fab012011-07-13 15:25:33 +00002328 }
bungeman@google.com0abbff92013-07-27 20:37:56 +00002329 //TODO: if this is a bitmap font, squash hinting and subpixel.
reed@google.come8fab012011-07-13 15:25:33 +00002330 rec->setHinting(h);
reed@google.comda440672011-07-13 18:02:28 +00002331
reed@google.com9181aa82011-08-05 14:28:31 +00002332// turn this off since GDI might turn A8 into BW! Need a bigger fix.
2333#if 0
reed@google.comda440672011-07-13 18:02:28 +00002334 // Disable LCD when rotated, since GDI's output is ugly
2335 if (isLCD(*rec) && !isAxisAligned(*rec)) {
2336 rec->fMaskFormat = SkMask::kA8_Format;
2337 }
reed@google.com9181aa82011-08-05 14:28:31 +00002338#endif
reed@google.com754e4eb2011-09-26 13:21:39 +00002339
reed@google.com0da48612013-03-19 16:06:52 +00002340 if (!fCanBeLCD && isLCD(*rec)) {
bungeman@google.comcb1bbb32012-10-12 18:48:35 +00002341 rec->fMaskFormat = SkMask::kA8_Format;
2342 rec->fFlags &= ~SkScalerContext::kGenA8FromLCD_Flag;
reed@google.com754e4eb2011-09-26 13:21:39 +00002343 }
reed@google.com754e4eb2011-09-26 13:21:39 +00002344}
reed@google.com070da5e2013-03-27 20:01:49 +00002345
2346///////////////////////////////////////////////////////////////////////////////
2347
2348#include "SkFontMgr.h"
reed@google.com484f5bc2013-04-24 19:14:56 +00002349#include "SkDataTable.h"
2350
bungeman@google.coma9802692013-08-07 02:45:25 +00002351static bool valid_logfont_for_enum(const LOGFONT& lf) {
2352 // TODO: Vector FON is unsupported and should not be listed.
2353 return
2354 // Ignore implicit vertical variants.
2355 lf.lfFaceName[0] && lf.lfFaceName[0] != '@'
2356
2357 // DEFAULT_CHARSET is used to get all fonts, but also implies all
2358 // character sets. Filter assuming all fonts support ANSI_CHARSET.
2359 && ANSI_CHARSET == lf.lfCharSet
2360 ;
reed@google.com484f5bc2013-04-24 19:14:56 +00002361}
2362
bungeman@google.coma9802692013-08-07 02:45:25 +00002363/** An EnumFontFamExProc implementation which interprets builderParam as
2364 * an SkTDArray<ENUMLOGFONTEX>* and appends logfonts which
2365 * pass the valid_logfont_for_enum predicate.
2366 */
2367static int CALLBACK enum_family_proc(const LOGFONT* lf, const TEXTMETRIC*,
2368 DWORD fontType, LPARAM builderParam) {
2369 if (valid_logfont_for_enum(*lf)) {
reed@google.coma65a6812013-05-02 19:47:24 +00002370 SkTDArray<ENUMLOGFONTEX>* array = (SkTDArray<ENUMLOGFONTEX>*)builderParam;
2371 *array->append() = *(ENUMLOGFONTEX*)lf;
reed@google.com484f5bc2013-04-24 19:14:56 +00002372 }
2373 return 1; // non-zero means continue
2374}
2375
reed@google.com484f5bc2013-04-24 19:14:56 +00002376class SkFontStyleSetGDI : public SkFontStyleSet {
2377public:
reed@google.coma65a6812013-05-02 19:47:24 +00002378 SkFontStyleSetGDI(const TCHAR familyName[]) {
bungeman@google.coma9802692013-08-07 02:45:25 +00002379 LOGFONT lf;
2380 sk_bzero(&lf, sizeof(lf));
2381 lf.lfCharSet = DEFAULT_CHARSET;
2382 _tcscpy_s(lf.lfFaceName, familyName);
2383
halcanary96fcdcc2015-08-27 07:41:13 -07002384 HDC hdc = ::CreateCompatibleDC(nullptr);
bungeman@google.coma9802692013-08-07 02:45:25 +00002385 ::EnumFontFamiliesEx(hdc, &lf, enum_family_proc, (LPARAM)&fArray, 0);
reed@google.com484f5bc2013-04-24 19:14:56 +00002386 ::DeleteDC(hdc);
2387 }
2388
mtklein36352bf2015-03-25 18:17:31 -07002389 int count() override {
reed@google.com484f5bc2013-04-24 19:14:56 +00002390 return fArray.count();
2391 }
2392
mtklein36352bf2015-03-25 18:17:31 -07002393 void getStyle(int index, SkFontStyle* fs, SkString* styleName) override {
reed@google.com484f5bc2013-04-24 19:14:56 +00002394 if (fs) {
bungemana4c4a2d2014-10-20 13:33:19 -07002395 *fs = get_style(fArray[index].elfLogFont);
reed@google.com484f5bc2013-04-24 19:14:56 +00002396 }
reed@google.coma65a6812013-05-02 19:47:24 +00002397 if (styleName) {
2398 const ENUMLOGFONTEX& ref = fArray[index];
2399 // For some reason, ENUMLOGFONTEX and LOGFONT disagree on their type in the
2400 // non-unicode version.
2401 // ENUMLOGFONTEX uses BYTE
2402 // LOGFONT uses CHAR
2403 // Here we assert they that the style name is logically the same (size) as
2404 // a TCHAR, so we can use the same converter function.
2405 SkASSERT(sizeof(TCHAR) == sizeof(ref.elfStyle[0]));
2406 tchar_to_skstring((const TCHAR*)ref.elfStyle, styleName);
2407 }
reed@google.com484f5bc2013-04-24 19:14:56 +00002408 }
2409
mtklein36352bf2015-03-25 18:17:31 -07002410 SkTypeface* createTypeface(int index) override {
reed@google.coma65a6812013-05-02 19:47:24 +00002411 return SkCreateTypefaceFromLOGFONT(fArray[index].elfLogFont);
reed@google.com484f5bc2013-04-24 19:14:56 +00002412 }
2413
mtklein36352bf2015-03-25 18:17:31 -07002414 SkTypeface* matchStyle(const SkFontStyle& pattern) override {
bungeman147ea2f2015-11-12 09:50:08 -08002415 return this->matchStyleCSS3(pattern);
reed@google.com484f5bc2013-04-24 19:14:56 +00002416 }
2417
2418private:
reed@google.coma65a6812013-05-02 19:47:24 +00002419 SkTDArray<ENUMLOGFONTEX> fArray;
reed@google.com484f5bc2013-04-24 19:14:56 +00002420};
2421
reed@google.com484f5bc2013-04-24 19:14:56 +00002422class SkFontMgrGDI : public SkFontMgr {
bungeman@google.coma9802692013-08-07 02:45:25 +00002423public:
2424 SkFontMgrGDI() {
reed@google.com484f5bc2013-04-24 19:14:56 +00002425 LOGFONT lf;
2426 sk_bzero(&lf, sizeof(lf));
2427 lf.lfCharSet = DEFAULT_CHARSET;
2428
halcanary96fcdcc2015-08-27 07:41:13 -07002429 HDC hdc = ::CreateCompatibleDC(nullptr);
reed@google.com484f5bc2013-04-24 19:14:56 +00002430 ::EnumFontFamiliesEx(hdc, &lf, enum_family_proc, (LPARAM)&fLogFontArray, 0);
2431 ::DeleteDC(hdc);
2432 }
2433
reed@google.com484f5bc2013-04-24 19:14:56 +00002434protected:
mtklein36352bf2015-03-25 18:17:31 -07002435 int onCountFamilies() const override {
reed@google.com484f5bc2013-04-24 19:14:56 +00002436 return fLogFontArray.count();
2437 }
2438
mtklein36352bf2015-03-25 18:17:31 -07002439 void onGetFamilyName(int index, SkString* familyName) const override {
reed@google.com484f5bc2013-04-24 19:14:56 +00002440 SkASSERT((unsigned)index < (unsigned)fLogFontArray.count());
reed@google.coma65a6812013-05-02 19:47:24 +00002441 tchar_to_skstring(fLogFontArray[index].elfLogFont.lfFaceName, familyName);
reed@google.com484f5bc2013-04-24 19:14:56 +00002442 }
2443
mtklein36352bf2015-03-25 18:17:31 -07002444 SkFontStyleSet* onCreateStyleSet(int index) const override {
reed@google.com484f5bc2013-04-24 19:14:56 +00002445 SkASSERT((unsigned)index < (unsigned)fLogFontArray.count());
halcanary385fe4d2015-08-26 13:07:48 -07002446 return new SkFontStyleSetGDI(fLogFontArray[index].elfLogFont.lfFaceName);
reed@google.com484f5bc2013-04-24 19:14:56 +00002447 }
2448
mtklein36352bf2015-03-25 18:17:31 -07002449 SkFontStyleSet* onMatchFamily(const char familyName[]) const override {
halcanary96fcdcc2015-08-27 07:41:13 -07002450 if (nullptr == familyName) {
reed@google.com484f5bc2013-04-24 19:14:56 +00002451 familyName = ""; // do we need this check???
2452 }
2453 LOGFONT lf;
2454 logfont_for_name(familyName, &lf);
halcanary385fe4d2015-08-26 13:07:48 -07002455 return new SkFontStyleSetGDI(lf.lfFaceName);
reed@google.com484f5bc2013-04-24 19:14:56 +00002456 }
2457
reed@google.com484f5bc2013-04-24 19:14:56 +00002458 virtual SkTypeface* onMatchFamilyStyle(const char familyName[],
mtklein36352bf2015-03-25 18:17:31 -07002459 const SkFontStyle& fontstyle) const override {
reed@google.com437eea12013-04-25 20:40:02 +00002460 // could be in base impl
reed@google.com484f5bc2013-04-24 19:14:56 +00002461 SkAutoTUnref<SkFontStyleSet> sset(this->matchFamily(familyName));
2462 return sset->matchStyle(fontstyle);
2463 }
2464
djsollen33068c12014-11-14 10:52:53 -08002465 virtual SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle&,
2466 const char* bcp47[], int bcp47Count,
mtklein36352bf2015-03-25 18:17:31 -07002467 SkUnichar character) const override {
halcanary96fcdcc2015-08-27 07:41:13 -07002468 return nullptr;
djsollen33068c12014-11-14 10:52:53 -08002469 }
2470
reed@google.com484f5bc2013-04-24 19:14:56 +00002471 virtual SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember,
mtklein36352bf2015-03-25 18:17:31 -07002472 const SkFontStyle& fontstyle) const override {
reed@google.com437eea12013-04-25 20:40:02 +00002473 // could be in base impl
reed@google.com484f5bc2013-04-24 19:14:56 +00002474 SkString familyName;
2475 ((LogFontTypeface*)familyMember)->getFamilyName(&familyName);
2476 return this->matchFamilyStyle(familyName.c_str(), fontstyle);
2477 }
2478
mtklein36352bf2015-03-25 18:17:31 -07002479 SkTypeface* onCreateFromStream(SkStreamAsset* bareStream, int ttcIndex) const override {
bungeman5f213d92015-01-27 05:39:10 -08002480 SkAutoTDelete<SkStreamAsset> stream(bareStream);
reed@google.com437eea12013-04-25 20:40:02 +00002481 return create_from_stream(stream);
reed@google.com484f5bc2013-04-24 19:14:56 +00002482 }
reed@google.com437eea12013-04-25 20:40:02 +00002483
mtklein36352bf2015-03-25 18:17:31 -07002484 SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const override {
reed@google.com437eea12013-04-25 20:40:02 +00002485 // could be in base impl
halcanary385fe4d2015-08-26 13:07:48 -07002486 return this->createFromStream(new SkMemoryStream(data));
reed@google.com484f5bc2013-04-24 19:14:56 +00002487 }
reed@google.com437eea12013-04-25 20:40:02 +00002488
mtklein36352bf2015-03-25 18:17:31 -07002489 SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override {
reed@google.com437eea12013-04-25 20:40:02 +00002490 // could be in base impl
scroggoa1193e42015-01-21 12:09:53 -08002491 return this->createFromStream(SkStream::NewFromFile(path));
reed@google.com484f5bc2013-04-24 19:14:56 +00002492 }
2493
bungeman11a77c62016-04-12 13:45:06 -07002494 SkTypeface* onLegacyCreateTypeface(const char familyName[], SkFontStyle style) const override {
bungeman@google.comf7159bb2013-11-20 15:11:05 +00002495 LOGFONT lf;
halcanary96fcdcc2015-08-27 07:41:13 -07002496 if (nullptr == familyName) {
bungeman@google.comf7159bb2013-11-20 15:11:05 +00002497 lf = get_default_font();
2498 } else {
2499 logfont_for_name(familyName, &lf);
2500 }
bungemana4c4a2d2014-10-20 13:33:19 -07002501
bungeman11a77c62016-04-12 13:45:06 -07002502 lf.lfWeight = style.weight();
bungemanb4bb7d82016-04-27 10:21:04 -07002503 lf.lfItalic = style.slant() == SkFontStyle::kUpright_Slant ? FALSE : TRUE;
bungeman@google.comf7159bb2013-11-20 15:11:05 +00002504 return SkCreateTypefaceFromLOGFONT(lf);
reed@google.com30ddd612013-07-30 17:47:39 +00002505 }
2506
reed@google.com484f5bc2013-04-24 19:14:56 +00002507private:
reed@google.coma65a6812013-05-02 19:47:24 +00002508 SkTDArray<ENUMLOGFONTEX> fLogFontArray;
reed@google.com484f5bc2013-04-24 19:14:56 +00002509};
reed@google.com070da5e2013-03-27 20:01:49 +00002510
reed@google.com30ddd612013-07-30 17:47:39 +00002511///////////////////////////////////////////////////////////////////////////////
2512
halcanary385fe4d2015-08-26 13:07:48 -07002513SkFontMgr* SkFontMgr_New_GDI() { return new SkFontMgrGDI; }
mtklein1ee76512015-11-02 10:20:27 -08002514
2515#endif//defined(SK_BUILD_FOR_WIN32)