File Coverage

blib/lib/SWF/Builder/Character/Text.pm
Criterion Covered Total %
statement 130 159 81.7
branch 20 38 52.6
condition 5 9 55.5
subroutine 20 24 83.3
pod n/a
total 175 230 76.0


line stmt bran cond sub pod time code
1             package SWF::Builder::Character::Text;
2              
3 1     1   7 use strict;
  1         2  
  1         42  
4 1     1   6 use utf8;
  1         2  
  1         56  
5              
6             our $VERSION="0.04";
7              
8             @SWF::Builder::Character::Text::ISA = qw/ SWF::Builder::Character::UsableAsMask /;
9             @SWF::Builder::Character::Text::Imported::ISA = qw/ SWF::Builder::Character::Imported SWF::Builder::Character::Text /;
10             @SWF::Builder::Character::StaticText::Imported::ISA = qw/ SWF::Builder::Character::Text::Imported /;
11              
12             ####
13              
14             package SWF::Builder::Character::Text::Def;
15              
16 1     1   158 use Carp;
  1         2  
  1         87  
17 1     1   6 use SWF::Element;
  1         3  
  1         20  
18 1     1   5 use SWF::Builder::Character;
  1         2  
  1         29  
19 1     1   5 use SWF::Builder::Character::Font;
  1         2  
  1         23  
20 1     1   6 use SWF::Builder::ExElement;
  1         2  
  1         2285  
