File Coverage

blib/lib/SVG/Element.pm
Criterion Covered Total %
statement 205 314 65.2
branch 89 148 60.1
condition 15 40 37.5
subroutine 28 41 68.2
pod 1 33 3.0
total 338 576 58.6


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