| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#! perl |
|
2
|
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
13
|
use v5.26; |
|
|
1
|
|
|
|
|
5
|
|
|
4
|
1
|
|
|
1
|
|
6
|
use Object::Pad; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
7
|
|
|
5
|
1
|
|
|
1
|
|
98
|
use utf8; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
6
|
|
|
6
|
|
|
|
|
|
|
class SVGPDF::Element; |
|
7
|
|
|
|
|
|
|
|
|
8
|
1
|
|
|
1
|
|
228
|
use Carp; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
9168
|
|
|
9
|
|
|
|
|
|
|
|
|
10
|
0
|
|
|
0
|
0
|
|
field $xo :mutator; |
|
|
0
|
|
|
|
|
|
|
|
11
|
0
|
0
|
|
0
|
0
|
|
field $style :accessor; |
|
|
0
|
|
|
|
|
|
|
|
12
|
0
|
0
|
|
0
|
0
|
|
field $name :param :accessor; |
|
|
0
|
|
|
|
|
|
|
|
13
|
0
|
0
|
|
0
|
0
|
|
field $atts :param :accessor; |
|
|
0
|
|
|
|
|
|
|
|
14
|
0
|
0
|
|
0
|
0
|
|
field $css :accessor; |
|
|
0
|
|
|
|
|
|
|
|
15
|
0
|
0
|
|
0
|
0
|
|
field $content :param :accessor; # array of children |
|
|
0
|
|
|
|
|
|
|
|
16
|
0
|
0
|
|
0
|
0
|
|
field $root :param :accessor; # top module |
|
|
0
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
BUILD { |
|
19
|
|
|
|
|
|
|
$css = $root->css; |
|
20
|
|
|
|
|
|
|
$xo = $root->xoforms->[-1]->{xo}; |
|
21
|
|
|
|
|
|
|
}; |
|
22
|
|
|
|
|
|
|
|
|
23
|
0
|
|
|
0
|
|
|
method _dbg (@args) { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
24
|
0
|
|
|
|
|
|
$root->_dbg(@args); |
|
25
|
|
|
|
|
|
|
} |
|
26
|
|
|
|
|
|
|
|
|
27
|
0
|
|
|
0
|
0
|
|
method css_push ( $updated_atts = undef ) { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
28
|
0
|
|
0
|
|
|
|
$style = $css->push( element => $name, %{$updated_atts // $atts} ); |
|
|
0
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
} |
|
30
|
|
|
|
|
|
|
|
|
31
|
0
|
|
|
0
|
0
|
|
method css_pop () { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
32
|
0
|
|
|
|
|
|
$css->pop; |
|
33
|
|
|
|
|
|
|
} |
|
34
|
|
|
|
|
|
|
|
|
35
|
0
|
|
|
0
|
0
|
|
method set_transform ( $tf ) { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
36
|
0
|
0
|
|
|
|
|
return unless $tf; |
|
37
|
|
|
|
|
|
|
|
|
38
|
0
|
|
|
|
|
|
my $nooptimize = 1; |
|
39
|
0
|
|
|
|
|
|
$tf =~ s/\s+/ /g; |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
# The parts of the transform need to be executed in order. |
|
42
|
0
|
|
|
|
|
|
while ( $tf =~ /\S/ ) { |
|
43
|
0
|
0
|
|
|
|
|
if ( $tf =~ /^\s*translate\s*\((.*?)\)(.*)/ ) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
44
|
0
|
|
|
|
|
|
$tf = $2; |
|
45
|
0
|
|
|
|
|
|
my ( $x, $y ) = $self->getargs($1); |
|
46
|
0
|
|
0
|
|
|
|
$y ||= 0; |
|
47
|
0
|
0
|
0
|
|
|
|
if ( $nooptimize || $x || $y ) { |
|
|
|
|
0
|
|
|
|
|
|
48
|
0
|
|
|
|
|
|
$xo->transform( translate => [ $x, $y ] ); |
|
49
|
0
|
|
|
|
|
|
$self->_dbg( "transform translate(%.2f,%.2f)", $x, $y ); |
|
50
|
|
|
|
|
|
|
} |
|
51
|
|
|
|
|
|
|
} |
|
52
|
|
|
|
|
|
|
elsif ( $tf =~ /^\s*rotate\s*\((.*?)\)(.*)/ ) { |
|
53
|
0
|
|
|
|
|
|
$tf = $2; |
|
54
|
0
|
|
|
|
|
|
my ( $r, $x, $y ) = $self->getargs($1); |
|
55
|
0
|
0
|
0
|
|
|
|
if ( $nooptimize || $r ) { |
|
56
|
0
|
0
|
0
|
|
|
|
if ( $x || $y ) { |
|
57
|
0
|
|
|
|
|
|
$xo->transform( translate => [ $x, $y ] ); |
|
58
|
0
|
|
|
|
|
|
$self->_dbg( "transform translate(%.2f,%.2f)", $x, $y ); |
|
59
|
|
|
|
|
|
|
} |
|
60
|
0
|
|
|
|
|
|
$self->_dbg( "transform rotate(%.2f)", $r ); |
|
61
|
0
|
|
|
|
|
|
$xo->transform( rotate => $r ); |
|
62
|
0
|
0
|
0
|
|
|
|
if ( $x || $y ) { |
|
63
|
0
|
|
|
|
|
|
$xo->transform( translate => [ -$x, -$y ] ); |
|
64
|
0
|
|
|
|
|
|
$self->_dbg( "transform translate(%.2f,%.2f)", -$x, -$y ); |
|
65
|
|
|
|
|
|
|
} |
|
66
|
|
|
|
|
|
|
} |
|
67
|
|
|
|
|
|
|
} |
|
68
|
|
|
|
|
|
|
elsif ( $tf =~ /^\s*scale\s*\((.*?)\)(.*)/ ) { |
|
69
|
0
|
|
|
|
|
|
$tf = $2; |
|
70
|
0
|
|
|
|
|
|
my ( $x, $y ) = $self->getargs($1); |
|
71
|
0
|
|
0
|
|
|
|
$y ||= $x; |
|
72
|
0
|
0
|
0
|
|
|
|
if ( $nooptimize || $x != 1 && $y != 1 ) { |
|
|
|
|
0
|
|
|
|
|
|
73
|
0
|
|
|
|
|
|
$self->_dbg( "transform scale(%.2f,%.2f)", $x, $y ); |
|
74
|
0
|
|
|
|
|
|
$xo->transform( scale => [ $x, $y ] ); |
|
75
|
|
|
|
|
|
|
} |
|
76
|
|
|
|
|
|
|
} |
|
77
|
|
|
|
|
|
|
elsif ( $tf =~ /^\s*matrix\s*\((.*?)\)(.*)/ ) { |
|
78
|
0
|
|
|
|
|
|
$tf = $2; |
|
79
|
0
|
|
|
|
|
|
my ( @m ) = $self->getargs($1); |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
# 1 0 0 1 dx dy translate |
|
82
|
|
|
|
|
|
|
# sx 0 0 sy 0 0 scale |
|
83
|
|
|
|
|
|
|
# c s -s c 0 0 rotate (s = sin, c = cos) |
|
84
|
|
|
|
|
|
|
# 1 a b 1 0 0 skew (a = tan a, b = tan b) |
|
85
|
|
|
|
|
|
|
|
|
86
|
0
|
|
|
|
|
|
$self->_dbg( "transform matrix(%.2f,%.2f %.2f,%.2f %.2f,%.2f)", @m); |
|
87
|
0
|
|
|
|
|
|
$xo->matrix(@m); |
|
88
|
|
|
|
|
|
|
} |
|
89
|
|
|
|
|
|
|
elsif ( $tf =~ /^\s*skew([XY])\s*\((.*?)\)(.*)/i ) { |
|
90
|
0
|
|
|
|
|
|
$tf = $3; |
|
91
|
0
|
|
|
|
|
|
my ( $x ) = $self->getargs($2); |
|
92
|
0
|
|
|
|
|
|
my $y = 0; |
|
93
|
0
|
0
|
|
|
|
|
if ( $1 eq "X" ) { |
|
94
|
0
|
|
|
|
|
|
$y = $x; |
|
95
|
0
|
|
|
|
|
|
$x = 0; |
|
96
|
|
|
|
|
|
|
} |
|
97
|
0
|
|
|
|
|
|
$self->_dbg( "transform skew(%.2f %.2f)", $x, $y ); |
|
98
|
0
|
|
|
|
|
|
$xo->transform( skew => [ $x, $y ] ); |
|
99
|
|
|
|
|
|
|
} |
|
100
|
|
|
|
|
|
|
else { |
|
101
|
0
|
0
|
|
|
|
|
warn("Ignoring transform: $tf") |
|
102
|
|
|
|
|
|
|
if $self->root->verbose; |
|
103
|
0
|
|
|
|
|
|
$self->_dbg("Ignoring transform: \"$tf\""); |
|
104
|
0
|
|
|
|
|
|
$tf = ""; |
|
105
|
|
|
|
|
|
|
} |
|
106
|
|
|
|
|
|
|
# %rel = ( relative => 1 ); |
|
107
|
|
|
|
|
|
|
} |
|
108
|
|
|
|
|
|
|
} |
|
109
|
|
|
|
|
|
|
|
|
110
|
0
|
|
|
0
|
0
|
|
method set_graphics () { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
|
|
112
|
0
|
|
|
|
|
|
my $msg = $name; |
|
113
|
|
|
|
|
|
|
|
|
114
|
0
|
0
|
|
|
|
|
if ( defined( my $lw = $style->{'stroke-width'} ) ) { |
|
115
|
|
|
|
|
|
|
my $w = $self->u( $lw, |
|
116
|
|
|
|
|
|
|
fontsize => $style->{'font-size'}, |
|
117
|
0
|
|
|
|
|
|
width => $self->root->xoforms->[-1]->{diag}); |
|
118
|
0
|
|
|
|
|
|
$msg .= " stroke-width=$w"; |
|
119
|
0
|
0
|
|
|
|
|
if ( $lw =~ /e[mx]/ ) { |
|
120
|
|
|
|
|
|
|
$msg .= "($lw@" . |
|
121
|
0
|
|
0
|
|
|
|
( $style->{'font-size'}|| $self->root->fontsize) . ")"; |
|
122
|
|
|
|
|
|
|
} |
|
123
|
0
|
0
|
|
|
|
|
if ( $lw =~ /\%/ ) { |
|
124
|
|
|
|
|
|
|
$msg .= "($lw@" . |
|
125
|
0
|
|
|
|
|
|
( $self->root->xoforms->[-1]->{diag}) . ")"; |
|
126
|
|
|
|
|
|
|
} |
|
127
|
0
|
|
|
|
|
|
$xo->line_width($w); |
|
128
|
|
|
|
|
|
|
} |
|
129
|
|
|
|
|
|
|
|
|
130
|
0
|
0
|
|
|
|
|
if ( defined( my $linecap = $style->{'stroke-linecap'} ) ) { |
|
131
|
0
|
|
|
|
|
|
$linecap = lc($linecap); |
|
132
|
0
|
0
|
|
|
|
|
if ( $linecap eq "round" ) { $linecap = 1 } |
|
|
0
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
133
|
0
|
|
|
|
|
|
elsif ( $linecap eq "r" ) { $linecap = 1 } |
|
134
|
0
|
|
|
|
|
|
elsif ( $linecap eq "square" ) { $linecap = 2 } |
|
135
|
0
|
|
|
|
|
|
elsif ( $linecap eq "s" ) { $linecap = 2 } |
|
136
|
0
|
|
|
|
|
|
else { $linecap = 0 } # b butt |
|
137
|
0
|
|
|
|
|
|
$msg .= " linecap=$linecap"; |
|
138
|
0
|
|
|
|
|
|
$xo->line_cap($linecap); |
|
139
|
|
|
|
|
|
|
} |
|
140
|
|
|
|
|
|
|
|
|
141
|
0
|
0
|
|
|
|
|
if ( defined( my $linejoin = $style->{'stroke-linejoin'} ) ) { |
|
142
|
0
|
|
|
|
|
|
$linejoin = lc($linejoin); |
|
143
|
0
|
0
|
|
|
|
|
if ( $linejoin eq "round" ) { $linejoin = 1 } |
|
|
0
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
144
|
0
|
|
|
|
|
|
elsif ( $linejoin eq "r" ) { $linejoin = 1 } |
|
145
|
0
|
|
|
|
|
|
elsif ( $linejoin eq "bevel" ) { $linejoin = 2 } |
|
146
|
0
|
|
|
|
|
|
elsif ( $linejoin eq "b" ) { $linejoin = 2 } |
|
147
|
0
|
|
|
|
|
|
else { $linejoin = 0 } # m miter |
|
148
|
0
|
|
|
|
|
|
$msg .= " linejoin=$linejoin"; |
|
149
|
0
|
|
|
|
|
|
$xo->line_join($linejoin); |
|
150
|
|
|
|
|
|
|
} |
|
151
|
|
|
|
|
|
|
|
|
152
|
0
|
|
|
|
|
|
my $color = $style->{color}; |
|
153
|
0
|
|
|
|
|
|
my $stroke = $style->{stroke}; |
|
154
|
0
|
0
|
|
|
|
|
if ( lc($stroke) eq "currentcolor" ) { |
|
155
|
|
|
|
|
|
|
# Nothing. Use current. |
|
156
|
0
|
|
|
|
|
|
$msg .= " stroke=(current)"; |
|
157
|
0
|
|
|
|
|
|
$stroke = $color; |
|
158
|
|
|
|
|
|
|
} |
|
159
|
0
|
0
|
|
|
|
|
if ( $stroke ne "none" ) { |
|
160
|
0
|
|
|
|
|
|
$stroke =~ s/\s+//g; |
|
161
|
0
|
0
|
|
|
|
|
if ( $stroke =~ /rgb\(([\d.]+)%,([\d.]+)%,([\d.]+)%\)/ ) { |
|
|
|
0
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
$stroke = sprintf("#%02X%02X%02X", |
|
163
|
0
|
|
|
|
|
|
map { $_*2.55 } $1, $2, $3); |
|
|
0
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
} |
|
165
|
|
|
|
|
|
|
elsif ( $stroke =~ /rgb\(([\d.]+),([\d.]+),([\d.]+)\)/ ) { |
|
166
|
0
|
|
|
|
|
|
$stroke = sprintf("#%02X%02X%02X", $1, $2, $3); |
|
167
|
|
|
|
|
|
|
} |
|
168
|
0
|
|
|
|
|
|
$xo->stroke_color($stroke); |
|
169
|
0
|
|
|
|
|
|
$msg .= " stroke=$stroke"; |
|
170
|
|
|
|
|
|
|
} |
|
171
|
|
|
|
|
|
|
else { |
|
172
|
0
|
|
|
|
|
|
$msg .= " stroke=none"; |
|
173
|
|
|
|
|
|
|
} |
|
174
|
|
|
|
|
|
|
|
|
175
|
0
|
|
|
|
|
|
my $fill = $style->{fill}; |
|
176
|
0
|
0
|
|
|
|
|
if ( lc($fill) eq "currentcolor" ) { |
|
177
|
|
|
|
|
|
|
# Nothing. Use current. |
|
178
|
0
|
|
|
|
|
|
$msg .= " fill=(current)"; |
|
179
|
0
|
|
|
|
|
|
$fill = $color; |
|
180
|
|
|
|
|
|
|
} |
|
181
|
0
|
0
|
0
|
|
|
|
if ( lc($fill) ne "none" && $fill ne "transparent" ) { |
|
182
|
0
|
|
|
|
|
|
$fill =~ s/\s+//g; |
|
183
|
0
|
0
|
|
|
|
|
if ( $fill =~ /rgb\(([\d.]+)%,([\d.]+)%,([\d.]+)%\)/ ) { |
|
|
|
0
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
$fill = sprintf("#%02X%02X%02X", |
|
185
|
0
|
|
|
|
|
|
map { $_*2.55 } $1, $2, $3); |
|
|
0
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
} |
|
187
|
|
|
|
|
|
|
elsif ( $fill =~ /rgb\(([\d.]+),([\d.]+),([\d.]+)\)/ ) { |
|
188
|
0
|
|
|
|
|
|
$fill = sprintf("#%02X%02X%02X", $1, $2, $3); |
|
189
|
|
|
|
|
|
|
} |
|
190
|
0
|
|
|
|
|
|
$xo->fill_color($fill); |
|
191
|
0
|
|
|
|
|
|
$msg .= " fill=$fill"; |
|
192
|
|
|
|
|
|
|
} |
|
193
|
|
|
|
|
|
|
else { |
|
194
|
0
|
|
|
|
|
|
$msg .= " fill=none"; |
|
195
|
|
|
|
|
|
|
} |
|
196
|
|
|
|
|
|
|
|
|
197
|
0
|
0
|
|
|
|
|
if ( my $sda = $style->{'stroke-dasharray'} ) { |
|
198
|
0
|
|
|
|
|
|
my @sda; |
|
199
|
0
|
0
|
0
|
|
|
|
if ( $sda && $sda ne "none" ) { |
|
200
|
0
|
|
|
|
|
|
$sda =~ s/,/ /g; |
|
201
|
0
|
|
|
|
|
|
@sda = split( ' ', $sda ); |
|
202
|
|
|
|
|
|
|
} |
|
203
|
0
|
|
|
|
|
|
$msg .= " sda=@sda"; |
|
204
|
0
|
|
|
|
|
|
$xo->line_dash_pattern(@sda); |
|
205
|
|
|
|
|
|
|
} |
|
206
|
|
|
|
|
|
|
|
|
207
|
0
|
|
|
|
|
|
$self->_dbg( "%s", $msg ); |
|
208
|
0
|
|
|
|
|
|
return $style; |
|
209
|
|
|
|
|
|
|
} |
|
210
|
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
# Return a stroke/fill/paint sub depending on the fill stroke styles. |
|
212
|
0
|
|
|
0
|
|
|
method _paintsub () { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
213
|
0
|
0
|
0
|
|
|
|
if ( $style->{stroke} |
|
|
|
0
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
214
|
|
|
|
|
|
|
&& $style->{stroke} ne 'none' |
|
215
|
|
|
|
|
|
|
&& $style->{stroke} ne 'transparent' |
|
216
|
|
|
|
|
|
|
# Hmm. Saw a note somewhere that it defaults to 0 but other notes |
|
217
|
|
|
|
|
|
|
# say that it should be 1px... |
|
218
|
|
|
|
|
|
|
&& $style->{'stroke-width'}//1 != 0 |
|
219
|
|
|
|
|
|
|
) { |
|
220
|
0
|
0
|
0
|
|
|
|
if ( $style->{fill} |
|
|
|
|
0
|
|
|
|
|
|
221
|
|
|
|
|
|
|
&& $style->{fill} ne 'none' |
|
222
|
|
|
|
|
|
|
&& $style->{fill} ne 'transparent' |
|
223
|
|
|
|
|
|
|
) { |
|
224
|
|
|
|
|
|
|
return sub { |
|
225
|
|
|
|
|
|
|
$self->_dbg("xo paint (", |
|
226
|
0
|
|
|
0
|
|
|
join(" ", $style->{stroke}, $style->{fill} ), ")"); |
|
227
|
0
|
|
|
|
|
|
$xo->paint; |
|
228
|
0
|
|
|
|
|
|
}; |
|
229
|
|
|
|
|
|
|
} |
|
230
|
|
|
|
|
|
|
else { |
|
231
|
|
|
|
|
|
|
return sub { |
|
232
|
0
|
|
|
0
|
|
|
$self->_dbg("xo stroke (", $style->{stroke}, ")"); |
|
233
|
0
|
|
|
|
|
|
$xo->stroke; |
|
234
|
0
|
|
|
|
|
|
}; |
|
235
|
|
|
|
|
|
|
} |
|
236
|
|
|
|
|
|
|
} |
|
237
|
|
|
|
|
|
|
elsif ( $style->{fill} |
|
238
|
|
|
|
|
|
|
&& $style->{fill} ne 'none' |
|
239
|
|
|
|
|
|
|
&& $style->{fill} ne 'transparent' |
|
240
|
|
|
|
|
|
|
) { |
|
241
|
|
|
|
|
|
|
return sub { |
|
242
|
0
|
|
|
0
|
|
|
$self->_dbg("xo fill (", $style->{stroke}, ")"); |
|
243
|
0
|
|
|
|
|
|
$xo->fill; |
|
244
|
0
|
|
|
|
|
|
}; |
|
245
|
|
|
|
|
|
|
} |
|
246
|
|
|
|
|
|
|
else { |
|
247
|
0
|
|
|
0
|
|
|
return sub {}; |
|
248
|
|
|
|
|
|
|
} |
|
249
|
|
|
|
|
|
|
} |
|
250
|
|
|
|
|
|
|
|
|
251
|
0
|
|
|
0
|
0
|
|
method process () { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
# Unless overridden in a subclass there's not much we can do. |
|
253
|
0
|
|
|
|
|
|
state $warned = { desc => 1, title => 1, metadata => 1 }; |
|
254
|
|
|
|
|
|
|
warn("SVG: Skipping element \"$name\" (not implemented)\n") |
|
255
|
0
|
0
|
0
|
|
|
|
unless $warned->{$name}++ || !$self->root->verbose; |
|
256
|
0
|
|
|
|
|
|
$self->_dbg("skipping $name (not implemented)"); |
|
257
|
|
|
|
|
|
|
# $self->traverse; |
|
258
|
|
|
|
|
|
|
} |
|
259
|
|
|
|
|
|
|
|
|
260
|
0
|
|
|
0
|
0
|
|
method get_children () { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
# Note: This is the only place where these objects are created. |
|
263
|
|
|
|
|
|
|
|
|
264
|
0
|
|
|
|
|
|
my @res; |
|
265
|
0
|
|
|
|
|
|
for my $e ( @{$self->content} ) { |
|
|
0
|
|
|
|
|
|
|
|
266
|
0
|
0
|
|
|
|
|
if ( $e->{type} eq 'e' ) { |
|
|
|
0
|
|
|
|
|
|
|
267
|
0
|
|
|
|
|
|
my $pkg = "SVGPDF::" . ucfirst(lc $e->{name}); |
|
268
|
0
|
0
|
|
|
|
|
$pkg = "SVGPDF::Element" unless $pkg->can("process"); |
|
269
|
|
|
|
|
|
|
push( @res, $pkg->new |
|
270
|
|
|
|
|
|
|
( name => $e->{name}, |
|
271
|
0
|
|
|
|
|
|
atts => { map { lc($_) => $e->{attrib}->{$_} } keys %{$e->{attrib}} }, |
|
|
0
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
content => $e->{content}, |
|
273
|
0
|
|
|
|
|
|
root => $self->root, |
|
274
|
|
|
|
|
|
|
) ); |
|
275
|
|
|
|
|
|
|
} |
|
276
|
|
|
|
|
|
|
elsif ( $e->{type} eq 't' ) { |
|
277
|
|
|
|
|
|
|
push( @res, SVGPDF::TextElement->new |
|
278
|
|
|
|
|
|
|
( content => $e->{content}, |
|
279
|
0
|
|
|
|
|
|
) ); |
|
280
|
|
|
|
|
|
|
} |
|
281
|
|
|
|
|
|
|
else { |
|
282
|
|
|
|
|
|
|
# Basically a 'cannot happen', |
|
283
|
0
|
|
|
|
|
|
croak("Unhandled node type ", $e->{type}); |
|
284
|
|
|
|
|
|
|
} |
|
285
|
|
|
|
|
|
|
} |
|
286
|
0
|
|
|
|
|
|
return @res; |
|
287
|
|
|
|
|
|
|
} |
|
288
|
|
|
|
|
|
|
|
|
289
|
0
|
|
|
0
|
0
|
|
method traverse () { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
290
|
0
|
|
|
|
|
|
for my $c ( $self->get_children ) { |
|
291
|
0
|
0
|
|
|
|
|
next if ref($c) eq "SVGPDF::TextElement"; |
|
292
|
0
|
|
|
|
|
|
$self->_dbg("+ start handling ", $c->name, " (", ref($c), ")"); |
|
293
|
0
|
|
|
|
|
|
$c->process; |
|
294
|
0
|
|
|
|
|
|
$self->_dbg("- end handling ", $c->name); |
|
295
|
|
|
|
|
|
|
} |
|
296
|
|
|
|
|
|
|
} |
|
297
|
|
|
|
|
|
|
|
|
298
|
0
|
|
|
0
|
0
|
|
method u ( $a, %args ) { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
299
|
0
|
0
|
|
|
|
|
confess("Undef in units") unless defined $a; |
|
300
|
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
# Pixels per point. Usually 96/72. |
|
302
|
0
|
|
|
|
|
|
my $pxpt = $self->root->pxpi / $self->root->ptpi; |
|
303
|
|
|
|
|
|
|
|
|
304
|
0
|
0
|
|
|
|
|
return undef unless $a =~ /^([-+]?[\d.]+)(.*)$/; |
|
305
|
0
|
0
|
|
|
|
|
return $1*$pxpt if $2 eq "pt"; |
|
306
|
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
# default is px |
|
308
|
0
|
0
|
0
|
|
|
|
return $1 if $2 eq "" || $2 eq "px"; |
|
309
|
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
# 1 inch = pxpi px. |
|
311
|
0
|
0
|
|
|
|
|
return $1/2.54 * $self->root->pxpi if $2 eq "cm"; |
|
312
|
0
|
0
|
|
|
|
|
return $1/25.4 * $self->root->pxpi if $2 eq "mm"; |
|
313
|
0
|
0
|
|
|
|
|
return $1 * $self->root->pxpi if $2 eq "in"; |
|
314
|
|
|
|
|
|
|
|
|
315
|
0
|
0
|
|
|
|
|
if ( $2 eq '%' ) { |
|
316
|
0
|
|
0
|
|
|
|
my $w = $args{width} || $self->root->xoforms->[-1]->{diag}; |
|
317
|
0
|
|
|
|
|
|
return $1/100 * $w * $pxpt; |
|
318
|
|
|
|
|
|
|
} |
|
319
|
|
|
|
|
|
|
# Font dependent. |
|
320
|
|
|
|
|
|
|
# CSS defines em to be the font size. |
|
321
|
0
|
0
|
|
|
|
|
if ( $2 eq "em" ) { |
|
322
|
|
|
|
|
|
|
return $1 * ( $args{fontsize} |
|
323
|
0
|
|
0
|
|
|
|
|| $style->{'font-size'} |
|
324
|
|
|
|
|
|
|
|| $self->root->fontsize ); |
|
325
|
|
|
|
|
|
|
} |
|
326
|
|
|
|
|
|
|
# CSS defines ex to be half the font size. |
|
327
|
0
|
0
|
|
|
|
|
if ( $2 eq "ex" ) { |
|
328
|
|
|
|
|
|
|
return $1 * 0.5 * ( $args{fontsize} |
|
329
|
0
|
|
0
|
|
|
|
|| $style->{'font-size'} |
|
330
|
|
|
|
|
|
|
|| $self->root->fontsize ); |
|
331
|
|
|
|
|
|
|
} |
|
332
|
|
|
|
|
|
|
|
|
333
|
0
|
|
|
|
|
|
confess("Unhandled units in \"$a\""); |
|
334
|
0
|
|
|
|
|
|
return $a; # will hopefully crash somewhere... |
|
335
|
|
|
|
|
|
|
} |
|
336
|
|
|
|
|
|
|
|
|
337
|
0
|
|
|
0
|
0
|
|
method getargs ( $a ) { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
338
|
0
|
0
|
|
|
|
|
confess("Null attr?") unless defined $a; |
|
339
|
0
|
|
|
|
|
|
$a =~ s/^\s+//; |
|
340
|
0
|
|
|
|
|
|
$a =~ s/\s+$//; |
|
341
|
0
|
|
|
|
|
|
map { $self->u($_) } split( /\s*[,\s]\s*/, $a ); |
|
|
0
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
} |
|
343
|
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
# Initial fiddling with entity attributes. |
|
345
|
0
|
|
|
0
|
0
|
|
method get_params ( @desc ) { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
346
|
0
|
0
|
|
|
|
|
my $atts = shift(@desc) if ref($desc[0]) eq 'HASH'; |
|
347
|
0
|
|
|
|
|
|
my @res; |
|
348
|
0
|
|
0
|
|
|
|
my %atts = %{ $atts // $self->atts }; # copy |
|
|
0
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
# xlink:href is obsoleted in favour of href. |
|
351
|
0
|
0
|
0
|
|
|
|
$atts{href} //= delete $atts{"xlink:href"} if exists $atts{"xlink:href"}; |
|
352
|
|
|
|
|
|
|
|
|
353
|
0
|
|
|
|
|
|
my @todo; |
|
354
|
0
|
|
|
|
|
|
for my $param ( @desc ) { |
|
355
|
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
# Attribute may be followed by ':' and flags. |
|
357
|
|
|
|
|
|
|
# 0 undef -> 0 |
|
358
|
|
|
|
|
|
|
# h process units, % is viewBox height |
|
359
|
|
|
|
|
|
|
# s undef -> "" |
|
360
|
|
|
|
|
|
|
# u process units |
|
361
|
|
|
|
|
|
|
# v process units, % is viewBox width |
|
362
|
|
|
|
|
|
|
# U undef -> 0, process units |
|
363
|
|
|
|
|
|
|
# ! barf if undef |
|
364
|
0
|
|
|
|
|
|
my $flags = ""; |
|
365
|
0
|
0
|
|
|
|
|
( $param, $flags ) = ( $1, $2 ) |
|
366
|
|
|
|
|
|
|
if $param =~ /^(.*):(.*)$/; |
|
367
|
0
|
|
|
|
|
|
$param = lc($param); |
|
368
|
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
# Get and remove the attribute. |
|
370
|
0
|
|
|
|
|
|
my $p = delete( $atts{$param} ); |
|
371
|
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
# Queue. |
|
373
|
0
|
|
|
|
|
|
push( @todo, [ $param, $flags, $p ] ); |
|
374
|
|
|
|
|
|
|
} |
|
375
|
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
# CSS push with updated attributes. |
|
377
|
0
|
|
|
|
|
|
$self->css_push( \%atts ); |
|
378
|
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
# Now we can process the values. |
|
380
|
0
|
|
|
|
|
|
for ( @todo ) { |
|
381
|
0
|
|
|
|
|
|
my ( $param, $flags, $p ) = @$_; |
|
382
|
|
|
|
|
|
|
|
|
383
|
0
|
0
|
|
|
|
|
unless ( defined $p ) { |
|
384
|
0
|
0
|
|
|
|
|
if ( $flags =~ /s/ ) { $p = ""; } |
|
|
0
|
0
|
|
|
|
|
|
|
385
|
0
|
|
|
|
|
|
elsif ( $flags =~ /[0HUV]/ ) { $p = 0; } |
|
386
|
|
|
|
|
|
|
else { |
|
387
|
0
|
0
|
|
|
|
|
croak("Undefined mandatory attribute: $param") |
|
388
|
|
|
|
|
|
|
if $flags =~ /\!/; |
|
389
|
0
|
|
|
|
|
|
push( @res, $p ); |
|
390
|
0
|
|
|
|
|
|
next; |
|
391
|
|
|
|
|
|
|
} |
|
392
|
|
|
|
|
|
|
} |
|
393
|
|
|
|
|
|
|
|
|
394
|
0
|
|
|
|
|
|
$flags = lc($flags); |
|
395
|
|
|
|
|
|
|
# Convert units if 'u' flag. |
|
396
|
0
|
0
|
|
|
|
|
if ( $flags =~ /([huv])/ ) { |
|
397
|
0
|
|
|
|
|
|
my $flag = $1; |
|
398
|
0
|
0
|
|
|
|
|
if ( $p =~ /^([\d.]+)\%$/ ) { |
|
399
|
0
|
|
|
|
|
|
$p = $1/100; |
|
400
|
0
|
0
|
0
|
|
|
|
if ( $flags eq "w" || $param =~ /^(?:w(?:idth)|x)?$/i ) { |
|
|
|
0
|
0
|
|
|
|
|
|
401
|
|
|
|
|
|
|
# Percentage of viewBox width. |
|
402
|
0
|
|
|
|
|
|
$p *= $root->xoforms->[-1]->{width}; |
|
403
|
|
|
|
|
|
|
} |
|
404
|
|
|
|
|
|
|
elsif ( $flag eq "h" || $param =~ /^(?:h(?:eight)?|y)$/i ) { |
|
405
|
|
|
|
|
|
|
# Percentage of viewBox height. |
|
406
|
0
|
|
|
|
|
|
$p *= $root->xoforms->[-1]->{height}; |
|
407
|
|
|
|
|
|
|
} |
|
408
|
|
|
|
|
|
|
else { |
|
409
|
|
|
|
|
|
|
# Percentage of viewBox diagonal. |
|
410
|
0
|
|
|
|
|
|
$p *= $root->xoforms->[-1]->{diag}; |
|
411
|
|
|
|
|
|
|
} |
|
412
|
|
|
|
|
|
|
} |
|
413
|
|
|
|
|
|
|
else { |
|
414
|
0
|
|
|
|
|
|
$p = $self->u($p); |
|
415
|
|
|
|
|
|
|
} |
|
416
|
|
|
|
|
|
|
} |
|
417
|
|
|
|
|
|
|
|
|
418
|
0
|
|
|
|
|
|
push( @res, $p ); |
|
419
|
|
|
|
|
|
|
} |
|
420
|
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
# Return param values. |
|
422
|
0
|
|
|
|
|
|
return @res; |
|
423
|
|
|
|
|
|
|
} |
|
424
|
|
|
|
|
|
|
|
|
425
|
0
|
|
|
0
|
0
|
|
method get_cdata () { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
426
|
0
|
|
|
|
|
|
my $res = ""; |
|
427
|
0
|
|
|
|
|
|
for ( $self->get_children ) { |
|
428
|
0
|
0
|
|
|
|
|
$res .= "\n" . $_->content if ref($_) eq "SVGPDF::TextElement"; |
|
429
|
|
|
|
|
|
|
} |
|
430
|
0
|
|
|
|
|
|
$res; |
|
431
|
|
|
|
|
|
|
} |
|
432
|
|
|
|
|
|
|
|
|
433
|
0
|
|
|
0
|
0
|
|
method nfi ( $tag ) { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
434
|
0
|
|
|
|
|
|
state $aw = {}; |
|
435
|
|
|
|
|
|
|
warn("SVG: $tag - not fully implemented, expect strange results.\n") |
|
436
|
0
|
0
|
0
|
|
|
|
unless !$self->root->verbose || $aw->{$tag}++; |
|
437
|
|
|
|
|
|
|
} |
|
438
|
|
|
|
|
|
|
|
|
439
|
0
|
|
|
0
|
0
|
|
method set_font ( $xo, $style ) { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
440
|
0
|
|
|
|
|
|
my $msg =""; |
|
441
|
0
|
|
|
|
|
|
my $ret; |
|
442
|
|
|
|
|
|
|
{ |
|
443
|
0
|
|
|
0
|
|
|
local $SIG{__WARN__} = sub { $msg .= "@_" }; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
444
|
0
|
|
|
|
|
|
$ret = $self->root->fontmanager->set_font( $xo, $style ); |
|
445
|
|
|
|
|
|
|
} |
|
446
|
0
|
0
|
0
|
|
|
|
if ( $msg && $self->root->verbose ) { |
|
447
|
0
|
|
|
|
|
|
warn($msg); |
|
448
|
|
|
|
|
|
|
} |
|
449
|
0
|
|
|
|
|
|
$ret; |
|
450
|
|
|
|
|
|
|
} |
|
451
|
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
################ Bounding Box ################ |
|
453
|
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
# method bb ( $x, $y, $t = 0 ) { |
|
455
|
|
|
|
|
|
|
# my $bb = $self->root->xoforms->[-1]->{bb}; |
|
456
|
|
|
|
|
|
|
# |
|
457
|
|
|
|
|
|
|
# $t = $self->u($t) unless $t =~ /^[-+]?\d*(?:\.\d*)$/; |
|
458
|
|
|
|
|
|
|
# $t /= 2; |
|
459
|
|
|
|
|
|
|
# $bb->[0] = $x-$t if $bb->[0] > $x-$t; |
|
460
|
|
|
|
|
|
|
# $bb->[1] = $y-$t if $bb->[1] > $y-$t; |
|
461
|
|
|
|
|
|
|
# $bb->[2] = $x+$t if $bb->[2] < $x+$t; |
|
462
|
|
|
|
|
|
|
# $bb->[3] = $y+$t if $bb->[3] < $y+$t; |
|
463
|
|
|
|
|
|
|
# |
|
464
|
|
|
|
|
|
|
# return $bb; |
|
465
|
|
|
|
|
|
|
# } |
|
466
|
|
|
|
|
|
|
# |
|
467
|
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
################ TextElement ################ |
|
469
|
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
class SVGPDF::TextElement; |
|
471
|
|
|
|
|
|
|
|
|
472
|
0
|
0
|
|
0
|
|
|
field $content :param :accessor; |
|
|
0
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
# Actually, we should take style->{white-space} into account... |
|
475
|
|
|
|
|
|
|
BUILD { |
|
476
|
|
|
|
|
|
|
# Reduce whitespace. |
|
477
|
|
|
|
|
|
|
$content =~ s/\s+/ /g; |
|
478
|
|
|
|
|
|
|
} |
|
479
|
|
|
|
|
|
|
|
|
480
|
0
|
|
|
0
|
|
|
method process () { |
|
|
0
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
# Nothing to process. |
|
482
|
|
|
|
|
|
|
} |
|
483
|
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
1; |