21              
22             @SWF::Builder::Character::Text::Def::ISA = qw/ SWF::Builder::Character::Text SWF::Builder::ExElement::Color::AddColor/;
23              
24             sub new {
25 1     1   3 my ($class, $font, $text) = @_;
26 1         1 my $tag;
27 1         11 my $self = bless {
28             _bounds => SWF::Builder::ExElement::BoundaryRect->new,
29             _textrecords => SWF::Element::Array::TEXTRECORDARRAY2->new,
30             _kerning => 1,
31             _current_font => '',
32             _current_size => 12,
33             _max_ascent => 0,
34             _max_descent => 0,
35             _p_max_descent=> 0,
36             _current_X => 0,
37             _current_Y => 0,
38             _leading => 0,
39             _nl => undef,
40             _nl_X => 0,
41             _nlbounds => SWF::Builder::ExElement::BoundaryRect->new,
42             }, $class;
43 1         14 $self->_init_character;
44 1         12 $self->_init_is_alpha;
45 1         18 $self->{_nl} = $self->_get_last_record;
46 1 50       5 $self->font($font) if defined $font;
47 1 50       3 $self->text($text) if defined $text;
48 1         8 $self;
49             }
50              
51             sub _get_last_record {
52 4     4   5 my $self = shift;
53 4         8 my $records = $self->{_textrecords};
54 4         5 my $r;
55              
56 4 100 66     23 if (!@$records or $records->[-1]->GlyphEntries->defined) {
57 1         16 $r = SWF::Element::TEXTRECORD2->new;
58 1         18 push @$records, $r;
59 1         3 return $r;
60             } else {
61 3         76 return $records->[-1];
62             }
63             }
64              
65             sub font {
66 1     1   4 my ($self, $font) = @_;
67 1 50       6 return if $font eq $self->{_current_font};
68 1 50       9 croak "Invalid font" unless UNIVERSAL::isa($font, 'SWF::Builder::Character::Font');
69 1 50       7 croak "The font applied to the static text needs to embed glyph data" unless $font->embed;
70 1         5 my $r = $self->_get_last_record;
71 1         3 my $size = $self->{_current_size};
72 1         7 $r->TextHeight($size*20);
73 1         11 $r->FontID($font->{ID});
74 1         10 $self->{_current_font} = $font;
75 1         13 $self->_depends($font);
76 1         108 my $as = $font->{_tag}->FontAscent * $size / 1024;
77 1         11 my $des = $font->{_tag}->FontDescent * $size / 1024;
78 1 50       11 $self->{_max_ascent} = $as if $self->{_max_ascent} < $as;
79 1 50       6 $self->{_max_descent} = $des if $self->{_max_descent} < $des;
80 1         5 $self;
81             }
82              
83             sub size {
84 1     1   2 my ($self, $size) = @_;
85 1         4 my $r = $self->_get_last_record;
86 1         5 $r->TextHeight($size*20);
87 1         7 $r->FontID($self->{_current_font}->{ID});
88 1         8 $self->{_current_size} = $size;
89 1         4 my $as = $self->{_current_font}{_tag}->FontAscent * $size / 1024;
90 1         7 my $des = $self->{_current_font}{_tag}->FontDescent * $size / 1024;
91 1 50       7 $self->{_max_ascent} = $as if $self->{_max_ascent} < $as;
92 1 50       5 $self->{_max_descent} = $des if $self->{_max_descent} < $des;
93 1         5 $self;
94             }
95              
96             sub kerning {
97 0     0   0 my ($self, $kern) = @_;
98              
99 0 0       0 if (defined $kern) {
100 0         0 $self->{_kerning} = $kern;
101 0         0 $self;
102             } else {
103 0         0 $self->{_kerning};
104             }
105             }
106              
107             sub leading {
108 0     0   0 my ($self, $leading) = @_;
109 0 0       0 if (defined $leading) {
110 0         0 $self->{_leading} = $leading;
111 0         0 $self;
112             } else {
113 0         0 $self->{_leading};
114             }
115             }
116              
117             sub color {
118 1     1   2 my ($self, $color) = @_;
119 1         3 my $r = $self->_get_last_record;
120 1         13 $color = $self->_add_color($color);
121 1         259 $r->TextColor($color);
122 1         12 $self;
123             }
124              
125             sub _bbox_adjust {
126 2     2   6 my $self = $_[0]; # Don't use 'shift'
127 2         5 my $nl = $self->{_nl};
128 2         6 my $nlbbox = $self->{_nlbounds};
129 2 100       9 return unless defined $nlbbox->[0];
130              
131 1         5 my $s = $self->{_current_Y} + $self->{_max_ascent} + $self->{_p_max_descent};
132              
133 1         9 $self->{_bounds}->set_boundary($nlbbox->[0], $nlbbox->[1]+$s*20, $nlbbox->[2], $nlbbox->[3]+$s*20);
134 1         6 $self->{_nlbounds} = SWF::Builder::ExElement::BoundaryRect->new;
135             }
136              
137             sub _line_adjust {
138 1     1   3 my $self = $_[0]; # Don't use 'shift'
139 1         4 &_bbox_adjust;
140 1         5 $self->{_current_Y} += $self->{_max_ascent} + $self->{_p_max_descent};
141 1         9 $self->{_nl}->YOffset($self->{_current_Y}*20);
142 1         7 my $size = $self->{_current_size};
143 1         5 my $ft = $self->{_current_font}{_tag};
144 1         4 $self->{_max_ascent} = $ft->FontAscent * $size / 1024;
145 1         9 $self->{_max_descent} = $ft->FontDescent * $size / 1024;
146 1         7 $self->{_nl} = undef;
147             }
148              
149             sub position {
150 0     0   0 &_line_adjust;
151 0         0 goto &_position;
152             }
153              
154             sub _position {
155 0     0   0 my ($self, $x, $y) = @_;
156 0         0 my $r = $self->_get_last_record;
157 0         0 $r->XOffset($x*20);
158 0         0 $r->YOffset($y*20);
159 0         0 $self->{_bounds}->set_boundary($x*20, $y*20, $x*20, $y*20);
160 0         0 $self->{_current_X} = $self->{_nl_X} = $x;
161 0         0 $self->{_current_Y} = $y;
162 0         0 $self->{_nl} = $r;
163 0         0 $self->{_p_max_descent} = 0;
164 0         0 $self;
165             }
166              
167             sub text {
168 1     1   2 my ($self, $text) = @_;
169 1         11 my @text = split /([\x00-\x1f]+)/, $text;
170 1         2 my $font = $self->{_current_font};
171 1         3 my $scale = $self->{_current_size} / 51.2;
172 1         2 my $glyph_hash = $font->{_glyph_hash};
173            
174 1         5 while (my($text, $ctrl) = splice(@text, 0, 2)) {
175 1         2 my $bbox = $self->{_nlbounds};
176 1         6 $font->add_glyph($text);
177 1         7 my @chars = split //, $text;
178 1 50       5 if (@chars) {
179 1         10 my $gent = $self->{_textrecords}[-1]->GlyphEntries;
180 1         10 my $c1 = shift @chars;
181 1         4 push @chars, undef;
182 1         3 my $x = $self->{_current_X};
183 1         2 for my $c (@chars) {
184 4         9 my $ord_c1 = ord($c1);
185 4 100 66     48 my $kern = ($self->{_kerning} and defined $c) ? $font->kern($ord_c1, ord($c)) : 0;
186             # my $kern = 0;
187 4         14 my $adv = ($glyph_hash->{$c1}[0] + $kern) * $scale;
188 4         9 my $b = $glyph_hash->{$c1}[1]{_bounds};
189 4 50       10 if (defined $b->[0]) {
190 4         65 $bbox->set_boundary($x*20+$b->[0]*$scale, $b->[1]*$scale, $x*20+$b->[2]*$scale, $b->[3]*$scale);
191             } else {
192 0         0 $bbox->set_boundary($x*20, 0, $x*20, 0);
193             }
194 4         18 push @$gent, SWF::Builder::Text::GLYPHENTRY->new($ord_c1, $adv, $font);
195 4         6 $x += $adv;
196 4         14 $c1 = $c;
197             }
198 1         4 $self->{_current_X} = $x;
199             }
200              
201 1 50 33     11 if ($ctrl and (my $n = $ctrl=~tr/\n/\n/)) {
202 0         0 my $md = $self->{_max_descent};
203 0         0 my $height = $self->{_max_ascent} + $md;
204 0         0 $self->_line_adjust;
205             # $self->_position($self->{_nl_X}, $self->{_current_Y} + $height * ($n-1) + ($font->{_tag}->FontLeading * $scale / 20 + $self->{_leading})*$n);
206 0         0 $self->_position($self->{_nl_X}, $self->{_current_Y} + $height * ($n-1) + $self->{_leading} * $n);
207 0         0 $self->{_p_max_descent} = $md;
208             }
209             }
210 1         6 $self;
211             }
212              
213             sub get_bbox {
214 1     1   7 my $self = shift;
215 1         5 $self->_bbox_adjust;
216 1         2 return map{$_/20} @{$self->{_bounds}};
  4         9  
  1         4  
217             }
218              
219             sub _pack {
220 1     1   3 my ($self, $stream) = @_;
221            
222 1 50       10 $self->_line_adjust if $self->{_nl};
223            
224 1         3 my $x = $self->{_current_X} = 0;
225 1         3 my $y = $self->{_current_Y} = 0;
226            
227 1         2 my $tag;
228 1 50       6 if ($self->{_is_alpha}) {
229 1         33 $tag = SWF::Element::Tag::DefineText2->new;
230             } else {
231 0         0 $tag = SWF::Element::Tag::DefineText->new;
232             }
233 1         66 $tag->configure( CharacterID => $self->{ID},
234             TextBounds => $self->{_bounds},
235             TextRecords => $self->{_textrecords},
236             );
237 1         61 $tag->pack($stream);
238              
239             }
240              
241              
242             ####
243              
244             {
245             package SWF::Builder::Text::GLYPHENTRY;
246             @SWF::Builder::Text::GLYPHENTRY::ISA = ('SWF::Element::GLYPHENTRY');
247              
248             sub new {
249 4     4   8 my ($class, $code, $adv, $font) = @_;
250 4         22 bless [$code, $adv*20, $font->{_code_hash}], $class;
251             }
252              
253             sub GlyphIndex {
254 8     8   945 my $self = shift;
255              
256 8         38 return $self->[2]{$self->[0]};
257             }
258              
259             sub GlyphAdvance {
260 8     8   33 return shift->[1];
261             }
262             }
263              
264             1;
265             __END__