blob: 49289712e1dad17b4515c3137871cf1d5b639fd4 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@google.comac6b9792011-03-11 15:42:51 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
reed@google.comac6b9792011-03-11 15:42:51 +00007 */
8
reed@google.comac6b9792011-03-11 15:42:51 +00009#include "SkAdvancedTypefaceMetrics.h"
bungeman@google.coma5501992012-05-18 19:06:41 +000010#include "SkBase64.h"
bungeman@google.com1bfe01d2012-08-28 16:02:42 +000011#include "SkColorPriv.h"
bungeman@google.coma5501992012-05-18 19:06:41 +000012#include "SkData.h"
13#include "SkDescriptor.h"
bungeman@google.come70f7982012-06-01 19:38:19 +000014#include "SkFontDescriptor.h"
bungeman@google.coma5501992012-05-18 19:06:41 +000015#include "SkFontHost.h"
bungeman@google.combbe50132012-07-24 20:33:21 +000016#include "SkGlyph.h"
bungeman@google.com97efada2012-07-30 20:40:50 +000017#include "SkMaskGamma.h"
bungeman@google.coma5501992012-05-18 19:06:41 +000018#include "SkOTUtils.h"
reed@google.com27889872012-08-07 16:15:13 +000019#include "SkPath.h"
reed@google.comac6b9792011-03-11 15:42:51 +000020#include "SkStream.h"
bungeman@google.coma5501992012-05-18 19:06:41 +000021#include "SkString.h"
reed@google.comac6b9792011-03-11 15:42:51 +000022#include "SkThread.h"
23#include "SkTypeface_win.h"
reed@google.com59d2f632011-05-02 19:36:59 +000024#include "SkTypefaceCache.h"
reed@google.comac6b9792011-03-11 15:42:51 +000025#include "SkUtils.h"
26
bungeman@google.coma5501992012-05-18 19:06:41 +000027#include "SkTypes.h"
28#include <tchar.h>
29#include <usp10.h>
30#include <objbase.h>
reed@google.comac6b9792011-03-11 15:42:51 +000031
reed@google.com81275392012-06-18 14:08:56 +000032static bool compute_bounds_outset(const LOGFONT& lf, SkIRect* outset) {
reed@google.com5a121ad2012-06-15 14:27:15 +000033
reed@google.comb8a5c612012-06-13 20:01:44 +000034 static const struct {
reed@google.com5a121ad2012-06-15 14:27:15 +000035 const char* fUCName; // UTF8 encoded, ascii is upper-case
reed@google.com81275392012-06-18 14:08:56 +000036 SkIRect fOutset; // these are deltas for the glyph's bounds
reed@google.comb8a5c612012-06-13 20:01:44 +000037 } gData[] = {
reed@google.com5a121ad2012-06-15 14:27:15 +000038 // http://code.google.com/p/chromium/issues/detail?id=130842
reed@google.com81275392012-06-18 14:08:56 +000039 { "DOTUM", { 0, 0, 0, 1 } },
40 { "DOTUMCHE", { 0, 0, 0, 1 } },
41 { "\xEB\x8F\x8B\xEC\x9B\x80", { 0, 0, 0, 1 } },
42 { "\xEB\x8F\x8B\xEC\x9B\x80\xEC\xB2\xB4", { 0, 0, 0, 1 } },
43 { "MS UI GOTHIC", { 1, 0, 0, 0 } },
reed@google.comb8a5c612012-06-13 20:01:44 +000044 };
45
reed@google.com5a121ad2012-06-15 14:27:15 +000046 /**
47 * We convert the target name into upper-case (for ascii chars) UTF8.
48 * Our database is already stored in this fashion, and it allows us to
49 * search it with straight memcmp, since everyone is in this canonical
50 * form.
51 */
reed@google.comb8a5c612012-06-13 20:01:44 +000052
reed@google.com5a121ad2012-06-15 14:27:15 +000053 // temp storage is max # TCHARs * max expantion for UTF8 + null
54 char name[kMaxBytesInUTF8Sequence * LF_FACESIZE + 1];
55 int index = 0;
56 for (int i = 0; i < LF_FACESIZE; ++i) {
57 uint16_t c = lf.lfFaceName[i];
reed@google.comb8a5c612012-06-13 20:01:44 +000058 if (c >= 'a' && c <= 'z') {
59 c = c - 'a' + 'A';
60 }
reed@google.com5a121ad2012-06-15 14:27:15 +000061 size_t n = SkUTF16_ToUTF8(&c, 1, &name[index]);
62 index += n;
reed@google.comb8a5c612012-06-13 20:01:44 +000063 if (0 == c) {
64 break;
65 }
66 }
67
68 for (size_t j = 0; j < SK_ARRAY_COUNT(gData); ++j) {
69 if (!strcmp(gData[j].fUCName, name)) {
reed@google.com81275392012-06-18 14:08:56 +000070 *outset = gData[j].fOutset;
71 return true;
reed@google.comb8a5c612012-06-13 20:01:44 +000072 }
73 }
reed@google.com81275392012-06-18 14:08:56 +000074 return false;
75}
76
77// outset isn't really a rect, but 4 (non-negative) values to outset the
78// glyph's metrics by. For "normal" fonts, all these values should be 0.
79static void apply_outset(SkGlyph* glyph, const SkIRect& outset) {
80 SkASSERT(outset.fLeft >= 0);
81 SkASSERT(outset.fTop >= 0);
82 SkASSERT(outset.fRight >= 0);
83 SkASSERT(outset.fBottom >= 0);
84
85 glyph->fLeft -= outset.fLeft;
86 glyph->fTop -= outset.fTop;
87 glyph->fWidth += outset.fLeft + outset.fRight;
88 glyph->fHeight += outset.fTop + outset.fBottom;
reed@google.comb8a5c612012-06-13 20:01:44 +000089}
90
reed@google.com6f5df482011-09-28 20:33:24 +000091// always packed xxRRGGBB
92typedef uint32_t SkGdiRGB;
93
94template <typename T> T* SkTAddByteOffset(T* ptr, size_t byteOffset) {
95 return (T*)((char*)ptr + byteOffset);
96}
97
reed@google.coma767fa02011-08-05 21:40:26 +000098// define this in your Makefile or .gyp to enforce AA requests
99// which GDI ignores at small sizes. This flag guarantees AA
100// for rotated text, regardless of GDI's notions.
101//#define SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
102
reed@google.comac6b9792011-03-11 15:42:51 +0000103// client3d has to undefine this for now
104#define CAN_USE_LOGFONT_NAME
105
reed@google.com82a34d82011-07-26 19:33:08 +0000106static bool isLCD(const SkScalerContext::Rec& rec) {
107 return SkMask::kLCD16_Format == rec.fMaskFormat ||
108 SkMask::kLCD32_Format == rec.fMaskFormat;
109}
110
reed@google.coma767fa02011-08-05 21:40:26 +0000111static bool bothZero(SkScalar a, SkScalar b) {
112 return 0 == a && 0 == b;
113}
114
115// returns false if there is any non-90-rotation or skew
116static bool isAxisAligned(const SkScalerContext::Rec& rec) {
117 return 0 == rec.fPreSkewX &&
118 (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) ||
119 bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1]));
120}
121
122static bool needToRenderWithSkia(const SkScalerContext::Rec& rec) {
123#ifdef SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS
124 // What we really want to catch is when GDI will ignore the AA request and give
125 // us BW instead. Smallish rotated text is one heuristic, so this code is just
126 // an approximation. We shouldn't need to do this for larger sizes, but at those
127 // sizes, the quality difference gets less and less between our general
128 // scanconverter and GDI's.
129 if (SkMask::kA8_Format == rec.fMaskFormat && !isAxisAligned(rec)) {
130 return true;
131 }
132#endif
133 // false means allow GDI to generate the bits
134 return false;
135}
136
reed@google.comac6b9792011-03-11 15:42:51 +0000137using namespace skia_advanced_typeface_metrics_utils;
138
reed@google.comac6b9792011-03-11 15:42:51 +0000139static const uint16_t BUFFERSIZE = (16384 - 32);
140static uint8_t glyphbuf[BUFFERSIZE];
141
reed@google.comac6b9792011-03-11 15:42:51 +0000142/**
ctguil@chromium.org5aa937b2011-08-04 01:01:24 +0000143 * Since LOGFONT wants its textsize as an int, and we support fractional sizes,
reed@google.comac6b9792011-03-11 15:42:51 +0000144 * and since we have a cache of LOGFONTs for our tyepfaces, we always set the
145 * lfHeight to a canonical size, and then we use the 2x2 matrix to achieve the
146 * actual requested size.
147 */
148static const int gCanonicalTextSize = 64;
149
150static void make_canonical(LOGFONT* lf) {
ctguil@chromium.org5aa937b2011-08-04 01:01:24 +0000151 lf->lfHeight = -gCanonicalTextSize;
reed@google.com59d2f632011-05-02 19:36:59 +0000152 lf->lfQuality = CLEARTYPE_QUALITY;//PROOF_QUALITY;
153 lf->lfCharSet = DEFAULT_CHARSET;
reed@google.com82a34d82011-07-26 19:33:08 +0000154// lf->lfClipPrecision = 64;
reed@google.com59d2f632011-05-02 19:36:59 +0000155}
156
bungeman@google.com90d812b2011-10-24 21:25:01 +0000157static SkTypeface::Style get_style(const LOGFONT& lf) {
reed@google.com59d2f632011-05-02 19:36:59 +0000158 unsigned style = 0;
159 if (lf.lfWeight >= FW_BOLD) {
160 style |= SkTypeface::kBold;
161 }
162 if (lf.lfItalic) {
163 style |= SkTypeface::kItalic;
164 }
bungeman@google.com90d812b2011-10-24 21:25:01 +0000165 return static_cast<SkTypeface::Style>(style);
reed@google.com59d2f632011-05-02 19:36:59 +0000166}
167
168static void setStyle(LOGFONT* lf, SkTypeface::Style style) {
169 lf->lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL ;
170 lf->lfItalic = ((style & SkTypeface::kItalic) != 0);
reed@google.comac6b9792011-03-11 15:42:51 +0000171}
172
173static inline FIXED SkFixedToFIXED(SkFixed x) {
174 return *(FIXED*)(&x);
175}
bungeman@google.coma0319f62012-04-18 15:40:50 +0000176static inline SkFixed SkFIXEDToFixed(FIXED x) {
177 return *(SkFixed*)(&x);
178}
reed@google.comac6b9792011-03-11 15:42:51 +0000179
180static inline FIXED SkScalarToFIXED(SkScalar x) {
181 return SkFixedToFIXED(SkScalarToFixed(x));
182}
183
bungeman@google.coma0319f62012-04-18 15:40:50 +0000184static unsigned calculateOutlineGlyphCount(HDC hdc) {
reed@google.comac6b9792011-03-11 15:42:51 +0000185 // The 'maxp' table stores the number of glyphs at offset 4, in 2 bytes.
ctguil@chromium.orgf4c26222011-05-16 22:00:05 +0000186 const DWORD maxpTag =
187 SkEndian_SwapBE32(SkSetFourByteTag('m', 'a', 'x', 'p'));
reed@google.comac6b9792011-03-11 15:42:51 +0000188 uint16_t glyphs;
189 if (GetFontData(hdc, maxpTag, 4, &glyphs, sizeof(glyphs)) != GDI_ERROR) {
190 return SkEndian_SwapBE16(glyphs);
191 }
ctguil@chromium.org5aa937b2011-08-04 01:01:24 +0000192
reed@google.comac6b9792011-03-11 15:42:51 +0000193 // Binary search for glyph count.
194 static const MAT2 mat2 = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
195 int32_t max = SK_MaxU16 + 1;
196 int32_t min = 0;
197 GLYPHMETRICS gm;
198 while (min < max) {
199 int32_t mid = min + ((max - min) / 2);
200 if (GetGlyphOutlineW(hdc, mid, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0,
201 NULL, &mat2) == GDI_ERROR) {
202 max = mid;
203 } else {
204 min = mid + 1;
205 }
206 }
207 SkASSERT(min == max);
208 return min;
209}
210
reed@google.comac6b9792011-03-11 15:42:51 +0000211class LogFontTypeface : public SkTypeface {
reed@google.comac6b9792011-03-11 15:42:51 +0000212public:
bungeman@google.comcb1bbb32012-10-12 18:48:35 +0000213 LogFontTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf, bool serializeAsStream = false) :
214 SkTypeface(style, fontID, false), fLogFont(lf), fSerializeAsStream(serializeAsStream) {
215
216 // If the font has cubic outlines, it will not be rendered with ClearType.
217 HFONT font = CreateFontIndirect(&lf);
218
219 HDC deviceContext = ::CreateCompatibleDC(NULL);
220 HFONT savefont = (HFONT)SelectObject(deviceContext, font);
221
222 TEXTMETRIC textMetric;
223 if (0 == GetTextMetrics(deviceContext, &textMetric)) {
224 SkFontHost::EnsureTypefaceAccessible(*this);
225 if (0 == GetTextMetrics(deviceContext, &textMetric)) {
226 textMetric.tmPitchAndFamily = TMPF_TRUETYPE;
227 }
228 }
229 if (deviceContext) {
230 ::SelectObject(deviceContext, savefont);
231 ::DeleteDC(deviceContext);
232 }
233 if (font) {
234 ::DeleteObject(font);
235 }
236
237 // Used a logfont on a memory context, should never get a device font.
238 // Therefore all TMPF_DEVICE will be PostScript (cubic) fonts.
239 fCanBeLCD = !((textMetric.tmPitchAndFamily & TMPF_VECTOR) &&
240 (textMetric.tmPitchAndFamily & TMPF_DEVICE));
241 }
reed@google.comac6b9792011-03-11 15:42:51 +0000242
reed@google.com59d2f632011-05-02 19:36:59 +0000243 LOGFONT fLogFont;
bungeman@google.come70f7982012-06-01 19:38:19 +0000244 bool fSerializeAsStream;
bungeman@google.comcb1bbb32012-10-12 18:48:35 +0000245 bool fCanBeLCD;
reed@google.comac6b9792011-03-11 15:42:51 +0000246
reed@google.com59d2f632011-05-02 19:36:59 +0000247 static LogFontTypeface* Create(const LOGFONT& lf) {
bungeman@google.com90d812b2011-10-24 21:25:01 +0000248 SkTypeface::Style style = get_style(lf);
reed@google.com59d2f632011-05-02 19:36:59 +0000249 SkFontID fontID = SkTypefaceCache::NewFontID();
250 return new LogFontTypeface(style, fontID, lf);
reed@google.comac6b9792011-03-11 15:42:51 +0000251 }
252};
253
bungeman@google.coma5501992012-05-18 19:06:41 +0000254class FontMemResourceTypeface : public LogFontTypeface {
255public:
256 /**
257 * Takes ownership of fontMemResource.
258 */
259 FontMemResourceTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf, HANDLE fontMemResource) :
bungeman@google.comcb1bbb32012-10-12 18:48:35 +0000260 LogFontTypeface(style, fontID, lf, true), fFontMemResource(fontMemResource) {
bungeman@google.come70f7982012-06-01 19:38:19 +0000261 }
bungeman@google.coma5501992012-05-18 19:06:41 +0000262
263 HANDLE fFontMemResource;
264
265 /**
266 * The created FontMemResourceTypeface takes ownership of fontMemResource.
267 */
268 static FontMemResourceTypeface* Create(const LOGFONT& lf, HANDLE fontMemResource) {
269 SkTypeface::Style style = get_style(lf);
270 SkFontID fontID = SkTypefaceCache::NewFontID();
271 return new FontMemResourceTypeface(style, fontID, lf, fontMemResource);
272 }
273
274protected:
275 virtual void weak_dispose() const SK_OVERRIDE {
276 RemoveFontMemResourceEx(fFontMemResource);
277 //SkTypefaceCache::Remove(this);
278 INHERITED::weak_dispose();
279 }
280
281private:
282 typedef LogFontTypeface INHERITED;
283};
284
reed@google.comac6b9792011-03-11 15:42:51 +0000285static const LOGFONT& get_default_font() {
286 static LOGFONT gDefaultFont;
reed@google.comac6b9792011-03-11 15:42:51 +0000287 return gDefaultFont;
288}
289
reed@google.com59d2f632011-05-02 19:36:59 +0000290static bool FindByLogFont(SkTypeface* face, SkTypeface::Style requestedStyle, void* ctx) {
bungeman@google.coma5501992012-05-18 19:06:41 +0000291 LogFontTypeface* lface = static_cast<LogFontTypeface*>(face);
reed@google.com59d2f632011-05-02 19:36:59 +0000292 const LOGFONT* lf = reinterpret_cast<const LOGFONT*>(ctx);
reed@google.comac6b9792011-03-11 15:42:51 +0000293
bungeman@google.coma5501992012-05-18 19:06:41 +0000294 return lface &&
295 get_style(lface->fLogFont) == requestedStyle &&
reed@google.com59d2f632011-05-02 19:36:59 +0000296 !memcmp(&lface->fLogFont, lf, sizeof(LOGFONT));
297}
298
299/**
300 * This guy is public. It first searches the cache, and if a match is not found,
301 * it creates a new face.
302 */
303SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT& origLF) {
304 LOGFONT lf = origLF;
305 make_canonical(&lf);
bungeman@google.comee51d1a2012-02-16 12:40:48 +0000306 SkTypeface* face = SkTypefaceCache::FindByProcAndRef(FindByLogFont, &lf);
307 if (NULL == face) {
reed@google.com59d2f632011-05-02 19:36:59 +0000308 face = LogFontTypeface::Create(lf);
bungeman@google.com90d812b2011-10-24 21:25:01 +0000309 SkTypefaceCache::Add(face, get_style(lf));
reed@google.com59d2f632011-05-02 19:36:59 +0000310 }
311 return face;
reed@google.comac6b9792011-03-11 15:42:51 +0000312}
313
reed@google.comdb77a6a2011-07-19 19:08:33 +0000314/**
bungeman@google.coma5501992012-05-18 19:06:41 +0000315 * The created SkTypeface takes ownership of fontMemResource.
316 */
317SkTypeface* SkCreateFontMemResourceTypefaceFromLOGFONT(const LOGFONT& origLF, HANDLE fontMemResource) {
318 LOGFONT lf = origLF;
319 make_canonical(&lf);
320 FontMemResourceTypeface* face = FontMemResourceTypeface::Create(lf, fontMemResource);
321 SkTypefaceCache::Add(face, get_style(lf), false);
322 return face;
323}
324
325/**
reed@google.comdb77a6a2011-07-19 19:08:33 +0000326 * This guy is public
327 */
328void SkLOGFONTFromTypeface(const SkTypeface* face, LOGFONT* lf) {
329 if (NULL == face) {
330 *lf = get_default_font();
331 } else {
bungeman@google.coma5501992012-05-18 19:06:41 +0000332 *lf = static_cast<const LogFontTypeface*>(face)->fLogFont;
reed@google.comdb77a6a2011-07-19 19:08:33 +0000333 }
334}
335
reed@google.com7d26c592011-06-13 13:01:10 +0000336SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
reed@google.comac6b9792011-03-11 15:42:51 +0000337 // Zero means that we don't have any fallback fonts for this fontID.
338 // This function is implemented on Android, but doesn't have much
339 // meaning here.
340 return 0;
341}
342
bungeman@google.com39698b12011-11-15 22:26:41 +0000343static void ensure_typeface_accessible(SkFontID fontID) {
bungeman@google.coma5501992012-05-18 19:06:41 +0000344 LogFontTypeface* face = static_cast<LogFontTypeface*>(SkTypefaceCache::FindByID(fontID));
bungeman@google.comee51d1a2012-02-16 12:40:48 +0000345 if (face) {
346 SkFontHost::EnsureTypefaceAccessible(*face);
347 }
bungeman@google.com39698b12011-11-15 22:26:41 +0000348}
349
reed@google.com59d2f632011-05-02 19:36:59 +0000350static void GetLogFontByID(SkFontID fontID, LOGFONT* lf) {
bungeman@google.coma5501992012-05-18 19:06:41 +0000351 LogFontTypeface* face = static_cast<LogFontTypeface*>(SkTypefaceCache::FindByID(fontID));
reed@google.com59d2f632011-05-02 19:36:59 +0000352 if (face) {
353 *lf = face->fLogFont;
354 } else {
355 sk_bzero(lf, sizeof(LOGFONT));
356 }
357}
358
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000359// Construct Glyph to Unicode table.
360// Unicode code points that require conjugate pairs in utf16 are not
361// supported.
362// TODO(arthurhsu): Add support for conjugate pairs. It looks like that may
363// require parsing the TTF cmap table (platform 4, encoding 12) directly instead
364// of calling GetFontUnicodeRange().
365static void populate_glyph_to_unicode(HDC fontHdc, const unsigned glyphCount,
366 SkTDArray<SkUnichar>* glyphToUnicode) {
367 DWORD glyphSetBufferSize = GetFontUnicodeRanges(fontHdc, NULL);
368 if (!glyphSetBufferSize) {
369 return;
370 }
371
372 SkAutoTDeleteArray<BYTE> glyphSetBuffer(new BYTE[glyphSetBufferSize]);
373 GLYPHSET* glyphSet =
374 reinterpret_cast<LPGLYPHSET>(glyphSetBuffer.get());
375 if (GetFontUnicodeRanges(fontHdc, glyphSet) != glyphSetBufferSize) {
376 return;
377 }
378
379 glyphToUnicode->setCount(glyphCount);
380 memset(glyphToUnicode->begin(), 0, glyphCount * sizeof(SkUnichar));
381 for (DWORD i = 0; i < glyphSet->cRanges; ++i) {
382 // There is no guarantee that within a Unicode range, the corresponding
383 // glyph id in a font file are continuous. So, even if we have ranges,
384 // we can't just use the first and last entry of the range to compute
385 // result. We need to enumerate them one by one.
386 int count = glyphSet->ranges[i].cGlyphs;
387 SkAutoTArray<WCHAR> chars(count + 1);
388 chars[count] = 0; // termintate string
389 SkAutoTArray<WORD> glyph(count);
390 for (USHORT j = 0; j < count; ++j) {
391 chars[j] = glyphSet->ranges[i].wcLow + j;
392 }
393 GetGlyphIndicesW(fontHdc, chars.get(), count, glyph.get(),
394 GGI_MARK_NONEXISTING_GLYPHS);
395 // If the glyph ID is valid, and the glyph is not mapped, then we will
396 // fill in the char id into the vector. If the glyph is mapped already,
397 // skip it.
398 // TODO(arthurhsu): better improve this. e.g. Get all used char ids from
399 // font cache, then generate this mapping table from there. It's
400 // unlikely to have collisions since glyph reuse happens mostly for
401 // different Unicode pages.
402 for (USHORT j = 0; j < count; ++j) {
403 if (glyph[j] != 0xffff && glyph[j] < glyphCount &&
404 (*glyphToUnicode)[glyph[j]] == 0) {
405 (*glyphToUnicode)[glyph[j]] = chars[j];
406 }
407 }
408 }
409}
410
reed@google.com99edd432011-09-09 14:59:59 +0000411//////////////////////////////////////////////////////////////////////////////////////
412
413static int alignTo32(int n) {
414 return (n + 31) & ~31;
415}
416
417struct MyBitmapInfo : public BITMAPINFO {
418 RGBQUAD fMoreSpaceForColors[1];
419};
420
421class HDCOffscreen {
422public:
423 HDCOffscreen() {
424 fFont = 0;
425 fDC = 0;
426 fBM = 0;
427 fBits = NULL;
428 fWidth = fHeight = 0;
429 fIsBW = false;
430 }
431
432 ~HDCOffscreen() {
433 if (fDC) {
434 DeleteDC(fDC);
435 }
436 if (fBM) {
437 DeleteObject(fBM);
438 }
439 }
440
441 void init(HFONT font, const XFORM& xform) {
442 fFont = font;
443 fXform = xform;
444 }
445
bungeman@google.com97efada2012-07-30 20:40:50 +0000446 const void* draw(const SkGlyph&, bool isBW, size_t* srcRBPtr);
reed@google.com99edd432011-09-09 14:59:59 +0000447
448private:
449 HDC fDC;
450 HBITMAP fBM;
451 HFONT fFont;
452 XFORM fXform;
453 void* fBits; // points into fBM
454 int fWidth;
455 int fHeight;
456 bool fIsBW;
reed@google.com754e4eb2011-09-26 13:21:39 +0000457
458 enum {
459 // will always trigger us to reset the color, since we
reed@google.com6f5df482011-09-28 20:33:24 +0000460 // should only store 0 or 0x00FFFFFF or gray (0x007F7F7F)
reed@google.com754e4eb2011-09-26 13:21:39 +0000461 kInvalid_Color = 12345
462 };
reed@google.com99edd432011-09-09 14:59:59 +0000463};
464
reed@google.com754e4eb2011-09-26 13:21:39 +0000465const void* HDCOffscreen::draw(const SkGlyph& glyph, bool isBW,
bungeman@google.com97efada2012-07-30 20:40:50 +0000466 size_t* srcRBPtr) {
reed@google.com99edd432011-09-09 14:59:59 +0000467 if (0 == fDC) {
468 fDC = CreateCompatibleDC(0);
469 if (0 == fDC) {
470 return NULL;
471 }
472 SetGraphicsMode(fDC, GM_ADVANCED);
473 SetBkMode(fDC, TRANSPARENT);
474 SetTextAlign(fDC, TA_LEFT | TA_BASELINE);
475 SelectObject(fDC, fFont);
bungeman@google.com97efada2012-07-30 20:40:50 +0000476
477 COLORREF color = 0x00FFFFFF;
478 COLORREF prev = SetTextColor(fDC, color);
479 SkASSERT(prev != CLR_INVALID);
reed@google.com99edd432011-09-09 14:59:59 +0000480 }
481
482 if (fBM && (fIsBW != isBW || fWidth < glyph.fWidth || fHeight < glyph.fHeight)) {
483 DeleteObject(fBM);
484 fBM = 0;
485 }
reed@google.com754e4eb2011-09-26 13:21:39 +0000486 fIsBW = isBW;
reed@google.com99edd432011-09-09 14:59:59 +0000487
reed@google.com99edd432011-09-09 14:59:59 +0000488 fWidth = SkMax32(fWidth, glyph.fWidth);
489 fHeight = SkMax32(fHeight, glyph.fHeight);
490
491 int biWidth = isBW ? alignTo32(fWidth) : fWidth;
492
493 if (0 == fBM) {
494 MyBitmapInfo info;
495 sk_bzero(&info, sizeof(info));
496 if (isBW) {
497 RGBQUAD blackQuad = { 0, 0, 0, 0 };
498 RGBQUAD whiteQuad = { 0xFF, 0xFF, 0xFF, 0 };
499 info.bmiColors[0] = blackQuad;
500 info.bmiColors[1] = whiteQuad;
501 }
502 info.bmiHeader.biSize = sizeof(info.bmiHeader);
503 info.bmiHeader.biWidth = biWidth;
504 info.bmiHeader.biHeight = fHeight;
505 info.bmiHeader.biPlanes = 1;
506 info.bmiHeader.biBitCount = isBW ? 1 : 32;
507 info.bmiHeader.biCompression = BI_RGB;
508 if (isBW) {
509 info.bmiHeader.biClrUsed = 2;
510 }
511 fBM = CreateDIBSection(fDC, &info, DIB_RGB_COLORS, &fBits, 0, 0);
512 if (0 == fBM) {
513 return NULL;
514 }
515 SelectObject(fDC, fBM);
516 }
517
518 // erase
519 size_t srcRB = isBW ? (biWidth >> 3) : (fWidth << 2);
520 size_t size = fHeight * srcRB;
bungeman@google.com97efada2012-07-30 20:40:50 +0000521 memset(fBits, 0, size);
reed@google.com99edd432011-09-09 14:59:59 +0000522
523 XFORM xform = fXform;
524 xform.eDx = (float)-glyph.fLeft;
525 xform.eDy = (float)-glyph.fTop;
526 SetWorldTransform(fDC, &xform);
527
528 uint16_t glyphID = glyph.getGlyphID();
bungeman@google.com39698b12011-11-15 22:26:41 +0000529 BOOL ret = ExtTextOutW(fDC, 0, 0, ETO_GLYPH_INDEX, NULL, reinterpret_cast<LPCWSTR>(&glyphID), 1, NULL);
reed@google.com99edd432011-09-09 14:59:59 +0000530 GdiFlush();
bungeman@google.com39698b12011-11-15 22:26:41 +0000531 if (0 == ret) {
532 return NULL;
533 }
reed@google.com99edd432011-09-09 14:59:59 +0000534 *srcRBPtr = srcRB;
535 // offset to the start of the image
536 return (const char*)fBits + (fHeight - glyph.fHeight) * srcRB;
537}
538
reed@google.comb8a5c612012-06-13 20:01:44 +0000539//////////////////////////////////////////////////////////////////////////////
reed@google.com59d2f632011-05-02 19:36:59 +0000540
reed@google.comac6b9792011-03-11 15:42:51 +0000541class SkScalerContext_Windows : public SkScalerContext {
542public:
543 SkScalerContext_Windows(const SkDescriptor* desc);
544 virtual ~SkScalerContext_Windows();
545
546protected:
bungeman@google.com97efada2012-07-30 20:40:50 +0000547 virtual unsigned generateGlyphCount() SK_OVERRIDE;
548 virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE;
549 virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE;
550 virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE;
bungeman@google.coma76de722012-10-26 19:35:54 +0000551 virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE;
bungeman@google.com97efada2012-07-30 20:40:50 +0000552 virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE;
bungeman@google.coma76de722012-10-26 19:35:54 +0000553 virtual void generateFontMetrics(SkPaint::FontMetrics* mX,
554 SkPaint::FontMetrics* mY) SK_OVERRIDE;
reed@google.com99edd432011-09-09 14:59:59 +0000555
reed@google.comac6b9792011-03-11 15:42:51 +0000556private:
reed@google.com99edd432011-09-09 14:59:59 +0000557 HDCOffscreen fOffscreen;
ctguil@chromium.org5aa937b2011-08-04 01:01:24 +0000558 SkScalar fScale; // to get from canonical size to real size
reed@google.comac6b9792011-03-11 15:42:51 +0000559 MAT2 fMat22;
560 XFORM fXform;
561 HDC fDDC;
562 HFONT fSavefont;
563 HFONT fFont;
564 SCRIPT_CACHE fSC;
565 int fGlyphCount;
reed@google.com1dd17a12011-05-17 14:04:41 +0000566
reed@google.comb8a5c612012-06-13 20:01:44 +0000567 /**
568 * Some fonts need extra pixels added to avoid clipping, as the bounds
569 * returned by getOutlineMetrics does not match what GDI draws. Since
570 * this costs more RAM and therefore slower blits, we have a table to
571 * only do this for known "bad" fonts.
572 */
reed@google.com81275392012-06-18 14:08:56 +0000573 SkIRect fOutset;
reed@google.comb8a5c612012-06-13 20:01:44 +0000574
reed@google.com1dd17a12011-05-17 14:04:41 +0000575 HFONT fHiResFont;
576 MAT2 fMat22Identity;
577 SkMatrix fHiResMatrix;
bungeman@google.coma0319f62012-04-18 15:40:50 +0000578 enum Type {
579 kTrueType_Type, kBitmap_Type,
580 } fType;
581 TEXTMETRIC fTM;
reed@google.comac6b9792011-03-11 15:42:51 +0000582};
583
584static float mul2float(SkScalar a, SkScalar b) {
585 return SkScalarToFloat(SkScalarMul(a, b));
586}
587
588static FIXED float2FIXED(float x) {
589 return SkFixedToFIXED(SkFloatToFixed(x));
590}
591
digit@google.com1771cbf2012-01-26 21:26:40 +0000592SK_DECLARE_STATIC_MUTEX(gFTMutex);
reed@google.com59d2f632011-05-02 19:36:59 +0000593
reed@google.com1dd17a12011-05-17 14:04:41 +0000594#define HIRES_TEXTSIZE 2048
595#define HIRES_SHIFT 11
596static inline SkFixed HiResToFixed(int value) {
597 return value << (16 - HIRES_SHIFT);
598}
599
600static bool needHiResMetrics(const SkScalar mat[2][2]) {
601 return mat[1][0] || mat[0][1];
602}
603
reed@google.com82a34d82011-07-26 19:33:08 +0000604static BYTE compute_quality(const SkScalerContext::Rec& rec) {
605 switch (rec.fMaskFormat) {
606 case SkMask::kBW_Format:
607 return NONANTIALIASED_QUALITY;
608 case SkMask::kLCD16_Format:
609 case SkMask::kLCD32_Format:
610 return CLEARTYPE_QUALITY;
611 default:
reed@google.com8351aab2012-01-18 17:06:35 +0000612 if (rec.fFlags & SkScalerContext::kGenA8FromLCD_Flag) {
613 return CLEARTYPE_QUALITY;
614 } else {
615 return ANTIALIASED_QUALITY;
616 }
reed@google.com82a34d82011-07-26 19:33:08 +0000617 }
618}
619
reed@google.comac6b9792011-03-11 15:42:51 +0000620SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc)
621 : SkScalerContext(desc), fDDC(0), fFont(0), fSavefont(0), fSC(0)
622 , fGlyphCount(-1) {
623 SkAutoMutexAcquire ac(gFTMutex);
624
reed@google.comac6b9792011-03-11 15:42:51 +0000625 fDDC = ::CreateCompatibleDC(NULL);
reed@google.com1dd17a12011-05-17 14:04:41 +0000626 SetGraphicsMode(fDDC, GM_ADVANCED);
reed@google.comac6b9792011-03-11 15:42:51 +0000627 SetBkMode(fDDC, TRANSPARENT);
628
629 // Scaling by the DPI is inconsistent with how Skia draws elsewhere
630 //SkScalar height = -(fRec.fTextSize * GetDeviceCaps(ddc, LOGPIXELSY) / 72);
reed@google.com59d2f632011-05-02 19:36:59 +0000631 LOGFONT lf;
632 GetLogFontByID(fRec.fFontID, &lf);
reed@google.comac6b9792011-03-11 15:42:51 +0000633 lf.lfHeight = -gCanonicalTextSize;
reed@google.com82a34d82011-07-26 19:33:08 +0000634 lf.lfQuality = compute_quality(fRec);
reed@google.comac6b9792011-03-11 15:42:51 +0000635 fFont = CreateFontIndirect(&lf);
reed@google.com1dd17a12011-05-17 14:04:41 +0000636
reed@google.com81275392012-06-18 14:08:56 +0000637 if (!compute_bounds_outset(lf, &fOutset)) {
638 fOutset.setEmpty();
639 }
reed@google.comb8a5c612012-06-13 20:01:44 +0000640
reed@google.com1dd17a12011-05-17 14:04:41 +0000641 // if we're rotated, or want fractional widths, create a hires font
642 fHiResFont = 0;
bungeman@google.comc84547a2012-01-05 20:18:06 +0000643 if (needHiResMetrics(fRec.fPost2x2)) {
reed@google.com1dd17a12011-05-17 14:04:41 +0000644 lf.lfHeight = -HIRES_TEXTSIZE;
645 fHiResFont = CreateFontIndirect(&lf);
646
647 fMat22Identity.eM11 = fMat22Identity.eM22 = SkFixedToFIXED(SK_Fixed1);
648 fMat22Identity.eM12 = fMat22Identity.eM21 = SkFixedToFIXED(0);
649
650 // construct a matrix to go from HIRES logical units to our device units
651 fRec.getSingleMatrix(&fHiResMatrix);
652 SkScalar scale = SkScalarInvert(SkIntToScalar(HIRES_TEXTSIZE));
653 fHiResMatrix.preScale(scale, scale);
654 }
reed@google.comac6b9792011-03-11 15:42:51 +0000655 fSavefont = (HFONT)SelectObject(fDDC, fFont);
reed@google.coma767fa02011-08-05 21:40:26 +0000656
bungeman@google.coma0319f62012-04-18 15:40:50 +0000657 if (0 == GetTextMetrics(fDDC, &fTM)) {
658 ensure_typeface_accessible(fRec.fFontID);
659 if (0 == GetTextMetrics(fDDC, &fTM)) {
660 fTM.tmPitchAndFamily = TMPF_TRUETYPE;
661 }
662 }
663 // Used a logfont on a memory context, should never get a device font.
bungeman@google.com90b7e382012-04-20 15:26:28 +0000664 // Therefore all TMPF_DEVICE will be PostScript fonts.
665
666 // If TMPF_VECTOR is set, one of TMPF_TRUETYPE or TMPF_DEVICE must be set,
667 // otherwise we have a vector FON, which we don't support.
668 // This was determined by testing with Type1 PFM/PFB and OpenTypeCFF OTF,
669 // as well as looking at Wine bugs and sources.
670 SkASSERT(!(fTM.tmPitchAndFamily & TMPF_VECTOR) ||
671 (fTM.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_DEVICE)));
672
673 if (fTM.tmPitchAndFamily & TMPF_VECTOR) {
bungeman@google.coma0319f62012-04-18 15:40:50 +0000674 // Truetype or PostScript.
675 // Stroked FON also gets here (TMPF_VECTOR), but we don't handle it.
676 fType = SkScalerContext_Windows::kTrueType_Type;
677 fScale = fRec.fTextSize / gCanonicalTextSize;
678
679 fXform.eM11 = mul2float(fScale, fRec.fPost2x2[0][0]);
680 fXform.eM12 = mul2float(fScale, fRec.fPost2x2[1][0]);
681 fXform.eM21 = mul2float(fScale, fRec.fPost2x2[0][1]);
682 fXform.eM22 = mul2float(fScale, fRec.fPost2x2[1][1]);
683 fXform.eDx = 0;
684 fXform.eDy = 0;
685
686 fMat22.eM11 = float2FIXED(fXform.eM11);
687 fMat22.eM12 = float2FIXED(fXform.eM12);
688 fMat22.eM21 = float2FIXED(-fXform.eM21);
689 fMat22.eM22 = float2FIXED(-fXform.eM22);
690
691 if (needToRenderWithSkia(fRec)) {
692 this->forceGenerateImageFromPath();
693 }
694
695 } else {
696 // Assume bitmap
697 fType = SkScalerContext_Windows::kBitmap_Type;
698 fScale = SK_Scalar1;
699
700 fXform.eM11 = 1.0f;
701 fXform.eM12 = 0.0f;
702 fXform.eM21 = 0.0f;
703 fXform.eM22 = 1.0f;
704 fXform.eDx = 0.0f;
705 fXform.eDy = 0.0f;
706
707 fMat22.eM11 = SkScalarToFIXED(fRec.fPost2x2[0][0]);
708 fMat22.eM12 = SkScalarToFIXED(fRec.fPost2x2[1][0]);
709 fMat22.eM21 = SkScalarToFIXED(-fRec.fPost2x2[0][1]);
710 fMat22.eM22 = SkScalarToFIXED(-fRec.fPost2x2[1][1]);
711
712 lf.lfHeight = -SkScalarCeilToInt(fRec.fTextSize);
713 HFONT bitmapFont = CreateFontIndirect(&lf);
714 SelectObject(fDDC, bitmapFont);
715 ::DeleteObject(fFont);
716 fFont = bitmapFont;
717
718 if (0 == GetTextMetrics(fDDC, &fTM)) {
719 ensure_typeface_accessible(fRec.fFontID);
720 //if the following fails, we'll just draw at gCanonicalTextSize.
721 GetTextMetrics(fDDC, &fTM);
722 }
reed@google.coma767fa02011-08-05 21:40:26 +0000723 }
reed@google.com99edd432011-09-09 14:59:59 +0000724
725 fOffscreen.init(fFont, fXform);
reed@google.comac6b9792011-03-11 15:42:51 +0000726}
727
728SkScalerContext_Windows::~SkScalerContext_Windows() {
729 if (fDDC) {
730 ::SelectObject(fDDC, fSavefont);
731 ::DeleteDC(fDDC);
732 }
733 if (fFont) {
734 ::DeleteObject(fFont);
735 }
reed@google.com1dd17a12011-05-17 14:04:41 +0000736 if (fHiResFont) {
737 ::DeleteObject(fHiResFont);
738 }
reed@google.comac6b9792011-03-11 15:42:51 +0000739 if (fSC) {
740 ::ScriptFreeCache(&fSC);
741 }
742}
743
744unsigned SkScalerContext_Windows::generateGlyphCount() {
745 if (fGlyphCount < 0) {
bungeman@google.coma0319f62012-04-18 15:40:50 +0000746 if (fType == SkScalerContext_Windows::kBitmap_Type) {
747 return fTM.tmLastChar;
748 }
749 fGlyphCount = calculateOutlineGlyphCount(fDDC);
reed@google.comac6b9792011-03-11 15:42:51 +0000750 }
751 return fGlyphCount;
752}
753
754uint16_t SkScalerContext_Windows::generateCharToGlyph(SkUnichar uni) {
755 uint16_t index = 0;
756 WCHAR c[2];
757 // TODO(ctguil): Support characters that generate more than one glyph.
758 if (SkUTF16_FromUnichar(uni, (uint16_t*)c) == 1) {
759 // Type1 fonts fail with uniscribe API. Use GetGlyphIndices for plane 0.
760 SkAssertResult(GetGlyphIndicesW(fDDC, c, 1, &index, 0));
761 } else {
762 // Use uniscribe to detemine glyph index for non-BMP characters.
763 // Need to add extra item to SCRIPT_ITEM to work around a bug in older
764 // windows versions. https://bugzilla.mozilla.org/show_bug.cgi?id=366643
765 SCRIPT_ITEM si[2 + 1];
766 int items;
767 SkAssertResult(
768 SUCCEEDED(ScriptItemize(c, 2, 2, NULL, NULL, si, &items)));
769
770 WORD log[2];
771 SCRIPT_VISATTR vsa;
772 int glyphs;
773 SkAssertResult(SUCCEEDED(ScriptShape(
774 fDDC, &fSC, c, 2, 1, &si[0].a, &index, log, &vsa, &glyphs)));
775 }
776 return index;
777}
778
779void SkScalerContext_Windows::generateAdvance(SkGlyph* glyph) {
780 this->generateMetrics(glyph);
781}
782
783void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) {
784
785 SkASSERT(fDDC);
786
bungeman@google.coma0319f62012-04-18 15:40:50 +0000787 if (fType == SkScalerContext_Windows::kBitmap_Type) {
788 SIZE size;
789 WORD glyphs = glyph->getGlyphID(0);
790 if (0 == GetTextExtentPointI(fDDC, &glyphs, 1, &size)) {
791 glyph->fWidth = SkToS16(fTM.tmMaxCharWidth);
792 } else {
793 glyph->fWidth = SkToS16(size.cx);
794 }
795 glyph->fHeight = SkToS16(size.cy);
796
797 glyph->fTop = SkToS16(-fTM.tmAscent);
798 glyph->fLeft = SkToS16(0);
799 glyph->fAdvanceX = SkIntToFixed(glyph->fWidth);
800 glyph->fAdvanceY = 0;
801
802 //Apply matrix to values.
803 glyph->fAdvanceY = SkFixedMul(SkFIXEDToFixed(fMat22.eM21), glyph->fAdvanceX);
804 glyph->fAdvanceX = SkFixedMul(SkFIXEDToFixed(fMat22.eM11), glyph->fAdvanceX);
805
reed@google.com81275392012-06-18 14:08:56 +0000806 apply_outset(glyph, fOutset);
bungeman@google.coma0319f62012-04-18 15:40:50 +0000807 return;
808 }
809
reed@google.comac6b9792011-03-11 15:42:51 +0000810 GLYPHMETRICS gm;
reed@google.com1dd17a12011-05-17 14:04:41 +0000811 sk_bzero(&gm, sizeof(gm));
reed@google.comac6b9792011-03-11 15:42:51 +0000812
813 glyph->fRsbDelta = 0;
814 glyph->fLsbDelta = 0;
815
816 // Note: need to use GGO_GRAY8_BITMAP instead of GGO_METRICS because GGO_METRICS returns a smaller
817 // BlackBlox; we need the bigger one in case we need the image. fAdvance is the same.
818 uint32_t ret = GetGlyphOutlineW(fDDC, glyph->getGlyphID(0), GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
bungeman@google.com39698b12011-11-15 22:26:41 +0000819 if (GDI_ERROR == ret) {
820 ensure_typeface_accessible(fRec.fFontID);
821 ret = GetGlyphOutlineW(fDDC, glyph->getGlyphID(0), GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
822 }
reed@google.comac6b9792011-03-11 15:42:51 +0000823
824 if (GDI_ERROR != ret) {
825 if (ret == 0) {
826 // for white space, ret is zero and gmBlackBoxX, gmBlackBoxY are 1 incorrectly!
827 gm.gmBlackBoxX = gm.gmBlackBoxY = 0;
828 }
829 glyph->fWidth = gm.gmBlackBoxX;
830 glyph->fHeight = gm.gmBlackBoxY;
831 glyph->fTop = SkToS16(gm.gmptGlyphOrigin.y - gm.gmBlackBoxY);
832 glyph->fLeft = SkToS16(gm.gmptGlyphOrigin.x);
833 glyph->fAdvanceX = SkIntToFixed(gm.gmCellIncX);
834 glyph->fAdvanceY = -SkIntToFixed(gm.gmCellIncY);
835
reed@google.comf8cead52011-09-02 20:08:11 +0000836 // we outset in all dimensions, since the image may bleed outside
reed@google.comac6b9792011-03-11 15:42:51 +0000837 // of the computed bounds returned by GetGlyphOutline.
838 // This was deduced by trial and error for small text (e.g. 8pt), so there
839 // maybe a more precise way to make this adjustment...
reed@google.comf8cead52011-09-02 20:08:11 +0000840 //
841 // This test shows us clipping the tops of some of the CJK fonts unless we
842 // increase the top of the box by 2, hence the height by 4. This seems to
843 // correspond to an embedded bitmap font, but not sure.
844 // LayoutTests/fast/text/backslash-to-yen-sign-euc.html
845 //
reed@google.com5e2df642011-09-21 18:42:09 +0000846 if (glyph->fWidth) { // don't outset an empty glyph
847 glyph->fWidth += 4;
848 glyph->fHeight += 4;
849 glyph->fTop -= 2;
850 glyph->fLeft -= 2;
reed@google.comb8a5c612012-06-13 20:01:44 +0000851
reed@google.com81275392012-06-18 14:08:56 +0000852 apply_outset(glyph, fOutset);
reed@google.com5e2df642011-09-21 18:42:09 +0000853 }
reed@google.com1dd17a12011-05-17 14:04:41 +0000854
855 if (fHiResFont) {
856 SelectObject(fDDC, fHiResFont);
857 sk_bzero(&gm, sizeof(gm));
858 ret = GetGlyphOutlineW(fDDC, glyph->getGlyphID(0), GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22Identity);
859 if (GDI_ERROR != ret) {
860 SkPoint advance;
861 fHiResMatrix.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance);
862 glyph->fAdvanceX = SkScalarToFixed(advance.fX);
863 glyph->fAdvanceY = SkScalarToFixed(advance.fY);
864 }
865 SelectObject(fDDC, fFont);
866 }
reed@google.comac6b9792011-03-11 15:42:51 +0000867 } else {
bungeman@google.coma0319f62012-04-18 15:40:50 +0000868 glyph->zeroMetrics();
reed@google.comac6b9792011-03-11 15:42:51 +0000869 }
870}
871
872void SkScalerContext_Windows::generateFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my) {
873// Note: This code was borrowed from generateLineHeight, which has a note
874// stating that it may be incorrect.
875 if (!(mx || my))
876 return;
877
878 SkASSERT(fDDC);
879
bungeman@google.coma0319f62012-04-18 15:40:50 +0000880 if (fType == SkScalerContext_Windows::kBitmap_Type) {
881 if (mx) {
882 mx->fTop = SkIntToScalar(-fTM.tmAscent);
883 mx->fAscent = SkIntToScalar(-fTM.tmAscent);
884 mx->fDescent = -SkIntToScalar(fTM.tmDescent);
885 mx->fBottom = SkIntToScalar(fTM.tmDescent);
886 mx->fLeading = SkIntToScalar(fTM.tmInternalLeading
887 + fTM.tmExternalLeading);
888 }
889
890 if (my) {
891 my->fTop = SkIntToScalar(-fTM.tmAscent);
892 my->fAscent = SkIntToScalar(-fTM.tmAscent);
893 my->fDescent = SkIntToScalar(-fTM.tmDescent);
894 my->fBottom = SkIntToScalar(fTM.tmDescent);
895 my->fLeading = SkIntToScalar(fTM.tmInternalLeading
896 + fTM.tmExternalLeading);
897 }
898 return;
899 }
900
reed@google.comac6b9792011-03-11 15:42:51 +0000901 OUTLINETEXTMETRIC otm;
902
903 uint32_t ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
bungeman@google.com39698b12011-11-15 22:26:41 +0000904 if (GDI_ERROR == ret) {
905 ensure_typeface_accessible(fRec.fFontID);
906 ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
907 }
reed@google.comac6b9792011-03-11 15:42:51 +0000908 if (sizeof(otm) != ret) {
bungeman@google.coma0319f62012-04-18 15:40:50 +0000909 return;
reed@google.comac6b9792011-03-11 15:42:51 +0000910 }
911
912 if (mx) {
913 mx->fTop = -fScale * otm.otmTextMetrics.tmAscent;
ctguil@chromium.org5aa937b2011-08-04 01:01:24 +0000914 mx->fAscent = -fScale * otm.otmAscent;
915 mx->fDescent = -fScale * otm.otmDescent;
916 mx->fBottom = fScale * otm.otmTextMetrics.tmDescent;
917 mx->fLeading = fScale * (otm.otmTextMetrics.tmInternalLeading
918 + otm.otmTextMetrics.tmExternalLeading);
reed@google.comac6b9792011-03-11 15:42:51 +0000919 }
920
921 if (my) {
ctguil@chromium.org5aa937b2011-08-04 01:01:24 +0000922 my->fTop = -fScale * otm.otmTextMetrics.tmAscent;
923 my->fAscent = -fScale * otm.otmAscent;
924 my->fDescent = -fScale * otm.otmDescent;
925 my->fBottom = fScale * otm.otmTextMetrics.tmDescent;
926 my->fLeading = fScale * (otm.otmTextMetrics.tmInternalLeading
927 + otm.otmTextMetrics.tmExternalLeading);
reed@google.comac6b9792011-03-11 15:42:51 +0000928 }
929}
930
reed@google.com7430a332011-10-03 14:37:38 +0000931////////////////////////////////////////////////////////////////////////////////////////
932
933static void build_power_table(uint8_t table[], float ee) {
934 for (int i = 0; i < 256; i++) {
935 float x = i / 255.f;
bungeman@google.com97efada2012-07-30 20:40:50 +0000936 x = sk_float_pow(x, ee);
reed@google.com7430a332011-10-03 14:37:38 +0000937 int xx = SkScalarRound(SkFloatToScalar(x * 255));
938 table[i] = SkToU8(xx);
939 }
940}
941
bungeman@google.com97efada2012-07-30 20:40:50 +0000942/**
943 * This will invert the gamma applied by GDI (gray-scale antialiased), so we
944 * can get linear values.
945 *
946 * GDI grayscale appears to use a hard-coded gamma of 2.3.
947 *
948 * GDI grayscale appears to draw using the black and white rasterizer at four
949 * times the size and then downsamples to compute the coverage mask. As a
950 * result there are only seventeen total grays. This lack of fidelity means
951 * that shifting into other color spaces is imprecise.
952 */
953static const uint8_t* getInverseGammaTableGDI() {
reed@google.com7430a332011-10-03 14:37:38 +0000954 static bool gInited;
bungeman@google.com97efada2012-07-30 20:40:50 +0000955 static uint8_t gTableGdi[256];
956 if (!gInited) {
957 build_power_table(gTableGdi, 2.3f);
958 gInited = true;
959 }
960 return gTableGdi;
961}
962
963/**
964 * This will invert the gamma applied by GDI ClearType, so we can get linear
965 * values.
966 *
967 * GDI ClearType uses SPI_GETFONTSMOOTHINGCONTRAST / 1000 as the gamma value.
968 * If this value is not specified, the default is a gamma of 1.4.
969 */
970static const uint8_t* getInverseGammaTableClearType() {
971 static bool gInited;
972 static uint8_t gTableClearType[256];
reed@google.com7430a332011-10-03 14:37:38 +0000973 if (!gInited) {
974 UINT level = 0;
975 if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &level, 0) || !level) {
976 // can't get the data, so use a default
977 level = 1400;
978 }
bungeman@google.com97efada2012-07-30 20:40:50 +0000979 build_power_table(gTableClearType, level / 1000.0f);
reed@google.com7430a332011-10-03 14:37:38 +0000980 gInited = true;
981 }
bungeman@google.com97efada2012-07-30 20:40:50 +0000982 return gTableClearType;
reed@google.com7430a332011-10-03 14:37:38 +0000983}
984
reed@google.comac6b9792011-03-11 15:42:51 +0000985#include "SkColorPriv.h"
986
bungeman@google.com63853142012-08-01 15:36:46 +0000987//Cannot assume that the input rgb is gray due to possible setting of kGenA8FromLCD_Flag.
bungeman@google.com97efada2012-07-30 20:40:50 +0000988template<bool APPLY_PREBLEND>
989static inline uint8_t rgb_to_a8(SkGdiRGB rgb, const uint8_t* table8) {
bungeman@google.com63853142012-08-01 15:36:46 +0000990 U8CPU r = (rgb >> 16) & 0xFF;
991 U8CPU g = (rgb >> 8) & 0xFF;
992 U8CPU b = (rgb >> 0) & 0xFF;
bungeman@google.com1bfe01d2012-08-28 16:02:42 +0000993 return sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8);
reed@google.com8351aab2012-01-18 17:06:35 +0000994}
995
bungeman@google.com97efada2012-07-30 20:40:50 +0000996template<bool APPLY_PREBLEND>
997static inline uint16_t rgb_to_lcd16(SkGdiRGB rgb, const uint8_t* tableR,
998 const uint8_t* tableG,
999 const uint8_t* tableB) {
1000 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
1001 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG);
1002 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB);
1003 return SkPack888ToRGB16(r, g, b);
reed@google.com82a34d82011-07-26 19:33:08 +00001004}
1005
bungeman@google.com97efada2012-07-30 20:40:50 +00001006template<bool APPLY_PREBLEND>
1007static inline SkPMColor rgb_to_lcd32(SkGdiRGB rgb, const uint8_t* tableR,
1008 const uint8_t* tableG,
1009 const uint8_t* tableB) {
1010 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
1011 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG);
1012 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB);
1013 return SkPackARGB32(0xFF, r, g, b);
reed@google.com754e4eb2011-09-26 13:21:39 +00001014}
1015
reed@google.com82cff022011-09-22 14:33:40 +00001016// Is this GDI color neither black nor white? If so, we have to keep this
1017// image as is, rather than smashing it down to a BW mask.
1018//
1019// returns int instead of bool, since we don't want/have to pay to convert
1020// the zero/non-zero value into a bool
1021static int is_not_black_or_white(SkGdiRGB c) {
1022 // same as (but faster than)
1023 // c &= 0x00FFFFFF;
1024 // return 0 == c || 0x00FFFFFF == c;
1025 return (c + (c & 1)) & 0x00FFFFFF;
reed@google.com5e2df642011-09-21 18:42:09 +00001026}
1027
1028static bool is_rgb_really_bw(const SkGdiRGB* src, int width, int height, int srcRB) {
1029 for (int y = 0; y < height; ++y) {
1030 for (int x = 0; x < width; ++x) {
reed@google.com82cff022011-09-22 14:33:40 +00001031 if (is_not_black_or_white(src[x])) {
reed@google.com5e2df642011-09-21 18:42:09 +00001032 return false;
1033 }
1034 }
reed@google.com6f5df482011-09-28 20:33:24 +00001035 src = SkTAddByteOffset(src, srcRB);
reed@google.com5e2df642011-09-21 18:42:09 +00001036 }
1037 return true;
1038}
1039
bungeman@google.com97efada2012-07-30 20:40:50 +00001040// gdi's bitmap is upside-down, so we reverse dst walking in Y
1041// whenever we copy it into skia's buffer
reed@google.com5e2df642011-09-21 18:42:09 +00001042static void rgb_to_bw(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
bungeman@google.com97efada2012-07-30 20:40:50 +00001043 const SkGlyph& glyph) {
reed@google.com5e2df642011-09-21 18:42:09 +00001044 const int width = glyph.fWidth;
1045 const size_t dstRB = (width + 7) >> 3;
1046 uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1047
1048 int byteCount = width >> 3;
1049 int bitCount = width & 7;
1050
1051 // adjust srcRB to skip the values in our byteCount loop,
1052 // since we increment src locally there
1053 srcRB -= byteCount * 8 * sizeof(SkGdiRGB);
1054
1055 for (int y = 0; y < glyph.fHeight; ++y) {
1056 if (byteCount > 0) {
reed@google.com5e2df642011-09-21 18:42:09 +00001057 for (int i = 0; i < byteCount; ++i) {
reed@google.com7a230142011-09-27 14:07:21 +00001058 unsigned byte = 0;
bungeman@google.com97efada2012-07-30 20:40:50 +00001059 byte |= src[0] & (1 << 7);
1060 byte |= src[1] & (1 << 6);
1061 byte |= src[2] & (1 << 5);
1062 byte |= src[3] & (1 << 4);
1063 byte |= src[4] & (1 << 3);
1064 byte |= src[5] & (1 << 2);
1065 byte |= src[6] & (1 << 1);
1066 byte |= src[7] & (1 << 0);
reed@google.com6a8f14d2011-09-27 12:54:24 +00001067 dst[i] = byte;
reed@google.com5e2df642011-09-21 18:42:09 +00001068 src += 8;
1069 }
1070 }
1071 if (bitCount > 0) {
1072 unsigned byte = 0;
1073 unsigned mask = 0x80;
1074 for (int i = 0; i < bitCount; i++) {
bungeman@google.com97efada2012-07-30 20:40:50 +00001075 byte |= src[i] & mask;
reed@google.com5e2df642011-09-21 18:42:09 +00001076 mask >>= 1;
1077 }
1078 dst[byteCount] = byte;
1079 }
reed@google.com6f5df482011-09-28 20:33:24 +00001080 src = SkTAddByteOffset(src, srcRB);
reed@google.com5e2df642011-09-21 18:42:09 +00001081 dst -= dstRB;
1082 }
1083}
1084
bungeman@google.com97efada2012-07-30 20:40:50 +00001085template<bool APPLY_PREBLEND>
reed@google.com5e2df642011-09-21 18:42:09 +00001086static void rgb_to_a8(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
bungeman@google.com97efada2012-07-30 20:40:50 +00001087 const SkGlyph& glyph, const uint8_t* table8) {
reed@google.com5e2df642011-09-21 18:42:09 +00001088 const size_t dstRB = glyph.rowBytes();
1089 const int width = glyph.fWidth;
1090 uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1091
1092 for (int y = 0; y < glyph.fHeight; y++) {
1093 for (int i = 0; i < width; i++) {
bungeman@google.com97efada2012-07-30 20:40:50 +00001094 dst[i] = rgb_to_a8<APPLY_PREBLEND>(src[i], table8);
reed@google.com5e2df642011-09-21 18:42:09 +00001095 }
reed@google.com6f5df482011-09-28 20:33:24 +00001096 src = SkTAddByteOffset(src, srcRB);
reed@google.com5e2df642011-09-21 18:42:09 +00001097 dst -= dstRB;
1098 }
1099}
1100
bungeman@google.com97efada2012-07-30 20:40:50 +00001101template<bool APPLY_PREBLEND>
1102static void rgb_to_lcd16(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph,
1103 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
reed@google.com5e2df642011-09-21 18:42:09 +00001104 const size_t dstRB = glyph.rowBytes();
1105 const int width = glyph.fWidth;
1106 uint16_t* SK_RESTRICT dst = (uint16_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1107
1108 for (int y = 0; y < glyph.fHeight; y++) {
1109 for (int i = 0; i < width; i++) {
bungeman@google.com97efada2012-07-30 20:40:50 +00001110 dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(src[i], tableR, tableG, tableB);
reed@google.com5e2df642011-09-21 18:42:09 +00001111 }
reed@google.com6f5df482011-09-28 20:33:24 +00001112 src = SkTAddByteOffset(src, srcRB);
reed@google.com5e2df642011-09-21 18:42:09 +00001113 dst = (uint16_t*)((char*)dst - dstRB);
1114 }
1115}
1116
bungeman@google.com97efada2012-07-30 20:40:50 +00001117template<bool APPLY_PREBLEND>
1118static void rgb_to_lcd32(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph,
1119 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
reed@google.com754e4eb2011-09-26 13:21:39 +00001120 const size_t dstRB = glyph.rowBytes();
1121 const int width = glyph.fWidth;
bungeman@google.com97efada2012-07-30 20:40:50 +00001122 uint32_t* SK_RESTRICT dst = (uint32_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
reed@google.com754e4eb2011-09-26 13:21:39 +00001123
1124 for (int y = 0; y < glyph.fHeight; y++) {
1125 for (int i = 0; i < width; i++) {
bungeman@google.com97efada2012-07-30 20:40:50 +00001126 dst[i] = rgb_to_lcd32<APPLY_PREBLEND>(src[i], tableR, tableG, tableB);
reed@google.com754e4eb2011-09-26 13:21:39 +00001127 }
reed@google.com6f5df482011-09-28 20:33:24 +00001128 src = SkTAddByteOffset(src, srcRB);
bungeman@google.com97efada2012-07-30 20:40:50 +00001129 dst = (uint32_t*)((char*)dst - dstRB);
reed@google.com754e4eb2011-09-26 13:21:39 +00001130 }
1131}
1132
reed@google.com6f5df482011-09-28 20:33:24 +00001133static inline unsigned clamp255(unsigned x) {
1134 SkASSERT(x <= 256);
1135 return x - (x >> 8);
1136}
1137
bungeman@google.coma76de722012-10-26 19:35:54 +00001138void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) {
bungeman@google.com97efada2012-07-30 20:40:50 +00001139 SkAutoMutexAcquire ac(gFTMutex);
reed@google.comac6b9792011-03-11 15:42:51 +00001140 SkASSERT(fDDC);
1141
reed@google.com62711172011-05-18 15:08:10 +00001142 const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat;
reed@google.com82a34d82011-07-26 19:33:08 +00001143 const bool isAA = !isLCD(fRec);
reed@google.comac6b9792011-03-11 15:42:51 +00001144
reed@google.com99edd432011-09-09 14:59:59 +00001145 size_t srcRB;
bungeman@google.com97efada2012-07-30 20:40:50 +00001146 const void* bits = fOffscreen.draw(glyph, isBW, &srcRB);
bungeman@google.com39698b12011-11-15 22:26:41 +00001147 if (NULL == bits) {
1148 ensure_typeface_accessible(fRec.fFontID);
bungeman@google.com97efada2012-07-30 20:40:50 +00001149 bits = fOffscreen.draw(glyph, isBW, &srcRB);
bungeman@google.com39698b12011-11-15 22:26:41 +00001150 if (NULL == bits) {
1151 sk_bzero(glyph.fImage, glyph.computeImageSize());
1152 return;
1153 }
reed@google.com82a34d82011-07-26 19:33:08 +00001154 }
reed@google.comac6b9792011-03-11 15:42:51 +00001155
bungeman@google.com97efada2012-07-30 20:40:50 +00001156 if (!isBW) {
bungeman@google.com1bd2d672012-08-13 20:01:51 +00001157 const uint8_t* table;
1158 //The offscreen contains a GDI blit if isAA and kGenA8FromLCD_Flag is not set.
1159 //Otherwise the offscreen contains a ClearType blit.
1160 if (isAA && !(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag)) {
1161 table = getInverseGammaTableGDI();
1162 } else {
1163 table = getInverseGammaTableClearType();
bungeman@google.com97efada2012-07-30 20:40:50 +00001164 }
1165 //Note that the following cannot really be integrated into the
1166 //pre-blend, since we may not be applying the pre-blend; when we aren't
1167 //applying the pre-blend it means that a filter wants linear anyway.
1168 //Other code may also be applying the pre-blend, so we'd need another
1169 //one with this and one without.
reed@google.com6f5df482011-09-28 20:33:24 +00001170 SkGdiRGB* addr = (SkGdiRGB*)bits;
1171 for (int y = 0; y < glyph.fHeight; ++y) {
1172 for (int x = 0; x < glyph.fWidth; ++x) {
1173 int r = (addr[x] >> 16) & 0xFF;
1174 int g = (addr[x] >> 8) & 0xFF;
1175 int b = (addr[x] >> 0) & 0xFF;
reed@google.com7430a332011-10-03 14:37:38 +00001176 addr[x] = (table[r] << 16) | (table[g] << 8) | table[b];
reed@google.com6f5df482011-09-28 20:33:24 +00001177 }
1178 addr = SkTAddByteOffset(addr, srcRB);
1179 }
1180 }
1181
reed@google.com82a34d82011-07-26 19:33:08 +00001182 int width = glyph.fWidth;
1183 size_t dstRB = glyph.rowBytes();
1184 if (isBW) {
1185 const uint8_t* src = (const uint8_t*)bits;
reed@google.com82a34d82011-07-26 19:33:08 +00001186 uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1187 for (int y = 0; y < glyph.fHeight; y++) {
1188 memcpy(dst, src, dstRB);
1189 src += srcRB;
1190 dst -= dstRB;
reed@google.comac6b9792011-03-11 15:42:51 +00001191 }
reed@google.com82a34d82011-07-26 19:33:08 +00001192 } else if (isAA) {
reed@google.com6f5df482011-09-28 20:33:24 +00001193 // since the caller may require A8 for maskfilters, we can't check for BW
1194 // ... until we have the caller tell us that explicitly
reed@google.com5e2df642011-09-21 18:42:09 +00001195 const SkGdiRGB* src = (const SkGdiRGB*)bits;
bungeman@google.coma76de722012-10-26 19:35:54 +00001196 if (fPreBlend.isApplicable()) {
1197 rgb_to_a8<true>(src, srcRB, glyph, fPreBlend.fG);
bungeman@google.com97efada2012-07-30 20:40:50 +00001198 } else {
bungeman@google.coma76de722012-10-26 19:35:54 +00001199 rgb_to_a8<false>(src, srcRB, glyph, fPreBlend.fG);
bungeman@google.com97efada2012-07-30 20:40:50 +00001200 }
reed@google.com82a34d82011-07-26 19:33:08 +00001201 } else { // LCD16
reed@google.com5e2df642011-09-21 18:42:09 +00001202 const SkGdiRGB* src = (const SkGdiRGB*)bits;
1203 if (is_rgb_really_bw(src, width, glyph.fHeight, srcRB)) {
bungeman@google.com97efada2012-07-30 20:40:50 +00001204 rgb_to_bw(src, srcRB, glyph);
reed@google.com5e2df642011-09-21 18:42:09 +00001205 ((SkGlyph*)&glyph)->fMaskFormat = SkMask::kBW_Format;
1206 } else {
reed@google.com754e4eb2011-09-26 13:21:39 +00001207 if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
bungeman@google.coma76de722012-10-26 19:35:54 +00001208 if (fPreBlend.isApplicable()) {
1209 rgb_to_lcd16<true>(src, srcRB, glyph,
1210 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
bungeman@google.com97efada2012-07-30 20:40:50 +00001211 } else {
bungeman@google.coma76de722012-10-26 19:35:54 +00001212 rgb_to_lcd16<false>(src, srcRB, glyph,
1213 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
bungeman@google.com97efada2012-07-30 20:40:50 +00001214 }
reed@google.com754e4eb2011-09-26 13:21:39 +00001215 } else {
1216 SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat);
bungeman@google.coma76de722012-10-26 19:35:54 +00001217 if (fPreBlend.isApplicable()) {
1218 rgb_to_lcd32<true>(src, srcRB, glyph,
1219 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
bungeman@google.com97efada2012-07-30 20:40:50 +00001220 } else {
bungeman@google.coma76de722012-10-26 19:35:54 +00001221 rgb_to_lcd32<false>(src, srcRB, glyph,
1222 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
bungeman@google.com97efada2012-07-30 20:40:50 +00001223 }
reed@google.com754e4eb2011-09-26 13:21:39 +00001224 }
reed@google.comac6b9792011-03-11 15:42:51 +00001225 }
1226 }
reed@google.comac6b9792011-03-11 15:42:51 +00001227}
1228
1229void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) {
1230
1231 SkAutoMutexAcquire ac(gFTMutex);
1232
1233 SkASSERT(&glyph && path);
1234 SkASSERT(fDDC);
1235
1236 path->reset();
1237
1238#if 0
1239 char buf[1024];
1240 sprintf(buf, "generatePath: id:%d, w=%d, h=%d, font:%s,fh:%d\n", glyph.fID, glyph.fWidth, glyph.fHeight, lf.lfFaceName, lf.lfHeight);
1241 OutputDebugString(buf);
1242#endif
1243
1244 GLYPHMETRICS gm;
1245 uint32_t total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, BUFFERSIZE, glyphbuf, &fMat22);
bungeman@google.com39698b12011-11-15 22:26:41 +00001246 if (GDI_ERROR == total_size) {
1247 ensure_typeface_accessible(fRec.fFontID);
1248 total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, BUFFERSIZE, glyphbuf, &fMat22);
1249 }
reed@google.comac6b9792011-03-11 15:42:51 +00001250
1251 if (GDI_ERROR != total_size) {
1252
1253 const uint8_t* cur_glyph = glyphbuf;
1254 const uint8_t* end_glyph = glyphbuf + total_size;
1255
1256 while(cur_glyph < end_glyph) {
1257 const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
1258
1259 const uint8_t* end_poly = cur_glyph + th->cb;
1260 const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
1261
1262 path->moveTo(SkFixedToScalar(*(SkFixed*)(&th->pfxStart.x)), SkFixedToScalar(*(SkFixed*)(&th->pfxStart.y)));
1263
1264 while(cur_poly < end_poly) {
1265 const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
1266
1267 if (pc->wType == TT_PRIM_LINE) {
1268 for (uint16_t i = 0; i < pc->cpfx; i++) {
1269 path->lineTo(SkFixedToScalar(*(SkFixed*)(&pc->apfx[i].x)), SkFixedToScalar(*(SkFixed*)(&pc->apfx[i].y)));
1270 }
1271 }
1272
1273 if (pc->wType == TT_PRIM_QSPLINE) {
1274 for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline
1275 POINTFX pnt_b = pc->apfx[u]; // B is always the current point
1276 POINTFX pnt_c = pc->apfx[u+1];
1277
1278 if (u < pc->cpfx - 2) { // If not on last spline, compute C
1279 pnt_c.x = SkFixedToFIXED(SkFixedAve(*(SkFixed*)(&pnt_b.x), *(SkFixed*)(&pnt_c.x)));
1280 pnt_c.y = SkFixedToFIXED(SkFixedAve(*(SkFixed*)(&pnt_b.y), *(SkFixed*)(&pnt_c.y)));
1281 }
1282
1283 path->quadTo(SkFixedToScalar(*(SkFixed*)(&pnt_b.x)), SkFixedToScalar(*(SkFixed*)(&pnt_b.y)), SkFixedToScalar(*(SkFixed*)(&pnt_c.x)), SkFixedToScalar(*(SkFixed*)(&pnt_c.y)));
1284 }
1285 }
1286 cur_poly += sizeof(uint16_t) * 2 + sizeof(POINTFX) * pc->cpfx;
1287 }
1288 cur_glyph += th->cb;
1289 path->close();
1290 }
1291 }
1292 else {
1293 SkASSERT(false);
1294 }
1295 //char buf[1024];
1296 //sprintf(buf, "generatePath: count:%d\n", count);
1297 //OutputDebugString(buf);
1298}
1299
bungeman@google.come70f7982012-06-01 19:38:19 +00001300static void logfont_for_name(const char* familyName, LOGFONT& lf) {
1301 memset(&lf, 0, sizeof(LOGFONT));
1302#ifdef UNICODE
1303 // Get the buffer size needed first.
1304 size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName,
1305 -1, NULL, 0);
1306 // Allocate a buffer (str_len already has terminating null
1307 // accounted for).
1308 wchar_t *wideFamilyName = new wchar_t[str_len];
1309 // Now actually convert the string.
1310 ::MultiByteToWideChar(CP_UTF8, 0, familyName, -1,
1311 wideFamilyName, str_len);
1312 ::wcsncpy(lf.lfFaceName, wideFamilyName, LF_FACESIZE - 1);
1313 delete [] wideFamilyName;
1314 lf.lfFaceName[LF_FACESIZE-1] = L'\0';
1315#else
1316 ::strncpy(lf.lfFaceName, familyName, LF_FACESIZE - 1);
1317 lf.lfFaceName[LF_FACESIZE - 1] = '\0';
1318#endif
1319}
1320
bungeman@google.com7103f182012-10-31 20:53:49 +00001321static void tchar_to_skstring(const TCHAR* t, SkString* s) {
bungeman@google.come70f7982012-06-01 19:38:19 +00001322#ifdef UNICODE
bungeman@google.com7103f182012-10-31 20:53:49 +00001323 size_t sSize = WideCharToMultiByte(CP_UTF8, 0, t, -1, NULL, 0, NULL, NULL);
1324 s->resize(sSize);
1325 WideCharToMultiByte(CP_UTF8, 0, t, -1, s->writable_str(), sSize, NULL, NULL);
bungeman@google.come70f7982012-06-01 19:38:19 +00001326#else
bungeman@google.com7103f182012-10-31 20:53:49 +00001327 s->set(t);
bungeman@google.come70f7982012-06-01 19:38:19 +00001328#endif
1329}
1330
1331void SkFontHost::Serialize(const SkTypeface* rawFace, SkWStream* stream) {
1332 const LogFontTypeface* face = static_cast<const LogFontTypeface*>(rawFace);
1333 SkFontDescriptor descriptor(face->style());
1334
bungeman@google.com7103f182012-10-31 20:53:49 +00001335 // Get the actual name of the typeface. The logfont may not know this.
1336 HFONT font = CreateFontIndirect(&face->fLogFont);
1337
1338 HDC deviceContext = ::CreateCompatibleDC(NULL);
1339 HFONT savefont = (HFONT)SelectObject(deviceContext, font);
1340
1341 int fontNameLen; //length of fontName in TCHARS.
1342 if (0 == (fontNameLen = GetTextFace(deviceContext, 0, NULL))) {
1343 SkFontHost::EnsureTypefaceAccessible(*rawFace);
1344 if (0 == (fontNameLen = GetTextFace(deviceContext, 0, NULL))) {
1345 fontNameLen = 0;
1346 }
1347 }
1348
1349 SkAutoSTArray<LF_FULLFACESIZE, TCHAR> fontName(fontNameLen+1);
1350 if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) {
1351 SkFontHost::EnsureTypefaceAccessible(*rawFace);
1352 if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) {
1353 fontName[0] = 0;
1354 }
1355 }
1356
1357 if (deviceContext) {
1358 ::SelectObject(deviceContext, savefont);
1359 ::DeleteDC(deviceContext);
1360 }
1361 if (font) {
1362 ::DeleteObject(font);
1363 }
1364
bungeman@google.come70f7982012-06-01 19:38:19 +00001365 SkString familyName;
bungeman@google.com7103f182012-10-31 20:53:49 +00001366 tchar_to_skstring(fontName.get(), &familyName);
bungeman@google.come70f7982012-06-01 19:38:19 +00001367 descriptor.setFamilyName(familyName.c_str());
1368 //TODO: FileName and PostScriptName currently unsupported.
1369
1370 descriptor.serialize(stream);
1371
1372 if (face->fSerializeAsStream) {
1373 // store the entire font in the fontData
1374 SkAutoTUnref<SkStream> fontStream(SkFontHost::OpenStream(face->uniqueID()));
1375 const uint32_t length = fontStream->getLength();
1376
1377 stream->writePackedUInt(length);
1378 stream->writeStream(fontStream, length);
1379 } else {
1380 stream->writePackedUInt(0);
1381 }
reed@google.comac6b9792011-03-11 15:42:51 +00001382}
1383
1384SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
bungeman@google.come70f7982012-06-01 19:38:19 +00001385 SkFontDescriptor descriptor(stream);
1386
1387 const uint32_t customFontDataLength = stream->readPackedUInt();
1388 if (customFontDataLength > 0) {
1389 // generate a new stream to store the custom typeface
1390 SkAutoTUnref<SkMemoryStream> fontStream(SkNEW_ARGS(SkMemoryStream, (customFontDataLength - 1)));
1391 stream->read((void*)fontStream->getMemoryBase(), customFontDataLength - 1);
1392
1393 return CreateTypefaceFromStream(fontStream.get());
1394 }
1395
1396 return SkFontHost::CreateTypeface(NULL, descriptor.getFamilyName(), descriptor.getStyle());
reed@google.comac6b9792011-03-11 15:42:51 +00001397}
1398
1399static bool getWidthAdvance(HDC hdc, int gId, int16_t* advance) {
1400 // Initialize the MAT2 structure to the identify transformation matrix.
1401 static const MAT2 mat2 = {SkScalarToFIXED(1), SkScalarToFIXED(0),
1402 SkScalarToFIXED(0), SkScalarToFIXED(1)};
1403 int flags = GGO_METRICS | GGO_GLYPH_INDEX;
1404 GLYPHMETRICS gm;
1405 if (GDI_ERROR == GetGlyphOutline(hdc, gId, flags, &gm, 0, NULL, &mat2)) {
1406 return false;
1407 }
1408 SkASSERT(advance);
1409 *advance = gm.gmCellIncX;
1410 return true;
1411}
1412
1413// static
1414SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
vandebo@chromium.org325cb9a2011-03-30 18:36:29 +00001415 uint32_t fontID,
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +00001416 SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
1417 const uint32_t* glyphIDs,
1418 uint32_t glyphIDsCount) {
reed@google.com59d2f632011-05-02 19:36:59 +00001419 LOGFONT lf;
1420 GetLogFontByID(fontID, &lf);
reed@google.comac6b9792011-03-11 15:42:51 +00001421 SkAdvancedTypefaceMetrics* info = NULL;
1422
1423 HDC hdc = CreateCompatibleDC(NULL);
1424 HFONT font = CreateFontIndirect(&lf);
1425 HFONT savefont = (HFONT)SelectObject(hdc, font);
1426 HFONT designFont = NULL;
1427
reed@google.com05b6f3a2011-11-28 15:30:28 +00001428 const char stem_chars[] = {'i', 'I', '!', '1'};
1429 int16_t min_width;
1430 unsigned glyphCount;
1431
reed@google.comac6b9792011-03-11 15:42:51 +00001432 // To request design units, create a logical font whose height is specified
1433 // as unitsPerEm.
1434 OUTLINETEXTMETRIC otm;
bungeman@google.com39698b12011-11-15 22:26:41 +00001435 unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
1436 if (0 == otmRet) {
1437 ensure_typeface_accessible(fontID);
1438 otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
1439 }
1440 if (!otmRet || !GetTextFace(hdc, LF_FACESIZE, lf.lfFaceName)) {
reed@google.comac6b9792011-03-11 15:42:51 +00001441 goto Error;
1442 }
1443 lf.lfHeight = -SkToS32(otm.otmEMSquare);
1444 designFont = CreateFontIndirect(&lf);
1445 SelectObject(hdc, designFont);
1446 if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm)) {
1447 goto Error;
1448 }
bungeman@google.coma0319f62012-04-18 15:40:50 +00001449 glyphCount = calculateOutlineGlyphCount(hdc);
reed@google.comac6b9792011-03-11 15:42:51 +00001450
1451 info = new SkAdvancedTypefaceMetrics;
1452 info->fEmSize = otm.otmEMSquare;
1453 info->fMultiMaster = false;
1454 info->fLastGlyphID = SkToU16(glyphCount - 1);
1455 info->fStyle = 0;
bungeman@google.com7103f182012-10-31 20:53:49 +00001456 tchar_to_skstring(lf.lfFaceName, &info->fFontName);
reed@google.comac6b9792011-03-11 15:42:51 +00001457
vandebo@chromium.org6744d492011-05-09 18:13:47 +00001458 if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) {
1459 populate_glyph_to_unicode(hdc, glyphCount, &(info->fGlyphToUnicode));
1460 }
1461
vandebo@chromium.orgd41e70d2012-03-08 19:41:01 +00001462 if (glyphCount > 0 &&
1463 (otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE)) {
reed@google.comac6b9792011-03-11 15:42:51 +00001464 info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
1465 } else {
1466 info->fType = SkAdvancedTypefaceMetrics::kOther_Font;
1467 info->fItalicAngle = 0;
1468 info->fAscent = 0;
1469 info->fDescent = 0;
1470 info->fStemV = 0;
1471 info->fCapHeight = 0;
1472 info->fBBox = SkIRect::MakeEmpty();
1473 return info;
1474 }
ctguil@chromium.org5aa937b2011-08-04 01:01:24 +00001475
reed@google.comac6b9792011-03-11 15:42:51 +00001476 // If this bit is clear the font is a fixed pitch font.
1477 if (!(otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
1478 info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
1479 }
1480 if (otm.otmTextMetrics.tmItalic) {
1481 info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
1482 }
1483 // Setting symbolic style by default for now.
1484 info->fStyle |= SkAdvancedTypefaceMetrics::kSymbolic_Style;
1485 if (otm.otmTextMetrics.tmPitchAndFamily & FF_ROMAN) {
1486 info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
1487 } else if (otm.otmTextMetrics.tmPitchAndFamily & FF_SCRIPT) {
1488 info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
1489 }
1490
1491 // The main italic angle of the font, in tenths of a degree counterclockwise
1492 // from vertical.
1493 info->fItalicAngle = otm.otmItalicAngle / 10;
1494 info->fAscent = SkToS16(otm.otmTextMetrics.tmAscent);
1495 info->fDescent = SkToS16(-otm.otmTextMetrics.tmDescent);
1496 // TODO(ctguil): Use alternate cap height calculation.
1497 // MSDN says otmsCapEmHeight is not support but it is returning a value on
1498 // my Win7 box.
1499 info->fCapHeight = otm.otmsCapEmHeight;
1500 info->fBBox =
1501 SkIRect::MakeLTRB(otm.otmrcFontBox.left, otm.otmrcFontBox.top,
1502 otm.otmrcFontBox.right, otm.otmrcFontBox.bottom);
1503
1504 // Figure out a good guess for StemV - Min width of i, I, !, 1.
1505 // This probably isn't very good with an italic font.
reed@google.com05b6f3a2011-11-28 15:30:28 +00001506 min_width = SHRT_MAX;
reed@google.comac6b9792011-03-11 15:42:51 +00001507 info->fStemV = 0;
reed@google.comac6b9792011-03-11 15:42:51 +00001508 for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) {
1509 ABC abcWidths;
1510 if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) {
1511 int16_t width = abcWidths.abcB;
1512 if (width > 0 && width < min_width) {
1513 min_width = width;
1514 info->fStemV = min_width;
1515 }
1516 }
1517 }
1518
1519 // If bit 1 is set, the font may not be embedded in a document.
1520 // If bit 1 is clear, the font can be embedded.
1521 // If bit 2 is set, the embedding is read-only.
1522 if (otm.otmfsType & 0x1) {
1523 info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
ctguil@chromium.org0e6dc0a2011-03-30 20:41:16 +00001524 } else if (perGlyphInfo &
1525 SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) {
ctguil@chromium.org5aa937b2011-08-04 01:01:24 +00001526 if (info->fStyle & SkAdvancedTypefaceMetrics::kFixedPitch_Style) {
1527 appendRange(&info->fGlyphWidths, 0);
1528 info->fGlyphWidths->fAdvance.append(1, &min_width);
1529 finishRange(info->fGlyphWidths.get(), 0,
1530 SkAdvancedTypefaceMetrics::WidthRange::kDefault);
1531 } else {
1532 info->fGlyphWidths.reset(
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +00001533 getAdvanceData(hdc,
1534 glyphCount,
1535 glyphIDs,
1536 glyphIDsCount,
1537 &getWidthAdvance));
ctguil@chromium.org5aa937b2011-08-04 01:01:24 +00001538 }
reed@google.comac6b9792011-03-11 15:42:51 +00001539 }
1540
1541Error:
1542 SelectObject(hdc, savefont);
1543 DeleteObject(designFont);
1544 DeleteObject(font);
1545 DeleteDC(hdc);
1546
1547 return info;
1548}
1549
bungeman@google.coma5501992012-05-18 19:06:41 +00001550//Dummy representation of a Base64 encoded GUID from create_unique_font_name.
1551#define BASE64_GUID_ID "XXXXXXXXXXXXXXXXXXXXXXXX"
1552//Length of GUID representation from create_id, including NULL terminator.
1553#define BASE64_GUID_ID_LEN SK_ARRAY_COUNT(BASE64_GUID_ID)
reed@google.comac6b9792011-03-11 15:42:51 +00001554
bungeman@google.coma5501992012-05-18 19:06:41 +00001555SK_COMPILE_ASSERT(BASE64_GUID_ID_LEN < LF_FACESIZE, GUID_longer_than_facesize);
1556
1557/**
1558 NameID 6 Postscript names cannot have the character '/'.
1559 It would be easier to hex encode the GUID, but that is 32 bytes,
1560 and many systems have issues with names longer than 28 bytes.
1561 The following need not be any standard base64 encoding.
1562 The encoded value is never decoded.
1563*/
rmistry@google.comd6176b02012-08-23 18:14:13 +00001564static const char postscript_safe_base64_encode[] =
bungeman@google.coma5501992012-05-18 19:06:41 +00001565 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1566 "abcdefghijklmnopqrstuvwxyz"
1567 "0123456789-_=";
1568
1569/**
1570 Formats a GUID into Base64 and places it into buffer.
1571 buffer should have space for at least BASE64_GUID_ID_LEN characters.
1572 The string will always be null terminated.
1573 XXXXXXXXXXXXXXXXXXXXXXXX0
1574 */
1575static void format_guid_b64(const GUID& guid, char* buffer, size_t bufferSize) {
1576 SkASSERT(bufferSize >= BASE64_GUID_ID_LEN);
1577 size_t written = SkBase64::Encode(&guid, sizeof(guid), buffer, postscript_safe_base64_encode);
1578 SkASSERT(written < LF_FACESIZE);
1579 buffer[written] = '\0';
1580}
1581
1582/**
1583 Creates a Base64 encoded GUID and places it into buffer.
1584 buffer should have space for at least BASE64_GUID_ID_LEN characters.
1585 The string will always be null terminated.
1586 XXXXXXXXXXXXXXXXXXXXXXXX0
1587 */
1588static HRESULT create_unique_font_name(char* buffer, size_t bufferSize) {
1589 GUID guid = {};
1590 if (FAILED(CoCreateGuid(&guid))) {
1591 return E_UNEXPECTED;
1592 }
1593 format_guid_b64(guid, buffer, bufferSize);
1594
1595 return S_OK;
1596}
1597
1598/**
1599 Introduces a font to GDI. On failure will return NULL. The returned handle
1600 should eventually be passed to RemoveFontMemResourceEx.
1601*/
1602static HANDLE activate_font(SkData* fontData) {
1603 DWORD numFonts = 0;
1604 //AddFontMemResourceEx just copies the data, but does not specify const.
1605 HANDLE fontHandle = AddFontMemResourceEx(const_cast<void*>(fontData->data()),
1606 fontData->size(),
1607 0,
1608 &numFonts);
1609
1610 if (fontHandle != NULL && numFonts < 1) {
1611 RemoveFontMemResourceEx(fontHandle);
1612 return NULL;
1613 }
1614
1615 return fontHandle;
1616}
1617
bungeman@google.coma5501992012-05-18 19:06:41 +00001618SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
1619 // Create a unique and unpredictable font name.
1620 // Avoids collisions and access from CSS.
1621 char familyName[BASE64_GUID_ID_LEN];
1622 const int familyNameSize = SK_ARRAY_COUNT(familyName);
1623 if (FAILED(create_unique_font_name(familyName, familyNameSize))) {
1624 return NULL;
1625 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001626
bungeman@google.coma5501992012-05-18 19:06:41 +00001627 // Change the name of the font.
bungeman@google.come9bbee32012-05-21 13:46:13 +00001628 SkAutoTUnref<SkData> rewrittenFontData(SkOTUtils::RenameFont(stream, familyName, familyNameSize-1));
1629 if (NULL == rewrittenFontData.get()) {
bungeman@google.coma5501992012-05-18 19:06:41 +00001630 return NULL;
1631 }
bungeman@google.coma5501992012-05-18 19:06:41 +00001632
1633 // Register the font with GDI.
bungeman@google.come9bbee32012-05-21 13:46:13 +00001634 HANDLE fontReference = activate_font(rewrittenFontData.get());
bungeman@google.coma5501992012-05-18 19:06:41 +00001635 if (NULL == fontReference) {
1636 return NULL;
1637 }
1638
1639 // Create the typeface.
1640 LOGFONT lf;
1641 logfont_for_name(familyName, lf);
1642
1643 return SkCreateFontMemResourceTypefaceFromLOGFONT(lf, fontReference);
reed@google.comac6b9792011-03-11 15:42:51 +00001644}
1645
1646SkStream* SkFontHost::OpenStream(SkFontID uniqueID) {
ctguil@chromium.orgf4c26222011-05-16 22:00:05 +00001647 const DWORD kTTCTag =
1648 SkEndian_SwapBE32(SkSetFourByteTag('t', 't', 'c', 'f'));
reed@google.com59d2f632011-05-02 19:36:59 +00001649 LOGFONT lf;
1650 GetLogFontByID(uniqueID, &lf);
reed@google.comac6b9792011-03-11 15:42:51 +00001651
1652 HDC hdc = ::CreateCompatibleDC(NULL);
reed@google.com59d2f632011-05-02 19:36:59 +00001653 HFONT font = CreateFontIndirect(&lf);
reed@google.comac6b9792011-03-11 15:42:51 +00001654 HFONT savefont = (HFONT)SelectObject(hdc, font);
1655
vandebo@chromium.orgd6044812011-05-13 03:41:29 +00001656 SkMemoryStream* stream = NULL;
1657 DWORD tables[2] = {kTTCTag, 0};
1658 for (int i = 0; i < SK_ARRAY_COUNT(tables); i++) {
1659 size_t bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0);
bungeman@google.com39698b12011-11-15 22:26:41 +00001660 if (bufferSize == GDI_ERROR) {
1661 ensure_typeface_accessible(uniqueID);
1662 bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0);
1663 }
vandebo@chromium.orgd6044812011-05-13 03:41:29 +00001664 if (bufferSize != GDI_ERROR) {
1665 stream = new SkMemoryStream(bufferSize);
1666 if (GetFontData(hdc, tables[i], 0, (void*)stream->getMemoryBase(),
1667 bufferSize)) {
1668 break;
1669 } else {
1670 delete stream;
1671 stream = NULL;
1672 }
1673 }
reed@google.comac6b9792011-03-11 15:42:51 +00001674 }
1675
1676 SelectObject(hdc, savefont);
1677 DeleteObject(font);
1678 DeleteDC(hdc);
1679
1680 return stream;
1681}
1682
1683SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) {
1684 return SkNEW_ARGS(SkScalerContext_Windows, (desc));
1685}
1686
1687/** Return the closest matching typeface given either an existing family
1688 (specified by a typeface in that family) or by a familyName, and a
1689 requested style.
bungeman@google.com90d812b2011-10-24 21:25:01 +00001690 1) If familyFace is null, use familyName.
1691 2) If familyName is null, use familyFace.
reed@google.comac6b9792011-03-11 15:42:51 +00001692 3) If both are null, return the default font that best matches style
1693 This MUST not return NULL.
1694 */
1695
1696SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
1697 const char familyName[],
reed@google.comac6b9792011-03-11 15:42:51 +00001698 SkTypeface::Style style) {
reed@google.com59d2f632011-05-02 19:36:59 +00001699 LOGFONT lf;
reed@google.comac6b9792011-03-11 15:42:51 +00001700 if (NULL == familyFace && NULL == familyName) {
reed@google.com59d2f632011-05-02 19:36:59 +00001701 lf = get_default_font();
1702 } else if (familyFace) {
1703 LogFontTypeface* face = (LogFontTypeface*)familyFace;
1704 lf = face->fLogFont;
reed@google.comac6b9792011-03-11 15:42:51 +00001705 } else {
bungeman@google.coma5501992012-05-18 19:06:41 +00001706 logfont_for_name(familyName, lf);
reed@google.comac6b9792011-03-11 15:42:51 +00001707 }
reed@google.com59d2f632011-05-02 19:36:59 +00001708 setStyle(&lf, style);
1709 return SkCreateTypefaceFromLOGFONT(lf);
reed@google.comac6b9792011-03-11 15:42:51 +00001710}
1711
reed@google.comac6b9792011-03-11 15:42:51 +00001712SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
bungeman@google.com515899e2012-10-11 19:03:12 +00001713 SkTypeface* face = NULL;
1714 SkAutoTUnref<SkFILEStream> stream(SkNEW_ARGS(SkFILEStream, (path)));
1715
1716 if (stream->isValid()) {
1717 face = CreateTypefaceFromStream(stream);
1718 }
1719 return face;
reed@google.comac6b9792011-03-11 15:42:51 +00001720}
1721
bungeman@google.comcb1bbb32012-10-12 18:48:35 +00001722void SkFontHost::FilterRec(SkScalerContext::Rec* rec, SkTypeface* typeface) {
reed@google.come8fab012011-07-13 15:25:33 +00001723 unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag |
1724 SkScalerContext::kAutohinting_Flag |
1725 SkScalerContext::kEmbeddedBitmapText_Flag |
1726 SkScalerContext::kEmbolden_Flag |
bungeman@google.comc84547a2012-01-05 20:18:06 +00001727 SkScalerContext::kSubpixelPositioning_Flag |
reed@google.come8fab012011-07-13 15:25:33 +00001728 SkScalerContext::kLCD_BGROrder_Flag |
1729 SkScalerContext::kLCD_Vertical_Flag;
1730 rec->fFlags &= ~flagsWeDontSupport;
1731
reed@google.come8fab012011-07-13 15:25:33 +00001732 SkPaint::Hinting h = rec->getHinting();
reed@google.comda440672011-07-13 18:02:28 +00001733
1734 // I think we can support no-hinting, if we get hires outlines and just
1735 // use skia to rasterize into a gray-scale mask...
1736#if 0
reed@google.come8fab012011-07-13 15:25:33 +00001737 switch (h) {
1738 case SkPaint::kNo_Hinting:
1739 case SkPaint::kSlight_Hinting:
1740 h = SkPaint::kNo_Hinting;
1741 break;
1742 case SkPaint::kNormal_Hinting:
1743 case SkPaint::kFull_Hinting:
1744 h = SkPaint::kNormal_Hinting;
1745 break;
1746 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00001747 SkDEBUGFAIL("unknown hinting");
reed@google.come8fab012011-07-13 15:25:33 +00001748 }
reed@google.comda440672011-07-13 18:02:28 +00001749#else
1750 h = SkPaint::kNormal_Hinting;
1751#endif
reed@google.come8fab012011-07-13 15:25:33 +00001752 rec->setHinting(h);
reed@google.comda440672011-07-13 18:02:28 +00001753
reed@google.com9181aa82011-08-05 14:28:31 +00001754// turn this off since GDI might turn A8 into BW! Need a bigger fix.
1755#if 0
reed@google.comda440672011-07-13 18:02:28 +00001756 // Disable LCD when rotated, since GDI's output is ugly
1757 if (isLCD(*rec) && !isAxisAligned(*rec)) {
1758 rec->fMaskFormat = SkMask::kA8_Format;
1759 }
reed@google.com9181aa82011-08-05 14:28:31 +00001760#endif
reed@google.com754e4eb2011-09-26 13:21:39 +00001761
bungeman@google.comcb1bbb32012-10-12 18:48:35 +00001762 LogFontTypeface* logfontTypeface = static_cast<LogFontTypeface*>(typeface);
1763 if (!logfontTypeface->fCanBeLCD && isLCD(*rec)) {
1764 rec->fMaskFormat = SkMask::kA8_Format;
1765 rec->fFlags &= ~SkScalerContext::kGenA8FromLCD_Flag;
reed@google.com754e4eb2011-09-26 13:21:39 +00001766 }
reed@google.com754e4eb2011-09-26 13:21:39 +00001767}