• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  ** Copyright 2006, The Android Open Source Project
3  **
4  ** Licensed under the Apache License, Version 2.0 (the "License");
5  ** you may not use this file except in compliance with the License.
6  ** You may obtain a copy of the License at
7  **
8  **     http://www.apache.org/licenses/LICENSE-2.0
9  **
10  ** Unless required by applicable law or agreed to in writing, software
11  ** distributed under the License is distributed on an "AS IS" BASIS,
12  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  ** See the License for the specific language governing permissions and
14  ** limitations under the License.
15  */
16 
17 #include "SkString.h"
18 //#include "SkStream.h"
19 
20 #include "SkEndian.h"
21 #include "SkFontHost.h"
22 #include "SkDescriptor.h"
23 #include "SkAdvancedTypefaceMetrics.h"
24 #include "SkStream.h"
25 #include "SkThread.h"
26 #include "SkTypeface_win.h"
27 #include "SkTypefaceCache.h"
28 #include "SkUtils.h"
29 
30 #ifdef WIN32
31 #include "windows.h"
32 #include "tchar.h"
33 #include "Usp10.h"
34 
35 // client3d has to undefine this for now
36 #define CAN_USE_LOGFONT_NAME
37 
38 using namespace skia_advanced_typeface_metrics_utils;
39 
40 static const uint16_t BUFFERSIZE = (16384 - 32);
41 static uint8_t glyphbuf[BUFFERSIZE];
42 
43 // Give 1MB font cache budget
44 #define FONT_CACHE_MEMORY_BUDGET    (1024 * 1024)
45 
46 /**
47  *	Since LOGFONT wants its textsize as an int, and we support fractional sizes,
48  *  and since we have a cache of LOGFONTs for our tyepfaces, we always set the
49  *  lfHeight to a canonical size, and then we use the 2x2 matrix to achieve the
50  *  actual requested size.
51  */
52 static const int gCanonicalTextSize = 64;
53 
make_canonical(LOGFONT * lf)54 static void make_canonical(LOGFONT* lf) {
55 	lf->lfHeight = -gCanonicalTextSize;
56     lf->lfQuality = CLEARTYPE_QUALITY;//PROOF_QUALITY;
57     lf->lfCharSet = DEFAULT_CHARSET;
58 }
59 
getStyle(const LOGFONT & lf)60 static SkTypeface::Style getStyle(const LOGFONT& lf) {
61     unsigned style = 0;
62     if (lf.lfWeight >= FW_BOLD) {
63         style |= SkTypeface::kBold;
64     }
65     if (lf.lfItalic) {
66         style |= SkTypeface::kItalic;
67     }
68     return (SkTypeface::Style)style;
69 }
70 
setStyle(LOGFONT * lf,SkTypeface::Style style)71 static void setStyle(LOGFONT* lf, SkTypeface::Style style) {
72     lf->lfWeight = (style & SkTypeface::kBold) != 0 ? FW_BOLD : FW_NORMAL ;
73     lf->lfItalic = ((style & SkTypeface::kItalic) != 0);
74 }
75 
SkFixedToFIXED(SkFixed x)76 static inline FIXED SkFixedToFIXED(SkFixed x) {
77     return *(FIXED*)(&x);
78 }
79 
SkScalarToFIXED(SkScalar x)80 static inline FIXED SkScalarToFIXED(SkScalar x) {
81     return SkFixedToFIXED(SkScalarToFixed(x));
82 }
83 
calculateGlyphCount(HDC hdc)84 static unsigned calculateGlyphCount(HDC hdc) {
85     // The 'maxp' table stores the number of glyphs at offset 4, in 2 bytes.
86     const DWORD maxpTag =
87         SkEndian_SwapBE32(SkSetFourByteTag('m', 'a', 'x', 'p'));
88     uint16_t glyphs;
89     if (GetFontData(hdc, maxpTag, 4, &glyphs, sizeof(glyphs)) != GDI_ERROR) {
90         return SkEndian_SwapBE16(glyphs);
91     }
92 
93     // Binary search for glyph count.
94     static const MAT2 mat2 = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
95     int32_t max = SK_MaxU16 + 1;
96     int32_t min = 0;
97     GLYPHMETRICS gm;
98     while (min < max) {
99         int32_t mid = min + ((max - min) / 2);
100         if (GetGlyphOutlineW(hdc, mid, GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0,
101                              NULL, &mat2) == GDI_ERROR) {
102             max = mid;
103         } else {
104             min = mid + 1;
105         }
106     }
107     SkASSERT(min == max);
108     return min;
109 }
110 
GetFontStyle(const LOGFONT & lf)111 static SkTypeface::Style GetFontStyle(const LOGFONT& lf) {
112     int style = SkTypeface::kNormal;
113     if (lf.lfWeight == FW_SEMIBOLD || lf.lfWeight == FW_DEMIBOLD || lf.lfWeight == FW_BOLD)
114         style |= SkTypeface::kBold;
115     if (lf.lfItalic)
116         style |= SkTypeface::kItalic;
117 
118     return (SkTypeface::Style)style;
119 }
120 
121 class LogFontTypeface : public SkTypeface {
122 public:
LogFontTypeface(SkTypeface::Style style,SkFontID fontID,const LOGFONT & lf)123     LogFontTypeface(SkTypeface::Style style, SkFontID fontID, const LOGFONT& lf) :
124       SkTypeface(style, fontID, false), fLogFont(lf) {}
125 
126     LOGFONT fLogFont;
127 
Create(const LOGFONT & lf)128     static LogFontTypeface* Create(const LOGFONT& lf) {
129         SkTypeface::Style style = GetFontStyle(lf);
130         SkFontID fontID = SkTypefaceCache::NewFontID();
131         return new LogFontTypeface(style, fontID, lf);
132     }
133 };
134 
get_default_font()135 static const LOGFONT& get_default_font() {
136     static LOGFONT gDefaultFont;
137     // don't hardcode on Windows, Win2000, XP, Vista, and international all have different default
138     // and the user could change too
139 
140 
141 //  lfMessageFont is garbage on my XP, so skip for now
142 #if 0
143     if (gDefaultFont.lfFaceName[0] != 0) {
144         return gDefaultFont;
145     }
146 
147     NONCLIENTMETRICS ncm;
148     ncm.cbSize = sizeof(NONCLIENTMETRICS);
149     SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
150 
151     //memcpy(&gDefaultFont, &(ncm.lfMessageFont), sizeof(LOGFONT));
152 #endif
153 
154     return gDefaultFont;
155 }
156 
FindByLogFont(SkTypeface * face,SkTypeface::Style requestedStyle,void * ctx)157 static bool FindByLogFont(SkTypeface* face, SkTypeface::Style requestedStyle, void* ctx) {
158     LogFontTypeface* lface = reinterpret_cast<LogFontTypeface*>(face);
159     const LOGFONT* lf = reinterpret_cast<const LOGFONT*>(ctx);
160 
161     return getStyle(lface->fLogFont) == requestedStyle &&
162            !memcmp(&lface->fLogFont, lf, sizeof(LOGFONT));
163 }
164 
165 /**
166  *  This guy is public. It first searches the cache, and if a match is not found,
167  *  it creates a new face.
168  */
SkCreateTypefaceFromLOGFONT(const LOGFONT & origLF)169 SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT& origLF) {
170     LOGFONT lf = origLF;
171     make_canonical(&lf);
172     SkTypeface* face = SkTypefaceCache::FindByProc(FindByLogFont, &lf);
173     if (face) {
174         face->ref();
175     } else {
176         face = LogFontTypeface::Create(lf);
177         SkTypefaceCache::Add(face, getStyle(lf));
178     }
179     return face;
180 }
181 
NextLogicalFont(SkFontID currFontID,SkFontID origFontID)182 SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
183   // Zero means that we don't have any fallback fonts for this fontID.
184   // This function is implemented on Android, but doesn't have much
185   // meaning here.
186   return 0;
187 }
188 
GetLogFontByID(SkFontID fontID,LOGFONT * lf)189 static void GetLogFontByID(SkFontID fontID, LOGFONT* lf) {
190     LogFontTypeface* face = (LogFontTypeface*)SkTypefaceCache::FindByID(fontID);
191     if (face) {
192         *lf = face->fLogFont;
193     } else {
194         sk_bzero(lf, sizeof(LOGFONT));
195     }
196 }
197 
198 // Construct Glyph to Unicode table.
199 // Unicode code points that require conjugate pairs in utf16 are not
200 // supported.
201 // TODO(arthurhsu): Add support for conjugate pairs. It looks like that may
202 // require parsing the TTF cmap table (platform 4, encoding 12) directly instead
203 // of calling GetFontUnicodeRange().
populate_glyph_to_unicode(HDC fontHdc,const unsigned glyphCount,SkTDArray<SkUnichar> * glyphToUnicode)204 static void populate_glyph_to_unicode(HDC fontHdc, const unsigned glyphCount,
205                                       SkTDArray<SkUnichar>* glyphToUnicode) {
206     DWORD glyphSetBufferSize = GetFontUnicodeRanges(fontHdc, NULL);
207     if (!glyphSetBufferSize) {
208         return;
209     }
210 
211     SkAutoTDeleteArray<BYTE> glyphSetBuffer(new BYTE[glyphSetBufferSize]);
212     GLYPHSET* glyphSet =
213         reinterpret_cast<LPGLYPHSET>(glyphSetBuffer.get());
214     if (GetFontUnicodeRanges(fontHdc, glyphSet) != glyphSetBufferSize) {
215         return;
216     }
217 
218     glyphToUnicode->setCount(glyphCount);
219     memset(glyphToUnicode->begin(), 0, glyphCount * sizeof(SkUnichar));
220     for (DWORD i = 0; i < glyphSet->cRanges; ++i) {
221         // There is no guarantee that within a Unicode range, the corresponding
222         // glyph id in a font file are continuous. So, even if we have ranges,
223         // we can't just use the first and last entry of the range to compute
224         // result. We need to enumerate them one by one.
225         int count = glyphSet->ranges[i].cGlyphs;
226         SkAutoTArray<WCHAR> chars(count + 1);
227         chars[count] = 0;  // termintate string
228         SkAutoTArray<WORD> glyph(count);
229         for (USHORT j = 0; j < count; ++j) {
230             chars[j] = glyphSet->ranges[i].wcLow + j;
231         }
232         GetGlyphIndicesW(fontHdc, chars.get(), count, glyph.get(),
233                          GGI_MARK_NONEXISTING_GLYPHS);
234         // If the glyph ID is valid, and the glyph is not mapped, then we will
235         // fill in the char id into the vector. If the glyph is mapped already,
236         // skip it.
237         // TODO(arthurhsu): better improve this. e.g. Get all used char ids from
238         // font cache, then generate this mapping table from there. It's
239         // unlikely to have collisions since glyph reuse happens mostly for
240         // different Unicode pages.
241         for (USHORT j = 0; j < count; ++j) {
242             if (glyph[j] != 0xffff && glyph[j] < glyphCount &&
243                 (*glyphToUnicode)[glyph[j]] == 0) {
244                 (*glyphToUnicode)[glyph[j]] = chars[j];
245             }
246         }
247     }
248 }
249 
250 //////////////////////////////////////////////////////////////////////////////////////////////
251 
252 class SkScalerContext_Windows : public SkScalerContext {
253 public:
254     SkScalerContext_Windows(const SkDescriptor* desc);
255     virtual ~SkScalerContext_Windows();
256 
257 protected:
258     virtual unsigned generateGlyphCount();
259     virtual uint16_t generateCharToGlyph(SkUnichar uni);
260     virtual void generateAdvance(SkGlyph* glyph);
261     virtual void generateMetrics(SkGlyph* glyph);
262     virtual void generateImage(const SkGlyph& glyph);
263     virtual void generatePath(const SkGlyph& glyph, SkPath* path);
264     virtual void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY);
265     //virtual SkDeviceContext getDC() {return ddc;}
266 private:
267 	SkScalar	 fScale;	// to get from canonical size to real size
268     MAT2         fMat22;
269     XFORM        fXform;
270     HDC          fDDC;
271     HFONT        fSavefont;
272     HFONT        fFont;
273     SCRIPT_CACHE fSC;
274     int          fGlyphCount;
275 
276     HFONT        fHiResFont;
277     MAT2         fMat22Identity;
278     SkMatrix     fHiResMatrix;
279 };
280 
mul2float(SkScalar a,SkScalar b)281 static float mul2float(SkScalar a, SkScalar b) {
282     return SkScalarToFloat(SkScalarMul(a, b));
283 }
284 
float2FIXED(float x)285 static FIXED float2FIXED(float x) {
286     return SkFixedToFIXED(SkFloatToFixed(x));
287 }
288 
289 static SkMutex gFTMutex;
290 
291 #define HIRES_TEXTSIZE  2048
292 #define HIRES_SHIFT     11
HiResToFixed(int value)293 static inline SkFixed HiResToFixed(int value) {
294     return value << (16 - HIRES_SHIFT);
295 }
296 
needHiResMetrics(const SkScalar mat[2][2])297 static bool needHiResMetrics(const SkScalar mat[2][2]) {
298     return mat[1][0] || mat[0][1];
299 }
300 
SkScalerContext_Windows(const SkDescriptor * desc)301 SkScalerContext_Windows::SkScalerContext_Windows(const SkDescriptor* desc)
302         : SkScalerContext(desc), fDDC(0), fFont(0), fSavefont(0), fSC(0)
303         , fGlyphCount(-1) {
304     SkAutoMutexAcquire  ac(gFTMutex);
305 
306 	fScale = fRec.fTextSize / gCanonicalTextSize;
307 
308     fXform.eM11 = mul2float(fScale, fRec.fPost2x2[0][0]);
309     fXform.eM12 = mul2float(fScale, fRec.fPost2x2[1][0]);
310     fXform.eM21 = mul2float(fScale, fRec.fPost2x2[0][1]);
311     fXform.eM22 = mul2float(fScale, fRec.fPost2x2[1][1]);
312     fXform.eDx = 0;
313     fXform.eDy = 0;
314 
315     fMat22.eM11 = float2FIXED(fXform.eM11);
316     fMat22.eM12 = float2FIXED(fXform.eM12);
317     fMat22.eM21 = float2FIXED(-fXform.eM21);
318     fMat22.eM22 = float2FIXED(-fXform.eM22);
319 
320     fDDC = ::CreateCompatibleDC(NULL);
321     SetGraphicsMode(fDDC, GM_ADVANCED);
322     SetBkMode(fDDC, TRANSPARENT);
323 
324     // Scaling by the DPI is inconsistent with how Skia draws elsewhere
325     //SkScalar height = -(fRec.fTextSize * GetDeviceCaps(ddc, LOGPIXELSY) / 72);
326     LOGFONT lf;
327     GetLogFontByID(fRec.fFontID, &lf);
328     lf.lfHeight = -gCanonicalTextSize;
329     fFont = CreateFontIndirect(&lf);
330 
331     // if we're rotated, or want fractional widths, create a hires font
332     fHiResFont = 0;
333     if (needHiResMetrics(fRec.fPost2x2) || (fRec.fFlags & kSubpixelPositioning_Flag)) {
334         lf.lfHeight = -HIRES_TEXTSIZE;
335         fHiResFont = CreateFontIndirect(&lf);
336 
337         fMat22Identity.eM11 = fMat22Identity.eM22 = SkFixedToFIXED(SK_Fixed1);
338         fMat22Identity.eM12 = fMat22Identity.eM21 = SkFixedToFIXED(0);
339 
340         // construct a matrix to go from HIRES logical units to our device units
341         fRec.getSingleMatrix(&fHiResMatrix);
342         SkScalar scale = SkScalarInvert(SkIntToScalar(HIRES_TEXTSIZE));
343         fHiResMatrix.preScale(scale, scale);
344     }
345     fSavefont = (HFONT)SelectObject(fDDC, fFont);
346 }
347 
~SkScalerContext_Windows()348 SkScalerContext_Windows::~SkScalerContext_Windows() {
349     if (fDDC) {
350         ::SelectObject(fDDC, fSavefont);
351         ::DeleteDC(fDDC);
352     }
353     if (fFont) {
354         ::DeleteObject(fFont);
355     }
356     if (fHiResFont) {
357         ::DeleteObject(fHiResFont);
358     }
359     if (fSC) {
360         ::ScriptFreeCache(&fSC);
361     }
362 }
363 
generateGlyphCount()364 unsigned SkScalerContext_Windows::generateGlyphCount() {
365     if (fGlyphCount < 0) {
366         fGlyphCount = calculateGlyphCount(fDDC);
367     }
368     return fGlyphCount;
369 }
370 
generateCharToGlyph(SkUnichar uni)371 uint16_t SkScalerContext_Windows::generateCharToGlyph(SkUnichar uni) {
372     uint16_t index = 0;
373     WCHAR c[2];
374     // TODO(ctguil): Support characters that generate more than one glyph.
375     if (SkUTF16_FromUnichar(uni, (uint16_t*)c) == 1) {
376         // Type1 fonts fail with uniscribe API. Use GetGlyphIndices for plane 0.
377         SkAssertResult(GetGlyphIndicesW(fDDC, c, 1, &index, 0));
378     } else {
379         // Use uniscribe to detemine glyph index for non-BMP characters.
380         // Need to add extra item to SCRIPT_ITEM to work around a bug in older
381         // windows versions. https://bugzilla.mozilla.org/show_bug.cgi?id=366643
382         SCRIPT_ITEM si[2 + 1];
383         int items;
384         SkAssertResult(
385             SUCCEEDED(ScriptItemize(c, 2, 2, NULL, NULL, si, &items)));
386 
387         WORD log[2];
388         SCRIPT_VISATTR vsa;
389         int glyphs;
390         SkAssertResult(SUCCEEDED(ScriptShape(
391             fDDC, &fSC, c, 2, 1, &si[0].a, &index, log, &vsa, &glyphs)));
392     }
393     return index;
394 }
395 
generateAdvance(SkGlyph * glyph)396 void SkScalerContext_Windows::generateAdvance(SkGlyph* glyph) {
397     this->generateMetrics(glyph);
398 }
399 
generateMetrics(SkGlyph * glyph)400 void SkScalerContext_Windows::generateMetrics(SkGlyph* glyph) {
401 
402     SkASSERT(fDDC);
403 
404     GLYPHMETRICS gm;
405     sk_bzero(&gm, sizeof(gm));
406 
407     glyph->fRsbDelta = 0;
408     glyph->fLsbDelta = 0;
409 
410     // Note: need to use GGO_GRAY8_BITMAP instead of GGO_METRICS because GGO_METRICS returns a smaller
411     // BlackBlox; we need the bigger one in case we need the image.  fAdvance is the same.
412     uint32_t ret = GetGlyphOutlineW(fDDC, glyph->getGlyphID(0), GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
413 
414     if (GDI_ERROR != ret) {
415         if (ret == 0) {
416             // for white space, ret is zero and gmBlackBoxX, gmBlackBoxY are 1 incorrectly!
417             gm.gmBlackBoxX = gm.gmBlackBoxY = 0;
418         }
419         glyph->fWidth   = gm.gmBlackBoxX;
420         glyph->fHeight  = gm.gmBlackBoxY;
421         glyph->fTop     = SkToS16(gm.gmptGlyphOrigin.y - gm.gmBlackBoxY);
422         glyph->fLeft    = SkToS16(gm.gmptGlyphOrigin.x);
423         glyph->fAdvanceX = SkIntToFixed(gm.gmCellIncX);
424         glyph->fAdvanceY = -SkIntToFixed(gm.gmCellIncY);
425 
426         // we outset by 1 in all dimensions, since the lcd image may bleed outside
427         // of the computed bounds returned by GetGlyphOutline.
428         // This was deduced by trial and error for small text (e.g. 8pt), so there
429         // maybe a more precise way to make this adjustment...
430         if (SkMask::kLCD16_Format == fRec.fMaskFormat) {
431             glyph->fWidth += 2;
432             glyph->fHeight += 2;
433             glyph->fTop -= 1;
434             glyph->fLeft -= 1;
435         }
436 
437         if (fHiResFont) {
438             SelectObject(fDDC, fHiResFont);
439             sk_bzero(&gm, sizeof(gm));
440             ret = GetGlyphOutlineW(fDDC, glyph->getGlyphID(0), GGO_METRICS | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22Identity);
441             if (GDI_ERROR != ret) {
442                 SkPoint advance;
443                 fHiResMatrix.mapXY(SkIntToScalar(gm.gmCellIncX), SkIntToScalar(gm.gmCellIncY), &advance);
444                 glyph->fAdvanceX = SkScalarToFixed(advance.fX);
445                 glyph->fAdvanceY = SkScalarToFixed(advance.fY);
446             }
447             SelectObject(fDDC, fFont);
448         }
449     } else {
450         glyph->fWidth = 0;
451     }
452 }
453 
generateFontMetrics(SkPaint::FontMetrics * mx,SkPaint::FontMetrics * my)454 void SkScalerContext_Windows::generateFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my) {
455 // Note: This code was borrowed from generateLineHeight, which has a note
456 // stating that it may be incorrect.
457     if (!(mx || my))
458       return;
459 
460     SkASSERT(fDDC);
461 
462     OUTLINETEXTMETRIC otm;
463 
464     uint32_t ret = GetOutlineTextMetrics(fDDC, sizeof(otm), &otm);
465     if (sizeof(otm) != ret) {
466       return;
467     }
468 
469     if (mx) {
470         mx->fTop = -fScale * otm.otmTextMetrics.tmAscent;
471 		mx->fAscent = -fScale * otm.otmAscent;
472 		mx->fDescent = -fScale * otm.otmDescent;
473 		mx->fBottom = fScale * otm.otmTextMetrics.tmDescent;
474 		mx->fLeading = fScale * (otm.otmTextMetrics.tmInternalLeading
475 								 + otm.otmTextMetrics.tmExternalLeading);
476     }
477 
478     if (my) {
479 		my->fTop = -fScale * otm.otmTextMetrics.tmAscent;
480 		my->fAscent = -fScale * otm.otmAscent;
481 		my->fDescent = -fScale * otm.otmDescent;
482 		my->fBottom = fScale * otm.otmTextMetrics.tmDescent;
483 		my->fLeading = fScale * (otm.otmTextMetrics.tmInternalLeading
484 								 + otm.otmTextMetrics.tmExternalLeading);
485     }
486 }
487 
488 #include "SkColorPriv.h"
489 
rgb_to_lcd16(uint32_t rgb)490 static inline uint16_t rgb_to_lcd16(uint32_t rgb) {
491     int r = (rgb >> 16) & 0xFF;
492     int g = (rgb >>  8) & 0xFF;
493     int b = (rgb >>  0) & 0xFF;
494 
495     // invert, since we draw black-on-white, but we want the original
496     // src mask values.
497     r = 255 - r;
498     g = 255 - g;
499     b = 255 - b;
500     return SkPackRGB16(SkR32ToR16(r), SkG32ToG16(g), SkB32ToB16(b));
501 }
502 
alignTo32(int n)503 static int alignTo32(int n) {
504     return (n + 31) & ~31;
505 }
506 
507 struct MyBitmapInfo : public BITMAPINFO {
508     RGBQUAD fMoreSpaceForColors[1];
509 };
510 
generateImage(const SkGlyph & glyph)511 void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) {
512 
513     SkAutoMutexAcquire  ac(gFTMutex);
514 
515     SkASSERT(fDDC);
516 
517     const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat;
518     if ((SkMask::kLCD16_Format == fRec.fMaskFormat) || isBW) {
519         HDC dc = CreateCompatibleDC(0);
520         void* bits = 0;
521         int biWidth = isBW ? alignTo32(glyph.fWidth) : glyph.fWidth;
522         MyBitmapInfo info;
523         sk_bzero(&info, sizeof(info));
524         if (isBW) {
525             RGBQUAD blackQuad = { 0, 0, 0, 0 };
526             RGBQUAD whiteQuad = { 0xFF, 0xFF, 0xFF, 0 };
527             info.bmiColors[0] = blackQuad;
528             info.bmiColors[1] = whiteQuad;
529         }
530         info.bmiHeader.biSize = sizeof(info.bmiHeader);
531         info.bmiHeader.biWidth = biWidth;
532         info.bmiHeader.biHeight = glyph.fHeight;
533         info.bmiHeader.biPlanes = 1;
534         info.bmiHeader.biBitCount = isBW ? 1 : 32;
535         info.bmiHeader.biCompression = BI_RGB;
536         if (isBW) {
537             info.bmiHeader.biClrUsed = 2;
538         }
539         HBITMAP bm = CreateDIBSection(dc, &info, DIB_RGB_COLORS, &bits, 0, 0);
540         SelectObject(dc, bm);
541 
542         // erase to white
543         size_t srcRB = isBW ? (biWidth >> 3) : (glyph.fWidth << 2);
544         size_t size = glyph.fHeight * srcRB;
545         memset(bits, isBW ? 0 : 0xFF, size);
546 
547         SetGraphicsMode(dc, GM_ADVANCED);
548         SetBkMode(dc, TRANSPARENT);
549         SetTextAlign(dc, TA_LEFT | TA_BASELINE);
550 
551         XFORM xform = fXform;
552         xform.eDx = (float)-glyph.fLeft;
553         xform.eDy = (float)-glyph.fTop;
554         SetWorldTransform(dc, &xform);
555 
556         HGDIOBJ prevFont = SelectObject(dc, fFont);
557         COLORREF color = SetTextColor(dc, isBW ? 0xFFFFFF : 0);
558         SkASSERT(color != CLR_INVALID);
559         uint16_t glyphID = glyph.getGlyphID();
560 #if defined(UNICODE)
561         ExtTextOut(dc, 0, 0, ETO_GLYPH_INDEX, NULL, (LPCWSTR)&glyphID, 1, NULL);
562 #else
563         ExtTextOut(dc, 0, 0, ETO_GLYPH_INDEX, NULL, (LPCSTR)&glyphID, 1, NULL);
564 #endif
565         GdiFlush();
566 
567         // downsample from rgba to rgb565
568         int width = glyph.fWidth;
569         size_t dstRB = glyph.rowBytes();
570         if (isBW) {
571             const uint8_t* src = (const uint8_t*)bits;
572             // gdi's bitmap is upside-down, so we reverse dst walking in Y
573             uint8_t* dst = (uint8_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
574             for (int y = 0; y < glyph.fHeight; y++) {
575                 memcpy(dst, src, dstRB);
576                 src += srcRB;
577                 dst -= dstRB;
578             }
579         } else {    // LCD16
580             const uint32_t* src = (const uint32_t*)bits;
581             // gdi's bitmap is upside-down, so we reverse dst walking in Y
582             uint16_t* dst = (uint16_t*)((char*)glyph.fImage + (glyph.fHeight - 1) * dstRB);
583             for (int y = 0; y < glyph.fHeight; y++) {
584                 for (int i = 0; i < width; i++) {
585                     dst[i] = rgb_to_lcd16(src[i]);
586                 }
587                 src = (const uint32_t*)((const char*)src + srcRB);
588                 dst = (uint16_t*)((char*)dst - dstRB);
589             }
590         }
591 
592         DeleteDC(dc);
593         DeleteObject(bm);
594         return;
595     }
596 
597     GLYPHMETRICS gm;
598     memset(&gm, 0, sizeof(gm));
599     uint32_t bytecount = 0;
600     uint32_t total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX, &gm, 0, NULL, &fMat22);
601     if (GDI_ERROR != total_size && total_size > 0) {
602         uint8_t *pBuff = new uint8_t[total_size];
603         if (NULL != pBuff) {
604             total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_GRAY8_BITMAP | GGO_GLYPH_INDEX, &gm, total_size, pBuff, &fMat22);
605 
606             SkASSERT(total_size != GDI_ERROR);
607 
608             SkASSERT(glyph.fWidth == gm.gmBlackBoxX);
609             SkASSERT(glyph.fHeight == gm.gmBlackBoxY);
610 
611             uint8_t* dst = (uint8_t*)glyph.fImage;
612             uint32_t pitch = (gm.gmBlackBoxX + 3) & ~0x3;
613             if (pitch != glyph.rowBytes()) {
614                 SkASSERT(false); // glyph.fImage has different rowsize!?
615             }
616 
617             for (int32_t y = gm.gmBlackBoxY - 1; y >= 0; y--) {
618                 uint8_t* src = pBuff + pitch * y;
619 
620                 for (uint32_t x = 0; x < gm.gmBlackBoxX; x++) {
621                     if (*src > 63) {
622                         *dst = 0xFF;
623                     }
624                     else {
625                         *dst = *src << 2; // scale to 0-255
626                     }
627                     dst++;
628                     src++;
629                     bytecount++;
630                 }
631                 memset(dst, 0, glyph.rowBytes() - glyph.fWidth);
632                 dst += glyph.rowBytes() - glyph.fWidth;
633             }
634 
635             delete[] pBuff;
636         }
637     }
638 
639     SkASSERT(GDI_ERROR != total_size && total_size >= 0);
640 
641 }
642 
generatePath(const SkGlyph & glyph,SkPath * path)643 void SkScalerContext_Windows::generatePath(const SkGlyph& glyph, SkPath* path) {
644 
645     SkAutoMutexAcquire  ac(gFTMutex);
646 
647     SkASSERT(&glyph && path);
648     SkASSERT(fDDC);
649 
650     path->reset();
651 
652 #if 0
653     char buf[1024];
654     sprintf(buf, "generatePath: id:%d, w=%d, h=%d, font:%s,fh:%d\n", glyph.fID, glyph.fWidth, glyph.fHeight, lf.lfFaceName, lf.lfHeight);
655     OutputDebugString(buf);
656 #endif
657 
658     GLYPHMETRICS gm;
659     uint32_t total_size = GetGlyphOutlineW(fDDC, glyph.fID, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, BUFFERSIZE, glyphbuf, &fMat22);
660 
661     if (GDI_ERROR != total_size) {
662 
663         const uint8_t* cur_glyph = glyphbuf;
664         const uint8_t* end_glyph = glyphbuf + total_size;
665 
666         while(cur_glyph < end_glyph) {
667             const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
668 
669             const uint8_t* end_poly = cur_glyph + th->cb;
670             const uint8_t* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
671 
672             path->moveTo(SkFixedToScalar(*(SkFixed*)(&th->pfxStart.x)), SkFixedToScalar(*(SkFixed*)(&th->pfxStart.y)));
673 
674             while(cur_poly < end_poly) {
675                 const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
676 
677                 if (pc->wType == TT_PRIM_LINE) {
678                     for (uint16_t i = 0; i < pc->cpfx; i++) {
679                         path->lineTo(SkFixedToScalar(*(SkFixed*)(&pc->apfx[i].x)), SkFixedToScalar(*(SkFixed*)(&pc->apfx[i].y)));
680                     }
681                 }
682 
683                 if (pc->wType == TT_PRIM_QSPLINE) {
684                     for (uint16_t u = 0; u < pc->cpfx - 1; u++) { // Walk through points in spline
685                         POINTFX pnt_b = pc->apfx[u];    // B is always the current point
686                         POINTFX pnt_c = pc->apfx[u+1];
687 
688                         if (u < pc->cpfx - 2) {          // If not on last spline, compute C
689                             pnt_c.x = SkFixedToFIXED(SkFixedAve(*(SkFixed*)(&pnt_b.x), *(SkFixed*)(&pnt_c.x)));
690                             pnt_c.y = SkFixedToFIXED(SkFixedAve(*(SkFixed*)(&pnt_b.y), *(SkFixed*)(&pnt_c.y)));
691                         }
692 
693                         path->quadTo(SkFixedToScalar(*(SkFixed*)(&pnt_b.x)), SkFixedToScalar(*(SkFixed*)(&pnt_b.y)), SkFixedToScalar(*(SkFixed*)(&pnt_c.x)), SkFixedToScalar(*(SkFixed*)(&pnt_c.y)));
694                     }
695                 }
696                 cur_poly += sizeof(uint16_t) * 2 + sizeof(POINTFX) * pc->cpfx;
697             }
698             cur_glyph += th->cb;
699             path->close();
700         }
701     }
702     else {
703         SkASSERT(false);
704     }
705     //char buf[1024];
706     //sprintf(buf, "generatePath: count:%d\n", count);
707     //OutputDebugString(buf);
708 }
709 
Serialize(const SkTypeface * face,SkWStream * stream)710 void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
711     SkASSERT(!"SkFontHost::Serialize unimplemented");
712 }
713 
Deserialize(SkStream * stream)714 SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
715     SkASSERT(!"SkFontHost::Deserialize unimplemented");
716     return NULL;
717 }
718 
getWidthAdvance(HDC hdc,int gId,int16_t * advance)719 static bool getWidthAdvance(HDC hdc, int gId, int16_t* advance) {
720     // Initialize the MAT2 structure to the identify transformation matrix.
721     static const MAT2 mat2 = {SkScalarToFIXED(1), SkScalarToFIXED(0),
722                         SkScalarToFIXED(0), SkScalarToFIXED(1)};
723     int flags = GGO_METRICS | GGO_GLYPH_INDEX;
724     GLYPHMETRICS gm;
725     if (GDI_ERROR == GetGlyphOutline(hdc, gId, flags, &gm, 0, NULL, &mat2)) {
726         return false;
727     }
728     SkASSERT(advance);
729     *advance = gm.gmCellIncX;
730     return true;
731 }
732 
733 // static
GetAdvancedTypefaceMetrics(uint32_t fontID,SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo)734 SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
735         uint32_t fontID,
736         SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo) {
737     LOGFONT lf;
738     GetLogFontByID(fontID, &lf);
739     SkAdvancedTypefaceMetrics* info = NULL;
740 
741     HDC hdc = CreateCompatibleDC(NULL);
742     HFONT font = CreateFontIndirect(&lf);
743     HFONT savefont = (HFONT)SelectObject(hdc, font);
744     HFONT designFont = NULL;
745 
746     // To request design units, create a logical font whose height is specified
747     // as unitsPerEm.
748     OUTLINETEXTMETRIC otm;
749     if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm) ||
750         !GetTextFace(hdc, LF_FACESIZE, lf.lfFaceName)) {
751         goto Error;
752     }
753     lf.lfHeight = -SkToS32(otm.otmEMSquare);
754     designFont = CreateFontIndirect(&lf);
755     SelectObject(hdc, designFont);
756     if (!GetOutlineTextMetrics(hdc, sizeof(otm), &otm)) {
757         goto Error;
758     }
759     const unsigned glyphCount = calculateGlyphCount(hdc);
760 
761     info = new SkAdvancedTypefaceMetrics;
762     info->fEmSize = otm.otmEMSquare;
763     info->fMultiMaster = false;
764     info->fLastGlyphID = SkToU16(glyphCount - 1);
765     info->fStyle = 0;
766 #ifdef UNICODE
767     // Get the buffer size needed first.
768     size_t str_len = WideCharToMultiByte(CP_UTF8, 0, lf.lfFaceName, -1, NULL,
769                                          0, NULL, NULL);
770     // Allocate a buffer (str_len already has terminating null accounted for).
771     char *familyName = new char[str_len];
772     // Now actually convert the string.
773     WideCharToMultiByte(CP_UTF8, 0, lf.lfFaceName, -1, familyName, str_len,
774                           NULL, NULL);
775     info->fFontName.set(familyName);
776     delete [] familyName;
777 #else
778     info->fFontName.set(lf.lfFaceName);
779 #endif
780 
781     if (perGlyphInfo & SkAdvancedTypefaceMetrics::kToUnicode_PerGlyphInfo) {
782         populate_glyph_to_unicode(hdc, glyphCount, &(info->fGlyphToUnicode));
783     }
784 
785     if (otm.otmTextMetrics.tmPitchAndFamily & TMPF_TRUETYPE) {
786         info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
787     } else {
788         info->fType = SkAdvancedTypefaceMetrics::kOther_Font;
789         info->fItalicAngle = 0;
790         info->fAscent = 0;
791         info->fDescent = 0;
792         info->fStemV = 0;
793         info->fCapHeight = 0;
794         info->fBBox = SkIRect::MakeEmpty();
795         return info;
796     }
797 
798     // If this bit is clear the font is a fixed pitch font.
799     if (!(otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
800         info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
801     }
802     if (otm.otmTextMetrics.tmItalic) {
803         info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
804     }
805     // Setting symbolic style by default for now.
806     info->fStyle |= SkAdvancedTypefaceMetrics::kSymbolic_Style;
807     if (otm.otmTextMetrics.tmPitchAndFamily & FF_ROMAN) {
808         info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
809     } else if (otm.otmTextMetrics.tmPitchAndFamily & FF_SCRIPT) {
810             info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
811     }
812 
813     // The main italic angle of the font, in tenths of a degree counterclockwise
814     // from vertical.
815     info->fItalicAngle = otm.otmItalicAngle / 10;
816     info->fAscent = SkToS16(otm.otmTextMetrics.tmAscent);
817     info->fDescent = SkToS16(-otm.otmTextMetrics.tmDescent);
818     // TODO(ctguil): Use alternate cap height calculation.
819     // MSDN says otmsCapEmHeight is not support but it is returning a value on
820     // my Win7 box.
821     info->fCapHeight = otm.otmsCapEmHeight;
822     info->fBBox =
823         SkIRect::MakeLTRB(otm.otmrcFontBox.left, otm.otmrcFontBox.top,
824                           otm.otmrcFontBox.right, otm.otmrcFontBox.bottom);
825 
826     // Figure out a good guess for StemV - Min width of i, I, !, 1.
827     // This probably isn't very good with an italic font.
828     int16_t min_width = SHRT_MAX;
829     info->fStemV = 0;
830     char stem_chars[] = {'i', 'I', '!', '1'};
831     for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) {
832         ABC abcWidths;
833         if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) {
834             int16_t width = abcWidths.abcB;
835             if (width > 0 && width < min_width) {
836                 min_width = width;
837                 info->fStemV = min_width;
838             }
839         }
840     }
841 
842     // If bit 1 is set, the font may not be embedded in a document.
843     // If bit 1 is clear, the font can be embedded.
844     // If bit 2 is set, the embedding is read-only.
845     if (otm.otmfsType & 0x1) {
846         info->fType = SkAdvancedTypefaceMetrics::kNotEmbeddable_Font;
847     } else if (perGlyphInfo &
848                SkAdvancedTypefaceMetrics::kHAdvance_PerGlyphInfo) {
849         info->fGlyphWidths.reset(
850             getAdvanceData(hdc, glyphCount, &getWidthAdvance));
851     }
852 
853 Error:
854     SelectObject(hdc, savefont);
855     DeleteObject(designFont);
856     DeleteObject(font);
857     DeleteDC(hdc);
858 
859     return info;
860 }
861 
CreateTypefaceFromStream(SkStream * stream)862 SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
863 
864     //Should not be used on Windows, keep linker happy
865     SkASSERT(false);
866     return SkCreateTypefaceFromLOGFONT(get_default_font());
867 }
868 
OpenStream(SkFontID uniqueID)869 SkStream* SkFontHost::OpenStream(SkFontID uniqueID) {
870     const DWORD kTTCTag =
871         SkEndian_SwapBE32(SkSetFourByteTag('t', 't', 'c', 'f'));
872     LOGFONT lf;
873     GetLogFontByID(uniqueID, &lf);
874 
875     HDC hdc = ::CreateCompatibleDC(NULL);
876     HFONT font = CreateFontIndirect(&lf);
877     HFONT savefont = (HFONT)SelectObject(hdc, font);
878 
879     SkMemoryStream* stream = NULL;
880     DWORD tables[2] = {kTTCTag, 0};
881     for (int i = 0; i < SK_ARRAY_COUNT(tables); i++) {
882         size_t bufferSize = GetFontData(hdc, tables[i], 0, NULL, 0);
883         if (bufferSize != GDI_ERROR) {
884             stream = new SkMemoryStream(bufferSize);
885             if (GetFontData(hdc, tables[i], 0, (void*)stream->getMemoryBase(),
886                             bufferSize)) {
887                 break;
888             } else {
889                 delete stream;
890                 stream = NULL;
891             }
892         }
893     }
894 
895     SelectObject(hdc, savefont);
896     DeleteObject(font);
897     DeleteDC(hdc);
898 
899     return stream;
900 }
901 
CreateScalerContext(const SkDescriptor * desc)902 SkScalerContext* SkFontHost::CreateScalerContext(const SkDescriptor* desc) {
903     return SkNEW_ARGS(SkScalerContext_Windows, (desc));
904 }
905 
906 /** Return the closest matching typeface given either an existing family
907  (specified by a typeface in that family) or by a familyName, and a
908  requested style.
909  1) If familyFace is null, use famillyName.
910  2) If famillyName is null, use familyFace.
911  3) If both are null, return the default font that best matches style
912  This MUST not return NULL.
913  */
914 
CreateTypeface(const SkTypeface * familyFace,const char familyName[],const void * data,size_t bytelength,SkTypeface::Style style)915 SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
916                                        const char familyName[],
917                                        const void* data, size_t bytelength,
918                                        SkTypeface::Style style) {
919     LOGFONT lf;
920     if (NULL == familyFace && NULL == familyName) {
921         lf = get_default_font();
922     } else if (familyFace) {
923         LogFontTypeface* face = (LogFontTypeface*)familyFace;
924         lf = face->fLogFont;
925     } else {
926         memset(&lf, 0, sizeof(LOGFONT));
927 #ifdef UNICODE
928         // Get the buffer size needed first.
929         size_t str_len = ::MultiByteToWideChar(CP_UTF8, 0, familyName,
930                                                 -1, NULL, 0);
931         // Allocate a buffer (str_len already has terminating null
932         // accounted for).
933         wchar_t *wideFamilyName = new wchar_t[str_len];
934         // Now actually convert the string.
935         ::MultiByteToWideChar(CP_UTF8, 0, familyName, -1,
936                                 wideFamilyName, str_len);
937         ::wcsncpy(lf.lfFaceName, wideFamilyName, LF_FACESIZE);
938         delete [] wideFamilyName;
939 #else
940         ::strncpy(lf.lfFaceName, familyName, LF_FACESIZE);
941 #endif
942         lf.lfFaceName[LF_FACESIZE-1] = '\0';
943     }
944     setStyle(&lf, style);
945     return SkCreateTypefaceFromLOGFONT(lf);
946 }
947 
ShouldPurgeFontCache(size_t sizeAllocatedSoFar)948 size_t SkFontHost::ShouldPurgeFontCache(size_t sizeAllocatedSoFar) {
949     if (sizeAllocatedSoFar > FONT_CACHE_MEMORY_BUDGET)
950         return sizeAllocatedSoFar - FONT_CACHE_MEMORY_BUDGET;
951     else
952         return 0;   // nothing to do
953 }
954 
ComputeGammaFlag(const SkPaint & paint)955 int SkFontHost::ComputeGammaFlag(const SkPaint& paint) {
956     return 0;
957 }
958 
GetGammaTables(const uint8_t * tables[2])959 void SkFontHost::GetGammaTables(const uint8_t* tables[2]) {
960     tables[0] = NULL;   // black gamma (e.g. exp=1.4)
961     tables[1] = NULL;   // white gamma (e.g. exp= 1/1.4)
962 }
963 
CreateTypefaceFromFile(const char path[])964 SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
965     printf("SkFontHost::CreateTypefaceFromFile unimplemented");
966     return NULL;
967 }
968 
FilterRec(SkScalerContext::Rec * rec)969 void SkFontHost::FilterRec(SkScalerContext::Rec* rec) {
970     // We don't control the hinting nor ClearType settings here
971     rec->setHinting(SkPaint::kNormal_Hinting);
972 
973     // we do support LCD16
974     if (SkMask::kLCD16_Format == rec->fMaskFormat) {
975         return;
976     }
977 
978     if (SkMask::FormatIsLCD((SkMask::Format)rec->fMaskFormat)) {
979         rec->fMaskFormat = SkMask::kA8_Format;
980     }
981 }
982 
983 #endif // WIN32
984