#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_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_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; } }