File Coverage

blib/lib/SVG/Element.pm
Criterion Covered Total %
statement 206 315 65.4
branch 89 148 60.1
condition 13 37 35.1
subroutine 28 41 68.2
pod 1 33 3.0
total 337 574 58.7


line stmt bran cond sub pod time code
1             package SVG::Element;
2              
3 25     25   9890 use strict;
  25         46  
  25         608  
4 25     25   100 use warnings;
  25         40  
  25         841  
5              
6             our $VERSION = '2.87';
7              
8             =pod
9              
10             =encoding UTF-8
11              
12             =head1 NAME
13              
14             SVG::Element - Generate the element bits for SVG.pm
15              
16             =head1 AUTHOR
17              
18             Ronan Oger, cpan@roitsystems.com
19              
20             =head1 SEE ALSO
21              
22             For description of the methods see L.
23              
24             =cut
25              
26 25     25   167 use SVG::XML;
  25         43  
  25         1905  
27 25     25   9777 use SVG::DOM;
  25         55  
  25         1115  
28 25     25   10103 use SVG::Extension;
  25         53  
  25         737  
29 25     25   156 use Scalar::Util qw/weaken/;
  25         37  
  25         90050  
30              
31             our $AUTOLOAD;
32              
33             my @autosubs = qw(
34             animateMotion animateColor animateTransform circle ellipse rect polyline
35             path polygon line title desc defs
36             altGlyph altGlyphDef altGlyphItem clipPath color-profile
37             cursor definition-src font-face-format font-face-name
38             font-face-src font-face-url foreignObject glyph
39             glyphRef hkern marker mask metadata missing-glyph
40             mpath switch symbol textPath tref tspan view vkern marker textbox
41             flowText style script
42             image a g
43             );
44              
45             our %autosubs = map { $_ => 1 } @autosubs;
46              
47             #-------------------------------------------------------------------------------
48              
49             sub new {
50 157     157 0 379 my ( $proto, $name, %attrs ) = @_;
51 157   33     434 my $class = ref($proto) || $proto;
52 157         316 my $self = { -name => $name };
53 157         343 foreach my $key ( keys %attrs ) {
54              
55             #handle escapes for special elements such as anchor
56 743 100       1319 if ( $key =~ /^-/ ) {
57 542 100       703 if ( $key eq '-href' ) {
58 4         5 $self->{'xlink:href'} = $attrs{$key};
59 4 50       7 $self->{'xlink:type'} = $attrs{-type} if $attrs{-type};
60 4 50       13 $self->{'xlink:role'} = $attrs{-role} if $attrs{-role};
61 4 100       7 $self->{'xlink:title'} = $attrs{-title} if $attrs{-title};
62 4 100       7 $self->{'xlink:show'} = $attrs{-show} if $attrs{-show};
63             $self->{'xlink:arcrole'} = $attrs{-arcrole}
64 4 50       6 if $attrs{-arcrole};
65             $self->{'xlink:actuate'} = $attrs{-actuate}
66 4 100       7 if $attrs{-actuate};
67 4         5 next;
68             }
69             }
70 739         968 $self->{$key} = $attrs{$key};
71             }
72              
73 157         406 return bless( $self, $class );
74             }
75              
76             #-------------------------------------------------------------------------------
77              
78             sub release {
79 9     9 0 10 my $self = shift;
80              
81 9         8 foreach my $key ( keys( %{$self} ) ) {
  9         22  
82 84 100       135 next if $key =~ /^-/;
83 5 50       8 if ( ref( $self->{$key} ) =~ /^SVG/ ) {
84 0         0 eval { $self->{$key}->release; };
  0         0  
85             }
86 5         5 delete( $self->{$key} );
87             }
88              
89 9         143 return $self;
90             }
91              
92             sub xmlify {
93 130     130 0 2189 my $self = shift;
94 130   50     527 my $ns = $self->{-namespace} || $self->{-docref}->{-namespace} || undef;
95 130         170 my $xml = '';
96              
97             #prep the attributes
98 130         150 my %attrs;
99 130         140 foreach my $k ( keys( %{$self} ) ) {
  130         474  
100 1707 100       2568 if ( $k =~ /^-/ ) { next; }
  1432         1569  
101 275 50       707 if ( ref( $self->{$k} ) eq 'ARRAY' ) {
    100          
    50          
102 0         0 $attrs{$k} = join( ', ', @{ $self->{$k} } );
  0         0  
103             }
104             elsif ( ref( $self->{$k} ) eq 'HASH' ) {
105 5         16 $attrs{$k} = cssstyle( %{ $self->{$k} } );
  5         22  
106             }
107             elsif ( ref( $self->{$k} ) eq '' ) {
108 270         438 $attrs{$k} = $self->{$k};
109             }
110             }
111              
112             #prep the tag
113 130 100       430 if ( $self->{-comment} ) {
    100          
114 22         81 $xml .= $self->xmlcomment( $self->{-comment} );
115 22         120 return $xml;
116             }
117             elsif ( $self->{-name} eq 'document' ) {
118              
119             #write the xml header
120 23 100       110 $xml .= $self->xmldecl unless $self->{-inline};
121              
122             $xml .= $self->xmlpi( $self->{-document}->{-pi} )
123 23 100       80 if $self->{-document}->{-pi};
124              
125             #and write the dtd if this is inline
126 23 100       112 $xml .= $self->dtddecl unless $self->{-inline};
127              
128             #rest of the xml
129 23         47 foreach my $k ( @{ $self->{-childs} } ) {
  23         72  
130 23 50       109 if ( ref($k) =~ /^SVG::Element/ ) {
131 23         183 $xml .= $k->xmlify($ns);
132             }
133             }
134              
135 23         137 return $xml;
136             }
137             my $is_cdataish
138             = defined $self->{-cdata}
139             || defined $self->{-CDATA}
140 85   100     340 || defined $self->{-cdata_noxmlesc};
141 85 100 100     217 if ( defined $self->{-childs} || $is_cdataish ) {
142             $xml .= $self->{-docref}->{-elsep}
143 49 100 66     185 unless ( $self->{-inline} && $self->{-name} );
144 49         122 $xml .= $self->{-docref}->{-indent} x $self->{-docref}->{-level};
145 49         213 $xml .= xmltagopen_ln( $self->{-name}, $ns, %attrs );
146 49         96 $self->{-docref}->{-level}++;
147 49         67 foreach my $k ( @{ $self->{-childs} } ) {
  49         111  
148 70 50       264 if ( ref($k) =~ /^SVG::Element/ ) {
149 70         285 $xml .= $k->xmlify($ns);
150             }
151             }
152              
153 49 100       123 if ( defined $self->{-cdata} ) {
154 12         34 $xml .= $self->xmlescp( $self->{-cdata} );
155             }
156 49 100       107 if ( defined $self->{-CDATA} ) {
157 3         7 $xml .= '{-CDATA} . ']]>';
158             }
159 49 100       123 if ( defined $self->{-cdata_noxmlesc} ) {
160 1         4 $xml .= $self->{-cdata_noxmlesc};
161             }
162              
163             #return without writing the tag out if it the document tag
164 49         70 $self->{-docref}->{-level}--;
165 49 100       102 unless ($is_cdataish) {
166 33         68 $xml .= $self->{-docref}->{-elsep};
167 33         69 $xml .= $self->{-docref}->{-indent} x $self->{-docref}->{-level};
168             }
169 49         121 $xml .= xmltagclose_ln( $self->{-name}, $ns );
170             }
171             else {
172 36         69 $xml .= $self->{-docref}->{-elsep};
173 36         106 $xml .= $self->{-docref}->{-indent} x $self->{-docref}->{-level};
174 36         115 $xml .= xmltag_ln( $self->{-name}, $ns, %attrs );
175             }
176              
177             #return the finished tag
178 85         359 return $xml;
179             }
180              
181             sub perlify {
182 0     0 0 0 my $self = shift;
183 0         0 my $code = '';
184              
185             #prep the attributes
186 0         0 my %attrs;
187 0         0 foreach my $k ( keys( %{$self} ) ) {
  0         0  
188 0 0       0 next if $k =~ /^-/;
189 0 0       0 if ( ref( $self->{$k} ) eq 'ARRAY' ) {
    0          
    0          
190 0         0 $attrs{$k} = join( ', ', @{ $self->{$k} } );
  0         0  
191             }
192             elsif ( ref( $self->{$k} ) eq 'HASH' ) {
193 0         0 $attrs{$k} = cssstyle( %{ $self->{$k} } );
  0         0  
194             }
195             elsif ( ref( $self->{$k} ) eq '' ) {
196 0         0 $attrs{$k} = $self->{$k};
197             }
198             }
199              
200 0 0       0 if ( $self->{-comment} ) {
    0          
    0          
201 0         0 $code .= "->comment($self->{-comment})";
202 0         0 return $code;
203             }
204             elsif ( $self->{-pi} ) {
205 0         0 $code .= "->pi($self->{-pi})";
206 0         0 return $code;
207             }
208             elsif ( $self->{-name} eq 'document' ) {
209              
210             #write the xml header
211             #$xml .= $self->xmldecl;
212             #and write the dtd if this is inline
213             #$xml .= $self->dtddecl unless $self->{-inline};
214 0         0 foreach my $k ( @{ $self->{-childs} } ) {
  0         0  
215 0 0       0 if ( ref($k) =~ /^SVG::Element/ ) {
216 0         0 $code .= $k->perlify();
217             }
218             }
219 0         0 return $code;
220             }
221              
222 0 0       0 if ( defined $self->{-childs} ) {
223 0         0 $code .= $self->{-docref}->{-elsep};
224 0         0 $code .= $self->{-docref}->{-indent} x $self->{-docref}->{-level};
225             $code
226             .= $self->{-name} . '('
227 0         0 . ( join ', ', ( map {"$_=>'$attrs{$_}'"} sort keys %attrs ) )
  0         0  
228             . ')';
229 0 0       0 if ( $self->{-cdata} ) {
    0          
    0          
230 0         0 $code .= "->cdata($self->{-cdata})";
231             }
232             elsif ( $self->{-CDATA} ) {
233 0         0 $code .= "->CDATA($self->{-CDATA})";
234             }
235             elsif ( $self->{-cdata_noxmlesc} ) {
236 0         0 $code .= "->cdata_noxmlesc($self->{-cdata_noxmlesc})";
237             }
238              
239 0         0 $self->{-docref}->{-level}++;
240 0         0 foreach my $k ( @{ $self->{-childs} } ) {
  0         0  
241 0 0       0 if ( ref($k) =~ /^SVG::Element/ ) {
242 0         0 $code .= $k->perlify();
243             }
244             }
245 0         0 $self->{-docref}->{-level}--;
246             }
247             else {
248 0         0 $code .= $self->{-docref}->{-elsep};
249 0         0 $code .= $self->{-docref}->{-indent} x $self->{-docref}->{-level};
250             $code
251             .= $self->{-name} . '('
252 0         0 . ( join ', ', ( map {"$_=>'$attrs{$_}'"} sort keys %attrs ) )
  0         0  
253             . ')';
254             }
255              
256 0         0 return $code;
257             }
258             *toperl = \&perlify;
259              
260             sub addchilds {
261 122     122 0 174 my $self = shift;
262 122         160 push @{ $self->{-childs} }, @_;
  122         270  
263 122         155 return $self;
264             }
265              
266             sub tag {
267 124     124 0 347 my ( $self, $name, %attrs ) = @_;
268              
269 124 100       265 unless ( $self->{-parent} ) {
270              
271             #traverse down the tree until you find a non-document entry
272 102         291 while ( $self->{-document} ) { $self = $self->{-document} }
  69         140  
273             }
274 124         343 my $tag = new SVG::Element( $name, %attrs );
275              
276             #define the element namespace
277 124 50       254 $tag->{-namespace} = $attrs{-namespace} if ( $attrs{-namespace} );
278              
279             #add the tag to the document element
280 124         257 $tag->{-docref} = $self->{-docref};
281 124         311 weaken( $tag->{-docref} );
282              
283             #create the empty idlist hash ref unless it already exists
284             $tag->{-docref}->{-idlist} = {}
285 124 100       268 unless ( defined $tag->{-docref}->{-idlist} );
286              
287             #verify that the current id is unique. compain on exception
288             #>>>TBD: add -strictids option to disable this check if desired
289 124 100       213 if ( $tag->{id} ) {
290 13 100       49 if ( $self->getElementByID( $tag->{id} ) ) {
291 2         5 $self->error( $tag->{id} => 'ID already exists in document' );
292 1         3 return;
293             }
294             }
295              
296             #add the current id reference to the document id hash
297 122 100       211 if ( defined( $tag->{id} ) ) {
298 11         23 $tag->{-docref}->{-idlist}->{ $tag->{id} } = $tag;
299             }
300              
301             #create the empty idlist hash ref unless it already exists
302             $tag->{-docref}->{-elist} = {}
303 122 100       316 unless ( defined $tag->{-docref}->{-elist} );
304              
305             #create the empty idlist hash ref unless it already exists
306             $tag->{-docref}->{-elist}->{ $tag->{-name} } = []
307 122 100       334 unless ( defined $tag->{-docref}->{-elist}->{ $tag->{-name} } );
308              
309             #add the current element ref to the corresponding element-hash array
310             # -elist is a hash of element names. key name is element, content is object ref.
311              
312             # add the reference to $tag to the array of refs that belong to the
313             # key $tag->{-name}.
314 122         168 unshift @{ $tag->{-docref}->{-elist}->{ $tag->{-name} } }, $tag;
  122         286  
315              
316             # attach element to the DOM of the document
317 122         236 $tag->{-parent} = $self;
318 122         286 weaken( $tag->{-parent} );
319 122         189 $tag->{-parentname} = $self->{-name};
320 122         351 $self->addchilds($tag);
321              
322 122         325 return ($tag);
323             }
324              
325             *element = \&tag;
326              
327             sub anchor {
328 3     3 0 17 my ( $self, %attrs ) = @_;
329 3         6 my $an = $self->tag( 'a', %attrs );
330              
331             #$an->{'xlink:href'}=$attrs{-href} if(defined $attrs{-href});
332             #$an->{'target'}=$attrs{-target} if(defined $attrs{-target});
333 3         6 return ($an);
334             }
335              
336             sub svg {
337 33     33 0 201 my ( $self, %attrs ) = @_;
338 33         202 my $svg = $self->tag( 'svg', %attrs );
339 33 100       130 $svg->{'height'} = '100%' unless ( $svg->{'height'} );
340 33 100       124 $svg->{'width'} = '100%' unless ( $svg->{'width'} );
341 33         122 return ($svg);
342             }
343              
344             sub rectangle {
345 1     1 0 10 my ( $self, %attrs ) = @_;
346 1         3 return $self->tag( 'rect', %attrs );
347             }
348              
349             #sub image {
350             # my ($self,%attrs)=@_;
351             # my $im=$self->tag('image',%attrs);
352             # #$im->{'xlink:href'}=$attrs{-href} if(defined $attrs{-href});
353             # return $im;
354             #}
355              
356             sub use {
357 0     0 0 0 my ( $self, %attrs ) = @_;
358 0         0 my $u = $self->tag( 'use', %attrs );
359 0 0       0 $u->{'xlink:href'} = $attrs{-href} if ( defined $attrs{-href} );
360 0         0 return $u;
361             }
362              
363             sub text {
364 20     20 0 571 my ( $self, %attrs ) = @_;
365 20         55 my $pre = '';
366 20   50     90 $pre = $attrs{-type} || 'std';
367 20         67 my %get_pre = (
368             std => 'text',
369             path => 'textPath',
370             span => 'tspan',
371             );
372              
373 20         54 $pre = $get_pre{ lc($pre) };
374 20         50 my $text = $self->tag( $pre, %attrs );
375 20 50       50 $text->{'xlink:href'} = $attrs{-href} if ( defined $attrs{-href} );
376 20 50       46 $text->{'target'} = $attrs{-target} if ( defined $attrs{-target} );
377 20         126 return ($text);
378             }
379              
380             sub comment {
381 19     19 0 69 my ( $self, @text ) = @_;
382 19         51 my $tag = $self->tag('comment');
383 19         47 $tag->{-comment} = [@text];
384 19         44 return $tag;
385             }
386              
387             sub pi {
388 4     4 0 2134 my ( $self, @text ) = @_;
389 4 100       23 return $self->{-document}->{-pi} unless scalar @text;
390 2         3 my @pi;
391 2 100       5 @pi = @{ $self->{-document}->{-pi} } if $self->{-document}->{-pi};
  1         3  
392 2 100       4 unshift( @text, @pi ) if @pi;
393 2         4 $self->{-document}->{-pi} = \@text;
394 2         4 my $tag = $self->tag('pi');
395 2         4 return $tag;
396             }
397              
398             =pod
399              
400             =head2 get_path
401              
402             Documented as L.
403              
404             =cut
405              
406             sub get_path {
407 1     1 1 438 my ( $self, %attrs ) = @_;
408              
409 1   50     3 my $type = $attrs{-type} || 'path';
410 1         2 my @x = @{ $attrs{x} };
  1         2  
411 1         2 my @y = @{ $attrs{y} };
  1         2  
412 1         1 my $points;
413              
414             # we need a path-like point string returned
415 1 50       9 if ( lc($type) eq 'path' ) {
    50          
416 0         0 my $char = 'M';
417             $char = ' m '
418 0 0 0     0 if ( defined $attrs{-relative} && lc( $attrs{-relative} ) );
419 0         0 while (@x) {
420              
421             #scale each value
422 0         0 my $x = shift @x;
423 0         0 my $y = shift @y;
424              
425             #append the scaled value to the graph
426 0         0 $points .= "$char $x $y ";
427 0         0 $char = ' L ';
428             $char = ' l '
429             if ( defined $attrs{-relative}
430 0 0 0     0 && lc( $attrs{-relative} ) );
431             }
432             $points .= ' z '
433 0 0 0     0 if ( defined $attrs{-closed} && lc( $attrs{-closed} ) );
434 0         0 my %out = ( d => $points );
435 0         0 return \%out;
436             }
437             elsif ( lc($type) =~ /^poly/ ) {
438 1         3 while (@x) {
439              
440             #scale each value
441 5         6 my $x = shift @x;
442 5         5 my $y = shift @y;
443              
444             #append the scaled value to the graph
445 5         12 $points .= "$x,$y ";
446             }
447             }
448 1         11 my %out = ( points => $points );
449 1         5 return \%out;
450             }
451              
452             sub make_path {
453 0     0 0 0 my ( $self, %attrs ) = @_;
454 0         0 return get_path(%attrs);
455             }
456              
457             sub set_path {
458 0     0 0 0 my ( $self, %attrs ) = @_;
459 0         0 return get_path(%attrs);
460             }
461              
462             sub animate {
463 0     0 0 0 my ( $self, %attrs ) = @_;
464 0         0 my %rtr = %attrs;
465 0         0 my $method = $rtr{'-method'}; # Set | Transform | Motion | Color
466              
467 0         0 $method = lc($method);
468              
469             # we do not want this to pollute the generation of the tag
470 0         0 delete $rtr{-method}; #bug report from briac.
471              
472 0         0 my %animation_method = (
473             transform => 'animateTransform',
474             motion => 'animateMotion',
475             color => 'animateColor',
476             set => 'set',
477             attribute => 'animate',
478             );
479              
480 0   0     0 my $name = $animation_method{$method} || 'animate';
481              
482             #list of legal entities for each of the 5 methods of animations
483 0         0 my %legal = (
484             animate => q{ begin dur end min max restart repeatCount
485             repeatDur fill attributeType attributeName additive
486             accumulate calcMode values keyTimes keySplines
487             from to by },
488             animateTransform => q{ begin dur end min max restart repeatCount
489             repeatDur fill additive accumulate calcMode values
490             keyTimes keySplines from to by calcMode path keyPoints
491             rotate origin type attributeName attributeType },
492             animateMotion => q{ begin dur end min max restart repeatCount
493             repeatDur fill additive accumulate calcMode values
494             to by keyTimes keySplines from path keyPoints
495             rotate origin },
496             animateColor => q{ begin dur end min max restart repeatCount
497             repeatDur fill additive accumulate calcMode values
498             keyTimes keySplines from to by },
499             set => q{ begin dur end min max restart repeatCount repeatDur
500             fill to },
501             );
502              
503 0         0 foreach my $k ( keys %rtr ) {
504 0 0       0 next if ( $k =~ /\-/ );
505              
506 0 0       0 if ( $legal{$name} !~ /\b$k\b/ ) {
507 0         0 $self->error( "$name.$k" => 'Illegal animation command' );
508             }
509             }
510              
511 0         0 return $self->tag( $name, %rtr );
512             }
513              
514             sub group {
515 12     12 0 89 my ( $self, %attrs ) = @_;
516 12         37 return $self->tag( 'g', %attrs );
517             }
518              
519             sub STYLE {
520 0     0 0 0 my ( $self, %attrs ) = @_;
521              
522 0   0     0 $self->{style} = $self->{style} || {};
523 0         0 foreach my $k ( keys %attrs ) {
524 0         0 $self->{style}->{$k} = $attrs{$k};
525             }
526              
527 0         0 return $self;
528             }
529              
530             sub mouseaction {
531 0     0 0 0 my ( $self, %attrs ) = @_;
532              
533 0   0     0 $self->{mouseaction} = $self->{mouseaction} || {};
534 0         0 foreach my $k ( keys %attrs ) {
535 0         0 $self->{mouseaction}->{$k} = $attrs{$k};
536             }
537              
538 0         0 return $self;
539             }
540              
541             sub attrib {
542 3     3 0 1068 my ( $self, $name, $val ) = @_;
543              
544             #verify that the current id is unique. compain on exception
545 3 50       7 if ( $name eq 'id' ) {
546 0 0       0 if ( $self->getElementByID($val) ) {
547 0         0 $self->error( $val => 'ID already exists in document' );
548 0         0 return;
549             }
550             }
551              
552 3 100       8 if ( not defined $val ) {
553 2 50       4 if ( scalar(@_) == 2 ) {
554              
555             # two arguments only - retrieve
556 2         8 return $self->{$name};
557             }
558             else {
559              
560             # 3rd argument is undef - delete
561 0         0 delete $self->{$name};
562             }
563             }
564             else {
565              
566             # 3 defined arguments - set
567 1         3 $self->{$name} = $val;
568             }
569              
570 1         2 return $self;
571             }
572             *attr = \&attrib;
573             *attribute = \&attrib;
574              
575             sub cdata {
576 19     19 0 48 my ( $self, @txt ) = @_;
577 19         54 $self->{-cdata} = join( ' ', @txt );
578 19         53 return ($self);
579             }
580              
581             sub CDATA {
582 2     2 0 10 my ( $self, @txt ) = @_;
583 2         16 $self->{-CDATA} = join( '\n', @txt );
584 2         6 return ($self);
585             }
586              
587             sub cdata_noxmlesc {
588 1     1 0 3 my ( $self, @txt ) = @_;
589 1         3 $self->{-cdata_noxmlesc} = join( '\n', @txt );
590 1         17 return ($self);
591             }
592              
593             sub filter {
594 0     0 0 0 my ( $self, %attrs ) = @_;
595 0         0 return $self->tag( 'filter', %attrs );
596             }
597              
598             sub fe {
599 1     1 0 10 my ( $self, %attrs ) = @_;
600              
601 1 50       3 return 0 unless ( $attrs{'-type'} );
602 1         23 my %allowed = (
603             blend => 'feBlend',
604             colormatrix => 'feColorMatrix',
605             componenttrans => 'feComponentTrans',
606             Componenttrans => 'feComponentTrans',
607             composite => 'feComposite',
608             convolvematrix => 'feConvolveMatrix',
609             diffuselighting => 'feDiffuseLighting',
610             displacementmap => 'feDisplacementMap',
611             distantlight => 'feDistantLight',
612             flood => 'feFlood',
613             funca => 'feFuncA',
614             funcb => 'feFuncB',
615             funcg => 'feFuncG',
616             funcr => 'feFuncR',
617             gaussianblur => 'feGaussianBlur',
618             image => 'feImage',
619             merge => 'feMerge',
620             mergenode => 'feMergeNode',
621             morphology => 'feMorphology',
622             offset => 'feOffset',
623             pointlight => 'fePointLight',
624             specularlighting => 'feSpecularLighting',
625             spotlight => 'feSpotLight',
626             tile => 'feTile',
627             turbulence => 'feTurbulence',
628             );
629              
630 1         4 my $key = lc( $attrs{'-type'} );
631 1   50     3 my $fe_name = $allowed{ lc($key) } || 'error:illegal_filter_element';
632 1         3 delete $attrs{'-type'};
633              
634 1         4 return $self->tag( $fe_name, %attrs );
635             }
636              
637             sub pattern {
638 0     0 0 0 my ( $self, %attrs ) = @_;
639 0         0 return $self->tag( 'pattern', %attrs );
640             }
641              
642             sub set {
643 0     0 0 0 my ( $self, %attrs ) = @_;
644 0         0 return $self->tag( 'set', %attrs );
645             }
646              
647             sub stop {
648 0     0 0 0 my ( $self, %attrs ) = @_;
649 0         0 return $self->tag( 'stop', %attrs );
650             }
651              
652             sub gradient {
653 0     0 0 0 my ( $self, %attrs ) = @_;
654              
655 0   0     0 my $type = $attrs{'-type'} || 'linear';
656 0 0       0 unless ( $type =~ /^(linear|radial)$/ ) {
657 0         0 $type = 'linear';
658             }
659 0         0 delete $attrs{'-type'};
660              
661 0         0 return $self->tag( $type . 'Gradient', %attrs );
662             }
663              
664             #-------------------------------------------------------------------------------
665             # Internal methods
666              
667             sub error {
668 12     12 0 17 my ( $self, $command, $error ) = @_;
669              
670 12 100       28 if ( $self->{-docref}->{-raiseerror} ) {
    50          
671 1         12 die "$command: $error\n";
672             }
673             elsif ( $self->{-docref}->{-printerror} ) {
674 0         0 print STDERR "$command: $error\n";
675             }
676              
677 11         36 $self->{errors}{$command} = $error;
678             }
679              
680             # This AUTOLOAD method is activated when '-auto' is passed to SVG.pm
681             sub autoload {
682 1298     1298 0 2239 my $self = shift;
683 1298         4479 my ( $package, $sub ) = ( $AUTOLOAD =~ /(.*)::([^:]+)$/ );
684              
685 1298 100       2203 if ( $sub eq 'DESTROY' ) {
686 9         14 return $self->release();
687             }
688             else {
689              
690             # the import routine may call us with a tag name involving '-'s
691 1289         1445 my $tag = $sub;
692 1289         1587 $sub =~ tr/-/_/;
693              
694             # N.B.: The \ on \@_ makes sure that the incoming arguments are
695             # used and not the ones passed when the subroutine was created.
696             # eval "sub $package\:\:$sub (\$;\@) { return shift->tag('$tag',\@_) }";
697             #per rt.perl.org comment by slaven.
698              
699 1289 100       5142 if ( !$package->can($sub) ) {
700             ## no critic (TestingAndDebugging::ProhibitNoStrict)
701 25     25   267 no strict 'refs';
  25         55  
  25         4811  
702 1142         3079 *{ $package . '::' . $sub }
703 1142     33   3359 = sub { return shift->tag( $tag, @_ ) };
  33         1341  
704             }
705 1289 100       2984 return $self->$sub(@_) if $self;
706             }
707             }
708              
709             #-------------------------------------------------------------------------------
710             # GD Routines
711              
712             sub colorAllocate {
713 0     0 0   my ( $self, $red, $green, $blue ) = @_;
714 0           return 'rgb(' . int($red) . ',' . int($green) . ',' . int($blue) . ')';
715             }
716              
717             #-------------------------------------------------------------------------------
718              
719             1;