Files
Dario Sassi b709776f5f EgtGeomKernel :
- piccole mdofiche poco più che estetiche.
2025-01-20 08:30:39 +01:00

857 lines
28 KiB
C++

//----------------------------------------------------------------------------
// EgalTech 2014-2014
//----------------------------------------------------------------------------
// File : FontOs.cpp Data : 05.06.14 Versione : 1.5f2
// Contenuto : Implementazione della classe OsFont (font di sistema).
//
//
//
// Modifiche : 01.06.14 DS Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "FontOs.h"
#include "FontAux.h"
#include "FontConst.h"
#include "CurveLine.h"
#include "CurveBezier.h"
#include "CurveComposite.h"
#include "SurfFlatRegion.h"
#include "GeoConst.h"
#include "/EgtDev/Include/EGkGeomDB.h"
#include "/EgtDev/Include/EGkGdbIterator.h"
#include "/EgtDev/Include/EGkCurve.h"
#include "/EgtDev/Include/EGkCurveAux.h"
#include "/EgtDev/Include/EGkSfrCreate.h"
#include "/EgtDev/Include/EGnStringUtils.h"
#include "/EgtDev/Include/EGnFileUtils.h"
#include "/EgtDev/Include/EgtStringConverter.h"
#include "/EgtDev/Include/EgtStringDecoder.h"
#include "/EgtDev/Include/EgtStringEncoder.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
using namespace std ;
//----------------------------------------------------------------------------
const int OSF_HSTD = 100 ;
//----------------------------------------------------------------------------
OsFont::OsFont( void)
{
m_hDC = nullptr ;
m_hFont = nullptr ;
}
//----------------------------------------------------------------------------
OsFont::~OsFont( void)
{
if ( m_hFont != nullptr)
DeleteObject( m_hFont) ;
m_hFont = nullptr ;
if ( m_hDC != nullptr)
ReleaseDC( NULL, m_hDC) ;
m_hDC = nullptr ;
}
//----------------------------------------------------------------------------
bool
OsFont::SetCurrFont( const string& sFont, int nWeight, bool bItalic,
double dHeight, double dRatio, double dAddAdvance)
{
string sFontUp = sFont ;
ToUpper( sFontUp) ;
// se il font non è già caricato o sono cambiati dei parametri di creazione
if ( m_sFont != sFontUp || nWeight != m_nWeight || bItalic != m_bItalic) {
// pulisco la path del font
m_sFont.clear() ;
// cancello eventuale precedente font
if ( m_hFont != nullptr)
DeleteObject( m_hFont) ;
// se necessario, recupero il device di schermo
if ( m_hDC == nullptr)
m_hDC = GetDC( nullptr) ;
if ( m_hDC == nullptr)
return false ;
::SetMapMode( m_hDC, MM_TEXT) ;
// creo il font
m_hFont = CreateFontW( - OSF_HSTD, 0, 0, 0, nWeight, bItalic, false, false, DEFAULT_CHARSET,
OUT_TT_ONLY_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH,
stringtoW( sFont)) ;
if ( m_hFont == nullptr)
return false ;
// aggiorno dati del font
if ( ! CalcFontData())
return false ;
// aggiorno la path del font
m_sFont = sFontUp ;
}
// salvo i dati
m_nWeight = nWeight ;
m_bItalic = bItalic ;
m_dHeight = max( dHeight, FNT_MIN_HEIGHT) ;
m_dRatio = dRatio ;
m_dAddAdvance = dAddAdvance ;
return true ;
}
//----------------------------------------------------------------------------
bool
OsFont::CalcFontData( void)
{
// verifico esistenza font corrente (non controllo nome)
if ( m_hDC == nullptr || m_hFont == nullptr)
return false ;
// rendo corrente il font
HFONT hPrevFont = (HFONT) SelectObject( m_hDC, m_hFont) ;
if ( hPrevFont == nullptr)
return false ;
// dati generali
TEXTMETRIC tm ;
if ( ! GetTextMetrics( m_hDC, &tm))
return false ;
double dCoeff = (( tm.tmHeight > 0) ? double( OSF_HSTD) / tm.tmHeight : 1) ;
m_dH = ( tm.tmHeight + tm.tmExternalLeading) * dCoeff ;
m_dHCap = ( tm.tmAscent - tm.tmInternalLeading) * dCoeff ;
m_dHx = 0.6667 * m_dHCap ; // approx
m_dAsc = tm.tmAscent * dCoeff ;
m_dDesc = tm.tmDescent * dCoeff ;
m_dAdv = tm.tmMaxCharWidth * dCoeff ;
// cerco dato più preciso su altezza delle maiuscole
GLYPHMETRICS gm ;
MAT2 mat = { {0,1},{0,0},{0,0},{0,1}} ;
// recupero l'altezza della lettera 'H' (72)
DWORD dwSize = GetGlyphOutlineW( m_hDC, 72, GGO_NATIVE, &gm, 0, NULL, &mat) ;
if ( dwSize != GDI_ERROR) {
m_dHCap = gm.gmBlackBoxY ;
m_dHx = 0.6667 * m_dHCap ; // approx
}
// ripristino il font originale
SelectObject( m_hDC, hPrevFont) ;
return true ;
}
//----------------------------------------------------------------------------
bool
OsFont::GetCapHeight( double& dCapH) const
{
// verifico esistenza font corrente
if ( m_hDC == nullptr || m_hFont == nullptr || m_sFont.empty())
return false ;
// uso il fattore di scala per Y = m_dHeight / m_dHCap
dCapH = m_dHCap * m_dHeight / m_dHCap ;
return true ;
}
//----------------------------------------------------------------------------
bool
OsFont::GetAscent( double& dAsc) const
{
// verifico esistenza font corrente
if ( m_hDC == nullptr || m_hFont == nullptr || m_sFont.empty())
return false ;
// uso il fattore di scala per Y = m_dHeight / m_dHCap
dAsc = m_dAsc * m_dHeight / m_dHCap ;
return true ;
}
//----------------------------------------------------------------------------
bool
OsFont::GetDescent( double& dDesc) const
{
// verifico esistenza font corrente
if ( m_hDC == nullptr || m_hFont == nullptr || m_sFont.empty())
return false ;
// uso il fattore di scala per Y = m_dHeight / m_dHCap
dDesc = m_dDesc * m_dHeight / m_dHCap ;
return true ;
}
//----------------------------------------------------------------------------
bool
OsFont::GetXBox( const string& sText, int nInsPos, bool bCapOrBound, BBox3d& b3Box) const
{
// verifico esistenza font corrente
if ( m_hDC == nullptr || m_hFont == nullptr || m_sFont.empty())
return false ;
// rendo corrente il font
HFONT hPrevFont = (HFONT) SelectObject( m_hDC, m_hFont) ;
if ( hPrevFont == nullptr)
return false ;
// calcolo i fattori di scala
double dScaY = m_dHeight / m_dHCap ;
double dScaX = dScaY * m_dRatio ;
// recupero altezza maiuscole, ascent, descent e interlinea
double dHCap = m_dHeight ;
double dAscent = m_dAsc * m_dHeight / m_dHCap ;
double dDescent = m_dDesc * m_dHeight / m_dHCap ;
double dH = m_dH * m_dHeight / m_dHCap ;
// converto i byte della stringa in codici carattere
UINTVECTOR vCode ;
GetCodePoints( sText, vCode) ;
// scandisco i codici
double dCurrW = 0 ;
double dMaxW = 0 ;
double dMinH = 0 ;
for ( unsigned int i = 0 ; i < vCode.size() ; ++ i) {
// verifico se comando di a capo
int nLbLen ;
if ( IsLineBreak( vCode, i, nLbLen)) {
dCurrW = 0 ;
dMinH -= dH ;
i += nLbLen ;
continue ;
}
// recupero l'avanzamento di ogni carattere
ABC abc ;
double dAdvance ;
if ( GetCharABCWidths( m_hDC, vCode[i], vCode[i], &abc))
dAdvance = ( abc.abcA + abc.abcB + abc.abcC) ;
else
dAdvance = m_dAdv ;
dCurrW += dAdvance * dScaX + m_dAddAdvance ;
if ( dCurrW > dMaxW)
dMaxW = dCurrW ;
}
// punti estremi
Point3d ptMin( 0, dMinH - ( bCapOrBound ? 0 : dDescent), 0) ;
Point3d ptMax( dMaxW, ( bCapOrBound ? dHCap : dAscent), 0) ;
// sistemazioni per la posizione del punto di inserimento
Vector3d vtIpMove = GetTextInsertPointMove( dMaxW, dHCap, dMinH, nInsPos) ;
ptMin.Translate( vtIpMove) ;
ptMax.Translate( vtIpMove) ;
// assegno l'ingombro
b3Box.Set( ptMin, ptMax) ;
// ripristino il font originale
SelectObject( m_hDC, hPrevFont) ;
return true ;
}
//----------------------------------------------------------------------------
bool
OsFont::GetOutline( const string& sText, int nInsPos, ICURVEPLIST& lstPC) const
{
// verifico esistenza font corrente
if ( m_hDC == nullptr || m_hFont == nullptr || m_sFont.empty())
return false ;
// rendo corrente il font
HFONT hPrevFont = (HFONT) SelectObject( m_hDC, m_hFont) ;
if ( hPrevFont == nullptr)
return false ;
// calcolo i fattori di scala
double dScaY = m_dHeight / m_dHCap ;
double dScaX = dScaY * m_dRatio ;
double dScaZ = 1 ;
// recupero altezza maiuscole e interlinea
double dHCap = m_dHeight ;
double dH = m_dH * m_dHeight / m_dHCap ;
// converto i byte della stringa in codici carattere
UINTVECTOR vCode ;
GetCodePoints( sText, vCode) ;
// ciclo sui codici
double dMaxW = 0 ;
double dMinH = 0 ;
Vector3d vtMove ;
ICURVEPLIST lstTmpPC ;
for ( unsigned int i = 0 ; i < vCode.size() ; ++ i) {
// verifico se comando di a capo
int nLbLen ;
if ( IsLineBreak( vCode, i, nLbLen)) {
vtMove.Set( 0, vtMove.y - dH, 0) ;
if ( vtMove.y < dMinH)
dMinH = vtMove.y ;
i += nLbLen ;
continue ;
}
// recupero l'outline
double dAdvance ;
if ( ! GetCharOutline( vCode[i], dAdvance, lstTmpPC))
return false ;
// lo trasformo opportunamente
for ( auto iIter = lstTmpPC.begin() ; iIter != lstTmpPC.end() ; ++ iIter) {
// trasformazioni
(*iIter)->Scale( GLOB_FRM, dScaX, dScaY, dScaZ) ;
(*iIter)->Translate( vtMove) ;
// inserimento nella lista principale
lstPC.push_back( (*iIter)) ;
}
vtMove += Vector3d( dAdvance * dScaX + m_dAddAdvance, 0, 0) ;
if ( vtMove.x > dMaxW)
dMaxW = vtMove.x ;
// ciclo di pulizia ( non devo cancellare le curve, perchè spostate nella lista principale)
lstTmpPC.clear() ;
}
// sistemazioni per la posizione del punto di inserimento
Vector3d vtIpMove = GetTextInsertPointMove( dMaxW, dHCap, dMinH, nInsPos) ;
for ( const auto& pCrv : lstPC)
pCrv->Translate( vtIpMove) ;
// inverto i percorsi per avere gli esterni CCW
for ( const auto& pCrv : lstPC)
pCrv->Invert() ;
// assegno l'estrusione
for ( const auto& pCrv : lstPC)
pCrv->SetExtrusion( Z_AX) ;
// ripristino il font originale
SelectObject( m_hDC, hPrevFont) ;
return true ;
}
//----------------------------------------------------------------------------
bool
OsFont::GetRegion( const string& sText, int nInsPos, ISURFFRPLIST& lstSFR) const
{
// verifico esistenza font corrente
if ( m_hDC == nullptr || m_hFont == nullptr || m_sFont.empty())
return false ;
// rendo corrente il font
HFONT hPrevFont = (HFONT) SelectObject( m_hDC, m_hFont) ;
if ( hPrevFont == nullptr)
return false ;
// calcolo i fattori di scala
double dScaY = m_dHeight / m_dHCap ;
double dScaX = dScaY * m_dRatio ;
double dScaZ = 1 ;
// recupero altezza maiuscole e interlinea
double dHCap = m_dHeight ;
double dH = m_dH * m_dHeight / m_dHCap ;
// converto i byte della stringa in codici carattere
UINTVECTOR vCode ;
GetCodePoints( sText, vCode) ;
// ciclo sui codici
double dMaxW = 0 ;
double dMinH = 0 ;
Vector3d vtMove ;
for ( unsigned int i = 0 ; i < vCode.size() ; ++ i) {
// verifico se comando di a capo
int nLbLen ;
if ( IsLineBreak( vCode, i, nLbLen)) {
vtMove.Set( 0, vtMove.y - dH, 0) ;
if ( vtMove.y < dMinH)
dMinH = vtMove.y ;
i += nLbLen ;
continue ;
}
// recupero l'outline
double dAdvance ;
ICURVEPLIST lstPC ;
if ( ! GetCharOutline( vCode[i], dAdvance, lstPC))
return false ;
// lo trasformo opportunamente
for ( auto iIter = lstPC.begin() ; iIter != lstPC.end() ; ++ iIter) {
// inverto i percorsi per avere gli esterni CCW
(*iIter)->Invert() ;
// la trasformo per avere solo archi e rette
GetCurveComposite( *iIter)->ArcsBezierCurvesToArcsPerpExtr( LIN_TOL_FINE, ANG_STRAIGHT) ;
}
// creo la regione
SurfFlatRegionByContours SfrCntr( false, true) ;
for ( auto& PC : lstPC)
SfrCntr.AddCurve( PC) ;
PtrOwner<SurfFlatRegion> pSfr( GetBasicSurfFlatRegion( SfrCntr.GetSurf())) ;
if ( ! IsNull( pSfr)) {
// trasformazioni
pSfr->Scale( GLOB_FRM, dScaX, dScaY, dScaZ) ;
pSfr->Translate( vtMove) ;
// inserimento in lista
lstSFR.push_back( Release( pSfr)) ;
}
// aggiorno per larghezza
vtMove += Vector3d( dAdvance * dScaX + m_dAddAdvance, 0, 0) ;
if ( vtMove.x > dMaxW)
dMaxW = vtMove.x ;
}
// sistemazioni per la posizione del punto di inserimento
Vector3d vtIpMove = GetTextInsertPointMove( dMaxW, dHCap, dMinH, nInsPos) ;
for ( const auto& pSfr : lstSFR)
pSfr->Translate( vtIpMove) ;
// ripristino il font originale
SelectObject( m_hDC, hPrevFont) ;
return true ;
}
//----------------------------------------------------------------------------
bool
OsFont::ApproxWithLines( const string& sText, int nInsPos, double dLinTol, double dAngTolDeg,
POLYLINELIST& lstPL) const
{
// verifico esistenza font corrente
if ( m_hDC == nullptr || m_hFont == nullptr || m_sFont.empty())
return false ;
// rendo corrente il font
HFONT hPrevFont = (HFONT) SelectObject( m_hDC, m_hFont) ;
if ( hPrevFont == nullptr)
return false ;
// controllo valore tolleranza lineare
if ( dLinTol > FNT_MAX_LINTOL_TO_H * m_dHeight)
dLinTol = max( FNT_MAX_LINTOL_TO_H * m_dHeight, EPS_SMALL) ;
// calcolo i fattori di scala
double dScaY = m_dHeight / m_dHCap ;
double dScaX = dScaY * m_dRatio ;
double dScaZ = 1 ;
// recupero altezza maiuscole e interlinea
double dHCap = m_dHeight ;
double dH = m_dH * m_dHeight / m_dHCap ;
// converto i byte della stringa in codici carattere
UINTVECTOR vCode ;
GetCodePoints( sText, vCode) ;
// ciclo sui caratteri
double dMaxW = 0 ;
double dMinH = 0 ;
Vector3d vtMove ;
ICURVEPLIST lstPC ;
for ( unsigned int i = 0 ; i < vCode.size() ; ++ i) {
// verifico se comando di a capo
int nLbLen ;
if ( IsLineBreak( vCode, i, nLbLen)) {
vtMove.Set( 0, vtMove.y - dH, 0) ;
if ( vtMove.y < dMinH)
dMinH = vtMove.y ;
i += nLbLen ;
continue ;
}
// recupero l'outline
double dAdvance ;
if ( ! GetCharOutline( vCode[i], dAdvance, lstPC))
return false ;
// lo approssimo con segmenti di retta
for ( auto iIter = lstPC.begin() ; iIter != lstPC.end() ; ++ iIter) {
// trasformazioni
(*iIter)->Scale( GLOB_FRM, dScaX, dScaY, dScaZ) ;
(*iIter)->Translate( vtMove) ;
// approssimo con rette
lstPL.emplace_back() ;
if ( ! (*iIter)->ApproxWithLines( dLinTol, dAngTolDeg, ICurve::APL_STD, lstPL.back()))
return false ;
}
vtMove += Vector3d( dAdvance * dScaX + m_dAddAdvance, 0, 0) ;
if ( vtMove.x > dMaxW)
dMaxW = vtMove.x ;
// ciclo di pulizia
for ( auto iIter = lstPC.begin() ; iIter != lstPC.end() ; ++ iIter)
delete (*iIter) ;
lstPC.clear() ;
}
// sistemazioni per la posizione del punto di inserimento
Vector3d vtIpMove = GetTextInsertPointMove( dMaxW, dHCap, dMinH, nInsPos) ;
for ( auto& PL : lstPL)
PL.Translate( vtIpMove) ;
// inverto le polilinee per avere gli esterni CCW
for ( auto& PL : lstPL)
PL.Invert() ;
// ripristino il font originale
SelectObject( m_hDC, hPrevFont) ;
return true ;
}
//----------------------------------------------------------------------------
bool
OsFont::ApproxWithArcs( const string& sText, int nInsPos, double dLinTol, double dAngTolDeg,
POLYARCLIST& lstPA) const
{
// verifico esistenza font corrente
if ( m_hDC == nullptr || m_hFont == nullptr || m_sFont.empty())
return false ;
// rendo corrente il font
HFONT hPrevFont = (HFONT) SelectObject( m_hDC, m_hFont) ;
if ( hPrevFont == nullptr)
return false ;
// controllo valore tolleranza lineare
if ( dLinTol > FNT_MAX_LINTOL_TO_H * m_dHeight)
dLinTol = max( FNT_MAX_LINTOL_TO_H * m_dHeight, EPS_SMALL) ;
// calcolo i fattori di scala
double dScaY = m_dHeight / m_dHCap ;
double dScaX = dScaY * m_dRatio ;
double dScaZ = 1 ;
// recupero altezza maiuscole e interlinea
double dHCap = m_dHeight ;
double dH = m_dH * m_dHeight / m_dHCap ;
// converto i byte della stringa in codici carattere
UINTVECTOR vCode ;
GetCodePoints( sText, vCode) ;
// ciclo sui caratteri
double dMaxW = 0 ;
double dMinH = 0 ;
Vector3d vtMove ;
ICURVEPLIST lstPC ;
for ( unsigned int i = 0 ; i < vCode.size() ; ++ i) {
// verifico se comando di a capo
int nLbLen ;
if ( IsLineBreak( vCode, i, nLbLen)) {
vtMove.Set( 0, vtMove.y - dH, 0) ;
if ( vtMove.y < dMinH)
dMinH = vtMove.y ;
i += nLbLen ;
continue ;
}
// recupero l'outline
double dAdvance ;
if ( ! GetCharOutline( vCode[i], dAdvance, lstPC))
return false ;
// lo approssimo con segmenti di arco e retta
for ( auto iIter = lstPC.begin() ; iIter != lstPC.end() ; ++ iIter) {
// trasformazioni
(*iIter)->Scale( GLOB_FRM, dScaX, dScaY, dScaZ) ;
(*iIter)->Translate( vtMove) ;
// approssimo con archi
lstPA.emplace_back() ;
if ( ! (*iIter)->ApproxWithArcs( dLinTol, dAngTolDeg, lstPA.back()))
return false ;
}
vtMove += Vector3d( dAdvance * dScaX + m_dAddAdvance, 0, 0) ;
if ( vtMove.x > dMaxW)
dMaxW = vtMove.x ;
// ciclo di pulizia
for ( auto iIter = lstPC.begin() ; iIter != lstPC.end() ; ++ iIter)
delete (*iIter) ;
lstPC.clear() ;
}
// sistemazioni per la posizione del punto di inserimento
Vector3d vtIpMove = GetTextInsertPointMove( dMaxW, dHCap, dMinH, nInsPos) ;
for ( auto& PA : lstPA)
PA.Translate( vtIpMove) ;
// inverto i poliarchi per avere gli esterni CCW
for ( auto& PA : lstPA)
PA.Invert() ;
// ripristino il font originale
SelectObject( m_hDC, hPrevFont) ;
return true ;
}
//----------------------------------------------------------------------------
bool
OsFont::GetTextLines( const string& sText, int nInsPos, PNTVECTOR& vPt, STRVECTOR& vLine) const
{
// pulisco i parametri di ritorno
vPt.clear() ;
vLine.clear() ;
// verifico esistenza font corrente
if ( m_hDC == nullptr || m_hFont == nullptr || m_sFont.empty())
return false ;
// rendo corrente il font
HFONT hPrevFont = (HFONT) SelectObject( m_hDC, m_hFont) ;
if ( hPrevFont == nullptr)
return false ;
// calcolo i fattori di scala
double dScaY = m_dHeight / m_dHCap ;
double dScaX = dScaY * m_dRatio ;
// recupero altezza maiuscole e interlinea
double dHCap = m_dHeight ;
double dH = m_dH * m_dHeight / m_dHCap ;
// converto i byte della stringa in codici carattere
UINTVECTOR vCode ;
GetCodePoints( sText, vCode) ;
// ciclo sui codici
double dMaxW = 0 ;
double dMinH = 0 ;
Vector3d vtMove ;
UINTVECTOR vTmpCode ;
for ( unsigned int i = 0 ; i < vCode.size() ; ++ i) {
// verifico se comando di a capo
int nLbLen ;
if ( IsLineBreak( vCode, i, nLbLen)) {
// salvo la linea, se contiene qualcosa
if ( ! vTmpCode.empty()) {
string sLine ;
SetCodePoints( vTmpCode, sLine) ;
vLine.push_back( sLine) ;
vTmpCode.clear() ;
vPt.emplace_back( 0, vtMove.y, 0) ;
}
// sistemo la posizione
vtMove.Set( 0, vtMove.y - dH, 0) ;
if ( vtMove.y < dMinH)
dMinH = vtMove.y ;
// passo oltre
i += nLbLen ;
continue ;
}
// salvo il codice
vTmpCode.push_back( vCode[i]) ;
// recupero l'advance
double dAdvance ;
if ( ! GetCharAdvance( vCode[i], dAdvance))
return false ;
// aggiorno lo spostamento
vtMove += Vector3d( dAdvance * dScaX + m_dAddAdvance, 0, 0) ;
if ( vtMove.x > dMaxW)
dMaxW = vtMove.x ;
}
// salvo eventuale ultima linea
if ( ! vTmpCode.empty()) {
string sLine ;
SetCodePoints( vTmpCode, sLine) ;
vLine.push_back( sLine) ;
vTmpCode.clear() ;
vPt.emplace_back( 0, vtMove.y, 0) ;
}
// sistemazioni per la posizione del punto di inserimento
Vector3d vtIpMove = GetTextInsertPointMove( dMaxW, dHCap, dMinH, nInsPos) ;
for ( auto& Pt : vPt)
Pt.Translate( vtIpMove) ;
// ripristino il font originale
SelectObject( m_hDC, hPrevFont) ;
return true ;
}
//----------------------------------------------------------------------------
double
DoubleFromFixed( FIXED fx)
{
return ( double( fx.value) + double( fx.fract) * ( 1.0 / 65536.0)) ;
}
//----------------------------------------------------------------------------
FIXED
MediaTwoFixed( FIXED fx1, FIXED fx2)
{
long l = 0L ;
l = (*((long*)&(fx1)) + *((long*)&(fx2))) / 2L ;
return (*(FIXED*)&l) ;
}
//----------------------------------------------------------------------------
bool
OsFont::GetCharAdvance( unsigned int nChar, double& dAdvance) const
{
GLYPHMETRICS gm ;
MAT2 mat = { {0,1},{0,0},{0,0},{0,1}} ;
// recupero la dimensione necessaria del buffer e lo alloco
DWORD dwSize = GetGlyphOutlineW( m_hDC, nChar, GGO_NATIVE, &gm, 0, NULL, &mat) ;
if ( dwSize == GDI_ERROR)
return false ;
// assegno l'avanzamento al prossimo carattere
dAdvance = gm.gmCellIncX ;
return true ;
}
//----------------------------------------------------------------------------
bool
OsFont::GetCharOutline( unsigned int nChar, double& dAdvance, ICURVEPLIST& lstPC) const
{
GLYPHMETRICS gm ;
MAT2 mat = { {0,1},{0,0},{0,0},{0,1}} ;
// recupero la dimensione necessaria del buffer e lo alloco
DWORD dwSize = GetGlyphOutlineW( m_hDC, nChar, GGO_NATIVE, &gm, 0, NULL, &mat) ;
if ( dwSize == GDI_ERROR)
return false ;
PtrOwner<char> pBuffer( new( nothrow) char[dwSize]) ;
if ( IsNull( pBuffer))
return false ;
// recupero l'outline
DWORD dErr = GetGlyphOutlineW( m_hDC, nChar, GGO_NATIVE, &gm, dwSize, pBuffer, &mat) ;
if ( dErr == GDI_ERROR)
return false ;
// assegno l'avanzamento al prossimo carattere
dAdvance = gm.gmCellIncX ;
// mentre esistono nuovi contorni
LPTTPOLYGONHEADER pHeader = (LPTTPOLYGONHEADER) ::Get( pBuffer) ;
while ( (LPSTR) pHeader < ( pBuffer + ptrdiff_t( dwSize))) {
// leggo un nuovo contorno
if ( pHeader->dwType == TT_POLYGON_TYPE) {
// creo curva composita
PtrOwner<CurveComposite> pCCompo( CreateBasicCurveComposite()) ;
if ( IsNull( pCCompo))
return false ;
// posizionamento sul punto iniziale
Point3d ptFirst( DoubleFromFixed( pHeader->pfxStart.x),
DoubleFromFixed( pHeader->pfxStart.y),
0) ;
Point3d ptLast = ptFirst ;
// puntatore alla prima polycurva
LPTTPOLYCURVE pCurve = (LPTTPOLYCURVE)( pHeader + 1) ;
// mentre esistono polycurve
while ( (LPSTR) pCurve < ( (LPSTR) pHeader + ptrdiff_t( pHeader->cb))) {
// numero punti
int nPnt = pCurve->cpfx ;
// se rette
if ( pCurve->wType == TT_PRIM_LINE) {
for ( int i = 0 ; i < nPnt ; ++ i ) {
Point3d ptP( DoubleFromFixed( pCurve->apfx[i].x),
DoubleFromFixed( pCurve->apfx[i].y),
0) ;
if ( ! AreSamePointApprox( ptLast, ptP)) {
// aggiungo la retta alla curva composita
if ( ! AddLineToCompo( pCCompo, ptLast, ptP))
return false ;
// salvo punto come ultimo
ptLast = ptP ;
}
}
}
// se curve di Bezier quadratiche
else if ( pCurve->wType == TT_PRIM_QSPLINE) {
for ( int i = 0 ; i < nPnt - 1 ; ++ i ) {
// punto medio CBezier
Point3d ptM( DoubleFromFixed( pCurve->apfx[i].x),
DoubleFromFixed( pCurve->apfx[i].y),
0) ;
// punto finale CBezier
POINTFX pfEnd ;
// se non è alla fine è il medio dei due punti adiacenti del poligono
if ( i < ( nPnt - 2)) {
pfEnd.x = MediaTwoFixed( pCurve->apfx[i].x, pCurve->apfx[i+1].x) ;
pfEnd.y = MediaTwoFixed( pCurve->apfx[i].y, pCurve->apfx[i+1].y) ;
}
else
pfEnd = pCurve->apfx[i+1] ;
Point3d ptE( DoubleFromFixed( pfEnd.x),
DoubleFromFixed( pfEnd.y),
0) ;
// aggiungo la curva di Bezier quadratica alla curva composita
if ( ! AddCBezierQuadToCompo( pCCompo, ptLast, ptM, ptE))
return false ;
// salvo punto finale come ultimo
ptLast = ptE ;
}
}
// altrimenti errore
else {
return false ;
}
// si passa alla polycurva successiva
pCurve = (LPTTPOLYCURVE) &( pCurve->apfx[nPnt]) ;
}
// si aggiunge, se necessario, una linea retta per chiudere la curva
if ( ! AreSamePointApprox( ptFirst, ptLast)) {
// aggiungo la retta alla curva composita
if ( ! AddLineToCompo( pCCompo, ptLast, ptFirst))
return false ;
// salvo ultimo punto
ptLast = ptFirst ;
}
// se curva composita ok, la inserisco in lista
if ( pCCompo->IsValid())
lstPC.push_back( ::Release( pCCompo)) ;
}
// mi sposto sul prossimo contorno
pHeader = (LPTTPOLYGONHEADER) ( (LPSTR) pHeader + ptrdiff_t( pHeader->cb)) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
OsFont::AddLineToCompo( ICurveComposite* pCCompo, const Point3d& ptStart, const Point3d& ptEnd) const
{
// verifico curva composita
if ( pCCompo == nullptr)
return false ;
// creo retta, la imposto e la inserisco nella curva composita
PtrOwner<CurveLine> pCLine( CreateBasicCurveLine()) ;
if ( IsNull( pCLine))
return false ;
if ( ! pCLine->Set( ptStart, ptEnd))
return false ;
if ( ! pCCompo->AddCurve( ::Release( pCLine)))
return false ;
return true ;
}
//----------------------------------------------------------------------------
bool
OsFont::AddCBezierQuadToCompo( ICurveComposite* pCCompo,
const Point3d& ptStart, const Point3d& ptMid, const Point3d& ptEnd) const
{
// verifico curva composita
if ( pCCompo == nullptr)
return false ;
// creo curva di Bezier quadratica, la imposto e la inserisco nella curva composita
PtrOwner<CurveBezier> pCBezier( CreateBasicCurveBezier()) ;
if ( IsNull( pCBezier))
return false ;
if ( ! pCBezier->Init( 2, false) ||
! pCBezier->SetControlPoint( 0, ptStart) ||
! pCBezier->SetControlPoint( 1, ptMid) ||
! pCBezier->SetControlPoint( 2, ptEnd))
return false ;
if ( ! pCCompo->AddCurve( ::Release( pCBezier)))
return false ;
return true ;
}