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