//---------------------------------------------------------------------------- // GraphicsPath class - Version 0.1.2 - 07-11-2004 // Marlon Mircevski //---------------------------------------------------------------------------- //#include "stdafx.h" #include #include #include "ap_GraphicsPath.h" #include "ap_Graphics.h" #include "ap_Pen.h" //#include "ap_FontFamily.h" //#define UNICODE //#define _UNICODE #include "ap_Font.h" //#include "agg_font_win32_tt.h" #pragma warning(disable : 4786) //#pragma warning(disable : 4097) #include "agg_rasterizer_scanline_aa.h" #include "agg_conv_transform.h" #include "agg_conv_stroke.h" #include "agg_conv_contour.h" #include "agg_conv_unclose_polygon.h" #include "agg_bezier_arc.h" #include "agg_conv_curve.h" namespace Aggplus { ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// GraphicsPath::GraphicsPath() { } GraphicsPath::~GraphicsPath() { } GraphicsPath *GraphicsPath::Clone() { GraphicsPath *pNew=new GraphicsPath; pNew->m_agg_ps=m_agg_ps; return(pNew); } Status GraphicsPath::Reset() { m_agg_ps.remove_all(); return Ok; } Status GraphicsPath::StartFigure() { m_agg_ps.start_new_path(); return Ok; } Status GraphicsPath::CloseFigure() { m_agg_ps.close_polygon(); return Ok; } /* void GraphicsPath::GetLastPoint(PointF *pfLast) const { double x, y; m_agg_ps.last_vertex(&x, &y); pfLast->X=(float)x; pfLast->Y=(float)y; } */ void GraphicsPath::z_MoveTo(float X, float Y) { m_agg_ps.move_to(X, Y); } void GraphicsPath::z_LineTo(float X, float Y) { m_agg_ps.line_to(X, Y); } int GraphicsPath::GetPointCount() const { unsigned int nPointCount=0; unsigned int nTotal = m_agg_ps.total_vertices(); double x, y; for(unsigned int i=0;i=360.0f) { //ZTODO: to emulate Gdi+ behavior } agg::bezier_arc arc(x+width/2.00, y+height/2.00, width/2.00, height/2.00, agg::deg2rad(startAngle), agg::deg2rad(sweepAngle)); //2.3 m_agg_ps.add_path(arc, 0, !z_is_poly_closed()); if(z_is_poly_closed()) m_agg_ps.concat_path(arc, 0); else m_agg_ps.join_path(arc, 0); return Ok; } Status GraphicsPath::AddEllipse(REAL x, REAL y, REAL width, REAL height) { agg::bezier_arc arc(x+width/2.00, y+height/2.00, width/2.00, height/2.00, 0.00, 2.00*agg::pi); //2.3 m_agg_ps.add_path(arc, 0, true); m_agg_ps.join_path(arc, 0); return Ok; } void GraphicsPath::GetBounds(RectF *pRct) { unsigned int nTotal = m_agg_ps.total_vertices(); if(nTotal) { agg::rect_d bounds(1e100, 1e100, -1e100, -1e100); double x, y; for(unsigned int i=0;i bounds.x2) bounds.x2 = x; if(y > bounds.y2) bounds.y2 = y; } /* if(nTip) { if(!(nTip&agg::path_flags_close)) { if(x < bounds.x1) bounds.x1 = x; if(y < bounds.y1) bounds.y1 = y; if(x > bounds.x2) bounds.x2 = x; if(y > bounds.y2) bounds.y2 = y; } } */ } pRct->X=(float)bounds.x1; pRct->Y=(float)bounds.y1; pRct->Width=(float)(bounds.x2-bounds.x1); pRct->Height=(float)(bounds.y2-bounds.y1); } else { *pRct=RectF(0,0,0,0); } } Status GraphicsPath::Transform(const Matrix* matrix) { if(matrix) { agg::path_storage p2(m_agg_ps); agg::conv_transform trans(p2, matrix->m_agg_mtx); m_agg_ps.remove_all(); //2.3 m_agg_ps.add_path(trans, 0, false); m_agg_ps.concat_path(trans, 0); } return Ok; } BOOL GraphicsPath::IsVisible(REAL x, REAL y, const Graphics* g) { assert(g==NULL); //ZTODO agg::rasterizer_scanline_aa<> ras; typedef agg::conv_curve conv_crv_type; agg::path_storage p_copy(m_agg_ps); conv_crv_type p3(p_copy); //2.3 ras.add_path(p3); m_agg_ps.join_path(p3, 0); return(ras.hit_test((int)x, (int)y)); } void GraphicsPath::Widen(const Pen* Pen, const Matrix* matrix, float flatness) { assert(Pen); assert(matrix==NULL && flatness==0.00); //ZTODO typedef agg::conv_curve conv_crv_type; typedef agg::conv_contour Path_Conv_Contour; conv_crv_type crv(m_agg_ps); Path_Conv_Contour pg(crv); pg.miter_limit(0.50); //?pg.miter_limit_theta(0.05); //?pg.approximation_scale(2.00); pg.width(Pen->GetWidth()); agg::line_join_e LineJoin; switch(Pen->GetLineJoin()) { case LineJoinMiter : LineJoin=agg::miter_join; break; case LineJoinBevel : LineJoin=agg::bevel_join; break; default: case LineJoinRound : LineJoin=agg::round_join; break; case LineJoinMiterClipped: LineJoin=agg::miter_join_revert; break; } pg.line_join(LineJoin); pg.auto_detect_orientation(false); agg::path_storage psNew; //2.3 psNew.add_path(pg, 0, false); //m_agg_ps.concat_path(pg, 0); m_agg_ps.concat_path(pg, 0); m_agg_ps=psNew; } void GraphicsPath::z_Stroke(const Pen* Pen) { assert(Pen); typedef agg::conv_stroke Path_Conv_Stroke; Path_Conv_Stroke pg(m_agg_ps); pg.line_join(agg::round_join); pg.line_cap(agg::round_cap); pg.approximation_scale(25.00); //pg.miter_limit(0.50); //dali? pg.width(Pen->GetWidth()); //pg.auto_detect_orientation(true); agg::path_storage psNew; //2.3 psNew.add_path(pg, 0, false); psNew.concat_path(pg, 0); m_agg_ps=psNew; } #define SPC WCHAR(' ') #define RET WCHAR('\n') Status GraphicsPath::AddStringFont(const WCHAR *string, INT length, const Font *font, const RectF &layoutRect, const StringFormat *format) { return aggplus_flat_add_string_byfont_getbounds(this, string, length, font, layoutRect, format, NULL, NULL, NULL); } Status aggplus_flat_add_string_byfont_getbounds(GraphicsPath *path, const WCHAR *string, INT length, const Font *font, const RectF &layoutRect, const StringFormat *format, RectF *Bounds, int *codepointsFitted, int *linesFilled) { if(!font || !font->IsAvailable()) { return InvalidParameter; } StringFormat *pDefault_format=NULL; if(!format) { pDefault_format=new StringFormat; format=pDefault_format; } if(length<0) length=(Aggplus::INT)wcslen(string); StringAlignment alignment=format->GetAlignment(); //double m_weight_value=0.00; double f_em_height=font->GetEmHeight(); double f_em_linespacing = font->GetLineSpacing(); //double f_em_ascent = font->GetCellAscent(); double f_font_size=font->get_res_unit_to_pixel()*font->GetSize(); double f_line_Advance=f_font_size * f_em_linespacing / f_em_height; float f_txt_max_width=(float)(layoutRect.Width-2.0*font->get_1_6_em()); float f_txt_max_height=(float)(layoutRect.Y+layoutRect.Height); float f_text_offpoint=layoutRect.X; if( alignment==StringAlignmentNear) { } else if(alignment==StringAlignmentCenter) { f_text_offpoint+=f_txt_max_width/2.00f; } else if(alignment==StringAlignmentFar) { f_text_offpoint+=f_txt_max_width; } if(layoutRect.Width<=0.0f) { f_txt_max_width=REAL_MAX; } //Infinite if(layoutRect.Height<=0.0f) { f_txt_max_height=REAL_MAX; } //Infinite double dblOrgY=layoutRect.Y; float bnd_x1=REAL_MAX, bnd_x2=REAL_MIN; float bnd_y1=REAL_MAX, bnd_y2=REAL_MIN; bool break_by_newline=true; bnd_y1=(REAL)dblOrgY; int num_lines=0; int num_chars=0; while(length>0 && dblOrgY+f_line_Advance0 && *string==SPC) { string++; length--; num_chars++; } //strip spaces from begin. } if(!length) break; int nLinChars, nAdvanceChars; float fLinStart, fLinWidth; aggplus_flat_measure_fit_chars(font, string, length, f_txt_max_width, &fLinStart, &fLinWidth, &nLinChars, &nAdvanceChars, &break_by_newline); if(nLinChars>0) { assert(nAdvanceChars); PointF origin(f_text_offpoint, (REAL)dblOrgY); if( alignment==StringAlignmentNear) { } else if(alignment==StringAlignmentCenter) { origin.X-=fLinWidth/2.00f; } else if(alignment==StringAlignmentFar) { origin.X-=fLinWidth; } else { } //StringAlignmentNear if(bnd_x1>origin.X) bnd_x1=origin.X; if(bnd_x2 origin.X-=fLinStart; if(path) aggplus_flat_add_string_byfont_singleline(path, string, nLinChars, font, origin); } else if(nAdvanceChars==0) { nAdvanceChars++; } //just skip string+=nAdvanceChars; length-=nAdvanceChars; num_lines++; num_chars+=nAdvanceChars; /* if(length==0 && nLinChars==0) { assert(FALSE); } */ dblOrgY+=f_line_Advance; if(bnd_y20) { if(bnd_y2REAL_MIN && bnd_y2>REAL_MIN) { Bounds->X=bnd_x1; Bounds->Width=(Aggplus::REAL)(bnd_x2-bnd_x1 +2.0*font->get_1_6_em()); //Eh! Bounds->Y=bnd_y1; Bounds->Height=bnd_y2-bnd_y1; } else { Bounds->X=Bounds->Y=Bounds->Width=Bounds->Height=0.0f; } } if(pDefault_format) delete(pDefault_format); //AddRectangle(layoutRect); return Ok; } void aggplus_flat_add_string_byfont_singleline(GraphicsPath *path, const WCHAR* string, int length, const Font* font, const PointF &origin) { if(!path) { assert(FALSE);return; } if(!font || !font->IsAvailable()) { assert(FALSE);return; } //z_Convert_wcharp_to_charp cText(string); //if(length<0) length=cText.m_nLength; if(length<0) length=(int)wcslen(string); //const char* p = cText.m_pcStr; const WCHAR* p = string; font_manager_type fman(*(font->get_agg_font_engine())); // Pipeline to process the vectors glyph paths (curves + contour) agg::conv_curve m_curves(fman.path_adaptor()); agg::conv_contour > m_contour(m_curves); double m_weight_value=0.00; double f_em_height=font->GetEmHeight(); double f_em_linespacing = font->GetLineSpacing(); double f_em_ascent = font->GetCellAscent(); double f_font_size=font->get_res_unit_to_pixel()*font->GetSize(); double f_line_Advance=f_font_size * f_em_linespacing / f_em_height; double x0 = origin.X+ font->get_1_6_em(); //for :) 1/6em see http://support.microsoft.com/default.aspx?scid=kb;en-us;307208 double y0 = origin.Y+ f_font_size*f_em_ascent/f_em_height; { double x = x0; double y = y0; int nLines=0; while(*p && length) { const agg::glyph_cache* glyph = fman.glyph(*p); if(glyph) { //TRACE("%04X\n", *p); assert(glyph->data_type==agg::glyph_data_outline); // increment pen position switch(*p) { case L'\r': assert(FALSE); //Invalid, should be single line break; case RET: assert(FALSE); //Invalid, should be single line nLines++; x = x0; y=y0+double(nLines)*f_line_Advance; break; default: fman.add_kerning(&x, &y); //It initializes the embedded adaptors that interpret glyph data. //You don't need to do it unless you need to actually render the glyph. fman.init_embedded_adaptors(glyph, x, y); /* 2.3 if(fabs(m_weight_value) <= 0.01) { path->z_get_agg_path_storage()->add_path(m_curves, 0, false); } else { path->z_get_agg_path_storage()->add_path(m_contour, 0, false); } */ if(fabs(m_weight_value) <= 0.01) { path->z_get_agg_path_storage()->concat_path(m_curves, 0); } else { path->z_get_agg_path_storage()->concat_path(m_contour, 0); } x += glyph->advance_x; y += glyph->advance_y; break; } } ++p; length--; } } } } //Changes //0.1.0 27-10-2004 //GraphicsPath::AddStringFontFormatted with StringAlignment //Font::z_measure_fit_chars changes - stripping of spaces at the end //0.1.1 03-11-2004 //GraphicsPath::GetPointCount //GraphicsPath::GetPathPoints //GraphicsPath::AddBezier //GraphicsPath::AddArc fixed //GraphicsPath::AddEllipse fixed //0.1.2 07-11-2004 //GraphicsPath::AddStringFont //added flat func. aggplus_flat_add_string_byfont_singleline //added flat func. aggplus_flat_add_string_byfont_getbounds