File Coverage

blib/lib/SWF/Builder/Character/Font/TTF.pm
Criterion Covered Total %
statement 121 185 65.4
branch 27 66 40.9
condition 11 32 34.3
subroutine 12 13 92.3
pod n/a
total 171 296 57.7


line stmt bran cond sub pod time code
1             package SWF::Builder::Character::Font::TTF; # stub
2              
3             our $VERSION="0.07";
4              
5             ####
6              
7             package SWF::Builder::Character::Font::Def; # addition
8              
9 1     1   6 use strict;
  1         2  
  1         35  
10 1     1   5 use utf8;
  1         2  
  1         6  
11              
12 1     1   23 use SWF::Builder::ExElement;
  1         2  
  1         52  
13 1     1   5 use SWF::Builder::Shape;
  1         2  
  1         19  
14 1     1   1023 use Font::TTF::Font;
  1         72733  
  1         38  
15 1     1   919 use Font::TTF::Ttc;
  1         912  
  1         35  
16 1     1   10 use Carp;
  1         2  
  1         2547  
17              
18             sub _init_font {
19 1     1   4 my ($self, $fontfile, $fontname) = @_;
20              
21 1         3 my $type = 0;
22 1         17 my $tag = $self->{_tag};
23 1         10 $self->{_ttf_tables} = (my $ttft = bless {}, 'SWF::Builder::Font::TTFTables');
24              
25 1 50 33     13 my $font = Font::TTF::Font->open($fontfile) ||
26             Font::TTF::Ttc->open($fontfile)
27             or croak "Can't open font file '$fontfile'";
28 1         74754 my ($p_font, $head, $name, $os2, $hhea, $cmap, $loca, $hmtx, $kern);
29 1         5 $ttft->{_font} = $p_font = $font;
30            
31 1 50       7 if (ref($font)=~/:Ttc$/) { # TrueType collection
32 0         0 my @names;
33 0         0 $p_font = $font->{directs}[0]; # Primary font needs to access some table.
34 0         0 for my $f (@{$font->{directs}}) { # For each collected font...
  0         0  
35 0         0 my $names;
36 0         0 $f->{name}->read;
37 0         0 for my $pid (@{$f->{name}{strings}[1]}) { # gathers all font names ( latin, unicode...)
  0         0  
38            
39 0         0 for my $eid (@$pid) {
40 0         0 while (my ($lid, $s) = each(%$eid)) {
41 0         0 $names .= "$s\n";
42             }
43             }
44             }
45 0 0       0 if (index($names, "$fontname\n") >=0) { # if match $fontname to the gathered,
46 0         0 $font = $f; # accept the font.
47 0         0 last;
48             }
49             }
50             }
51              
52             EMBED:
53             {
54 1 50 33     2 $name = $font->{name}||$p_font->{name} # font name
  1         17  
55             or croak 'Invalid font';
56 1 50 33     80 if ($os2 = $font->{'OS/2'}||$p_font->{'OS/2'}) { # get OS/2 table to check the lisence.
57 1         8 $os2->read;
58 1   50     2933 my $fstype = $os2->{fsType} && 0;
59            
60 1 50       30 if ($fstype & 0x302) {
    50          
61 0         0 warn "Embedding outlines of the font '$fontfile' is not permitted.\n";
62 0         0 $self->{_embed} = 0;
63 0         0 last EMBED;
64             } elsif ($fstype & 4) {
65 0         0 warn "The font '$fontfile' can use only for 'Preview & Print'.\n";
66 0         0 $self->{_read_only} = 1;
67             }
68             } else {
69 0         0 warn "The font '$fontfile' doesn't have any lisence information. See the lisence of the font.\n";
70             }
71 1 50 33     9 $head = $font->{head}||$p_font->{head} # header
72             or croak "Can't find TTF header of the font $fontname";
73 1 50 33     20 $hhea = $font->{hhea}||$p_font->{hhea} # horizontal header
74             or croak "Can't find hhea table of the font $fontname";
75 1 50 33     15 $cmap = $font->{cmap}||$p_font->{cmap} # chr-glyph mapping
76             or croak "Can't find cmap table of the font $fontname";
77 1 50 33     7 $loca = $font->{loca}||$p_font->{loca} # glyph location index
78             or croak "Can't find glyph index table of the font $fontname";
79 1 50 33     15 $hmtx = $font->{hmtx}||$p_font->{hmtx} # horizontal metrics
80             or croak "Can't find hmtx table of the font $fontname";
81 1 50 33     14 $kern = $font->{kern}||$p_font->{kern} # kerning table (optional)
82             and $kern->read;
83 1         9 $head->read;
84 1         24 $name->read;
85 1         1191 $hhea->read;
86 1         781 $cmap->read;
87 1         1710 $hmtx->read;
88 1         1683 $loca->read;
89 1         1951 my $scale = 1024 / $head->{unitsPerEm}; # 1024(Twips/Em) / S(units/Em) = Scale(twips/unit)
90 1         13 $tag->FontAscent($hhea->{Ascender} * $scale);
91 1         13 $tag->FontDescent(-$hhea->{Descender} * $scale);
92 1         9 $tag->FontLeading($hhea->{LineGap} * $scale); # ?
93 1         8 $self->{_scale} = $scale/20; # pixels/unit
94 1 50       7 $self->{_average_width} = defined($os2) ? $os2->{xAvgCharWidth}*$scale : 512;
95 1   33     6 $ttft->{_cmap} = ($cmap->find_ms or croak "Can't find unicode cmap table in the font $fontname")->{val}; # Unicode cmap
96 1         40 $ttft->{_advance}= $hmtx->{advance};
97 1         2 $ttft->{_loca} = $loca;
98 1         3 eval {
99 1         3 for my $kt (@{$kern->{tables}}) {
  1         10  
100 0 0       0 if ($kt->{coverage} & 1) {
101 0         0 $self->{_ttf_tables}{_kern} = $kt->{kern}; # horizontal kerning
102 0         0 last;
103             }
104             }
105             };
106             }
107 1 50       6 unless ($fontname) {
108 1         8 ($fontname) = ($name->find_name(1)=~/(.+)/); # Cleaning up is needed. But why?
109 1 50       32 ($fontname) = ($fontfile =~ /.*\/([^\\\/.]+)/) unless $fontname;
110             }
111 1         4 utf2bin($fontname);
112 1         5 $tag->FontName($fontname);
113 1         204 $type = $head->{macStyle};
114 1 50       5 $tag->FontFlagsBold(1) if ($type & 1);
115 1 50       5 $tag->FontFlagsItalic(1) if ($type & 2);
116              
117 1         7 $self;
118             }
119              
120             sub get_fontnames {
121 0     0   0 my ($self, $ttc) = @_;
122              
123 0 0       0 my $font = Font::TTF::Ttc->open($ttc)
124             or croak "Can't open TTC font file '$ttc'";
125              
126 0         0 my @names;
127 0         0 for my $f (@{$font->{directs}}) { # For each collected font...
  0         0  
128 0         0 $f->{name}->read;
129 0         0 my @alias_names;
130 0         0 for my $pid (@{$f->{name}{strings}[1]}) { # gathers all font names ( latin, unicode...)
  0         0  
131              
132 0         0 for my $eid (@$pid) {
133 0         0 while (my ($lid, $s) = each(%$eid)) {
134 0         0 push @alias_names, $s;
135             }
136             }
137             }
138 0         0 push @names, \@alias_names;
139             }
140 0         0 return \@names;
141             }
142              
143             sub kern {
144 3     3   7 my ($self, $code1, $code2) = @_;
145 3 50       15 my $kern_t = $self->{_ttf_tables}{_kern} or return 0;
146 0         0 my $cmap = $self->{_ttf_tables}{_cmap};
147 0 0       0 if (exists $kern_t->{$cmap->{$code1}}) {
148 0 0       0 if (exists $kern_t->{$cmap->{$code1}}{$cmap->{$code2}}) {
149 0         0 return $kern_t->{$cmap->{$code1}}{$cmap->{$code2}}/20;
150             }
151             }
152 0         0 return 0;
153             }
154              
155             sub _draw_glyph {
156 4     4   10 my ($self, $c, $gshape) = @_;
157 4 50       21 return unless $self->{_embed};
158              
159 4         10 my $scale = $self->{_scale};
160 4         22 my $gid = $self->{_ttf_tables}{_cmap}{ord($c)};
161 4         14 my $gtable = $self->{_ttf_tables}{_loca}{glyphs};
162 4         8 my $glyph1 = $gtable->[$gid];
163 4 50       9 if (defined $glyph1) {
164 4         23 $glyph1->read_dat;
165 4 50       3017 unless (exists $glyph1->{comps}) {
166 4         18 $self->_draw_glyph_component($glyph1, $gshape);
167             } else {
168 0         0 for my $cg (@{$glyph1->{comps}}) {
  0         0  
169 0         0 my @m;
170 0 0       0 @m = (translate => [$cg->{args}[0] * $scale, -$cg->{args}[1] * $scale]) if exists $cg->{args};
171 0 0       0 if (exists $cg->{scale}) { # Not tested...
172 0         0 my $s = $cg->{scale};
173 0         0 push @m, (ScaleX => $s->[0], RotateSkew0 => $s->[1], RotateSkew1 => $s->[2], ScaleY => $s->[3]);
174             }
175 0         0 my $ngs = $gshape->transform(\@m);
176 0         0 my $glyph = $gtable->[$cg->{glyph}];
177 0         0 $glyph->read_dat;
178 0         0 $self->_draw_glyph_component($glyph, $ngs);
179 0         0 $ngs->end_transform;
180             }
181             }
182             }
183 4         36 return $self->{_ttf_tables}{_advance}[$gid] * $scale;
184             }
185              
186             sub _draw_glyph_component {
187 4     4   9 my ($self, $glyph, $gshape) = @_;
188              
189 4         8 my $scale = $self->{_scale};
190              
191 4         11 my $i = 0;
192 4         8 for my $j (@{$glyph->{endPoints}}) {
  4         8  
193 7         21 my @x = map {$_ * $scale} @{$glyph->{x}}[$i..$j];
  130         202  
  7         21  
194 7         30 my @y = map {-$_ * $scale} @{$glyph->{y}}[$i..$j];
  130         195  
  7         18  
195 7         26 my @f = @{$glyph->{flags}}[$i..$j];
  7         31  
196 7         15 $i=$j+1;
197 7         10 my $sx = shift @x;
198 7         11 my $sy = shift @y;
199 7         12 my $f = shift @f;
200 7 50       19 unless ($f & 1) {
201 0         0 push @x, $sx;
202 0         0 push @y, $sy;
203 0         0 push @f, $f;
204 0 0       0 if ($f[0] & 1) {
205 0         0 $sx = shift @x;
206 0         0 $sy = shift @y;
207 0         0 $f = shift @f;
208             } else {
209 0         0 $sx = ($sx+$x[0])/2;
210 0         0 $sy = ($sy+$y[0])/2;
211 0         0 $f = 1;
212             }
213             }
214 7         12 push @x, $sx;
215 7         9 push @y, $sy;
216 7         11 push @f, $f;
217 7         31 $gshape->moveto($sx, $sy);
218 7         22 while(@x) {
219 113         391 my ($x, $y, $f)=(shift(@x), shift(@y), (shift(@f) & 1));
220            
221 113 100       305 if ($f) {
222 3         21 $gshape->lineto($x, $y);
223             } else {
224 110         111 my ($ax, $ay);
225 110 100       176 if ($f[0] & 1) {
226 17         25 $ax=shift @x;
227 17         22 $ay=shift @y;
228 17         19 shift @f;
229             } else {
230 93         2902 $ax=($x+$x[0])/2;
231 93         315 $ay=($y+$y[0])/2;
232             }
233 110         554 $gshape->curveto($x, $y, $ax, $ay);
234             }
235             }
236             }
237             }
238              
239             sub _destroy {
240 1     1   2 my $self = shift;
241 1         6 my $f = $self->{_ttf_tables}{_font};
242 1         3 %{$self->{_ttf_tables}} = ();
  1         4  
243 1 50       12 $f->release if $f;
244 1         1339 $self->SUPER::_destroy;
245             }
246              
247             1;