summaryrefslogtreecommitdiff
path: root/src/corelib/render/software/svg/agg_svg_path_renderer.pas
diff options
context:
space:
mode:
authorGraeme Geldenhuys <graeme@mastermaths.co.za>2012-02-27 19:53:35 +0200
committerGraeme Geldenhuys <graeme@mastermaths.co.za>2012-03-07 22:44:08 +0200
commitb50c7fe536960a49349475f5c361044b097f24dc (patch)
treeeb74f0624ebaca3b6ee64a08b3edb63883eb06c2 /src/corelib/render/software/svg/agg_svg_path_renderer.pas
parenta955b0e4833ba419478be83523fe433d645cd789 (diff)
downloadfpGUI-b50c7fe536960a49349475f5c361044b097f24dc.tar.xz
initial import of AggPas 2.4 RM3
The AggPas demos will not compile at this time, because I have restructured the directories a bit. I wanted a pristine checkin though. The demos will be fixed in the next few commits.
Diffstat (limited to 'src/corelib/render/software/svg/agg_svg_path_renderer.pas')
-rw-r--r--src/corelib/render/software/svg/agg_svg_path_renderer.pas893
1 files changed, 893 insertions, 0 deletions
diff --git a/src/corelib/render/software/svg/agg_svg_path_renderer.pas b/src/corelib/render/software/svg/agg_svg_path_renderer.pas
new file mode 100644
index 00000000..c1fa0614
--- /dev/null
+++ b/src/corelib/render/software/svg/agg_svg_path_renderer.pas
@@ -0,0 +1,893 @@
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.4 (Public License)
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
+//
+// Anti-Grain Geometry - Version 2.4 Release Milano 3 (AggPas 2.4 RM3)
+// Pascal Port By: Milan Marusinec alias Milano
+// milan@marusinec.sk
+// http://www.aggpas.org
+// Copyright (c) 2005-2006
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+//----------------------------------------------------------------------------
+// Contact: mcseem@antigrain.com
+// mcseemagg@yahoo.com
+// http://www.antigrain.com
+//
+// [Pascal Port History] -----------------------------------------------------
+//
+// 24.04.2006-Milano: Unit port establishment
+//
+{ agg_svg_path_renderer.pas }
+unit
+ agg_svg_path_renderer ;
+
+INTERFACE
+
+{$I agg_mode.inc }
+
+uses
+ agg_basics ,
+ agg_path_storage ,
+ agg_conv_transform ,
+ agg_conv_stroke ,
+ agg_conv_contour ,
+ agg_conv_curve ,
+ agg_color ,
+ agg_array ,
+ agg_bounding_rect ,
+ agg_rasterizer_scanline_aa ,
+ agg_vertex_source ,
+ agg_svg_path_tokenizer ,
+ agg_svg_exception ,
+ agg_trans_affine ,
+ agg_math_stroke ,
+ agg_scanline ,
+ agg_renderer_scanline ,
+ agg_render_scanlines ;
+
+{ TYPES DEFINITION }
+type
+ conv_count = object(vertex_source )
+ m_source : vertex_source_ptr;
+ m_count : unsigned;
+
+ constructor Construct(vs : vertex_source_ptr );
+
+ procedure count_(n : unsigned );
+ function _count : unsigned;
+
+ procedure rewind(path_id : unsigned ); virtual;
+ function vertex(x ,y : double_ptr ) : unsigned; virtual;
+
+ end;
+
+// Basic path attributes
+ path_attributes_ptr = ^path_attributes;
+ path_attributes = object
+ index : unsigned;
+
+ fill_color ,
+ stroke_color : aggclr;
+ fill_flag ,
+ stroke_flag ,
+ even_odd_flag : boolean;
+
+ line_join ,
+ line_cap : unsigned;
+ miter_limit ,
+ stroke_width : double;
+
+ transform : trans_affine;
+
+ // Empty constructor
+ constructor Construct; overload;
+
+ // Copy constructor
+ constructor Construct(attr : path_attributes_ptr ); overload;
+
+ // Copy constructor with new index value
+ constructor Construct(attr : path_attributes_ptr; idx : unsigned ); overload;
+
+ end;
+
+// Path container and renderer.
+ path_renderer_ptr = ^path_renderer;
+ path_renderer = object(unsigned_list )
+ m_storage : path_storage;
+ m_attr_storage ,
+ m_attr_stack : pod_deque;
+ m_transform : trans_affine;
+
+ m_curved : conv_curve;
+ m_curved_count : conv_count;
+
+ m_curved_stroked : conv_stroke;
+ m_curved_stroked_trans : conv_transform;
+
+ m_curved_trans : conv_transform;
+ m_curved_trans_contour : conv_contour;
+
+ constructor Construct;
+ destructor Destruct;
+
+ procedure remove_all;
+
+ // Use these functions as follows:
+ // begin_path when the XML tag <path> comes ("start_element" handler)
+ // parse_path on "d=" tag attribute
+ // end_path when parsing of the entire tag is done.
+ procedure begin_path;
+ procedure parse_path(tok : path_tokenizer_ptr );
+ procedure end_path;
+
+ // The following functions are essentially a "reflection" of
+ // the respective SVG path commands.
+ procedure move_to (x ,y : double; rel : boolean = false ); // M, m
+ procedure line_to (x ,y : double; rel : boolean = false ); // L, l
+ procedure hline_to(x : double; rel : boolean = false ); // H, h
+ procedure vline_to(y : double; rel : boolean = false ); // V, v
+
+ procedure curve3(x1 ,y1 ,x ,y : double; rel : boolean = false ); overload; // Q, q
+ procedure curve3(x ,y : double; rel : boolean = false ); overload; // T, t
+ procedure curve4(x1 ,y1 ,x2 ,y2 ,x ,y : double; rel : boolean = false ); overload; // C, c
+ procedure curve4(x2 ,y2 ,x ,y : double; rel : boolean = false ); overload; // S, s
+
+ procedure close_subpath; // Z, z
+
+ procedure add_path(vs : vertex_source_ptr; path_id : unsigned = 0; solid_path : boolean = true );
+ function vertex_count : unsigned;
+
+ // Call these functions on <g> tag (start_element, end_element respectively)
+ procedure push_attr;
+ procedure pop_attr;
+
+ // Attribute setting functions
+ procedure fill (f : aggclr_ptr );
+ procedure stroke (s : aggclr_ptr );
+ procedure even_odd (flag : boolean );
+ procedure stroke_width(w : double );
+
+ procedure fill_none;
+ procedure stroke_none;
+
+ procedure fill_opacity (op : double );
+ procedure stroke_opacity(op : double );
+ procedure line_join (join : unsigned );
+ procedure line_cap (cap : unsigned );
+ procedure miter_limit (ml : double );
+
+ function transform : trans_affine_ptr;
+
+ // Make all polygons CCW-oriented
+ procedure arrange_orientations;
+
+ // Expand all polygons
+ procedure expand(value : double );
+
+ function array_operator(idx : unsigned ) : unsigned; virtual;
+ procedure bounding_rect (x1 ,y1 ,x2 ,y2 : double_ptr );
+
+ // Rendering. One can specify two additional parameters:
+ // trans_affine and opacity. They can be used to transform the whole
+ // image and/or to make it translucent.
+ procedure render(
+ ras : rasterizer_scanline_ptr;
+ sl : scanline_ptr;
+ ren : renderer_scanline_ptr;
+ mtx : trans_affine_ptr;
+ cb : rect_ptr;
+ opacity : double = 1.0 );
+
+ // Private
+ function cur_attr : path_attributes_ptr;
+
+ end;
+
+{ GLOBAL PROCEDURES }
+
+
+IMPLEMENTATION
+{ LOCAL VARIABLES & CONSTANTS }
+{ UNIT IMPLEMENTATION }
+{ CONSTRUCT }
+constructor conv_count.Construct;
+begin
+ m_source:=vs;
+ m_count :=0;
+
+end;
+
+{ COUNT_ }
+procedure conv_count.count_;
+begin
+ m_count:=n;
+
+end;
+
+{ _COUNT }
+function conv_count._count;
+begin
+ result:=m_count;
+
+end;
+
+{ REWIND }
+procedure conv_count.rewind;
+begin
+ m_source.rewind(path_id );
+
+end;
+
+{ VERTEX }
+function conv_count.vertex;
+begin
+ inc(m_count );
+
+ result:=m_source.vertex(x ,y );
+
+end;
+
+{ CONSTRUCT }
+constructor path_attributes.Construct;
+begin
+ index:=0;
+
+ fill_color.ConstrInt (0 ,0 ,0 );
+ stroke_color.ConstrInt(0 ,0 ,0 );
+
+ fill_flag :=true;
+ stroke_flag :=false;
+ even_odd_flag:=false;
+ line_join :=miter_join;
+ line_cap :=butt_cap;
+ miter_limit :=4.0;
+ stroke_width :=1.0;
+
+ transform.Construct;
+
+end;
+
+{ CONSTRUCT }
+constructor path_attributes.Construct(attr : path_attributes_ptr );
+begin
+ index:=attr.index;
+
+ fill_color.Construct (@attr.fill_color );
+ stroke_color.Construct(@attr.stroke_color );
+
+ fill_flag :=attr.fill_flag;
+ stroke_flag :=attr.stroke_flag;
+ even_odd_flag:=attr.even_odd_flag;
+ line_join :=attr.line_join;
+ line_cap :=attr.line_cap;
+ miter_limit :=attr.miter_limit;
+ stroke_width :=attr.stroke_width;
+
+ transform.Construct;
+ transform.assign_all(@attr.transform );
+
+end;
+
+{ CONSTRUCT }
+constructor path_attributes.Construct(attr : path_attributes_ptr; idx : unsigned );
+begin
+ index:=idx;
+
+ fill_color.Construct (@attr.fill_color );
+ stroke_color.Construct(@attr.stroke_color );
+
+ fill_flag :=attr.fill_flag;
+ stroke_flag :=attr.stroke_flag;
+ even_odd_flag:=attr.even_odd_flag;
+ line_join :=attr.line_join;
+ line_cap :=attr.line_cap;
+ miter_limit :=attr.miter_limit;
+ stroke_width :=attr.stroke_width;
+
+ transform.Construct;
+ transform.assign_all(@attr.transform );
+
+end;
+
+{ CONSTRUCT }
+constructor path_renderer.Construct;
+begin
+ m_storage.Construct;
+ m_attr_storage.Construct(sizeof(path_attributes ) );
+ m_attr_stack.Construct(sizeof(path_attributes ) );
+ m_transform.Construct;
+
+ m_curved.Construct (@m_storage );
+ m_curved_count.Construct(@m_curved );
+
+ m_curved_stroked.Construct (@m_curved_count );
+ m_curved_stroked_trans.Construct(@m_curved_stroked ,@m_transform );
+
+ m_curved_trans.Construct (@m_curved_count ,@m_transform );
+ m_curved_trans_contour.Construct(@m_curved_trans );
+
+end;
+
+{ DESTRUCT }
+destructor path_renderer.Destruct;
+begin
+ m_curved_trans_contour.Destruct;
+ m_curved_stroked.Destruct;
+ m_curved.Destruct;
+
+ m_attr_stack.Destruct;
+ m_attr_storage.Destruct;
+ m_storage.Destruct;
+
+end;
+
+{ REMOVE_ALL }
+procedure path_renderer.remove_all;
+begin
+ m_storage.remove_all;
+ m_attr_storage.remove_all;
+ m_attr_stack.remove_all;
+ m_transform.reset;
+
+end;
+
+{ BEGIN_PATH }
+procedure path_renderer.begin_path;
+var
+ idx : unsigned;
+ attr : path_attributes;
+
+begin
+ push_attr;
+
+ idx:=m_storage.start_new_path;
+
+ attr.Construct(cur_attr ,idx );
+
+ m_attr_storage.add(@attr );
+
+end;
+
+{ PARSE_PATH }
+procedure path_renderer.parse_path;
+var
+ arg : array[0..9 ] of double;
+ i : unsigned;
+ cmd : char;
+ buf : array[0..99 ] of char;
+
+begin
+ while tok.next do
+ begin
+ cmd:=tok.last_command;
+
+ case cmd of
+ 'M' ,'m' :
+ begin
+ arg[0 ]:=tok.last_number;
+ arg[1 ]:=tok.next(cmd );
+
+ move_to(arg[0 ] ,arg[1 ] ,cmd = 'm' );
+
+ end;
+
+ 'L' ,'l' :
+ begin
+ arg[0 ]:=tok.last_number;
+ arg[1 ]:=tok.next(cmd );
+
+ line_to(arg[0 ] ,arg[1 ] ,cmd = 'l' );
+
+ end;
+
+ 'V' ,'v' :
+ vline_to(tok.last_number ,cmd = 'v' );
+
+ 'H' ,'h' :
+ hline_to(tok.last_number ,cmd = 'h' );
+
+ 'Q' ,'q' :
+ begin
+ arg[0 ]:=tok.last_number;
+
+ for i:=1 to 3 do
+ arg[i ]:=tok.next(cmd );
+
+ curve3(arg[0 ] ,arg[1 ] ,arg[2 ] ,arg[3 ] ,cmd = 'q' );
+
+ end;
+
+ 'T' ,'t' :
+ begin
+ arg[0 ]:=tok.last_number;
+ arg[1 ]:=tok.next(cmd );
+
+ curve3(arg[0 ] ,arg[1 ] ,cmd = 't' );
+
+ end;
+
+ 'C' ,'c' :
+ begin
+ arg[0 ]:=tok.last_number;
+
+ for i:=1 to 5 do
+ arg[i ]:=tok.next(cmd );
+
+ curve4(arg[0 ] ,arg[1 ] ,arg[2 ] ,arg[3 ] ,arg[4 ] ,arg[5 ] ,cmd = 'c' );
+
+ end;
+
+ 'S' ,'s' :
+ begin
+ arg[0 ]:=tok.last_number;
+
+ for i:=1 to 3 do
+ arg[i ]:=tok.next(cmd );
+
+ curve4(arg[0 ] ,arg[1 ] ,arg[2 ] ,arg[3 ] ,cmd = 's' );
+
+ end;
+
+ 'A' ,'a' :
+ raise svg_exception.Construct(PChar('parse_path: Command A: NOT IMPLEMENTED YET' ) );
+
+ 'Z' ,'z' :
+ close_subpath;
+
+ else
+ begin
+ sprintf(@buf[0 ] ,'parse_path: Invalid Command %c' ,unsigned(cmd ) );
+
+ raise svg_exception.Construct(PChar(@buf[0 ] ) );
+
+ end;
+
+ end;
+
+ end;
+
+end;
+
+{ END_PATH }
+procedure path_renderer.end_path;
+var
+ idx : unsigned;
+ attr : path_attributes;
+
+begin
+ if m_attr_storage.size = 0 then
+ raise svg_exception(PChar('end_path : The path was not begun' ) );
+
+ attr.Construct(cur_attr );
+
+ idx :=path_attributes_ptr(m_attr_storage.array_operator(m_attr_storage.size - 1 ) ).index;
+ attr.index:=idx;
+
+ move(
+ pointer(@attr )^ ,
+ path_attributes_ptr(m_attr_storage.array_operator(m_attr_storage.size - 1 ) )^ ,
+ sizeof(path_attributes ) );
+
+ pop_attr;
+
+end;
+
+{ MOVE_TO }
+procedure path_renderer.move_to;
+begin
+ if rel then
+ m_storage.rel_to_abs(@x ,@y );
+
+ m_storage.move_to(x ,y );
+
+end;
+
+{ LINE_TO }
+procedure path_renderer.line_to;
+begin
+ if rel then
+ m_storage.rel_to_abs(@x ,@y );
+
+ m_storage.line_to(x ,y );
+
+end;
+
+{ HLINE_TO }
+procedure path_renderer.hline_to;
+var
+ x2 ,y2 : double;
+
+begin
+ x2:=0.0;
+ y2:=0.0;
+
+ if m_storage.total_vertices <> 0 then
+ begin
+ m_storage.vertex_(m_storage.total_vertices - 1 ,@x2 ,@y2 );
+
+ if rel then
+ x:=x + x2;
+
+ m_storage.line_to(x ,y2 );
+
+ end;
+
+end;
+
+{ VLINE_TO }
+procedure path_renderer.vline_to;
+var
+ x2 ,y2 : double;
+
+begin
+ x2:=0.0;
+ y2:=0.0;
+
+ if m_storage.total_vertices <> 0 then
+ begin
+ m_storage.vertex_(m_storage.total_vertices - 1 ,@x2 ,@y2 );
+
+ if rel then
+ y:=y + y2;
+
+ m_storage.line_to(x2 ,y );
+
+ end;
+
+end;
+
+{ CURVE3 }
+procedure path_renderer.curve3(x1 ,y1 ,x ,y : double; rel : boolean = false );
+begin
+ if rel then
+ begin
+ m_storage.rel_to_abs(@x1 ,@y1 );
+ m_storage.rel_to_abs(@x ,@y );
+
+ end;
+
+ m_storage.curve3(x1 ,y1 ,x ,y );
+
+end;
+
+{ CURVE3 }
+procedure path_renderer.curve3(x ,y : double; rel : boolean = false );
+begin
+// raise exception("curve3(x, y) : NOT IMPLEMENTED YET");
+ if rel then
+ m_storage.curve3_rel(x ,y )
+ else
+ m_storage.curve3(x ,y );
+
+end;
+
+{ CURVE4 }
+procedure path_renderer.curve4(x1 ,y1 ,x2 ,y2 ,x ,y : double; rel : boolean = false );
+begin
+ if rel then
+ begin
+ m_storage.rel_to_abs(@x1 ,@y1 );
+ m_storage.rel_to_abs(@x2 ,@y2 );
+ m_storage.rel_to_abs(@x ,@y );
+
+ end;
+
+ m_storage.curve4(x1 ,y1 ,x2 ,y2 ,x ,y );
+
+end;
+
+{ CURVE4 }
+procedure path_renderer.curve4(x2 ,y2 ,x ,y : double; rel : boolean = false );
+begin
+//throw exception("curve4(x2, y2, x, y) : NOT IMPLEMENTED YET");
+ if rel then
+ m_storage.curve4_rel(x2 ,y2 ,x ,y )
+ else
+ m_storage.curve4(x2 ,y2 ,x ,y );
+
+end;
+
+{ CLOSE_SUBPATH }
+procedure path_renderer.close_subpath;
+begin
+ m_storage.end_poly(path_flags_close );
+
+end;
+
+{ ADD_PATH }
+procedure path_renderer.add_path;
+begin
+ m_storage.add_path(vs ,path_id ,solid_path );
+
+end;
+
+{ VERTEX_COUNT }
+function path_renderer.vertex_count;
+begin
+ result:=m_curved_count._count;
+
+end;
+
+{ PUSH_ATTR }
+procedure path_renderer.push_attr;
+var
+ attr : path_attributes;
+
+begin
+ if m_attr_stack.size <> 0 then
+ m_attr_stack.add(
+ m_attr_stack.array_operator(m_attr_stack.size - 1 ) )
+ else
+ begin
+ attr.Construct;
+
+ m_attr_stack.add(@attr );
+
+ end;
+
+end;
+
+{ POP_ATTR }
+procedure path_renderer.pop_attr;
+begin
+ if m_attr_stack.size = 0 then
+ raise svg_exception(PChar('pop_attr : Attribute stack is empty' ) );
+
+ m_attr_stack.remove_last;
+
+end;
+
+{ FILL }
+procedure path_renderer.fill;
+var
+ attr : path_attributes_ptr;
+
+begin
+ attr:=cur_attr;
+
+ attr.fill_color:=f^;
+ attr.fill_flag :=true;
+
+end;
+
+{ STROKE }
+procedure path_renderer.stroke;
+var
+ attr : path_attributes_ptr;
+
+begin
+ attr:=cur_attr;
+
+ attr.stroke_color:=s^;
+ attr.stroke_flag :=true;
+
+end;
+
+{ EVEN_ODD }
+procedure path_renderer.even_odd;
+begin
+ cur_attr.even_odd_flag:=flag;
+
+end;
+
+{ STROKE_WIDTH }
+procedure path_renderer.stroke_width;
+var
+ attr : path_attributes_ptr;
+
+begin
+ attr:=cur_attr;
+
+ attr.stroke_width:=w;
+ attr.stroke_flag :=true;
+
+end;
+
+{ FILL_NONE }
+procedure path_renderer.fill_none;
+begin
+ cur_attr.fill_flag:=false;
+
+end;
+
+{ STROKE_NONE }
+procedure path_renderer.stroke_none;
+begin
+ cur_attr.stroke_flag:=false;
+
+end;
+
+{ FILL_OPACITY }
+procedure path_renderer.fill_opacity;
+begin
+ cur_attr.fill_color.opacity_(op );
+
+end;
+
+{ STROKE_OPACITY }
+procedure path_renderer.stroke_opacity;
+begin
+ cur_attr.stroke_color.opacity_(op );
+
+end;
+
+{ LINE_JOIN }
+procedure path_renderer.line_join;
+begin
+ cur_attr.line_join:=join;
+
+end;
+
+{ LINE_CAP }
+procedure path_renderer.line_cap;
+begin
+ cur_attr.line_cap:=cap;
+
+end;
+
+{ MITER_LIMIT }
+procedure path_renderer.miter_limit;
+begin
+ cur_attr.miter_limit:=ml;
+
+end;
+
+{ TRANSFORM }
+function path_renderer.transform;
+begin
+ result:=@cur_attr.transform;
+
+end;
+
+{ ARRANGE_ORIENTATIONS }
+procedure path_renderer.arrange_orientations;
+begin
+ m_storage.arrange_orientations_all_paths(path_flags_ccw );
+
+end;
+
+{ EXPAND }
+procedure path_renderer.expand;
+begin
+ m_curved_trans_contour.width_(value );
+
+end;
+
+{ ARRAY_OPERATOR }
+function path_renderer.array_operator;
+begin
+ m_transform.assign_all(
+ @path_attributes_ptr(
+ m_attr_storage.array_operator(idx ) ).transform );
+
+ result:=path_attributes_ptr(m_attr_storage.array_operator(idx ) ).index;
+
+end;
+
+{ BOUNDING_RECT }
+procedure path_renderer.bounding_rect;
+var
+ trans : conv_transform;
+
+begin
+ trans.Construct(@m_storage ,@m_transform );
+
+ bounding_rect_ul(
+ @trans ,@self ,0 ,m_attr_storage.size ,x1 ,y1 ,x2 ,y2 );
+
+end;
+
+{ RENDER }
+procedure path_renderer.render;
+var
+ i : unsigned;
+
+ scl : double;
+
+ attr : path_attributes_ptr;
+
+ color : aggclr;
+
+begin
+ ras.clip_box (cb.x1 ,cb.y1 ,cb.x2 ,cb.y2 );
+ m_curved_count.count_(0 );
+
+ i:=0;
+
+ while i < m_attr_storage.size do
+ begin
+ attr:=path_attributes_ptr(m_attr_storage.array_operator(i ) );
+
+ m_transform.assign_all(@attr.transform );
+ m_transform.multiply (mtx );
+
+ scl:=m_transform.scale;
+
+ //m_curved.approximation_method(curve_inc );
+
+ m_curved.approximation_scale_(scl );
+ m_curved.angle_tolerance_ (0.0 );
+
+ color.Construct;
+
+ if attr.fill_flag then
+ begin
+ ras.reset;
+
+ if attr.even_odd_flag then
+ ras.filling_rule(fill_even_odd )
+ else
+ ras.filling_rule(fill_non_zero );
+
+ if Abs(m_curved_trans_contour._width ) < 0.0001 then
+ ras.add_path(@m_curved_trans ,attr.index )
+ else
+ begin
+ m_curved_trans_contour.miter_limit_(attr.miter_limit );
+
+ ras.add_path(@m_curved_trans_contour ,attr.index );
+
+ end;
+
+ color:=attr.fill_color;
+
+ color.opacity_ (color._opacity * opacity );
+ ren.color_ (@color );
+ render_scanlines(ras ,sl ,ren );
+
+ end;
+
+ if attr.stroke_flag then
+ begin
+ m_curved_stroked.width_(attr.stroke_width );
+
+ //m_curved_stroked.line_join_((attr.line_join == miter_join) ? miter_join_round : attr.line_join);
+
+ m_curved_stroked.line_join_ (attr.line_join );
+ m_curved_stroked.line_cap_ (attr.line_cap );
+ m_curved_stroked.miter_limit_ (attr.miter_limit );
+ m_curved_stroked.approximation_scale_(scl );
+
+ // If the *visual* line width is considerable we
+ // turn on processing of curve cusps.
+ //---------------------
+ if attr.stroke_width * scl > 1.0 then
+ m_curved.angle_tolerance_(0.2 );
+
+ ras.reset;
+ ras.filling_rule(fill_non_zero );
+ ras.add_path (@m_curved_stroked_trans ,attr.index );
+
+ color:=attr.stroke_color;
+
+ color.opacity_ (color._opacity * opacity);
+ ren.color_ (@color );
+ render_scanlines(ras ,sl ,ren );
+
+ end;
+
+ inc(i );
+
+ end;
+
+end;
+
+{ CUR_ATTR }
+function path_renderer.cur_attr;
+begin
+ if m_attr_stack.size = 0 then
+ raise svg_exception.Construct(PChar('cur_attr : Attribute stack is empty' ) );
+
+ result:=
+ path_attributes_ptr(
+ m_attr_stack.array_operator(m_attr_stack.size - 1 ) );
+
+end;
+
+END.
+