Files
core/ASCImageStudio3/ASCGraphics/agg/ap_Font.cpp

408 lines
11 KiB
C++

//#include "stdafx.h"
#include "ap_Font.h"
namespace Aggplus
{
Font::Font()
{
Construct(NULL, 0.00, 0, UnitPixel);
}
Font::Font(const WCHAR *familyName, REAL emSize, INT style, Unit unit)
{
Construct(familyName, emSize, style, unit);//, Unit unit
}
void Font::Construct(const WCHAR* familyName, float emSize, int style, Unit unit)//
{
m_agg_pFeng=NULL;
m_femSize=0.00;
m_hDC=::GetDC(NULL);
if(emSize<1.0f)
{
/*assert(FALSE);*/ return;
} //Not implemented
if(!familyName || !(*familyName))
{
/*assert(FALSE);*/ return;
} //finished
m_Unit=unit;
m_agg_pFeng=new font_engine_type(m_hDC);
m_agg_pFeng->hinting(true);
m_agg_pFeng->flip_y(true);
m_agg_pFeng->height(emSize);
float ffSize=emSize;
switch(m_Unit)
{
case UnitDisplay : delete(m_agg_pFeng);m_agg_pFeng=NULL; return; break; //INVALID! 1 -- Variable -- for PageTransform only
case UnitWorld : // 0 -- World coordinate (non-physical unit)
case UnitPixel : break; // 2 -- Each unit is one device pixel.
default:
case UnitPoint : m_agg_pFeng->resolution(96);break; //ffSize=(emSize*96.0)/72.0; break; //100 // 3 -- Each unit is a printer's point, or 1/72 inch.
}
m_agg_pFeng->width(0.00);
//m_agg_pFeng->transform(agg::trans_affine_rotation(agg::deg2rad(00.0)));
agg::glyph_rendering gren = agg::glyph_ren_outline;
//z_Convert_wcharp_to_charp cFamName(familyName);
const WCHAR* pSour = familyName;
int n_Length=WideCharToMultiByte(CP_ACP, 0, pSour, -1, NULL, NULL, NULL, NULL);
char *pcStr=NULL;
if(n_Length)
{
pcStr=new char[n_Length];
WideCharToMultiByte(CP_ACP, 0, pSour, -1, pcStr, n_Length, NULL, NULL);
}
int nweight_=FW_REGULAR;
if(style&FontStyleBold) nweight_=FW_BOLD;
//lstrlen
BOOL bSucc=m_agg_pFeng->create_font(pcStr /*familyName*/ /*cFamName.m_pcStr*/, gren, ffSize, 0.00, nweight_,
(style&FontStyleItalic)!=0,
//(style&FontStyleUnderline)!=0,
//(style&FontStyleStrikeout)!=0,
DEFAULT_CHARSET, FF_DONTCARE);
if(pcStr) { delete(pcStr); }
//RUSSIAN_CHARSET, ANSI_CHARSET
//assert(bSucc);
//if(!bSucc) bSucc=m_agg_pFeng->create_font(cuStr.GetString(), gren, emSize, 0.00, FW_DONTCARE, false, false, false, DEFAULT_CHARSET, FF_DONTCARE);
if(bSucc)
{
int nSave_dc=SaveDC(m_hDC);
SetMapMode(m_hDC, MM_ISOTROPIC);
//SetWindowExtEx(m_hDC, 65500, 65500, NULL); //SetViewportExtEx(m_hDC, 100, 100, NULL);
SetWindowExtEx(m_hDC, 20480, 20480, NULL);
SetViewportExtEx(m_hDC, 1200, -1200, NULL);
//Default Values for Arial
int otmMacAscent=31;
int otmMacDescent=-7;
UINT otmMacLineGap=1;
UINT otmEMSquare=2048;
LONG tmAscent=34;
{
OUTLINETEXTMETRIC Otm;memset(&Otm, 0, sizeof(OUTLINETEXTMETRIC));
Otm.otmSize=sizeof(OUTLINETEXTMETRIC);
if(!GetOutlineTextMetrics(m_hDC, sizeof(OUTLINETEXTMETRIC), &Otm))
{
/*assert(FALSE);*/
} //FAILED
else
{
otmMacAscent=Otm.otmMacAscent;
otmMacDescent=Otm.otmMacDescent;
otmMacLineGap=Otm.otmMacLineGap;
otmEMSquare=Otm.otmEMSquare;
tmAscent=Otm.otmTextMetrics.tmAscent;
}
}
int n_mac_Ascn=otmMacAscent;
int n_mac_Desc=abs(otmMacDescent);
int n_mac_LGap=otmMacLineGap;
m_nEmHeight=(unsigned short)otmEMSquare;
int ntxtAscent=tmAscent;
m_nCellAscent=(n_mac_Ascn*m_nEmHeight)/ntxtAscent;
m_nCellDescent=(n_mac_Desc*m_nEmHeight)/ntxtAscent;
m_nLineSpacing=((n_mac_Ascn+n_mac_Desc+n_mac_LGap)*m_nEmHeight)/ntxtAscent;
m_femSize=emSize;
RestoreDC(m_hDC, nSave_dc);
}
else
{
delete(m_agg_pFeng);m_agg_pFeng=NULL;
}
}
Font::~Font()
{
if(m_agg_pFeng)
delete(m_agg_pFeng);
::ReleaseDC(NULL, m_hDC); m_hDC=0;
}
BOOL Font::IsAvailable() const
{
return(m_agg_pFeng!=NULL);
}
REAL Font::GetHeight(REAL dpi) const
{
double dblLineSpacing=GetLineSpacing();
double dblEmHeight=GetEmHeight();
//double dblResolution=m_agg_pFeng->resolution();
double dblMult=1.00;
if(m_Unit!=UnitPixel)
dblMult=dpi/72.00;
return REAL(dblLineSpacing*(m_femSize/dblEmHeight)*dblMult);
}
float Font::get_res_unit_to_pixel() const
{
switch(m_Unit)
{
case UnitPixel:return(1.0f);
default:
case UnitPoint:return(float(96.0/72.0));
}
}
void Font::MeasureChars2(const WCHAR* string, int length, const PointF &origin, MeasureCharsRectF *rcArray) const
{
if(!IsAvailable())
{ /*assert(FALSE);*/return; }
if(length<0)
length=(long)wcslen(string);
const WCHAR* p = string;
unsigned num_glyphs = 0;
typedef agg::font_cache_manager<font_engine_type> font_manager_type;
font_manager_type m_fman(*m_agg_pFeng);
//double m_weight_value=0.00;
double f_em_height = GetEmHeight();
double f_em_ascent = GetCellAscent();
double f_font_size=get_res_unit_to_pixel()*GetSize();
double m_height_value=f_font_size*f_em_ascent/f_em_height;
{
double x = origin.X;//+z_get_1_6_em();
double y0 = origin.Y+m_height_value;// - m_height_value - 10.0;
double y = y0;
//bool bFirst=false;
while(*p && length)
{
const agg::glyph_cache* glyph = m_fman.glyph(*p);
if(*p!='\n' && glyph)
{
m_fman.add_kerning(&x, &y);
//assert(glyph->data_type==agg::glyph_data_outline);
//if(!bFirst) { x-=glyph->bounds.x1; bFirst=true; }
rcArray[num_glyphs].X=float(x+glyph->bounds.x1);//+glyph->bounds.x1);
//rcArray[num_glyphs].X=float(x+glyph->bounds.x1);//+glyph->bounds.x1);
rcArray[num_glyphs].Y=float(y+glyph->bounds.y1);
rcArray[num_glyphs].Width=float(glyph->bounds.x2-glyph->bounds.x1);
rcArray[num_glyphs].Height=float(glyph->bounds.y2-glyph->bounds.y1);
rcArray[num_glyphs].StartX=float(x);
rcArray[num_glyphs].Advance=float(glyph->advance_x);
// increment pen position
x += glyph->advance_x;
y += glyph->advance_y;
++num_glyphs;
}
++p;
length--;
}
}
}
//ZTODO: Test new function
void aggplus_flat_measure_fit_chars(const Font *font, const WCHAR* string, int length, float fMaxWidth, float *pfLinStart, float *pfLinWidth, int *pnLinChars, int *pnAdvanceChars, bool *break_by_newline)
{
if(!font->IsAvailable())
{
/*assert(FALSE);*/return;
}
if(length<0) length=(long)wcslen(string);
if(!length) { *pfLinStart=*pfLinWidth=0.00;*pnLinChars=0; return; }
*pfLinStart=0.0f;
*break_by_newline=false;
const WCHAR* p = string;
typedef agg::font_cache_manager<font_engine_type> font_manager_type;
font_manager_type m_fman(*font->get_agg_font_engine());
int n_last_fit_nonspace=0;
double f_last_fit_nonspace_advance_width=0.00;
double f_last_fit_nonspace_blckbox_width=0.00;
int n_last_fit_allchars=0;
double f_last_fit_allchars_advance_width=0.00;
double f_last_fit_allchars_blckbox_width=0.00;
int n_plus_advance=0;
double f_prev_fit_advance_width=0.00;
double f_prev_fit_blckbox_width=0.00;
double f_next_fit_advance_width=0.00;
double f_next_fit_blckbox_width=0.00;
double y = 0.00;
WCHAR prev_char=0;//' ';
bool prev_char_is_white=false;
bool prev_char_is_begin_white=false;
int q=0;
bool bStop=false;
while(*p)
{
bool char_is_white=false;
bool char_is_begin_white=false;
const agg::glyph_cache* glyph = m_fman.glyph(*p);
if(!glyph) break;
//assert(glyph->data_type==agg::glyph_data_outline);
if(*p=='\n')
{
n_last_fit_nonspace=q;
f_last_fit_nonspace_blckbox_width=f_next_fit_blckbox_width;
n_plus_advance++;
*break_by_newline=true;
bStop=true;
}
else if(*p=='\r')
{
//Ignore it
n_plus_advance++;
}
else
{
if(!q)
*pfLinStart=(float)glyph->bounds.x1;
//else?
m_fman.add_kerning(&f_next_fit_advance_width, &y);
//***
f_next_fit_blckbox_width=f_next_fit_advance_width;
f_next_fit_advance_width+=glyph->advance_x;
f_next_fit_blckbox_width+=glyph->bounds.x2;
q++;
//***
switch(*p)
{
case ' ':
//char_is_white=true;
char_is_begin_white=true;
if(n_last_fit_allchars==0)
{
n_last_fit_nonspace=q;
f_last_fit_nonspace_advance_width=f_next_fit_advance_width;
f_last_fit_nonspace_blckbox_width=f_next_fit_blckbox_width;
//Check this:
n_last_fit_allchars=q;
f_last_fit_allchars_advance_width=f_next_fit_advance_width;
f_last_fit_allchars_blckbox_width=f_next_fit_blckbox_width;
}
else
{
if(!prev_char_is_begin_white)
{
n_last_fit_nonspace=n_last_fit_allchars;
f_last_fit_nonspace_advance_width=f_last_fit_allchars_advance_width;
f_last_fit_nonspace_blckbox_width=f_last_fit_allchars_blckbox_width;
}
}
break;
//ZTODO
case '(':case '[':case '{': //ZTODO: spec case
char_is_begin_white=true;
case '-':case '!':case '?':case '%':case ')':case ']':case '}':
char_is_white=true;
//break;
default:
if(f_next_fit_blckbox_width>=fMaxWidth)
{
//case when single word don't fit
if(n_last_fit_nonspace==0)
{
n_last_fit_nonspace=n_last_fit_allchars;
f_last_fit_nonspace_blckbox_width=f_last_fit_allchars_blckbox_width;
}
bStop=true;
}
else
{
if(char_is_begin_white)
{
if(!prev_char_is_begin_white)
{
n_last_fit_nonspace=n_last_fit_allchars;
f_last_fit_nonspace_advance_width=f_last_fit_allchars_advance_width;
f_last_fit_nonspace_blckbox_width=f_last_fit_allchars_blckbox_width;
}
char_is_white=false;
}
else if(prev_char_is_white)
{
n_last_fit_nonspace=n_last_fit_allchars;
f_last_fit_nonspace_advance_width=f_last_fit_allchars_advance_width;
f_last_fit_nonspace_blckbox_width=f_last_fit_allchars_blckbox_width;
}
n_last_fit_allchars=q;
f_last_fit_allchars_advance_width=f_next_fit_advance_width;
f_last_fit_allchars_blckbox_width=f_next_fit_blckbox_width;
}
break;
}
f_prev_fit_blckbox_width=f_prev_fit_advance_width;
f_prev_fit_advance_width+=glyph->advance_x;
f_prev_fit_blckbox_width+=glyph->bounds.x2;
}
if(bStop)
break;
length--;
if(!length)
{
n_last_fit_nonspace=n_last_fit_allchars;
f_last_fit_nonspace_blckbox_width=f_last_fit_allchars_blckbox_width;
break;
}
prev_char=*p;
prev_char_is_white=char_is_white;
prev_char_is_begin_white=char_is_begin_white;
++p;
y += glyph->advance_y;
}
*pnLinChars=n_last_fit_nonspace;
*pnAdvanceChars=n_last_fit_nonspace+n_plus_advance;
*pfLinWidth=(float)f_last_fit_nonspace_blckbox_width;
}
double Font::get_1_6_em() const
{
return (GetSize()*get_res_unit_to_pixel())/6.00;
}
}