#ifndef _GLYPH_STRING_H #define _GLYPH_STRING_H #include "FontConsts.h" 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; // Номер текущего символа }; #endif /* _GLYPH_STRING_H */