|
1 |
|
2 /* |
|
3 * 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. |
|
7 */ |
|
8 |
|
9 #include "SkAdvancedTypefaceMetrics.h" |
|
10 #include "SkBase64.h" |
|
11 #include "SkColorPriv.h" |
|
12 #include "SkData.h" |
|
13 #include "SkDescriptor.h" |
|
14 #include "SkFontDescriptor.h" |
|
15 #include "SkFontHost.h" |
|
16 #include "SkGlyph.h" |
|
17 #include "SkHRESULT.h" |
|
18 #include "SkMaskGamma.h" |
|
19 #include "SkOTTable_maxp.h" |
|
20 #include "SkOTTable_name.h" |
|
21 #include "SkOTUtils.h" |
|
22 #include "SkPath.h" |
|
23 #include "SkSFNTHeader.h" |
|
24 #include "SkStream.h" |
|
25 #include "SkString.h" |
|
26 #include "SkTemplates.h" |
|
27 #include "SkThread.h" |
|
28 #include "SkTypeface_win.h" |
|
29 #include "SkTypefaceCache.h" |
|
30 #include "SkUtils.h" |
|
31 |
|
32 #include "SkTypes.h" |
|
33 #include <tchar.h> |
|
34 #include <usp10.h> |
|
35 #include <objbase.h> |
|
36 |
|
37 static void (*gEnsureLOGFONTAccessibleProc)(const LOGFONT&); |
|
38 |
|
39 void SkTypeface_SetEnsureLOGFONTAccessibleProc(void (*proc)(const LOGFONT&)) { |
|
40 gEnsureLOGFONTAccessibleProc = proc; |
|
41 } |
|
42 |
|
43 static void call_ensure_accessible(const LOGFONT& lf) { |
|
44 if (gEnsureLOGFONTAccessibleProc) { |
|
45 gEnsureLOGFONTAccessibleProc(lf); |
|
46 } |
|
47 } |
|
48 |
|
49 /////////////////////////////////////////////////////////////////////////////// |
|
50 |
|
51 // always packed xxRRGGBB |
|
52 typedef uint32_t SkGdiRGB; |
|
53 |
|
54 // define this in your Makefile or .gyp to enforce AA requests |
|
55 // which GDI ignores at small sizes. This flag guarantees AA |
|
56 // for rotated text, regardless of GDI's notions. |
|
57 //#define SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS |
|
58 |
|
59 static bool isLCD(const SkScalerContext::Rec& rec) { |
|
60 return SkMask::kLCD16_Format == rec.fMaskFormat || |
|
61 SkMask::kLCD32_Format == rec.fMaskFormat; |
|
62 } |
|
63 |
|
64 static bool bothZero(SkScalar a, SkScalar b) { |
|
65 return 0 == a && 0 == b; |
|
66 } |
|
67 |
|
68 // returns false if there is any non-90-rotation or skew |
|
69 static bool isAxisAligned(const SkScalerContext::Rec& rec) { |
|
70 return 0 == rec.fPreSkewX && |
|
71 (bothZero(rec.fPost2x2[0][1], rec.fPost2x2[1][0]) || |
|
72 bothZero(rec.fPost2x2[0][0], rec.fPost2x2[1][1])); |
|
73 } |
|
74 |
|
75 static bool needToRenderWithSkia(const SkScalerContext::Rec& rec) { |
|
76 #ifdef SK_ENFORCE_ROTATED_TEXT_AA_ON_WINDOWS |
|
77 // What we really want to catch is when GDI will ignore the AA request and give |
|
78 // us BW instead. Smallish rotated text is one heuristic, so this code is just |
|
79 // an approximation. We shouldn't need to do this for larger sizes, but at those |
|
80 // sizes, the quality difference gets less and less between our general |
|
81 // scanconverter and GDI's. |
|
82 if (SkMask::kA8_Format == rec.fMaskFormat && !isAxisAligned(rec)) { |
|
83 return true; |
|
84 } |
|
85 #endif |
|
86 return rec.getHinting() == SkPaint::kNo_Hinting || rec.getHinting() == SkPaint::kSlight_Hinting; |
|
87 } |
|
88 |
|
89 using namespace skia_advanced_typeface_metrics_utils; |
|
90 |
|
91 static void tchar_to_skstring(const TCHAR t[], SkString* s) { |
|
92 #ifdef UNICODE |
|
93 size_t sSize = WideCharToMultiByte(CP_UTF8, 0, t, -1, NULL, 0, NULL, NULL); |
|
94 s->resize(sSize); |
|
95 WideCharToMultiByte(CP_UTF8, 0, t, -1, s->writable_str(), sSize, NULL, NULL); |
|
96 #else |
|
97 s->set(t); |
|
98 #endif |
|
99 } |
|
100 |
|
101 static void dcfontname_to_skstring(HDC deviceContext, const LOGFONT& lf, SkString* familyName) { |
|
102 int fontNameLen; //length of fontName in TCHARS. |
|
103 if (0 == (fontNameLen = GetTextFace(deviceContext, 0, NULL))) { |
|
104 call_ensure_accessible(lf); |
|
105 if (0 == (fontNameLen = GetTextFace(deviceContext, 0, NULL))) { |
|
106 fontNameLen = 0; |
|
107 } |
|
108 } |
|
109 |
|
110 SkAutoSTArray<LF_FULLFACESIZE, TCHAR> fontName(fontNameLen+1); |
|
111 if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) { |
|
112 call_ensure_accessible(lf); |
|
113 if (0 == GetTextFace(deviceContext, fontNameLen, fontName.get())) { |
|
114 fontName[0] = 0; |
|
115 } |
|
116 } |
|
117 |
|
118 tchar_to_skstring(fontName.get(), familyName); |
|
119 } |
|
120 |
|
121 static void make_canonical(LOGFONT* lf) { |
|
122 lf->lfHeight = -64; |
|
123 lf->lfQuality = CLEARTYPE_QUALITY;//PROOF_QUALITY; |
|
124 lf->lfCharSet = DEFAULT_CHARSET; |
|
125 // lf->lfClipPrecision = 64; |
|
126 } |
|
127 |
|
128 static SkTypeface::Style get_style(const LOGFONT& lf) { |
|
129 unsigned style = 0; |
|
130 if (lf.lfWeight >= FW_BOLD) { |
|
131 style |= SkTypeface::kBold; |
|
132 } |
|
133 if (lf.lfItalic) { |
|
134 style |= SkTypeface::kItalic; |
|
135 } |
|
136 return static_cast<SkTypeface::Style>(style); |
|
137 } |
|
138 |
|
139 static void setStyle(LOGFONT* lf, SkTypeface::Style style) { |
|
140 lf->lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL ; |
|
141 lf->lfItalic = ((style & SkTypeface::kItalic) != 0); |
|
142 } |
|
143 |
|
144 static inline FIXED SkFixedToFIXED(SkFixed x) { |
|
145 return *(FIXED*)(&x); |
|
146 } |
|
147 static inline SkFixed SkFIXEDToFixed(FIXED x) { |
|
148 return *(SkFixed*)(&x); |
|
149 } |
|
150 |
|
151 static inline FIXED SkScalarToFIXED(SkScalar x) { |
|
152 return SkFixedToFIXED(SkScalarToFixed(x)); |
|
153 } |
|
154 |
|
155 static inline SkScalar SkFIXEDToScalar(FIXED x) { |
|
156 return SkFixedToScalar(SkFIXEDToFixed(x)); |
|
157 } |
|
158 |
|
159 static unsigned calculateGlyphCount(HDC hdc, const LOGFONT& lf) { |
|
160 TEXTMETRIC textMetric; |
|
161 if (0 == GetTextMetrics(hdc, &textMetric)) { |
|
162 textMetric.tmPitchAndFamily = TMPF_VECTOR; |
|
163 call_ensure_accessible(lf); |
|
164 GetTextMetrics(hdc, &textMetric); |
|
165 } |
|
166 |
|
167 if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) { |
|
168 return textMetric.tmLastChar; |
|
169 } |
|
170 |
|
171 // The 'maxp' table stores the number of glyphs at offset 4, in 2 bytes. |
|
172 uint16_t glyphs; |
|
173 if (GDI_ERROR != GetFontData(hdc, SkOTTableMaximumProfile::TAG, 4, &glyphs, sizeof(glyphs))) { |
|
174 return SkEndian_SwapBE16(glyphs); |
|
175 } |
|
176 |
|
177 // Binary search for glyph count. |
|
178 static const MAT2 mat2 = {{0, 1}, {0, 0}, {0, 0}, {0, 1}}; |
|
179 int32_t max = SK_MaxU16 + 1; |
|
180 int32_t min = 0; |
|
181 GLYPHMETRICS gm; |
|
182 while (min < max) { |
|
183 int32_t mid = min + ((max - min) / 2); |
|
184 if (GetGlyphOutlineW(hdc, mid, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, |
|
185 NULL, &mat2) == GDI_ERROR) { |
|
186 max = mid; |
|
187 } else { |
|
188 min = mid + 1; |
|
189 } |
|
190 } |
|
191 SkASSERT(min == max); |
|
192 return min; |
|
193 } |
|
194 |
|
195 static unsigned calculateUPEM(HDC hdc, const LOGFONT& lf) { |
|
196 TEXTMETRIC textMetric; |
|
197 if (0 == GetTextMetrics(hdc, &textMetric)) { |
|
198 textMetric.tmPitchAndFamily = TMPF_VECTOR; |
|
199 call_ensure_accessible(lf); |
|
200 GetTextMetrics(hdc, &textMetric); |
|
201 } |
|
202 |
|
203 if (!(textMetric.tmPitchAndFamily & TMPF_VECTOR)) { |
|
204 return textMetric.tmMaxCharWidth; |
|
205 } |
|
206 |
|
207 OUTLINETEXTMETRIC otm; |
|
208 unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm); |
|
209 if (0 == otmRet) { |
|
210 call_ensure_accessible(lf); |
|
211 otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm); |
|
212 } |
|
213 |
|
214 return (0 == otmRet) ? 0 : otm.otmEMSquare; |
|
215 } |
|
216 |
|
217 class LogFontTypeface : public SkTypeface { |
|
218 public: |
|
219 LogFontTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf, bool serializeAsStream = false) : |
|
220 SkTypeface(style, fontID, false), fLogFont(lf), fSerializeAsStream(serializeAsStream) { |
|
221 |
|
222 // If the font has cubic outlines, it will not be rendered with ClearType. |
|
223 HFONT font = CreateFontIndirect(&lf); |
|
224 |
|
225 HDC deviceContext = ::CreateCompatibleDC(NULL); |
|
226 HFONT savefont = (HFONT)SelectObject(deviceContext, font); |
|
227 |
|
228 TEXTMETRIC textMetric; |
|
229 if (0 == GetTextMetrics(deviceContext, &textMetric)) { |
|
230 call_ensure_accessible(lf); |
|
231 if (0 == GetTextMetrics(deviceContext, &textMetric)) { |
|
232 textMetric.tmPitchAndFamily = TMPF_TRUETYPE; |
|
233 } |
|
234 } |
|
235 if (deviceContext) { |
|
236 ::SelectObject(deviceContext, savefont); |
|
237 ::DeleteDC(deviceContext); |
|
238 } |
|
239 if (font) { |
|
240 ::DeleteObject(font); |
|
241 } |
|
242 |
|
243 // The fixed pitch bit is set if the font is *not* fixed pitch. |
|
244 this->setIsFixedPitch((textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0); |
|
245 |
|
246 // Used a logfont on a memory context, should never get a device font. |
|
247 // Therefore all TMPF_DEVICE will be PostScript (cubic) fonts. |
|
248 fCanBeLCD = !((textMetric.tmPitchAndFamily & TMPF_VECTOR) && |
|
249 (textMetric.tmPitchAndFamily & TMPF_DEVICE)); |
|
250 } |
|
251 |
|
252 LOGFONT fLogFont; |
|
253 bool fSerializeAsStream; |
|
254 bool fCanBeLCD; |
|
255 |
|
256 static LogFontTypeface* Create(const LOGFONT& lf) { |
|
257 SkTypeface::Style style = get_style(lf); |
|
258 SkFontID fontID = SkTypefaceCache::NewFontID(); |
|
259 return new LogFontTypeface(style, fontID, lf); |
|
260 } |
|
261 |
|
262 static void EnsureAccessible(const SkTypeface* face) { |
|
263 call_ensure_accessible(static_cast<const LogFontTypeface*>(face)->fLogFont); |
|
264 } |
|
265 |
|
266 protected: |
|
267 virtual SkStream* onOpenStream(int* ttcIndex) const SK_OVERRIDE; |
|
268 virtual SkScalerContext* onCreateScalerContext(const SkDescriptor*) const SK_OVERRIDE; |
|
269 virtual void onFilterRec(SkScalerContextRec*) const SK_OVERRIDE; |
|
270 virtual SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics( |
|
271 SkAdvancedTypefaceMetrics::PerGlyphInfo, |
|
272 const uint32_t*, uint32_t) const SK_OVERRIDE; |
|
273 virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const SK_OVERRIDE; |
|
274 virtual int onCharsToGlyphs(const void* chars, Encoding encoding, |
|
275 uint16_t glyphs[], int glyphCount) const SK_OVERRIDE; |
|
276 virtual int onCountGlyphs() const SK_OVERRIDE; |
|
277 virtual int onGetUPEM() const SK_OVERRIDE; |
|
278 virtual SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const SK_OVERRIDE; |
|
279 virtual int onGetTableTags(SkFontTableTag tags[]) const SK_OVERRIDE; |
|
280 virtual size_t onGetTableData(SkFontTableTag, size_t offset, |
|
281 size_t length, void* data) const SK_OVERRIDE; |
|
282 }; |
|
283 |
|
284 class FontMemResourceTypeface : public LogFontTypeface { |
|
285 public: |
|
286 /** |
|
287 * Takes ownership of fontMemResource. |
|
288 */ |
|
289 FontMemResourceTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf, HANDLE fontMemResource) : |
|
290 LogFontTypeface(style, fontID, lf, true), fFontMemResource(fontMemResource) { |
|
291 } |
|
292 |
|
293 HANDLE fFontMemResource; |
|
294 |
|
295 /** |
|
296 * The created FontMemResourceTypeface takes ownership of fontMemResource. |
|
297 */ |
|
298 static FontMemResourceTypeface* Create(const LOGFONT& lf, HANDLE fontMemResource) { |
|
299 SkTypeface::Style style = get_style(lf); |
|
300 SkFontID fontID = SkTypefaceCache::NewFontID(); |
|
301 return new FontMemResourceTypeface(style, fontID, lf, fontMemResource); |
|
302 } |
|
303 |
|
304 protected: |
|
305 virtual void weak_dispose() const SK_OVERRIDE { |
|
306 RemoveFontMemResourceEx(fFontMemResource); |
|
307 //SkTypefaceCache::Remove(this); |
|
308 INHERITED::weak_dispose(); |
|
309 } |
|
310 |
|
311 private: |
|
312 typedef LogFontTypeface INHERITED; |
|
313 }; |
|
314 |
|
315 static const LOGFONT& get_default_font() { |
|
316 static LOGFONT gDefaultFont; |
|
317 return gDefaultFont; |
|
318 } |
|
319 |
|
320 static bool FindByLogFont(SkTypeface* face, SkTypeface::Style requestedStyle, void* ctx) { |
|
321 LogFontTypeface* lface = static_cast<LogFontTypeface*>(face); |
|
322 const LOGFONT* lf = reinterpret_cast<const LOGFONT*>(ctx); |
|
323 |
|
324 return lface && |
|
325 get_style(lface->fLogFont) == requestedStyle && |
|
326 !memcmp(&lface->fLogFont, lf, sizeof(LOGFONT)); |
|
327 } |
|
328 |
|
329 /** |
|
330 * This guy is public. It first searches the cache, and if a match is not found, |
|
331 * it creates a new face. |
|
332 */ |
|
333 SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT& origLF) { |
|
334 LOGFONT lf = origLF; |
|
335 make_canonical(&lf); |
|
336 SkTypeface* face = SkTypefaceCache::FindByProcAndRef(FindByLogFont, &lf); |
|
337 if (NULL == face) { |
|
338 face = LogFontTypeface::Create(lf); |
|
339 SkTypefaceCache::Add(face, get_style(lf)); |
|
340 } |
|
341 return face; |
|
342 } |
|
343 |
|
344 /** |
|
345 * The created SkTypeface takes ownership of fontMemResource. |
|
346 */ |
|
347 SkTypeface* SkCreateFontMemResourceTypefaceFromLOGFONT(const LOGFONT& origLF, HANDLE fontMemResource) { |
|
348 LOGFONT lf = origLF; |
|
349 make_canonical(&lf); |
|
350 FontMemResourceTypeface* face = FontMemResourceTypeface::Create(lf, fontMemResource); |
|
351 SkTypefaceCache::Add(face, get_style(lf), false); |
|
352 return face; |
|
353 } |
|
354 |
|
355 /** |
|
356 * This guy is public |
|
357 */ |
|
358 void SkLOGFONTFromTypeface(const SkTypeface* face, LOGFONT* lf) { |
|
359 if (NULL == face) { |
|
360 *lf = get_default_font(); |
|
361 } else { |
|
362 *lf = static_cast<const LogFontTypeface*>(face)->fLogFont; |
|
363 } |
|
364 } |
|
365 |
|
366 // Construct Glyph to Unicode table. |
|
367 // Unicode code points that require conjugate pairs in utf16 are not |
|
368 // supported. |
|
369 // TODO(arthurhsu): Add support for conjugate pairs. It looks like that may |
|
370 // require parsing the TTF cmap table (platform 4, encoding 12) directly instead |
|
371 // of calling GetFontUnicodeRange(). |
|
372 static void populate_glyph_to_unicode(HDC fontHdc, const unsigned glyphCount, |
|
373 SkTDArray<SkUnichar>* glyphToUnicode) { |
|
374 DWORD glyphSetBufferSize = GetFontUnicodeRanges(fontHdc, NULL); |
|
375 if (!glyphSetBufferSize) { |
|
376 return; |
|
377 } |
|
378 |
|
379 SkAutoTDeleteArray<BYTE> glyphSetBuffer(new BYTE[glyphSetBufferSize]); |
|
380 GLYPHSET* glyphSet = |
|
381 reinterpret_cast<LPGLYPHSET>(glyphSetBuffer.get()); |
|
382 if (GetFontUnicodeRanges(fontHdc, glyphSet) != glyphSetBufferSize) { |
|
383 return; |
|
384 } |
|
385 |
|
386 glyphToUnicode->setCount(glyphCount); |
|
387 memset(glyphToUnicode->begin(), 0, glyphCount * sizeof(SkUnichar)); |
|
388 for (DWORD i = 0; i < glyphSet->cRanges; ++i) { |
|
389 // There is no guarantee that within a Unicode range, the corresponding |
|
390 // glyph id in a font file are continuous. So, even if we have ranges, |
|
391 // we can't just use the first and last entry of the range to compute |
|
392 // result. We need to enumerate them one by one. |
|
393 int count = glyphSet->ranges[i].cGlyphs; |
|
394 SkAutoTArray<WCHAR> chars(count + 1); |
|
395 chars[count] = 0; // termintate string |
|
396 SkAutoTArray<WORD> glyph(count); |
|
397 for (USHORT j = 0; j < count; ++j) { |
|
398 chars[j] = glyphSet->ranges[i].wcLow + j; |
|
399 } |
|
400 GetGlyphIndicesW(fontHdc, chars.get(), count, glyph.get(), |
|
401 GGI_MARK_NONEXISTING_GLYPHS); |
|
402 // If the glyph ID is valid, and the glyph is not mapped, then we will |
|
403 // fill in the char id into the vector. If the glyph is mapped already, |
|
404 // skip it. |
|
405 // TODO(arthurhsu): better improve this. e.g. Get all used char ids from |
|
406 // font cache, then generate this mapping table from there. It's |
|
407 // unlikely to have collisions since glyph reuse happens mostly for |
|
408 // different Unicode pages. |
|
409 for (USHORT j = 0; j < count; ++j) { |
|
410 if (glyph[j] != 0xffff && glyph[j] < glyphCount && |
|
411 (*glyphToUnicode)[glyph[j]] == 0) { |
|
412 (*glyphToUnicode)[glyph[j]] = chars[j]; |
|
413 } |
|
414 } |
|
415 } |
|
416 } |
|
417 |
|
418 ////////////////////////////////////////////////////////////////////////////////////// |
|
419 |
|
420 static int alignTo32(int n) { |
|
421 return (n + 31) & ~31; |
|
422 } |
|
423 |
|
424 struct MyBitmapInfo : public BITMAPINFO { |
|
425 RGBQUAD fMoreSpaceForColors[1]; |
|
426 }; |
|
427 |
|
428 class HDCOffscreen { |
|
429 public: |
|
430 HDCOffscreen() { |
|
431 fFont = 0; |
|
432 fDC = 0; |
|
433 fBM = 0; |
|
434 fBits = NULL; |
|
435 fWidth = fHeight = 0; |
|
436 fIsBW = false; |
|
437 } |
|
438 |
|
439 ~HDCOffscreen() { |
|
440 if (fDC) { |
|
441 DeleteDC(fDC); |
|
442 } |
|
443 if (fBM) { |
|
444 DeleteObject(fBM); |
|
445 } |
|
446 } |
|
447 |
|
448 void init(HFONT font, const XFORM& xform) { |
|
449 fFont = font; |
|
450 fXform = xform; |
|
451 } |
|
452 |
|
453 const void* draw(const SkGlyph&, bool isBW, size_t* srcRBPtr); |
|
454 |
|
455 private: |
|
456 HDC fDC; |
|
457 HBITMAP fBM; |
|
458 HFONT fFont; |
|
459 XFORM fXform; |
|
460 void* fBits; // points into fBM |
|
461 int fWidth; |
|
462 int fHeight; |
|
463 bool fIsBW; |
|
464 }; |
|
465 |
|
466 const void* HDCOffscreen::draw(const SkGlyph& glyph, bool isBW, |
|
467 size_t* srcRBPtr) { |
|
468 // Can we share the scalercontext's fDDC, so we don't need to create |
|
469 // a separate fDC here? |
|
470 if (0 == fDC) { |
|
471 fDC = CreateCompatibleDC(0); |
|
472 if (0 == fDC) { |
|
473 return NULL; |
|
474 } |
|
475 SetGraphicsMode(fDC, GM_ADVANCED); |
|
476 SetBkMode(fDC, TRANSPARENT); |
|
477 SetTextAlign(fDC, TA_LEFT | TA_BASELINE); |
|
478 SelectObject(fDC, fFont); |
|
479 |
|
480 COLORREF color = 0x00FFFFFF; |
|
481 SkDEBUGCODE(COLORREF prev =) SetTextColor(fDC, color); |
|
482 SkASSERT(prev != CLR_INVALID); |
|
483 } |
|
484 |
|
485 if (fBM && (fIsBW != isBW || fWidth < glyph.fWidth || fHeight < glyph.fHeight)) { |
|
486 DeleteObject(fBM); |
|
487 fBM = 0; |
|
488 } |
|
489 fIsBW = isBW; |
|
490 |
|
491 fWidth = SkMax32(fWidth, glyph.fWidth); |
|
492 fHeight = SkMax32(fHeight, glyph.fHeight); |
|
493 |
|
494 int biWidth = isBW ? alignTo32(fWidth) : fWidth; |
|
495 |
|
496 if (0 == fBM) { |
|
497 MyBitmapInfo info; |
|
498 sk_bzero(&info, sizeof(info)); |
|
499 if (isBW) { |
|
500 RGBQUAD blackQuad = { 0, 0, 0, 0 }; |
|
501 RGBQUAD whiteQuad = { 0xFF, 0xFF, 0xFF, 0 }; |
|
502 info.bmiColors[0] = blackQuad; |
|
503 info.bmiColors[1] = whiteQuad; |
|
504 } |
|
505 info.bmiHeader.biSize = sizeof(info.bmiHeader); |
|
506 info.bmiHeader.biWidth = biWidth; |
|
507 info.bmiHeader.biHeight = fHeight; |
|
508 info.bmiHeader.biPlanes = 1; |
|
509 info.bmiHeader.biBitCount = isBW ? 1 : 32; |
|
510 info.bmiHeader.biCompression = BI_RGB; |
|
511 if (isBW) { |
|
512 info.bmiHeader.biClrUsed = 2; |
|
513 } |
|
514 fBM = CreateDIBSection(fDC, &info, DIB_RGB_COLORS, &fBits, 0, 0); |
|
515 if (0 == fBM) { |
|
516 return NULL; |
|
517 } |
|
518 SelectObject(fDC, fBM); |
|
519 } |
|
520 |
|
521 // erase |
|
522 size_t srcRB = isBW ? (biWidth >> 3) : (fWidth << 2); |
|
523 size_t size = fHeight * srcRB; |
|
524 memset(fBits, 0, size); |
|
525 |
|
526 XFORM xform = fXform; |
|
527 xform.eDx = (float)-glyph.fLeft; |
|
528 xform.eDy = (float)-glyph.fTop; |
|
529 SetWorldTransform(fDC, &xform); |
|
530 |
|
531 uint16_t glyphID = glyph.getGlyphID(); |
|
532 BOOL ret = ExtTextOutW(fDC, 0, 0, ETO_GLYPH_INDEX, NULL, reinterpret_cast<LPCWSTR>(&glyphID), 1, NULL); |
|
533 GdiFlush(); |
|
534 if (0 == ret) { |
|
535 return NULL; |
|
536 } |
|
537 *srcRBPtr = srcRB; |
|
538 // offset to the start of the image |
|
539 return (const char*)fBits + (fHeight - glyph.fHeight) * srcRB; |
|
540 } |
|
541 |
|
542 ////////////////////////////////////////////////////////////////////////////// |
|
543 #define BUFFERSIZE (1 << 13) |
|
544 |
|
545 class SkScalerContext_GDI : public SkScalerContext { |
|
546 public: |
|
547 SkScalerContext_GDI(SkTypeface*, const SkDescriptor* desc); |
|
548 virtual ~SkScalerContext_GDI(); |
|
549 |
|
550 // Returns true if the constructor was able to complete all of its |
|
551 // initializations (which may include calling GDI). |
|
552 bool isValid() const; |
|
553 |
|
554 protected: |
|
555 virtual unsigned generateGlyphCount() SK_OVERRIDE; |
|
556 virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE; |
|
557 virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE; |
|
558 virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE; |
|
559 virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE; |
|
560 virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE; |
|
561 virtual void generateFontMetrics(SkPaint::FontMetrics* mX, |
|
562 SkPaint::FontMetrics* mY) SK_OVERRIDE; |
|
563 |
|
564 private: |
|
565 DWORD getGDIGlyphPath(const SkGlyph& glyph, UINT flags, |
|
566 SkAutoSTMalloc<BUFFERSIZE, uint8_t>* glyphbuf); |
|
567 |
|
568 HDCOffscreen fOffscreen; |
|
569 /** fGsA is the non-rotational part of total matrix without the text height scale. |
|
570 * Used to find the magnitude of advances. |
|
571 */ |
|
572 MAT2 fGsA; |
|
573 /** The total matrix without the textSize. */ |
|
574 MAT2 fMat22; |
|
575 /** Scales font to EM size. */ |
|
576 MAT2 fHighResMat22; |
|
577 HDC fDDC; |
|
578 HFONT fSavefont; |
|
579 HFONT fFont; |
|
580 SCRIPT_CACHE fSC; |
|
581 int fGlyphCount; |
|
582 |
|
583 /** The total matrix which also removes EM scale. */ |
|
584 SkMatrix fHiResMatrix; |
|
585 /** fG_inv is the inverse of the rotational part of the total matrix. |
|
586 * Used to set the direction of advances. |
|
587 */ |
|
588 SkMatrix fG_inv; |
|
589 enum Type { |
|
590 kTrueType_Type, kBitmap_Type, kLine_Type |
|
591 } fType; |
|
592 TEXTMETRIC fTM; |
|
593 }; |
|
594 |
|
595 static FIXED float2FIXED(float x) { |
|
596 return SkFixedToFIXED(SkFloatToFixed(x)); |
|
597 } |
|
598 |
|
599 static BYTE compute_quality(const SkScalerContext::Rec& rec) { |
|
600 switch (rec.fMaskFormat) { |
|
601 case SkMask::kBW_Format: |
|
602 return NONANTIALIASED_QUALITY; |
|
603 case SkMask::kLCD16_Format: |
|
604 case SkMask::kLCD32_Format: |
|
605 return CLEARTYPE_QUALITY; |
|
606 default: |
|
607 if (rec.fFlags & SkScalerContext::kGenA8FromLCD_Flag) { |
|
608 return CLEARTYPE_QUALITY; |
|
609 } else { |
|
610 return ANTIALIASED_QUALITY; |
|
611 } |
|
612 } |
|
613 } |
|
614 |
|
615 SkScalerContext_GDI::SkScalerContext_GDI(SkTypeface* rawTypeface, |
|
616 const SkDescriptor* desc) |
|
617 : SkScalerContext(rawTypeface, desc) |
|
618 , fDDC(0) |
|
619 , fSavefont(0) |
|
620 , fFont(0) |
|
621 , fSC(0) |
|
622 , fGlyphCount(-1) |
|
623 { |
|
624 LogFontTypeface* typeface = reinterpret_cast<LogFontTypeface*>(rawTypeface); |
|
625 |
|
626 fDDC = ::CreateCompatibleDC(NULL); |
|
627 if (!fDDC) { |
|
628 return; |
|
629 } |
|
630 SetGraphicsMode(fDDC, GM_ADVANCED); |
|
631 SetBkMode(fDDC, TRANSPARENT); |
|
632 |
|
633 SkPoint h = SkPoint::Make(SK_Scalar1, 0); |
|
634 // A is the total matrix. |
|
635 SkMatrix A; |
|
636 fRec.getSingleMatrix(&A); |
|
637 A.mapPoints(&h, 1); |
|
638 |
|
639 // Find the Given's matrix [[c, -s],[s, c]] which rotates the baseline vector h |
|
640 // (where the baseline is mapped to) to the positive horizontal axis. |
|
641 const SkScalar& a = h.fX; |
|
642 const SkScalar& b = h.fY; |
|
643 SkScalar c, s; |
|
644 if (0 == b) { |
|
645 c = SkDoubleToScalar(_copysign(SK_Scalar1, a)); |
|
646 s = 0; |
|
647 } else if (0 == a) { |
|
648 c = 0; |
|
649 s = SkDoubleToScalar(-_copysign(SK_Scalar1, b)); |
|
650 } else if (SkScalarAbs(b) > SkScalarAbs(a)) { |
|
651 SkScalar t = a / b; |
|
652 SkScalar u = SkDoubleToScalar(_copysign(SkScalarSqrt(SK_Scalar1 + t*t), b)); |
|
653 s = -1 / u; |
|
654 c = -s * t; |
|
655 } else { |
|
656 SkScalar t = b / a; |
|
657 SkScalar u = SkDoubleToScalar(_copysign(SkScalarSqrt(SK_Scalar1 + t*t), a)); |
|
658 c = 1 / u; |
|
659 s = -c * t; |
|
660 } |
|
661 |
|
662 // G is the Given's Matrix for A (rotational matrix such that GA[0][1] == 0). |
|
663 SkMatrix G; |
|
664 G.setAll(c, -s, 0, |
|
665 s, c, 0, |
|
666 0, 0, SkScalarToPersp(SK_Scalar1)); |
|
667 |
|
668 // GA is the matrix A with rotation removed. |
|
669 SkMatrix GA(G); |
|
670 GA.preConcat(A); |
|
671 |
|
672 // realTextSize is the actual device size we want (as opposed to the size the user requested). |
|
673 // gdiTextSide is the size we request from GDI. |
|
674 // If the scale is negative, this means the matrix will do the flip anyway. |
|
675 SkScalar realTextSize = SkScalarAbs(GA.get(SkMatrix::kMScaleY)); |
|
676 SkScalar gdiTextSize = SkScalarRoundToScalar(realTextSize); |
|
677 if (gdiTextSize == 0) { |
|
678 gdiTextSize = SK_Scalar1; |
|
679 } |
|
680 |
|
681 // When not hinting, remove only the gdiTextSize scale which will be applied by GDI. |
|
682 // When GDI hinting, remove the entire Y scale to prevent 'subpixel' metrics. |
|
683 SkScalar scale = (fRec.getHinting() == SkPaint::kNo_Hinting || |
|
684 fRec.getHinting() == SkPaint::kSlight_Hinting) |
|
685 ? SkScalarInvert(gdiTextSize) |
|
686 : SkScalarInvert(realTextSize); |
|
687 |
|
688 // sA is the total matrix A without the textSize (so GDI knows the text size separately). |
|
689 // When this matrix is used with GetGlyphOutline, no further processing is needed. |
|
690 SkMatrix sA(A); |
|
691 sA.preScale(scale, scale); //remove text size |
|
692 |
|
693 // GsA is the non-rotational part of A without the text height scale. |
|
694 // This is what is used to find the magnitude of advances. |
|
695 SkMatrix GsA(GA); |
|
696 GsA.preScale(scale, scale); //remove text size, G is rotational so reorders with the scale. |
|
697 |
|
698 fGsA.eM11 = SkScalarToFIXED(GsA.get(SkMatrix::kMScaleX)); |
|
699 fGsA.eM12 = SkScalarToFIXED(-GsA.get(SkMatrix::kMSkewY)); // This should be ~0. |
|
700 fGsA.eM21 = SkScalarToFIXED(-GsA.get(SkMatrix::kMSkewX)); |
|
701 fGsA.eM22 = SkScalarToFIXED(GsA.get(SkMatrix::kMScaleY)); |
|
702 |
|
703 // fG_inv is G inverse, which is fairly simple since G is 2x2 rotational. |
|
704 fG_inv.setAll(G.get(SkMatrix::kMScaleX), -G.get(SkMatrix::kMSkewX), G.get(SkMatrix::kMTransX), |
|
705 -G.get(SkMatrix::kMSkewY), G.get(SkMatrix::kMScaleY), G.get(SkMatrix::kMTransY), |
|
706 G.get(SkMatrix::kMPersp0), G.get(SkMatrix::kMPersp1), G.get(SkMatrix::kMPersp2)); |
|
707 |
|
708 LOGFONT lf = typeface->fLogFont; |
|
709 lf.lfHeight = -SkScalarTruncToInt(gdiTextSize); |
|
710 lf.lfQuality = compute_quality(fRec); |
|
711 fFont = CreateFontIndirect(&lf); |
|
712 if (!fFont) { |
|
713 return; |
|
714 } |
|
715 |
|
716 fSavefont = (HFONT)SelectObject(fDDC, fFont); |
|
717 |
|
718 if (0 == GetTextMetrics(fDDC, &fTM)) { |
|
719 call_ensure_accessible(lf); |
|
720 if (0 == GetTextMetrics(fDDC, &fTM)) { |
|
721 fTM.tmPitchAndFamily = TMPF_TRUETYPE; |
|
722 } |
|
723 } |
|
724 |
|
725 XFORM xform; |
|
726 if (fTM.tmPitchAndFamily & TMPF_VECTOR) { |
|
727 // Used a logfont on a memory context, should never get a device font. |
|
728 // Therefore all TMPF_DEVICE will be PostScript fonts. |
|
729 |
|
730 // If TMPF_VECTOR is set, one of TMPF_TRUETYPE or TMPF_DEVICE means that |
|
731 // we have an outline font. Otherwise we have a vector FON, which is |
|
732 // scalable, but not an outline font. |
|
733 // This was determined by testing with Type1 PFM/PFB and |
|
734 // OpenTypeCFF OTF, as well as looking at Wine bugs and sources. |
|
735 if (fTM.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_DEVICE)) { |
|
736 // Truetype or PostScript. |
|
737 fType = SkScalerContext_GDI::kTrueType_Type; |
|
738 } else { |
|
739 // Stroked FON. |
|
740 fType = SkScalerContext_GDI::kLine_Type; |
|
741 } |
|
742 |
|
743 // fPost2x2 is column-major, left handed (y down). |
|
744 // XFORM 2x2 is row-major, left handed (y down). |
|
745 xform.eM11 = SkScalarToFloat(sA.get(SkMatrix::kMScaleX)); |
|
746 xform.eM12 = SkScalarToFloat(sA.get(SkMatrix::kMSkewY)); |
|
747 xform.eM21 = SkScalarToFloat(sA.get(SkMatrix::kMSkewX)); |
|
748 xform.eM22 = SkScalarToFloat(sA.get(SkMatrix::kMScaleY)); |
|
749 xform.eDx = 0; |
|
750 xform.eDy = 0; |
|
751 |
|
752 // MAT2 is row major, right handed (y up). |
|
753 fMat22.eM11 = float2FIXED(xform.eM11); |
|
754 fMat22.eM12 = float2FIXED(-xform.eM12); |
|
755 fMat22.eM21 = float2FIXED(-xform.eM21); |
|
756 fMat22.eM22 = float2FIXED(xform.eM22); |
|
757 |
|
758 if (needToRenderWithSkia(fRec)) { |
|
759 this->forceGenerateImageFromPath(); |
|
760 } |
|
761 |
|
762 // Create a hires matrix if we need linear metrics. |
|
763 if (this->isSubpixel()) { |
|
764 OUTLINETEXTMETRIC otm; |
|
765 UINT success = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm); |
|
766 if (0 == success) { |
|
767 call_ensure_accessible(lf); |
|
768 success = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm); |
|
769 } |
|
770 if (0 != success) { |
|
771 SkScalar upem = SkIntToScalar(otm.otmEMSquare); |
|
772 |
|
773 SkScalar gdiTextSizeToEMScale = upem / gdiTextSize; |
|
774 fHighResMat22.eM11 = float2FIXED(gdiTextSizeToEMScale); |
|
775 fHighResMat22.eM12 = float2FIXED(0); |
|
776 fHighResMat22.eM21 = float2FIXED(0); |
|
777 fHighResMat22.eM22 = float2FIXED(gdiTextSizeToEMScale); |
|
778 |
|
779 SkScalar removeEMScale = SkScalarInvert(upem); |
|
780 fHiResMatrix = A; |
|
781 fHiResMatrix.preScale(removeEMScale, removeEMScale); |
|
782 } |
|
783 } |
|
784 |
|
785 } else { |
|
786 // Assume bitmap |
|
787 fType = SkScalerContext_GDI::kBitmap_Type; |
|
788 |
|
789 xform.eM11 = 1.0f; |
|
790 xform.eM12 = 0.0f; |
|
791 xform.eM21 = 0.0f; |
|
792 xform.eM22 = 1.0f; |
|
793 xform.eDx = 0.0f; |
|
794 xform.eDy = 0.0f; |
|
795 |
|
796 // fPost2x2 is column-major, left handed (y down). |
|
797 // MAT2 is row major, right handed (y up). |
|
798 fMat22.eM11 = SkScalarToFIXED(fRec.fPost2x2[0][0]); |
|
799 fMat22.eM12 = SkScalarToFIXED(-fRec.fPost2x2[1][0]); |
|
800 fMat22.eM21 = SkScalarToFIXED(-fRec.fPost2x2[0][1]); |
|
801 fMat22.eM22 = SkScalarToFIXED(fRec.fPost2x2[1][1]); |
|
802 } |
|
803 |
|
804 fOffscreen.init(fFont, xform); |
|
805 } |
|
806 |
|
807 SkScalerContext_GDI::~SkScalerContext_GDI() { |
|
808 if (fDDC) { |
|
809 ::SelectObject(fDDC, fSavefont); |
|
810 ::DeleteDC(fDDC); |
|
811 } |
|
812 if (fFont) { |
|
813 ::DeleteObject(fFont); |
|
814 } |
|
815 if (fSC) { |
|
816 ::ScriptFreeCache(&fSC); |
|
817 } |
|
818 } |
|
819 |
|
820 bool SkScalerContext_GDI::isValid() const { |
|
821 return fDDC && fFont; |
|
822 } |
|
823 |
|
824 unsigned SkScalerContext_GDI::generateGlyphCount() { |
|
825 if (fGlyphCount < 0) { |
|
826 fGlyphCount = calculateGlyphCount( |
|
827 fDDC, static_cast<const LogFontTypeface*>(this->getTypeface())->fLogFont); |
|
828 } |
|
829 return fGlyphCount; |
|
830 } |
|
831 |
|
832 uint16_t SkScalerContext_GDI::generateCharToGlyph(SkUnichar utf32) { |
|
833 uint16_t index = 0; |
|
834 WCHAR utf16[2]; |
|
835 // TODO(ctguil): Support characters that generate more than one glyph. |
|
836 if (SkUTF16_FromUnichar(utf32, (uint16_t*)utf16) == 1) { |
|
837 // Type1 fonts fail with uniscribe API. Use GetGlyphIndices for plane 0. |
|
838 |
|
839 /** Real documentation for GetGlyphIndiciesW: |
|
840 * |
|
841 * When GGI_MARK_NONEXISTING_GLYPHS is not specified and a character does not map to a |
|
842 * glyph, then the 'default character's glyph is returned instead. The 'default character' |
|
843 * is available in fTM.tmDefaultChar. FON fonts have a default character, and there exists |
|
844 * a usDefaultChar in the 'OS/2' table, version 2 and later. If there is no |
|
845 * 'default character' specified by the font, then often the first character found is used. |
|
846 * |
|
847 * When GGI_MARK_NONEXISTING_GLYPHS is specified and a character does not map to a glyph, |
|
848 * then the glyph 0xFFFF is used. In Windows XP and earlier, Bitmap/Vector FON usually use |
|
849 * glyph 0x1F instead ('Terminal' appears to be special, returning 0xFFFF). |
|
850 * Type1 PFM/PFB, TT, OT TT, OT CFF all appear to use 0xFFFF, even on XP. |
|
851 */ |
|
852 DWORD result = GetGlyphIndicesW(fDDC, utf16, 1, &index, GGI_MARK_NONEXISTING_GLYPHS); |
|
853 if (result == GDI_ERROR |
|
854 || 0xFFFF == index |
|
855 || (0x1F == index && |
|
856 (fType == SkScalerContext_GDI::kBitmap_Type || |
|
857 fType == SkScalerContext_GDI::kLine_Type) |
|
858 /*&& winVer < Vista */) |
|
859 ) |
|
860 { |
|
861 index = 0; |
|
862 } |
|
863 } else { |
|
864 // Use uniscribe to detemine glyph index for non-BMP characters. |
|
865 static const int numWCHAR = 2; |
|
866 static const int maxItems = 2; |
|
867 // MSDN states that this can be NULL, but some things don't work then. |
|
868 SCRIPT_CONTROL sc = { 0 }; |
|
869 // Add extra item to SCRIPT_ITEM to work around a bug (now documented). |
|
870 // https://bugzilla.mozilla.org/show_bug.cgi?id=366643 |
|
871 SCRIPT_ITEM si[maxItems + 1]; |
|
872 int numItems; |
|
873 HRZM(ScriptItemize(utf16, numWCHAR, maxItems, &sc, NULL, si, &numItems), |
|
874 "Could not itemize character."); |
|
875 |
|
876 // Sometimes ScriptShape cannot find a glyph for a non-BMP and returns 2 space glyphs. |
|
877 static const int maxGlyphs = 2; |
|
878 SCRIPT_VISATTR vsa[maxGlyphs]; |
|
879 WORD outGlyphs[maxGlyphs]; |
|
880 WORD logClust[numWCHAR]; |
|
881 int numGlyphs; |
|
882 HRZM(ScriptShape(fDDC, &fSC, utf16, numWCHAR, maxGlyphs, &si[0].a, |
|
883 outGlyphs, logClust, vsa, &numGlyphs), |
|
884 "Could not shape character."); |
|
885 if (1 == numGlyphs) { |
|
886 index = outGlyphs[0]; |
|
887 } |
|
888 } |
|
889 return index; |
|
890 } |
|
891 |
|
892 void SkScalerContext_GDI::generateAdvance(SkGlyph* glyph) { |
|
893 this->generateMetrics(glyph); |
|
894 } |
|
895 |
|
896 void SkScalerContext_GDI::generateMetrics(SkGlyph* glyph) { |
|
897 SkASSERT(fDDC); |
|
898 |
|
899 if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) { |
|
900 SIZE size; |
|
901 WORD glyphs = glyph->getGlyphID(0); |
|
902 if (0 == GetTextExtentPointI(fDDC, &glyphs, 1, &size)) { |
|
903 glyph->fWidth = SkToS16(fTM.tmMaxCharWidth); |
|
904 } else { |
|
905 glyph->fWidth = SkToS16(size.cx); |
|
906 } |
|
907 glyph->fHeight = SkToS16(size.cy); |
|
908 |
|
909 glyph->fTop = SkToS16(-fTM.tmAscent); |
|
910 // Bitmap FON cannot underhang, but vector FON may. |
|
911 // There appears no means of determining underhang of vector FON. |
|
912 glyph->fLeft = SkToS16(0); |
|
913 glyph->fAdvanceX = SkIntToFixed(glyph->fWidth); |
|
914 glyph->fAdvanceY = 0; |
|
915 |
|
916 // Vector FON will transform nicely, but bitmap FON do not. |
|
917 if (fType == SkScalerContext_GDI::kLine_Type) { |
|
918 SkRect bounds = SkRect::MakeXYWH(glyph->fLeft, glyph->fTop, |
|
919 glyph->fWidth, glyph->fHeight); |
|
920 SkMatrix m; |
|
921 m.setAll(SkFIXEDToScalar(fMat22.eM11), -SkFIXEDToScalar(fMat22.eM21), 0, |
|
922 -SkFIXEDToScalar(fMat22.eM12), SkFIXEDToScalar(fMat22.eM22), 0, |
|
923 0, 0, SkScalarToPersp(SK_Scalar1)); |
|
924 m.mapRect(&bounds); |
|
925 bounds.roundOut(); |
|
926 glyph->fLeft = SkScalarTruncToInt(bounds.fLeft); |
|
927 glyph->fTop = SkScalarTruncToInt(bounds.fTop); |
|
928 glyph->fWidth = SkScalarTruncToInt(bounds.width()); |
|
929 glyph->fHeight = SkScalarTruncToInt(bounds.height()); |
|
930 } |
|
931 |
|
932 // Apply matrix to advance. |
|
933 glyph->fAdvanceY = SkFixedMul(-SkFIXEDToFixed(fMat22.eM12), glyph->fAdvanceX); |
|
934 glyph->fAdvanceX = SkFixedMul(SkFIXEDToFixed(fMat22.eM11), glyph->fAdvanceX); |
|
935 |
|
936 return; |
|
937 } |
|
938 |
|
939 UINT glyphId = glyph->getGlyphID(0); |
|
940 |
|
941 GLYPHMETRICS gm; |
|
942 sk_bzero(&gm, sizeof(gm)); |
|
943 |
|
944 DWORD status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22); |
|
945 if (GDI_ERROR == status) { |
|
946 LogFontTypeface::EnsureAccessible(this->getTypeface()); |
|
947 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22); |
|
948 if (GDI_ERROR == status) { |
|
949 glyph->zeroMetrics(); |
|
950 return; |
|
951 } |
|
952 } |
|
953 |
|
954 bool empty = false; |
|
955 // The black box is either the embedded bitmap size or the outline extent. |
|
956 // It is 1x1 if nothing is to be drawn, but will also be 1x1 if something very small |
|
957 // is to be drawn, like a '.'. We need to outset '.' but do not wish to outset ' '. |
|
958 if (1 == gm.gmBlackBoxX && 1 == gm.gmBlackBoxY) { |
|
959 // If GetGlyphOutline with GGO_NATIVE returns 0, we know there was no outline. |
|
960 DWORD bufferSize = GetGlyphOutlineW(fDDC, glyphId, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22); |
|
961 empty = (0 == bufferSize); |
|
962 } |
|
963 |
|
964 glyph->fTop = SkToS16(-gm.gmptGlyphOrigin.y); |
|
965 glyph->fLeft = SkToS16(gm.gmptGlyphOrigin.x); |
|
966 if (empty) { |
|
967 glyph->fWidth = 0; |
|
968 glyph->fHeight = 0; |
|
969 } else { |
|
970 // Outset, since the image may bleed out of the black box. |
|
971 // For embedded bitmaps the black box should be exact. |
|
972 // For outlines we need to outset by 1 in all directions for bleed. |
|
973 // For ClearType we need to outset by 2 for bleed. |
|
974 glyph->fWidth = gm.gmBlackBoxX + 4; |
|
975 glyph->fHeight = gm.gmBlackBoxY + 4; |
|
976 glyph->fTop -= 2; |
|
977 glyph->fLeft -= 2; |
|
978 } |
|
979 glyph->fAdvanceX = SkIntToFixed(gm.gmCellIncX); |
|
980 glyph->fAdvanceY = SkIntToFixed(gm.gmCellIncY); |
|
981 glyph->fRsbDelta = 0; |
|
982 glyph->fLsbDelta = 0; |
|
983 |
|
984 if (this->isSubpixel()) { |
|
985 sk_bzero(&gm, sizeof(gm)); |
|
986 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fHighResMat22); |
|
987 if (GDI_ERROR != status) { |
|
988 SkPoint advance; |
|
989 fHiResMatrix.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance); |
|
990 glyph->fAdvanceX = SkScalarToFixed(advance.fX); |
|
991 glyph->fAdvanceY = SkScalarToFixed(advance.fY); |
|
992 } |
|
993 } else if (!isAxisAligned(this->fRec)) { |
|
994 status = GetGlyphOutlineW(fDDC, glyphId, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fGsA); |
|
995 if (GDI_ERROR != status) { |
|
996 SkPoint advance; |
|
997 fG_inv.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance); |
|
998 glyph->fAdvanceX = SkScalarToFixed(advance.fX); |
|
999 glyph->fAdvanceY = SkScalarToFixed(advance.fY); |
|
1000 } |
|
1001 } |
|
1002 } |
|
1003 |
|
1004 static const MAT2 gMat2Identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}}; |
|
1005 void SkScalerContext_GDI::generateFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my) { |
|
1006 if (!(mx || my)) { |
|
1007 return; |
|
1008 } |
|
1009 |
|
1010 if (mx) { |
|
1011 sk_bzero(mx, sizeof(*mx)); |
|
1012 } |
|
1013 if (my) { |
|
1014 sk_bzero(my, sizeof(*my)); |
|
1015 } |
|
1016 |
|
1017 SkASSERT(fDDC); |
|
1018 |
|
1019 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS |
|
1020 if (fType == SkScalerContext_GDI::kBitmap_Type || fType == SkScalerContext_GDI::kLine_Type) { |
|
1021 #endif |
|
1022 if (mx) { |
|
1023 mx->fTop = SkIntToScalar(-fTM.tmAscent); |
|
1024 mx->fAscent = SkIntToScalar(-fTM.tmAscent); |
|
1025 mx->fDescent = SkIntToScalar(fTM.tmDescent); |
|
1026 mx->fBottom = SkIntToScalar(fTM.tmDescent); |
|
1027 mx->fLeading = SkIntToScalar(fTM.tmExternalLeading); |
|
1028 } |
|
1029 |
|
1030 if (my) { |
|
1031 my->fTop = SkIntToScalar(-fTM.tmAscent); |
|
1032 my->fAscent = SkIntToScalar(-fTM.tmAscent); |
|
1033 my->fDescent = SkIntToScalar(fTM.tmDescent); |
|
1034 my->fBottom = SkIntToScalar(fTM.tmDescent); |
|
1035 my->fLeading = SkIntToScalar(fTM.tmExternalLeading); |
|
1036 my->fAvgCharWidth = SkIntToScalar(fTM.tmAveCharWidth); |
|
1037 my->fMaxCharWidth = SkIntToScalar(fTM.tmMaxCharWidth); |
|
1038 my->fXMin = 0; |
|
1039 my->fXMax = my->fMaxCharWidth; |
|
1040 //my->fXHeight = 0; |
|
1041 } |
|
1042 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS |
|
1043 return; |
|
1044 } |
|
1045 #endif |
|
1046 |
|
1047 OUTLINETEXTMETRIC otm; |
|
1048 |
|
1049 uint32_t ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm); |
|
1050 if (0 == ret) { |
|
1051 LogFontTypeface::EnsureAccessible(this->getTypeface()); |
|
1052 ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm); |
|
1053 } |
|
1054 if (0 == ret) { |
|
1055 return; |
|
1056 } |
|
1057 |
|
1058 if (mx) { |
|
1059 mx->fTop = SkIntToScalar(-otm.otmrcFontBox.left); |
|
1060 mx->fAscent = SkIntToScalar(-otm.otmAscent); |
|
1061 mx->fDescent = SkIntToScalar(-otm.otmDescent); |
|
1062 mx->fBottom = SkIntToScalar(otm.otmrcFontBox.right); |
|
1063 mx->fLeading = SkIntToScalar(otm.otmLineGap); |
|
1064 mx->fUnderlineThickness = SkIntToScalar(otm.otmsUnderscoreSize); |
|
1065 mx->fUnderlinePosition = -SkIntToScalar(otm.otmsUnderscorePosition); |
|
1066 |
|
1067 mx->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag; |
|
1068 mx->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag; |
|
1069 } |
|
1070 |
|
1071 if (my) { |
|
1072 #ifndef SK_GDI_ALWAYS_USE_TEXTMETRICS_FOR_FONT_METRICS |
|
1073 my->fTop = SkIntToScalar(-otm.otmrcFontBox.top); |
|
1074 my->fAscent = SkIntToScalar(-otm.otmAscent); |
|
1075 my->fDescent = SkIntToScalar(-otm.otmDescent); |
|
1076 my->fBottom = SkIntToScalar(-otm.otmrcFontBox.bottom); |
|
1077 my->fLeading = SkIntToScalar(otm.otmLineGap); |
|
1078 my->fAvgCharWidth = SkIntToScalar(otm.otmTextMetrics.tmAveCharWidth); |
|
1079 my->fMaxCharWidth = SkIntToScalar(otm.otmTextMetrics.tmMaxCharWidth); |
|
1080 my->fXMin = SkIntToScalar(otm.otmrcFontBox.left); |
|
1081 my->fXMax = SkIntToScalar(otm.otmrcFontBox.right); |
|
1082 my->fUnderlineThickness = SkIntToScalar(otm.otmsUnderscoreSize); |
|
1083 my->fUnderlinePosition = -SkIntToScalar(otm.otmsUnderscorePosition); |
|
1084 |
|
1085 my->fFlags |= SkPaint::FontMetrics::kUnderlineThinknessIsValid_Flag; |
|
1086 my->fFlags |= SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag; |
|
1087 #endif |
|
1088 my->fXHeight = SkIntToScalar(otm.otmsXHeight); |
|
1089 |
|
1090 GLYPHMETRICS gm; |
|
1091 sk_bzero(&gm, sizeof(gm)); |
|
1092 DWORD len = GetGlyphOutlineW(fDDC, 'x', GGO_METRICS, &gm, 0, 0, &gMat2Identity); |
|
1093 if (len != GDI_ERROR && gm.gmBlackBoxY > 0) { |
|
1094 my->fXHeight = SkIntToScalar(gm.gmBlackBoxY); |
|
1095 } |
|
1096 } |
|
1097 } |
|
1098 |
|
1099 //////////////////////////////////////////////////////////////////////////////////////// |
|
1100 |
|
1101 #define SK_SHOW_TEXT_BLIT_COVERAGE 0 |
|
1102 |
|
1103 static void build_power_table(uint8_t table[], float ee) { |
|
1104 for (int i = 0; i < 256; i++) { |
|
1105 float x = i / 255.f; |
|
1106 x = sk_float_pow(x, ee); |
|
1107 int xx = SkScalarRoundToInt(x * 255); |
|
1108 table[i] = SkToU8(xx); |
|
1109 } |
|
1110 } |
|
1111 |
|
1112 /** |
|
1113 * This will invert the gamma applied by GDI (gray-scale antialiased), so we |
|
1114 * can get linear values. |
|
1115 * |
|
1116 * GDI grayscale appears to use a hard-coded gamma of 2.3. |
|
1117 * |
|
1118 * GDI grayscale appears to draw using the black and white rasterizer at four |
|
1119 * times the size and then downsamples to compute the coverage mask. As a |
|
1120 * result there are only seventeen total grays. This lack of fidelity means |
|
1121 * that shifting into other color spaces is imprecise. |
|
1122 */ |
|
1123 static const uint8_t* getInverseGammaTableGDI() { |
|
1124 // Since build_power_table is idempotent, many threads can build gTableGdi |
|
1125 // simultaneously. |
|
1126 |
|
1127 // Microsoft Specific: |
|
1128 // Making gInited volatile provides read-aquire and write-release in vc++. |
|
1129 // In VS2012, see compiler option /volatile:(ms|iso). |
|
1130 // Replace with C++11 atomics when possible. |
|
1131 static volatile bool gInited; |
|
1132 static uint8_t gTableGdi[256]; |
|
1133 if (gInited) { |
|
1134 // Need a L/L (read) barrier (full acquire not needed). If gInited is observed |
|
1135 // true then gTableGdi is observable, but it must be requested. |
|
1136 } else { |
|
1137 build_power_table(gTableGdi, 2.3f); |
|
1138 // Need a S/S (write) barrier (full release not needed) here so that this |
|
1139 // write to gInited becomes observable after gTableGdi. |
|
1140 gInited = true; |
|
1141 } |
|
1142 return gTableGdi; |
|
1143 } |
|
1144 |
|
1145 /** |
|
1146 * This will invert the gamma applied by GDI ClearType, so we can get linear |
|
1147 * values. |
|
1148 * |
|
1149 * GDI ClearType uses SPI_GETFONTSMOOTHINGCONTRAST / 1000 as the gamma value. |
|
1150 * If this value is not specified, the default is a gamma of 1.4. |
|
1151 */ |
|
1152 static const uint8_t* getInverseGammaTableClearType() { |
|
1153 // We don't expect SPI_GETFONTSMOOTHINGCONTRAST to ever change, so building |
|
1154 // gTableClearType with build_power_table is effectively idempotent. |
|
1155 |
|
1156 // Microsoft Specific: |
|
1157 // Making gInited volatile provides read-aquire and write-release in vc++. |
|
1158 // In VS2012, see compiler option /volatile:(ms|iso). |
|
1159 // Replace with C++11 atomics when possible. |
|
1160 static volatile bool gInited; |
|
1161 static uint8_t gTableClearType[256]; |
|
1162 if (gInited) { |
|
1163 // Need a L/L (read) barrier (acquire not needed). If gInited is observed |
|
1164 // true then gTableClearType is observable, but it must be requested. |
|
1165 } else { |
|
1166 UINT level = 0; |
|
1167 if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &level, 0) || !level) { |
|
1168 // can't get the data, so use a default |
|
1169 level = 1400; |
|
1170 } |
|
1171 build_power_table(gTableClearType, level / 1000.0f); |
|
1172 // Need a S/S (write) barrier (release not needed) here so that this |
|
1173 // write to gInited becomes observable after gTableClearType. |
|
1174 gInited = true; |
|
1175 } |
|
1176 return gTableClearType; |
|
1177 } |
|
1178 |
|
1179 #include "SkColorPriv.h" |
|
1180 |
|
1181 //Cannot assume that the input rgb is gray due to possible setting of kGenA8FromLCD_Flag. |
|
1182 template<bool APPLY_PREBLEND> |
|
1183 static inline uint8_t rgb_to_a8(SkGdiRGB rgb, const uint8_t* table8) { |
|
1184 U8CPU r = (rgb >> 16) & 0xFF; |
|
1185 U8CPU g = (rgb >> 8) & 0xFF; |
|
1186 U8CPU b = (rgb >> 0) & 0xFF; |
|
1187 return sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8); |
|
1188 } |
|
1189 |
|
1190 template<bool APPLY_PREBLEND> |
|
1191 static inline uint16_t rgb_to_lcd16(SkGdiRGB rgb, const uint8_t* tableR, |
|
1192 const uint8_t* tableG, |
|
1193 const uint8_t* tableB) { |
|
1194 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR); |
|
1195 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG); |
|
1196 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB); |
|
1197 #if SK_SHOW_TEXT_BLIT_COVERAGE |
|
1198 r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10); |
|
1199 #endif |
|
1200 return SkPack888ToRGB16(r, g, b); |
|
1201 } |
|
1202 |
|
1203 template<bool APPLY_PREBLEND> |
|
1204 static inline SkPMColor rgb_to_lcd32(SkGdiRGB rgb, const uint8_t* tableR, |
|
1205 const uint8_t* tableG, |
|
1206 const uint8_t* tableB) { |
|
1207 U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 16) & 0xFF, tableR); |
|
1208 U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 8) & 0xFF, tableG); |
|
1209 U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>((rgb >> 0) & 0xFF, tableB); |
|
1210 #if SK_SHOW_TEXT_BLIT_COVERAGE |
|
1211 r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10); |
|
1212 #endif |
|
1213 return SkPackARGB32(0xFF, r, g, b); |
|
1214 } |
|
1215 |
|
1216 // Is this GDI color neither black nor white? If so, we have to keep this |
|
1217 // image as is, rather than smashing it down to a BW mask. |
|
1218 // |
|
1219 // returns int instead of bool, since we don't want/have to pay to convert |
|
1220 // the zero/non-zero value into a bool |
|
1221 static int is_not_black_or_white(SkGdiRGB c) { |
|
1222 // same as (but faster than) |
|
1223 // c &= 0x00FFFFFF; |
|
1224 // return 0 == c || 0x00FFFFFF == c; |
|
1225 return (c + (c & 1)) & 0x00FFFFFF; |
|
1226 } |
|
1227 |
|
1228 static bool is_rgb_really_bw(const SkGdiRGB* src, int width, int height, size_t srcRB) { |
|
1229 for (int y = 0; y < height; ++y) { |
|
1230 for (int x = 0; x < width; ++x) { |
|
1231 if (is_not_black_or_white(src[x])) { |
|
1232 return false; |
|
1233 } |
|
1234 } |
|
1235 src = SkTAddOffset<const SkGdiRGB>(src, srcRB); |
|
1236 } |
|
1237 return true; |
|
1238 } |
|
1239 |
|
1240 // gdi's bitmap is upside-down, so we reverse dst walking in Y |
|
1241 // whenever we copy it into skia's buffer |
|
1242 static void rgb_to_bw(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, |
|
1243 const SkGlyph& glyph) { |
|
1244 const int width = glyph.fWidth; |
|
1245 const size_t dstRB = (width + 7) >> 3; |
|
1246 uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); |
|
1247 |
|
1248 int byteCount = width >> 3; |
|
1249 int bitCount = width & 7; |
|
1250 |
|
1251 // adjust srcRB to skip the values in our byteCount loop, |
|
1252 // since we increment src locally there |
|
1253 srcRB -= byteCount * 8 * sizeof(SkGdiRGB); |
|
1254 |
|
1255 for (int y = 0; y < glyph.fHeight; ++y) { |
|
1256 if (byteCount > 0) { |
|
1257 for (int i = 0; i < byteCount; ++i) { |
|
1258 unsigned byte = 0; |
|
1259 byte |= src[0] & (1 << 7); |
|
1260 byte |= src[1] & (1 << 6); |
|
1261 byte |= src[2] & (1 << 5); |
|
1262 byte |= src[3] & (1 << 4); |
|
1263 byte |= src[4] & (1 << 3); |
|
1264 byte |= src[5] & (1 << 2); |
|
1265 byte |= src[6] & (1 << 1); |
|
1266 byte |= src[7] & (1 << 0); |
|
1267 dst[i] = byte; |
|
1268 src += 8; |
|
1269 } |
|
1270 } |
|
1271 if (bitCount > 0) { |
|
1272 unsigned byte = 0; |
|
1273 unsigned mask = 0x80; |
|
1274 for (int i = 0; i < bitCount; i++) { |
|
1275 byte |= src[i] & mask; |
|
1276 mask >>= 1; |
|
1277 } |
|
1278 dst[byteCount] = byte; |
|
1279 } |
|
1280 src = SkTAddOffset<const SkGdiRGB>(src, srcRB); |
|
1281 dst -= dstRB; |
|
1282 } |
|
1283 #if SK_SHOW_TEXT_BLIT_COVERAGE |
|
1284 if (glyph.fWidth > 0 && glyph.fHeight > 0) { |
|
1285 uint8_t* first = (uint8_t*)glyph.fImage; |
|
1286 uint8_t* last = (uint8_t*)((char*)glyph.fImage + glyph.fHeight * dstRB - 1); |
|
1287 *first |= 1 << 7; |
|
1288 *last |= bitCount == 0 ? 1 : 1 << (8 - bitCount); |
|
1289 } |
|
1290 #endif |
|
1291 } |
|
1292 |
|
1293 template<bool APPLY_PREBLEND> |
|
1294 static void rgb_to_a8(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, |
|
1295 const SkGlyph& glyph, const uint8_t* table8) { |
|
1296 const size_t dstRB = glyph.rowBytes(); |
|
1297 const int width = glyph.fWidth; |
|
1298 uint8_t* SK_RESTRICT dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); |
|
1299 |
|
1300 for (int y = 0; y < glyph.fHeight; y++) { |
|
1301 for (int i = 0; i < width; i++) { |
|
1302 dst[i] = rgb_to_a8<APPLY_PREBLEND>(src[i], table8); |
|
1303 #if SK_SHOW_TEXT_BLIT_COVERAGE |
|
1304 dst[i] = SkMax32(dst[i], 10); |
|
1305 #endif |
|
1306 } |
|
1307 src = SkTAddOffset<const SkGdiRGB>(src, srcRB); |
|
1308 dst -= dstRB; |
|
1309 } |
|
1310 } |
|
1311 |
|
1312 template<bool APPLY_PREBLEND> |
|
1313 static void rgb_to_lcd16(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph, |
|
1314 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) { |
|
1315 const size_t dstRB = glyph.rowBytes(); |
|
1316 const int width = glyph.fWidth; |
|
1317 uint16_t* SK_RESTRICT dst = (uint16_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); |
|
1318 |
|
1319 for (int y = 0; y < glyph.fHeight; y++) { |
|
1320 for (int i = 0; i < width; i++) { |
|
1321 dst[i] = rgb_to_lcd16<APPLY_PREBLEND>(src[i], tableR, tableG, tableB); |
|
1322 } |
|
1323 src = SkTAddOffset<const SkGdiRGB>(src, srcRB); |
|
1324 dst = (uint16_t*)((char*)dst - dstRB); |
|
1325 } |
|
1326 } |
|
1327 |
|
1328 template<bool APPLY_PREBLEND> |
|
1329 static void rgb_to_lcd32(const SkGdiRGB* SK_RESTRICT src, size_t srcRB, const SkGlyph& glyph, |
|
1330 const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) { |
|
1331 const size_t dstRB = glyph.rowBytes(); |
|
1332 const int width = glyph.fWidth; |
|
1333 uint32_t* SK_RESTRICT dst = (uint32_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); |
|
1334 |
|
1335 for (int y = 0; y < glyph.fHeight; y++) { |
|
1336 for (int i = 0; i < width; i++) { |
|
1337 dst[i] = rgb_to_lcd32<APPLY_PREBLEND>(src[i], tableR, tableG, tableB); |
|
1338 } |
|
1339 src = SkTAddOffset<const SkGdiRGB>(src, srcRB); |
|
1340 dst = (uint32_t*)((char*)dst - dstRB); |
|
1341 } |
|
1342 } |
|
1343 |
|
1344 static inline unsigned clamp255(unsigned x) { |
|
1345 SkASSERT(x <= 256); |
|
1346 return x - (x >> 8); |
|
1347 } |
|
1348 |
|
1349 void SkScalerContext_GDI::generateImage(const SkGlyph& glyph) { |
|
1350 SkASSERT(fDDC); |
|
1351 |
|
1352 const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat; |
|
1353 const bool isAA = !isLCD(fRec); |
|
1354 |
|
1355 size_t srcRB; |
|
1356 const void* bits = fOffscreen.draw(glyph, isBW, &srcRB); |
|
1357 if (NULL == bits) { |
|
1358 LogFontTypeface::EnsureAccessible(this->getTypeface()); |
|
1359 bits = fOffscreen.draw(glyph, isBW, &srcRB); |
|
1360 if (NULL == bits) { |
|
1361 sk_bzero(glyph.fImage, glyph.computeImageSize()); |
|
1362 return; |
|
1363 } |
|
1364 } |
|
1365 |
|
1366 if (!isBW) { |
|
1367 const uint8_t* table; |
|
1368 //The offscreen contains a GDI blit if isAA and kGenA8FromLCD_Flag is not set. |
|
1369 //Otherwise the offscreen contains a ClearType blit. |
|
1370 if (isAA && !(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag)) { |
|
1371 table = getInverseGammaTableGDI(); |
|
1372 } else { |
|
1373 table = getInverseGammaTableClearType(); |
|
1374 } |
|
1375 //Note that the following cannot really be integrated into the |
|
1376 //pre-blend, since we may not be applying the pre-blend; when we aren't |
|
1377 //applying the pre-blend it means that a filter wants linear anyway. |
|
1378 //Other code may also be applying the pre-blend, so we'd need another |
|
1379 //one with this and one without. |
|
1380 SkGdiRGB* addr = (SkGdiRGB*)bits; |
|
1381 for (int y = 0; y < glyph.fHeight; ++y) { |
|
1382 for (int x = 0; x < glyph.fWidth; ++x) { |
|
1383 int r = (addr[x] >> 16) & 0xFF; |
|
1384 int g = (addr[x] >> 8) & 0xFF; |
|
1385 int b = (addr[x] >> 0) & 0xFF; |
|
1386 addr[x] = (table[r] << 16) | (table[g] << 8) | table[b]; |
|
1387 } |
|
1388 addr = SkTAddOffset<SkGdiRGB>(addr, srcRB); |
|
1389 } |
|
1390 } |
|
1391 |
|
1392 int width = glyph.fWidth; |
|
1393 size_t dstRB = glyph.rowBytes(); |
|
1394 if (isBW) { |
|
1395 const uint8_t* src = (const uint8_t*)bits; |
|
1396 uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB); |
|
1397 for (int y = 0; y < glyph.fHeight; y++) { |
|
1398 memcpy(dst, src, dstRB); |
|
1399 src += srcRB; |
|
1400 dst -= dstRB; |
|
1401 } |
|
1402 #if SK_SHOW_TEXT_BLIT_COVERAGE |
|
1403 if (glyph.fWidth > 0 && glyph.fHeight > 0) { |
|
1404 int bitCount = width & 7; |
|
1405 uint8_t* first = (uint8_t*)glyph.fImage; |
|
1406 uint8_t* last = (uint8_t*)((char*)glyph.fImage + glyph.fHeight * dstRB - 1); |
|
1407 *first |= 1 << 7; |
|
1408 *last |= bitCount == 0 ? 1 : 1 << (8 - bitCount); |
|
1409 } |
|
1410 #endif |
|
1411 } else if (isAA) { |
|
1412 // since the caller may require A8 for maskfilters, we can't check for BW |
|
1413 // ... until we have the caller tell us that explicitly |
|
1414 const SkGdiRGB* src = (const SkGdiRGB*)bits; |
|
1415 if (fPreBlend.isApplicable()) { |
|
1416 rgb_to_a8<true>(src, srcRB, glyph, fPreBlend.fG); |
|
1417 } else { |
|
1418 rgb_to_a8<false>(src, srcRB, glyph, fPreBlend.fG); |
|
1419 } |
|
1420 } else { // LCD16 |
|
1421 const SkGdiRGB* src = (const SkGdiRGB*)bits; |
|
1422 if (is_rgb_really_bw(src, width, glyph.fHeight, srcRB)) { |
|
1423 rgb_to_bw(src, srcRB, glyph); |
|
1424 ((SkGlyph*)&glyph)->fMaskFormat = SkMask::kBW_Format; |
|
1425 } else { |
|
1426 if (SkMask::kLCD16_Format == glyph.fMaskFormat) { |
|
1427 if (fPreBlend.isApplicable()) { |
|
1428 rgb_to_lcd16<true>(src, srcRB, glyph, |
|
1429 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); |
|
1430 } else { |
|
1431 rgb_to_lcd16<false>(src, srcRB, glyph, |
|
1432 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); |
|
1433 } |
|
1434 } else { |
|
1435 SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat); |
|
1436 if (fPreBlend.isApplicable()) { |
|
1437 rgb_to_lcd32<true>(src, srcRB, glyph, |
|
1438 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); |
|
1439 } else { |
|
1440 rgb_to_lcd32<false>(src, srcRB, glyph, |
|
1441 fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); |
|
1442 } |
|
1443 } |
|
1444 } |
|
1445 } |
|
1446 } |
|
1447 |
|
1448 class GDIGlyphbufferPointIter { |
|
1449 public: |
|
1450 GDIGlyphbufferPointIter(const uint8_t* glyphbuf, DWORD total_size) |
|
1451 : fHeaderIter(glyphbuf, total_size), fCurveIter(), fPointIter() |
|
1452 { } |
|
1453 |
|
1454 POINTFX const * next() { |
|
1455 nextHeader: |
|
1456 if (!fCurveIter.isSet()) { |
|
1457 const TTPOLYGONHEADER* header = fHeaderIter.next(); |
|
1458 if (NULL == header) { |
|
1459 return NULL; |
|
1460 } |
|
1461 fCurveIter.set(header); |
|
1462 const TTPOLYCURVE* curve = fCurveIter.next(); |
|
1463 if (NULL == curve) { |
|
1464 return NULL; |
|
1465 } |
|
1466 fPointIter.set(curve); |
|
1467 return &header->pfxStart; |
|
1468 } |
|
1469 |
|
1470 const POINTFX* nextPoint = fPointIter.next(); |
|
1471 if (NULL == nextPoint) { |
|
1472 const TTPOLYCURVE* curve = fCurveIter.next(); |
|
1473 if (NULL == curve) { |
|
1474 fCurveIter.set(); |
|
1475 goto nextHeader; |
|
1476 } else { |
|
1477 fPointIter.set(curve); |
|
1478 } |
|
1479 nextPoint = fPointIter.next(); |
|
1480 } |
|
1481 return nextPoint; |
|
1482 } |
|
1483 |
|
1484 WORD currentCurveType() { |
|
1485 return fPointIter.fCurveType; |
|
1486 } |
|
1487 |
|
1488 private: |
|
1489 /** Iterates over all of the polygon headers in a glyphbuf. */ |
|
1490 class GDIPolygonHeaderIter { |
|
1491 public: |
|
1492 GDIPolygonHeaderIter(const uint8_t* glyphbuf, DWORD total_size) |
|
1493 : fCurPolygon(reinterpret_cast<const TTPOLYGONHEADER*>(glyphbuf)) |
|
1494 , fEndPolygon(SkTAddOffset<const TTPOLYGONHEADER>(glyphbuf, total_size)) |
|
1495 { } |
|
1496 |
|
1497 const TTPOLYGONHEADER* next() { |
|
1498 if (fCurPolygon >= fEndPolygon) { |
|
1499 return NULL; |
|
1500 } |
|
1501 const TTPOLYGONHEADER* thisPolygon = fCurPolygon; |
|
1502 fCurPolygon = SkTAddOffset<const TTPOLYGONHEADER>(fCurPolygon, fCurPolygon->cb); |
|
1503 return thisPolygon; |
|
1504 } |
|
1505 private: |
|
1506 const TTPOLYGONHEADER* fCurPolygon; |
|
1507 const TTPOLYGONHEADER* fEndPolygon; |
|
1508 }; |
|
1509 |
|
1510 /** Iterates over all of the polygon curves in a polygon header. */ |
|
1511 class GDIPolygonCurveIter { |
|
1512 public: |
|
1513 GDIPolygonCurveIter() : fCurCurve(NULL), fEndCurve(NULL) { } |
|
1514 |
|
1515 GDIPolygonCurveIter(const TTPOLYGONHEADER* curPolygon) |
|
1516 : fCurCurve(SkTAddOffset<const TTPOLYCURVE>(curPolygon, sizeof(TTPOLYGONHEADER))) |
|
1517 , fEndCurve(SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon->cb)) |
|
1518 { } |
|
1519 |
|
1520 bool isSet() { return fCurCurve != NULL; } |
|
1521 |
|
1522 void set(const TTPOLYGONHEADER* curPolygon) { |
|
1523 fCurCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon, sizeof(TTPOLYGONHEADER)); |
|
1524 fEndCurve = SkTAddOffset<const TTPOLYCURVE>(curPolygon, curPolygon->cb); |
|
1525 } |
|
1526 void set() { |
|
1527 fCurCurve = NULL; |
|
1528 fEndCurve = NULL; |
|
1529 } |
|
1530 |
|
1531 const TTPOLYCURVE* next() { |
|
1532 if (fCurCurve >= fEndCurve) { |
|
1533 return NULL; |
|
1534 } |
|
1535 const TTPOLYCURVE* thisCurve = fCurCurve; |
|
1536 fCurCurve = SkTAddOffset<const TTPOLYCURVE>(fCurCurve, size_of_TTPOLYCURVE(*fCurCurve)); |
|
1537 return thisCurve; |
|
1538 } |
|
1539 private: |
|
1540 size_t size_of_TTPOLYCURVE(const TTPOLYCURVE& curve) { |
|
1541 return 2*sizeof(WORD) + curve.cpfx*sizeof(POINTFX); |
|
1542 } |
|
1543 const TTPOLYCURVE* fCurCurve; |
|
1544 const TTPOLYCURVE* fEndCurve; |
|
1545 }; |
|
1546 |
|
1547 /** Iterates over all of the polygon points in a polygon curve. */ |
|
1548 class GDIPolygonCurvePointIter { |
|
1549 public: |
|
1550 GDIPolygonCurvePointIter() : fCurveType(0), fCurPoint(NULL), fEndPoint(NULL) { } |
|
1551 |
|
1552 GDIPolygonCurvePointIter(const TTPOLYCURVE* curPolygon) |
|
1553 : fCurveType(curPolygon->wType) |
|
1554 , fCurPoint(&curPolygon->apfx[0]) |
|
1555 , fEndPoint(&curPolygon->apfx[curPolygon->cpfx]) |
|
1556 { } |
|
1557 |
|
1558 bool isSet() { return fCurPoint != NULL; } |
|
1559 |
|
1560 void set(const TTPOLYCURVE* curPolygon) { |
|
1561 fCurveType = curPolygon->wType; |
|
1562 fCurPoint = &curPolygon->apfx[0]; |
|
1563 fEndPoint = &curPolygon->apfx[curPolygon->cpfx]; |
|
1564 } |
|
1565 void set() { |
|
1566 fCurPoint = NULL; |
|
1567 fEndPoint = NULL; |
|
1568 } |
|
1569 |
|
1570 const POINTFX* next() { |
|
1571 if (fCurPoint >= fEndPoint) { |
|
1572 return NULL; |
|
1573 } |
|
1574 const POINTFX* thisPoint = fCurPoint; |
|
1575 ++fCurPoint; |
|
1576 return thisPoint; |
|
1577 } |
|
1578 |
|
1579 WORD fCurveType; |
|
1580 private: |
|
1581 const POINTFX* fCurPoint; |
|
1582 const POINTFX* fEndPoint; |
|
1583 }; |
|
1584 |
|
1585 GDIPolygonHeaderIter fHeaderIter; |
|
1586 GDIPolygonCurveIter fCurveIter; |
|
1587 GDIPolygonCurvePointIter fPointIter; |
|
1588 }; |
|
1589 |
|
1590 static void sk_path_from_gdi_path(SkPath* path, const uint8_t* glyphbuf, DWORD total_size) { |
|
1591 const uint8_t* cur_glyph = glyphbuf; |
|
1592 const uint8_t* end_glyph = glyphbuf + total_size; |
|
1593 |
|
1594 while (cur_glyph < end_glyph) { |
|
1595 const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph; |
|
1596 |
|
1597 const uint8_t* end_poly = cur_glyph + th->cb; |
|
1598 const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER); |
|
1599 |
|
1600 path->moveTo(SkFixedToScalar( SkFIXEDToFixed(th->pfxStart.x)), |
|
1601 SkFixedToScalar(-SkFIXEDToFixed(th->pfxStart.y))); |
|
1602 |
|
1603 while (cur_poly < end_poly) { |
|
1604 const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly; |
|
1605 |
|
1606 if (pc->wType == TT_PRIM_LINE) { |
|
1607 for (uint16_t i = 0; i < pc->cpfx; i++) { |
|
1608 path->lineTo(SkFixedToScalar( SkFIXEDToFixed(pc->apfx[i].x)), |
|
1609 SkFixedToScalar(-SkFIXEDToFixed(pc->apfx[i].y))); |
|
1610 } |
|
1611 } |
|
1612 |
|
1613 if (pc->wType == TT_PRIM_QSPLINE) { |
|
1614 for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline |
|
1615 POINTFX pnt_b = pc->apfx[u]; // B is always the current point |
|
1616 POINTFX pnt_c = pc->apfx[u+1]; |
|
1617 |
|
1618 if (u < pc->cpfx - 2) { // If not on last spline, compute C |
|
1619 pnt_c.x = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.x), |
|
1620 SkFIXEDToFixed(pnt_c.x))); |
|
1621 pnt_c.y = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.y), |
|
1622 SkFIXEDToFixed(pnt_c.y))); |
|
1623 } |
|
1624 |
|
1625 path->quadTo(SkFixedToScalar( SkFIXEDToFixed(pnt_b.x)), |
|
1626 SkFixedToScalar(-SkFIXEDToFixed(pnt_b.y)), |
|
1627 SkFixedToScalar( SkFIXEDToFixed(pnt_c.x)), |
|
1628 SkFixedToScalar(-SkFIXEDToFixed(pnt_c.y))); |
|
1629 } |
|
1630 } |
|
1631 // Advance past this TTPOLYCURVE. |
|
1632 cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx; |
|
1633 } |
|
1634 cur_glyph += th->cb; |
|
1635 path->close(); |
|
1636 } |
|
1637 } |
|
1638 |
|
1639 #define move_next_expected_hinted_point(iter, pElem) do {\ |
|
1640 pElem = iter.next(); \ |
|
1641 if (NULL == pElem) return false; \ |
|
1642 } while(0) |
|
1643 |
|
1644 // It is possible for the hinted and unhinted versions of the same path to have |
|
1645 // a different number of points due to GDI's handling of flipped points. |
|
1646 // If this is detected, this will return false. |
|
1647 static bool sk_path_from_gdi_paths(SkPath* path, const uint8_t* glyphbuf, DWORD total_size, |
|
1648 GDIGlyphbufferPointIter hintedYs) { |
|
1649 const uint8_t* cur_glyph = glyphbuf; |
|
1650 const uint8_t* end_glyph = glyphbuf + total_size; |
|
1651 |
|
1652 POINTFX const * hintedPoint; |
|
1653 |
|
1654 while (cur_glyph < end_glyph) { |
|
1655 const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph; |
|
1656 |
|
1657 const uint8_t* end_poly = cur_glyph + th->cb; |
|
1658 const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER); |
|
1659 |
|
1660 move_next_expected_hinted_point(hintedYs, hintedPoint); |
|
1661 path->moveTo(SkFixedToScalar( SkFIXEDToFixed(th->pfxStart.x)), |
|
1662 SkFixedToScalar(-SkFIXEDToFixed(hintedPoint->y))); |
|
1663 |
|
1664 while (cur_poly < end_poly) { |
|
1665 const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly; |
|
1666 |
|
1667 if (pc->wType == TT_PRIM_LINE) { |
|
1668 for (uint16_t i = 0; i < pc->cpfx; i++) { |
|
1669 move_next_expected_hinted_point(hintedYs, hintedPoint); |
|
1670 path->lineTo(SkFixedToScalar( SkFIXEDToFixed(pc->apfx[i].x)), |
|
1671 SkFixedToScalar(-SkFIXEDToFixed(hintedPoint->y))); |
|
1672 } |
|
1673 } |
|
1674 |
|
1675 if (pc->wType == TT_PRIM_QSPLINE) { |
|
1676 POINTFX currentPoint = pc->apfx[0]; |
|
1677 move_next_expected_hinted_point(hintedYs, hintedPoint); |
|
1678 // only take the hinted y if it wasn't flipped |
|
1679 if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) { |
|
1680 currentPoint.y = hintedPoint->y; |
|
1681 } |
|
1682 for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline |
|
1683 POINTFX pnt_b = currentPoint;//pc->apfx[u]; // B is always the current point |
|
1684 POINTFX pnt_c = pc->apfx[u+1]; |
|
1685 move_next_expected_hinted_point(hintedYs, hintedPoint); |
|
1686 // only take the hinted y if it wasn't flipped |
|
1687 if (hintedYs.currentCurveType() == TT_PRIM_QSPLINE) { |
|
1688 pnt_c.y = hintedPoint->y; |
|
1689 } |
|
1690 currentPoint.x = pnt_c.x; |
|
1691 currentPoint.y = pnt_c.y; |
|
1692 |
|
1693 if (u < pc->cpfx - 2) { // If not on last spline, compute C |
|
1694 pnt_c.x = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.x), |
|
1695 SkFIXEDToFixed(pnt_c.x))); |
|
1696 pnt_c.y = SkFixedToFIXED(SkFixedAve(SkFIXEDToFixed(pnt_b.y), |
|
1697 SkFIXEDToFixed(pnt_c.y))); |
|
1698 } |
|
1699 |
|
1700 path->quadTo(SkFixedToScalar( SkFIXEDToFixed(pnt_b.x)), |
|
1701 SkFixedToScalar(-SkFIXEDToFixed(pnt_b.y)), |
|
1702 SkFixedToScalar( SkFIXEDToFixed(pnt_c.x)), |
|
1703 SkFixedToScalar(-SkFIXEDToFixed(pnt_c.y))); |
|
1704 } |
|
1705 } |
|
1706 // Advance past this TTPOLYCURVE. |
|
1707 cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx; |
|
1708 } |
|
1709 cur_glyph += th->cb; |
|
1710 path->close(); |
|
1711 } |
|
1712 return true; |
|
1713 } |
|
1714 |
|
1715 DWORD SkScalerContext_GDI::getGDIGlyphPath(const SkGlyph& glyph, UINT flags, |
|
1716 SkAutoSTMalloc<BUFFERSIZE, uint8_t>* glyphbuf) |
|
1717 { |
|
1718 GLYPHMETRICS gm; |
|
1719 |
|
1720 DWORD total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, BUFFERSIZE, glyphbuf->get(), &fMat22); |
|
1721 // Sometimes GetGlyphOutlineW returns a number larger than BUFFERSIZE even if BUFFERSIZE > 0. |
|
1722 // It has been verified that this does not involve a buffer overrun. |
|
1723 if (GDI_ERROR == total_size || total_size > BUFFERSIZE) { |
|
1724 // GDI_ERROR because the BUFFERSIZE was too small, or because the data was not accessible. |
|
1725 // When the data is not accessable GetGlyphOutlineW fails rather quickly, |
|
1726 // so just try to get the size. If that fails then ensure the data is accessible. |
|
1727 total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, 0, NULL, &fMat22); |
|
1728 if (GDI_ERROR == total_size) { |
|
1729 LogFontTypeface::EnsureAccessible(this->getTypeface()); |
|
1730 total_size = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, 0, NULL, &fMat22); |
|
1731 if (GDI_ERROR == total_size) { |
|
1732 SkASSERT(false); |
|
1733 return 0; |
|
1734 } |
|
1735 } |
|
1736 |
|
1737 glyphbuf->reset(total_size); |
|
1738 |
|
1739 DWORD ret = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, total_size, glyphbuf->get(), &fMat22); |
|
1740 if (GDI_ERROR == ret) { |
|
1741 LogFontTypeface::EnsureAccessible(this->getTypeface()); |
|
1742 ret = GetGlyphOutlineW(fDDC, glyph.fID, flags, &gm, total_size, glyphbuf->get(), &fMat22); |
|
1743 if (GDI_ERROR == ret) { |
|
1744 SkASSERT(false); |
|
1745 return 0; |
|
1746 } |
|
1747 } |
|
1748 } |
|
1749 return total_size; |
|
1750 } |
|
1751 |
|
1752 void SkScalerContext_GDI::generatePath(const SkGlyph& glyph, SkPath* path) { |
|
1753 SkASSERT(&glyph && path); |
|
1754 SkASSERT(fDDC); |
|
1755 |
|
1756 path->reset(); |
|
1757 |
|
1758 // Out of all the fonts on a typical Windows box, |
|
1759 // 25% of glyphs require more than 2KB. |
|
1760 // 1% of glyphs require more than 4KB. |
|
1761 // 0.01% of glyphs require more than 8KB. |
|
1762 // 8KB is less than 1% of the normal 1MB stack on Windows. |
|
1763 // Note that some web fonts glyphs require more than 20KB. |
|
1764 //static const DWORD BUFFERSIZE = (1 << 13); |
|
1765 |
|
1766 //GDI only uses hinted outlines when axis aligned. |
|
1767 UINT format = GGO_NATIVE | GGO_GLYPH_INDEX; |
|
1768 if (fRec.getHinting() == SkPaint::kNo_Hinting || fRec.getHinting() == SkPaint::kSlight_Hinting){ |
|
1769 format |= GGO_UNHINTED; |
|
1770 } |
|
1771 SkAutoSTMalloc<BUFFERSIZE, uint8_t> glyphbuf(BUFFERSIZE); |
|
1772 DWORD total_size = getGDIGlyphPath(glyph, format, &glyphbuf); |
|
1773 if (0 == total_size) { |
|
1774 return; |
|
1775 } |
|
1776 |
|
1777 if (fRec.getHinting() != SkPaint::kSlight_Hinting) { |
|
1778 sk_path_from_gdi_path(path, glyphbuf, total_size); |
|
1779 } else { |
|
1780 //GDI only uses hinted outlines when axis aligned. |
|
1781 UINT format = GGO_NATIVE | GGO_GLYPH_INDEX; |
|
1782 |
|
1783 SkAutoSTMalloc<BUFFERSIZE, uint8_t> hintedGlyphbuf(BUFFERSIZE); |
|
1784 DWORD hinted_total_size = getGDIGlyphPath(glyph, format, &hintedGlyphbuf); |
|
1785 if (0 == hinted_total_size) { |
|
1786 return; |
|
1787 } |
|
1788 |
|
1789 if (!sk_path_from_gdi_paths(path, glyphbuf, total_size, |
|
1790 GDIGlyphbufferPointIter(hintedGlyphbuf, hinted_total_size))) |
|
1791 { |
|
1792 path->reset(); |
|
1793 sk_path_from_gdi_path(path, glyphbuf, total_size); |
|
1794 } |
|
1795 } |
|
1796 } |
|
1797 |
|
1798 static void logfont_for_name(const char* familyName, LOGFONT* lf) { |
|
1799 sk_bzero(lf, sizeof(LOGFONT)); |
|
1800 #ifdef UNICODE |
|
1801 // Get the buffer size needed first. |
|
1802 size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName, |
|
1803 -1, NULL, 0); |
|
1804 // Allocate a buffer (str_len already has terminating null |
|
1805 // accounted for). |
|
1806 wchar_t *wideFamilyName = new wchar_t[str_len]; |
|
1807 // Now actually convert the string. |
|
1808 ::MultiByteToWideChar(CP_UTF8, 0, familyName, -1, |
|
1809 wideFamilyName, str_len); |
|
1810 ::wcsncpy(lf->lfFaceName, wideFamilyName, LF_FACESIZE - 1); |
|
1811 delete [] wideFamilyName; |
|
1812 lf->lfFaceName[LF_FACESIZE-1] = L'\0'; |
|
1813 #else |
|
1814 ::strncpy(lf->lfFaceName, familyName, LF_FACESIZE - 1); |
|
1815 lf->lfFaceName[LF_FACESIZE - 1] = '\0'; |
|
1816 #endif |
|
1817 } |
|
1818 |
|
1819 void LogFontTypeface::onGetFontDescriptor(SkFontDescriptor* desc, |
|
1820 bool* isLocalStream) const { |
|
1821 // Get the actual name of the typeface. The logfont may not know this. |
|
1822 HFONT font = CreateFontIndirect(&fLogFont); |
|
1823 |
|
1824 HDC deviceContext = ::CreateCompatibleDC(NULL); |
|
1825 HFONT savefont = (HFONT)SelectObject(deviceContext, font); |
|
1826 |
|
1827 SkString familyName; |
|
1828 dcfontname_to_skstring(deviceContext, fLogFont, &familyName); |
|
1829 |
|
1830 if (deviceContext) { |
|
1831 ::SelectObject(deviceContext, savefont); |
|
1832 ::DeleteDC(deviceContext); |
|
1833 } |
|
1834 if (font) { |
|
1835 ::DeleteObject(font); |
|
1836 } |
|
1837 |
|
1838 desc->setFamilyName(familyName.c_str()); |
|
1839 *isLocalStream = this->fSerializeAsStream; |
|
1840 } |
|
1841 |
|
1842 static bool getWidthAdvance(HDC hdc, int gId, int16_t* advance) { |
|
1843 // Initialize the MAT2 structure to the identify transformation matrix. |
|
1844 static const MAT2 mat2 = {SkScalarToFIXED(1), SkScalarToFIXED(0), |
|
1845 SkScalarToFIXED(0), SkScalarToFIXED(1)}; |
|
1846 int flags = GGO_METRICS | GGO_GLYPH_INDEX; |
|
1847 GLYPHMETRICS gm; |
|
1848 if (GDI_ERROR == GetGlyphOutline(hdc, gId, flags, &gm, 0, NULL, &mat2)) { |
|
1849 return false; |
|
1850 } |
|
1851 SkASSERT(advance); |
|
1852 *advance = gm.gmCellIncX; |
|
1853 return true; |
|
1854 } |
|
1855 |
|
1856 SkAdvancedTypefaceMetrics* LogFontTypeface::onGetAdvancedTypefaceMetrics( |
|
1857 SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo, |
|
1858 const uint32_t* glyphIDs, |
|
1859 uint32_t glyphIDsCount) const { |
|
1860 LOGFONT lf = fLogFont; |
|
1861 SkAdvancedTypefaceMetrics* info = NULL; |
|
1862 |
|
1863 HDC hdc = CreateCompatibleDC(NULL); |
|
1864 HFONT font = CreateFontIndirect(&lf); |
|
1865 HFONT savefont = (HFONT)SelectObject(hdc, font); |
|
1866 HFONT designFont = NULL; |
|
1867 |
|
1868 const char stem_chars[] = {'i', 'I', '!', '1'}; |
|
1869 int16_t min_width; |
|
1870 unsigned glyphCount; |
|
1871 |
|
1872 // To request design units, create a logical font whose height is specified |
|
1873 // as unitsPerEm. |
|
1874 OUTLINETEXTMETRIC otm; |
|
1875 unsigned int otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm); |
|
1876 if (0 == otmRet) { |
|
1877 call_ensure_accessible(lf); |
|
1878 otmRet = GetOutlineTextMetrics(hdc, sizeof(otm), &otm); |
|
1879 } |
|
1880 if (!otmRet || !GetTextFace(hdc, LF_FACESIZE, lf.lfFaceName)) { |
|
1881 goto Error; |
|
1882 } |
|
1883 lf.lfHeight = -SkToS32(otm.otmEMSquare); |
|
1884 designFont = CreateFontIndirect(&lf); |
|
1885 SelectObject(hdc, designFont); |
|
1886 if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm)) { |
|
1887 goto Error; |
|
1888 } |
|
1889 glyphCount = calculateGlyphCount(hdc, fLogFont); |
|
1890 |
|
1891 info = new SkAdvancedTypefaceMetrics; |
|
1892 info->fEmSize = otm.otmEMSquare; |
|
1893 info->fMultiMaster = false; |
|
1894 info->fLastGlyphID = SkToU16(glyphCount - 1); |
|
1895 info->fStyle = 0; |
|
1896 tchar_to_skstring(lf.lfFaceName, &info->fFontName); |
|
1897 |
|
1898 if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) { |
|
1899 populate_glyph_to_unicode(hdc, glyphCount, &(info->fGlyphToUnicode)); |
|
1900 } |
|
1901 |
|
1902 if (glyphCount > 0 && |
|
1903 (otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE)) { |
|
1904 info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font; |
|
1905 } else { |
|
1906 info->fType = SkAdvancedTypefaceMetrics::kOther_Font; |
|
1907 info->fItalicAngle = 0; |
|
1908 info->fAscent = 0; |
|
1909 info->fDescent = 0; |
|
1910 info->fStemV = 0; |
|
1911 info->fCapHeight = 0; |
|
1912 info->fBBox = SkIRect::MakeEmpty(); |
|
1913 goto ReturnInfo; |
|
1914 } |
|
1915 |
|
1916 // If this bit is clear the font is a fixed pitch font. |
|
1917 if (!(otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) { |
|
1918 info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style; |
|
1919 } |
|
1920 if (otm.otmTextMetrics.tmItalic) { |
|
1921 info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style; |
|
1922 } |
|
1923 if (otm.otmTextMetrics.tmPitchAndFamily & FF_ROMAN) { |
|
1924 info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style; |
|
1925 } else if (otm.otmTextMetrics.tmPitchAndFamily & FF_SCRIPT) { |
|
1926 info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style; |
|
1927 } |
|
1928 |
|
1929 // The main italic angle of the font, in tenths of a degree counterclockwise |
|
1930 // from vertical. |
|
1931 info->fItalicAngle = otm.otmItalicAngle / 10; |
|
1932 info->fAscent = SkToS16(otm.otmTextMetrics.tmAscent); |
|
1933 info->fDescent = SkToS16(-otm.otmTextMetrics.tmDescent); |
|
1934 // TODO(ctguil): Use alternate cap height calculation. |
|
1935 // MSDN says otmsCapEmHeight is not support but it is returning a value on |
|
1936 // my Win7 box. |
|
1937 info->fCapHeight = otm.otmsCapEmHeight; |
|
1938 info->fBBox = |
|
1939 SkIRect::MakeLTRB(otm.otmrcFontBox.left, otm.otmrcFontBox.top, |
|
1940 otm.otmrcFontBox.right, otm.otmrcFontBox.bottom); |
|
1941 |
|
1942 // Figure out a good guess for StemV - Min width of i, I, !, 1. |
|
1943 // This probably isn't very good with an italic font. |
|
1944 min_width = SHRT_MAX; |
|
1945 info->fStemV = 0; |
|
1946 for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) { |
|
1947 ABC abcWidths; |
|
1948 if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) { |
|
1949 int16_t width = abcWidths.abcB; |
|
1950 if (width > 0 && width < min_width) { |
|
1951 min_width = width; |
|
1952 info->fStemV = min_width; |
|
1953 } |
|
1954 } |
|
1955 } |
|
1956 |
|
1957 // If bit 1 is set, the font may not be embedded in a document. |
|
1958 // If bit 1 is clear, the font can be embedded. |
|
1959 // If bit 2 is set, the embedding is read-only. |
|
1960 if (otm.otmfsType & 0x1) { |
|
1961 info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font; |
|
1962 } else if (perGlyphInfo & |
|
1963 SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) { |
|
1964 if (info->fStyle & SkAdvancedTypefaceMetrics::kFixedPitch_Style) { |
|
1965 appendRange(&info->fGlyphWidths, 0); |
|
1966 info->fGlyphWidths->fAdvance.append(1, &min_width); |
|
1967 finishRange(info->fGlyphWidths.get(), 0, |
|
1968 SkAdvancedTypefaceMetrics::WidthRange::kDefault); |
|
1969 } else { |
|
1970 info->fGlyphWidths.reset( |
|
1971 getAdvanceData(hdc, |
|
1972 glyphCount, |
|
1973 glyphIDs, |
|
1974 glyphIDsCount, |
|
1975 &getWidthAdvance)); |
|
1976 } |
|
1977 } |
|
1978 |
|
1979 Error: |
|
1980 ReturnInfo: |
|
1981 SelectObject(hdc, savefont); |
|
1982 DeleteObject(designFont); |
|
1983 DeleteObject(font); |
|
1984 DeleteDC(hdc); |
|
1985 |
|
1986 return info; |
|
1987 } |
|
1988 |
|
1989 //Dummy representation of a Base64 encoded GUID from create_unique_font_name. |
|
1990 #define BASE64_GUID_ID "XXXXXXXXXXXXXXXXXXXXXXXX" |
|
1991 //Length of GUID representation from create_id, including NULL terminator. |
|
1992 #define BASE64_GUID_ID_LEN SK_ARRAY_COUNT(BASE64_GUID_ID) |
|
1993 |
|
1994 SK_COMPILE_ASSERT(BASE64_GUID_ID_LEN < LF_FACESIZE, GUID_longer_than_facesize); |
|
1995 |
|
1996 /** |
|
1997 NameID 6 Postscript names cannot have the character '/'. |
|
1998 It would be easier to hex encode the GUID, but that is 32 bytes, |
|
1999 and many systems have issues with names longer than 28 bytes. |
|
2000 The following need not be any standard base64 encoding. |
|
2001 The encoded value is never decoded. |
|
2002 */ |
|
2003 static const char postscript_safe_base64_encode[] = |
|
2004 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
|
2005 "abcdefghijklmnopqrstuvwxyz" |
|
2006 "0123456789-_="; |
|
2007 |
|
2008 /** |
|
2009 Formats a GUID into Base64 and places it into buffer. |
|
2010 buffer should have space for at least BASE64_GUID_ID_LEN characters. |
|
2011 The string will always be null terminated. |
|
2012 XXXXXXXXXXXXXXXXXXXXXXXX0 |
|
2013 */ |
|
2014 static void format_guid_b64(const GUID& guid, char* buffer, size_t bufferSize) { |
|
2015 SkASSERT(bufferSize >= BASE64_GUID_ID_LEN); |
|
2016 size_t written = SkBase64::Encode(&guid, sizeof(guid), buffer, postscript_safe_base64_encode); |
|
2017 SkASSERT(written < LF_FACESIZE); |
|
2018 buffer[written] = '\0'; |
|
2019 } |
|
2020 |
|
2021 /** |
|
2022 Creates a Base64 encoded GUID and places it into buffer. |
|
2023 buffer should have space for at least BASE64_GUID_ID_LEN characters. |
|
2024 The string will always be null terminated. |
|
2025 XXXXXXXXXXXXXXXXXXXXXXXX0 |
|
2026 */ |
|
2027 static HRESULT create_unique_font_name(char* buffer, size_t bufferSize) { |
|
2028 GUID guid = {}; |
|
2029 if (FAILED(CoCreateGuid(&guid))) { |
|
2030 return E_UNEXPECTED; |
|
2031 } |
|
2032 format_guid_b64(guid, buffer, bufferSize); |
|
2033 |
|
2034 return S_OK; |
|
2035 } |
|
2036 |
|
2037 /** |
|
2038 Introduces a font to GDI. On failure will return NULL. The returned handle |
|
2039 should eventually be passed to RemoveFontMemResourceEx. |
|
2040 */ |
|
2041 static HANDLE activate_font(SkData* fontData) { |
|
2042 DWORD numFonts = 0; |
|
2043 //AddFontMemResourceEx just copies the data, but does not specify const. |
|
2044 HANDLE fontHandle = AddFontMemResourceEx(const_cast<void*>(fontData->data()), |
|
2045 static_cast<DWORD>(fontData->size()), |
|
2046 0, |
|
2047 &numFonts); |
|
2048 |
|
2049 if (fontHandle != NULL && numFonts < 1) { |
|
2050 RemoveFontMemResourceEx(fontHandle); |
|
2051 return NULL; |
|
2052 } |
|
2053 |
|
2054 return fontHandle; |
|
2055 } |
|
2056 |
|
2057 static SkTypeface* create_from_stream(SkStream* stream) { |
|
2058 // Create a unique and unpredictable font name. |
|
2059 // Avoids collisions and access from CSS. |
|
2060 char familyName[BASE64_GUID_ID_LEN]; |
|
2061 const int familyNameSize = SK_ARRAY_COUNT(familyName); |
|
2062 if (FAILED(create_unique_font_name(familyName, familyNameSize))) { |
|
2063 return NULL; |
|
2064 } |
|
2065 |
|
2066 // Change the name of the font. |
|
2067 SkAutoTUnref<SkData> rewrittenFontData(SkOTUtils::RenameFont(stream, familyName, familyNameSize-1)); |
|
2068 if (NULL == rewrittenFontData.get()) { |
|
2069 return NULL; |
|
2070 } |
|
2071 |
|
2072 // Register the font with GDI. |
|
2073 HANDLE fontReference = activate_font(rewrittenFontData.get()); |
|
2074 if (NULL == fontReference) { |
|
2075 return NULL; |
|
2076 } |
|
2077 |
|
2078 // Create the typeface. |
|
2079 LOGFONT lf; |
|
2080 logfont_for_name(familyName, &lf); |
|
2081 |
|
2082 return SkCreateFontMemResourceTypefaceFromLOGFONT(lf, fontReference); |
|
2083 } |
|
2084 |
|
2085 SkStream* LogFontTypeface::onOpenStream(int* ttcIndex) const { |
|
2086 *ttcIndex = 0; |
|
2087 |
|
2088 const DWORD kTTCTag = |
|
2089 SkEndian_SwapBE32(SkSetFourByteTag('t', 't', 'c', 'f')); |
|
2090 LOGFONT lf = fLogFont; |
|
2091 |
|
2092 HDC hdc = ::CreateCompatibleDC(NULL); |
|
2093 HFONT font = CreateFontIndirect(&lf); |
|
2094 HFONT savefont = (HFONT)SelectObject(hdc, font); |
|
2095 |
|
2096 SkMemoryStream* stream = NULL; |
|
2097 DWORD tables[2] = {kTTCTag, 0}; |
|
2098 for (int i = 0; i < SK_ARRAY_COUNT(tables); i++) { |
|
2099 DWORD bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0); |
|
2100 if (bufferSize == GDI_ERROR) { |
|
2101 call_ensure_accessible(lf); |
|
2102 bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0); |
|
2103 } |
|
2104 if (bufferSize != GDI_ERROR) { |
|
2105 stream = new SkMemoryStream(bufferSize); |
|
2106 if (GetFontData(hdc, tables[i], 0, (void*)stream->getMemoryBase(), bufferSize)) { |
|
2107 break; |
|
2108 } else { |
|
2109 delete stream; |
|
2110 stream = NULL; |
|
2111 } |
|
2112 } |
|
2113 } |
|
2114 |
|
2115 SelectObject(hdc, savefont); |
|
2116 DeleteObject(font); |
|
2117 DeleteDC(hdc); |
|
2118 |
|
2119 return stream; |
|
2120 } |
|
2121 |
|
2122 static void bmpCharsToGlyphs(HDC hdc, const WCHAR* bmpChars, int count, uint16_t* glyphs, |
|
2123 bool Ox1FHack) |
|
2124 { |
|
2125 DWORD result = GetGlyphIndicesW(hdc, bmpChars, count, glyphs, GGI_MARK_NONEXISTING_GLYPHS); |
|
2126 if (GDI_ERROR == result) { |
|
2127 for (int i = 0; i < count; ++i) { |
|
2128 glyphs[i] = 0; |
|
2129 } |
|
2130 return; |
|
2131 } |
|
2132 |
|
2133 if (Ox1FHack) { |
|
2134 for (int i = 0; i < count; ++i) { |
|
2135 if (0xFFFF == glyphs[i] || 0x1F == glyphs[i]) { |
|
2136 glyphs[i] = 0; |
|
2137 } |
|
2138 } |
|
2139 } else { |
|
2140 for (int i = 0; i < count; ++i) { |
|
2141 if (0xFFFF == glyphs[i]){ |
|
2142 glyphs[i] = 0; |
|
2143 } |
|
2144 } |
|
2145 } |
|
2146 } |
|
2147 |
|
2148 static uint16_t nonBmpCharToGlyph(HDC hdc, SCRIPT_CACHE* scriptCache, const WCHAR utf16[2]) { |
|
2149 uint16_t index = 0; |
|
2150 // Use uniscribe to detemine glyph index for non-BMP characters. |
|
2151 static const int numWCHAR = 2; |
|
2152 static const int maxItems = 2; |
|
2153 // MSDN states that this can be NULL, but some things don't work then. |
|
2154 SCRIPT_CONTROL scriptControl = { 0 }; |
|
2155 // Add extra item to SCRIPT_ITEM to work around a bug (now documented). |
|
2156 // https://bugzilla.mozilla.org/show_bug.cgi?id=366643 |
|
2157 SCRIPT_ITEM si[maxItems + 1]; |
|
2158 int numItems; |
|
2159 HRZM(ScriptItemize(utf16, numWCHAR, maxItems, &scriptControl, NULL, si, &numItems), |
|
2160 "Could not itemize character."); |
|
2161 |
|
2162 // Sometimes ScriptShape cannot find a glyph for a non-BMP and returns 2 space glyphs. |
|
2163 static const int maxGlyphs = 2; |
|
2164 SCRIPT_VISATTR vsa[maxGlyphs]; |
|
2165 WORD outGlyphs[maxGlyphs]; |
|
2166 WORD logClust[numWCHAR]; |
|
2167 int numGlyphs; |
|
2168 HRZM(ScriptShape(hdc, scriptCache, utf16, numWCHAR, maxGlyphs, &si[0].a, |
|
2169 outGlyphs, logClust, vsa, &numGlyphs), |
|
2170 "Could not shape character."); |
|
2171 if (1 == numGlyphs) { |
|
2172 index = outGlyphs[0]; |
|
2173 } |
|
2174 return index; |
|
2175 } |
|
2176 |
|
2177 class SkAutoHDC { |
|
2178 public: |
|
2179 SkAutoHDC(const LOGFONT& lf) |
|
2180 : fHdc(::CreateCompatibleDC(NULL)) |
|
2181 , fFont(::CreateFontIndirect(&lf)) |
|
2182 , fSavefont((HFONT)SelectObject(fHdc, fFont)) |
|
2183 { } |
|
2184 ~SkAutoHDC() { |
|
2185 SelectObject(fHdc, fSavefont); |
|
2186 DeleteObject(fFont); |
|
2187 DeleteDC(fHdc); |
|
2188 } |
|
2189 operator HDC() { return fHdc; } |
|
2190 private: |
|
2191 HDC fHdc; |
|
2192 HFONT fFont; |
|
2193 HFONT fSavefont; |
|
2194 }; |
|
2195 #define SkAutoHDC(...) SK_REQUIRE_LOCAL_VAR(SkAutoHDC) |
|
2196 |
|
2197 int LogFontTypeface::onCharsToGlyphs(const void* chars, Encoding encoding, |
|
2198 uint16_t userGlyphs[], int glyphCount) const |
|
2199 { |
|
2200 SkAutoHDC hdc(fLogFont); |
|
2201 |
|
2202 TEXTMETRIC tm; |
|
2203 if (0 == GetTextMetrics(hdc, &tm)) { |
|
2204 call_ensure_accessible(fLogFont); |
|
2205 if (0 == GetTextMetrics(hdc, &tm)) { |
|
2206 tm.tmPitchAndFamily = TMPF_TRUETYPE; |
|
2207 } |
|
2208 } |
|
2209 bool Ox1FHack = !(tm.tmPitchAndFamily & TMPF_VECTOR) /*&& winVer < Vista */; |
|
2210 |
|
2211 SkAutoSTMalloc<256, uint16_t> scratchGlyphs; |
|
2212 uint16_t* glyphs; |
|
2213 if (userGlyphs != NULL) { |
|
2214 glyphs = userGlyphs; |
|
2215 } else { |
|
2216 glyphs = scratchGlyphs.reset(glyphCount); |
|
2217 } |
|
2218 |
|
2219 SCRIPT_CACHE sc = 0; |
|
2220 switch (encoding) { |
|
2221 case SkTypeface::kUTF8_Encoding: { |
|
2222 static const int scratchCount = 256; |
|
2223 WCHAR scratch[scratchCount]; |
|
2224 int glyphIndex = 0; |
|
2225 const char* currentUtf8 = reinterpret_cast<const char*>(chars); |
|
2226 SkUnichar currentChar; |
|
2227 if (glyphCount) { |
|
2228 currentChar = SkUTF8_NextUnichar(¤tUtf8); |
|
2229 } |
|
2230 while (glyphIndex < glyphCount) { |
|
2231 // Try a run of bmp. |
|
2232 int glyphsLeft = SkTMin(glyphCount - glyphIndex, scratchCount); |
|
2233 int runLength = 0; |
|
2234 while (runLength < glyphsLeft && currentChar <= 0xFFFF) { |
|
2235 scratch[runLength] = static_cast<WCHAR>(currentChar); |
|
2236 ++runLength; |
|
2237 if (runLength < glyphsLeft) { |
|
2238 currentChar = SkUTF8_NextUnichar(¤tUtf8); |
|
2239 } |
|
2240 } |
|
2241 if (runLength) { |
|
2242 bmpCharsToGlyphs(hdc, scratch, runLength, &glyphs[glyphIndex], Ox1FHack); |
|
2243 glyphIndex += runLength; |
|
2244 } |
|
2245 |
|
2246 // Try a run of non-bmp. |
|
2247 while (glyphIndex < glyphCount && currentChar > 0xFFFF) { |
|
2248 SkUTF16_FromUnichar(currentChar, reinterpret_cast<uint16_t*>(scratch)); |
|
2249 glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, scratch); |
|
2250 ++glyphIndex; |
|
2251 if (glyphIndex < glyphCount) { |
|
2252 currentChar = SkUTF8_NextUnichar(¤tUtf8); |
|
2253 } |
|
2254 } |
|
2255 } |
|
2256 break; |
|
2257 } |
|
2258 case SkTypeface::kUTF16_Encoding: { |
|
2259 int glyphIndex = 0; |
|
2260 const WCHAR* currentUtf16 = reinterpret_cast<const WCHAR*>(chars); |
|
2261 while (glyphIndex < glyphCount) { |
|
2262 // Try a run of bmp. |
|
2263 int glyphsLeft = glyphCount - glyphIndex; |
|
2264 int runLength = 0; |
|
2265 while (runLength < glyphsLeft && !SkUTF16_IsHighSurrogate(currentUtf16[runLength])) { |
|
2266 ++runLength; |
|
2267 } |
|
2268 if (runLength) { |
|
2269 bmpCharsToGlyphs(hdc, currentUtf16, runLength, &glyphs[glyphIndex], Ox1FHack); |
|
2270 glyphIndex += runLength; |
|
2271 currentUtf16 += runLength; |
|
2272 } |
|
2273 |
|
2274 // Try a run of non-bmp. |
|
2275 while (glyphIndex < glyphCount && SkUTF16_IsHighSurrogate(*currentUtf16)) { |
|
2276 glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, currentUtf16); |
|
2277 ++glyphIndex; |
|
2278 currentUtf16 += 2; |
|
2279 } |
|
2280 } |
|
2281 break; |
|
2282 } |
|
2283 case SkTypeface::kUTF32_Encoding: { |
|
2284 static const int scratchCount = 256; |
|
2285 WCHAR scratch[scratchCount]; |
|
2286 int glyphIndex = 0; |
|
2287 const uint32_t* utf32 = reinterpret_cast<const uint32_t*>(chars); |
|
2288 while (glyphIndex < glyphCount) { |
|
2289 // Try a run of bmp. |
|
2290 int glyphsLeft = SkTMin(glyphCount - glyphIndex, scratchCount); |
|
2291 int runLength = 0; |
|
2292 while (runLength < glyphsLeft && utf32[glyphIndex + runLength] <= 0xFFFF) { |
|
2293 scratch[runLength] = static_cast<WCHAR>(utf32[glyphIndex + runLength]); |
|
2294 ++runLength; |
|
2295 } |
|
2296 if (runLength) { |
|
2297 bmpCharsToGlyphs(hdc, scratch, runLength, &glyphs[glyphIndex], Ox1FHack); |
|
2298 glyphIndex += runLength; |
|
2299 } |
|
2300 |
|
2301 // Try a run of non-bmp. |
|
2302 while (glyphIndex < glyphCount && utf32[glyphIndex] > 0xFFFF) { |
|
2303 SkUTF16_FromUnichar(utf32[glyphIndex], reinterpret_cast<uint16_t*>(scratch)); |
|
2304 glyphs[glyphIndex] = nonBmpCharToGlyph(hdc, &sc, scratch); |
|
2305 ++glyphIndex; |
|
2306 } |
|
2307 } |
|
2308 break; |
|
2309 } |
|
2310 default: |
|
2311 SK_CRASH(); |
|
2312 } |
|
2313 |
|
2314 if (sc) { |
|
2315 ::ScriptFreeCache(&sc); |
|
2316 } |
|
2317 |
|
2318 for (int i = 0; i < glyphCount; ++i) { |
|
2319 if (0 == glyphs[i]) { |
|
2320 return i; |
|
2321 } |
|
2322 } |
|
2323 return glyphCount; |
|
2324 } |
|
2325 |
|
2326 int LogFontTypeface::onCountGlyphs() const { |
|
2327 HDC hdc = ::CreateCompatibleDC(NULL); |
|
2328 HFONT font = CreateFontIndirect(&fLogFont); |
|
2329 HFONT savefont = (HFONT)SelectObject(hdc, font); |
|
2330 |
|
2331 unsigned int glyphCount = calculateGlyphCount(hdc, fLogFont); |
|
2332 |
|
2333 SelectObject(hdc, savefont); |
|
2334 DeleteObject(font); |
|
2335 DeleteDC(hdc); |
|
2336 |
|
2337 return glyphCount; |
|
2338 } |
|
2339 |
|
2340 int LogFontTypeface::onGetUPEM() const { |
|
2341 HDC hdc = ::CreateCompatibleDC(NULL); |
|
2342 HFONT font = CreateFontIndirect(&fLogFont); |
|
2343 HFONT savefont = (HFONT)SelectObject(hdc, font); |
|
2344 |
|
2345 unsigned int upem = calculateUPEM(hdc, fLogFont); |
|
2346 |
|
2347 SelectObject(hdc, savefont); |
|
2348 DeleteObject(font); |
|
2349 DeleteDC(hdc); |
|
2350 |
|
2351 return upem; |
|
2352 } |
|
2353 |
|
2354 SkTypeface::LocalizedStrings* LogFontTypeface::onCreateFamilyNameIterator() const { |
|
2355 SkTypeface::LocalizedStrings* nameIter = |
|
2356 SkOTUtils::LocalizedStrings_NameTable::CreateForFamilyNames(*this); |
|
2357 if (NULL == nameIter) { |
|
2358 SkString familyName; |
|
2359 this->getFamilyName(&familyName); |
|
2360 SkString language("und"); //undetermined |
|
2361 nameIter = new SkOTUtils::LocalizedStrings_SingleName(familyName, language); |
|
2362 } |
|
2363 return nameIter; |
|
2364 } |
|
2365 |
|
2366 int LogFontTypeface::onGetTableTags(SkFontTableTag tags[]) const { |
|
2367 SkSFNTHeader header; |
|
2368 if (sizeof(header) != this->onGetTableData(0, 0, sizeof(header), &header)) { |
|
2369 return 0; |
|
2370 } |
|
2371 |
|
2372 int numTables = SkEndian_SwapBE16(header.numTables); |
|
2373 |
|
2374 if (tags) { |
|
2375 size_t size = numTables * sizeof(SkSFNTHeader::TableDirectoryEntry); |
|
2376 SkAutoSTMalloc<0x20, SkSFNTHeader::TableDirectoryEntry> dir(numTables); |
|
2377 if (size != this->onGetTableData(0, sizeof(header), size, dir.get())) { |
|
2378 return 0; |
|
2379 } |
|
2380 |
|
2381 for (int i = 0; i < numTables; ++i) { |
|
2382 tags[i] = SkEndian_SwapBE32(dir[i].tag); |
|
2383 } |
|
2384 } |
|
2385 return numTables; |
|
2386 } |
|
2387 |
|
2388 size_t LogFontTypeface::onGetTableData(SkFontTableTag tag, size_t offset, |
|
2389 size_t length, void* data) const |
|
2390 { |
|
2391 LOGFONT lf = fLogFont; |
|
2392 |
|
2393 HDC hdc = ::CreateCompatibleDC(NULL); |
|
2394 HFONT font = CreateFontIndirect(&lf); |
|
2395 HFONT savefont = (HFONT)SelectObject(hdc, font); |
|
2396 |
|
2397 tag = SkEndian_SwapBE32(tag); |
|
2398 if (NULL == data) { |
|
2399 length = 0; |
|
2400 } |
|
2401 DWORD bufferSize = GetFontData(hdc, tag, (DWORD) offset, data, (DWORD) length); |
|
2402 if (bufferSize == GDI_ERROR) { |
|
2403 call_ensure_accessible(lf); |
|
2404 bufferSize = GetFontData(hdc, tag, (DWORD) offset, data, (DWORD) length); |
|
2405 } |
|
2406 |
|
2407 SelectObject(hdc, savefont); |
|
2408 DeleteObject(font); |
|
2409 DeleteDC(hdc); |
|
2410 |
|
2411 return bufferSize == GDI_ERROR ? 0 : bufferSize; |
|
2412 } |
|
2413 |
|
2414 SkScalerContext* LogFontTypeface::onCreateScalerContext(const SkDescriptor* desc) const { |
|
2415 SkScalerContext_GDI* ctx = SkNEW_ARGS(SkScalerContext_GDI, |
|
2416 (const_cast<LogFontTypeface*>(this), desc)); |
|
2417 if (!ctx->isValid()) { |
|
2418 SkDELETE(ctx); |
|
2419 ctx = NULL; |
|
2420 } |
|
2421 return ctx; |
|
2422 } |
|
2423 |
|
2424 void LogFontTypeface::onFilterRec(SkScalerContextRec* rec) const { |
|
2425 if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag || |
|
2426 rec->fFlags & SkScalerContext::kLCD_Vertical_Flag) |
|
2427 { |
|
2428 rec->fMaskFormat = SkMask::kA8_Format; |
|
2429 rec->fFlags |= SkScalerContext::kGenA8FromLCD_Flag; |
|
2430 } |
|
2431 |
|
2432 unsigned flagsWeDontSupport = SkScalerContext::kDevKernText_Flag | |
|
2433 SkScalerContext::kForceAutohinting_Flag | |
|
2434 SkScalerContext::kEmbeddedBitmapText_Flag | |
|
2435 SkScalerContext::kEmbolden_Flag | |
|
2436 SkScalerContext::kLCD_BGROrder_Flag | |
|
2437 SkScalerContext::kLCD_Vertical_Flag; |
|
2438 rec->fFlags &= ~flagsWeDontSupport; |
|
2439 |
|
2440 SkPaint::Hinting h = rec->getHinting(); |
|
2441 switch (h) { |
|
2442 case SkPaint::kNo_Hinting: |
|
2443 break; |
|
2444 case SkPaint::kSlight_Hinting: |
|
2445 // Only do slight hinting when axis aligned. |
|
2446 // TODO: re-enable slight hinting when FontHostTest can pass. |
|
2447 //if (!isAxisAligned(*rec)) { |
|
2448 h = SkPaint::kNo_Hinting; |
|
2449 //} |
|
2450 break; |
|
2451 case SkPaint::kNormal_Hinting: |
|
2452 case SkPaint::kFull_Hinting: |
|
2453 // TODO: need to be able to distinguish subpixel positioned glyphs |
|
2454 // and linear metrics. |
|
2455 //rec->fFlags &= ~SkScalerContext::kSubpixelPositioning_Flag; |
|
2456 h = SkPaint::kNormal_Hinting; |
|
2457 break; |
|
2458 default: |
|
2459 SkDEBUGFAIL("unknown hinting"); |
|
2460 } |
|
2461 //TODO: if this is a bitmap font, squash hinting and subpixel. |
|
2462 rec->setHinting(h); |
|
2463 |
|
2464 // turn this off since GDI might turn A8 into BW! Need a bigger fix. |
|
2465 #if 0 |
|
2466 // Disable LCD when rotated, since GDI's output is ugly |
|
2467 if (isLCD(*rec) && !isAxisAligned(*rec)) { |
|
2468 rec->fMaskFormat = SkMask::kA8_Format; |
|
2469 } |
|
2470 #endif |
|
2471 |
|
2472 if (!fCanBeLCD && isLCD(*rec)) { |
|
2473 rec->fMaskFormat = SkMask::kA8_Format; |
|
2474 rec->fFlags &= ~SkScalerContext::kGenA8FromLCD_Flag; |
|
2475 } |
|
2476 } |
|
2477 |
|
2478 /////////////////////////////////////////////////////////////////////////////// |
|
2479 |
|
2480 #include "SkFontMgr.h" |
|
2481 #include "SkDataTable.h" |
|
2482 |
|
2483 static bool valid_logfont_for_enum(const LOGFONT& lf) { |
|
2484 // TODO: Vector FON is unsupported and should not be listed. |
|
2485 return |
|
2486 // Ignore implicit vertical variants. |
|
2487 lf.lfFaceName[0] && lf.lfFaceName[0] != '@' |
|
2488 |
|
2489 // DEFAULT_CHARSET is used to get all fonts, but also implies all |
|
2490 // character sets. Filter assuming all fonts support ANSI_CHARSET. |
|
2491 && ANSI_CHARSET == lf.lfCharSet |
|
2492 ; |
|
2493 } |
|
2494 |
|
2495 /** An EnumFontFamExProc implementation which interprets builderParam as |
|
2496 * an SkTDArray<ENUMLOGFONTEX>* and appends logfonts which |
|
2497 * pass the valid_logfont_for_enum predicate. |
|
2498 */ |
|
2499 static int CALLBACK enum_family_proc(const LOGFONT* lf, const TEXTMETRIC*, |
|
2500 DWORD fontType, LPARAM builderParam) { |
|
2501 if (valid_logfont_for_enum(*lf)) { |
|
2502 SkTDArray<ENUMLOGFONTEX>* array = (SkTDArray<ENUMLOGFONTEX>*)builderParam; |
|
2503 *array->append() = *(ENUMLOGFONTEX*)lf; |
|
2504 } |
|
2505 return 1; // non-zero means continue |
|
2506 } |
|
2507 |
|
2508 static SkFontStyle compute_fontstyle(const LOGFONT& lf) { |
|
2509 return SkFontStyle(lf.lfWeight, SkFontStyle::kNormal_Width, |
|
2510 lf.lfItalic ? SkFontStyle::kItalic_Slant |
|
2511 : SkFontStyle::kUpright_Slant); |
|
2512 } |
|
2513 |
|
2514 class SkFontStyleSetGDI : public SkFontStyleSet { |
|
2515 public: |
|
2516 SkFontStyleSetGDI(const TCHAR familyName[]) { |
|
2517 LOGFONT lf; |
|
2518 sk_bzero(&lf, sizeof(lf)); |
|
2519 lf.lfCharSet = DEFAULT_CHARSET; |
|
2520 _tcscpy_s(lf.lfFaceName, familyName); |
|
2521 |
|
2522 HDC hdc = ::CreateCompatibleDC(NULL); |
|
2523 ::EnumFontFamiliesEx(hdc, &lf, enum_family_proc, (LPARAM)&fArray, 0); |
|
2524 ::DeleteDC(hdc); |
|
2525 } |
|
2526 |
|
2527 virtual int count() SK_OVERRIDE { |
|
2528 return fArray.count(); |
|
2529 } |
|
2530 |
|
2531 virtual void getStyle(int index, SkFontStyle* fs, SkString* styleName) SK_OVERRIDE { |
|
2532 if (fs) { |
|
2533 *fs = compute_fontstyle(fArray[index].elfLogFont); |
|
2534 } |
|
2535 if (styleName) { |
|
2536 const ENUMLOGFONTEX& ref = fArray[index]; |
|
2537 // For some reason, ENUMLOGFONTEX and LOGFONT disagree on their type in the |
|
2538 // non-unicode version. |
|
2539 // ENUMLOGFONTEX uses BYTE |
|
2540 // LOGFONT uses CHAR |
|
2541 // Here we assert they that the style name is logically the same (size) as |
|
2542 // a TCHAR, so we can use the same converter function. |
|
2543 SkASSERT(sizeof(TCHAR) == sizeof(ref.elfStyle[0])); |
|
2544 tchar_to_skstring((const TCHAR*)ref.elfStyle, styleName); |
|
2545 } |
|
2546 } |
|
2547 |
|
2548 virtual SkTypeface* createTypeface(int index) SK_OVERRIDE { |
|
2549 return SkCreateTypefaceFromLOGFONT(fArray[index].elfLogFont); |
|
2550 } |
|
2551 |
|
2552 virtual SkTypeface* matchStyle(const SkFontStyle& pattern) SK_OVERRIDE { |
|
2553 // todo: |
|
2554 return SkCreateTypefaceFromLOGFONT(fArray[0].elfLogFont); |
|
2555 } |
|
2556 |
|
2557 private: |
|
2558 SkTDArray<ENUMLOGFONTEX> fArray; |
|
2559 }; |
|
2560 |
|
2561 class SkFontMgrGDI : public SkFontMgr { |
|
2562 public: |
|
2563 SkFontMgrGDI() { |
|
2564 LOGFONT lf; |
|
2565 sk_bzero(&lf, sizeof(lf)); |
|
2566 lf.lfCharSet = DEFAULT_CHARSET; |
|
2567 |
|
2568 HDC hdc = ::CreateCompatibleDC(NULL); |
|
2569 ::EnumFontFamiliesEx(hdc, &lf, enum_family_proc, (LPARAM)&fLogFontArray, 0); |
|
2570 ::DeleteDC(hdc); |
|
2571 } |
|
2572 |
|
2573 protected: |
|
2574 virtual int onCountFamilies() const SK_OVERRIDE { |
|
2575 return fLogFontArray.count(); |
|
2576 } |
|
2577 |
|
2578 virtual void onGetFamilyName(int index, SkString* familyName) const SK_OVERRIDE { |
|
2579 SkASSERT((unsigned)index < (unsigned)fLogFontArray.count()); |
|
2580 tchar_to_skstring(fLogFontArray[index].elfLogFont.lfFaceName, familyName); |
|
2581 } |
|
2582 |
|
2583 virtual SkFontStyleSet* onCreateStyleSet(int index) const SK_OVERRIDE { |
|
2584 SkASSERT((unsigned)index < (unsigned)fLogFontArray.count()); |
|
2585 return SkNEW_ARGS(SkFontStyleSetGDI, (fLogFontArray[index].elfLogFont.lfFaceName)); |
|
2586 } |
|
2587 |
|
2588 virtual SkFontStyleSet* onMatchFamily(const char familyName[]) const SK_OVERRIDE { |
|
2589 if (NULL == familyName) { |
|
2590 familyName = ""; // do we need this check??? |
|
2591 } |
|
2592 LOGFONT lf; |
|
2593 logfont_for_name(familyName, &lf); |
|
2594 return SkNEW_ARGS(SkFontStyleSetGDI, (lf.lfFaceName)); |
|
2595 } |
|
2596 |
|
2597 virtual SkTypeface* onMatchFamilyStyle(const char familyName[], |
|
2598 const SkFontStyle& fontstyle) const SK_OVERRIDE { |
|
2599 // could be in base impl |
|
2600 SkAutoTUnref<SkFontStyleSet> sset(this->matchFamily(familyName)); |
|
2601 return sset->matchStyle(fontstyle); |
|
2602 } |
|
2603 |
|
2604 virtual SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember, |
|
2605 const SkFontStyle& fontstyle) const SK_OVERRIDE { |
|
2606 // could be in base impl |
|
2607 SkString familyName; |
|
2608 ((LogFontTypeface*)familyMember)->getFamilyName(&familyName); |
|
2609 return this->matchFamilyStyle(familyName.c_str(), fontstyle); |
|
2610 } |
|
2611 |
|
2612 virtual SkTypeface* onCreateFromStream(SkStream* stream, int ttcIndex) const SK_OVERRIDE { |
|
2613 return create_from_stream(stream); |
|
2614 } |
|
2615 |
|
2616 virtual SkTypeface* onCreateFromData(SkData* data, int ttcIndex) const SK_OVERRIDE { |
|
2617 // could be in base impl |
|
2618 SkAutoTUnref<SkStream> stream(SkNEW_ARGS(SkMemoryStream, (data))); |
|
2619 return this->createFromStream(stream); |
|
2620 } |
|
2621 |
|
2622 virtual SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const SK_OVERRIDE { |
|
2623 // could be in base impl |
|
2624 SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path)); |
|
2625 return this->createFromStream(stream); |
|
2626 } |
|
2627 |
|
2628 virtual SkTypeface* onLegacyCreateTypeface(const char familyName[], |
|
2629 unsigned styleBits) const SK_OVERRIDE { |
|
2630 LOGFONT lf; |
|
2631 if (NULL == familyName) { |
|
2632 lf = get_default_font(); |
|
2633 } else { |
|
2634 logfont_for_name(familyName, &lf); |
|
2635 } |
|
2636 setStyle(&lf, (SkTypeface::Style)styleBits); |
|
2637 return SkCreateTypefaceFromLOGFONT(lf); |
|
2638 } |
|
2639 |
|
2640 private: |
|
2641 SkTDArray<ENUMLOGFONTEX> fLogFontArray; |
|
2642 }; |
|
2643 |
|
2644 /////////////////////////////////////////////////////////////////////////////// |
|
2645 |
|
2646 SkFontMgr* SkFontMgr_New_GDI() { |
|
2647 return SkNEW(SkFontMgrGDI); |
|
2648 } |