1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.3
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
4 //
5 // Permission to copy, use, modify, sell and distribute this software
6 // is granted provided this copyright notice appears in all copies.
7 // This software is provided "as is" without express or implied
8 // warranty, and with no claim as to its suitability for any purpose.
9 //
10 //----------------------------------------------------------------------------
11 // Contact: mcseem@antigrain.com
12 //          mcseemagg@yahoo.com
13 //          http://www.antigrain.com
14 //----------------------------------------------------------------------------
15 //
16 // SVG path renderer.
17 //
18 //----------------------------------------------------------------------------
19 
20 #include <stdio.h>
21 #include "agg_svg_path_renderer.h"
22 
23 namespace mapserver
24 {
25 namespace svg
26 {
27 
28     //------------------------------------------------------------------------
path_renderer()29     path_renderer::path_renderer() :
30         m_curved(m_storage),
31         m_curved_count(m_curved),
32 
33         m_curved_stroked(m_curved_count),
34         m_curved_stroked_trans(m_curved_stroked, m_transform),
35 
36         m_curved_trans(m_curved_count, m_transform),
37         m_curved_trans_contour(m_curved_trans)
38     {
39         m_curved_trans_contour.auto_detect_orientation(false);
40     }
41 
42     //------------------------------------------------------------------------
remove_all()43     void path_renderer::remove_all()
44     {
45         m_storage.remove_all();
46         m_attr_storage.remove_all();
47         m_attr_stack.remove_all();
48         m_transform.reset();
49     }
50 
51     //------------------------------------------------------------------------
begin_path()52     void path_renderer::begin_path()
53     {
54         push_attr();
55         unsigned idx = m_storage.start_new_path();
56         m_attr_storage.add(path_attributes(cur_attr(), idx));
57     }
58 
59     //------------------------------------------------------------------------
end_path()60     void path_renderer::end_path()
61     {
62         if(m_attr_storage.size() == 0)
63         {
64             throw exception("end_path : The path was not begun");
65         }
66         path_attributes attr = cur_attr();
67         unsigned idx = m_attr_storage[m_attr_storage.size() - 1].index;
68         attr.index = idx;
69         m_attr_storage[m_attr_storage.size() - 1] = attr;
70         pop_attr();
71     }
72 
73     //------------------------------------------------------------------------
move_to(double x,double y,bool rel)74     void path_renderer::move_to(double x, double y, bool rel)          // M, m
75     {
76         if(rel) m_storage.rel_to_abs(&x, &y);
77         m_storage.move_to(x, y);
78     }
79 
80     //------------------------------------------------------------------------
line_to(double x,double y,bool rel)81     void path_renderer::line_to(double x,  double y, bool rel)         // L, l
82     {
83         if(rel) m_storage.rel_to_abs(&x, &y);
84         m_storage.line_to(x, y);
85     }
86 
87     //------------------------------------------------------------------------
hline_to(double x,bool rel)88     void path_renderer::hline_to(double x, bool rel)                   // H, h
89     {
90         double x2 = 0.0;
91         double y2 = 0.0;
92         if(m_storage.total_vertices())
93         {
94             m_storage.vertex(m_storage.total_vertices() - 1, &x2, &y2);
95             if(rel) x += x2;
96             m_storage.line_to(x, y2);
97         }
98     }
99 
100     //------------------------------------------------------------------------
vline_to(double y,bool rel)101     void path_renderer::vline_to(double y, bool rel)                   // V, v
102     {
103         double x2 = 0.0;
104         double y2 = 0.0;
105         if(m_storage.total_vertices())
106         {
107             m_storage.vertex(m_storage.total_vertices() - 1, &x2, &y2);
108             if(rel) y += y2;
109             m_storage.line_to(x2, y);
110         }
111     }
112 
113     //------------------------------------------------------------------------
curve3(double x1,double y1,double x,double y,bool rel)114     void path_renderer::curve3(double x1, double y1,                   // Q, q
115                                double x,  double y, bool rel)
116     {
117         if(rel)
118         {
119             m_storage.rel_to_abs(&x1, &y1);
120             m_storage.rel_to_abs(&x,  &y);
121         }
122         m_storage.curve3(x1, y1, x, y);
123     }
124 
125     //------------------------------------------------------------------------
curve3(double x,double y,bool rel)126     void path_renderer::curve3(double x, double y, bool rel)           // T, t
127     {
128 //        throw exception("curve3(x, y) : NOT IMPLEMENTED YET");
129         if(rel)
130         {
131             m_storage.curve3_rel(x, y);
132         } else
133         {
134             m_storage.curve3(x, y);
135         }
136     }
137 
138     //------------------------------------------------------------------------
curve4(double x1,double y1,double x2,double y2,double x,double y,bool rel)139     void path_renderer::curve4(double x1, double y1,                   // C, c
140                                double x2, double y2,
141                                double x,  double y, bool rel)
142     {
143         if(rel)
144         {
145             m_storage.rel_to_abs(&x1, &y1);
146             m_storage.rel_to_abs(&x2, &y2);
147             m_storage.rel_to_abs(&x,  &y);
148         }
149         m_storage.curve4(x1, y1, x2, y2, x, y);
150     }
151 
152     //------------------------------------------------------------------------
curve4(double x2,double y2,double x,double y,bool rel)153     void path_renderer::curve4(double x2, double y2,                   // S, s
154                                double x,  double y, bool rel)
155     {
156         //throw exception("curve4(x2, y2, x, y) : NOT IMPLEMENTED YET");
157         if(rel)
158         {
159             m_storage.curve4_rel(x2, y2, x, y);
160         } else
161         {
162             m_storage.curve4(x2, y2, x, y);
163         }
164     }
165 
166     //------------------------------------------------------------------------
close_subpath()167     void path_renderer::close_subpath()
168     {
169         m_storage.end_poly(path_flags_close);
170     }
171 
172     //------------------------------------------------------------------------
cur_attr()173     path_attributes& path_renderer::cur_attr()
174     {
175         if(m_attr_stack.size() == 0)
176         {
177             throw exception("cur_attr : Attribute stack is empty");
178         }
179         return m_attr_stack[m_attr_stack.size() - 1];
180     }
181 
182     //------------------------------------------------------------------------
push_attr()183     void path_renderer::push_attr()
184     {
185         m_attr_stack.add(m_attr_stack.size() ?
186                          m_attr_stack[m_attr_stack.size() - 1] :
187                          path_attributes());
188     }
189 
190     //------------------------------------------------------------------------
pop_attr()191     void path_renderer::pop_attr()
192     {
193         if(m_attr_stack.size() == 0)
194         {
195             throw exception("pop_attr : Attribute stack is empty");
196         }
197         m_attr_stack.remove_last();
198     }
199 
200     //------------------------------------------------------------------------
fill(const rgba8 & f)201     void path_renderer::fill(const rgba8& f)
202     {
203         path_attributes& attr = cur_attr();
204         attr.fill_color = f;
205         attr.fill_flag = true;
206     }
207 
208     //------------------------------------------------------------------------
stroke(const rgba8 & s)209     void path_renderer::stroke(const rgba8& s)
210     {
211         path_attributes& attr = cur_attr();
212         attr.stroke_color = s;
213         attr.stroke_flag = true;
214     }
215 
216     //------------------------------------------------------------------------
even_odd(bool flag)217     void path_renderer::even_odd(bool flag)
218     {
219         cur_attr().even_odd_flag = flag;
220     }
221 
222     //------------------------------------------------------------------------
stroke_width(double w)223     void path_renderer::stroke_width(double w)
224     {
225         cur_attr().stroke_width = w;
226     }
227 
228     //------------------------------------------------------------------------
fill_none()229     void path_renderer::fill_none()
230     {
231         cur_attr().fill_flag = false;
232     }
233 
234     //------------------------------------------------------------------------
stroke_none()235     void path_renderer::stroke_none()
236     {
237         cur_attr().stroke_flag = false;
238     }
239 
240     //------------------------------------------------------------------------
fill_opacity(double op)241     void path_renderer::fill_opacity(double op)
242     {
243         cur_attr().fill_color.opacity(op);
244     }
245 
246     //------------------------------------------------------------------------
stroke_opacity(double op)247     void path_renderer::stroke_opacity(double op)
248     {
249         cur_attr().stroke_color.opacity(op);
250     }
251 
252     //------------------------------------------------------------------------
line_join(line_join_e join)253     void path_renderer::line_join(line_join_e join)
254     {
255         cur_attr().line_join = join;
256     }
257 
258     //------------------------------------------------------------------------
line_cap(line_cap_e cap)259     void path_renderer::line_cap(line_cap_e cap)
260     {
261         cur_attr().line_cap = cap;
262     }
263 
264     //------------------------------------------------------------------------
miter_limit(double ml)265     void path_renderer::miter_limit(double ml)
266     {
267         cur_attr().miter_limit = ml;
268     }
269 
270     //------------------------------------------------------------------------
transform()271     trans_affine& path_renderer::transform()
272     {
273         return cur_attr().transform;
274     }
275 
276     //------------------------------------------------------------------------
parse_path(path_tokenizer & tok)277     void path_renderer::parse_path(path_tokenizer& tok)
278     {
279         while(tok.next())
280         {
281             double arg[10];
282             char cmd = tok.last_command();
283             unsigned i;
284             switch(cmd)
285             {
286                 case 'M': case 'm':
287                     arg[0] = tok.last_number();
288                     arg[1] = tok.next(cmd);
289                     move_to(arg[0], arg[1], cmd == 'm');
290                     break;
291 
292                 case 'L': case 'l':
293                     arg[0] = tok.last_number();
294                     arg[1] = tok.next(cmd);
295                     line_to(arg[0], arg[1], cmd == 'l');
296                     break;
297 
298                 case 'V': case 'v':
299                     vline_to(tok.last_number(), cmd == 'v');
300                     break;
301 
302                 case 'H': case 'h':
303                     hline_to(tok.last_number(), cmd == 'h');
304                     break;
305 
306                 case 'Q': case 'q':
307                     arg[0] = tok.last_number();
308                     for(i = 1; i < 4; i++)
309                     {
310                         arg[i] = tok.next(cmd);
311                     }
312                     curve3(arg[0], arg[1], arg[2], arg[3], cmd == 'q');
313                     break;
314 
315                 case 'T': case 't':
316                     arg[0] = tok.last_number();
317                     arg[1] = tok.next(cmd);
318                     curve3(arg[0], arg[1], cmd == 't');
319                     break;
320 
321                 case 'C': case 'c':
322                     arg[0] = tok.last_number();
323                     for(i = 1; i < 6; i++)
324                     {
325                         arg[i] = tok.next(cmd);
326                     }
327                     curve4(arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], cmd == 'c');
328                     break;
329 
330                 case 'S': case 's':
331                     arg[0] = tok.last_number();
332                     for(i = 1; i < 4; i++)
333                     {
334                         arg[i] = tok.next(cmd);
335                     }
336                     curve4(arg[0], arg[1], arg[2], arg[3], cmd == 's');
337                     break;
338 
339                 case 'A': case 'a':
340                     throw exception("parse_path: Command A: NOT IMPLEMENTED YET");
341 
342                 case 'Z': case 'z':
343                     close_subpath();
344                     break;
345 
346                 default:
347                 {
348                     char buf[100];
349                     sprintf(buf, "parse_path: Invalid Command %c", cmd);
350                     throw exception(buf);
351                 }
352             }
353         }
354     }
355 
356 }
357 }
358 
359