1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.4 (Public License)
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
4 //
5 // Anti-Grain Geometry - Version 2.4 Release Milano 3 (AggPas 2.4 RM3)
6 // Pascal Port By: Milan Marusinec alias Milano
7 //                 milan@marusinec.sk
8 //                 http://www.aggpas.org
9 // Copyright (c) 2005-2006
10 //
11 // Permission to copy, use, modify, sell and distribute this software
12 // is granted provided this copyright notice appears in all copies.
13 // This software is provided "as is" without express or implied
14 // warranty, and with no claim as to its suitability for any purpose.
15 //
16 //----------------------------------------------------------------------------
17 // Contact: mcseem@antigrain.com
18 //          mcseemagg@yahoo.com
19 //          http://www.antigrain.com
20 //
21 // [Pascal Port History] -----------------------------------------------------
22 //
23 // 03.01.2007-Milano: Adjustments for ExpatWrap (Win,Linux & Mac)
24 // 23.06.2006-Milano: ptrcomp adjustments
25 // 24.04.2006-Milano: Unit port establishment
26 //
27 { agg_svg_parser.pas }
28 unit
29  agg_svg_parser ;
30 
31 INTERFACE
32 
33 {$DEFINE EXPAT_WRAPPER }
34 {$I agg_mode.inc }
35 
36 uses
37  SysUtils ,
38  agg_basics ,
39  agg_color ,
40  agg_svg_path_tokenizer ,
41  agg_svg_path_renderer ,
42  agg_svg_exception ,
43  agg_trans_affine ,
44  agg_math_stroke ,
45  expat ,
46  file_utils_ ;
47 
48 { TYPES DEFINITION }
49 const
50  buf_size = 512;
51 
52 type
53  parser_ptr = ^parser;
54  parser = object
55    m_path      : path_renderer_ptr;
56    m_tokenizer : path_tokenizer;
57 
58    m_buf   ,
59    m_title : char_ptr;
60 
61    m_title_len  : unsigned;
62    m_title_flag ,
63    m_path_flag  : boolean;
64    m_attr_name  ,
65    m_attr_value : char_ptr;
66 
67    m_attr_name_len   ,
68    m_attr_name_aloc  ,
69    m_attr_value_len  ,
70    m_attr_value_aloc : unsigned;
71 
72    constructor Construct(path : path_renderer_ptr );
73    destructor  Destruct;
74 
75    procedure parse(fname : shortstring );
titlenull76    function  title : char_ptr;
77 
78   // XML event handlers
79    procedure parse_attr     (attr : char_ptr_ptr ); overload;
80    procedure parse_path     (attr : char_ptr_ptr );
81    procedure parse_poly     (attr : char_ptr_ptr; close_flag : boolean );
82    procedure parse_rect     (attr : char_ptr_ptr );
83    procedure parse_line     (attr : char_ptr_ptr );
84    procedure parse_style    (str : agg_basics.char_ptr );
85    procedure parse_transform(str : agg_basics.char_ptr );
86 
parse_matrixnull87    function  parse_matrix   (str : agg_basics.char_ptr ) : unsigned;
parse_translatenull88    function  parse_translate(str : agg_basics.char_ptr ) : unsigned;
parse_rotatenull89    function  parse_rotate   (str : agg_basics.char_ptr ) : unsigned;
parse_scalenull90    function  parse_scale    (str : agg_basics.char_ptr ) : unsigned;
parse_skew_xnull91    function  parse_skew_x   (str : agg_basics.char_ptr ) : unsigned;
parse_skew_ynull92    function  parse_skew_y   (str : agg_basics.char_ptr ) : unsigned;
93 
parse_attrnull94    function  parse_attr      (name ,value : agg_basics.char_ptr ) : boolean; overload;
parse_name_valuenull95    function  parse_name_value(nv_start ,nv_end : agg_basics.char_ptr ) : boolean;
96 
97    procedure copy_name (start ,end_ : agg_basics.char_ptr );
98    procedure copy_value(start ,end_ : agg_basics.char_ptr );
99 
100   end;
101 
102 { GLOBAL PROCEDURES }
103  procedure start_element(data : pointer; el : char_ptr; attr : char_ptr_ptr ); {$IFDEF EXPAT_WRAPPER }cdecl; {$ENDIF }
104  procedure end_element  (data : pointer; el : char_ptr ); {$IFDEF EXPAT_WRAPPER }cdecl; {$ENDIF }
105  procedure content      (data : pointer; s : char_ptr; len : int ); {$IFDEF EXPAT_WRAPPER }cdecl; {$ENDIF }
106 
107 
108 IMPLEMENTATION
109 { LOCAL VARIABLES & CONSTANTS }
110 type
111  named_color_ptr = ^named_color;
112  named_color = record
113    name : array[0..21 ] of char;
114 
115    r ,g ,b ,a : int8u;
116 
117   end;
118 
119 const
120  colors_num = 148;
121 
122  colors : array[0..colors_num - 1 ] of named_color =
123   ((name:'aliceblue';            r:240; g:248; b:255; a:255 ) ,
124    (name:'antiquewhite';         r:250; g:235; b:215; a:255 ) ,
125    (name:'aqua';                 r:0;   g:255; b:255; a:255 ) ,
126    (name:'aquamarine';           r:127; g:255; b:212; a:255 ) ,
127    (name:'azure';                r:240; g:255; b:255; a:255 ) ,
128    (name:'beige';                r:245; g:245; b:220; a:255 ) ,
129    (name:'bisque';               r:255; g:228; b:196; a:255 ) ,
130    (name:'black';                r:0;   g:0;   b:0;   a:255 ) ,
131    (name:'blanchedalmond';       r:255; g:235; b:205; a:255 ) ,
132    (name:'blue';                 r:0;   g:0;   b:255; a:255 ) ,
133    (name:'blueviolet';           r:138; g:43;  b:226; a:255 ) ,
134    (name:'brown';                r:165; g:42;  b:42;  a:255 ) ,
135    (name:'burlywood';            r:222; g:184; b:135; a:255 ) ,
136    (name:'cadetblue';            r:95;  g:158; b:160; a:255 ) ,
137    (name:'chartreuse';           r:127; g:255; b:0;   a:255 ) ,
138    (name:'chocolate';            r:210; g:105; b:30;  a:255 ) ,
139    (name:'coral';                r:255; g:127; b:80;  a:255 ) ,
140    (name:'cornflowerblue';       r:100; g:149; b:237; a:255 ) ,
141    (name:'cornsilk';             r:255; g:248; b:220; a:255 ) ,
142    (name:'crimson';              r:220; g:20;  b:60;  a:255 ) ,
143    (name:'cyan';                 r:0;   g:255; b:255; a:255 ) ,
144    (name:'darkblue';             r:0;   g:0;   b:139; a:255 ) ,
145    (name:'darkcyan';             r:0;   g:139; b:139; a:255 ) ,
146    (name:'darkgoldenrod';        r:184; g:134; b:11;  a:255 ) ,
147    (name:'darkgray';             r:169; g:169; b:169; a:255 ) ,
148    (name:'darkgreen';            r:0;   g:100; b:0;   a:255 ) ,
149    (name:'darkgrey';             r:169; g:169; b:169; a:255 ) ,
150    (name:'darkkhaki';            r:189; g:183; b:107; a:255 ) ,
151    (name:'darkmagenta';          r:139; g:0;   b:139; a:255 ) ,
152    (name:'darkolivegreen';       r:85;  g:107; b:47;  a:255 ) ,
153    (name:'darkorange';           r:255; g:140; b:0;   a:255 ) ,
154    (name:'darkorchid';           r:153; g:50;  b:204; a:255 ) ,
155    (name:'darkred';              r:139; g:0;   b:0;   a:255 ) ,
156    (name:'darksalmon';           r:233; g:150; b:122; a:255 ) ,
157    (name:'darkseagreen';         r:143; g:188; b:143; a:255 ) ,
158    (name:'darkslateblue';        r:72;  g:61;  b:139; a:255 ) ,
159    (name:'darkslategray';        r:47;  g:79;  b:79;  a:255 ) ,
160    (name:'darkslategrey';        r:47;  g:79;  b:79;  a:255 ) ,
161    (name:'darkturquoise';        r:0;   g:206; b:209; a:255 ) ,
162    (name:'darkviolet';           r:148; g:0;   b:211; a:255 ) ,
163    (name:'deeppink';             r:255; g:20;  b:147; a:255 ) ,
164    (name:'deepskyblue';          r:0;   g:191; b:255; a:255 ) ,
165    (name:'dimgray';              r:105; g:105; b:105; a:255 ) ,
166    (name:'dimgrey';              r:105; g:105; b:105; a:255 ) ,
167    (name:'dodgerblue';           r:30;  g:144; b:255; a:255 ) ,
168    (name:'firebrick';            r:178; g:34;  b:34;  a:255 ) ,
169    (name:'floralwhite';          r:255; g:250; b:240; a:255 ) ,
170    (name:'forestgreen';          r:34;  g:139; b:34;  a:255 ) ,
171    (name:'fuchsia';              r:255; g:0;   b:255; a:255 ) ,
172    (name:'gainsboro';            r:220; g:220; b:220; a:255 ) ,
173    (name:'ghostwhite';           r:248; g:248; b:255; a:255 ) ,
174    (name:'gold';                 r:255; g:215; b:0;   a:255 ) ,
175    (name:'goldenrod';            r:218; g:165; b:32;  a:255 ) ,
176    (name:'gray';                 r:128; g:128; b:128; a:255 ) ,
177    (name:'green';                r:0;   g:128; b:0;   a:255 ) ,
178    (name:'greenyellow';          r:173; g:255; b:47;  a:255 ) ,
179    (name:'grey';                 r:128; g:128; b:128; a:255 ) ,
180    (name:'honeydew';             r:240; g:255; b:240; a:255 ) ,
181    (name:'hotpink';              r:255; g:105; b:180; a:255 ) ,
182    (name:'indianred';            r:205; g:92;  b:92;  a:255 ) ,
183    (name:'indigo';               r:75;  g:0;   b:130; a:255 ) ,
184    (name:'ivory';                r:255; g:255; b:240; a:255 ) ,
185    (name:'khaki';                r:240; g:230; b:140; a:255 ) ,
186    (name:'lavender';             r:230; g:230; b:250; a:255 ) ,
187    (name:'lavenderblush';        r:255; g:240; b:245; a:255 ) ,
188    (name:'lawngreen';            r:124; g:252; b:0;   a:255 ) ,
189    (name:'lemonchiffon';         r:255; g:250; b:205; a:255 ) ,
190    (name:'lightblue';            r:173; g:216; b:230; a:255 ) ,
191    (name:'lightcoral';           r:240; g:128; b:128; a:255 ) ,
192    (name:'lightcyan';            r:224; g:255; b:255; a:255 ) ,
193    (name:'lightgoldenrodyellow'; r:250; g:250; b:210; a:255 ) ,
194    (name:'lightgray';            r:211; g:211; b:211; a:255 ) ,
195    (name:'lightgreen';           r:144; g:238; b:144; a:255 ) ,
196    (name:'lightgrey';            r:211; g:211; b:211; a:255 ) ,
197    (name:'lightpink';            r:255; g:182; b:193; a:255 ) ,
198    (name:'lightsalmon';          r:255; g:160; b:122; a:255 ) ,
199    (name:'lightseagreen';        r:32;  g:178; b:170; a:255 ) ,
200    (name:'lightskyblue';         r:135; g:206; b:250; a:255 ) ,
201    (name:'lightslategray';       r:119; g:136; b:153; a:255 ) ,
202    (name:'lightslategrey';       r:119; g:136; b:153; a:255 ) ,
203    (name:'lightsteelblue';       r:176; g:196; b:222; a:255 ) ,
204    (name:'lightyellow';          r:255; g:255; b:224; a:255 ) ,
205    (name:'lime';                 r:0;   g:255; b:0;   a:255 ) ,
206    (name:'limegreen';            r:50;  g:205; b:50;  a:255 ) ,
207    (name:'linen';                r:250; g:240; b:230; a:255 ) ,
208    (name:'magenta';              r:255; g:0;   b:255; a:255 ) ,
209    (name:'maroon';               r:128; g:0;   b:0;   a:255 ) ,
210    (name:'mediumaquamarine';     r:102; g:205; b:170; a:255 ) ,
211    (name:'mediumblue';           r:0;   g:0;   b:205; a:255 ) ,
212    (name:'mediumorchid';         r:186; g:85;  b:211; a:255 ) ,
213    (name:'mediumpurple';         r:147; g:112; b:219; a:255 ) ,
214    (name:'mediumseagreen';       r:60;  g:179; b:113; a:255 ) ,
215    (name:'mediumslateblue';      r:123; g:104; b:238; a:255 ) ,
216    (name:'mediumspringgreen';    r:0;   g:250; b:154; a:255 ) ,
217    (name:'mediumturquoise';      r:72;  g:209; b:204; a:255 ) ,
218    (name:'mediumvioletred';      r:199; g:21;  b:133; a:255 ) ,
219    (name:'midnightblue';         r:25;  g:25;  b:112; a:255 ) ,
220    (name:'mintcream';            r:245; g:255; b:250; a:255 ) ,
221    (name:'mistyrose';            r:255; g:228; b:225; a:255 ) ,
222    (name:'moccasin';             r:255; g:228; b:181; a:255 ) ,
223    (name:'navajowhite';          r:255; g:222; b:173; a:255 ) ,
224    (name:'navy';                 r:0;   g:0;   b:128; a:255 ) ,
225    (name:'oldlace';              r:253; g:245; b:230; a:255 ) ,
226    (name:'olive';                r:128; g:128; b:0;   a:255 ) ,
227    (name:'olivedrab';            r:107; g:142; b:35;  a:255 ) ,
228    (name:'orange';               r:255; g:165; b:0;   a:255 ) ,
229    (name:'orangered';            r:255; g:69;  b:0;   a:255 ) ,
230    (name:'orchid';               r:218; g:112; b:214; a:255 ) ,
231    (name:'palegoldenrod';        r:238; g:232; b:170; a:255 ) ,
232    (name:'palegreen';            r:152; g:251; b:152; a:255 ) ,
233    (name:'paleturquoise';        r:175; g:238; b:238; a:255 ) ,
234    (name:'palevioletred';        r:219; g:112; b:147; a:255 ) ,
235    (name:'papayawhip';           r:255; g:239; b:213; a:255 ) ,
236    (name:'peachpuff';            r:255; g:218; b:185; a:255 ) ,
237    (name:'peru';                 r:205; g:133; b:63;  a:255 ) ,
238    (name:'pink';                 r:255; g:192; b:203; a:255 ) ,
239    (name:'plum';                 r:221; g:160; b:221; a:255 ) ,
240    (name:'powderblue';           r:176; g:224; b:230; a:255 ) ,
241    (name:'purple';               r:128; g:0;   b:128; a:255 ) ,
242    (name:'red';                  r:255; g:0;   b:0;   a:255 ) ,
243    (name:'rosybrown';            r:188; g:143; b:143; a:255 ) ,
244    (name:'royalblue';            r:65;  g:105; b:225; a:255 ) ,
245    (name:'saddlebrown';          r:139; g:69;  b:19;  a:255 ) ,
246    (name:'salmon';               r:250; g:128; b:114; a:255 ) ,
247    (name:'sandybrown';           r:244; g:164; b:96;  a:255 ) ,
248    (name:'seagreen';             r:46;  g:139; b:87;  a:255 ) ,
249    (name:'seashell';             r:255; g:245; b:238; a:255 ) ,
250    (name:'sienna';               r:160; g:82;  b:45;  a:255 ) ,
251    (name:'silver';               r:192; g:192; b:192; a:255 ) ,
252    (name:'skyblue';              r:135; g:206; b:235; a:255 ) ,
253    (name:'slateblue';            r:106; g:90;  b:205; a:255 ) ,
254    (name:'slategray';            r:112; g:128; b:144; a:255 ) ,
255    (name:'slategrey';            r:112; g:128; b:144; a:255 ) ,
256    (name:'snow';                 r:255; g:250; b:250; a:255 ) ,
257    (name:'springgreen';          r:0;   g:255; b:127; a:255 ) ,
258    (name:'steelblue';            r:70;  g:130; b:180; a:255 ) ,
259    (name:'tan';                  r:210; g:180; b:140; a:255 ) ,
260    (name:'teal';                 r:0;   g:128; b:128; a:255 ) ,
261    (name:'thistle';              r:216; g:191; b:216; a:255 ) ,
262    (name:'tomato';               r:255; g:99;  b:71;  a:255 ) ,
263    (name:'turquoise';            r:64;  g:224; b:208; a:255 ) ,
264    (name:'violet';               r:238; g:130; b:238; a:255 ) ,
265    (name:'wheat';                r:245; g:222; b:179; a:255 ) ,
266    (name:'white';                r:255; g:255; b:255; a:255 ) ,
267    (name:'whitesmoke';           r:245; g:245; b:245; a:255 ) ,
268    (name:'yellow';               r:255; g:255; b:0;   a:255 ) ,
269    (name:'yellowgreen';          r:154; g:205; b:50;  a:255 ) ,
270    (name:'zzzzzzzzzzz';          r:0;   g:0;   b:0;   a:0   ) );
271 
272  pageEqHigh : shortstring =
273   #1#2#3#4#5#6#7#8#9#10#11#12#13#14#15#16 +
274   #17#18#19#20#21#22#23#24#25#26#27#28#29#30#31#32 +
275   #33#34#35#36#37#38#39#40#41#42#43#44#45#46#47#48 +
276   #49#50#51#52#53#54#55#56#57#58#59#60#61#62#63#64 +
277   #65#66#67#68#69#70#71#72#73#74#75#76#77#78#79#80 +
278   #81#82#83#84#85#86#87#88#89#90#91#92#93#94#95#96 +
279   #65#66#67#68#69#70#71#72#73#74#75#76#77#78#79#80 +
280   #81#82#83#84#85#86#87#88#89#90#123#124#125#126#127#128 +
281   #129#130#131#132#133#134#135#136#137#138#139#140#141#142#143#144 +
282   #145#146#147#148#149#150#151#152#153#154#155#156#157#158#159#160 +
283   #161#162#163#164#165#166#167#168#169#170#171#172#173#174#175#176 +
284   #177#178#179#180#181#182#183#184#185#186#187#188#189#190#191#192 +
285   #193#194#195#196#197#198#199#200#201#202#203#204#205#206#207#208 +
286   #209#210#211#212#213#214#215#216#217#218#219#220#221#222#223#224 +
287   #225#226#227#228#229#230#231#232#233#234#235#236#237#238#239#240 +
288   #241#242#243#244#245#246#247#248#249#250#251#252#253#254#255;
289 
290 { UNIT IMPLEMENTATION }
291 { START_ELEMENT }
292 procedure start_element;
293 var
294  this : parser_ptr;
295 
296 begin
297  this:=parser_ptr(data );
298 
299  if StrComp(PChar(el ) ,'title' ) = 0 then
300   this.m_title_flag:=true
301  else
302   if StrComp(PChar(el ) ,'g' ) = 0 then
303    begin
304     this.m_path.push_attr;
305     this.parse_attr(attr );
306 
307    end
308   else
309    if StrComp(PChar(el ) ,'path' ) = 0 then
310     begin
311      if this.m_path_flag then
312       raise svg_exception.Construct(PChar('start_element: Nested path' ) );
313 
314      this.m_path.begin_path;
315      this.parse_path(attr );
316      this.m_path.end_path;
317 
318      this.m_path_flag:=true;
319 
320     end
321    else
322     if StrComp(PChar(el ) ,'rect' ) = 0 then
323      this.parse_rect(attr )
324     else
325      if StrComp(PChar(el ) ,'line' ) = 0 then
326       this.parse_line(attr )
327      else
328       if StrComp(PChar(el ) ,'polyline' ) = 0 then
329        this.parse_poly(attr ,false )
330       else
331        if StrComp(PChar(el ) ,'polygon' ) = 0 then
332         this.parse_poly(attr ,true );
333 
334      //else
335      // if StrComp(PChar(el ) ,'<OTHER_ELEMENTS>' ) = 0 then
336      //  begin
337      //  end
338      //...
339 
340 end;
341 
342 { END_ELEMENT }
343 procedure end_element;
344 var
345  this : parser_ptr;
346 
347 begin
348  this:=parser_ptr(data );
349 
350  if StrComp(PChar(el ) ,'title' ) = 0 then
351   this.m_title_flag:=false
352  else
353   if StrComp(PChar(el ) ,'g' ) = 0 then
354    this.m_path.pop_attr
355   else
356    if StrComp(PChar(el ) ,'path' ) = 0 then
357     this.m_path_flag:=false;
358 
359  //else
360  // if StrComp(PChar(el ) ,'<OTHER_ELEMENTS>' ) = 0 then
361  //  begin
362  //  end
363  // ...
364 
365 end;
366 
367 { CONTENT }
368 procedure content;
369 var
370  this : parser_ptr;
371 
372 begin
373  this:=parser_ptr(data );
374 
375 // m_title_flag signals that the <title> tag is being parsed now.
376 // The following code concatenates the pieces of content of the <title> tag.
377  if this.m_title_flag then
378   begin
379    if len + this.m_title_len > 255 then
380     len:=255 - this.m_title_len;
381 
382    if len > 0 then
383     begin
384      move(
385       s^ ,
386       char_ptr(ptrcomp(this.m_title ) + this.m_title_len )^ ,
387       len );
388 
389      inc(this.m_title_len ,len );
390 
391      char_ptr(ptrcomp(this.m_title ) + this.m_title_len )^:=#0;
392 
393     end;
394 
395   end;
396 
397 end;
398 
399 { hex_unsigned }
hex_unsignednull400 function hex_unsigned(hexstr : agg_basics.char_ptr ) : unsigned;
401 
xyintnull402 function xyint(x ,y : integer ) : integer;
403 var
404  f : integer;
405  m : boolean;
406 
407 begin
408  m:=false;
409 
410  if y < 0 then
411   begin
412    y:=y * -1;
413    m:=true;
414 
415   end;
416 
417  result:=x;
418 
419  if y > 1 then
420   for f:=1 to y - 1 do
421    result:=result * x;
422 
423  if m then
424   result:=result * -1;
425 
426 end;
427 
428 var
429  h   : shortstring;
430  fcb : byte;
431  yps ,
432  mul ,
433  num : unsigned;
434 
435 label
436  Err ,Esc ;
437 
438 const
439  hex : string[16 ] = '0123456789ABCDEF';
440 
441 begin
442  h:='';
443 
444  while hexstr^ <> #0 do
445   begin
446    h:=h + pageEqHigh[byte(hexstr^ ) ];
447 
448    inc(ptrcomp(hexstr ) );
449 
450   end;
451 
452  if length(h ) > 0 then
453   begin
454    case h[length(h ) ] of
455     '0'..'9' ,'A'..'F' :
456     else
457      goto Err;
458 
459    end;
460 
461    num:=pos(h[length(h ) ] ,hex ) - 1;
462    yps:=2;
463    mul:=xyint(4 ,yps );
464 
465    if length(h ) > 1 then
466     for fcb:=length(h ) - 1 downto 1 do
467      begin
468       case h[fcb ] of
469        '0'..'9' ,'A'..'F' :
470        else
471         goto Err;
472 
473       end;
474 
475       inc(num ,(pos(h[fcb ] ,hex ) - 1 ) * mul );
476       inc(yps ,2 );
477 
478       mul:=xyint(4 ,yps );
479 
480      end;
481 
482    goto Esc;
483 
484   end;
485 
486 Err:
487  num:=0;
488 
489 Esc:
490  result:=num;
491 
492 end;
493 
494 { parse_color }
parse_colornull495 function parse_color(str : agg_basics.char_ptr ) : aggclr;
496 var
497  u : unsigned;
498  p : named_color_ptr;
499  m : shortstring;
500 
501 begin
502  while str^ = ' ' do
503   inc(ptrcomp(str ) );
504 
505  if str^ = '#' then
506   begin
507    inc(ptrcomp(str ) );
508 
509    u:=hex_unsigned(str );
510 
511    result.Construct(rgb8_packed(u ) );
512 
513   end
514  else
515   begin
516    p:=NIL;
517 
518    for u:=0 to colors_num - 1 do
519     if StrComp(colors[u ].name ,PChar(str ) ) = 0 then
520      begin
521       p:=@colors[u ];
522 
523       break;
524 
525      end;
526 
527    if p = NIL then
528     begin
529      m:='parse_color: Invalid color name ' + StrPas(PChar(str ) ) + #0;
530 
531      raise svg_exception.Construct(PChar(@m[1 ] ) );
532 
533     end;
534 
535    result.ConstrInt(p.r ,p.g ,p.b ,p.a );
536 
537   end;
538 
539 end;
540 
541 { parse_double }
parse_doublenull542 function parse_double(str : agg_basics.char_ptr ) : double;
543 begin
544  while str^ = ' ' do
545   inc(ptrcomp(str ) );
546 
547  result:=get_double(pointer(PChar(str ) ) );
548 
549 end;
550 
551 { islower }
islowernull552 function islower(ch : char ) : boolean;
553 begin
554  case ch of
555   #97..#122 :
556    result:=true;
557 
558   else
559    result:=false;
560 
561  end;
562 
563 end;
564 
565 { is_numeric }
is_numericnull566 function is_numeric(ch : char ) : boolean;
567 begin
568  result:=Pos(ch ,'0123456789+-.eE' ) <> 0;
569 
570 end;
571 
572 { parse_transform_args }
parse_transform_argsnull573 function parse_transform_args(str : agg_basics.char_ptr; args : double_ptr; max_na : unsigned; na : unsigned_ptr ) : unsigned;
574 var
575  ptr ,end_ : agg_basics.char_ptr;
576 
577 begin
578  na^:=0;
579  ptr:=str;
580 
581  while (ptr^ <> #0 ) and
582        (ptr^ <> '(' ) do
583   inc(ptrcomp(ptr ) );
584 
585  if ptr^ = #0 then
586   raise svg_exception.Construct(PChar('parse_transform_args: Invalid syntax' ) );
587 
588  end_:=ptr;
589 
590  while (end_^ <> #0 ) and
591        (end_^ <> ')' ) do
592   inc(ptrcomp(end_ ) );
593 
594  if end_^ = #0 then
595   raise svg_exception.Construct(PChar('parse_transform_args: Invalid syntax' ) );
596 
597  while ptrcomp(ptr ) < ptrcomp(end_ ) do
598   if is_numeric(ptr^ ) then
599    begin
600     if na^ >= max_na then
601      raise svg_exception.Construct(PChar('parse_transform_args: Too many arguments' ) );
602 
603     double_ptr(ptrcomp(args ) + na^ * sizeof(double ) )^:=get_double(ptr );
604 
605     inc(na^ );
606 
607     while (ptrcomp(ptr ) < ptrcomp(end_ ) ) and
608           is_numeric(ptr^ ) do
609      inc(ptrcomp(ptr ) );
610 
611    end
612   else
613    inc(ptrcomp(ptr ) );
614 
615  result:=unsigned(ptrcomp(end_ ) - ptrcomp(str ) );
616 
617 end;
618 
619 { CONSTRUCT }
620 constructor parser.Construct;
621 begin
622  m_path:=path;
623 
624  m_tokenizer.Construct;
625 
626  agg_getmem(pointer(m_buf ) ,buf_size );
627  agg_getmem(pointer(m_title ) ,256 );
628 
629  m_title_len :=0;
630  m_title_flag:=false;
631  m_path_flag :=false;
632 
633  m_attr_name_aloc :=128;
634  m_attr_value_aloc:=1024;
635 
636  agg_getmem(pointer(m_attr_name ) ,m_attr_name_aloc );
637  agg_getmem(pointer(m_attr_value ) ,m_attr_value_aloc );
638 
639  m_attr_name_len :=127;
640  m_attr_value_len:=1023;
641 
642  m_title^:=#0;
643 
644 end;
645 
646 { DESTRUCT }
647 destructor parser.Destruct;
648 begin
649  agg_freemem(pointer(m_attr_value ) ,m_attr_value_aloc );
650  agg_freemem(pointer(m_attr_name ) ,m_attr_name_aloc );
651  agg_freemem(pointer(m_title ) ,256 );
652  agg_freemem(pointer(m_buf ) ,buf_size );
653 
654 end;
655 
656 { PARSE }
657 procedure parser.parse;
658 var
659  msg : array[0..1023 ] of char;
660 
661  p  : XML_Parser;
662  af : api_file;
663  ts : char_ptr;
664 
665  done : boolean;
666  len  : int;
667 
668 begin
669  p:=XML_ParserCreate(NIL );
670 
671  if p = NIL then
672   raise svg_exception.Construct(PChar('Couldn''t allocate memory for parser' ) );
673 
674  XML_SetUserData            (p ,@self );
675  XML_SetElementHandler      (p ,@start_element ,@end_element );
676  XML_SetCharacterDataHandler(p ,@content );
677 
678  fname:=fname + #0;
679 
680  dec(byte(fname[0 ] ) );
681 
682  if not api_open_file(af ,fname ) then
683   begin
684    sprintf(@msg[0 ] ,'Couldn''t open file %s' ,unsigned(@fname[1 ] ) );
685 
686    XML_ParserFree(p );
687 
688    raise svg_exception.Construct(PChar(@msg[0 ] ) );
689 
690   end;
691 
692  done:=false;
693 
694  repeat
695   api_read_file(af ,m_buf ,buf_size ,len );
696 
697   done:=len < buf_size;
698 
699   if XML_Parse(p ,pointer(m_buf ) ,len ,int(done ) ) = XML_STATUS_ERROR then
700    begin
701     api_close_file(af );
702     XML_ParserFree(p );
703 
704     sprintf(
705      @msg[0 ] ,
706      '%s at line ' ,
707      unsigned(
708       XML_ErrorString(
709        int(XML_GetErrorCode(p ) ) ) ) );
710 
711     sprintf(
712      @msg[StrLen(msg ) ] ,
713      '%d'#13 ,
714      XML_GetCurrentLineNumber(p ) );
715 
716     raise svg_exception.Construct(PChar(@msg[0 ] ) );
717 
718    end;
719 
720  until done;
721 
722  api_close_file(af );
723  XML_ParserFree(p );
724 
725  ts:=m_title;
726 
727  while ts^ <> #0 do
728   begin
729    if byte(ts^ ) < byte(' ' ) then
730     ts^:=' ';
731 
732    inc(ptrcomp(ts ) );
733 
734   end;
735 
736 end;
737 
738 { TITLE }
parser.titlenull739 function parser.title;
740 begin
741  result:=m_title;
742 
743 end;
744 
745 { PARSE_ATTR }
746 procedure parser.parse_attr(attr : char_ptr_ptr );
747 var
748  i : int;
749 
750 begin
751  i:=0;
752 
753  while char_ptr_ptr(ptrcomp(attr ) + i * sizeof(char_ptr ) )^ <> NIL do
754   begin
755    if StrComp(PChar(char_ptr_ptr(ptrcomp(attr ) + i * sizeof(char_ptr ) )^ ) ,'style' ) = 0 then
756     parse_style(agg_basics.char_ptr_ptr(ptrcomp(attr ) + (i + 1 ) * sizeof(char_ptr ) )^ )
757    else
758     parse_attr(
759      agg_basics.char_ptr_ptr(ptrcomp(attr ) + i * sizeof(char_ptr ) )^ ,
760      agg_basics.char_ptr_ptr(ptrcomp(attr ) + (i + 1 ) * sizeof(char_ptr ) )^ );
761 
762    inc(i ,2 );
763 
764   end;
765 
766 end;
767 
768 { PARSE_PATH }
769 procedure parser.parse_path;
770 var
771  i : int;
772 
773  tmp : array[0..3 ] of agg_basics.char_ptr;
774 
775 begin
776  i:=0;
777 
778  while char_ptr_ptr(ptrcomp(attr ) + i * sizeof(char_ptr ) )^ <> NIL do
779   begin
780   // The <path> tag can consist of the path itself ("d=")
781   // as well as of other parameters like "style=", "transform=", etc.
ofnull782   // In the last case we simply rely on the function of parsing
783   // attributes (see 'else' branch).
784    if StrComp(PChar(char_ptr_ptr(ptrcomp(attr ) + i * sizeof(char_ptr ) )^ ) ,'d' ) = 0 then
785     begin
786      m_tokenizer.set_path_str(agg_basics.char_ptr_ptr(ptrcomp(attr ) + (i + 1 ) * sizeof(char_ptr ) )^ );
787 
788      m_path.parse_path(@m_tokenizer );
789 
790     end
791    else
792     begin
793     // Create a temporary single pair "name-value" in order
794     // to avoid multiple calls for the same attribute.
795      tmp[0 ]:=agg_basics.char_ptr_ptr(ptrcomp(attr ) + i * sizeof(char_ptr ) )^;
796      tmp[1 ]:=agg_basics.char_ptr_ptr(ptrcomp(attr ) + (i + 1 ) * sizeof(char_ptr ) )^;
797      tmp[2 ]:=NIL;
798      tmp[3 ]:=NIL;
799 
800      parse_attr(@tmp );
801 
802     end;
803 
804    inc(i ,2 );
805 
806   end;
807 
808 end;
809 
810 { PARSE_POLY }
811 procedure parser.parse_poly;
812 var
813  i : int;
814 
815  x ,y : double;
816 
817 begin
818  x:=0.0;
819  y:=0.0;
820 
821  m_path.begin_path;
822 
823  i:=0;
824 
825  while char_ptr_ptr(ptrcomp(attr ) + i * sizeof(char_ptr ) )^ <> NIL do
826   begin
827    if not parse_attr(
828            agg_basics.char_ptr_ptr(ptrcomp(attr ) + i * sizeof(char_ptr ) )^ ,
829            agg_basics.char_ptr_ptr(ptrcomp(attr ) + (i + 1 ) * sizeof(char_ptr ) )^ ) then
830     if StrComp(PChar(agg_basics.char_ptr_ptr(ptrcomp(attr ) + i * sizeof(char_ptr ) )^ ) ,'points' ) = 0 then
831      begin
832       m_tokenizer.set_path_str(agg_basics.char_ptr_ptr(ptrcomp(attr ) + (i + 1 ) * sizeof(char_ptr ) )^ );
833 
834       if not m_tokenizer.next then
835        raise svg_exception.Construct(PChar('parse_poly: Too few coordinates' ) );
836 
837       x:=m_tokenizer.last_number;
838 
839       if not m_tokenizer.next then
840        raise svg_exception.Construct(PChar('parse_poly: Too few coordinates' ) );
841 
842       y:=m_tokenizer.last_number;
843 
844       m_path.move_to(x ,y );
845 
846       while m_tokenizer.next do
847        begin
848         x:=m_tokenizer.last_number;
849 
850         if not m_tokenizer.next then
851          raise svg_exception.Construct(PChar('parse_poly: Odd number of coordinates' ) );
852 
853         y:=m_tokenizer.last_number;
854 
855         m_path.line_to(x ,y );
856 
857        end;
858 
859      end;
860 
861    inc(i ,2 );
862 
863   end;
864 
865  m_path.end_path;
866 
867 end;
868 
869 { PARSE_RECT }
870 procedure parser.parse_rect;
871 var
872  i : int;
873 
874  x ,y ,w ,h : double;
875 
876 begin
877  x:=0.0;
878  y:=0.0;
879  w:=0.0;
880  h:=0.0;
881 
882  m_path.begin_path;
883 
884  i:=0;
885 
886  while char_ptr_ptr(ptrcomp(attr ) + i * sizeof(char_ptr ) )^ <> NIL do
887   begin
888    if not parse_attr(
889            agg_basics.char_ptr_ptr(ptrcomp(attr ) + i * sizeof(char_ptr ) )^ ,
890            agg_basics.char_ptr_ptr(ptrcomp(attr ) + (i + 1 ) * sizeof(char_ptr ) )^ ) then
891     begin
892      if StrComp(PChar(char_ptr_ptr(ptrcomp(attr ) + i * sizeof(char_ptr ) )^ ) ,'x' ) = 0 then
893       x:=parse_double(agg_basics.char_ptr_ptr(ptrcomp(attr ) + (i + 1 ) * sizeof(char_ptr ) )^ );
894 
895      if StrComp(PChar(char_ptr_ptr(ptrcomp(attr ) + i * sizeof(char_ptr ) )^ ) ,'y' ) = 0 then
896       y:=parse_double(agg_basics.char_ptr_ptr(ptrcomp(attr ) + (i + 1 ) * sizeof(char_ptr ) )^ );
897 
898      if StrComp(PChar(char_ptr_ptr(ptrcomp(attr ) + i * sizeof(char_ptr ) )^ ) ,'width' ) = 0 then
899       w:=parse_double(agg_basics.char_ptr_ptr(ptrcomp(attr ) + (i + 1 ) * sizeof(char_ptr ) )^ );
900 
901      if StrComp(PChar(char_ptr_ptr(ptrcomp(attr ) + i * sizeof(char_ptr ) )^ ) ,'height' ) = 0 then
902       h:=parse_double(agg_basics.char_ptr_ptr(ptrcomp(attr ) + (i + 1 ) * sizeof(char_ptr ) )^ );
903 
904      // rx - to be implemented
905      // ry - to be implemented
906 
907     end;
908 
909    inc(i ,2 );
910 
911   end;
912 
913  if (w <> 0.0 ) and
914     (h <> 0.0 ) then
915   begin
916    if w < 0.0 then
917     raise svg_exception.Construct(PChar('parse_rect: Invalid width: ' ) );
918 
919    if h < 0.0 then
920     raise svg_exception.Construct(PChar('parse_rect: Invalid height: ' ) );
921 
922    m_path.move_to(x     ,y );
923    m_path.line_to(x + w ,y );
924    m_path.line_to(x + w ,y + h );
925    m_path.line_to(x     ,y + h );
926    m_path.close_subpath;
927 
928   end;
929 
930  m_path.end_path;
931 
932 end;
933 
934 { PARSE_LINE }
935 procedure parser.parse_line;
936 var
937  i : int;
938 
939  x1 ,y1 ,x2 ,y2 : double;
940 
941 begin
942  x1:=0.0;
943  y1:=0.0;
944  x2:=0.0;
945  y2:=0.0;
946 
947  m_path.begin_path;
948 
949  i:=0;
950 
951  while char_ptr_ptr(ptrcomp(attr ) + i * sizeof(char_ptr ) )^ <> NIL do
952   begin
953    if not parse_attr(
954            agg_basics.char_ptr_ptr(ptrcomp(attr ) + i * sizeof(char_ptr ) )^ ,
955            agg_basics.char_ptr_ptr(ptrcomp(attr ) + (i + 1 ) * sizeof(char_ptr ) )^ ) then
956     begin
957      if StrComp(PChar(char_ptr_ptr(ptrcomp(attr ) + i * sizeof(char_ptr ) )^ ) ,'x1' ) = 0 then
958       x1:=parse_double(agg_basics.char_ptr_ptr(ptrcomp(attr ) + (i + 1 ) * sizeof(char_ptr ) )^ );
959 
960      if StrComp(PChar(char_ptr_ptr(ptrcomp(attr ) + i * sizeof(char_ptr ) )^ ) ,'y1' ) = 0 then
961       y1:=parse_double(agg_basics.char_ptr_ptr(ptrcomp(attr ) + (i + 1 ) * sizeof(char_ptr ) )^ );
962 
963      if StrComp(PChar(char_ptr_ptr(ptrcomp(attr ) + i * sizeof(char_ptr ) )^ ) ,'x2' ) = 0 then
964       x2:=parse_double(agg_basics.char_ptr_ptr(ptrcomp(attr ) + (i + 1 ) * sizeof(char_ptr ) )^ );
965 
966      if StrComp(PChar(char_ptr_ptr(ptrcomp(attr ) + i * sizeof(char_ptr ) )^ ) ,'y2' ) = 0 then
967       y2:=parse_double(agg_basics.char_ptr_ptr(ptrcomp(attr ) + (i + 1 ) * sizeof(char_ptr ) )^ );
968 
969     end;
970 
971    inc(i ,2 );
972 
973   end;
974 
975  m_path.move_to(x1 ,y1 );
976  m_path.line_to(x2 ,y2 );
977  m_path.end_path;
978 
979 end;
980 
981 { PARSE_STYLE }
982 procedure parser.parse_style;
983 var
984  nv_start ,nv_end : agg_basics.char_ptr;
985 
986 begin
987  while str^ <> #0 do
988   begin
989   // Left Trim
990    while (str^ <> #0 ) and
991          (str^ = ' ' ) do
992     inc(ptrcomp(str ) );
993 
994    nv_start:=str;
995 
996    while (str^ <> #0 ) and
997          (str^ <> ';' ) do
998     inc(ptrcomp(str ) );
999 
1000    nv_end:=str;
1001 
1002   // Right Trim
1003    while (ptrcomp(nv_end ) > ptrcomp(nv_start ) ) and
1004          ((nv_end^ = ';' ) or
1005           (nv_end^ = ' ' ) ) do
1006     dec(ptrcomp(nv_end ) );
1007 
1008    inc(ptrcomp(nv_end ) );
1009 
1010    parse_name_value(nv_start ,nv_end );
1011 
1012    if str^ <> #0 then
1013     inc(ptrcomp(str ) );
1014 
1015   end;
1016 
1017 end;
1018 
1019 { PARSE_TRANSFORM }
1020 procedure parser.parse_transform;
1021 begin
1022  while str^ <> #0 do
1023   begin
1024    if islower(str^ ) then
1025     if StrLComp(PChar(str ) ,'matrix' ,6 ) = 0 then
1026      inc(ptrcomp(str ) ,parse_matrix(str ) )
1027     else
1028      if StrLComp(PChar(str ) ,'translate' ,9 ) = 0 then
1029       inc(ptrcomp(str ) ,parse_translate(str ) )
1030      else
1031       if StrLComp(PChar(str ) ,'rotate' ,6 ) = 0 then
1032        inc(ptrcomp(str ) ,parse_rotate(str ) )
1033       else
1034        if StrLComp(PChar(str ) ,'scale' ,5 ) = 0 then
1035         inc(ptrcomp(str ) ,parse_scale(str ) )
1036        else
1037         if StrLComp(PChar(str ) ,'skewX' ,5 ) = 0 then
1038          inc(ptrcomp(str ) ,parse_skew_x(str ) )
1039         else
1040          if StrLComp(PChar(str ) ,'skewY' ,5 ) = 0  then
1041           inc(ptrcomp(str ) ,parse_skew_y(str ) )
1042          else
1043           inc(ptrcomp(str ) )
1044 
1045    else
1046     inc(ptrcomp(str ) );
1047 
1048   end;
1049 
1050 end;
1051 
1052 { PARSE_MATRIX }
parser.parse_matrixnull1053 function parser.parse_matrix;
1054 var
1055  args : array[0..5 ] of double;
1056 
1057  na ,len : unsigned;
1058 
1059  ta : trans_affine;
1060 
1061 begin
1062  na :=0;
1063  len:=parse_transform_args(str ,@args ,6 ,@na );
1064 
1065  if na <> 6 then
1066   raise svg_exception.Construct(PChar('parse_matrix: Invalid number of arguments' ) );
1067 
1068  ta.Construct(args[0 ] ,args[1 ] ,args[2 ] ,args[3 ] ,args[4 ] ,args[5 ] );
1069 
1070  m_path.transform.premultiply(@ta );
1071 
1072  result:=len;
1073 
1074 end;
1075 
1076 { PARSE_TRANSLATE }
parser.parse_translatenull1077 function parser.parse_translate;
1078 var
1079  args : array[0..1 ] of double;
1080 
1081  na ,len : unsigned;
1082 
1083  tat : trans_affine_translation;
1084 
1085 begin
1086  na :=0;
1087  len:=parse_transform_args(str ,@args ,2 ,@na );
1088 
1089  if na = 1 then
1090   args[1 ]:=0.0;
1091 
1092  tat.Construct(args[0 ] ,args[1 ] );
1093 
1094  m_path.transform.premultiply(@tat );
1095 
1096  result:=len;
1097 
1098 end;
1099 
1100 { PARSE_ROTATE }
parser.parse_rotatenull1101 function parser.parse_rotate;
1102 var
1103  args : array[0..2 ] of double;
1104 
1105  na ,len : unsigned;
1106 
1107  tar : trans_affine_rotation;
1108 
1109  tat ,t : trans_affine_translation;
1110 
1111 begin
1112  na :=0;
1113  len:=parse_transform_args(str ,@args ,3 ,@na );
1114 
1115  if na = 1 then
1116   begin
1117    tar.Construct(deg2rad(args[0 ] ) );
1118 
1119    m_path.transform.premultiply(@tar  );
1120 
1121   end
1122  else
1123   if na = 3 then
1124    begin
1125     t.Construct(-args[1 ] ,-args[2 ] );
1126 
1127     tar.Construct(deg2rad(args[0 ] ) );
1128     tat.Construct(args[1 ] ,args[2 ] );
1129 
1130     t.multiply(@tar );
1131     t.multiply(@tat );
1132 
1133     m_path.transform.premultiply(@t );
1134 
1135    end
1136   else
1137    raise svg_exception.Construct(PChar('parse_rotate: Invalid number of arguments' ) );
1138 
1139  result:=len;
1140 
1141 end;
1142 
1143 { PARSE_SCALE }
parser.parse_scalenull1144 function parser.parse_scale;
1145 var
1146  args : array[0..1 ] of double;
1147 
1148  na ,len : unsigned;
1149 
1150  tas : trans_affine_scaling;
1151 
1152 begin
1153  na :=0;
1154  len:=parse_transform_args(str ,@args ,2 ,@na );
1155 
1156  if na = 1 then
1157   args[1 ]:=args[0 ];
1158 
1159  tas.Construct(args[0 ] ,args[1 ] );
1160 
1161  m_path.transform.premultiply(@tas );
1162 
1163  result:=len;
1164 
1165 end;
1166 
1167 { PARSE_SKEW_X }
parser.parse_skew_xnull1168 function parser.parse_skew_x;
1169 var
1170  arg : double;
1171 
1172  na ,len : unsigned;
1173 
1174  tas : trans_affine_skewing;
1175 
1176 begin
1177  na :=0;
1178  len:=parse_transform_args(str ,@arg ,1 ,@na );
1179 
1180  tas.Construct(deg2rad(arg ) ,0.0 );
1181 
1182  m_path.transform.premultiply(@tas );
1183 
1184  result:=len;
1185 
1186 end;
1187 
1188 { PARSE_SKEW_Y }
parser.parse_skew_ynull1189 function parser.parse_skew_y;
1190 var
1191  arg : double;
1192 
1193  na ,len : unsigned;
1194 
1195  tas : trans_affine_skewing;
1196 
1197 begin
1198  na :=0;
1199  len:=parse_transform_args(str ,@arg ,1 ,@na );
1200 
1201  tas.Construct(0.0 ,deg2rad(arg ) );
1202 
1203  m_path.transform.premultiply(@tas );
1204 
1205  result:=len;
1206 
1207 end;
1208 
1209 { PARSE_ATTR }
parser.parse_attrnull1210 function parser.parse_attr(name ,value : agg_basics.char_ptr ) : boolean;
1211 var
1212  clr : aggclr;
1213 
1214 begin
1215  result:=true;
1216 
1217  if StrComp(PChar(name ) ,'style' ) = 0 then
1218   parse_style(value )
1219  else
1220   if StrComp(PChar(name ) ,'fill' ) = 0 then
1221    if StrComp(PChar(value ) ,'none' ) = 0 then
1222     m_path.fill_none
1223    else
1224     begin
1225      clr:=parse_color(value );
1226 
1227      m_path.fill(@clr );
1228 
1229     end
1230   else
1231    if StrComp(PChar(name ) ,'fill-opacity' ) = 0 then
1232     m_path.fill_opacity(parse_double(value ) )
1233    else
1234     if StrComp(PChar(name ) ,'stroke' ) = 0 then
1235      if StrComp(PChar(value ) ,'none' ) = 0 then
1236       m_path.stroke_none
1237      else
1238       begin
1239        clr:=parse_color(value );
1240 
1241        m_path.stroke(@clr );
1242 
1243       end
1244     else
1245      if StrComp(PChar(name ) ,'stroke-width' ) = 0 then
1246       m_path.stroke_width(parse_double(value ) )
1247      else
1248       if StrComp(PChar(name ) ,'stroke-linecap' ) = 0 then
1249        begin
1250         if StrComp(PChar(value ) ,'butt' ) = 0 then
1251          m_path.line_cap(butt_cap )
1252         else
1253          if StrComp(PChar(value ) ,'round' ) = 0 then
1254           m_path.line_cap(round_cap )
1255          else
1256           if StrComp(PChar(value ) ,'square' ) = 0 then
1257            m_path.line_cap(square_cap );
1258 
1259        end
1260       else
1261        if StrComp(PChar(name ) ,'stroke-linejoin' ) = 0 then
1262         begin
1263          if StrComp(PChar(value ) ,'miter' ) = 0 then
1264           m_path.line_join(miter_join )
1265          else
1266           if StrComp(PChar(value ) ,'round' ) = 0 then
1267            m_path.line_join(round_join )
1268           else
1269            if StrComp(PChar(value ) ,'bevel' ) = 0 then
1270             m_path.line_join(bevel_join );
1271 
1272         end
1273        else
1274         if StrComp(PChar(name ) ,'stroke-miterlimit' ) = 0 then
1275          m_path.miter_limit(parse_double(value ) )
1276         else
1277          if StrComp(PChar(name ) ,'stroke-opacity' ) = 0 then
1278           m_path.stroke_opacity(parse_double(value ) )
1279          else
1280           if StrComp(PChar(name ) ,'transform' ) = 0 then
1281            parse_transform(value )
1282 
1283         //else
1284         // if StrComp(PChar(el ) ,'<OTHER_ATTRIBUTES>' ) = 0 then
1285         //  begin
1286         //  end
1287         // ...
1288 
1289           else
1290            result:=false;
1291 
1292 end;
1293 
1294 { PARSE_NAME_VALUE }
parser.parse_name_valuenull1295 function parser.parse_name_value;
1296 var
1297  str ,val : agg_basics.char_ptr;
1298 
1299 begin
1300  str:=nv_start;
1301 
1302  while (ptrcomp(str ) < ptrcomp(nv_end ) ) and
1303        (str^ <> ':' ) do
1304   inc(ptrcomp(str ) );
1305 
1306  val:=str;
1307 
1308 // Right Trim
1309  while (ptrcomp(str ) > ptrcomp(nv_start ) ) and
1310        ((str^ = ':' ) or
1311         (str^ = ' ' ) ) do
1312   dec(ptrcomp(str ) );
1313 
1314  inc(ptrcomp(str ) );
1315 
1316  copy_name(nv_start ,str );
1317 
1318  while (ptrcomp(val ) < ptrcomp(nv_end ) ) and
1319        ((val^ = ':' ) or
1320         (val^ = ' ' ) ) do
1321   inc(ptrcomp(val ) );
1322 
1323  copy_value(val ,nv_end );
1324 
1325  result:=parse_attr(agg_basics.char_ptr(m_attr_name ) ,agg_basics.char_ptr(m_attr_value ) );
1326 
1327 end;
1328 
1329 { COPY_NAME }
1330 procedure parser.copy_name;
1331 var
1332  len : unsigned;
1333 
1334 begin
1335  len:=ptrcomp(end_ ) - ptrcomp(start );
1336 
1337  if (m_attr_name_len = 0 ) or
1338     (len > m_attr_name_len ) then
1339   begin
1340    agg_freemem(pointer(m_attr_name ) ,m_attr_name_aloc );
1341 
1342    m_attr_name_aloc:=len + 1;
1343 
1344    agg_freemem(pointer(m_attr_name ) ,m_attr_name_aloc );
1345 
1346    m_attr_name_len:=len;
1347 
1348   end;
1349 
1350  if len <> 0 then
1351   move(start^ ,m_attr_name^ ,len );
1352 
1353  char_ptr(ptrcomp(m_attr_name ) + len )^:=#0;
1354 
1355 end;
1356 
1357 { COPY_VALUE }
1358 procedure parser.copy_value;
1359 var
1360  len : unsigned;
1361 
1362 begin
1363  len:=ptrcomp(end_ ) - ptrcomp(start );
1364 
1365  if (m_attr_value_len = 0 ) or
1366     (len > m_attr_value_len ) then
1367   begin
1368    agg_freemem(pointer(m_attr_value ) ,m_attr_value_aloc );
1369 
1370    m_attr_value_aloc:=len + 1;
1371 
1372    agg_getmem(pointer(m_attr_value ) ,m_attr_value_aloc );
1373 
1374    m_attr_value_len:=len;
1375 
1376   end;
1377 
1378  if len <> 0 then
1379   move(start^ ,m_attr_value^ ,len );
1380 
1381  char_ptr(ptrcomp(m_attr_value ) + len )^:=#0;
1382 
1383 end;
1384 
1385 END.
1386 
1387