2793 lines
64 KiB
C++
2793 lines
64 KiB
C++
/*
|
|
* (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 <math.h>
|
|
|
|
#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<TFontCacheSizes> 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("<Style bold='%d' italic='%d'/>"), bBold, bItalic);
|
|
|
|
CString strFontName = strName;
|
|
|
|
strFontName.Replace(L"&", L"&");
|
|
strFontName.Replace(L"'", L"'");
|
|
strFontName.Replace(L"<", L"<");
|
|
strFontName.Replace(L">", L">");
|
|
strFontName.Replace(L"\"", L""");
|
|
|
|
CString sXml = _T("<FontProperties><Name value='");
|
|
sXml += strFontName;
|
|
sXml += _T("'/>");
|
|
sXml += strStyle;
|
|
sXml += _T("</FontProperties>");
|
|
|
|
CWinFontInfo *pFontInfo = pList->GetByParams(sXml);
|
|
if (NULL == pFontInfo)
|
|
continue;
|
|
|
|
RELEASEOBJECT((m_pDefaultFont[nIndex]));
|
|
|
|
m_pDefaultFont[nIndex] = new CFreeTypeFont();
|
|
|
|
BSTR bsFontPath = pFontInfo->m_wsFontPath.AllocSysString();
|
|
BOOL bIsOpened = m_pDefaultFont[nIndex]->LoadFont(m_pLibrary, bsFontPath, pFontInfo->m_lIndex, m_bAntiAliasing, m_bUseKerning);
|
|
SysFreeString(bsFontPath);
|
|
|
|
if (!bIsOpened)
|
|
{
|
|
RELEASEOBJECT(m_pDefaultFont[nIndex]);
|
|
continue;
|
|
}
|
|
|
|
m_pDefaultFont[nIndex]->UpdateStyles(bBold, bItalic);
|
|
}
|
|
}
|
|
|
|
CString GetFontPath(CString strName, CWinFontList* pList)
|
|
{
|
|
CString strFontName = strName;
|
|
|
|
strFontName.Replace(L"&", L"&");
|
|
strFontName.Replace(L"'", L"'");
|
|
strFontName.Replace(L"<", L"<");
|
|
strFontName.Replace(L">", L">");
|
|
strFontName.Replace(L"\"", L""");
|
|
|
|
CString sXml = _T("<FontProperties><Name value='");
|
|
sXml += strFontName;
|
|
sXml += _T("'/>");
|
|
sXml += _T("</FontProperties>");
|
|
|
|
CWinFontInfo *pFontInfo = pList->GetByParams(sXml);
|
|
if (pFontInfo)
|
|
return pFontInfo->m_wsFontPath;
|
|
|
|
return _T("");
|
|
}
|
|
|
|
private:
|
|
|
|
double UpdateSize(double dOldSize, double dDpi, double dNewDpi)
|
|
{
|
|
if ( 0 == dNewDpi ) dNewDpi = 72.0;
|
|
if ( 0 == dDpi ) dDpi = 72.0;
|
|
|
|
return dOldSize * dDpi / dNewDpi;
|
|
}
|
|
double UpdateDpi(double dDpi, double dSize, double dNewSize)
|
|
{
|
|
if ( 0 == dNewSize ) dNewSize = 10.0;
|
|
if ( 0 == dDpi ) dDpi = 72.0;
|
|
|
|
return dDpi * dSize / dNewSize;
|
|
}
|
|
|
|
__forceinline void _blend_pixel(BYTE* p, BYTE cr, BYTE cg, BYTE cb, BYTE ca, BYTE cover)
|
|
{
|
|
BYTE alpha = (BYTE)((ca * (cover + 1)) >> 8);
|
|
if (alpha == 255)
|
|
{
|
|
p[0] = cb;
|
|
p[1] = cg;
|
|
p[2] = cr;
|
|
p[3] = 255;
|
|
}
|
|
|
|
BYTE r = p[2];
|
|
BYTE g = p[1];
|
|
BYTE b = p[0];
|
|
BYTE a = p[3];
|
|
p[2] = (BYTE)(((cr - r) * alpha + (r << 8)) >> 8);
|
|
p[1] = (BYTE)(((cg - g) * alpha + (g << 8)) >> 8);
|
|
p[0] = (BYTE)(((cb - b) * alpha + (b << 8)) >> 8);
|
|
p[3] = (BYTE)((alpha + a) - ((alpha * a + 255) >> 8));
|
|
}
|
|
};
|
|
|
|
#endif |