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