Commit bc470ac5 authored by Oleg.Korshul's avatar Oleg.Korshul Committed by Alexander Trofimov

git-svn-id:...

git-svn-id: svn://fileserver/activex/AVS/Sources/TeamlabOffice/trunk/ServerComponents@52331 954022d7-b5bf-4e40-9824-e11837661b57
parent b56cea22
#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 // 18 ( Word 2007)
//-------------------------------------------------------------------------------------------------------------------------------
// TGlyphBitmap
//-------------------------------------------------------------------------------------------------------------------------------
struct TGlyphBitmap
{
int nX; // X
int nY; // Y
int nWidth; //
int nHeight; //
BOOL bAA; // Anti-aliased: True , Bitmap 8-(.. ); False - Bitmap 1-
unsigned char *pData; // Bitmap data( )
BOOL bFreeData; // True, pData
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; // BaseLine
float fLeft; //
float fTop; // BBox
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; // x y int
int nMRU; // Valid bit (0x80000000) MRU
int nX; // X
int nY; // Y
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++ )
{
//memset( (void *)(m_pGlyphsBuffer + nIndex), 0x00, sizeof( TGlyph ) );
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++ )
{
//memset( (void *)(m_pGlyphsBuffer + nIndex), 0x00, sizeof( TGlyph ) );
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] ) )
{
// BBox
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 );
//fRight = max( fRight, m_pGlyphsBuffer[nIndex].fRight );
//fLeft = min( fLeft, m_pGlyphsBuffer[nIndex].fLeft );
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] ) )
{
// BBox
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; // ( )^(-1)
private:
TGlyph *m_pGlyphsBuffer; //
int m_nGlyphsCount; //
int m_nGlyphIndex; //
};
//-------------------------------------------------------------------------------------------------------------------------------
struct TFontCacheSizes
{
unsigned short ushUnicode; //
EGlyphState eState; // /
int nCMapIndex; // 'cmap',
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 // 65536 * sizeof(unsigned short)
//-------------------------------------------------------------------------------------------------------------------------------
// CFreeTypeFont
//-------------------------------------------------------------------------------------------------------------------------------
class CFreeTypeFont
{
public:
CFreeTypeFont()
{
m_pSize = NULL;
m_dTextScale = 1;
m_dUnitsKoef = 1;
m_bStringGID = FALSE;
m_nDefaultChar = -1;
m_nSymbolic = -1;
m_pFace = NULL;
// file
m_pBaseAddress = NULL;
m_hFile = NULL;
m_hMapFile = NULL;
// font
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()
{
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 );
}
void InitCache()
{
// (max - min + 1), 2 , .
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; // 24
}
else
{
m_nGlyphSize = ((m_nGlyphWidth + 7) >> 3) * m_nGlyphHeight; // 1
}
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)
{
// non-anti-aliased ( )
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;
}
}
// GlyphBitmap
TGlyphBitmap oNewBitmap;
if ( !MakeGlyph( nCode, nFracX, nFracY, &oNewBitmap ) )
{
return FALSE;
}
// Glyph BBox, Bitmap
if ( oNewBitmap.nWidth > m_nGlyphWidth || oNewBitmap.nHeight > m_nGlyphHeight )
{
*pBitmap = oNewBitmap;
return TRUE;
}
// GlyphBitmap
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;
// TO DO: (".notdef") TrueType
UpdateMatrix2();
if ( FT_Load_Glyph( m_pFace, unGID, LOAD_MODE ) )
{
return FALSE;
}
if ( FT_Render_Glyph( pGlyphSlot, REND_MODE /*m_bAntiAliasing ? ft_render_mode_normal : ft_render_mode_mono*/ ) )
{
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;
// FontMatrix
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 ) ) ) ) )
{
//
unGID = m_nDefaultChar;
oSizes.eState = glyphstateNormal;
pString->SetState( nIndex, glyphstateNormal );
}
else
{
oSizes.eState = glyphstateNormal;
pString->SetState( nIndex, glyphstateNormal );
}
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 );
//pString->SetBBox( nIndex, (float)(oBBox.xMin >> 6), (float)(oBBox.yMax >> 6), (float)(oBBox.xMax >> 6), (float)(oBBox.yMin >> 6) );
fPenX += oSizes.fAdvanceX + m_fCharSpacing;//(float)(pFace->glyph->advance.x >> 6);
if ( m_bNeedDoBold )
{
// , 1 ( DPI 1 )
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 );
}
else // if ( glyphstateNormal == eState )
{
pString->SetState( nIndex, glyphstateNormal );
}
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 )
{
// , 1 ( DPI 1 )
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;
//pCurGlyph->bBitmap = m_oCacheSizes.Get(nCacheIndex).bBitmap;//m_arrCacheSizes[nCacheIndex].bBitmap;
//pCurGlyph->oBitmap = m_oCacheSizes.Get(nCacheIndex).oBitmap;//m_arrCacheSizes[nCacheIndex].oBitmap;
}
unPrevGID = unGID;
}
pString->m_fEndX = fPenX + pString->m_fX;
pString->m_fEndY = fPenY + pString->m_fY;
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;
for ( int nIndex = 0; nIndex < pString->GetLength(); nIndex++ )
{
// FontMatrix
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 ) ) ) ) )
{
//
unGID = m_nDefaultChar;
oSizes.eState = glyphstateNormal;
pString->SetState( nIndex, glyphstateNormal );
}
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);
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 )
{
// , 1 ( DPI 1 )
fPenX += 1;
}
pCurGlyph->bBitmap = true;
FT_GlyphSlot pGlyphSlot = pFace->glyph;
if ( FT_Render_Glyph( pGlyphSlot, REND_MODE/*m_bAntiAliasing ? ft_render_mode_normal : ft_render_mode_mono*/ ) )
{
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)
{
//double dKoef = ( 255 + 10 ) / (double)255;
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 )
{
//for ( int nX = 0; nX < nRowSize; nX++ )
//{
// pDstBuffer[nX] = min( 255, ( pSrcBuffer[nX]) * dKoef );
//}
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 );
}
else // if ( glyphstateNormal == eState )
{
pString->SetState( nIndex, glyphstateNormal );
}
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 )
{
// , 1 ( DPI 1 )
fPenX += 1;
}
pCurGlyph->bBitmap = oSizes.bBitmap;// m_oCacheSizes.Get(nCacheIndex).bBitmap;
pCurGlyph->oBitmap = oSizes.oBitmap;// m_oCacheSizes.Get(nCacheIndex).oBitmap;
}
unPrevGID = unGID;
}
pString->m_fEndX = fPenX + pString->m_fX;
pString->m_fEndY = fPenY + pString->m_fY;
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)
{
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;
// (dSize) DPI
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;
}
// , charset
// ulCodePageRange, Cmap.
// Charset Name Charset Value(hex) Codepage number Platform_ID Encoding_ID Description
// -------------------------------------------------------------------------------------------------
//
// SYMBOL_CHARSET 2 (x02) 3 0 Symbol
// SHIFTJIS_CHARSET 128 (x80) 932 3 2 ShiftJIS
// GB2313_CHARSET 134 (x86) 936 3 3 PRC
// CHINESEBIG5_CHARSET 136 (x88) 950 3 4 Big5
// HANGEUL_CHARSET 129 (x81) 949 3 5 Wansung
// JOHAB_CHARSET 130 (x82) 1361 3 6 Johab
if ( 4 == un4ByteIndex && 0 == nResult )
{
for( int nIndex = 0; nIndex < pFace->num_charmaps; nIndex++ )
{
// Symbol
if ( 31 == ulBit && 0 == pFace->charmaps[nIndex]->encoding_id && 3 == pFace->charmaps[nIndex]->platform_id )
{
nResult = 1;
break;
}
// ShiftJIS
if ( 17 == ulBit && 2 == pFace->charmaps[nIndex]->encoding_id && 3 == pFace->charmaps[nIndex]->platform_id )
{
nResult = 1;
break;
}
// PRC
if ( 18 == ulBit && 3 == pFace->charmaps[nIndex]->encoding_id && 3 == pFace->charmaps[nIndex]->platform_id )
{
nResult = 1;
break;
}
// Big5
if ( 20 == ulBit && 4 == pFace->charmaps[nIndex]->encoding_id && 3 == pFace->charmaps[nIndex]->platform_id )
{
nResult = 1;
break;
}
// Wansung
if ( 19 == ulBit && 5 == pFace->charmaps[nIndex]->encoding_id && 3 == pFace->charmaps[nIndex]->platform_id )
{
nResult = 1;
break;
}
// Johab
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()
{
m_arrdFontMatrix[0] = 1;
m_arrdFontMatrix[1] = 0;
m_arrdFontMatrix[2] = 0;
m_arrdFontMatrix[3] = 1;
m_arrdFontMatrix[4] = 0;
m_arrdFontMatrix[5] = 0;
}
virtual void 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)
{
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_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)
{
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;
// BBox
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;
}
// This is a kludge: some buggy PDF generators embed fonts with zero bounding boxes.
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);
}
// (FontMatrix)
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;
// 31
if ( !( pOs2->ulCodePageRange1 & 0x80000000 ) && !( pOs2->ulCodePageRange1 == 0 && pOs2->ulCodePageRange2 == 0 ) )
return -1;
for( int nIndex = 0; nIndex < m_pFace->num_charmaps; nIndex++ )
{
// Symbol
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)
{
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;
// (dSize) DPI
if ( FT_Set_Char_Size( m_pFace, 0, (int)m_fSize * 64, 0, 0 ) )
{
return FALSE;
}
// CFont m_fSize = 1.0f, m_dUnitsKoef = 1.0
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; // -1 - , > 0 - GID
int m_nSymbolic; // cmap = ulCodePageRange 31 , cmap (3 0 (Symbol)); -1 =
FT_Face m_pFace; // face
// file
void *m_pBaseAddress;
HANDLE m_hFile;
HANDLE m_hMapFile;
// font
double m_arrdFontMatrix[6]; // FontMatrix (Text space -> Device space)
double m_arrdTextMatrix[6]; // TextMatrix (Text space -> User space)
BOOL m_bAntiAliasing; // Anti-aliasing
BOOL m_bUseKerning; // Kerning
float m_fSize; //
unsigned int m_unHorDpi; //
unsigned int m_unVerDpi; //
BOOL m_bNeedDoItalic; // | 2- , ,
BOOL m_bNeedDoBold; // | .
float m_fCharSpacing; //
int m_nMinX; //
int m_nMinY; // Glyph BBox
int m_nMaxX; //
int m_nMaxY; //
unsigned char *m_pCache; // Glyph bitmap cache
TFontCacheTag *m_pCacheTags; // Cache Tags
int m_nGlyphWidth; // Glyph bitmaps
int m_nGlyphHeight; // Glyph bitmaps
int m_nGlyphSize; // Glyph bitmaps
int m_nCacheSets; // Sets
int m_nCacheAssoc; // Glyphs Set
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; // LoadString: FALSE - , TRUE -
BOOL m_bUseDefaultFont; //
double m_dCharSpacing; // ( , )
BOOL m_bAntiAliasing;
BOOL m_bUseKerning;
BOOL m_bUseCIDs;
public:
CFontManagerLight()
{
m_pLibrary = NULL;
if (FT_Init_FreeType(&m_pLibrary))
m_pLibrary = NULL;
}
~CFontManagerLight()
{
if (NULL != m_pLibrary)
{
FT_Done_FreeType(m_pLibrary);
m_pLibrary = NULL;
}
RELEASEOBJECT(m_pFont);
}
BOOL LoadFontFromFile(CString sSrcPath, float fEmSize, double dHorDpi, double dVerDpi, long lFaceIndex)
{
if (!m_pLibrary)
return FALSE;
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);
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 )
{
long lUnicode = oCurGlyph.lUnicode;
if ( false == oCurGlyph.bBitmap )
m_pFont->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)
{
// must be bgra
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);
}
}
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 /* _FONT_MANAGER_LIGHT_H */
\ No newline at end of file
...@@ -3,8 +3,9 @@ ...@@ -3,8 +3,9 @@
#pragma once #pragma once
#include "./File.h" #include "./File.h"
#include "./WinFont.h" #include "./FontManagerLight.h"
#include "./WinFontStorage.h" #include "./WinFontStorage.h"
#include "./../Images/ImageGdipFile.h"
[object, uuid("F30AE253-88EF-4ae2-81B6-D9E1502082FF"), dual, pointer_default(unique)] [object, uuid("F30AE253-88EF-4ae2-81B6-D9E1502082FF"), dual, pointer_default(unique)]
__interface IWinFonts : IDispatch __interface IWinFonts : IDispatch
...@@ -380,14 +381,14 @@ private: ...@@ -380,14 +381,14 @@ private:
} }
// ------------------------------------------- // -------------------------------------------
#if 0
// //
double dW_mm = 80; double dW_mm = 80;
LONG lH1_px = LONG(7 * 96 / 25.4); LONG lH1_px = LONG(7 * 96 / 25.4);
LONG lWidthPix = (LONG)(dW_mm * 96 / 25.4); LONG lWidthPix = (LONG)(dW_mm * 96 / 25.4);
LONG lHeightPix = (LONG)(nCountFonts * lH1_px); LONG lHeightPix = (LONG)(nCountFonts * lH1_px);
MediaCore::IAVSUncompressedVideoFrame* pFrame = NULL;
CoCreateInstance(MediaCore::CLSID_CAVSUncompressedVideoFrame, NULL, CLSCTX_ALL, MediaCore::IID_IAVSUncompressedVideoFrame, (void**)&pFrame); IUncompressedFrame* pFrame;
CoCreateInstance(__uuidof(CUncompressedFrame), NULL, CLSCTX_ALL, __uuidof(IUncompressedFrame), (void**)&pFrame);
pFrame->put_ColorSpace( ( 1 << 6) | ( 1 << 31) ); // CPS_BGRA | CPS_FLIP pFrame->put_ColorSpace( ( 1 << 6) | ( 1 << 31) ); // CPS_BGRA | CPS_FLIP
pFrame->put_Width( lWidthPix ); pFrame->put_Width( lWidthPix );
...@@ -407,29 +408,18 @@ private: ...@@ -407,29 +408,18 @@ private:
pBuffer[i] = 0; pBuffer[i] = 0;
} }
IAVSGraphicsRenderer* pRenderer = NULL; IImageGdipFile* pImFile;
CoCreateInstance(__uuidof(CAVSGraphicsRenderer), NULL, CLSCTX_ALL, __uuidof(IAVSGraphicsRenderer), (void**)&pRenderer); CoCreateInstance(__uuidof(CImageGdipFile), NULL, CLSCTX_ALL, __uuidof(IImageGdipFile), (void**)&pImFile);
// FontManager
IAVSFontManager* man = NULL; IUnknown* punkFrame = NULL;
CoCreateInstance(__uuidof(CAVSFontManager), NULL, CLSCTX_INPROC, __uuidof(IAVSFontManager), (void**)&man); pFrame->QueryInterface(IID_IUnknown, (void**)&punkFrame);
man->Initialize(L"");
man->SetDefaultFont( L"Arial" );
IAVSFontManager2* man2 = NULL; pImFile->put_Frame(punkFrame);
man->QueryInterface(__uuidof(IAVSFontManager2), (void**)&man2);
man2->UseDefaultFont(TRUE);
RELEASEINTERFACE(man2);
VARIANT vtVariant; RELEASEINTERFACE(punkFrame);
vtVariant.vt = VT_UNKNOWN;
vtVariant.punkVal = (IUnknown*)man;
pRenderer->SetAdditionalParam( L"FontManager", vtVariant );
pRenderer->put_Width(dW_mm); CFontManagerLight oFontManager;
pRenderer->put_Height(lHeightPix * 25.4 / 96); // default!
pRenderer->CreateFromMediaData((IUnknown*)pFrame, 0, 0, lWidthPix, lHeightPix);
#endif
// . . // . .
// , // ,
...@@ -523,65 +513,52 @@ private: ...@@ -523,65 +513,52 @@ private:
lFaceIndex = pPair->m_value.m_lFaceIndexBI; lFaceIndex = pPair->m_value.m_lFaceIndexBI;
} }
#if 0
CString strFontPath = _T(""); CString strFontPath = _T("");
CAtlMap<LONG, CString>::CPair* _pair = mapFontFiles2.Lookup(lFontIndex); CAtlMap<LONG, CString>::CPair* _pair = mapFontFiles2.Lookup(lFontIndex);
if (NULL != _pair) if (NULL != _pair)
strFontPath = _pair->m_value; strFontPath = _pair->m_value;
BSTR bsFontPath = strFontPath.AllocSysString(); oFontManager.LoadFontFromFile(strFontPath, 14, 96, 96, lFaceIndex);
LoadFontFromFile(bsFontPath, 10, 72, 72, lFaceIndex);
BOOL bIsSymbol = (-1 != ((CFreeTypeFont*)m_pFont)->GetSymbolic()) ? TRUE : FALSE; CFreeTypeFont* pFont = oFontManager.GetFont();
BOOL bIsSymbol = FALSE;
if (pFont)
bIsSymbol = (-1 != (pFont->GetSymbolic())) ? TRUE : FALSE;
if (bIsSymbol) if (bIsSymbol)
{ {
SysFreeString(bsFontPath); oFontManager.LoadFontFromFile(_T("C:\\Windows\\Fonts\\cour.ttf"), 14, 96, 96, lFaceIndex);
strFontPath = _T("C:\\Windows\\Fonts\\cour.ttf"); pFont = oFontManager.GetFont();
bsFontPath = strFontPath.AllocSysString(); }
if (pFont)
{
pFont->SetStringGID(FALSE);
pFont->SetCharSpacing(0);
} }
pRenderer->put_BrushColor1(0);
BSTR bsText = pPair->m_value.m_sName.AllocSysString(); BSTR bsText = pPair->m_value.m_sName.AllocSysString();
pRenderer->put_FontPath(bsFontPath); oFontManager.FillString(bsText, 5, 25.4 * (index * lH1_px + lH1_px) / 96 - 2, 96, 96, pFrame, 255 /* black */);
pRenderer->put_FontSize(14);
pRenderer->put_FontStringGID(0);
pRenderer->put_FontCharSpace(0);
pRenderer->CommandDrawText(bsText, 5, 25.4 * (index * lH1_px + lH1_px) / 96 - 2, 0, 0, 0);
SysFreeString(bsText); SysFreeString(bsText);
SysFreeString(bsFontPath);
// endthumbnail
#endif
} }
oWriterJS.WriteStringC(_T("];\n\n")); oWriterJS.WriteStringC(_T("];\n\n"));
#if 0
//
ImageStudio::IImageTransforms* pTransform = NULL;
CoCreateInstance(ImageStudio::CLSID_ImageTransforms, NULL, CLSCTX_ALL, ImageStudio::IID_IImageTransforms, (void**)&pTransform);
VARIANT var;
var.vt = VT_UNKNOWN;
var.punkVal = (IUnknown*)pFrame;
wchar_t sTempPath[MAX_PATH], sTempFile[MAX_PATH]; wchar_t sTempPath[MAX_PATH], sTempFile[MAX_PATH];
if ( 0 == GetTempPath( MAX_PATH, sTempPath ) ) if ( 0 == GetTempPath( MAX_PATH, sTempPath ) )
return S_FALSE; return;
if ( 0 == GetTempFileName( sTempPath, "thumbnail", 0, sTempFile ) ) if ( 0 == GetTempFileName( sTempPath, L"thumbnail", 0, sTempFile ) )
return S_FALSE; return;
CString strThumbnailPath(sTempFile); CString strThumbnailPath(sTempFile);
VARIANT_BOOL vbSuccess = VARIANT_FALSE; BSTR bsThPath = strThumbnailPath.AllocSysString();
CString _dst = _T("<ImageFile-SaveAsPng destinationpath=\"") + strThumbnailPath + _T("\" format=\"8888\"/>"); pImFile->SaveFile(bsThPath, 4);
BSTR bs_dst = _dst.AllocSysString(); SysFreeString(bsThPath);
pTransform->SetSource(0, var);
pTransform->SetXml(bs_dst, &vbSuccess);
pTransform->Transform(&vbSuccess);
RELEASEINTERFACE(pRenderer);
RELEASEINTERFACE(pFrame); RELEASEINTERFACE(pFrame);
RELEASEINTERFACE(pTransform); RELEASEINTERFACE(pImFile);
CFile oImageFile; CFile oImageFile;
oImageFile.OpenFile(strThumbnailPath); oImageFile.OpenFile(strThumbnailPath);
...@@ -590,14 +567,19 @@ private: ...@@ -590,14 +567,19 @@ private:
oImageFile.ReadFile(pData, nInputLen); oImageFile.ReadFile(pData, nInputLen);
oImageFile.CloseFile(); oImageFile.CloseFile();
BSTR bstrDelFile = strThumbnailPath.AllocSysString();
#ifdef _DEBUG
CopyFile(bstrDelFile, L"C:\\thumbnail.png", FALSE);
#endif
DeleteFile(bstrDelFile);
SysFreeString(bstrDelFile);
int nOutputLen = Base64EncodeGetRequiredLength(nInputLen, ATL_BASE64_FLAG_NOCRLF); int nOutputLen = Base64EncodeGetRequiredLength(nInputLen, ATL_BASE64_FLAG_NOCRLF);
BYTE* pOutput = new BYTE[nOutputLen]; BYTE* pOutput = new BYTE[nOutputLen];
Base64Encode(pData, nInputLen, (LPSTR)pOutput, &nOutputLen, ATL_BASE64_FLAG_NOCRLF); Base64Encode(pData, nInputLen, (LPSTR)pOutput, &nOutputLen, ATL_BASE64_FLAG_NOCRLF);
CString _s((char*)pOutput, nOutputLen); CString _s((char*)pOutput, nOutputLen);
#else
CString _s = _T("none");
#endif
oWriterJS.WriteStringC(_T("window[\"g_standart_fonts_thumbnail\"] = \"data:image/png;base64,")); oWriterJS.WriteStringC(_T("window[\"g_standart_fonts_thumbnail\"] = \"data:image/png;base64,"));
oWriterJS.WriteStringC(_s); oWriterJS.WriteStringC(_s);
......
...@@ -306,6 +306,10 @@ ...@@ -306,6 +306,10 @@
RelativePath=".\Fonts\File.h" RelativePath=".\Fonts\File.h"
> >
</File> </File>
<File
RelativePath=".\Fonts\FontManagerLight.h"
>
</File>
<File <File
RelativePath=".\Fonts\FontUtils.h" RelativePath=".\Fonts\FontUtils.h"
> >
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment