Merge to XFA: Use stdint.h types throughout PDFium.
[pdfium.git] / xfa / src / fgas / src / font / fx_gdifont.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.\r
2 // Use of this source code is governed by a BSD-style license that can be\r
3 // found in the LICENSE file.\r
4 \r
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\r
6 \r
7 #include "../fgas_base.h"\r
8 #include "fx_gdifont.h"\r
9 #include "fx_stdfontmgr.h"\r
10 #ifdef _FXPLUS\r
11 #if _FX_OS_ == _FX_WIN32_DESKTOP_ || _FX_OS_ == _FX_WIN32_MOBILE_ || _FX_OS_ == _FX_WIN64_\r
12 CFX_GdiFontCache::CFX_GdiFontCache()\r
13     : m_GlyphMap(128)\r
14 {\r
15 }\r
16 CFX_GdiFontCache::~CFX_GdiFontCache()\r
17 {\r
18     FX_POSITION pos = m_GlyphMap.GetStartPosition();\r
19     int32_t iGlyph;\r
20     FX_LPGDIGOCACHE pGlyph;\r
21     while (pos != NULL) {\r
22         pGlyph = NULL;\r
23         m_GlyphMap.GetNextAssoc(pos, (void*&)iGlyph, (void*&)pGlyph);\r
24         if (pGlyph != NULL) {\r
25             FDE_Free(pGlyph->pOutline);\r
26             FDE_Free(pGlyph);\r
27         }\r
28     }\r
29     m_GlyphMap.RemoveAll();\r
30 }\r
31 void CFX_GdiFontCache::SetCachedGlyphOutline(FX_DWORD dwGlyph, const GLYPHMETRICS &gm, FX_LPBYTE pOutline)\r
32 {\r
33     FXSYS_assert(pOutline != NULL);\r
34     FX_LPGDIGOCACHE pGlyph = (FX_LPGDIGOCACHE)FDE_Alloc(sizeof(FX_GDIGOCACHE));\r
35     pGlyph->gm = gm;\r
36     pGlyph->pOutline = pOutline;\r
37     m_GlyphMap.SetAt((void*)dwGlyph, (void*)pGlyph);\r
38 }\r
39 FX_LPCGDIGOCACHE CFX_GdiFontCache::GetCachedGlyphOutline(FX_DWORD dwGlyph) const\r
40 {\r
41     FX_LPCGDIGOCACHE pGlyph = NULL;\r
42     if (!m_GlyphMap.Lookup((void*)dwGlyph, (void*&)pGlyph)) {\r
43         return FALSE;\r
44     }\r
45     return pGlyph;\r
46 }\r
47 IFX_Font* IFX_Font::LoadFont(FX_LPCWSTR pszFontFamily, FX_DWORD dwFontStyles, FX_WORD wCodePage, IFX_FontMgr *pFontMgr)\r
48 {\r
49     CFX_GdiFont *pFont = FX_NEW CFX_GdiFont(pFontMgr);\r
50     if (!pFont->LoadFont(pszFontFamily, dwFontStyles, wCodePage)) {\r
51         pFont->Release();\r
52         return NULL;\r
53     }\r
54     return pFont;\r
55 }\r
56 IFX_Font* IFX_Font::LoadFont(FX_LPCBYTE pBuffer, int32_t iLength, IFX_FontMgr *pFontMgr)\r
57 {\r
58     CFX_GdiFont *pFont = FX_NEW CFX_GdiFont(pFontMgr);\r
59     if (!pFont->LoadFont(pBuffer, iLength)) {\r
60         pFont->Release();\r
61         return NULL;\r
62     }\r
63     return pFont;\r
64 }\r
65 IFX_Font* IFX_Font::LoadFont(FX_LPCWSTR pszFileName, IFX_FontMgr *pFontMgr)\r
66 {\r
67     CFX_GdiFont *pFont = FX_NEW CFX_GdiFont(pFontMgr);\r
68     if (!pFont->LoadFont(pszFileName)) {\r
69         pFont->Release();\r
70         return NULL;\r
71     }\r
72     return pFont;\r
73 }\r
74 IFX_Font* IFX_Font::LoadFont(IFX_Stream *pFontStream, IFX_FontMgr *pFontMgr, FX_BOOL bSaveStream )\r
75 {\r
76     CFX_GdiFont *pFont = FX_NEW CFX_GdiFont(pFontMgr);\r
77     if (!pFont->LoadFont(pFontStream)) {\r
78         pFont->Release();\r
79         return NULL;\r
80     }\r
81     return pFont;\r
82 }\r
83 IFX_Font* IFX_Font::LoadFont(CFX_Font *pExtFont, IFX_FontMgr *pFontMgr)\r
84 {\r
85     FXSYS_assert(FALSE);\r
86     return NULL;\r
87 }\r
88 #define FX_GDIFONT_FONTCACHESIZE        8\r
89 CFX_GdiFont::CFX_GdiFont(IFX_FontMgr *pFontMgr)\r
90     : m_pFontMgr(pFontMgr)\r
91     , m_iRefCount(1)\r
92     , m_WidthCache(1024)\r
93     , m_hOldFont(NULL)\r
94     , m_hFont(NULL)\r
95     , m_hDC(NULL)\r
96     , m_wsFontFileName()\r
97     , m_FontFamilies()\r
98     , m_hRes(NULL)\r
99     , m_dwStyles(0)\r
100     , m_SubstFonts()\r
101     , m_FontMapper(16)\r
102     , m_FontCache(FX_GDIFONT_FONTCACHESIZE)\r
103 {\r
104     m_hDC = ::CreateCompatibleDC(NULL);\r
105     FX_memset(&m_LogFont, 0, sizeof(m_LogFont));\r
106     FXSYS_assert(m_hDC != NULL);\r
107 }\r
108 CFX_GdiFont::~CFX_GdiFont()\r
109 {\r
110     int32_t iCount = m_SubstFonts.GetSize();\r
111     for (int32_t i = 0; i < iCount; i ++) {\r
112         IFX_Font *pFont = (IFX_Font*)m_SubstFonts[i];\r
113         pFont->Release();\r
114     }\r
115     m_SubstFonts.RemoveAll();\r
116     m_FontMapper.RemoveAll();\r
117     if (m_hFont != NULL) {\r
118         ::SelectObject(m_hDC, m_hOldFont);\r
119         ::DeleteObject(m_hFont);\r
120     }\r
121     ::DeleteDC(m_hDC);\r
122     if (m_hRes != NULL) {\r
123         if (m_wsFontFileName.GetLength() > 0) {\r
124             ::RemoveFontResourceW((FX_LPCWSTR)m_wsFontFileName);\r
125         } else {\r
126             ::RemoveFontMemResourceEx(m_hRes);\r
127         }\r
128     }\r
129     m_WidthCache.RemoveAll();\r
130     ClearCache();\r
131 }\r
132 void CFX_GdiFont::ClearCache()\r
133 {\r
134     int32_t iCount = m_SubstFonts.GetSize();\r
135     for (int32_t i = 0; i < iCount; i ++) {\r
136         IFX_Font *pFont = (IFX_Font*)m_SubstFonts[i];\r
137         ((CFX_GdiFont*)pFont)->ClearCache();\r
138     }\r
139     FX_POSITION pos = m_FontCache.GetStartPosition();\r
140     FX_DWORD dwMAT2;\r
141     CFX_GdiFontCache *pCache;\r
142     while (pos != NULL) {\r
143         pCache = NULL;\r
144         m_FontCache.GetNextAssoc(pos, (void*&)dwMAT2, (void*&)pCache);\r
145         if (pCache != NULL) {\r
146             delete pCache;\r
147         }\r
148     }\r
149     m_FontCache.RemoveAll();\r
150 }\r
151 void CFX_GdiFont::Release()\r
152 {\r
153     if (-- m_iRefCount < 1) {\r
154         if (m_pFontMgr != NULL) {\r
155             m_pFontMgr->RemoveFont(this);\r
156         }\r
157         delete this;\r
158     }\r
159 }\r
160 IFX_Font* CFX_GdiFont::Retain()\r
161 {\r
162     ++ m_iRefCount;\r
163     return this;\r
164 }\r
165 FX_BOOL CFX_GdiFont::LoadFont(FX_LPCWSTR pszFontFamily, FX_DWORD dwFontStyles, FX_WORD wCodePage)\r
166 {\r
167     FXSYS_assert(m_hFont == NULL);\r
168     LOGFONTW lf;\r
169     FX_memset(&lf, 0, sizeof(lf));\r
170     lf.lfHeight = -1000;\r
171     lf.lfWeight = (dwFontStyles & FX_FONTSTYLE_Bold) ? FW_BOLD : FW_NORMAL;\r
172     lf.lfItalic = (dwFontStyles & FX_FONTSTYLE_Italic) != 0;\r
173     lf.lfPitchAndFamily = (dwFontStyles & FX_FONTSTYLE_FixedPitch) ? FIXED_PITCH : VARIABLE_PITCH;\r
174     if (dwFontStyles & FX_FONTSTYLE_Serif) {\r
175         lf.lfPitchAndFamily |= FF_ROMAN;\r
176     }\r
177     if (dwFontStyles & FX_FONTSTYLE_Script) {\r
178         lf.lfPitchAndFamily |= FF_SCRIPT;\r
179     }\r
180     if (dwFontStyles & FX_FONTSTYLE_Symbolic) {\r
181         lf.lfCharSet = SYMBOL_CHARSET;\r
182     } else {\r
183         FX_WORD wCharSet = FX_GetCharsetFromCodePage(wCodePage);\r
184         lf.lfCharSet = wCharSet != 0xFFFF ? (uint8_t)wCharSet : DEFAULT_CHARSET;\r
185     }\r
186     if (pszFontFamily == NULL) {\r
187         lf.lfFaceName[0] = L'\0';\r
188     } else {\r
189         FXSYS_wcsncpy(lf.lfFaceName, pszFontFamily, 31);\r
190     }\r
191     return LoadFont(lf);\r
192 }\r
193 FX_BOOL CFX_GdiFont::LoadFont(FX_LPCBYTE pBuffer, int32_t iLength)\r
194 {\r
195     FXSYS_assert(m_hFont == NULL && pBuffer != NULL && iLength > 0);\r
196     Gdiplus::PrivateFontCollection pfc;\r
197     if (pfc.AddMemoryFont(pBuffer, iLength) != Gdiplus::Ok) {\r
198         return FALSE;\r
199     }\r
200     if (GetFontFamilies(pfc) < 1) {\r
201         return FALSE;\r
202     }\r
203     FX_DWORD dwCount = 0;\r
204     m_hRes = ::AddFontMemResourceEx((void*)pBuffer, iLength, 0, &dwCount);\r
205     if (m_hRes == NULL) {\r
206         return FALSE;\r
207     }\r
208     CFX_WideString wsFamily = m_FontFamilies[0];\r
209     m_hFont = ::CreateFontW(-1000, 0, 0, 0, FW_NORMAL, FALSE, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, (FX_LPCWSTR)wsFamily);\r
210     if (m_hFont == NULL) {\r
211         ::RemoveFontMemResourceEx(m_hRes);\r
212         m_hRes = NULL;\r
213         return FALSE;\r
214     }\r
215     RetrieveFontStyles();\r
216     m_hOldFont = ::SelectObject(m_hDC, m_hFont);\r
217     ::GetOutlineTextMetricsW(m_hDC, sizeof(m_OutlineTM), &m_OutlineTM);\r
218     return TRUE;\r
219 }\r
220 FX_BOOL CFX_GdiFont::LoadFont(FX_LPCWSTR pszFileName)\r
221 {\r
222     FXSYS_assert(m_hFont == NULL && pszFileName != NULL);\r
223     Gdiplus::PrivateFontCollection pfc;\r
224     if (pfc.AddFontFile(pszFileName) != Gdiplus::Ok) {\r
225         return FALSE;\r
226     }\r
227     if (GetFontFamilies(pfc) < 1) {\r
228         return FALSE;\r
229     }\r
230     m_wsFontFileName = pszFileName;\r
231     m_hRes = (HANDLE)::AddFontResourceW(pszFileName);\r
232     if (m_hRes == NULL) {\r
233         return FALSE;\r
234     }\r
235     CFX_WideString wsFamily = m_FontFamilies[0];\r
236     m_hFont = ::CreateFontW(-1000, 0, 0, 0, FW_NORMAL, FALSE, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, (FX_LPCWSTR)wsFamily);\r
237     if (m_hFont == NULL) {\r
238         ::RemoveFontResourceW(pszFileName);\r
239         m_hRes = NULL;\r
240         return FALSE;\r
241     }\r
242     RetrieveFontStyles();\r
243     ::SelectObject(m_hDC, m_hFont);\r
244     ::GetOutlineTextMetricsW(m_hDC, sizeof(m_OutlineTM), &m_OutlineTM);\r
245     return TRUE;\r
246 }\r
247 FX_BOOL CFX_GdiFont::LoadFont(IFX_Stream *pFontStream)\r
248 {\r
249     FXSYS_assert(m_hFont == NULL && pFontStream != NULL);\r
250     int32_t iLength = pFontStream->GetLength();\r
251     if (iLength < 1) {\r
252         return FALSE;\r
253     }\r
254     FX_LPBYTE pBuf = (FX_LPBYTE)FDE_Alloc(iLength);\r
255     if (pBuf == NULL) {\r
256         return FALSE;\r
257     }\r
258     iLength = pFontStream->ReadData(pBuf, iLength);\r
259     FX_BOOL bRet = LoadFont(pBuf, iLength);\r
260     FDE_Free(pBuf);\r
261     return bRet;\r
262 }\r
263 FX_BOOL CFX_GdiFont::LoadFont(const LOGFONTW &lf)\r
264 {\r
265     FXSYS_assert(m_hFont == NULL);\r
266     m_hFont = ::CreateFontIndirectW((LPLOGFONTW)&lf);\r
267     if (m_hFont == NULL) {\r
268         return FALSE;\r
269     }\r
270     RetrieveFontStyles();\r
271     ::SelectObject(m_hDC, m_hFont);\r
272     ::GetOutlineTextMetricsW(m_hDC, sizeof(m_OutlineTM), &m_OutlineTM);\r
273     return TRUE;\r
274 }\r
275 int32_t CFX_GdiFont::GetFontFamilies(Gdiplus::FontCollection &fc)\r
276 {\r
277     int32_t iCount = fc.GetFamilyCount();\r
278     if (iCount < 1) {\r
279         return iCount;\r
280     }\r
281     Gdiplus::FontFamily *pFontFamilies = (Gdiplus::FontFamily*)FDE_Alloc(iCount * sizeof(Gdiplus::FontFamily));\r
282     if (pFontFamilies == NULL) {\r
283         return -1;\r
284     }\r
285     int32_t iFind = 0;\r
286     fc.GetFamilies(iCount, pFontFamilies, &iFind);\r
287     for (int32_t i = 0; i < iCount; i ++) {\r
288         CFX_WideString wsFamilyName;\r
289         FX_LPWSTR pName = wsFamilyName.GetBuffer(LF_FACESIZE);\r
290         pFontFamilies[i].GetFamilyName(pName);\r
291         wsFamilyName.ReleaseBuffer();\r
292         m_FontFamilies.Add(wsFamilyName);\r
293     }\r
294     FDE_Free(pFontFamilies);\r
295     return iCount;\r
296 }\r
297 void CFX_GdiFont::RetrieveFontStyles()\r
298 {\r
299     FXSYS_assert(m_hFont != NULL);\r
300     FX_memset(&m_LogFont, 0, sizeof(m_LogFont));\r
301     ::GetObjectW(m_hFont, sizeof(m_LogFont), &m_LogFont);\r
302     m_dwStyles = FX_GetGdiFontStyles(m_LogFont);\r
303 }\r
304 void CFX_GdiFont::GetFamilyName(CFX_WideString &wsFamily) const\r
305 {\r
306     FXSYS_assert(m_hFont != NULL);\r
307     wsFamily = m_LogFont.lfFaceName;\r
308 }\r
309 FX_BOOL CFX_GdiFont::GetCharWidth(FX_WCHAR wUnicode, int32_t &iWidth, FX_BOOL bRecursive, FX_BOOL bCharCode)\r
310 {\r
311     iWidth = (int32_t)(int16_t)m_WidthCache.GetAt(wUnicode, 0);\r
312     if (iWidth == 0 || iWidth == -1) {\r
313         IFX_Font *pFont = NULL;\r
314         int32_t iGlyph = GetGlyphIndex(wUnicode, TRUE, &pFont, bCharCode);\r
315         if (iGlyph != 0xFFFF && pFont != NULL) {\r
316             if (pFont == (IFX_Font*)this) {\r
317                 if (!::GetCharWidthI(m_hDC, iGlyph, 1, NULL, &iWidth)) {\r
318                     iWidth = -1;\r
319                 }\r
320             } else if (((CFX_GdiFont*)pFont)->GetCharWidth(wUnicode, iWidth, FALSE, bCharCode)) {\r
321                 return TRUE;\r
322             }\r
323         } else {\r
324             iWidth = -1;\r
325         }\r
326         Lock();\r
327         m_WidthCache.SetAtGrow(wUnicode, (int16_t)iWidth);\r
328         Unlock();\r
329     }\r
330     return iWidth > 0;\r
331 }\r
332 FX_BOOL CFX_GdiFont::GetCharWidth(FX_WCHAR wUnicode, int32_t &iWidth, FX_BOOL bCharCode)\r
333 {\r
334     return GetCharWidth(wUnicode, iWidth, TRUE, bCharCode);\r
335 }\r
336 int32_t CFX_GdiFont::GetGlyphIndex(FX_WCHAR wUnicode, FX_BOOL bRecursive, IFX_Font **ppFont, FX_BOOL bCharCode)\r
337 {\r
338     int32_t iGlyph = 0XFFFF;\r
339     if (::GetGlyphIndicesW(m_hDC, &wUnicode, 1, (LPWORD)&iGlyph, GGI_MARK_NONEXISTING_GLYPHS) != GDI_ERROR && iGlyph != 0xFFFF) {\r
340         if (ppFont != NULL) {\r
341             *ppFont = (IFX_Font*)this;\r
342         }\r
343         return iGlyph;\r
344     }\r
345     FX_LPCFONTUSB pFontUSB = FX_GetUnicodeBitField(wUnicode);\r
346     if (pFontUSB == NULL) {\r
347         return 0xFFFF;\r
348     }\r
349     FX_WORD wBitField = pFontUSB->wBitField;\r
350     if (wBitField >= 128) {\r
351         return 0xFFFF;\r
352     }\r
353     IFX_Font *pFont = NULL;\r
354     m_FontMapper.Lookup((void*)wBitField, (void*&)pFont);\r
355     if (pFont != NULL && pFont != (IFX_Font*)this) {\r
356         iGlyph = ((CFX_GdiFont*)pFont)->GetGlyphIndex(wUnicode, FALSE, NULL, bCharCode);\r
357         if (iGlyph != 0xFFFF) {\r
358             int32_t i = m_SubstFonts.Find(pFont);\r
359             if (i > -1) {\r
360                 iGlyph |= ((i + 1) << 24);\r
361                 if (ppFont != NULL) {\r
362                     *ppFont = pFont;\r
363                 }\r
364                 return iGlyph;\r
365             }\r
366         }\r
367     }\r
368     if (m_pFontMgr != NULL && bRecursive) {\r
369         IFX_Font *pFont = m_pFontMgr->GetDefFontByUnicode(wUnicode, m_dwStyles, m_LogFont.lfFaceName);\r
370         if (pFont != NULL) {\r
371             if (pFont == (IFX_Font*)this) {\r
372                 pFont->Release();\r
373                 return 0xFFFF;\r
374             }\r
375             m_FontMapper.SetAt((void*)wBitField, (void*)pFont);\r
376             int32_t i = m_SubstFonts.GetSize();\r
377             m_SubstFonts.Add(pFont);\r
378             iGlyph = ((CFX_GdiFont*)pFont)->GetGlyphIndex(wUnicode, FALSE, NULL, bCharCode);\r
379             if (iGlyph != 0xFFFF) {\r
380                 iGlyph |= ((i + 1) << 24);\r
381                 if (ppFont != NULL) {\r
382                     *ppFont = pFont;\r
383                 }\r
384                 return iGlyph;\r
385             }\r
386         }\r
387     }\r
388     return 0xFFFF;\r
389 }\r
390 int32_t CFX_GdiFont::GetGlyphIndex(FX_WCHAR wUnicode, FX_BOOL bCharCode)\r
391 {\r
392     return GetGlyphIndex(wUnicode, TRUE, NULL, bCharCode);\r
393 }\r
394 int32_t CFX_GdiFont::GetAscent() const\r
395 {\r
396     return m_OutlineTM.otmAscent;\r
397 }\r
398 int32_t CFX_GdiFont::GetDescent() const\r
399 {\r
400     return m_OutlineTM.otmDescent;\r
401 }\r
402 FX_BOOL CFX_GdiFont::GetCharBBox(FX_WCHAR wUnicode, CFX_Rect &bbox, FX_BOOL bCharCode)\r
403 {\r
404     int32_t iGlyphIndex = GetGlyphIndex(wUnicode, bCharCode);\r
405     if (iGlyphIndex == 0xFFFF) {\r
406         return FALSE;\r
407     }\r
408     IFX_Font *pFont = GetSubstFont(iGlyphIndex);\r
409     if (pFont == NULL) {\r
410         return FALSE;\r
411     }\r
412     GLYPHMETRICS gm;\r
413     iGlyphIndex &= 0x00FFFFFF;\r
414     static const MAT2 mat2 = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};\r
415     if (::GetGlyphOutlineW(((CFX_GdiFont*)pFont)->m_hDC, iGlyphIndex, GGO_GLYPH_INDEX | GGO_METRICS, &gm, 0, NULL, &mat2) != GDI_ERROR) {\r
416         bbox.left = gm.gmptGlyphOrigin.x;\r
417         bbox.top = gm.gmptGlyphOrigin.y;\r
418         bbox.width = gm.gmBlackBoxX;\r
419         bbox.height = gm.gmBlackBoxY;\r
420         return TRUE;\r
421     }\r
422     return FALSE;\r
423 }\r
424 FX_BOOL CFX_GdiFont::GetBBox(CFX_Rect &bbox)\r
425 {\r
426     bbox.left = m_OutlineTM.otmrcFontBox.left;\r
427     bbox.top = m_OutlineTM.otmrcFontBox.top;\r
428     bbox.width = m_OutlineTM.otmrcFontBox.right - m_OutlineTM.otmrcFontBox.left;\r
429     bbox.height = m_OutlineTM.otmrcFontBox.bottom - m_OutlineTM.otmrcFontBox.top;\r
430     return TRUE;\r
431 }\r
432 int32_t CFX_GdiFont::GetItalicAngle() const\r
433 {\r
434     return m_OutlineTM.otmItalicAngle / 10;\r
435 }\r
436 void CFX_GdiFont::Reset()\r
437 {\r
438     Lock();\r
439     m_WidthCache.RemoveAll();\r
440     ClearCache();\r
441     Unlock();\r
442 }\r
443 IFX_Font* CFX_GdiFont::GetSubstFont(int32_t iGlyphIndex) const\r
444 {\r
445     int32_t iHigher = (iGlyphIndex & 0x7F000000) >> 24;\r
446     if (iHigher == 0) {\r
447         return (IFX_Font*)this;\r
448     }\r
449     if (iHigher > m_SubstFonts.GetSize()) {\r
450         return (IFX_Font*)this;\r
451     }\r
452     return (IFX_Font*)m_SubstFonts[iHigher - 1];\r
453 }\r
454 FX_DWORD CFX_GdiFont::GetGlyphDIBits(int32_t iGlyphIndex, FX_ARGB argb, const MAT2 *pMatrix, GLYPHMETRICS &gm, FX_LPVOID pBuffer, FX_DWORD bufSize)\r
455 {\r
456     static const UINT uFormat = GGO_GLYPH_INDEX | GGO_GRAY8_BITMAP;\r
457     IFX_Font *pFont = GetSubstFont(iGlyphIndex);\r
458     if (pFont == NULL) {\r
459         return 0;\r
460     }\r
461     if (pFont != (IFX_Font*)this) {\r
462         return ((CFX_GdiFont*)pFont)->GetGlyphDIBits(iGlyphIndex & 0x00FFFFFF, argb, pMatrix, gm, pBuffer, bufSize);\r
463     }\r
464     FX_LPBYTE pGlyphOutline = NULL;\r
465     FXSYS_assert(pMatrix != NULL);\r
466     FX_DWORD dwMAT2 = GetMAT2HashCode((const FIXED*)pMatrix);\r
467     CFX_GdiFontCache *pCache = NULL;\r
468     if (m_FontCache.Lookup((void*)dwMAT2, (void*&)pCache) && pCache != NULL) {\r
469         FX_LPCGDIGOCACHE pGO = pCache->GetCachedGlyphOutline(iGlyphIndex);\r
470         if (pGO != NULL) {\r
471             gm = pGO->gm;\r
472             pGlyphOutline = pGO->pOutline;\r
473         }\r
474     }\r
475     if (pGlyphOutline == NULL) {\r
476         FX_DWORD dwGlyphSize = ::GetGlyphOutlineW(m_hDC, iGlyphIndex, uFormat, &gm, 0, NULL, pMatrix);\r
477         if (dwGlyphSize == 0 || dwGlyphSize == GDI_ERROR) {\r
478             return 0;\r
479         }\r
480         pGlyphOutline = (FX_LPBYTE)FX_Alloc(dwGlyphSize);\r
481         ::GetGlyphOutlineW(m_hDC, iGlyphIndex, uFormat, &gm, dwGlyphSize, pGlyphOutline, pMatrix);\r
482         if (pCache == NULL) {\r
483             pCache = FX_NEW CFX_GdiFontCache;\r
484             if (m_FontCache.GetCount() >= FX_GDIFONT_FONTCACHESIZE) {\r
485                 ClearCache();\r
486             }\r
487             m_FontCache.SetAt((void*)dwMAT2, (void*)pCache);\r
488         }\r
489         pCache->SetCachedGlyphOutline(iGlyphIndex, gm, pGlyphOutline);\r
490     }\r
491     FX_DWORD dwDibSize = gm.gmBlackBoxX * 4 * gm.gmBlackBoxY;\r
492     if (pBuffer == NULL || bufSize < dwDibSize) {\r
493         return dwDibSize;\r
494     }\r
495     CreateGlyphBitmap(gm.gmBlackBoxX, gm.gmBlackBoxY, pGlyphOutline, (FX_LPDWORD)pBuffer, argb);\r
496     return dwDibSize;\r
497 }\r
498 FX_DWORD CFX_GdiFont::GetHashCode() const\r
499 {\r
500     return FX_GetFontHashCode(FX_GetCodePageFromCharset(m_LogFont.lfCharSet), FX_GetGdiFontStyles(m_LogFont));\r
501 }\r
502 FX_DWORD CFX_GdiFont::GetMAT2HashCode(const FIXED *pFixed)\r
503 {\r
504     FXSYS_assert(pFixed != NULL);\r
505     FX_DWORD dwHash1 = 0, dwHash2 = 5381, dwRet;\r
506     for (int i = 0; i < 4; i ++) {\r
507         dwRet = *((const FX_DWORD*)pFixed);\r
508         dwHash1 = 1313 * dwHash1 + dwRet;\r
509         dwHash2 += (dwHash2 << 5) + dwRet;\r
510         pFixed ++;\r
511     }\r
512     return ((dwHash1 & 0x0000FFFF) << 16) | (dwHash2 & 0x0000FFFF);\r
513 }\r
514 void CFX_GdiFont::CreateGlyphBitmap(int32_t iWidth, int32_t iHeight, FX_LPBYTE pOutline, FX_LPDWORD pDIB, FX_ARGB argb)\r
515 {\r
516     int32_t padding = ((iWidth + 3) / 4) * 4 - iWidth;\r
517     FX_DWORD alpha;\r
518     int32_t i, j;\r
519     for (j = iHeight - 1; j >= 0; --j) {\r
520         for (i = iWidth - 1; i >= 0; --i) {\r
521             if ((alpha = *pOutline++) == 0) {\r
522                 *pDIB++ = 0;\r
523             } else {\r
524                 alpha = (argb >> 24) * (alpha * 4 - 1) / 256;\r
525                 *pDIB++ = (alpha << 24) | (argb & 0x00FFFFFF);\r
526             }\r
527         }\r
528         pOutline += padding;\r
529     }\r
530 }\r
531 #endif\r
532 #endif\r