/* * (c) Copyright Ascensio System SIA 2010-2014 * * This program is a free software product. You can redistribute it and/or * modify it under the terms of the GNU Affero General Public License (AGPL) * version 3 as published by the Free Software Foundation. In accordance with * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect * that Ascensio System SIA expressly excludes the warranty of non-infringement * of any third-party rights. * * This program is distributed WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html * * You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, * EU, LV-1021. * * The interactive user interfaces in modified source and object code versions * of the Program must display Appropriate Legal Notices, as required under * Section 5 of the GNU AGPL version 3. * * Pursuant to Section 7(b) of the License you must retain the original Product * logo when distributing the program. Pursuant to Section 7(e) we decline to * grant you any rights under trademark law for use of our trademarks. * * All the Product's GUI elements, including illustrations and icon sets, as * well as technical writing content are licensed under the terms of the * Creative Commons Attribution-ShareAlike 4.0 International. See the License * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode * */ #ifndef _FONT_MANAGER_LIGHT_H #define _FONT_MANAGER_LIGHT_H #include "stdafx.h" #include #include "./../UncompressedFrame/UncompressedFrame.h" #include "WinFont.h" #include FT_OUTLINE_H #include FT_SIZES_H #include FT_GLYPH_H #include FT_TRUETYPE_IDS_H #include FT_TRUETYPE_TABLES_H #include FT_XFREE86_H #include FT_ADVANCES_H #define LOAD_MODE FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_BITMAP | FT_LOAD_LINEAR_DESIGN #define REND_MODE FT_RENDER_MODE_NORMAL #define FONT_FRACTION_BITS 2 #define FONT_FRACTION (1 << FONT_FRACTION_BITS) #define FONT_FRACTION_MULT ((double)1 / (double)FONT_FRACTION) #define FONT_ITALIC_ANGLE 0.3090169943749 struct TGlyphBitmap { int nX; int nY; int nWidth; int nHeight; BOOL bAA; unsigned char *pData; BOOL bFreeData; TGlyphBitmap() { nX = 0; nY = 0; nWidth = 0; nHeight = 0; bAA = FALSE; pData = NULL; bFreeData = NULL; } }; enum EGlyphState { glyphstateNormal = 0, glyphstateDeafault, glyphstateMiss }; struct TGlyph { long lUnicode; float fX; float fY; float fLeft; float fTop; float fRight; float fBottom; struct TMetrics { float fWidth; float fHeight; float fHoriBearingX; float fHoriBearingY; float fHoriAdvance; float fVertBearingX; float fVertBearingY; float fVertAdvance; } oMetrics; EGlyphState eState; bool bBitmap; TGlyphBitmap oBitmap; }; struct TFontCacheTag { int nCode; short nFracX; short nFracY; int nMRU; int nX; int nY; int nWidth; int nHeight; }; class CGlyphString { public: CGlyphString() { m_fX = 0; m_fY = 0; m_fEndX = 0; m_fEndY = 0; m_nGlyphIndex = -1; m_nGlyphsCount = 0; m_pGlyphsBuffer = NULL; m_arrCTM[0] = 1; m_arrCTM[1] = 0; m_arrCTM[2] = 0; m_arrCTM[3] = 1; m_arrCTM[4] = 0; m_arrCTM[5] = 0; m_fTransX = 0; m_fTransY = 0; } CGlyphString(CStringW wsString, float fX = 0, float fY = 0) { m_nGlyphIndex = 0; m_nGlyphsCount = wsString.GetLength(); if ( m_nGlyphsCount > 0 ) m_pGlyphsBuffer = new TGlyph[m_nGlyphsCount]; else m_pGlyphsBuffer = NULL; for ( int nIndex = 0; nIndex < m_nGlyphsCount; nIndex++ ) { m_pGlyphsBuffer[nIndex].lUnicode = wsString.GetAt( nIndex ); m_pGlyphsBuffer[nIndex].bBitmap = false; } m_fX = fX; m_fY = fY; m_arrCTM[0] = 1; m_arrCTM[1] = 0; m_arrCTM[2] = 0; m_arrCTM[3] = 1; m_arrCTM[4] = 0; m_arrCTM[5] = 0; m_fTransX = 0; m_fTransY = 0; } ~CGlyphString() { if ( m_pGlyphsBuffer ) delete []m_pGlyphsBuffer; } void SetString(CStringW wsString, float fX = 0, float fY = 0) { m_fX = fX + m_fTransX; m_fY = fY + m_fTransY; if ( m_pGlyphsBuffer ) delete []m_pGlyphsBuffer; m_nGlyphsCount = wsString.GetLength(); m_nGlyphIndex = 0; m_pGlyphsBuffer = new TGlyph[m_nGlyphsCount]; for ( int nIndex = 0; nIndex < m_nGlyphsCount; nIndex++ ) { m_pGlyphsBuffer[nIndex].lUnicode = wsString.GetAt( nIndex ); m_pGlyphsBuffer[nIndex].bBitmap = false; } } void Reset() { if ( m_pGlyphsBuffer ) delete []m_pGlyphsBuffer; m_fX = 0; m_fY = 0; m_fEndX = 0; m_fEndY = 0; m_nGlyphIndex = -1; m_nGlyphsCount = 0; m_pGlyphsBuffer = NULL; m_arrCTM[0] = 1; m_arrCTM[1] = 0; m_arrCTM[2] = 0; m_arrCTM[3] = 1; m_arrCTM[4] = 0; m_arrCTM[5] = 0; m_fTransX = 0; m_fTransY = 0; } int GetLength() { return m_nGlyphsCount; } void SetBBox(int nIndex, float fLeft, float fTop, float fRight, float fBottom) { if ( m_nGlyphsCount <= 0 ) return; int nCurIndex = min( m_nGlyphsCount - 1, max( 0, nIndex ) ); m_pGlyphsBuffer[nCurIndex].fLeft = fLeft; m_pGlyphsBuffer[nCurIndex].fTop = fTop; m_pGlyphsBuffer[nCurIndex].fRight = fRight; m_pGlyphsBuffer[nCurIndex].fBottom = fBottom; } void SetMetrics(int nIndex, float fWidth, float fHeight, float fHoriAdvance, float fHoriBearingX, float fHoriBearingY, float fVertAdvance, float fVertBearingX, float fVertBearingY) { if ( m_nGlyphsCount <= 0 ) return; int nCurIndex = min( m_nGlyphsCount - 1, max( 0, nIndex ) ); m_pGlyphsBuffer[nCurIndex].oMetrics.fHeight = fHeight; m_pGlyphsBuffer[nCurIndex].oMetrics.fHoriAdvance = fHoriAdvance; m_pGlyphsBuffer[nCurIndex].oMetrics.fHoriBearingX = fHoriBearingX; m_pGlyphsBuffer[nCurIndex].oMetrics.fHoriBearingY = fHoriBearingY; m_pGlyphsBuffer[nCurIndex].oMetrics.fVertAdvance = fVertAdvance; m_pGlyphsBuffer[nCurIndex].oMetrics.fVertBearingX = fVertBearingX; m_pGlyphsBuffer[nCurIndex].oMetrics.fVertBearingY = fVertBearingY; m_pGlyphsBuffer[nCurIndex].oMetrics.fWidth = fWidth; } void SetStartPoint(int nIndex, float fX, float fY) { if ( m_nGlyphsCount <= 0 ) return; int nCurIndex = min( m_nGlyphsCount - 1, max( 0, nIndex ) ); m_pGlyphsBuffer[nCurIndex].fX = fX; m_pGlyphsBuffer[nCurIndex].fY = fY; } void SetState(int nIndex, EGlyphState eState) { if ( m_nGlyphsCount <= 0 ) return; int nCurIndex = min( m_nGlyphsCount - 1, max( 0, nIndex ) ); m_pGlyphsBuffer[nCurIndex].eState = eState; } void GetBBox(float *pfLeft, float *pfTop, float *pfRight, float *pfBottom, int nIndex = -1, int nType = 0) { int nCurIndex = 0; if ( nIndex < 0 ) { if ( m_nGlyphsCount <= 0 || m_nGlyphIndex < 1 || m_nGlyphIndex > m_nGlyphsCount ) return; nCurIndex = m_nGlyphIndex - 1; } else { if ( m_nGlyphsCount <= 0 ) return; nCurIndex = min( m_nGlyphsCount - 1, max( 0, nIndex ) ); } float fBottom = -m_pGlyphsBuffer[nCurIndex].fBottom; float fRight = m_pGlyphsBuffer[nCurIndex].fRight; float fLeft = m_pGlyphsBuffer[nCurIndex].fLeft; float fTop = -m_pGlyphsBuffer[nCurIndex].fTop; if ( 0 == nType && !( 1 == m_arrCTM[0] && 0 == m_arrCTM[1] && 0 == m_arrCTM[2] && 1 == m_arrCTM[3] && 0 == m_arrCTM[4] && 0 == m_arrCTM[5] ) ) { float arrfX[4] = { fLeft, fLeft, fRight, fRight }; float arrfY[4] = { fTop, fBottom, fBottom, fTop }; float fMinX = (float)(arrfX[0] * m_arrCTM[0] + arrfY[0] * m_arrCTM[2]); float fMinY = (float)(arrfX[0] * m_arrCTM[1] + arrfY[0] * m_arrCTM[3]); float fMaxX = fMinX; float fMaxY = fMinY; for ( int nIndex = 1; nIndex < 4; nIndex++ ) { float fX = (float)(arrfX[nIndex] * m_arrCTM[0] + arrfY[nIndex] * m_arrCTM[2]); float fY = (float)(arrfX[nIndex] * m_arrCTM[1] + arrfY[nIndex] * m_arrCTM[3]); fMaxX = max( fMaxX, fX ); fMinX = min( fMinX, fX ); fMaxY = max( fMaxY, fY ); fMinY = min( fMinY, fY ); } fLeft = fMinX; fRight = fMaxX; fTop = fMinY; fBottom = fMaxY; } *pfLeft = fLeft + m_pGlyphsBuffer[nCurIndex].fX + m_fX; *pfRight = fRight + m_pGlyphsBuffer[nCurIndex].fX + m_fX; *pfTop = fTop + m_pGlyphsBuffer[nCurIndex].fY + m_fY; *pfBottom = fBottom + m_pGlyphsBuffer[nCurIndex].fY + m_fY; } void GetBBox2(float *pfLeft, float *pfTop, float *pfRight, float *pfBottom) { if ( m_nGlyphsCount <= 0 ) { *pfLeft = 0; *pfRight = 0; *pfBottom = 0; *pfTop = 0; } float fBottom = 0; float fRight = 0; float fLeft = 0; float fTop = 0; for ( int nIndex = 0; nIndex < m_nGlyphsCount; nIndex++ ) { fBottom = max( fBottom, -m_pGlyphsBuffer[nIndex].fBottom ); fTop = min( fTop, -m_pGlyphsBuffer[nIndex].fTop ); } if ( !( 1 == m_arrCTM[0] && 0 == m_arrCTM[1] && 0 == m_arrCTM[2] && 1 == m_arrCTM[3] && 0 == m_arrCTM[4] && 0 == m_arrCTM[5] ) ) { float arrfX[4] = { fLeft, fLeft, fRight, fRight }; float arrfY[4] = { fTop, fBottom, fBottom, fTop }; float fMinX = (float)(arrfX[0] * m_arrCTM[0] + arrfY[0] * m_arrCTM[2]); float fMinY = (float)(arrfX[0] * m_arrCTM[1] + arrfY[0] * m_arrCTM[3]); float fMaxX = fMinX; float fMaxY = fMinY; for ( int nIndex = 1; nIndex < 4; nIndex++ ) { float fX = (float)(arrfX[nIndex] * m_arrCTM[0] + arrfY[nIndex] * m_arrCTM[2]); float fY = (float)(arrfX[nIndex] * m_arrCTM[1] + arrfY[nIndex] * m_arrCTM[3]); fMaxX = max( fMaxX, fX ); fMinX = min( fMinX, fX ); fMaxY = max( fMaxY, fY ); fMinY = min( fMinY, fY ); } fLeft = fMinX; fRight = fMaxX; fTop = fMinY; fBottom = fMaxY; } fLeft += m_fX; fRight += m_fX; fTop += m_fY; fBottom += m_fY; *pfLeft = min( fLeft, min(m_fX, m_fEndX) ); *pfRight = max( fRight, max(m_fX, m_fEndX) ); *pfTop = min( fTop, min(m_fY, m_fEndY) ); *pfBottom = max( fBottom, max(m_fY, m_fEndY) ); } void SetCTM(float fA, float fB, float fC, float fD, float fE ,float fF) { m_arrCTM[0] = fA; m_arrCTM[1] = fB; m_arrCTM[2] = fC; m_arrCTM[3] = fD; m_arrCTM[4] = fE; m_arrCTM[5] = fF; double dDet = fA * fD - fB * fC; if ( dDet < 0.001 && dDet >= 0 ) dDet = 0.001; else if ( dDet > - 0.001 && dDet < 0 ) dDet = -0.001; m_dIDet = 1 / dDet; } void ResetCTM() { m_arrCTM[0] = 1; m_arrCTM[1] = 0; m_arrCTM[2] = 0; m_arrCTM[3] = 1; m_arrCTM[4] = 0; m_arrCTM[5] = 0; m_dIDet = 1; } void Transform(float *pfX, float *pfY) { float fX = *pfX, fY = *pfY; *pfX = (float) ( fX * m_arrCTM[0] + fY * m_arrCTM[2] + m_arrCTM[4] ); *pfY = (float) ( fX * m_arrCTM[1] + fY * m_arrCTM[3] + m_arrCTM[5] ); } void SetTrans(float fX, float fY) { m_fTransX = (float) ( m_dIDet * ( fX * m_arrCTM[3] - m_arrCTM[2] * fY ) ); m_fTransY = (float) ( m_dIDet * ( fY * m_arrCTM[0] - m_arrCTM[1] * fX ) ); } TGlyph *GetAt(int nIndex) { if ( m_nGlyphsCount <= 0 ) { return NULL; } int nCurIndex = min( m_nGlyphsCount - 1, max( 0, nIndex ) ); return &(m_pGlyphsBuffer[nCurIndex]); } BOOL GetNext(TGlyph *pGlyph) { if ( m_nGlyphIndex >= m_nGlyphsCount || m_nGlyphIndex < 0 ) { pGlyph = NULL; return FALSE; } *pGlyph = m_pGlyphsBuffer[m_nGlyphIndex]; m_nGlyphIndex++; return TRUE; } public: float m_fTransX; float m_fTransY; float m_fX; float m_fY; float m_fEndX; float m_fEndY; double m_arrCTM[6]; double m_dIDet; private: TGlyph *m_pGlyphsBuffer; int m_nGlyphsCount; int m_nGlyphIndex; }; struct TFontCacheSizes { unsigned short ushUnicode; EGlyphState eState; int nCMapIndex; unsigned short ushGID; float fAdvanceX; struct TBBox { float fMinX; float fMaxX; float fMinY; float fMaxY; } oBBox; struct TMetrics { float fWidth; float fHeight; float fHoriBearingX; float fHoriBearingY; float fHoriAdvance; float fVertBearingX; float fVertBearingY; float fVertAdvance; } oMetrics; bool bBitmap; TGlyphBitmap oBitmap; }; #define FONT_CASHE_SIZES_SIZE 255 #define FONT_CACHE_SIZES_INDEXES_SIZE 65536 #define FONT_CACHE_SIZES_INDEXES_SIZE_2 131072 class CFreeTypeFont { public: CFreeTypeFont() { m_pDefaultFont = NULL; m_bUseDefaultFont = FALSE; m_pSize = NULL; m_dTextScale = 1; m_dUnitsKoef = 1; m_bStringGID = FALSE; m_nDefaultChar = -1; m_nSymbolic = -1; m_pFace = NULL; m_pBaseAddress = NULL; m_hFile = NULL; m_hMapFile = NULL; m_bAntiAliasing = FALSE; m_bUseKerning = FALSE; m_fSize = 1; m_unHorDpi = 0; m_unVerDpi = 0; m_bNeedDoItalic = FALSE; m_bNeedDoBold = FALSE; m_fCharSpacing = 0; m_nMinX = 0; m_nMinY = 0; m_nMaxX = 0; m_nMaxY = 0; m_pCache = NULL; m_pCacheTags = NULL; m_nGlyphWidth = 0; m_nGlyphHeight = 0; m_nGlyphSize = 0; m_nCacheSets = 0; m_nCacheAssoc = 0; } ~CFreeTypeFont() { CloseFile(); } void SetDefaultFont(CFreeTypeFont* pFont) { m_pDefaultFont = pFont; } CFreeTypeFont* GetDefaultFont() { return m_pDefaultFont; } void SetUseDefaultFont(BOOL bUse) { m_bUseDefaultFont = bUse; } void CloseFile() { if (NULL != m_pFace) FT_Done_Face(m_pFace); if ( m_pBaseAddress ) UnmapViewOfFile( m_pBaseAddress ); if ( m_hMapFile ) CloseHandle( m_hMapFile ); if ( m_hFile ) CloseHandle( m_hFile ); m_pFace = NULL; m_pBaseAddress = NULL; m_hFile = NULL; m_hMapFile = NULL; } void InitCache() { m_nGlyphWidth = m_nMaxX - m_nMinX + 3; m_nGlyphHeight = m_nMaxY - m_nMinY + 3; if ( m_nGlyphHeight > 1000 || m_nGlyphWidth > 1000 ) { m_nGlyphSize = 0; m_nCacheSets = 0; m_nCacheAssoc = 0; m_pCache = NULL; m_pCacheTags = NULL; return; } if ( m_bAntiAliasing ) { m_nGlyphSize = m_nGlyphWidth * m_nGlyphHeight; } else { m_nGlyphSize = ((m_nGlyphWidth + 7) >> 3) * m_nGlyphHeight; } m_nCacheAssoc = 8; if ( m_nGlyphSize <= 256 ) { m_nCacheSets = 8; } else if ( m_nGlyphSize <= 512 ) { m_nCacheSets = 4; } else if ( m_nGlyphSize <= 1024 ) { m_nCacheSets = 2; } else { m_nCacheSets = 1; } m_pCache = (unsigned char *)malloc( m_nCacheSets * m_nCacheAssoc * m_nGlyphSize ); m_pCacheTags = (TFontCacheTag *)malloc( m_nCacheSets * m_nCacheAssoc * sizeof(TFontCacheTag) ); for ( int nIndex = 0; nIndex < m_nCacheSets * m_nCacheAssoc; ++nIndex ) { m_pCacheTags[nIndex].nMRU = nIndex & (m_nCacheAssoc - 1); } } void ClearCache() { if ( m_pCache ) { free( m_pCache ); } if ( m_pCacheTags ) { free( m_pCacheTags ); } InitCache(); } virtual BOOL GetGlyph(int nCode, int nFracX, int nFracY, TGlyphBitmap *pBitmap) { if ( !m_bAntiAliasing || m_nGlyphHeight > 50 ) { nFracX = nFracY = 0; } int nI = ( nCode & (m_nCacheSets - 1) ) * m_nCacheAssoc; for ( int nJ = 0; nJ < m_nCacheAssoc; ++nJ ) { if ( ( m_pCacheTags[nI + nJ].nMRU & 0x80000000 ) && m_pCacheTags[nI + nJ].nCode == nCode && (int)m_pCacheTags[nI + nJ].nFracX == nFracX && (int)m_pCacheTags[nI + nJ].nFracY == nFracY ) { pBitmap->nX = m_pCacheTags[nI + nJ].nX; pBitmap->nY = m_pCacheTags[nI + nJ].nY; pBitmap->nWidth = m_pCacheTags[nI + nJ].nWidth; pBitmap->nHeight = m_pCacheTags[nI + nJ].nHeight; for ( int nK = 0; nK < m_nCacheAssoc; ++nK ) { if ( nK != nJ && ( m_pCacheTags[nI + nK].nMRU & 0x7fffffff ) < ( m_pCacheTags[nI + nJ].nMRU & 0x7fffffff ) ) { ++m_pCacheTags[nI + nK].nMRU; } } m_pCacheTags[nI + nJ].nMRU = 0x80000000; pBitmap->bAA = m_bAntiAliasing; pBitmap->pData = m_pCache + (nI + nJ) * m_nGlyphSize; pBitmap->bFreeData = FALSE; return TRUE; } } TGlyphBitmap oNewBitmap; if ( !MakeGlyph( nCode, nFracX, nFracY, &oNewBitmap ) ) { return FALSE; } if ( oNewBitmap.nWidth > m_nGlyphWidth || oNewBitmap.nHeight > m_nGlyphHeight ) { *pBitmap = oNewBitmap; return TRUE; } int nSize = 0; if ( m_bAntiAliasing ) { nSize = oNewBitmap.nWidth * oNewBitmap.nHeight; } else { nSize = ((oNewBitmap.nWidth + 7) >> 3) * oNewBitmap.nHeight; } unsigned char *pBuffer = NULL; for ( int nJ = 0; nJ < m_nCacheAssoc; ++nJ ) { if ( ( m_pCacheTags[nI + nJ].nMRU & 0x7fffffff ) == m_nCacheAssoc - 1 ) { m_pCacheTags[nI + nJ].nMRU = 0x80000000; m_pCacheTags[nI + nJ].nCode = nCode; m_pCacheTags[nI + nJ].nFracX = (short)nFracX; m_pCacheTags[nI + nJ].nFracY = (short)nFracY; m_pCacheTags[nI + nJ].nX = oNewBitmap.nX; m_pCacheTags[nI + nJ].nY = oNewBitmap.nY; m_pCacheTags[nI + nJ].nWidth = oNewBitmap.nWidth; m_pCacheTags[nI + nJ].nHeight = oNewBitmap.nHeight; pBuffer = m_pCache + (nI + nJ) * m_nGlyphSize; memcpy( pBuffer, oNewBitmap.pData, nSize ); } else { ++m_pCacheTags[nI + nJ].nMRU; } } *pBitmap = oNewBitmap; pBitmap->pData = pBuffer; pBitmap->bFreeData = FALSE; if ( oNewBitmap.bFreeData ) { free( oNewBitmap.pData ); } return TRUE; } virtual BOOL MakeGlyph(int nCode, int nFracX, int nFracY, TGlyphBitmap *pBitmap) { FT_Int unGID = SetCMapForCharCode2( nCode ); if ( unGID <= 0 ) return FALSE; m_pFace->size = m_pSize; FT_Vector oOffset; oOffset.x = (FT_Pos)(int)( (double)nFracX * FONT_FRACTION_MULT * 64 ); oOffset.y = 0; FT_GlyphSlot pGlyphSlot = m_pFace->glyph; if (m_pDefaultFont) m_pDefaultFont->UpdateMatrix2(); UpdateMatrix2(); if ( FT_Load_Glyph( m_pFace, unGID, LOAD_MODE ) ) { return FALSE; } if ( FT_Render_Glyph( pGlyphSlot, REND_MODE ) ) { return FALSE; } pBitmap->nX = pGlyphSlot->bitmap_left; pBitmap->nY = pGlyphSlot->bitmap_top; pBitmap->nWidth = pGlyphSlot->bitmap.width; pBitmap->nHeight = pGlyphSlot->bitmap.rows; pBitmap->bAA = m_bAntiAliasing; int nRowSize = 0; if ( m_bAntiAliasing ) { if ( m_bNeedDoBold ) pBitmap->nWidth++; nRowSize = pBitmap->nWidth; } else { nRowSize = (pBitmap->nWidth + 7) >> 3; } pBitmap->pData = (unsigned char *)malloc( nRowSize * pBitmap->nHeight ); pBitmap->bFreeData = TRUE; int nIndex; unsigned char *pDstBuffer, *pSrcBuffer; if ( !m_bNeedDoBold || !m_bAntiAliasing ) { for ( nIndex = 0, pDstBuffer = pBitmap->pData, pSrcBuffer = pGlyphSlot->bitmap.buffer; nIndex < pBitmap->nHeight; ++nIndex, pDstBuffer += nRowSize, pSrcBuffer += pGlyphSlot->bitmap.pitch ) { memcpy( pDstBuffer, pSrcBuffer, nRowSize ); } } else { int nY, nX; for ( nY = 0, pDstBuffer = pBitmap->pData, pSrcBuffer = pGlyphSlot->bitmap.buffer; nY < pBitmap->nHeight; ++nY, pDstBuffer += nRowSize, pSrcBuffer += pGlyphSlot->bitmap.pitch ) { for ( nX = pBitmap->nWidth - 1; nX >= 0; nX-- ) { if ( 0 != nX ) { int nFirstByte, nSecondByte; if ( pBitmap->nWidth - 1 == nX ) nFirstByte = 0; else nFirstByte = pSrcBuffer[nX]; nSecondByte = pSrcBuffer[nX - 1]; pDstBuffer[nX] = min( 255, nFirstByte + nSecondByte); } else { pDstBuffer[nX] = pSrcBuffer[nX]; } } } } return TRUE; } virtual BOOL GetString(CGlyphString *pString) { if ( pString->GetLength() <= 0 ) return TRUE; unsigned int unPrevGID = 0; float fPenX = 0, fPenY = 0; FT_Face pSrcFace = m_pFace; FT_Face pDefFace = NULL; CFreeTypeFont *pDefFont = NULL; if ( m_pDefaultFont ) { pDefFont = m_pDefaultFont; pDefFace = m_pDefaultFont->m_pFace; } if ( pDefFont ) pDefFont->UpdateMatrix1(); UpdateMatrix1(); for ( int nIndex = 0; nIndex < pString->GetLength(); nIndex++ ) { FT_Face pFace = pSrcFace; TGlyph *pCurGlyph = pString->GetAt( nIndex ); unsigned short ushUnicode = (unsigned short)pCurGlyph->lUnicode; int nCacheIndex = FindInSizesCache( ushUnicode ); unsigned int unGID = 0; if ( 0xFFFF == nCacheIndex ) { int nCMapIndex = 0; unGID = (unsigned int)SetCMapForCharCode( ushUnicode, &nCMapIndex ); TFontCacheSizes oSizes; oSizes.ushUnicode = ushUnicode; if ( !( ( unGID > 0 ) || ( -1 != m_nSymbolic && ( ushUnicode < 0xF000 ) && 0 < ( unGID = (unsigned int)SetCMapForCharCode( ushUnicode + 0xF000, &nCMapIndex ) ) ) ) ) { if ( FALSE == m_bUseDefaultFont || NULL == pDefFont || 0 >= ( unGID = pDefFont->SetCMapForCharCode( ushUnicode, &nCMapIndex ) ) ) { if ( m_nDefaultChar < 0 ) { oSizes.ushGID = -1; oSizes.eState = glyphstateMiss; oSizes.fAdvanceX = (float)(pSrcFace->size->metrics.max_advance >> 6) / 2.f; pString->SetStartPoint( nIndex, fPenX, fPenY ); pString->SetBBox( nIndex, 0, 0, 0, 0 ); pString->SetState( nIndex, glyphstateMiss ); FT_Fixed lAdv = 0; fPenX += oSizes.fAdvanceX + m_fCharSpacing; unPrevGID = 0; continue; } else { unGID = m_nDefaultChar; oSizes.eState = glyphstateNormal; pString->SetState( nIndex, glyphstateNormal ); pFace = pSrcFace; } } else { oSizes.eState = glyphstateDeafault; pString->SetState( nIndex, glyphstateDeafault ); pFace = pDefFace; } } else { oSizes.eState = glyphstateNormal; pString->SetState( nIndex, glyphstateNormal ); pFace = pSrcFace; } oSizes.ushGID = unGID; oSizes.nCMapIndex = nCMapIndex; if ( m_bUseKerning && unPrevGID && ( nIndex >= 0 && pString->GetAt( nIndex )->eState == pString->GetAt( nIndex - 1 )->eState ) ) { FT_Vector oDelta; FT_Get_Kerning( pFace, unPrevGID, unGID, FT_KERNING_DEFAULT, &oDelta ); fPenX += (float)(oDelta.x >> 6); } float fX = pString->m_fX + fPenX; float fY = pString->m_fY + fPenY; float fXX = (float)(pString->m_arrCTM[4] + fX * pString->m_arrCTM[0] + fY * pString->m_arrCTM[2] - pString->m_fX ); float fYY = (float)(pString->m_arrCTM[5] + fX * pString->m_arrCTM[1] + fY * pString->m_arrCTM[3] - pString->m_fY ); pString->SetStartPoint( nIndex, fXX, fYY); if ( FT_Load_Glyph( pFace, unGID, LOAD_MODE ) ) { pString->SetStartPoint( nIndex, -0xFFFF, -0xFFFF ); pString->SetState( nIndex, glyphstateMiss ); continue; } FT_Glyph pGlyph = NULL; if ( FT_Get_Glyph( pFace->glyph, &pGlyph ) ) { pString->SetStartPoint( nIndex, -0xFFFF, -0xFFFF ); pString->SetState( nIndex, glyphstateMiss ); continue; } FT_BBox oBBox; FT_Glyph_Get_CBox( pGlyph, ft_glyph_bbox_gridfit, &oBBox ); FT_Done_Glyph( pGlyph ); oSizes.fAdvanceX = (float)(pFace->glyph->linearHoriAdvance * m_dUnitsKoef / pFace->units_per_EM); oSizes.oBBox.fMinX = (float)(oBBox.xMin >> 6); oSizes.oBBox.fMaxX = (float)(oBBox.xMax >> 6); oSizes.oBBox.fMinY = (float)(oBBox.yMin >> 6); oSizes.oBBox.fMaxY = (float)(oBBox.yMax >> 6); oSizes.oMetrics.fHeight = (float)(pFace->glyph->metrics.height >> 6); oSizes.oMetrics.fHoriAdvance = (float)(pFace->glyph->metrics.horiAdvance >> 6); oSizes.oMetrics.fHoriBearingX = (float)(pFace->glyph->metrics.horiBearingX >> 6); oSizes.oMetrics.fHoriBearingY = (float)(pFace->glyph->metrics.horiBearingY >> 6); oSizes.oMetrics.fVertAdvance = (float)(pFace->glyph->metrics.vertAdvance >> 6); oSizes.oMetrics.fVertBearingX = (float)(pFace->glyph->metrics.vertBearingX >> 6); oSizes.oMetrics.fVertBearingY = (float)(pFace->glyph->metrics.vertBearingY >> 6); oSizes.oMetrics.fWidth = (float)(pFace->glyph->metrics.width >> 6); oSizes.bBitmap = false; oSizes.oBitmap.nX = 0; oSizes.oBitmap.nY = 0; oSizes.oBitmap.nHeight = 0; oSizes.oBitmap.nWidth = 0; oSizes.oBitmap.bFreeData = FALSE; oSizes.oBitmap.pData = NULL; oSizes.oBitmap.bAA = FALSE; pString->SetMetrics( nIndex, oSizes.oMetrics.fWidth, oSizes.oMetrics.fHeight, oSizes.oMetrics.fHoriAdvance, oSizes.oMetrics.fHoriBearingX, oSizes.oMetrics.fHoriBearingY, oSizes.oMetrics.fVertAdvance, oSizes.oMetrics.fVertBearingX, oSizes.oMetrics.fVertBearingY ); pString->SetBBox( nIndex, oSizes.oBBox.fMinX, oSizes.oBBox.fMaxY, oSizes.oBBox.fMaxX, oSizes.oBBox.fMinY ); fPenX += oSizes.fAdvanceX + m_fCharSpacing; if ( m_bNeedDoBold ) { fPenX += 1; } AddToSizesCache( oSizes ); } else { TFontCacheSizes oSizes = m_oCacheSizes.Get(nCacheIndex); int nCMapIndex = oSizes.nCMapIndex; unGID = oSizes.ushGID; EGlyphState eState = oSizes.eState; if ( glyphstateMiss == eState ) { pString->SetStartPoint( nIndex, fPenX, fPenY ); pString->SetBBox( nIndex, 0, 0, 0, 0 ); pString->SetState( nIndex, glyphstateMiss ); FT_Fixed lAdv = 0; fPenX += oSizes.fAdvanceX + m_fCharSpacing; unPrevGID = 0; continue; } else if ( glyphstateDeafault == eState ) { pString->SetState( nIndex, glyphstateDeafault ); pFace = pDefFace; } else { pString->SetState( nIndex, glyphstateNormal ); pFace = pSrcFace; } if ( 0 != pFace->num_charmaps ) { int nCurCMapIndex = FT_Get_Charmap_Index( pFace->charmap ); if ( nCurCMapIndex != nCMapIndex ) { nCMapIndex = max( 0, nCMapIndex ); FT_Set_Charmap( pFace, pFace->charmaps[nCMapIndex] ); } } if ( m_bUseKerning && unPrevGID && ( nIndex >= 0 && pString->GetAt( nIndex )->eState == pString->GetAt( nIndex - 1 )->eState ) ) { FT_Vector oDelta; FT_Get_Kerning( pFace, unPrevGID, unGID, FT_KERNING_DEFAULT, &oDelta ); fPenX += (float)(oDelta.x >> 6); } float fX = pString->m_fX + fPenX; float fY = pString->m_fY + fPenY; float fXX = (float)(pString->m_arrCTM[4] + fX * pString->m_arrCTM[0] + fY * pString->m_arrCTM[2] - pString->m_fX ); float fYY = (float)(pString->m_arrCTM[5] + fX * pString->m_arrCTM[1] + fY * pString->m_arrCTM[3] - pString->m_fY ); pString->SetStartPoint( nIndex, fXX, fYY); pString->SetMetrics( nIndex, oSizes.oMetrics.fWidth, oSizes.oMetrics.fHeight, oSizes.oMetrics.fHoriAdvance, oSizes.oMetrics.fHoriBearingX, oSizes.oMetrics.fHoriBearingY, oSizes.oMetrics.fVertAdvance, oSizes.oMetrics.fVertBearingX, oSizes.oMetrics.fVertBearingY ); pString->SetBBox( nIndex, oSizes.oBBox.fMinX, oSizes.oBBox.fMaxY, oSizes.oBBox.fMaxX, oSizes.oBBox.fMinY ); fPenX += oSizes.fAdvanceX + m_fCharSpacing; if ( m_bNeedDoBold ) { fPenX += 1; } oSizes.bBitmap = false; oSizes.oBitmap.nX = 0; oSizes.oBitmap.nY = 0; oSizes.oBitmap.nHeight = 0; oSizes.oBitmap.nWidth = 0; oSizes.oBitmap.bFreeData = FALSE; oSizes.oBitmap.pData = NULL; oSizes.oBitmap.bAA = FALSE; } unPrevGID = unGID; } pString->m_fEndX = fPenX + pString->m_fX; pString->m_fEndY = fPenY + pString->m_fY; if ( pDefFont ) pDefFont->UpdateMatrix2(); UpdateMatrix2(); return TRUE; } virtual BOOL GetString2(CGlyphString *pString) { if ( pString->GetLength() <= 0 ) return TRUE; unsigned int unPrevGID = 0; float fPenX = 0, fPenY = 0; FT_Face pSrcFace = m_pFace; FT_Face pDefFace = NULL; CFreeTypeFont* pDefFont = NULL; if ( m_pDefaultFont ) { pDefFont = m_pDefaultFont; pDefFace = m_pDefaultFont->m_pFace; } for ( int nIndex = 0; nIndex < pString->GetLength(); nIndex++ ) { if ( pDefFont ) pDefFont->UpdateMatrix1(); UpdateMatrix1(); FT_Face pFace = pSrcFace; TGlyph *pCurGlyph = pString->GetAt( nIndex ); unsigned short ushUnicode = (unsigned short)pCurGlyph->lUnicode; int nCacheIndex = FindInSizesCache( ushUnicode ); unsigned int unGID = 0; if ( 0xFFFF == nCacheIndex ) { int nCMapIndex = 0; unGID = (unsigned int)SetCMapForCharCode( ushUnicode, &nCMapIndex ); TFontCacheSizes oSizes; oSizes.ushUnicode = ushUnicode; if ( !( ( unGID > 0 ) || ( -1 != m_nSymbolic && ( ushUnicode < 0xF000 ) && 0 < ( unGID = (unsigned int)SetCMapForCharCode( ushUnicode + 0xF000, &nCMapIndex ) ) ) ) ) { if ( FALSE == m_bUseDefaultFont || NULL == pDefFont || 0 >= ( unGID = pDefFont->SetCMapForCharCode( ushUnicode, &nCMapIndex ) ) ) { if ( m_nDefaultChar < 0 ) { oSizes.ushGID = -1; oSizes.eState = glyphstateMiss; oSizes.fAdvanceX = (float)(pSrcFace->size->metrics.max_advance >> 6) / 2.f; pString->SetStartPoint( nIndex, fPenX, fPenY ); pString->SetBBox( nIndex, 0, 0, 0, 0 ); pString->SetState( nIndex, glyphstateMiss ); FT_Fixed lAdv = 0; fPenX += oSizes.fAdvanceX + m_fCharSpacing; continue; } else { unGID = m_nDefaultChar; oSizes.eState = glyphstateNormal; pString->SetState( nIndex, glyphstateNormal ); pFace = pSrcFace; } } else { oSizes.eState = glyphstateDeafault; pString->SetState( nIndex, glyphstateDeafault ); pFace = pDefFace; } } else { oSizes.eState = glyphstateNormal; pString->SetState( nIndex, glyphstateNormal ); pFace = pSrcFace; } oSizes.ushGID = unGID; oSizes.nCMapIndex = nCMapIndex; if ( m_bUseKerning && unPrevGID && ( nIndex >= 0 && pString->GetAt( nIndex )->eState == pString->GetAt( nIndex - 1 )->eState ) ) { FT_Vector oDelta; FT_Get_Kerning( pFace, unPrevGID, unGID, FT_KERNING_DEFAULT, &oDelta ); fPenX += (float)(oDelta.x >> 6); } float fX = pString->m_fX + fPenX; float fY = pString->m_fY + fPenY; float fXX = (float)(pString->m_arrCTM[4] + fX * pString->m_arrCTM[0] + fY * pString->m_arrCTM[2] - pString->m_fX ); float fYY = (float)(pString->m_arrCTM[5] + fX * pString->m_arrCTM[1] + fY * pString->m_arrCTM[3] - pString->m_fY ); pString->SetStartPoint( nIndex, fXX, fYY); if ( pDefFont ) pDefFont->UpdateMatrix2(); UpdateMatrix2(); if ( FT_Load_Glyph( pFace, unGID, LOAD_MODE ) ) { pString->SetStartPoint( nIndex, -0xFFFF, -0xFFFF ); pString->SetState( nIndex, glyphstateMiss ); continue; } FT_Glyph pGlyph = NULL; if ( FT_Get_Glyph( pFace->glyph, &pGlyph ) ) { pString->SetStartPoint( nIndex, -0xFFFF, -0xFFFF ); pString->SetState( nIndex, glyphstateMiss ); continue; } FT_BBox oBBox; FT_Glyph_Get_CBox( pGlyph, ft_glyph_bbox_gridfit, &oBBox ); FT_Done_Glyph( pGlyph ); float fAdvX = (float)(pFace->glyph->linearHoriAdvance * m_dUnitsKoef / pFace->units_per_EM ); oSizes.fAdvanceX = fAdvX; oSizes.oBBox.fMinX = (float)(oBBox.xMin >> 6); oSizes.oBBox.fMaxX = (float)(oBBox.xMax >> 6); oSizes.oBBox.fMinY = (float)(oBBox.yMin >> 6); oSizes.oBBox.fMaxY = (float)(oBBox.yMax >> 6); oSizes.oMetrics.fHeight = (float)(pFace->glyph->metrics.height >> 6); oSizes.oMetrics.fHoriAdvance = (float)(pFace->glyph->metrics.horiAdvance >> 6); oSizes.oMetrics.fHoriBearingX = (float)(pFace->glyph->metrics.horiBearingX >> 6); oSizes.oMetrics.fHoriBearingY = (float)(pFace->glyph->metrics.horiBearingY >> 6); oSizes.oMetrics.fVertAdvance = (float)(pFace->glyph->metrics.vertAdvance >> 6); oSizes.oMetrics.fVertBearingX = (float)(pFace->glyph->metrics.vertBearingX >> 6); oSizes.oMetrics.fVertBearingY = (float)(pFace->glyph->metrics.vertBearingY >> 6); oSizes.oMetrics.fWidth = (float)(pFace->glyph->metrics.width >> 6); pString->SetMetrics( nIndex, oSizes.oMetrics.fWidth, oSizes.oMetrics.fHeight, oSizes.oMetrics.fHoriAdvance, oSizes.oMetrics.fHoriBearingX, oSizes.oMetrics.fHoriBearingY, oSizes.oMetrics.fVertAdvance, oSizes.oMetrics.fVertBearingX, oSizes.oMetrics.fVertBearingY ); pString->SetBBox( nIndex, oSizes.oBBox.fMinX, oSizes.oBBox.fMaxY, oSizes.oBBox.fMaxX, oSizes.oBBox.fMinY ); fPenX += oSizes.fAdvanceX + m_fCharSpacing; if ( m_bNeedDoBold ) { fPenX += 1; } pCurGlyph->bBitmap = true; FT_GlyphSlot pGlyphSlot = pFace->glyph; if ( FT_Render_Glyph( pGlyphSlot, REND_MODE ) ) { return FALSE; } TGlyphBitmap *pBitmap = &(pCurGlyph->oBitmap); pBitmap->nX = pGlyphSlot->bitmap_left; pBitmap->nY = pGlyphSlot->bitmap_top; pBitmap->nWidth = pGlyphSlot->bitmap.width; pBitmap->nHeight = pGlyphSlot->bitmap.rows; pBitmap->bAA = m_bAntiAliasing; int nRowSize = 0; if ( m_bAntiAliasing ) { if ( m_bNeedDoBold ) pBitmap->nWidth++; nRowSize = pBitmap->nWidth; } else { nRowSize = (pBitmap->nWidth + 7) >> 3; } if (0 != (nRowSize * pBitmap->nHeight)) pBitmap->pData = (unsigned char *)malloc( nRowSize * pBitmap->nHeight ); else pBitmap->pData = NULL; pBitmap->bFreeData = FALSE; int nIndex2; unsigned char *pDstBuffer, *pSrcBuffer; if (NULL != pBitmap->pData) { if ( !m_bNeedDoBold || !m_bAntiAliasing ) { for ( nIndex2 = 0, pDstBuffer = pBitmap->pData, pSrcBuffer = pGlyphSlot->bitmap.buffer; nIndex2 < pBitmap->nHeight; ++nIndex2, pDstBuffer += nRowSize, pSrcBuffer += pGlyphSlot->bitmap.pitch ) { memcpy( pDstBuffer, pSrcBuffer, nRowSize ); } } else { int nY, nX; for ( nY = 0, pDstBuffer = pBitmap->pData, pSrcBuffer = pGlyphSlot->bitmap.buffer; nY < pBitmap->nHeight; ++nY, pDstBuffer += nRowSize, pSrcBuffer += pGlyphSlot->bitmap.pitch ) { for ( nX = pBitmap->nWidth - 1; nX >= 0; nX-- ) { if ( 0 != nX ) { int nFirstByte, nSecondByte; if ( pBitmap->nWidth - 1 == nX ) nFirstByte = 0; else nFirstByte = pSrcBuffer[nX]; nSecondByte = pSrcBuffer[nX - 1]; pDstBuffer[nX] = min( 255, nFirstByte + nSecondByte); } else { pDstBuffer[nX] = pSrcBuffer[nX]; } } } } } oSizes.bBitmap = pCurGlyph->bBitmap; oSizes.oBitmap.bAA = pBitmap->bAA; oSizes.oBitmap.bFreeData = pBitmap->bFreeData; oSizes.oBitmap.nX = pBitmap->nX; oSizes.oBitmap.nY = pBitmap->nY; oSizes.oBitmap.nWidth = pBitmap->nWidth; oSizes.oBitmap.nHeight = pBitmap->nHeight; oSizes.oBitmap.pData = pBitmap->pData; AddToSizesCache( oSizes ); } else { TFontCacheSizes oSizes = m_oCacheSizes.Get(nCacheIndex); int nCMapIndex = oSizes.nCMapIndex; unGID = oSizes.ushGID; EGlyphState eState = oSizes.eState; if ( glyphstateMiss == eState ) { pString->SetStartPoint( nIndex, fPenX, fPenY ); pString->SetBBox( nIndex, 0, 0, 0, 0 ); pString->SetState( nIndex, glyphstateMiss ); FT_Fixed lAdv = 0; fPenX += oSizes.fAdvanceX + m_fCharSpacing; unPrevGID = 0; continue; } else if ( glyphstateDeafault == eState ) { pString->SetState( nIndex, glyphstateDeafault ); pFace = pDefFace; } else { pString->SetState( nIndex, glyphstateNormal ); pFace = pSrcFace; } if ( 0 != pFace->num_charmaps ) { int nCurCMapIndex = FT_Get_Charmap_Index( pFace->charmap ); if ( nCurCMapIndex != nCMapIndex ) { nCMapIndex = max( 0, nCMapIndex ); FT_Set_Charmap( pFace, pFace->charmaps[nCMapIndex] ); } } if ( m_bUseKerning && unPrevGID && ( nIndex >= 0 && pString->GetAt( nIndex )->eState == pString->GetAt( nIndex - 1 )->eState ) ) { FT_Vector oDelta; FT_Get_Kerning( pFace, unPrevGID, unGID, FT_KERNING_DEFAULT, &oDelta ); fPenX += (float)(oDelta.x >> 6); } float fX = pString->m_fX + fPenX; float fY = pString->m_fY + fPenY; float fXX = (float)(pString->m_arrCTM[4] + fX * pString->m_arrCTM[0] + fY * pString->m_arrCTM[2] - pString->m_fX ); float fYY = (float)(pString->m_arrCTM[5] + fX * pString->m_arrCTM[1] + fY * pString->m_arrCTM[3] - pString->m_fY ); pString->SetStartPoint( nIndex, fXX, fYY); pString->SetMetrics( nIndex, oSizes.oMetrics.fWidth, oSizes.oMetrics.fHeight, oSizes.oMetrics.fHoriAdvance, oSizes.oMetrics.fHoriBearingX, oSizes.oMetrics.fHoriBearingY, oSizes.oMetrics.fVertAdvance, oSizes.oMetrics.fVertBearingX, oSizes.oMetrics.fVertBearingY ); pString->SetBBox( nIndex, oSizes.oBBox.fMinX, oSizes.oBBox.fMaxY, oSizes.oBBox.fMaxX, oSizes.oBBox.fMinY ); fPenX += oSizes.fAdvanceX + m_fCharSpacing; if ( m_bNeedDoBold ) { fPenX += 1; } pCurGlyph->bBitmap = oSizes.bBitmap; pCurGlyph->oBitmap = oSizes.oBitmap; } unPrevGID = unGID; } pString->m_fEndX = fPenX + pString->m_fX; pString->m_fEndY = fPenY + pString->m_fY; if ( pDefFont ) pDefFont->UpdateMatrix2(); UpdateMatrix2(); return TRUE; } virtual short GetAscender() { return m_pFace->ascender; } virtual short GetDescender() { return m_pFace->descender; } virtual unsigned short GetUnitsPerEm() { return m_pFace->units_per_EM; } virtual short GetLineSpacing() { return m_pFace->height; } virtual char * GetFamilyName() { return m_pFace->family_name; } virtual long GetFacesCount() { return m_pFace->num_faces; } virtual long GetFaceIndex() { return m_pFace->face_index; } virtual long GetGlyphsCount() { return m_pFace->num_glyphs; } virtual char *GetStyleName() { return m_pFace->style_name; } virtual short GetUnderlinePosition() { return m_pFace->underline_position; } virtual short GetUnderlineThickness() { return m_pFace->underline_thickness; } virtual short GetMaxAdvanceWidth() { return m_pFace->max_advance_width; } virtual short GetMaxAdvanceHeight() { return m_pFace->max_advance_height; } virtual void GetBBox(long *plMinX, long *plMinY, long *plMaxX, long *plMaxY) { *plMinX = m_pFace->bbox.xMin; *plMinY = m_pFace->bbox.yMin; *plMaxX = m_pFace->bbox.xMax; *plMaxY = m_pFace->bbox.yMax; } virtual bool IsCharAvailable(long lUnicode) { return ( SetCMapForCharCode2( lUnicode ) > 0 ); } virtual void SetSizeAndDpi(float fSize, unsigned int unHorDpi, unsigned int unVerDpi) { if ( m_pDefaultFont ) { m_pDefaultFont->SetSizeAndDpi( fSize, unHorDpi, unVerDpi ); } ClearCache(); ClearSizesCache(); float fOldSize = m_fSize; float fNewSize = fSize; float fKoef = fNewSize / fOldSize; if ( fKoef > 1.001 || fKoef < 0.999 || unHorDpi != m_unHorDpi || unVerDpi != m_unVerDpi ) { m_unHorDpi = unHorDpi; m_unVerDpi = unVerDpi; if ( fKoef > 1.001 || fKoef < 0.999 ) { m_fSize = fNewSize; UpdateMatrix0(); } m_dUnitsKoef = m_unHorDpi / 72.0 * m_fSize; if ( FT_Set_Char_Size( m_pFace, 0, (int)(fNewSize * 64), unHorDpi, unVerDpi ) ) { return; } } } virtual const char *GetFontFormat() { return FT_Get_X11_Font_Format(m_pFace); } virtual int IsUnicodeRangeAvailable(unsigned long ulBit, unsigned int un4ByteIndex) { FT_Face pFace = m_pFace; TT_OS2 *pOs2 = (TT_OS2 *)FT_Get_Sfnt_Table( pFace, ft_sfnt_os2 ); if ( NULL == pOs2 || 0xFFFF == pOs2->version ) return -1; int nResult = 0; unsigned long ulMult = 1; for ( unsigned long ulIndex = 0; ulIndex < ulBit; ulIndex++ ) ulMult <<= 1; switch(un4ByteIndex) { case 0: if ( pOs2->ulUnicodeRange1 & ulMult ) nResult = 1; break; case 1: if ( pOs2->ulUnicodeRange2 & ulMult ) nResult = 1; break; case 2: if ( pOs2->ulUnicodeRange3 & ulMult ) nResult = 1; break; case 3: if ( pOs2->ulUnicodeRange4 & ulMult ) nResult = 1; break; case 4: if ( pOs2->ulCodePageRange1 & ulMult ) nResult = 1; break; case 5: if ( pOs2->ulCodePageRange2 & ulMult ) nResult = 1; break; } if ( 4 == un4ByteIndex && 0 == nResult ) { for( int nIndex = 0; nIndex < pFace->num_charmaps; nIndex++ ) { if ( 31 == ulBit && 0 == pFace->charmaps[nIndex]->encoding_id && 3 == pFace->charmaps[nIndex]->platform_id ) { nResult = 1; break; } if ( 17 == ulBit && 2 == pFace->charmaps[nIndex]->encoding_id && 3 == pFace->charmaps[nIndex]->platform_id ) { nResult = 1; break; } if ( 18 == ulBit && 3 == pFace->charmaps[nIndex]->encoding_id && 3 == pFace->charmaps[nIndex]->platform_id ) { nResult = 1; break; } if ( 20 == ulBit && 4 == pFace->charmaps[nIndex]->encoding_id && 3 == pFace->charmaps[nIndex]->platform_id ) { nResult = 1; break; } if ( 19 == ulBit && 5 == pFace->charmaps[nIndex]->encoding_id && 3 == pFace->charmaps[nIndex]->platform_id ) { nResult = 1; break; } if ( 21 == ulBit && 6 == pFace->charmaps[nIndex]->encoding_id && 3 == pFace->charmaps[nIndex]->platform_id ) { nResult = 1; break; } } } return nResult; } virtual unsigned long GetCodeByGID(unsigned short unGID) { FT_Face pFace = m_pFace; if ( 0 == pFace->num_charmaps ) return unGID; int nCharCode = 0; if ( !pFace ) return nCharCode; for ( int nIndex = 0; nIndex < pFace->num_charmaps; nIndex++ ) { FT_CharMap pCharMap = pFace->charmaps[nIndex]; if ( FT_Set_Charmap( pFace, pCharMap ) ) continue; FT_ULong unCharCode; FT_UInt unCurGID; unCharCode = FT_Get_First_Char( pFace, &unCurGID ); while ( unCurGID != 0 ) { if ( unGID == unCurGID ) return unCharCode; unCharCode = FT_Get_Next_Char( pFace, unCharCode, &unCurGID ); } } return 0; } virtual void GetPanose(char **ppPanose) { TT_OS2 *pTable = (TT_OS2 *)FT_Get_Sfnt_Table( m_pFace, ft_sfnt_os2 ); ::memset( *ppPanose, 0x00, 10 ); if ( NULL == pTable ) return; ::memcpy( *ppPanose, pTable->panose, 10 ); } virtual bool IsFixedWidth() { return FT_IS_FIXED_WIDTH( m_pFace ) != 0; } virtual unsigned short GetNameIndex(char *sName) { unsigned int unGID = FT_Get_Name_Index( m_pFace, sName ); return unGID; } virtual void SetStringGID(BOOL bGID) { if ( m_bStringGID == bGID ) return; ClearSizesCache(); m_bStringGID = bGID; } virtual BOOL GetStringGID() { return m_bStringGID; } virtual void ResetFontMatrix() { if ( m_pDefaultFont ) { m_pDefaultFont->ResetFontMatrix(); } if ( m_bNeedDoItalic ) { m_arrdFontMatrix[0] = 1; m_arrdFontMatrix[1] = 0; m_arrdFontMatrix[2] = FONT_ITALIC_ANGLE; m_arrdFontMatrix[3] = 1; m_arrdFontMatrix[4] = 0; m_arrdFontMatrix[5] = 0; } else { m_arrdFontMatrix[0] = 1; m_arrdFontMatrix[1] = 0; m_arrdFontMatrix[2] = 0; m_arrdFontMatrix[3] = 1; m_arrdFontMatrix[4] = 0; m_arrdFontMatrix[5] = 0; } UpdateMatrix0(); } virtual void ResetTextMatrix() { if ( m_pDefaultFont ) { m_pDefaultFont->ResetTextMatrix(); } m_arrdTextMatrix[0] = 1; m_arrdTextMatrix[1] = 0; m_arrdTextMatrix[2] = 0; m_arrdTextMatrix[3] = 1; m_arrdTextMatrix[4] = 0; m_arrdTextMatrix[5] = 0; } virtual void ApplyTransform(float fA, float fB, float fC, float fD, float fE, float fF) { if ( m_pDefaultFont ) { m_pDefaultFont->ApplyTransform( fA, fB, fC, fD, fE, fF ); } double arrTemp[6] = { m_arrdFontMatrix[0], m_arrdFontMatrix[1], m_arrdFontMatrix[2], m_arrdFontMatrix[3] }; m_arrdFontMatrix[0] = arrTemp[0] * fA + arrTemp[1] * fC; m_arrdFontMatrix[1] = arrTemp[0] * fB + arrTemp[1] * fD; m_arrdFontMatrix[2] = arrTemp[2] * fA + arrTemp[3] * fC; m_arrdFontMatrix[3] = arrTemp[2] * fB + arrTemp[3] * fD; m_arrdFontMatrix[4] = arrTemp[4] * fA + arrTemp[5] * fC + fE; m_arrdFontMatrix[5] = arrTemp[4] * fB + arrTemp[5] * fD + fF; UpdateMatrix0(); } virtual void SetFontMatrix(float fA, float fB, float fC, float fD, float fE, float fF) { if ( m_pDefaultFont ) { m_pDefaultFont->SetFontMatrix( fA, fB, fC, fD, fE, fF ); } if ( m_bNeedDoItalic ) { m_arrdFontMatrix[0] = fA; m_arrdFontMatrix[1] = fB; m_arrdFontMatrix[2] = fC + fA * FONT_ITALIC_ANGLE; m_arrdFontMatrix[3] = fD + fB * FONT_ITALIC_ANGLE; m_arrdFontMatrix[4] = fE; m_arrdFontMatrix[5] = fF; } else { m_arrdFontMatrix[0] = fA; m_arrdFontMatrix[1] = fB; m_arrdFontMatrix[2] = fC; m_arrdFontMatrix[3] = fD; m_arrdFontMatrix[4] = fE; m_arrdFontMatrix[5] = fF; } ClearSizesCache(); } virtual void SetTextMatrix(float fA, float fB, float fC, float fD, float fE, float fF) { if ( m_pDefaultFont ) { m_pDefaultFont->SetTextMatrix( fA, fB, fC, fD, fE, fF ); } m_arrdTextMatrix[0] = fA; m_arrdTextMatrix[1] = -fB; m_arrdTextMatrix[2] = -fC; m_arrdTextMatrix[3] = fD; m_arrdTextMatrix[4] = fE; m_arrdTextMatrix[5] = fF; ClearSizesCache(); } int GetSymbolic() { return m_nSymbolic; } public: int SetCMapForCharCode(long lUnicode, int *pnCMapIndex) { *pnCMapIndex = -1; if ( m_bStringGID || 0 == m_pFace->num_charmaps ) return lUnicode; int nCharIndex = 0; if ( !m_pFace ) return nCharIndex; for ( int nIndex = 0; nIndex < m_pFace->num_charmaps; nIndex++ ) { FT_CharMap pCharMap = m_pFace->charmaps[nIndex]; if ( FT_Set_Charmap( m_pFace, pCharMap ) ) continue; FT_Encoding pEncoding = pCharMap->encoding; if ( FT_ENCODING_UNICODE == pEncoding ) { if ( nCharIndex = FT_Get_Char_Index( m_pFace, lUnicode ) ) { *pnCMapIndex = nIndex; return nCharIndex; } } else if ( FT_ENCODING_NONE == pEncoding || FT_ENCODING_MS_SYMBOL == pEncoding || FT_ENCODING_APPLE_ROMAN == pEncoding ) { FT_ULong charcode; FT_UInt gindex; charcode = FT_Get_First_Char( m_pFace, &gindex ); while ( gindex != 0 ) { charcode = FT_Get_Next_Char( m_pFace, charcode, &gindex ); if ( charcode == lUnicode ) { nCharIndex = gindex; *pnCMapIndex = nIndex; break; } } if ( nCharIndex = FT_Get_Char_Index( m_pFace, lUnicode ) ) { *pnCMapIndex = nIndex; } } } return nCharIndex; } int SetCMapForCharCode2(long lUnicode) { if ( m_bStringGID ) return lUnicode; FT_Int unGID; int nCMapIndex = 0; int nCacheIndex = m_arrCacheSizesIndexs[(unsigned short)lUnicode]; if ( 0xFFFF == nCacheIndex ) { return unGID = SetCMapForCharCode( lUnicode, &nCMapIndex ); } else { TFontCacheSizes oSizes = m_oCacheSizes.Get(nCacheIndex); unGID = oSizes.ushGID; nCMapIndex = oSizes.nCMapIndex; if ( 0 != m_pFace->num_charmaps ) { int nCurCMapIndex = FT_Get_Charmap_Index( m_pFace->charmap ); if ( nCurCMapIndex != nCMapIndex ) { nCMapIndex = max( 0, nCMapIndex ); FT_Set_Charmap( m_pFace, m_pFace->charmaps[nCMapIndex] ); } } } return unGID; } inline void UpdateMatrix0() { FT_Face pFace = m_pFace; double dSize = m_fSize; m_dTextScale = sqrt( m_arrdTextMatrix[2] * m_arrdTextMatrix[2] + m_arrdTextMatrix[3] * m_arrdTextMatrix[3] ); double dDiv = pFace->bbox.xMax > 20000 ? 65536 : 1; if ( pFace->units_per_EM == 0 ) pFace->units_per_EM = 2048; int nX = (int)((m_arrdFontMatrix[0] * pFace->bbox.xMin + m_arrdFontMatrix[2] * pFace->bbox.yMin) * dSize / (dDiv * pFace->units_per_EM)); m_nMinX = m_nMaxX = nX; int nY = (int)((m_arrdFontMatrix[1] * pFace->bbox.xMin + m_arrdFontMatrix[3] * pFace->bbox.yMin) * dSize / (dDiv * pFace->units_per_EM)); m_nMinY = m_nMaxY = nY; nX = (int)((m_arrdFontMatrix[0] * pFace->bbox.xMin + m_arrdFontMatrix[2] * pFace->bbox.yMax) * dSize / (dDiv * pFace->units_per_EM)); if ( nX < m_nMinX ) { m_nMinX = nX; } else if ( nX > m_nMaxX ) { m_nMaxX = nX; } nY = (int)((m_arrdFontMatrix[1] * pFace->bbox.xMin + m_arrdFontMatrix[3] * pFace->bbox.yMax) * dSize / (dDiv * pFace->units_per_EM)); if ( nY < m_nMinY ) { m_nMinY = nY; } else if ( nY > m_nMaxY ) { m_nMaxY = nY; } nX = (int)((m_arrdFontMatrix[0] * pFace->bbox.xMax + m_arrdFontMatrix[2] * pFace->bbox.yMin) * dSize / (dDiv * pFace->units_per_EM)); if ( nX < m_nMinX ) { m_nMinX = nX; } else if ( nX > m_nMaxX ) { m_nMaxX = nX; } nY = (int)((m_arrdFontMatrix[1] * pFace->bbox.xMax + m_arrdFontMatrix[3] * pFace->bbox.yMin) * dSize / (dDiv * pFace->units_per_EM)); if ( nY < m_nMinY ) { m_nMinY = nY; } else if ( nY > m_nMaxY ) { m_nMaxY = nY; } nX = (int)((m_arrdFontMatrix[0] * pFace->bbox.xMax + m_arrdFontMatrix[2] * pFace->bbox.yMax) * dSize / (dDiv * pFace->units_per_EM)); if ( nX < m_nMinX ) { m_nMinX = nX; } else if ( nX > m_nMaxX ) { m_nMaxX = nX; } nY = (int)((m_arrdFontMatrix[1] * pFace->bbox.xMax + m_arrdFontMatrix[3] * pFace->bbox.yMax) * dSize / (dDiv * pFace->units_per_EM)); if ( nY < m_nMinY ) { m_nMinY = nY; } else if ( nY > m_nMaxY ) { m_nMaxY = nY; } if ( m_nMaxX == m_nMinX ) { m_nMinX = 0; m_nMaxX = (int)dSize; } if ( m_nMaxY == m_nMinY ) { m_nMinY = 0; m_nMaxY = (int)((double)1.2 * dSize); } m_oFontMatrix.xx = (FT_Fixed)(m_arrdFontMatrix[0] * 65536); m_oFontMatrix.yx = (FT_Fixed)(m_arrdFontMatrix[1] * 65536); m_oFontMatrix.xy = (FT_Fixed)(m_arrdFontMatrix[2] * 65536); m_oFontMatrix.yy = (FT_Fixed)(m_arrdFontMatrix[3] * 65536); m_oTextMatrix.xx = (FT_Fixed)((m_arrdTextMatrix[0] / m_dTextScale) * 65536); m_oTextMatrix.yx = (FT_Fixed)((m_arrdTextMatrix[1] / m_dTextScale) * 65536); m_oTextMatrix.xy = (FT_Fixed)((m_arrdTextMatrix[2] / m_dTextScale) * 65536); m_oTextMatrix.yy = (FT_Fixed)((m_arrdTextMatrix[3] / m_dTextScale) * 65536); FT_Set_Transform( pFace, &m_oFontMatrix, NULL ); } inline void UpdateMatrix1() { m_oFontMatrix.xx = (FT_Fixed)(m_arrdFontMatrix[0] * 65536); m_oFontMatrix.yx = (FT_Fixed)(m_arrdFontMatrix[1] * 65536); m_oFontMatrix.xy = (FT_Fixed)(m_arrdFontMatrix[2] * 65536); m_oFontMatrix.yy = (FT_Fixed)(m_arrdFontMatrix[3] * 65536); FT_Set_Transform( m_pFace, &m_oFontMatrix, NULL ); } inline void UpdateMatrix2() { m_oFontMatrix.xx = (FT_Fixed)(( m_arrdFontMatrix[0] * m_arrdTextMatrix[0] + m_arrdFontMatrix[1] * m_arrdTextMatrix[2] ) * 65536); m_oFontMatrix.yx = (FT_Fixed)(( m_arrdFontMatrix[0] * m_arrdTextMatrix[1] + m_arrdFontMatrix[1] * m_arrdTextMatrix[3] ) * 65536); m_oFontMatrix.xy = (FT_Fixed)(( m_arrdFontMatrix[2] * m_arrdTextMatrix[0] + m_arrdFontMatrix[3] * m_arrdTextMatrix[2] ) * 65536); m_oFontMatrix.yy = (FT_Fixed)(( m_arrdFontMatrix[2] * m_arrdTextMatrix[1] + m_arrdFontMatrix[3] * m_arrdTextMatrix[3] ) * 65536); FT_Set_Transform( m_pFace, &m_oFontMatrix, NULL ); } void InitSizesCache() { m_oCacheSizes.Init(); } void ClearSizesCache() { m_oCacheSizes.Clear(); ::memset( m_arrCacheSizesIndexs, 0xFF, FONT_CACHE_SIZES_INDEXES_SIZE_2 ); } void AddToSizesCache(TFontCacheSizes oSizes) { m_arrCacheSizesIndexs[oSizes.ushUnicode] = m_oCacheSizes.Add( oSizes ); } __forceinline int FindInSizesCache(int nCode) { return m_arrCacheSizesIndexs[nCode]; } void GetDefaultChar() { TT_OS2 *pTable = (TT_OS2*)FT_Get_Sfnt_Table(m_pFace, ft_sfnt_os2); if (NULL == pTable) m_nDefaultChar = -1; m_nDefaultChar = pTable->usDefaultChar; } int GetSymbolicCmapIndex() { TT_OS2 *pOs2 = (TT_OS2 *)FT_Get_Sfnt_Table( m_pFace, ft_sfnt_os2 ); if ( NULL == pOs2 || 0xFFFF == pOs2->version ) return -1; if ( !( pOs2->ulCodePageRange1 & 0x80000000 ) && !( pOs2->ulCodePageRange1 == 0 && pOs2->ulCodePageRange2 == 0 ) ) return -1; for( int nIndex = 0; nIndex < m_pFace->num_charmaps; nIndex++ ) { if ( 0 == m_pFace->charmaps[nIndex]->encoding_id && 3 == m_pFace->charmaps[nIndex]->platform_id ) return nIndex; } return -1; } void UpdateStyles(BOOL bBold, BOOL bItalic) { CStringA sStyle = GetStyleName(); BOOL bSrcBold = ( -1 != sStyle.Find( "Bold" ) ); BOOL bSrcItalic = ( -1 != sStyle.Find( "Italic" ) ); if ( !bBold ) { SetBold( FALSE ); } else if ( bBold ) { if ( bSrcBold ) { SetBold( FALSE ); } else { SetBold( TRUE ); } } if ( !bItalic ) { SetItalic( FALSE ); } else if ( bItalic ) { if ( bSrcItalic ) { SetItalic( FALSE ); } else { SetItalic( TRUE ); } } } void SetBold(BOOL bBold) { m_bNeedDoBold = bBold; }; BOOL GetBold() { return m_bNeedDoBold; } void SetItalic(BOOL bItalic) { m_bNeedDoItalic = bItalic; ResetFontMatrix(); } BOOL GetItalic() { return m_bNeedDoItalic; } public: BOOL LoadFont(FT_Library pLibrary, wchar_t* wsFileName, long lIndex, BOOL bUseAA, BOOL bUseKern) { CloseFile(); FT_Face pFace = NULL; HANDLE hFile = CreateFile( (LPCWSTR)wsFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hFile) return NULL; DWORD nFileSize = GetFileSize(hFile, NULL); HANDLE hMapFile = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, nFileSize, NULL); if (NULL == hMapFile) { CloseHandle( hFile ); return FALSE; } void *pBaseAddress = MapViewOfFile( hMapFile, FILE_MAP_READ, 0, 0, 0 ); if ( !pBaseAddress ) { CloseHandle( hMapFile ); CloseHandle( hFile ); return FALSE; } FT_Open_Args oOpenArgs; oOpenArgs.flags = FT_OPEN_MEMORY; oOpenArgs.memory_base = (BYTE*)pBaseAddress; oOpenArgs.memory_size = (FT_Long)nFileSize; if (FT_Open_Face(pLibrary, &oOpenArgs, lIndex, &pFace)) { CloseHandle( hMapFile ); CloseHandle( hFile ); return FALSE; } if ( NULL == pFace->charmap && 0 != pFace->num_charmaps ) FT_Set_Charmap( pFace, pFace->charmaps[0] ); m_pFace = pFace; m_pBaseAddress = pBaseAddress; m_hFile = hFile; m_hMapFile = hMapFile; m_dUnitsKoef = 1.0; m_nDefaultChar = -1; GetDefaultChar(); m_nSymbolic = GetSymbolicCmapIndex(); if ( FT_New_Size( m_pFace, &m_pSize ) ) { return FALSE; } m_pFace->size = m_pSize; if ( FT_Set_Char_Size( m_pFace, 0, (int)m_fSize * 64, 0, 0 ) ) { return FALSE; } ResetFontMatrix(); ResetTextMatrix(); m_bAntiAliasing = bUseAA; m_bUseKerning = bUseKern; if ( TRUE == m_bUseKerning ) { m_bUseKerning = ( FT_HAS_KERNING( m_pFace ) > 0 ? TRUE : FALSE ); } InitSizesCache(); ::memset( m_arrCacheSizesIndexs, 0xFF, FONT_CACHE_SIZES_INDEXES_SIZE_2 ); m_bStringGID = FALSE; return true; } void SetCharSpacing(float fCharSpacing) { m_fCharSpacing = fCharSpacing; } float GetCharSpacing() { return m_fCharSpacing; } private: FT_Size m_pSize; FT_Matrix m_oFontMatrix; FT_Matrix m_oTextMatrix; double m_dTextScale; double m_dUnitsKoef; BOOL m_bStringGID; int m_nDefaultChar; int m_nSymbolic; FT_Face m_pFace; void *m_pBaseAddress; HANDLE m_hFile; HANDLE m_hMapFile; CFreeTypeFont* m_pDefaultFont; BOOL m_bUseDefaultFont; double m_arrdFontMatrix[6]; double m_arrdTextMatrix[6]; BOOL m_bAntiAliasing; BOOL m_bUseKerning; float m_fSize; unsigned int m_unHorDpi; unsigned int m_unVerDpi; BOOL m_bNeedDoItalic; BOOL m_bNeedDoBold; float m_fCharSpacing; int m_nMinX; int m_nMinY; int m_nMaxX; int m_nMaxY; unsigned char *m_pCache; TFontCacheTag *m_pCacheTags; int m_nGlyphWidth; int m_nGlyphHeight; int m_nGlyphSize; int m_nCacheSets; int m_nCacheAssoc; class CFontCacheSizes { public: CFontCacheSizes() { } ~CFontCacheSizes() { } void Init() { m_arrSizes.RemoveAll(); } void Clear() { for ( int nIndex = 0; nIndex < m_arrSizes.GetSize(); nIndex++ ) { unsigned char *pData = m_arrSizes.GetData()[nIndex].oBitmap.pData; if ( NULL != pData ) { free( pData ); pData = NULL; } } m_arrSizes.RemoveAll(); } int Add(TFontCacheSizes oSizes) { m_arrSizes.Add( oSizes ); return m_arrSizes.GetSize() - 1; } TFontCacheSizes Get(int nIndex) { return m_arrSizes.GetData()[nIndex]; } private: CSimpleArray m_arrSizes; } m_oCacheSizes; unsigned short m_arrCacheSizesIndexs[FONT_CACHE_SIZES_INDEXES_SIZE]; }; class CFontManagerLight { private: long m_lUnit; CGlyphString m_oGlyphString; FT_Library m_pLibrary; CFreeTypeFont* m_pFont; BOOL m_bStringGID; BOOL m_bUseDefaultFont; double m_dCharSpacing; BOOL m_bAntiAliasing; BOOL m_bUseKerning; BOOL m_bUseCIDs; CFreeTypeFont* m_pDefaultFont[4]; public: CFontManagerLight() { m_pFont = NULL; for (LONG i = 0; i < 4; ++i) m_pDefaultFont[i] = NULL; m_pLibrary = NULL; if (FT_Init_FreeType(&m_pLibrary)) m_pLibrary = NULL; m_bStringGID = FALSE; m_bUseDefaultFont = TRUE; m_dCharSpacing = 0; m_bAntiAliasing = TRUE; m_bUseKerning = TRUE; m_bUseCIDs = FALSE; } ~CFontManagerLight() { RELEASEOBJECT(m_pFont); for (LONG i = 0; i < 4; ++i) RELEASEOBJECT((m_pDefaultFont[i])); if (NULL != m_pLibrary) { FT_Done_FreeType(m_pLibrary); m_pLibrary = NULL; } } BOOL LoadFontFromFile(CString sSrcPath, float fEmSize, double dHorDpi, double dVerDpi, long lFaceIndex) { if (!m_pLibrary) return FALSE; RELEASEOBJECT(m_pFont); m_pFont = new CFreeTypeFont(); BSTR bsFontPath = sSrcPath.AllocSysString(); BOOL bIsOpened = m_pFont->LoadFont(m_pLibrary, bsFontPath, lFaceIndex, m_bAntiAliasing, m_bUseKerning); SysFreeString(bsFontPath); if (!bIsOpened) { RELEASEOBJECT(m_pFont); return FALSE; } m_pFont->UpdateStyles(FALSE, FALSE); m_pFont->SetDefaultFont(m_pDefaultFont[0]); m_pFont->SetUseDefaultFont( m_bUseDefaultFont ); fEmSize = (float)UpdateSize( (double) fEmSize, dVerDpi, (unsigned int)dVerDpi ); m_pFont->SetSizeAndDpi( fEmSize, (unsigned int)dHorDpi, (unsigned int)dVerDpi ); m_pFont->SetStringGID( m_bStringGID ); m_pFont->SetCharSpacing( (float)m_dCharSpacing ); m_oGlyphString.ResetCTM(); m_pFont->SetTextMatrix( 1, 0, 0, 1, 0, 0 ); return S_OK; } CFreeTypeFont* GetFont() { return m_pFont; } BOOL LoadString(BSTR bsString, float fX, float fY) { if ( !m_pFont ) return FALSE; CStringW wsBuffer = CStringW( bsString ); m_oGlyphString.SetString( wsBuffer, fX, fY ); m_pFont->GetString( &m_oGlyphString ); return TRUE; } BOOL LoadString2(BSTR bsString, float fX, float fY) { if ( !m_pFont ) { m_oGlyphString.Reset(); return FALSE; } CStringW wsBuffer = CStringW( bsString ); m_oGlyphString.SetString( wsBuffer, fX, fY ); m_pFont->GetString2( &m_oGlyphString ); return TRUE; } BOOL GetNextChar(TGlyphBitmap& oBitmap, float& fX, float& fY) { fX = -0xFFFF; fY = -0xFFFF; oBitmap.pData = NULL; BOOL ret = FALSE; BOOL bNotLast = TRUE; TGlyph oCurGlyph; if ( !(m_oGlyphString.GetNext( &oCurGlyph )) ) { return ret; } if (!m_pFont) return ret; if ( glyphstateNormal == oCurGlyph.eState || ( glyphstateDeafault == oCurGlyph.eState && NULL != m_pFont->GetDefaultFont() ) ) { long lUnicode = oCurGlyph.lUnicode; CFreeTypeFont *pCurFont = NULL; if ( glyphstateNormal == oCurGlyph.eState ) pCurFont = m_pFont; else pCurFont = m_pFont->GetDefaultFont(); if ( false == oCurGlyph.bBitmap ) pCurFont->GetGlyph( lUnicode, 0, 0, &oBitmap ); else oBitmap = oCurGlyph.oBitmap; if ( oBitmap.nWidth <= 0 || oBitmap.nHeight <= 0 ) { oBitmap.pData = NULL; } fX = m_oGlyphString.m_fX + oCurGlyph.fX + oBitmap.nX; fY = m_oGlyphString.m_fY + oCurGlyph.fY - oBitmap.nY; } else { oBitmap.pData = NULL; fX = m_oGlyphString.m_fX + oCurGlyph.fX; fY = m_oGlyphString.m_fY + oCurGlyph.fY; } ret = TRUE; return ret; } BOOL FillString(BSTR bsText, double dX, double dY, double dDpiX, double dDpiY, IUncompressedFrame* pFrame, DWORD dwColor) { double _x = dX * dDpiX / 25.4; double _y = dY * dDpiY / 25.4; m_pFont->SetTextMatrix(1, 0, 0, 1, 0, 0); LoadString2(bsText, (float)_x, (float)_y); float fX = 0; float fY = 0; VARIANT_BOOL bRes = VARIANT_FALSE; while (TRUE) { TGlyphBitmap oGlyph; float fX = 0, fY = 0; BOOL ret = GetNextChar(oGlyph, fX, fY); if (FALSE == ret) break; if (NULL != oGlyph.pData) { FillGlyph(pFrame, (int)fX, (int)fY, dwColor, oGlyph); } } return TRUE; } void FillGlyph(IUncompressedFrame* pFrame, int x, int y, DWORD dwColor, TGlyphBitmap& oGlyph) { BYTE* pBuffer = NULL; pFrame->get_Buffer(&pBuffer); LONG lWidth = 0; LONG lHeight = 0; pFrame->get_Width(&lWidth); pFrame->get_Height(&lHeight); LONG _srcX = 0; LONG _srcY = 0; LONG _srcW = oGlyph.nWidth; LONG _srcH = oGlyph.nHeight; if (x < 0) { _srcX += x; _srcW += x; x = 0; } if (y < 0) { _srcY += y; _srcH += y; y = 0; } LONG lOffsetX = x + _srcW - lWidth; LONG lOffsetY = y + _srcH - lHeight; if (lOffsetX > 0) _srcW -= lOffsetX; if (lOffsetY > 0) _srcH -= lOffsetY; if (_srcW <= 0 || _srcH <= 0) return; LONG lR = _srcX + _srcW; LONG lB = _srcY + _srcH; BYTE cb = (BYTE)((dwColor >> 24) & 0xFF); BYTE cg = (BYTE)((dwColor >> 16) & 0xFF); BYTE cr = (BYTE)((dwColor >> 8) & 0xFF); BYTE ca = (BYTE)(dwColor & 0xFF); BYTE* pLine = pBuffer + 4 * y * lWidth + 4 * x; for (LONG j = _srcY; j < lB; ++j) { BYTE* pAlpha = oGlyph.pData + oGlyph.nWidth * j + _srcX; BYTE* pPixels = pLine; for (LONG i = _srcX; i < lR; ++i, ++pAlpha) { _blend_pixel(pPixels, cr, cg, cb, ca, *pAlpha); pPixels += 4; } pLine += (4 * lWidth); } } void SetDefaultFont(CString strName, CWinFontList* pList) { for ( int nIndex = 0; nIndex < 4; nIndex++ ) { LONG bBold, bItalic; switch( nIndex ) { case 0: bBold = 0; bItalic = 0; break; case 1: bBold = 1; bItalic = 0; break; case 2: bBold = 0; bItalic = 1; break; case 3: bBold = 1; bItalic = 1; break; } CString strStyle = _T(""); strStyle.Format(_T("