blob: 46a89cc4cd54e14f30052b83f521eb234d14f61d [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:
reed@google.com59d2f632011-05-02 19:36:59 +0000213 LogFontTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf) :
bungeman@google.come70f7982012-06-01 19:38:19 +0000214 SkTypeface(style, fontID, false), fLogFont(lf), fSerializeAsStream(false) {}
reed@google.comac6b9792011-03-11 15:42:51 +0000215
reed@google.com59d2f632011-05-02 19:36:59 +0000216 LOGFONT fLogFont;
bungeman@google.come70f7982012-06-01 19:38:19 +0000217 bool fSerializeAsStream;
reed@google.comac6b9792011-03-11 15:42:51 +0000218
reed@google.com59d2f632011-05-02 19:36:59 +0000219 static LogFontTypeface* Create(const LOGFONT& lf) {
bungeman@google.com90d812b2011-10-24 21:25:01 +0000220 SkTypeface::Style style = get_style(lf);
reed@google.com59d2f632011-05-02 19:36:59 +0000221 SkFontID fontID = SkTypefaceCache::NewFontID();
222 return new LogFontTypeface(style, fontID, lf);
reed@google.comac6b9792011-03-11 15:42:51 +0000223 }
224};
225
bungeman@google.coma5501992012-05-18 19:06:41 +0000226class FontMemResourceTypeface : public LogFontTypeface {
227public:
228 /**
229 * Takes ownership of fontMemResource.
230 */
231 FontMemResourceTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf, HANDLE fontMemResource) :
bungeman@google.come70f7982012-06-01 19:38:19 +0000232 LogFontTypeface(style, fontID, lf), fFontMemResource(fontMemResource) {
233 fSerializeAsStream = true;
234 }
bungeman@google.coma5501992012-05-18 19:06:41 +0000235
236 HANDLE fFontMemResource;
237
238 /**
239 * The created FontMemResourceTypeface takes ownership of fontMemResource.
240 */
241 static FontMemResourceTypeface* Create(const LOGFONT& lf, HANDLE fontMemResource) {
242 SkTypeface::Style style = get_style(lf);
243 SkFontID fontID = SkTypefaceCache::NewFontID();
244 return new FontMemResourceTypeface(style, fontID, lf, fontMemResource);
245 }
246
247protected:
248 virtual void weak_dispose() const SK_OVERRIDE {
249 RemoveFontMemResourceEx(fFontMemResource);
250 //SkTypefaceCache::Remove(this);
251 INHERITED::weak_dispose();
252 }
253
254private:
255 typedef LogFontTypeface INHERITED;
256};
257
reed@google.comac6b9792011-03-11 15:42:51 +0000258static const LOGFONT& get_default_font() {
259 static LOGFONT gDefaultFont;
reed@google.comac6b9792011-03-11 15:42:51 +0000260 return gDefaultFont;
261}
262
reed@google.com59d2f632011-05-02 19:36:59 +0000263static bool FindByLogFont(SkTypeface* face, SkTypeface::Style requestedStyle, void* ctx) {
bungeman@google.coma5501992012-05-18 19:06:41 +0000264 LogFontTypeface* lface = static_cast<LogFontTypeface*>(face);
reed@google.com59d2f632011-05-02 19:36:59 +0000265 const LOGFONT* lf = reinterpret_cast<const LOGFONT*>(ctx);
reed@google.comac6b9792011-03-11 15:42:51 +0000266
bungeman@google.coma5501992012-05-18 19:06:41 +0000267 return lface &&
268 get_style(lface->fLogFont) == requestedStyle &&
reed@google.com59d2f632011-05-02 19:36:59 +0000269 !memcmp(&lface->fLogFont, lf, sizeof(LOGFONT));
270}
271
272/**
273 * This guy is public. It first searches the cache, and if a match is not found,
274 * it creates a new face.
275 */
276SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT& origLF) {
277 LOGFONT lf = origLF;
278 make_canonical(&lf);
bungeman@google.comee51d1a2012-02-16 12:40:48 +0000279 SkTypeface* face = SkTypefaceCache::FindByProcAndRef(FindByLogFont, &lf);
280 if (NULL == face) {
reed@google.com59d2f632011-05-02 19:36:59 +0000281 face = LogFontTypeface::Create(lf);
bungeman@google.com90d812b2011-10-24 21:25:01 +0000282 SkTypefaceCache::Add(face, get_style(lf));
reed@google.com59d2f632011-05-02 19:36:59 +0000283 }
284 return face;
reed@google.comac6b9792011-03-11 15:42:51 +0000285}
286
reed@google.comdb77a6a2011-07-19 19:08:33 +0000287/**
bungeman@google.coma5501992012-05-18 19:06:41 +0000288 * The created SkTypeface takes ownership of fontMemResource.
289 */
290SkTypeface* SkCreateFontMemResourceTypefaceFromLOGFONT(const LOGFONT& origLF, HANDLE fontMemResource) {
291 LOGFONT lf = origLF;
292 make_canonical(&lf);
293 FontMemResourceTypeface* face = FontMemResourceTypeface::Create(lf, fontMemResource);
294 SkTypefaceCache::Add(face, get_style(lf), false);
295 return face;
296}
297
298/**
reed@google.comdb77a6a2011-07-19 19:08:33 +0000299 * This guy is public
300 */
301void SkLOGFONTFromTypeface(const SkTypeface* face, LOGFONT* lf) {
302 if (NULL == face) {
303 *lf = get_default_font();
304 } else {
bungeman@google.coma5501992012-05-18 19:06:41 +0000305 *lf = static_cast<const LogFontTypeface*>(face)->fLogFont;
reed@google.comdb77a6a2011-07-19 19:08:33 +0000306 }
307}
308
reed@google.com7d26c592011-06-13 13:01:10 +0000309SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
reed@google.comac6b9792011-03-11 15:42:51 +0000310 // Zero means that we don't have any fallback fonts for this fontID.
311 // This function is implemented on Android, but doesn't have much
312 // meaning here.
313 return 0;
314}
315
bungeman@google.com39698b12011-11-15 22:26:41 +0000316static void ensure_typeface_accessible(SkFontID fontID) {
bungeman@google.coma5501992012-05-18 19:06:41 +0000317 LogFontTypeface* face = static_cast<LogFontTypeface*>(SkTypefaceCache::FindByID(fontID));
bungeman@google.comee51d1a2012-02-16 12:40:48 +0000318 if (face) {
319 SkFontHost::EnsureTypefaceAccessible(*face);
320 }
bungeman@google.com39698b12011-11-15 22:26:41 +0000321}
322
reed@google.com59d2f632011-05-02 19:36:59 +0000323static void GetLogFontByID(SkFontID fontID, LOGFONT* lf) {
bungeman@google.coma5501992012-05-18 19:06:41 +0000324 LogFontTypeface* face = static_cast<LogFontTypeface*>(SkTypefaceCache::FindByID(fontID));
reed@google.com59d2f632011-05-02 19:36:59 +0000325 if (face) {
326 *lf = face->fLogFont;
327 } else {
328 sk_bzero(lf, sizeof(LOGFONT));
329 }
330}
331
vandebo@chromium.org6744d492011-05-09 18:13:47 +0000332// Construct Glyph to Unicode table.
333// Unicode code points that require conjugate pairs in utf16 are not
334// supported.
335// TODO(arthurhsu): Add support for conjugate pairs. It looks like that may
336// require parsing the TTF cmap table (platform 4, encoding 12) directly instead
337// of calling GetFontUnicodeRange().
338static void populate_glyph_to_unicode(HDC fontHdc, const unsigned glyphCount,
339 SkTDArray<SkUnichar>* glyphToUnicode) {
340 DWORD glyphSetBufferSize = GetFontUnicodeRanges(fontHdc, NULL);
341 if (!glyphSetBufferSize) {
342 return;
343 }
344
345 SkAutoTDeleteArray<BYTE> glyphSetBuffer(new BYTE[glyphSetBufferSize]);
346 GLYPHSET* glyphSet =
347 reinterpret_cast<LPGLYPHSET>(glyphSetBuffer.get());
348 if (GetFontUnicodeRanges(fontHdc, glyphSet) != glyphSetBufferSize) {
349 return;
350 }
351
352 glyphToUnicode->setCount(glyphCount);
353 memset(glyphToUnicode->begin(), 0, glyphCount * sizeof(SkUnichar));
354 for (DWORD i = 0; i < glyphSet->cRanges; ++i) {
355 // There is no guarantee that within a Unicode range, the corresponding
356 // glyph id in a font file are continuous. So, even if we have ranges,
357 // we can't just use the first and last entry of the range to compute
358 // result. We need to enumerate them one by one.
359 int count = glyphSet->ranges[i].cGlyphs;
360 SkAutoTArray<WCHAR> chars(count + 1);
361 chars[count] = 0; // termintate string
362 SkAutoTArray<WORD> glyph(count);
363 for (USHORT j = 0; j < count; ++j) {
364 chars[j] = glyphSet->ranges[i].wcLow + j;
365 }
366 GetGlyphIndicesW(fontHdc, chars.get(), count, glyph.get(),
367 GGI_MARK_NONEXISTING_GLYPHS);
368 // If the glyph ID is valid, and the glyph is not mapped, then we will
369 // fill in the char id into the vector. If the glyph is mapped already,
370 // skip it.
371 // TODO(arthurhsu): better improve this. e.g. Get all used char ids from
372 // font cache, then generate this mapping table from there. It's
373 // unlikely to have collisions since glyph reuse happens mostly for
374 // different Unicode pages.
375 for (USHORT j = 0; j < count; ++j) {
376 if (glyph[j] != 0xffff && glyph[j] < glyphCount &&
377 (*glyphToUnicode)[glyph[j]] == 0) {
378 (*glyphToUnicode)[glyph[j]] = chars[j];
379 }
380 }
381 }
382}
383
reed@google.com99edd432011-09-09 14:59:59 +0000384//////////////////////////////////////////////////////////////////////////////////////
385
386static int alignTo32(int n) {
387 return (n + 31) & ~31;
388}
389
390struct MyBitmapInfo : public BITMAPINFO {
391 RGBQUAD fMoreSpaceForColors[1];
392};
393
394class HDCOffscreen {
395public:
396 HDCOffscreen() {
397 fFont = 0;
398 fDC = 0;
399 fBM = 0;
400 fBits = NULL;
401 fWidth = fHeight = 0;
402 fIsBW = false;
403 }
404
405 ~HDCOffscreen() {
406 if (fDC) {
407 DeleteDC(fDC);
408 }
409 if (fBM) {
410 DeleteObject(fBM);
411 }
412 }
413
414 void init(HFONT font, const XFORM& xform) {
415 fFont = font;
416 fXform = xform;
417 }
418
bungeman@google.com97efada2012-07-30 20:40:50 +0000419 const void* draw(const SkGlyph&, bool isBW, size_t* srcRBPtr);
reed@google.com99edd432011-09-09 14:59:59 +0000420
421private:
422 HDC fDC;
423 HBITMAP fBM;
424 HFONT fFont;
425 XFORM fXform;
426 void* fBits; // points into fBM
427 int fWidth;
428 int fHeight;
429 bool fIsBW;
reed@google.com754e4eb2011-09-26 13:21:39 +0000430
431 enum {
432 // will always trigger us to reset the color, since we
reed@google.com6f5df482011-09-28 20:33:24 +0000433 // should only store 0 or 0x00FFFFFF or gray (0x007F7F7F)
reed@google.com754e4eb2011-09-26 13:21:39 +0000434 kInvalid_Color = 12345
435 };
reed@google.com99edd432011-09-09 14:59:59 +0000436};
437
reed@google.com754e4eb2011-09-26 13:21:39 +0000438const void* HDCOffscreen::draw(const SkGlyph& glyph, bool isBW,
bungeman@google.com97efada2012-07-30 20:40:50 +0000439 size_t* srcRBPtr) {
reed@google.com99edd432011-09-09 14:59:59 +0000440 if (0 == fDC) {
441 fDC = CreateCompatibleDC(0);
442 if (0 == fDC) {
443 return NULL;
444 }
445 SetGraphicsMode(fDC, GM_ADVANCED);
446 SetBkMode(fDC, TRANSPARENT);
447 SetTextAlign(fDC, TA_LEFT | TA_BASELINE);
448 SelectObject(fDC, fFont);
bungeman@google.com97efada2012-07-30 20:40:50 +0000449
450 COLORREF color = 0x00FFFFFF;
451 COLORREF prev = SetTextColor(fDC, color);
452 SkASSERT(prev != CLR_INVALID);
reed@google.com99edd432011-09-09 14:59:59 +0000453 }
454
455 if (fBM && (fIsBW != isBW || fWidth < glyph.fWidth || fHeight < glyph.fHeight)) {
456 DeleteObject(fBM);
457 fBM = 0;
458 }
reed@google.com754e4eb2011-09-26 13:21:39 +0000459 fIsBW = isBW;
reed@google.com99edd432011-09-09 14:59:59 +0000460
reed@google.com99edd432011-09-09 14:59:59 +0000461 fWidth = SkMax32(fWidth, glyph.fWidth);
462 fHeight = SkMax32(fHeight, glyph.fHeight);
463
464 int biWidth = isBW ? alignTo32(fWidth) : fWidth;
465
466 if (0 == fBM) {
467 MyBitmapInfo info;
468 sk_bzero(&info, sizeof(info));
469 if (isBW) {
470 RGBQUAD blackQuad = { 0, 0, 0, 0 };
471 RGBQUAD whiteQuad = { 0xFF, 0xFF, 0xFF, 0 };
472 info.bmiColors[0] = blackQuad;
473 info.bmiColors[1] = whiteQuad;
474 }
475 info.bmiHeader.biSize = sizeof(info.bmiHeader);
476 info.bmiHeader.biWidth = biWidth;
477 info.bmiHeader.biHeight = fHeight;
478 info.bmiHeader.biPlanes = 1;
479 info.bmiHeader.biBitCount = isBW ? 1 : 32;
480 info.bmiHeader.biCompression = BI_RGB;
481 if (isBW) {
482 info.bmiHeader.biClrUsed = 2;
483 }
484 fBM = CreateDIBSection(fDC, &info, DIB_RGB_COLORS, &fBits, 0, 0);
485 if (0 == fBM) {
486 return NULL;
487 }
488 SelectObject(fDC, fBM);
489 }
490
491 // erase
492 size_t srcRB = isBW ? (biWidth >> 3) : (fWidth << 2);
493 size_t size = fHeight * srcRB;
bungeman@google.com97efada2012-07-30 20:40:50 +0000494 memset(fBits, 0, size);
reed@google.com99edd432011-09-09 14:59:59 +0000495
496 XFORM xform = fXform;
497 xform.eDx = (float)-glyph.fLeft;
498 xform.eDy = (float)-glyph.fTop;
499 SetWorldTransform(fDC, &xform);
500
501 uint16_t glyphID = glyph.getGlyphID();
bungeman@google.com39698b12011-11-15 22:26:41 +0000502 BOOL ret = ExtTextOutW(fDC, 0, 0, ETO_GLYPH_INDEX, NULL, reinterpret_cast<LPCWSTR>(&glyphID), 1, NULL);
reed@google.com99edd432011-09-09 14:59:59 +0000503 GdiFlush();
bungeman@google.com39698b12011-11-15 22:26:41 +0000504 if (0 == ret) {
505 return NULL;
506 }
reed@google.com99edd432011-09-09 14:59:59 +0000507 *srcRBPtr = srcRB;
508 // offset to the start of the image
509 return (const char*)fBits + (fHeight - glyph.fHeight) * srcRB;
510}
511
reed@google.comb8a5c612012-06-13 20:01:44 +0000512//////////////////////////////////////////////////////////////////////////////
reed@google.com59d2f632011-05-02 19:36:59 +0000513
reed@google.comac6b9792011-03-11 15:42:51 +0000514class SkScalerContext_Windows : public SkScalerContext {
515public:
516 SkScalerContext_Windows(const SkDescriptor* desc);
517 virtual ~SkScalerContext_Windows();
518
519protected:
bungeman@google.com97efada2012-07-30 20:40:50 +0000520 virtual unsigned generateGlyphCount() SK_OVERRIDE;
521 virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE;
522 virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE;
523 virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE;
524 virtual void generateImage(const SkGlyph& glyph, SkMaskGamma::PreBlend* maskPreBlend) SK_OVERRIDE;
525 virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE;
526 virtual void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY) SK_OVERRIDE;
reed@google.com99edd432011-09-09 14:59:59 +0000527
reed@google.comac6b9792011-03-11 15:42:51 +0000528private:
reed@google.com99edd432011-09-09 14:59:59 +0000529 HDCOffscreen fOffscreen;
ctguil@chromium.org5aa937b2011-08-04 01:01:24 +0000530 SkScalar fScale; // to get from canonical size to real size
reed@google.comac6b9792011-03-11 15:42:51 +0000531 MAT2 fMat22;
532 XFORM fXform;
533 HDC fDDC;
534 HFONT fSavefont;
535 HFONT fFont;
536 SCRIPT_CACHE fSC;
537 int fGlyphCount;
reed@google.com1dd17a12011-05-17 14:04:41 +0000538
reed@google.comb8a5c612012-06-13 20:01:44 +0000539 /**
540 * Some fonts need extra pixels added to avoid clipping, as the bounds
541 * returned by getOutlineMetrics does not match what GDI draws. Since
542 * this costs more RAM and therefore slower blits, we have a table to
543 * only do this for known "bad" fonts.
544 */
reed@google.com81275392012-06-18 14:08:56 +0000545 SkIRect fOutset;
reed@google.comb8a5c612012-06-13 20:01:44 +0000546
reed@google.com1dd17a12011-05-17 14:04:41 +0000547 HFONT fHiResFont;
548 MAT2 fMat22Identity;
549 SkMatrix fHiResMatrix;
bungeman@google.coma0319f62012-04-18 15:40:50 +0000550 enum Type {
551 kTrueType_Type, kBitmap_Type,
552 } fType;
553 TEXTMETRIC fTM;
reed@google.comac6b9792011-03-11 15:42:51 +0000554};
555
556static float mul2float(SkScalar a, SkScalar b) {
557 return SkScalarToFloat(SkScalarMul(a, b));
558}
559
560static FIXED float2FIXED(float x) {
561 return SkFixedToFIXED(SkFloatToFixed(x));
562}
563
digit@google.com1771cbf2012-01-26 21:26:40 +0000564SK_DECLARE_STATIC_MUTEX(gFTMutex);
reed@google.com59d2f632011-05-02 19:36:59 +0000565
reed@google.com1dd17a12011-05-17 14:04:41 +0000566#define HIRES_TEXTSIZE 2048
567#define HIRES_SHIFT 11
568static inline SkFixed HiResToFixed(int value) {
569 return value << (16 - HIRES_SHIFT);
570}
571
572static bool needHiResMetrics(const SkScalar mat[2][2]) {
573 return mat[1][0] || mat[0][1];
574}
575
reed@google.com82a34d82011-07-26 19:33:08 +0000576static BYTE compute_quality(const SkScalerContext::Rec& rec) {
577 switch (rec.fMaskFormat) {
578 case SkMask::kBW_Format:
579 return NONANTIALIASED_QUALITY;
580 case SkMask::kLCD16_Format:
581 case SkMask::kLCD32_Format:
582 return CLEARTYPE_QUALITY;
583 default:
reed@google.com8351aab2012-01-18 17:06:35 +0000584 if (rec.fFlags & SkScalerContext::kGenA8FromLCD_Flag) {
585 return CLEARTYPE_QUALITY;
586 } else {
587 return ANTIALIASED_QUALITY;
588 }
reed@google.com82a34d82011-07-26 19:33:08 +0000589 }
590}
591
reed@google.comac6b9792011-03-11 15:42:51 +0000592SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc)
593 : SkScalerContext(desc), fDDC(0), fFont(0), fSavefont(0), fSC(0)
594 , fGlyphCount(-1) {
595 SkAutoMutexAcquire ac(gFTMutex);
596
reed@google.comac6b9792011-03-11 15:42:51 +0000597 fDDC = ::CreateCompatibleDC(NULL);
reed@google.com1dd17a12011-05-17 14:04:41 +0000598 SetGraphicsMode(fDDC, GM_ADVANCED);
reed@google.comac6b9792011-03-11 15:42:51 +0000599 SetBkMode(fDDC, TRANSPARENT);
600
601 // Scaling by the DPI is inconsistent with how Skia draws elsewhere
602 //SkScalar height = -(fRec.fTextSize * GetDeviceCaps(ddc, LOGPIXELSY) / 72);
reed@google.com59d2f632011-05-02 19:36:59 +0000603 LOGFONT lf;
604 GetLogFontByID(fRec.fFontID, &lf);
reed@google.comac6b9792011-03-11 15:42:51 +0000605 lf.lfHeight = -gCanonicalTextSize;
reed@google.com82a34d82011-07-26 19:33:08 +0000606 lf.lfQuality = compute_quality(fRec);
reed@google.comac6b9792011-03-11 15:42:51 +0000607 fFont = CreateFontIndirect(&lf);
reed@google.com1dd17a12011-05-17 14:04:41 +0000608
reed@google.com81275392012-06-18 14:08:56 +0000609 if (!compute_bounds_outset(lf, &fOutset)) {
610 fOutset.setEmpty();
611 }
reed@google.comb8a5c612012-06-13 20:01:44 +0000612
reed@google.com1dd17a12011-05-17 14:04:41 +0000613 // if we're rotated, or want fractional widths, create a hires font
614 fHiResFont = 0;
bungeman@google.comc84547a2012-01-05 20:18:06 +0000615 if (needHiResMetrics(fRec.fPost2x2)) {
reed@google.com1dd17a12011-05-17 14:04:41 +0000616 lf.lfHeight = -HIRES_TEXTSIZE;
617 fHiResFont = CreateFontIndirect(&lf);
618
619 fMat22Identity.eM11 = fMat22Identity.eM22 = SkFixedToFIXED(SK_Fixed1);
620 fMat22Identity.eM12 = fMat22Identity.eM21 = SkFixedToFIXED(0);
621
622 // construct a matrix to go from HIRES logical units to our device units
623 fRec.getSingleMatrix(&fHiResMatrix);
624 SkScalar scale = SkScalarInvert(SkIntToScalar(HIRES_TEXTSIZE));
625 fHiResMatrix.preScale(scale, scale);
626 }
reed@google.comac6b9792011-03-11 15:42:51 +0000627 fSavefont = (HFONT)SelectObject(fDDC, fFont);
reed@google.coma767fa02011-08-05 21:40:26 +0000628
bungeman@google.coma0319f62012-04-18 15:40:50 +0000629 if (0 == GetTextMetrics(fDDC, &fTM)) {
630 ensure_typeface_accessible(fRec.fFontID);
631 if (0 == GetTextMetrics(fDDC, &fTM)) {
632 fTM.tmPitchAndFamily = TMPF_TRUETYPE;
633 }
634 }
635 // Used a logfont on a memory context, should never get a device font.
bungeman@google.com90b7e382012-04-20 15:26:28 +0000636 // Therefore all TMPF_DEVICE will be PostScript fonts.
637
638 // If TMPF_VECTOR is set, one of TMPF_TRUETYPE or TMPF_DEVICE must be set,
639 // otherwise we have a vector FON, which we don't support.
640 // This was determined by testing with Type1 PFM/PFB and OpenTypeCFF OTF,
641 // as well as looking at Wine bugs and sources.
642 SkASSERT(!(fTM.tmPitchAndFamily & TMPF_VECTOR) ||
643 (fTM.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_DEVICE)));
644
645 if (fTM.tmPitchAndFamily & TMPF_VECTOR) {
bungeman@google.coma0319f62012-04-18 15:40:50 +0000646 // Truetype or PostScript.
647 // Stroked FON also gets here (TMPF_VECTOR), but we don't handle it.
648 fType = SkScalerContext_Windows::kTrueType_Type;
649 fScale = fRec.fTextSize / gCanonicalTextSize;
650
651 fXform.eM11 = mul2float(fScale, fRec.fPost2x2[0][0]);
652 fXform.eM12 = mul2float(fScale, fRec.fPost2x2[1][0]);
653 fXform.eM21 = mul2float(fScale, fRec.fPost2x2[0][1]);
654 fXform.eM22 = mul2float(fScale, fRec.fPost2x2[1][1]);
655 fXform.eDx = 0;
656 fXform.eDy = 0;
657
658 fMat22.eM11 = float2FIXED(fXform.eM11);
659 fMat22.eM12 = float2FIXED(fXform.eM12);
660 fMat22.eM21 = float2FIXED(-fXform.eM21);
661 fMat22.eM22 = float2FIXED(-fXform.eM22);
662
663 if (needToRenderWithSkia(fRec)) {
664 this->forceGenerateImageFromPath();
665 }
666
667 } else {
668 // Assume bitmap
669 fType = SkScalerContext_Windows::kBitmap_Type;
670 fScale = SK_Scalar1;
671
672 fXform.eM11 = 1.0f;
673 fXform.eM12 = 0.0f;
674 fXform.eM21 = 0.0f;
675 fXform.eM22 = 1.0f;
676 fXform.eDx = 0.0f;
677 fXform.eDy = 0.0f;
678
679 fMat22.eM11 = SkScalarToFIXED(fRec.fPost2x2[0][0]);
680 fMat22.eM12 = SkScalarToFIXED(fRec.fPost2x2[1][0]);
681 fMat22.eM21 = SkScalarToFIXED(-fRec.fPost2x2[0][1]);
682 fMat22.eM22 = SkScalarToFIXED(-fRec.fPost2x2[1][1]);
683
684 lf.lfHeight = -SkScalarCeilToInt(fRec.fTextSize);
685 HFONT bitmapFont = CreateFontIndirect(&lf);
686 SelectObject(fDDC, bitmapFont);
687 ::DeleteObject(fFont);
688 fFont = bitmapFont;
689
690 if (0 == GetTextMetrics(fDDC, &fTM)) {
691 ensure_typeface_accessible(fRec.fFontID);
692 //if the following fails, we'll just draw at gCanonicalTextSize.
693 GetTextMetrics(fDDC, &fTM);
694 }
reed@google.coma767fa02011-08-05 21:40:26 +0000695 }
reed@google.com99edd432011-09-09 14:59:59 +0000696
697 fOffscreen.init(fFont, fXform);
reed@google.comac6b9792011-03-11 15:42:51 +0000698}
699
700SkScalerContext_Windows::~SkScalerContext_Windows() {
701 if (fDDC) {
702 ::SelectObject(fDDC, fSavefont);
703 ::DeleteDC(fDDC);
704 }
705 if (fFont) {
706 ::DeleteObject(fFont);
707 }
reed@google.com1dd17a12011-05-17 14:04:41 +0000708 if (fHiResFont) {
709 ::DeleteObject(fHiResFont);
710 }
reed@google.comac6b9792011-03-11 15:42:51 +0000711 if (fSC) {
712 ::ScriptFreeCache(&fSC);
713 }
714}
715
716unsigned SkScalerContext_Windows::generateGlyphCount() {
717 if (fGlyphCount < 0) {
bungeman@google.coma0319f62012-04-18 15:40:50 +0000718 if (fType == SkScalerContext_Windows::kBitmap_Type) {
719 return fTM.tmLastChar;
720 }
721 fGlyphCount = calculateOutlineGlyphCount(fDDC);
reed@google.comac6b9792011-03-11 15:42:51 +0000722 }
723 return fGlyphCount;
724}
725
726uint16_t SkScalerContext_Windows::generateCharToGlyph(SkUnichar uni) {
727 uint16_t index = 0;
728 WCHAR c[2];
729 // TODO(ctguil): Support characters that generate more than one glyph.
730 if (SkUTF16_FromUnichar(uni, (uint16_t*)c) == 1) {
731 // Type1 fonts fail with uniscribe API. Use GetGlyphIndices for plane 0.
732 SkAssertResult(GetGlyphIndicesW(fDDC, c, 1, &index, 0));
733 } else {
734 // Use uniscribe to detemine glyph index for non-BMP characters.
735 // Need to add extra item to SCRIPT_ITEM to work around a bug in older
736 // windows versions. https://bugzilla.mozilla.org/show_bug.cgi?id=366643
737 SCRIPT_ITEM si[2 + 1];
738 int items;
739 SkAssertResult(
740 SUCCEEDED(ScriptItemize(c, 2, 2, NULL, NULL, si, &items)));
741
742 WORD log[2];
743 SCRIPT_VISATTR vsa;
744 int glyphs;
745 SkAssertResult(SUCCEEDED(ScriptShape(
746 fDDC, &fSC, c, 2, 1, &si[0].a, &index, log, &vsa, &glyphs)));
747 }
748 return index;
749}
750
751void SkScalerContext_Windows::generateAdvance(SkGlyph* glyph) {
752 this->generateMetrics(glyph);
753}
754
755void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) {
756
757 SkASSERT(fDDC);
758
bungeman@google.coma0319f62012-04-18 15:40:50 +0000759 if (fType == SkScalerContext_Windows::kBitmap_Type) {
760 SIZE size;
761 WORD glyphs = glyph->getGlyphID(0);
762 if (0 == GetTextExtentPointI(fDDC, &glyphs, 1, &size)) {
763 glyph->fWidth = SkToS16(fTM.tmMaxCharWidth);
764 } else {
765 glyph->fWidth = SkToS16(size.cx);
766 }
767 glyph->fHeight = SkToS16(size.cy);
768
769 glyph->fTop = SkToS16(-fTM.tmAscent);
770 glyph->fLeft = SkToS16(0);
771 glyph->fAdvanceX = SkIntToFixed(glyph->fWidth);
772 glyph->fAdvanceY = 0;
773
774 //Apply matrix to values.
775 glyph->fAdvanceY = SkFixedMul(SkFIXEDToFixed(fMat22.eM21), glyph->fAdvanceX);
776 glyph->fAdvanceX = SkFixedMul(SkFIXEDToFixed(fMat22.eM11), glyph->fAdvanceX);
777
reed@google.com81275392012-06-18 14:08:56 +0000778 apply_outset(glyph, fOutset);
bungeman@google.coma0319f62012-04-18 15:40:50 +0000779 return;
780 }
781
reed@google.comac6b9792011-03-11 15:42:51 +0000782 GLYPHMETRICS gm;
reed@google.com1dd17a12011-05-17 14:04:41 +0000783 sk_bzero(&gm, sizeof(gm));
reed@google.comac6b9792011-03-11 15:42:51 +0000784
785 glyph->fRsbDelta = 0;
786 glyph->fLsbDelta = 0;
787
788 // Note: need to use GGO_GRAY8_BITMAP instead of GGO_METRICS because GGO_METRICS returns a smaller
789 // BlackBlox; we need the bigger one in case we need the image. fAdvance is the same.
790 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 +0000791 if (GDI_ERROR == ret) {
792 ensure_typeface_accessible(fRec.fFontID);
793 ret = GetGlyphOutlineW(fDDC, glyph->getGlyphID(0), GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
794 }
reed@google.comac6b9792011-03-11 15:42:51 +0000795
796 if (GDI_ERROR != ret) {
797 if (ret == 0) {
798 // for white space, ret is zero and gmBlackBoxX, gmBlackBoxY are 1 incorrectly!
799 gm.gmBlackBoxX = gm.gmBlackBoxY = 0;
800 }
801 glyph->fWidth = gm.gmBlackBoxX;
802 glyph->fHeight = gm.gmBlackBoxY;
803 glyph->fTop = SkToS16(gm.gmptGlyphOrigin.y - gm.gmBlackBoxY);
804 glyph->fLeft = SkToS16(gm.gmptGlyphOrigin.x);
805 glyph->fAdvanceX = SkIntToFixed(gm.gmCellIncX);
806 glyph->fAdvanceY = -SkIntToFixed(gm.gmCellIncY);
807
reed@google.comf8cead52011-09-02 20:08:11 +0000808 // we outset in all dimensions, since the image may bleed outside
reed@google.comac6b9792011-03-11 15:42:51 +0000809 // of the computed bounds returned by GetGlyphOutline.
810 // This was deduced by trial and error for small text (e.g. 8pt), so there
811 // maybe a more precise way to make this adjustment...
reed@google.comf8cead52011-09-02 20:08:11 +0000812 //
813 // This test shows us clipping the tops of some of the CJK fonts unless we
814 // increase the top of the box by 2, hence the height by 4. This seems to
815 // correspond to an embedded bitmap font, but not sure.
816 // LayoutTests/fast/text/backslash-to-yen-sign-euc.html
817 //
reed@google.com5e2df642011-09-21 18:42:09 +0000818 if (glyph->fWidth) { // don't outset an empty glyph
819 glyph->fWidth += 4;
820 glyph->fHeight += 4;
821 glyph->fTop -= 2;
822 glyph->fLeft -= 2;
reed@google.comb8a5c612012-06-13 20:01:44 +0000823
reed@google.com81275392012-06-18 14:08:56 +0000824 apply_outset(glyph, fOutset);
reed@google.com5e2df642011-09-21 18:42:09 +0000825 }
reed@google.com1dd17a12011-05-17 14:04:41 +0000826
827 if (fHiResFont) {
828 SelectObject(fDDC, fHiResFont);
829 sk_bzero(&gm, sizeof(gm));
830 ret = GetGlyphOutlineW(fDDC, glyph->getGlyphID(0), GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22Identity);
831 if (GDI_ERROR != ret) {
832 SkPoint advance;
833 fHiResMatrix.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance);
834 glyph->fAdvanceX = SkScalarToFixed(advance.fX);
835 glyph->fAdvanceY = SkScalarToFixed(advance.fY);
836 }
837 SelectObject(fDDC, fFont);
838 }
reed@google.comac6b9792011-03-11 15:42:51 +0000839 } else {
bungeman@google.coma0319f62012-04-18 15:40:50 +0000840 glyph->zeroMetrics();
reed@google.comac6b9792011-03-11 15:42:51 +0000841 }
842}
843
844void SkScalerContext_Windows::generateFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my) {
845// Note: This code was borrowed from generateLineHeight, which has a note
846// stating that it may be incorrect.
847 if (!(mx || my))
848 return;
849
850 SkASSERT(fDDC);
851
bungeman@google.coma0319f62012-04-18 15:40:50 +0000852 if (fType == SkScalerContext_Windows::kBitmap_Type) {
853 if (mx) {
854 mx->fTop = SkIntToScalar(-fTM.tmAscent);
855 mx->fAscent = SkIntToScalar(-fTM.tmAscent);
856 mx->fDescent = -SkIntToScalar(fTM.tmDescent);
857 mx->fBottom = SkIntToScalar(fTM.tmDescent);
858 mx->fLeading = SkIntToScalar(fTM.tmInternalLeading
859 + fTM.tmExternalLeading);
860 }
861
862 if (my) {
863 my->fTop = SkIntToScalar(-fTM.tmAscent);
864 my->fAscent = SkIntToScalar(-fTM.tmAscent);
865 my->fDescent = SkIntToScalar(-fTM.tmDescent);
866 my->fBottom = SkIntToScalar(fTM.tmDescent);
867 my->fLeading = SkIntToScalar(fTM.tmInternalLeading
868 + fTM.tmExternalLeading);
869 }
870 return;
871 }
872
reed@google.comac6b9792011-03-11 15:42:51 +0000873 OUTLINETEXTMETRIC otm;
874
875 uint32_t ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
bungeman@google.com39698b12011-11-15 22:26:41 +0000876 if (GDI_ERROR == ret) {
877 ensure_typeface_accessible(fRec.fFontID);
878 ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
879 }
reed@google.comac6b9792011-03-11 15:42:51 +0000880 if (sizeof(otm) != ret) {
bungeman@google.coma0319f62012-04-18 15:40:50 +0000881 return;
reed@google.comac6b9792011-03-11 15:42:51 +0000882 }
883
884 if (mx) {
885 mx->fTop = -fScale * otm.otmTextMetrics.tmAscent;
ctguil@chromium.org5aa937b2011-08-04 01:01:24 +0000886 mx->fAscent = -fScale * otm.otmAscent;
887 mx->fDescent = -fScale * otm.otmDescent;
888 mx->fBottom = fScale * otm.otmTextMetrics.tmDescent;
889 mx->fLeading = fScale * (otm.otmTextMetrics.tmInternalLeading
890 + otm.otmTextMetrics.tmExternalLeading);
reed@google.comac6b9792011-03-11 15:42:51 +0000891 }
892
893 if (my) {
ctguil@chromium.org5aa937b2011-08-04 01:01:24 +0000894 my->fTop = -fScale * otm.otmTextMetrics.tmAscent;
895 my->fAscent = -fScale * otm.otmAscent;
896 my->fDescent = -fScale * otm.otmDescent;
897 my->fBottom = fScale * otm.otmTextMetrics.tmDescent;
898 my->fLeading = fScale * (otm.otmTextMetrics.tmInternalLeading
899 + otm.otmTextMetrics.tmExternalLeading);
reed@google.comac6b9792011-03-11 15:42:51 +0000900 }
901}
902
reed@google.com7430a332011-10-03 14:37:38 +0000903////////////////////////////////////////////////////////////////////////////////////////
904
905static void build_power_table(uint8_t table[], float ee) {
906 for (int i = 0; i < 256; i++) {
907 float x = i / 255.f;
bungeman@google.com97efada2012-07-30 20:40:50 +0000908 x = sk_float_pow(x, ee);
reed@google.com7430a332011-10-03 14:37:38 +0000909 int xx = SkScalarRound(SkFloatToScalar(x * 255));
910 table[i] = SkToU8(xx);
911 }
912}
913
bungeman@google.com97efada2012-07-30 20:40:50 +0000914/**
915 * This will invert the gamma applied by GDI (gray-scale antialiased), so we
916 * can get linear values.
917 *
918 * GDI grayscale appears to use a hard-coded gamma of 2.3.
919 *
920 * GDI grayscale appears to draw using the black and white rasterizer at four
921 * times the size and then downsamples to compute the coverage mask. As a
922 * result there are only seventeen total grays. This lack of fidelity means
923 * that shifting into other color spaces is imprecise.
924 */
925static const uint8_t* getInverseGammaTableGDI() {
reed@google.com7430a332011-10-03 14:37:38 +0000926 static bool gInited;
bungeman@google.com97efada2012-07-30 20:40:50 +0000927 static uint8_t gTableGdi[256];
928 if (!gInited) {
929 build_power_table(gTableGdi, 2.3f);
930 gInited = true;
931 }
932 return gTableGdi;
933}
934
935/**
936 * This will invert the gamma applied by GDI ClearType, so we can get linear
937 * values.
938 *
939 * GDI ClearType uses SPI_GETFONTSMOOTHINGCONTRAST / 1000 as the gamma value.
940 * If this value is not specified, the default is a gamma of 1.4.
941 */
942static const uint8_t* getInverseGammaTableClearType() {
943 static bool gInited;
944 static uint8_t gTableClearType[256];
reed@google.com7430a332011-10-03 14:37:38 +0000945 if (!gInited) {
946 UINT level = 0;
947 if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &level, 0) || !level) {
948 // can't get the data, so use a default
949 level = 1400;
950 }
bungeman@google.com97efada2012-07-30 20:40:50 +0000951 build_power_table(gTableClearType, level / 1000.0f);
reed@google.com7430a332011-10-03 14:37:38 +0000952 gInited = true;
953 }
bungeman@google.com97efada2012-07-30 20:40:50 +0000954 return gTableClearType;
reed@google.com7430a332011-10-03 14:37:38 +0000955}
956
reed@google.comac6b9792011-03-11 15:42:51 +0000957#include "SkColorPriv.h"
958
bungeman@google.com63853142012-08-01 15:36:46 +0000959//Cannot assume that the input rgb is gray due to possible setting of kGenA8FromLCD_Flag.
bungeman@google.com97efada2012-07-30 20:40:50 +0000960template<bool APPLY_PREBLEND>
961static inline uint8_t rgb_to_a8(SkGdiRGB rgb, const uint8_t* table8) {
bungeman@google.com63853142012-08-01 15:36:46 +0000962 U8CPU r = (rgb >> 16) & 0xFF;
963 U8CPU g = (rgb >> 8) & 0xFF;
964 U8CPU b = (rgb >> 0) & 0xFF;
bungeman@google.com1bfe01d2012-08-28 16:02:42 +0000965 return sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8);
reed@google.com8351aab2012-01-18 17:06:35 +0000966}
967
bungeman@google.com97efada2012-07-30 20:40:50 +0000968template<bool APPLY_PREBLEND>
969static inline uint16_t rgb_to_lcd16(SkGdiRGB rgb, const uint8_t* tableR,
970 const uint8_t* tableG,
971 const uint8_t* tableB) {
972 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
973 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG);
974 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB);
975 return SkPack888ToRGB16(r, g, b);
reed@google.com82a34d82011-07-26 19:33:08 +0000976}
977
bungeman@google.com97efada2012-07-30 20:40:50 +0000978template<bool APPLY_PREBLEND>
979static inline SkPMColor rgb_to_lcd32(SkGdiRGB rgb, const uint8_t* tableR,
980 const uint8_t* tableG,
981 const uint8_t* tableB) {
982 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR);
983 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG);
984 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB);
985 return SkPackARGB32(0xFF, r, g, b);
reed@google.com754e4eb2011-09-26 13:21:39 +0000986}
987
reed@google.com82cff022011-09-22 14:33:40 +0000988// Is this GDI color neither black nor white? If so, we have to keep this
989// image as is, rather than smashing it down to a BW mask.
990//
991// returns int instead of bool, since we don't want/have to pay to convert
992// the zero/non-zero value into a bool
993static int is_not_black_or_white(SkGdiRGB c) {
994 // same as (but faster than)
995 // c &= 0x00FFFFFF;
996 // return 0 == c || 0x00FFFFFF == c;
997 return (c + (c & 1)) & 0x00FFFFFF;
reed@google.com5e2df642011-09-21 18:42:09 +0000998}
999
1000static bool is_rgb_really_bw(const SkGdiRGB* src, int width, int height, int srcRB) {
1001 for (int y = 0; y < height; ++y) {
1002 for (int x = 0; x < width; ++x) {
reed@google.com82cff022011-09-22 14:33:40 +00001003 if (is_not_black_or_white(src[x])) {
reed@google.com5e2df642011-09-21 18:42:09 +00001004 return false;
1005 }
1006 }
reed@google.com6f5df482011-09-28 20:33:24 +00001007 src = SkTAddByteOffset(src, srcRB);
reed@google.com5e2df642011-09-21 18:42:09 +00001008 }
1009 return true;
1010}
1011
bungeman@google.com97efada2012-07-30 20:40:50 +00001012// gdi's bitmap is upside-down, so we reverse dst walking in Y
1013// whenever we copy it into skia's buffer
reed@google.com5e2df642011-09-21 18:42:09 +00001014static void rgb_to_bw(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
bungeman@google.com97efada2012-07-30 20:40:50 +00001015 const SkGlyph& glyph) {
reed@google.com5e2df642011-09-21 18:42:09 +00001016 const int width = glyph.fWidth;
1017 const size_t dstRB = (width + 7) >> 3;
1018 uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1019
1020 int byteCount = width >> 3;
1021 int bitCount = width & 7;
1022
1023 // adjust srcRB to skip the values in our byteCount loop,
1024 // since we increment src locally there
1025 srcRB -= byteCount * 8 * sizeof(SkGdiRGB);
1026
1027 for (int y = 0; y < glyph.fHeight; ++y) {
1028 if (byteCount > 0) {
reed@google.com5e2df642011-09-21 18:42:09 +00001029 for (int i = 0; i < byteCount; ++i) {
reed@google.com7a230142011-09-27 14:07:21 +00001030 unsigned byte = 0;
bungeman@google.com97efada2012-07-30 20:40:50 +00001031 byte |= src[0] & (1 << 7);
1032 byte |= src[1] & (1 << 6);
1033 byte |= src[2] & (1 << 5);
1034 byte |= src[3] & (1 << 4);
1035 byte |= src[4] & (1 << 3);
1036 byte |= src[5] & (1 << 2);
1037 byte |= src[6] & (1 << 1);
1038 byte |= src[7] & (1 << 0);
reed@google.com6a8f14d2011-09-27 12:54:24 +00001039 dst[i] = byte;
reed@google.com5e2df642011-09-21 18:42:09 +00001040 src += 8;
1041 }
1042 }
1043 if (bitCount > 0) {
1044 unsigned byte = 0;
1045 unsigned mask = 0x80;
1046 for (int i = 0; i < bitCount; i++) {
bungeman@google.com97efada2012-07-30 20:40:50 +00001047 byte |= src[i] & mask;
reed@google.com5e2df642011-09-21 18:42:09 +00001048 mask >>= 1;
1049 }
1050 dst[byteCount] = byte;
1051 }
reed@google.com6f5df482011-09-28 20:33:24 +00001052 src = SkTAddByteOffset(src, srcRB);
reed@google.com5e2df642011-09-21 18:42:09 +00001053 dst -= dstRB;
1054 }
1055}
1056
bungeman@google.com97efada2012-07-30 20:40:50 +00001057template<bool APPLY_PREBLEND>
reed@google.com5e2df642011-09-21 18:42:09 +00001058static void rgb_to_a8(const SkGdiRGB* SK_RESTRICT src, size_t srcRB,
bungeman@google.com97efada2012-07-30 20:40:50 +00001059 const SkGlyph& glyph, const uint8_t* table8) {
reed@google.com5e2df642011-09-21 18:42:09 +00001060 const size_t dstRB = glyph.rowBytes();
1061 const int width = glyph.fWidth;
1062 uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1063
1064 for (int y = 0; y < glyph.fHeight; y++) {
1065 for (int i = 0; i < width; i++) {
bungeman@google.com97efada2012-07-30 20:40:50 +00001066 dst[i] = rgb_to_a8<APPLY_PREBLEND>(src[i], table8);
reed@google.com5e2df642011-09-21 18:42:09 +00001067 }
reed@google.com6f5df482011-09-28 20:33:24 +00001068 src = SkTAddByteOffset(src, srcRB);
reed@google.com5e2df642011-09-21 18:42:09 +00001069 dst -= dstRB;
1070 }
1071}
1072
bungeman@google.com97efada2012-07-30 20:40:50 +00001073template<bool APPLY_PREBLEND>
1074static void rgb_to_lcd16(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph,
1075 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
reed@google.com5e2df642011-09-21 18:42:09 +00001076 const size_t dstRB = glyph.rowBytes();
1077 const int width = glyph.fWidth;
1078 uint16_t* SK_RESTRICT dst = (uint16_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1079
1080 for (int y = 0; y < glyph.fHeight; y++) {
1081 for (int i = 0; i < width; i++) {
bungeman@google.com97efada2012-07-30 20:40:50 +00001082 dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(src[i], tableR, tableG, tableB);
reed@google.com5e2df642011-09-21 18:42:09 +00001083 }
reed@google.com6f5df482011-09-28 20:33:24 +00001084 src = SkTAddByteOffset(src, srcRB);
reed@google.com5e2df642011-09-21 18:42:09 +00001085 dst = (uint16_t*)((char*)dst - dstRB);
1086 }
1087}
1088
bungeman@google.com97efada2012-07-30 20:40:50 +00001089template<bool APPLY_PREBLEND>
1090static void rgb_to_lcd32(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph,
1091 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) {
reed@google.com754e4eb2011-09-26 13:21:39 +00001092 const size_t dstRB = glyph.rowBytes();
1093 const int width = glyph.fWidth;
bungeman@google.com97efada2012-07-30 20:40:50 +00001094 uint32_t* SK_RESTRICT dst = (uint32_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
reed@google.com754e4eb2011-09-26 13:21:39 +00001095
1096 for (int y = 0; y < glyph.fHeight; y++) {
1097 for (int i = 0; i < width; i++) {
bungeman@google.com97efada2012-07-30 20:40:50 +00001098 dst[i] = rgb_to_lcd32<APPLY_PREBLEND>(src[i], tableR, tableG, tableB);
reed@google.com754e4eb2011-09-26 13:21:39 +00001099 }
reed@google.com6f5df482011-09-28 20:33:24 +00001100 src = SkTAddByteOffset(src, srcRB);
bungeman@google.com97efada2012-07-30 20:40:50 +00001101 dst = (uint32_t*)((char*)dst - dstRB);
reed@google.com754e4eb2011-09-26 13:21:39 +00001102 }
1103}
1104
reed@google.com6f5df482011-09-28 20:33:24 +00001105static inline unsigned clamp255(unsigned x) {
1106 SkASSERT(x <= 256);
1107 return x - (x >> 8);
1108}
1109
bungeman@google.com97efada2012-07-30 20:40:50 +00001110void SkScalerContext_Windows::generateImage(const SkGlyph& glyph, SkMaskGamma::PreBlend* maskPreBlend) {
1111 SkAutoMutexAcquire ac(gFTMutex);
reed@google.comac6b9792011-03-11 15:42:51 +00001112 SkASSERT(fDDC);
1113
bungeman@google.com97efada2012-07-30 20:40:50 +00001114 //Must be careful not to use these if maskPreBlend == NULL
1115 const uint8_t* tableR = NULL;
1116 const uint8_t* tableG = NULL;
1117 const uint8_t* tableB = NULL;
1118 if (maskPreBlend) {
1119 tableR = maskPreBlend->fR;
1120 tableG = maskPreBlend->fG;
1121 tableB = maskPreBlend->fB;
1122 }
1123
reed@google.com62711172011-05-18 15:08:10 +00001124 const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat;
reed@google.com82a34d82011-07-26 19:33:08 +00001125 const bool isAA = !isLCD(fRec);
reed@google.comac6b9792011-03-11 15:42:51 +00001126
reed@google.com99edd432011-09-09 14:59:59 +00001127 size_t srcRB;
bungeman@google.com97efada2012-07-30 20:40:50 +00001128 const void* bits = fOffscreen.draw(glyph, isBW, &srcRB);
bungeman@google.com39698b12011-11-15 22:26:41 +00001129 if (NULL == bits) {
1130 ensure_typeface_accessible(fRec.fFontID);
bungeman@google.com97efada2012-07-30 20:40:50 +00001131 bits = fOffscreen.draw(glyph, isBW, &srcRB);
bungeman@google.com39698b12011-11-15 22:26:41 +00001132 if (NULL == bits) {
1133 sk_bzero(glyph.fImage, glyph.computeImageSize());
1134 return;
1135 }
reed@google.com82a34d82011-07-26 19:33:08 +00001136 }
reed@google.comac6b9792011-03-11 15:42:51 +00001137
bungeman@google.com97efada2012-07-30 20:40:50 +00001138 if (!isBW) {
bungeman@google.com1bd2d672012-08-13 20:01:51 +00001139 const uint8_t* table;
1140 //The offscreen contains a GDI blit if isAA and kGenA8FromLCD_Flag is not set.
1141 //Otherwise the offscreen contains a ClearType blit.
1142 if (isAA && !(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag)) {
1143 table = getInverseGammaTableGDI();
1144 } else {
1145 table = getInverseGammaTableClearType();
bungeman@google.com97efada2012-07-30 20:40:50 +00001146 }
1147 //Note that the following cannot really be integrated into the
1148 //pre-blend, since we may not be applying the pre-blend; when we aren't
1149 //applying the pre-blend it means that a filter wants linear anyway.
1150 //Other code may also be applying the pre-blend, so we'd need another
1151 //one with this and one without.
reed@google.com6f5df482011-09-28 20:33:24 +00001152 SkGdiRGB* addr = (SkGdiRGB*)bits;
1153 for (int y = 0; y < glyph.fHeight; ++y) {
1154 for (int x = 0; x < glyph.fWidth; ++x) {
1155 int r = (addr[x] >> 16) & 0xFF;
1156 int g = (addr[x] >> 8) & 0xFF;
1157 int b = (addr[x] >> 0) & 0xFF;
reed@google.com7430a332011-10-03 14:37:38 +00001158 addr[x] = (table[r] << 16) | (table[g] << 8) | table[b];
reed@google.com6f5df482011-09-28 20:33:24 +00001159 }
1160 addr = SkTAddByteOffset(addr, srcRB);
1161 }
1162 }
1163
reed@google.com82a34d82011-07-26 19:33:08 +00001164 int width = glyph.fWidth;
1165 size_t dstRB = glyph.rowBytes();
1166 if (isBW) {
1167 const uint8_t* src = (const uint8_t*)bits;
reed@google.com82a34d82011-07-26 19:33:08 +00001168 uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
1169 for (int y = 0; y < glyph.fHeight; y++) {
1170 memcpy(dst, src, dstRB);
1171 src += srcRB;
1172 dst -= dstRB;
reed@google.comac6b9792011-03-11 15:42:51 +00001173 }
reed@google.com82a34d82011-07-26 19:33:08 +00001174 } else if (isAA) {
reed@google.com6f5df482011-09-28 20:33:24 +00001175 // since the caller may require A8 for maskfilters, we can't check for BW
1176 // ... until we have the caller tell us that explicitly
reed@google.com5e2df642011-09-21 18:42:09 +00001177 const SkGdiRGB* src = (const SkGdiRGB*)bits;
bungeman@google.com97efada2012-07-30 20:40:50 +00001178 if (maskPreBlend) {
1179 rgb_to_a8<true>(src, srcRB, glyph, tableG);
1180 } else {
1181 rgb_to_a8<false>(src, srcRB, glyph, tableG);
1182 }
reed@google.com82a34d82011-07-26 19:33:08 +00001183 } else { // LCD16
reed@google.com5e2df642011-09-21 18:42:09 +00001184 const SkGdiRGB* src = (const SkGdiRGB*)bits;
1185 if (is_rgb_really_bw(src, width, glyph.fHeight, srcRB)) {
bungeman@google.com97efada2012-07-30 20:40:50 +00001186 rgb_to_bw(src, srcRB, glyph);
reed@google.com5e2df642011-09-21 18:42:09 +00001187 ((SkGlyph*)&glyph)->fMaskFormat = SkMask::kBW_Format;
1188 } else {
reed@google.com754e4eb2011-09-26 13:21:39 +00001189 if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
bungeman@google.com97efada2012-07-30 20:40:50 +00001190 if (maskPreBlend) {
1191 rgb_to_lcd16<true>(src, srcRB, glyph, tableR, tableG, tableB);
1192 } else {
1193 rgb_to_lcd16<false>(src, srcRB, glyph, tableR, tableG, tableB);
1194 }
reed@google.com754e4eb2011-09-26 13:21:39 +00001195 } else {
1196 SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat);
bungeman@google.com97efada2012-07-30 20:40:50 +00001197 if (maskPreBlend) {
1198 rgb_to_lcd32<true>(src, srcRB, glyph, tableR, tableG, tableB);
1199 } else {
1200 rgb_to_lcd32<false>(src, srcRB, glyph, tableR, tableG, tableB);
1201 }
reed@google.com754e4eb2011-09-26 13:21:39 +00001202 }
reed@google.comac6b9792011-03-11 15:42:51 +00001203 }
1204 }
reed@google.comac6b9792011-03-11 15:42:51 +00001205}
1206
1207void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) {
1208
1209 SkAutoMutexAcquire ac(gFTMutex);
1210
1211 SkASSERT(&glyph && path);
1212 SkASSERT(fDDC);
1213
1214 path->reset();
1215
1216#if 0
1217 char buf[1024];
1218 sprintf(buf, "generatePath: id:%d, w=%d, h=%d, font:%s,fh:%d\n", glyph.fID, glyph.fWidth, glyph.fHeight, lf.lfFaceName, lf.lfHeight);
1219 OutputDebugString(buf);
1220#endif
1221
1222 GLYPHMETRICS gm;
1223 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 +00001224 if (GDI_ERROR == total_size) {
1225 ensure_typeface_accessible(fRec.fFontID);
1226 total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, BUFFERSIZE, glyphbuf, &fMat22);
1227 }
reed@google.comac6b9792011-03-11 15:42:51 +00001228
1229 if (GDI_ERROR != total_size) {
1230
1231 const uint8_t* cur_glyph = glyphbuf;
1232 const uint8_t* end_glyph = glyphbuf + total_size;
1233
1234 while(cur_glyph < end_glyph) {
1235 const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
1236
1237 const uint8_t* end_poly = cur_glyph + th->cb;
1238 const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
1239
1240 path->moveTo(SkFixedToScalar(*(SkFixed*)(&th->pfxStart.x)), SkFixedToScalar(*(SkFixed*)(&th->pfxStart.y)));
1241
1242 while(cur_poly < end_poly) {
1243 const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
1244
1245 if (pc->wType == TT_PRIM_LINE) {
1246 for (uint16_t i = 0; i < pc->cpfx; i++) {
1247 path->lineTo(SkFixedToScalar(*(SkFixed*)(&pc->apfx[i].x)), SkFixedToScalar(*(SkFixed*)(&pc->apfx[i].y)));
1248 }
1249 }
1250
1251 if (pc->wType == TT_PRIM_QSPLINE) {
1252 for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline
1253 POINTFX pnt_b = pc->apfx[u]; // B is always the current point
1254 POINTFX pnt_c = pc->apfx[u+1];
1255
1256 if (u < pc->cpfx - 2) { // If not on last spline, compute C
1257 pnt_c.x = SkFixedToFIXED(SkFixedAve(*(SkFixed*)(&pnt_b.x), *(SkFixed*)(&pnt_c.x)));
1258 pnt_c.y = SkFixedToFIXED(SkFixedAve(*(SkFixed*)(&pnt_b.y), *(SkFixed*)(&pnt_c.y)));
1259 }
1260
1261 path->quadTo(SkFixedToScalar(*(SkFixed*)(&pnt_b.x)), SkFixedToScalar(*(SkFixed*)(&pnt_b.y)), SkFixedToScalar(*(SkFixed*)(&pnt_c.x)), SkFixedToScalar(*(SkFixed*)(&pnt_c.y)));
1262 }
1263 }
1264 cur_poly += sizeof(uint16_t) * 2 + sizeof(POINTFX) * pc->cpfx;
1265 }
1266 cur_glyph += th->cb;
1267 path->close();
1268 }
1269 }
1270 else {
1271 SkASSERT(false);
1272 }
1273 //char buf[1024];
1274 //sprintf(buf, "generatePath: count:%d\n", count);
1275 //OutputDebugString(buf);
1276}
1277
bungeman@google.come70f7982012-06-01 19:38:19 +00001278static void logfont_for_name(const char* familyName, LOGFONT& lf) {
1279 memset(&lf, 0, sizeof(LOGFONT));
1280#ifdef UNICODE
1281 // Get the buffer size needed first.
1282 size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName,
1283 -1, NULL, 0);
1284 // Allocate a buffer (str_len already has terminating null
1285 // accounted for).
1286 wchar_t *wideFamilyName = new wchar_t[str_len];
1287 // Now actually convert the string.
1288 ::MultiByteToWideChar(CP_UTF8, 0, familyName, -1,
1289 wideFamilyName, str_len);
1290 ::wcsncpy(lf.lfFaceName, wideFamilyName, LF_FACESIZE - 1);
1291 delete [] wideFamilyName;
1292 lf.lfFaceName[LF_FACESIZE-1] = L'\0';
1293#else
1294 ::strncpy(lf.lfFaceName, familyName, LF_FACESIZE - 1);
1295 lf.lfFaceName[LF_FACESIZE - 1] = '\0';
1296#endif
1297}
1298
1299static void logfont_to_name(const LOGFONT& lf, SkString* s) {
1300#ifdef UNICODE
1301 // Get the buffer size needed first.
1302 size_t str_len = WideCharToMultiByte(CP_UTF8, 0, lf.lfFaceName, -1, NULL,
1303 0, NULL, NULL);
1304 // Allocate a buffer (str_len already has terminating null accounted for).
1305 s->resize(str_len);
1306 // Now actually convert the string.
1307 WideCharToMultiByte(CP_UTF8, 0, lf.lfFaceName, -1,
1308 s->writable_str(), str_len,
1309 NULL, NULL);
1310#else
1311 s->set(lf.lfFaceName);
1312#endif
1313}
1314
1315void SkFontHost::Serialize(const SkTypeface* rawFace, SkWStream* stream) {
1316 const LogFontTypeface* face = static_cast<const LogFontTypeface*>(rawFace);
1317 SkFontDescriptor descriptor(face->style());
1318
1319 SkString familyName;
1320 logfont_to_name(face->fLogFont, &familyName);
1321 descriptor.setFamilyName(familyName.c_str());
1322 //TODO: FileName and PostScriptName currently unsupported.
1323
1324 descriptor.serialize(stream);
1325
1326 if (face->fSerializeAsStream) {
1327 // store the entire font in the fontData
1328 SkAutoTUnref<SkStream> fontStream(SkFontHost::OpenStream(face->uniqueID()));
1329 const uint32_t length = fontStream->getLength();
1330
1331 stream->writePackedUInt(length);
1332 stream->writeStream(fontStream, length);
1333 } else {
1334 stream->writePackedUInt(0);
1335 }
reed@google.comac6b9792011-03-11 15:42:51 +00001336}
1337
1338SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
bungeman@google.come70f7982012-06-01 19:38:19 +00001339 SkFontDescriptor descriptor(stream);
1340
1341 const uint32_t customFontDataLength = stream->readPackedUInt();
1342 if (customFontDataLength > 0) {
1343 // generate a new stream to store the custom typeface
1344 SkAutoTUnref<SkMemoryStream> fontStream(SkNEW_ARGS(SkMemoryStream, (customFontDataLength - 1)));
1345 stream->read((void*)fontStream->getMemoryBase(), customFontDataLength - 1);
1346
1347 return CreateTypefaceFromStream(fontStream.get());
1348 }
1349
1350 return SkFontHost::CreateTypeface(NULL, descriptor.getFamilyName(), descriptor.getStyle());
reed@google.comac6b9792011-03-11 15:42:51 +00001351}
1352
1353static bool getWidthAdvance(HDC hdc, int gId, int16_t* advance) {
1354 // Initialize the MAT2 structure to the identify transformation matrix.
1355 static const MAT2 mat2 = {SkScalarToFIXED(1), SkScalarToFIXED(0),
1356 SkScalarToFIXED(0), SkScalarToFIXED(1)};
1357 int flags = GGO_METRICS | GGO_GLYPH_INDEX;
1358 GLYPHMETRICS gm;
1359 if (GDI_ERROR == GetGlyphOutline(hdc, gId, flags, &gm, 0, NULL, &mat2)) {
1360 return false;
1361 }
1362 SkASSERT(advance);
1363 *advance = gm.gmCellIncX;
1364 return true;
1365}
1366
1367// static
1368SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
vandebo@chromium.org325cb9a2011-03-30 18:36:29 +00001369 uint32_t fontID,
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +00001370 SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
1371 const uint32_t* glyphIDs,
1372 uint32_t glyphIDsCount) {
reed@google.com59d2f632011-05-02 19:36:59 +00001373 LOGFONT lf;
1374 GetLogFontByID(fontID, &lf);
reed@google.comac6b9792011-03-11 15:42:51 +00001375 SkAdvancedTypefaceMetrics* info = NULL;
1376
1377 HDC hdc = CreateCompatibleDC(NULL);
1378 HFONT font = CreateFontIndirect(&lf);
1379 HFONT savefont = (HFONT)SelectObject(hdc, font);
1380 HFONT designFont = NULL;
1381
reed@google.com05b6f3a2011-11-28 15:30:28 +00001382 const char stem_chars[] = {'i', 'I', '!', '1'};
1383 int16_t min_width;
1384 unsigned glyphCount;
1385
reed@google.comac6b9792011-03-11 15:42:51 +00001386 // To request design units, create a logical font whose height is specified
1387 // as unitsPerEm.
1388 OUTLINETEXTMETRIC otm;
bungeman@google.com39698b12011-11-15 22:26:41 +00001389 unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
1390 if (0 == otmRet) {
1391 ensure_typeface_accessible(fontID);
1392 otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm);
1393 }
1394 if (!otmRet || !GetTextFace(hdc, LF_FACESIZE, lf.lfFaceName)) {
reed@google.comac6b9792011-03-11 15:42:51 +00001395 goto Error;
1396 }
1397 lf.lfHeight = -SkToS32(otm.otmEMSquare);
1398 designFont = CreateFontIndirect(&lf);
1399 SelectObject(hdc, designFont);
1400 if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm)) {
1401 goto Error;
1402 }
bungeman@google.coma0319f62012-04-18 15:40:50 +00001403 glyphCount = calculateOutlineGlyphCount(hdc);
reed@google.comac6b9792011-03-11 15:42:51 +00001404
1405 info = new SkAdvancedTypefaceMetrics;
1406 info->fEmSize = otm.otmEMSquare;
1407 info->fMultiMaster = false;
1408 info->fLastGlyphID = SkToU16(glyphCount - 1);
1409 info->fStyle = 0;
bungeman@google.come70f7982012-06-01 19:38:19 +00001410 logfont_to_name(lf, &info->fFontName);
reed@google.comac6b9792011-03-11 15:42:51 +00001411
vandebo@chromium.org6744d492011-05-09 18:13:47 +00001412 if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) {
1413 populate_glyph_to_unicode(hdc, glyphCount, &(info->fGlyphToUnicode));
1414 }
1415
vandebo@chromium.orgd41e70d2012-03-08 19:41:01 +00001416 if (glyphCount > 0 &&
1417 (otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE)) {
reed@google.comac6b9792011-03-11 15:42:51 +00001418 info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
1419 } else {
1420 info->fType = SkAdvancedTypefaceMetrics::kOther_Font;
1421 info->fItalicAngle = 0;
1422 info->fAscent = 0;
1423 info->fDescent = 0;
1424 info->fStemV = 0;
1425 info->fCapHeight = 0;
1426 info->fBBox = SkIRect::MakeEmpty();
1427 return info;
1428 }
ctguil@chromium.org5aa937b2011-08-04 01:01:24 +00001429
reed@google.comac6b9792011-03-11 15:42:51 +00001430 // If this bit is clear the font is a fixed pitch font.
1431 if (!(otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
1432 info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
1433 }
1434 if (otm.otmTextMetrics.tmItalic) {
1435 info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
1436 }
1437 // Setting symbolic style by default for now.
1438 info->fStyle |= SkAdvancedTypefaceMetrics::kSymbolic_Style;
1439 if (otm.otmTextMetrics.tmPitchAndFamily & FF_ROMAN) {
1440 info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
1441 } else if (otm.otmTextMetrics.tmPitchAndFamily & FF_SCRIPT) {
1442 info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
1443 }
1444
1445 // The main italic angle of the font, in tenths of a degree counterclockwise
1446 // from vertical.
1447 info->fItalicAngle = otm.otmItalicAngle / 10;
1448 info->fAscent = SkToS16(otm.otmTextMetrics.tmAscent);
1449 info->fDescent = SkToS16(-otm.otmTextMetrics.tmDescent);
1450 // TODO(ctguil): Use alternate cap height calculation.
1451 // MSDN says otmsCapEmHeight is not support but it is returning a value on
1452 // my Win7 box.
1453 info->fCapHeight = otm.otmsCapEmHeight;
1454 info->fBBox =
1455 SkIRect::MakeLTRB(otm.otmrcFontBox.left, otm.otmrcFontBox.top,
1456 otm.otmrcFontBox.right, otm.otmrcFontBox.bottom);
1457
1458 // Figure out a good guess for StemV - Min width of i, I, !, 1.
1459 // This probably isn't very good with an italic font.
reed@google.com05b6f3a2011-11-28 15:30:28 +00001460 min_width = SHRT_MAX;
reed@google.comac6b9792011-03-11 15:42:51 +00001461 info->fStemV = 0;
reed@google.comac6b9792011-03-11 15:42:51 +00001462 for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) {
1463 ABC abcWidths;
1464 if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) {
1465 int16_t width = abcWidths.abcB;
1466 if (width > 0 && width < min_width) {
1467 min_width = width;
1468 info->fStemV = min_width;
1469 }
1470 }
1471 }
1472
1473 // If bit 1 is set, the font may not be embedded in a document.
1474 // If bit 1 is clear, the font can be embedded.
1475 // If bit 2 is set, the embedding is read-only.
1476 if (otm.otmfsType & 0x1) {
1477 info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
ctguil@chromium.org0e6dc0a2011-03-30 20:41:16 +00001478 } else if (perGlyphInfo &
1479 SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) {
ctguil@chromium.org5aa937b2011-08-04 01:01:24 +00001480 if (info->fStyle & SkAdvancedTypefaceMetrics::kFixedPitch_Style) {
1481 appendRange(&info->fGlyphWidths, 0);
1482 info->fGlyphWidths->fAdvance.append(1, &min_width);
1483 finishRange(info->fGlyphWidths.get(), 0,
1484 SkAdvancedTypefaceMetrics::WidthRange::kDefault);
1485 } else {
1486 info->fGlyphWidths.reset(
vandebo@chromium.org37ad8fb2011-08-18 02:38:50 +00001487 getAdvanceData(hdc,
1488 glyphCount,
1489 glyphIDs,
1490 glyphIDsCount,
1491 &getWidthAdvance));
ctguil@chromium.org5aa937b2011-08-04 01:01:24 +00001492 }
reed@google.comac6b9792011-03-11 15:42:51 +00001493 }
1494
1495Error:
1496 SelectObject(hdc, savefont);
1497 DeleteObject(designFont);
1498 DeleteObject(font);
1499 DeleteDC(hdc);
1500
1501 return info;
1502}
1503
bungeman@google.coma5501992012-05-18 19:06:41 +00001504//Dummy representation of a Base64 encoded GUID from create_unique_font_name.
1505#define BASE64_GUID_ID "XXXXXXXXXXXXXXXXXXXXXXXX"
1506//Length of GUID representation from create_id, including NULL terminator.
1507#define BASE64_GUID_ID_LEN SK_ARRAY_COUNT(BASE64_GUID_ID)
reed@google.comac6b9792011-03-11 15:42:51 +00001508
bungeman@google.coma5501992012-05-18 19:06:41 +00001509SK_COMPILE_ASSERT(BASE64_GUID_ID_LEN < LF_FACESIZE, GUID_longer_than_facesize);
1510
1511/**
1512 NameID 6 Postscript names cannot have the character '/'.
1513 It would be easier to hex encode the GUID, but that is 32 bytes,
1514 and many systems have issues with names longer than 28 bytes.
1515 The following need not be any standard base64 encoding.
1516 The encoded value is never decoded.
1517*/
rmistry@google.comd6176b02012-08-23 18:14:13 +00001518static const char postscript_safe_base64_encode[] =
bungeman@google.coma5501992012-05-18 19:06:41 +00001519 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1520 "abcdefghijklmnopqrstuvwxyz"
1521 "0123456789-_=";
1522
1523/**
1524 Formats a GUID into Base64 and places it into buffer.
1525 buffer should have space for at least BASE64_GUID_ID_LEN characters.
1526 The string will always be null terminated.
1527 XXXXXXXXXXXXXXXXXXXXXXXX0
1528 */
1529static void format_guid_b64(const GUID& guid, char* buffer, size_t bufferSize) {
1530 SkASSERT(bufferSize >= BASE64_GUID_ID_LEN);
1531 size_t written = SkBase64::Encode(&guid, sizeof(guid), buffer, postscript_safe_base64_encode);
1532 SkASSERT(written < LF_FACESIZE);
1533 buffer[written] = '\0';
1534}
1535
1536/**
1537 Creates a Base64 encoded GUID and places it into buffer.
1538 buffer should have space for at least BASE64_GUID_ID_LEN characters.
1539 The string will always be null terminated.
1540 XXXXXXXXXXXXXXXXXXXXXXXX0
1541 */
1542static HRESULT create_unique_font_name(char* buffer, size_t bufferSize) {
1543 GUID guid = {};
1544 if (FAILED(CoCreateGuid(&guid))) {
1545 return E_UNEXPECTED;
1546 }
1547 format_guid_b64(guid, buffer, bufferSize);
1548
1549 return S_OK;
1550}
1551
1552/**
1553 Introduces a font to GDI. On failure will return NULL. The returned handle
1554 should eventually be passed to RemoveFontMemResourceEx.
1555*/
1556static HANDLE activate_font(SkData* fontData) {
1557 DWORD numFonts = 0;
1558 //AddFontMemResourceEx just copies the data, but does not specify const.
1559 HANDLE fontHandle = AddFontMemResourceEx(const_cast<void*>(fontData->data()),
1560 fontData->size(),
1561 0,
1562 &numFonts);
1563
1564 if (fontHandle != NULL && numFonts < 1) {
1565 RemoveFontMemResourceEx(fontHandle);
1566 return NULL;
1567 }
1568
1569 return fontHandle;
1570}
1571
bungeman@google.coma5501992012-05-18 19:06:41 +00001572SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
1573 // Create a unique and unpredictable font name.
1574 // Avoids collisions and access from CSS.
1575 char familyName[BASE64_GUID_ID_LEN];
1576 const int familyNameSize = SK_ARRAY_COUNT(familyName);
1577 if (FAILED(create_unique_font_name(familyName, familyNameSize))) {
1578 return NULL;
1579 }
rmistry@google.comd6176b02012-08-23 18:14:13 +00001580
bungeman@google.coma5501992012-05-18 19:06:41 +00001581 // Change the name of the font.
bungeman@google.come9bbee32012-05-21 13:46:13 +00001582 SkAutoTUnref<SkData> rewrittenFontData(SkOTUtils::RenameFont(stream, familyName, familyNameSize-1));
1583 if (NULL == rewrittenFontData.get()) {
bungeman@google.coma5501992012-05-18 19:06:41 +00001584 return NULL;
1585 }
bungeman@google.coma5501992012-05-18 19:06:41 +00001586
1587 // Register the font with GDI.
bungeman@google.come9bbee32012-05-21 13:46:13 +00001588 HANDLE fontReference = activate_font(rewrittenFontData.get());
bungeman@google.coma5501992012-05-18 19:06:41 +00001589 if (NULL == fontReference) {
1590 return NULL;
1591 }
1592
1593 // Create the typeface.
1594 LOGFONT lf;
1595 logfont_for_name(familyName, lf);
1596
1597 return SkCreateFontMemResourceTypefaceFromLOGFONT(lf, fontReference);
reed@google.comac6b9792011-03-11 15:42:51 +00001598}
1599
1600SkStream* SkFontHost::OpenStream(SkFontID uniqueID) {
ctguil@chromium.orgf4c26222011-05-16 22:00:05 +00001601 const DWORD kTTCTag =
1602 SkEndian_SwapBE32(SkSetFourByteTag('t', 't', 'c', 'f'));
reed@google.com59d2f632011-05-02 19:36:59 +00001603 LOGFONT lf;
1604 GetLogFontByID(uniqueID, &lf);
reed@google.comac6b9792011-03-11 15:42:51 +00001605
1606 HDC hdc = ::CreateCompatibleDC(NULL);
reed@google.com59d2f632011-05-02 19:36:59 +00001607 HFONT font = CreateFontIndirect(&lf);
reed@google.comac6b9792011-03-11 15:42:51 +00001608 HFONT savefont = (HFONT)SelectObject(hdc, font);
1609
vandebo@chromium.orgd6044812011-05-13 03:41:29 +00001610 SkMemoryStream* stream = NULL;
1611 DWORD tables[2] = {kTTCTag, 0};
1612 for (int i = 0; i < SK_ARRAY_COUNT(tables); i++) {
1613 size_t bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0);
bungeman@google.com39698b12011-11-15 22:26:41 +00001614 if (bufferSize == GDI_ERROR) {
1615 ensure_typeface_accessible(uniqueID);
1616 bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0);
1617 }
vandebo@chromium.orgd6044812011-05-13 03:41:29 +00001618 if (bufferSize != GDI_ERROR) {
1619 stream = new SkMemoryStream(bufferSize);
1620 if (GetFontData(hdc, tables[i], 0, (void*)stream->getMemoryBase(),
1621 bufferSize)) {
1622 break;
1623 } else {
1624 delete stream;
1625 stream = NULL;
1626 }
1627 }
reed@google.comac6b9792011-03-11 15:42:51 +00001628 }
1629
1630 SelectObject(hdc, savefont);
1631 DeleteObject(font);
1632 DeleteDC(hdc);
1633
1634 return stream;
1635}
1636
1637SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) {
1638 return SkNEW_ARGS(SkScalerContext_Windows, (desc));
1639}
1640
1641/** Return the closest matching typeface given either an existing family
1642 (specified by a typeface in that family) or by a familyName, and a
1643 requested style.
bungeman@google.com90d812b2011-10-24 21:25:01 +00001644 1) If familyFace is null, use familyName.
1645 2) If familyName is null, use familyFace.
reed@google.comac6b9792011-03-11 15:42:51 +00001646 3) If both are null, return the default font that best matches style
1647 This MUST not return NULL.
1648 */
1649
1650SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
1651 const char familyName[],
reed@google.comac6b9792011-03-11 15:42:51 +00001652 SkTypeface::Style style) {
reed@google.com59d2f632011-05-02 19:36:59 +00001653 LOGFONT lf;
reed@google.comac6b9792011-03-11 15:42:51 +00001654 if (NULL == familyFace && NULL == familyName) {
reed@google.com59d2f632011-05-02 19:36:59 +00001655 lf = get_default_font();
1656 } else if (familyFace) {
1657 LogFontTypeface* face = (LogFontTypeface*)familyFace;
1658 lf = face->fLogFont;
reed@google.comac6b9792011-03-11 15:42:51 +00001659 } else {
bungeman@google.coma5501992012-05-18 19:06:41 +00001660 logfont_for_name(familyName, lf);
reed@google.comac6b9792011-03-11 15:42:51 +00001661 }
reed@google.com59d2f632011-05-02 19:36:59 +00001662 setStyle(&lf, style);
1663 return SkCreateTypefaceFromLOGFONT(lf);
reed@google.comac6b9792011-03-11 15:42:51 +00001664}
1665
reed@google.comac6b9792011-03-11 15:42:51 +00001666SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
1667 printf("SkFontHost::CreateTypefaceFromFile unimplemented");
1668 return NULL;
1669}
1670
1671void SkFontHost::FilterRec(SkScalerContext::Rec* rec) {
reed@google.come8fab012011-07-13 15:25:33 +00001672 unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag |
1673 SkScalerContext::kAutohinting_Flag |
1674 SkScalerContext::kEmbeddedBitmapText_Flag |
1675 SkScalerContext::kEmbolden_Flag |
bungeman@google.comc84547a2012-01-05 20:18:06 +00001676 SkScalerContext::kSubpixelPositioning_Flag |
reed@google.come8fab012011-07-13 15:25:33 +00001677 SkScalerContext::kLCD_BGROrder_Flag |
1678 SkScalerContext::kLCD_Vertical_Flag;
1679 rec->fFlags &= ~flagsWeDontSupport;
1680
reed@google.come8fab012011-07-13 15:25:33 +00001681 SkPaint::Hinting h = rec->getHinting();
reed@google.comda440672011-07-13 18:02:28 +00001682
1683 // I think we can support no-hinting, if we get hires outlines and just
1684 // use skia to rasterize into a gray-scale mask...
1685#if 0
reed@google.come8fab012011-07-13 15:25:33 +00001686 switch (h) {
1687 case SkPaint::kNo_Hinting:
1688 case SkPaint::kSlight_Hinting:
1689 h = SkPaint::kNo_Hinting;
1690 break;
1691 case SkPaint::kNormal_Hinting:
1692 case SkPaint::kFull_Hinting:
1693 h = SkPaint::kNormal_Hinting;
1694 break;
1695 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +00001696 SkDEBUGFAIL("unknown hinting");
reed@google.come8fab012011-07-13 15:25:33 +00001697 }
reed@google.comda440672011-07-13 18:02:28 +00001698#else
1699 h = SkPaint::kNormal_Hinting;
1700#endif
reed@google.come8fab012011-07-13 15:25:33 +00001701 rec->setHinting(h);
reed@google.comda440672011-07-13 18:02:28 +00001702
reed@google.com9181aa82011-08-05 14:28:31 +00001703// turn this off since GDI might turn A8 into BW! Need a bigger fix.
1704#if 0
reed@google.comda440672011-07-13 18:02:28 +00001705 // Disable LCD when rotated, since GDI's output is ugly
1706 if (isLCD(*rec) && !isAxisAligned(*rec)) {
1707 rec->fMaskFormat = SkMask::kA8_Format;
1708 }
reed@google.com9181aa82011-08-05 14:28:31 +00001709#endif
reed@google.com754e4eb2011-09-26 13:21:39 +00001710
1711#if 0
1712 if (SkMask::kLCD16_Format == rec->fMaskFormat) {
1713 rec->fMaskFormat = SkMask::kLCD32_Format;
1714 }
1715#endif
reed@google.com754e4eb2011-09-26 13:21:39 +00001716}