File Coverage

blib/lib/PDF/Builder/FontManager.pm
Criterion Covered Total %
statement 73 352 20.7
branch 16 156 10.2
condition 18 66 27.2
subroutine 7 14 50.0
pod 7 7 100.0
total 121 595 20.3


line stmt bran cond sub pod time code
1             package PDF::Builder::FontManager;
2              
3 39     39   279 use strict;
  39         88  
  39         1581  
4 39     39   216 use warnings;
  39         82  
  39         3293  
5              
6             our $VERSION = '3.028'; # VERSION
7             our $LAST_UPDATE = '3.028'; # manually update whenever code is changed
8              
9 39     39   279 use Carp;
  39         74  
  39         3191  
10 39     39   337 use Scalar::Util qw(weaken);
  39         92  
  39         213811  
11              
12             # unless otherwise noted, routines beginning with _ are internal helper
13             # functions and should not be used by others
14             #
15             # TBD (future)
16             # spec use of synfont() against a base to get
17             # fake bold, italic, bold+italic
18             # small caps (80% height), perhaps petite caps (1 ex height)
19             # condensed and expanded (or via hscale())
20             # support for UTF-8 subfonts for single byte encoding fonts
21              
22             =head1 NAME
23              
24             PDF::Builder::FontManager - Managing the font library for PDF::Builder
25              
26             =head1 SYNOPSIS
27              
28             These routines are called from the PDF::Builder class (see C<get_font(),
29             add_font()> methods).
30              
31             # core fonts come preloaded
32             # Add new a new font face and variants
33             my $rc = $pdf->add_font(
34             'face' => $unique_face_name, # font family, e.g., Times
35             'type' => 'core', # note that core fonts preloaded
36             'style' => 'serif', # also sans-serif, script (cursive),
37             # and symbol
38             'width' => 'proportional', # also constant
39             'settings' => { 'encode' => $encoding },
40             # note that these are actual core font names rather than file paths
41             'file' => { 'roman' => 'Times-Roman',
42             'italic' => 'Times-Italic',
43             'bold' => 'Times-Bold',
44             'bold-italic' => 'Times-BoldItalic' },
45             # for non-core these would be the actual file paths
46             # prefixed with font search paths
47             );
48             $rc = $pdf->add_font(
49             'face' => 'DejaVuSans', # Deja Vu sans serif family
50             'type' => 'ttf', # otf uses 'ttf'
51             'style' => 'sans-serif',
52             'width' => 'proportional',
53             'settings' => { 'encode' => 'utf8' },
54             # the defined font paths will be prepended to find the actual path
55             'file' => { 'roman' => 'DejaVuSans.ttf',
56             'italic' => 'DejaVuSans-Oblique.ttf',
57             'bold' => 'DejaVuSans-Bold.ttf',
58             'bold-italic' => 'DejaVuSans-BoldOblique.ttf' }
59             );
60              
61             Some of the global data, which can be reset via the C<font_settings()> method:
62              
63             * default-face: initialized to Times-Roman (core), used if you start
64             formatting text without explicitly setting a face, or inheriting one
65             * default-serif: initialized to Times-Roman (core), used if you want
66             a "generic" serif typeface
67             * default-sansserif: initialized to Helvetica (core), used if you want
68             a "generic" sans-serif typeface
69             * default-constant: initialized to Courier (core), used if you want
70             a "generic" constant-width typeface
71             * default-script: NOT initialized (no default), used if you want
72             a "generic" script (cursive) typeface
73             * default-symbol initialized to Symbol (core), used if you want
74             a "generic" symbol typeface
75             * font-paths: C:/Windows/Fonts for Windows systems for TTF, other types
76             are in non-standard paths, and for non-Windows, anything goes
77              
78             Usage of C<get_font()> is to specify the face and variants, and then each time,
79             specify I<italic> and I<bold> to be on or off. If the desired file is not yet
80             opened, it will be, and the C<$font> returned. If the font was already
81             created earlier, the saved C<$font> will be returned.
82              
83             my $font = $pdf->get_font(
84             'face' => 'Times',
85             'italic' => 0, # desire Roman (upright)
86             'bold' => 0, # desire medium weight
87             );
88             # if $font is undef, we have a problem...
89             $text->font($font, $font_size);
90             $text->... # use this font (medium weight Times-Roman core font)
91             $font = $pdf->get_font('italic' => 1);
92             $text->... # switched to italic
93             $font = $pdf->get_font('italic' => 0);
94             $text->... # back to Roman (upright) text
95              
96             =head1 METHODS
97              
98             =head2 new
99              
100             PDF::Builder::FontManager->new(%opts)
101              
102             =over
103              
104             This is called from Builder.pm's C<new()>. Currently there are no options
105             selectable. It will set up the font manager system and preload it with the
106             core fonts. Various defaults will be set for the face (core Times-Roman),
107             serif face (core Times-Roman), sans-serif face (core Helvetica), constant
108             width (fixed pitch) face (core Courier), and a symbol font (core Symbol).
109             There is no default for a script (cursive) font unless you set one using
110             the C<font_settings()> method.
111              
112             =back
113              
114             =cut
115              
116             sub new {
117 234     234 1 761 my ($class, $pdf) = @_;
118              
119 234         990 my $self = bless { 'pdf' => $pdf }, $class;
120 234         874 weaken $self->{'pdf'};
121             #$pdf = $pdf->{'pdf'} if $pdf->isa('PDF::Builder');
122             #$class = ref($class) if ref($class);
123             #my $self = $class->SUPER::new($pdf);
124 234         738 $self->{' pdf'} = $pdf;
125 234         761 weaken $self->{' pdf'};
126              
127             # current font is default font until face explicitly changed.
128             # Times face should be element 0 of the font-list array.
129 234         1642 $self->{' current-font'} = {'face' => 'Times', 'index' => 0,
130             'italic' => 0, 'bold' => 0};
131             # just the face to use. index assumes standard core initialization
132 234         955 $self->{' default-font'} = {'face' => 'Times', 'index' => 0};
133 234         911 $self->{' default-serif'} = {'face' => 'Times', 'index' => 0};
134 234         1117 $self->{' default-sansserif'} = {'face' => 'Helvetica', 'index' => 1};
135 234         929 $self->{' default-constant'} = {'face' => 'Courier', 'index' => 2};
136 234         1010 $self->{' default-symbol'} = {'face' => 'Symbol', 'index' => 3};
137             # no script font loaded by default
138 234         833 $self->{' default-script'} = {'face' => undef, 'index' => -1};
139 234         660 $self->{' font-paths'} = [];
140              
141 234         811 $self->{' font-list'} = [];
142              
143             # For Windows, can at least initialize to TTF place. Any additional fonts
144             # for Windows, and all non-Windows paths, will have to be added by the
145             # user. Note that an absolute (starts with /) or semi-absolute (starts
146             # with ./ or ../) font path/file will NOT have any search paths
147             # prepended!
148 234         495 push @{$self->{' font-paths'}}, $pdf->font_path();
  234         1457  
149             # can add any additional paths, but better to do in Builder.pm
150              
151 234         1360 $self->_initialize_core();
152              
153 234         1403 return $self;
154             } # end of new()
155              
156             =head2 font_settings
157              
158             @list = $pdf->font_settings() # Get
159              
160             $pdf->font_settings(%info) # Set
161              
162             =over
163              
164             Get or set some information about fonts, particularly the fonts to be used for
165             "generic" purposes.
166              
167             "Get" returns a list (array) of the default font face name, the default generic
168             serif face, the default generic sans-serif face, the default generic constant
169             width face, the default generic symbol face, and the default generic script
170             (cursive) face. It is possible for an element to be undefined (e.g., the
171             generic script face is C<undef>).
172              
173             "Set" changes one or more default settings:
174              
175             'font' => face to use for the default font face (initialized to Times)
176             'serif' => face to use for the generic serif face (initialized to Times)
177             'sans-serif' => face to use for the generic sans serif face
178             (initialized to Helvetica)
179             'constant' => face to use for the generic constant width face
180             (initialized to Courier)
181             'script' => face to use for the generic script face (uninitialized)
182             'symbol' => face to use for the generic symbol face
183             (initialized to Symbol)
184              
185             =back
186              
187             =cut
188              
189             sub font_settings {
190 0     0 1 0 my ($self, %info) = @_;
191              
192 0 0       0 if (!keys %info) {
193             # Get default faces, nothing passed in
194             return (
195             $self->{' default-font'}->{'face'},
196             $self->{' default-serif'}->{'face'},
197             $self->{' default-sansserif'}->{'face'},
198             $self->{' default-constant'}->{'face'},
199             $self->{' default-script'}->{'face'},
200 0         0 $self->{' default-symbol'}->{'face'},
201             );
202             }
203              
204             # Set default info from %info passed in
205             # also check if face exists, and at same time pick up the index value
206 0         0 my $index;
207 0 0       0 if (defined $info{'font'}) {
208 0         0 $index = $self->_face2index($info{'font'});
209 0 0       0 if ($index >= 0) {
210 0         0 $self->{' default-font'}->{'face'} = $info{'font'};
211 0         0 $self->{' default-font'}->{'index'} = $index;
212             } else {
213 0         0 carp "font_settings can't find face $info{'font'}. ignored.";
214             }
215             }
216 0 0       0 if (defined $info{'serif'}) {
217 0         0 $index = $self->_face2index($info{'serif'});
218 0 0       0 if ($index >= 0) {
219 0         0 $self->{' default-serif'}->{'face'} = $info{'serif'};
220 0         0 $self->{' default-serif'}->{'index'} = $index;
221             } else {
222 0         0 carp "font_settings can't find face $info{'serif'}. ignored.";
223             }
224             }
225 0 0       0 if (defined $info{'sans-serif'}) {
226 0         0 $index = $self->_face2index($info{'sans-serif'});
227 0 0       0 if ($index >= 0) {
228 0         0 $self->{' default-sansserif'}->{'face'} = $info{'sans-serif'};
229 0         0 $self->{' default-sansserif'}->{'index'} = $index;
230             } else {
231 0         0 carp "font_settings can't find face $info{'sans-serif'}. ignored.";
232             }
233             }
234 0 0       0 if (defined $info{'constant'}) {
235 0         0 $index = $self->_face2index($info{'constant'});
236 0 0       0 if ($index >= 0) {
237 0         0 $self->{' default-constant'}->{'face'} = $info{'constant'};
238 0         0 $self->{' default-constant'}->{'index'} = $index;
239             } else {
240 0         0 carp "font_settings can't find face $info{'constant'}. ignored.";
241             }
242             }
243 0 0       0 if (defined $info{'script'}) {
244 0         0 $index = $self->_face2index($info{'script'});
245 0 0       0 if ($index >= 0) {
246 0         0 $self->{' default-script'}->{'face'} = $info{'script'};
247 0         0 $self->{' default-script'}->{'index'} = $index;
248             } else {
249 0         0 carp "font_settings can't find face $info{'script'}. ignored.";
250             }
251             }
252 0 0       0 if (defined $info{'symbol'}) {
253 0         0 $index = $self->_face2index($info{'symbol'});
254 0 0       0 if ($index >= 0) {
255 0         0 $self->{' default-symbol'}->{'face'} = $info{'symbol'};
256 0         0 $self->{' default-symbol'}->{'index'} = $index;
257             } else {
258 0         0 carp "font_settings can't find face $info{'symbol'}. ignored.";
259             }
260             }
261              
262 0         0 return;
263             }
264              
265             =head2 add_font_path
266              
267             $rc = $pdf->add_font_path("a directory path", %opts)
268              
269             =over
270              
271             This method adds one search path to the list of paths to search. In the
272             C<get_font()> method, each defined search path will be prepended to the C<file>
273             entry (except for core fonts) in turn, until the font file is found. However,
274             if the C<file> entry starts with / or ./ or ../, it will be used alone.
275             A C<file> entry starting with .../ is a special case, which is turned into ../
276             before the search path is prepended. This permits you to give a search path
277             that you expect to move up one or more directories.
278              
279             The font path search list always includes the current directory (.), and is
280             initialized in C<Builder.pm> as C<@font_path>. For the
281             Windows operating system, C</Windows/Fonts> usually contains a number of TTF
282             fonts that come standard with Windows, so it is added by default. Anything
283             else, including all Linux (and other non-Windows operating systems), will have
284             to be added depending on your particular system. Some common places are:
285              
286             Windows (B<NOTE:> use / and not \\ in Windows paths!). Linux systems may or
287             may not handle spaces in directory names gracefully!
288              
289             /Windows/Fonts
290             /WinNT/Fonts
291             /Program Files/MikTex 2.9/fonts/type1/urw/bookman (URW Bookman for MikTex)
292             /Program Files (x86)/MikTex 2.9/fonts/type1/urw/bookman (older versions)
293             /Program Files/Adobe/Acrobat DC/Resource/CIDFont (Adobe Reader fonts)
294             GhostScript may have its own directories
295              
296             Note that directory names with spaces (e.g., C</Program Files>) may not play
297             nice with some Linux systems, so they are not included by default.
298              
299             Linux, etc.
300              
301             /usr/share/fonts (common base)
302             /usr/local/share/fonts (common base)
303             /usr/share/fonts/dejavu-sans-fonts (Deja Vu Sans TTF specifically)
304             /usr/share/fonts/truetype/ttf-dejavu
305             /usr/share/fonts/truetype/dejavu
306             /usr/lib/defoma/gs.d/devs/fonts (GhostScript?)
307             /usr/share/fonts/type1/gsfonts (GhostScript PS)
308             /usr/share/X11/fonts/urw-fonts (URW PS)
309              
310             Third-party application installations, such as Adobe's Acrobat Reader, may be
311             a source of installed fonts, too.
312              
313             A return code of 0 means the path was successfully added, while 1 means there
314             was a problem encountered (and a message was issued).
315              
316             No options are currently defined.
317              
318             =back
319              
320             =cut
321              
322             sub add_font_path {
323 0     0 1 0 my ($self, $newpath, %opts) = @_;
324              
325 0         0 my $rc = 0; # OK so far!
326              
327             # TBD: consider validating that this $newpath exists?
328             # will not be using until actually attempt to open the file!
329 0         0 push @{ $self->{' font-paths'} }, $newpath;
  0         0  
330              
331 0         0 return $rc;
332             } # end of add_font_path()
333              
334             =head2 add_font
335              
336             $rc = add_font(%info)
337              
338             =over
339              
340             Add a new font entry (by face and variants) to the Font Manager's list of
341             known fonts.
342              
343             C<%info> items to be defined:
344              
345             =over
346              
347             =item face => 'face name'
348              
349             This should be a unique string to identify just one entry in the Font
350             Manager fonts table. I.e., you should not have two "Times" (one a core font
351             and the other a TTF font). Give them different names (face names are case
352             I<sensitive>, so 'Times' is different from 'times'). The C<face> name is
353             used to retrieve the desired font.
354              
355             The default core font face names
356             (I<Times, Helvetica, Courier, Symbol, ZapfDingbats,
357             Georgia, Verdana, Trebuchet, Wingdings, Webdings>),
358             as well as class names
359             I<current, default, serif, sans-serif, constant, script, symbol, -external->
360             are B<reserved> and should not be used for user-added faces.
361             They I<may> be redefined at your discretion.
362             The MS Windows core extension I<BankGothic> is currently B<not> added to the
363             core fonts automatically. I<-external-> may or may not be defined, and should
364             not be used by user code.
365              
366             B<Note> that use of Windows extension "core" fonts (Georgia, Verdana, Trebuchet,
367             Wingdings, and Webdings) expect those fonts to be installed on platforms if
368             they are used, and a (hopefully) close substitution will be attempted if not.
369             These fonts are normally available on Windows platforms, but may not be
370             available on non-Windows platforms. Use (create PDFs specifying them) at your
371             own risk.
372              
373             =item type => 'type string'
374              
375             This tells which Builder font routine to use to load the font. The allowed
376             entries are:
377              
378             =over
379              
380             =item B<core>
381              
382             This is a core font, and is loaded via the C<CoreFont()> routine. Note that
383             the core fonts are automatically preloaded (including additional ones on
384             Windows systems), so you should not need to explicitly load any core fonts
385             (at least, the 14 basic ones). All PDF installation are supposed to include
386             these 14 basic core fonts, but the precise actual file type may vary among
387             installations, and substitutions may be made (so long as the metrics match).
388             Currently, core fonts are limited to single byte encodings.
389              
390             On Windows systems, there are an additional 14 core fonts which are normally
391             loaded. These are Georgia, Verdana, Trebuchet, Wingdings, and Webdings faces.
392             Use caution if making use of these additional core fonts, as non-Windows
393             systems may not include them without explicit manual installation of these
394             fonts. These fonts may be safe to use if you know that all your PDF readers
395             will be running on Windows systems. Finally, PDF::Builder includes metrics
396             for Bank Gothic, but this is not automatically loaded into the core set, as
397             it is not clear whether all Windows systems actually include this font.
398              
399             =item B<ttf>
400              
401             This is a TrueType (.ttf) or OpenType (.otf) font, loaded with C<ttfont()>.
402             Currently this is the only
403             type which can be used with multibyte (e.g., I<utf8>) encodings, as well as
404             with single byte encodings such as I<Latin-1>. It is also the only font type
405             that can be used with HarfBuzz::Shaper. Many systems include a number of TTF
406             fonts, but unlike core fonts, none are automatically loaded by the PDF::Builder
407             Font Manager, and must be explicitly loaded via C<add_font()>.
408              
409             =item B<type1>
410              
411             This is a PostScript (Type1) font, loaded with C<psfont()>, which used to be
412             quite commonly used, but is
413             fairly rarely used today, having mostly been supplanted by the more capable
414             TTF format. Some systems may include some Type1 fonts, but Windows,
415             for example, does not normally come with any. No Type1 fonts are automatically
416             loaded by the PDF::Builder Font Manager, and must be explicitly loaded via
417             C<add_font()>.
418              
419             It is assumed that the font metrics file (.afm or .pfm) has the same base file
420             name as the glyph file (.pfa or .pfb), is found in the same directory, I<and>
421             either can work with either.
422             If you have need for a different directory, a different base name, or a
423             specific metrics file to go with a specific glyph file, let us know, so we can
424             add such functionality. Otherwise, you will need to directly use the C<psfont()>
425             method in order to specify such different paths.
426              
427             =item B<cjk>
428              
429             This is an East Asian (Chinese-Japanese-Korean) type font, loaded with the
430             C<cjkfont()> method. Note that CJK fonts
431             have never been well supported by PDF::Builder, and depend on some fairly old
432             (obsolete) features and external files (.cmap and .data). We suggest that,
433             rather than going directly to CJK files, you first try directly using the
434             (usually) TTF files, in the TTF format. Few systems come with CJK fonts
435             installed. No CJK fonts are automatically loaded by the PDF::Builder Font
436             Manager, and must be explicitly loaded via C<add_font()>.
437              
438             =item B<bdf>
439              
440             This is an Adobe Bitmap Distribution Format font, loaded with the C<bdfont()>
441             method, a very old bitmapped format
442             dating back to the early days of the X11 system. Unlike the filled smooth
443             outlines used in most modern fonts, BDF's are a coarse grid of on/off pixels.
444             Please be kind to your readers and use this format sparingly, such as only for
445             chapter titles or headings! Few systems come with BDF fonts installed any more.
446             No BDF fonts are automatically loaded by the PDF::Builder Font Manager, and
447             must be explicitly loaded via C<add_font()>.
448              
449             =back
450              
451             =item settings => { 'encode' => string, ... }
452              
453             This is a collection of any other settings, flags, etc. accepted by this
454             particular font type. See the POD for C<corefont>, C<ttfont>, etc. (per
455             I<type> for the allowable entries. An important one will be the encoding,
456             which you will need to specify, if you use any characters beyond basic ASCII.
457              
458             Currently, all fonts may use any single byte encoding you
459             desire (the default is I<CP-1252>). Only TTF type fonts (which includes OTF and
460             CJK fonts) may currently specify a multibyte encoding such as I<utf8>. Needless
461             to say, the text data that you pass to text routines must conform to the given
462             encoding. You are I<not> forced to use the same encoding for all defined fonts,
463             but if you wish to mix-and-match encodings, it is up to you to define your
464             text that uses the encoding specified for the particular font used!
465              
466             Note in particular when you use I<entities> that (if numeric) they are given
467             in the Unicode number. When out of the single byte range (x00-xFF), results are
468             unpredictable if you give an entity that does not fall within the encoding's
469             range! Also check results for Unicode points within the range x80-xFF if you
470             are using I<utf8> encoding.
471              
472             =item style => 'styling'
473              
474             This specifies the styling of the font: B<serif>, B<sans-serif>, B<constant>
475             (constant width, or fixed pitch), B<script> (cursive), or B<symbol>
476             (non-alphabetic). It has no effect on how a font is loaded or used, but may
477             be useful to you for defining a generic style font.
478              
479             =item width => 'relative widths'
480              
481             Currently, B<proportional> (variable width) and B<constant> (constant width)
482             may be specified. It has no effect on how a font is loaded or used, but may be
483             useful to you for defining a generic style font.
484              
485             =item file => {anonymous hash of source files}
486              
487             This tells the Font Manager where to find the actual font file.
488              
489             Various font paths are tried from the C<font_path> list to find an actual file.
490             TrueType and OpenType fonts
491             (C<'type'=E<gt>'ttf'>) may instead be given as a C<Font::TTF::Font> I<object>,
492             such as one extracted from a TTC (TrueType Collection) file, one per "file"
493             ('roman', 'italic', etc.). In a dump of the FontManager tables
494             (C<dump_font_tables()>), these will show up as a file "name" of
495             C<Font::TTF::Font=HASH(....)>. B<Other ways of specifying TTC fonts are
496             expected to be added in the future.>
497              
498             For core fonts, it is the standard I<name>, rather than a I<file> (and
499             remember, they are preloaded).
500             For all other types, it lists from one to four of the following variants:
501              
502             =over
503              
504             =item B<roman> => 'path to Roman'
505              
506             This specifies the "Roman" or "regular" posture variant of the font. Almost all
507             available fonts include a Roman (normal, upright posture) variant at normal
508             (medium) weight.
509              
510             =item B<italic> => 'path to Italic'
511              
512             This specifies the "Italic", "slanted", or "oblique" posture variant of the
513             font. Most available fonts include an italic variant at normal (medium) weight.
514              
515             =item B<bold> => 'path to Bold'
516              
517             This specifies the "Bold" or "heavy" variant of the font. Most available fonts
518             include a bold (heavy weight) variant with normal (Roman) posture.
519              
520             =item B<bold-italic> => 'path to BoldItalic'
521              
522             This specifies the "Bold" I<and> "Italic" variant of the font. Many
523             available fonts include a bold (heavy weight) variant with italic posture.
524              
525             =item B<symbol> => 'path to Symbol'
526              
527             For symbol type fonts (non-alphabetic), rather than risk confusion by reusing
528             the "roman" term, the "symbol" term is used to specify what is usually the
529             only variant of a symbol font. It is possible that there are bold, italic, and
530             even bold-italic variants of a symbol file, but if so, they are not
531             currently supported.
532              
533             =back
534              
535             You I<can> give the entire path of the font's source file, in an absolute
536             path, if you wish. However, it's usually less typing to use C<add_font_path()>
537             to specify a list of font directories to search, and only give the name (and
538             perhaps a subdirectory) for the path here in C<add_font()>.
539              
540             =back
541              
542             =back
543              
544             =cut
545              
546             sub add_font {
547 2340     2340 1 12041 my ($self, %info) = @_;
548              
549 2340         3815 my $rc = 0; # so far, so good!
550              
551             # basically, all %info gets pushed onto self->font_list as the next
552             # element. then an entry hash element is added for each variant,
553             # initialized to undef.
554              
555 2340         3927 my $ele = \%info; # don't want to modify original list
556 2340         4852 $ele->{'entry'} = undef; # store the discovered/enabled fonts here
557              
558             # check that all fields are defined, and file includes at least one
559             # subfield
560 2340 50       5581 if (!defined $info{'face'}) {
561 0         0 carp "add_font missing 'face' entry";
562 0         0 $rc = 1;
563             }
564             # is this face name already in use?
565 2340         3615 foreach (@{ $self->{' font-list'} }) {
  2340         5241  
566 10530 50       24555 if ($_->{'face'} eq $info{'face'}) {
567 0         0 carp "add_font finds face name '$info{'face'} already in use!";
568 0         0 $rc = 1;
569 0         0 last;
570             }
571             }
572             # is this face name reserved?
573             # foreach (qw/current default serif sans-serif constant script symbol -external-/) {
574             # if ($_ eq $info{'face'}) {
575             # carp "add_font finds face name '$info{'face'} is reserved!";
576             # $rc = 1;
577             # last;
578             # }
579             # }
580              
581 2340 50       5326 if (!defined $info{'type'}) {
582 0         0 carp "add_font missing 'type' entry";
583 0         0 $rc = 1;
584             }
585             # TBD what to do about synthetic fonts?
586 2340 0 33     5826 if ($info{'type'} ne 'core' &&
      33        
      0        
      0        
      0        
      0        
587             $info{'type'} ne 'ttf' &&
588             $info{'type'} ne 'type1' &&
589             $info{'type'} ne 'cjk' &&
590             $info{'type'} ne 'bdf' &&
591             !($info{'type'} eq '?' && $info{'face'} eq '-external-')) {
592 0         0 carp "add_font unknown 'type' entry $info{'type'}";
593 0         0 $rc = 1;
594             }
595              
596             # encode and other settings should be optional
597             #if (!defined $info{'settings'}) {
598             # carp "add_font missing 'settings' entry";
599             # $rc = 1;
600             #}
601             # TBD: utf8 etc only for ttf, check single byte encoding name is valid?
602              
603 2340 50       4744 if (!defined $info{'style'}) {
604 0         0 carp "add_font missing 'style' entry";
605 0         0 $rc = 1;
606             }
607 2340 50 100     15962 if ($info{'style'} ne 'serif' &&
      66        
      66        
      33        
      0        
      33        
608             $info{'style'} ne 'sans-serif' &&
609             $info{'style'} ne 'constant' &&
610             $info{'style'} ne 'script' &&
611             $info{'style'} ne 'symbol' &&
612             !($info{'style'} eq '?' && $info{'face'} eq '-external-')) {
613 0         0 carp "add_font unknown 'style' entry $info{'style'}";
614 0         0 $rc = 1;
615             }
616              
617 2340 50       5172 if (!defined $info{'width'}) {
618 0         0 carp "add_font missing 'width' entry";
619 0         0 $rc = 1;
620             }
621 2340 50 66     7913 if ($info{'width'} ne 'proportional' &&
      0        
      33        
622             $info{'width'} ne 'constant' &&
623             !($info{'width'} eq '?' && $info{'face'} eq '-external-')) {
624 0         0 carp "add_font unknown 'width' entry $info{'width'}";
625 0         0 $rc = 1;
626             }
627              
628 2340 50       5182 if (!defined $info{'file'}) {
629 0         0 carp "add_font missing 'file' entry";
630 0         0 $rc = 1;
631             }
632             # one or more of roman, italic, bold, bold-italic (non-symbol fonts)
633             # symbol faces ('style') use symbol, italic, bold, bold-italic
634             # create 'entry' of same structure, to hold undef and then $font
635             # will ignore any subfields not matching above list
636 2340         3667 my $found = 0; # did we find any of the required four?
637 2340         5507 my @style_list = qw/italic bold bold-italic/;
638 2340 100 66     8487 if (defined $info{'style'} && $info{'style'} ne 'symbol') {
639 1404         3231 unshift @style_list, 'roman';
640             }
641             # symbol valid only for style=symbol, where it is usually the only one
642 2340 100 66     8398 if (defined $info{'style'} && $info{'style'} eq 'symbol') {
643 936         2083 unshift @style_list, 'symbol';
644             }
645 2340         4807 foreach my $file (@style_list) {
646 9360 100       21332 if (defined $info{'file'}->{$file}) {
647 6552         13530 $ele->{'entry'}->{$file} = undef;
648 6552         12715 $found = 1;
649             }
650             }
651              
652 2340 50       4839 if (!$found) {
653 0         0 carp "add_font 'file' entry does not have at least one of roman, italic, bold, bold-italic, or symbol";
654 0         0 $rc = 1;
655             }
656 2340 50       4806 return $rc if $rc;
657              
658             # $ele should contain an entry to be inserted into the font list as an
659             # array element
660 2340         3464 push @{ $self->{' font-list'} }, $ele;
  2340         5754  
661 2340         6043 return 0;
662              
663             } # end of add_font()
664              
665             # load up the standard core fonts
666             sub _initialize_core {
667 234     234   519 my $self = shift;
668              
669 234         639 my $single = 'cp-1252'; # let's try this one for single byte encodings
670             # the universal core fonts. note that some systems may have similar
671             # fonts substituted (but the metrics should be the same)
672             # index = 0
673 234         2299 $self->add_font('face' => 'Times', 'type' => 'core',
674             'settings' => { 'encode' => $single },
675             'style' => 'serif', 'width' => 'proportional',
676             'file' => {'roman' => 'Times-Roman',
677             'italic' => 'Times-Italic',
678             'bold' => 'Times-Bold',
679             'bold-italic' => 'Times-BoldItalic'} );
680             # index = 1
681 234         1915 $self->add_font('face' => 'Helvetica', 'type' => 'core',
682             'settings' => { 'encode' => $single },
683             'style' => 'sans-serif', 'width' => 'proportional',
684             'file' => {'roman' => 'Helvetica',
685             'italic' => 'Helvetica-Oblique',
686             'bold' => 'Helvetica-Bold',
687             'bold-italic' => 'Helvetica-BoldOblique'} );
688             # index = 2
689 234         1903 $self->add_font('face' => 'Courier', 'type' => 'core',
690             'settings' => { 'encode' => $single },
691             'style' => 'serif', 'width' => 'constant',
692             'file' => {'roman' => 'Courier',
693             'italic' => 'Courier-Oblique',
694             'bold' => 'Courier-Bold',
695             'bold-italic' => 'Courier-BoldOblique'} );
696             # index = 3
697 234         1541 $self->add_font('face' => 'Symbol', 'type' => 'core',
698             'settings' => { 'encode' => $single },
699             'style' => 'symbol', 'width' => 'proportional',
700             'file' => {'symbol' => 'Symbol'} );
701             # index = 4
702 234         1605 $self->add_font('face' => 'ZapfDingbats', 'type' => 'core',
703             'settings' => { 'encode' => $single },
704             'style' => 'symbol', 'width' => 'proportional',
705             'file' => {'symbol' => 'ZapfDingbats'} );
706              
707             # apparently available on Windows systems
708             #if ($^O eq 'MSWin32') { # always allow, even on non-Windows platforms
709              
710             # index = 5
711 234         1901 $self->add_font('face' => 'Georgia', 'type' => 'core',
712             'settings' => { 'encode' => $single },
713             'style' => 'serif', 'width' => 'proportional',
714             'file' => {'roman' => 'Georgia',
715             'italic' => 'GeorgiaItalic',
716             'bold' => 'GeorgiaBold',
717             'bold-italic' => 'GeorgiaBoldItalic'} );
718             # index = 6
719 234         1786 $self->add_font('face' => 'Verdana', 'type' => 'core',
720             'settings' => { 'encode' => $single },
721             'style' => 'sans-serif', 'width' => 'proportional',
722             'file' => {'roman' => 'Verdana',
723             'italic' => 'VerdanaItalic',
724             'bold' => 'VerdanaBold',
725             'bold-italic' => 'VerdanaBoldItalic'} );
726             # index = 7
727 234         1711 $self->add_font('face' => 'Trebuchet', 'type' => 'core',
728             'settings' => { 'encode' => $single },
729             'style' => 'sans-serif', 'width' => 'proportional',
730             'file' => {'roman' => 'Trebuchet',
731             'italic' => 'TrebuchetItalic',
732             'bold' => 'TrebuchetBold',
733             'bold-italic' => 'TrebuchetBoldItalic'} );
734             # index = 8
735 234         1567 $self->add_font('face' => 'Wingdings', 'type' => 'core',
736             'settings' => { 'encode' => $single },
737             'style' => 'symbol', 'width' => 'proportional',
738             'file' => {'symbol' => 'Wingdings'} );
739             # index = 9
740 234         1453 $self->add_font('face' => 'Webdings', 'type' => 'core',
741             'settings' => { 'encode' => $single },
742             'style' => 'symbol', 'width' => 'proportional',
743             'file' => {'symbol' => 'Webdings'} );
744              
745             # there is also a Bank Gothic on my Windows system, but I'm not sure if I
746             # loaded that one from some place, or it came with Windows. In either case,
747             # I think it should be OK to provide the metrics (but not the font itself).
748             #
749             # Bank Gothic is confusing... it only has regular and italic, and it
750             # doesn't look anything like the examples shown on various font websites.
751             # I think some other sans-serif font is being substituted for it.
752             # $self->add_font('face' => 'BankGothic', 'type' => 'core',
753             # 'settings' => { 'encode' => $single },
754             # 'style' => 'sans-serif', 'width' => 'proportional',
755             # 'file' => {'roman' => 'BankGothic',
756             # 'italic' => 'BankGothicItalic',
757             # #'bold' => 'BankGothicBold',
758             # #'bold-italic' => 'BankGothicBoldItalic'}
759             # } );
760              
761             #} # Windows additional core fonts
762              
763 234         643 return;
764             } # end of _initialize_core()
765              
766             ## for some reason, this is uncallable from Content::Text
767             ## try to fix it... it belongs here and not in Text.pm
768             #=head2 get_fv_extents
769             #
770             # ($ascender, $descender, $d_leading) = $pdf->get_fv_extents($font_size, $leading)
771             #
772             #=over
773             #
774             #Get the I<current> font's vertical extents (points above and below the
775             #baseline), scaled by font_size, and leading is added to the descender amount.
776             #C<$descender> is the deepest glyph descender; C<$d_leading> is that plus the
777             #leading.
778             #
779             #Note that the extents are the maximum values defined for this particular
780             #I<font>, and not what the particular text's ascenders and descenders are
781             #actually using.
782             #
783             #=back
784             #
785             #=cut
786             #
787             #sub get_fv_extents {
788             # my ($self, $font_size, $leading) = @_;
789             #
790             # $leading = 1.0 if $leading <= 0; # actually, a bad value
791             # $leading++ if $leading < 1.0; # might have been given as fractional
792             #
793             # my $current = $self->{' current-font'}->{'face'}; # font name
794             # my $font = $self->get_font('face' => $current); # font object realized
795             # # now it's loaded, if it wasn't already
796             # my $ascender = $font->ascender()/1000*$font_size; # positive
797             # my $descender = $font->ascender()/1000*$font_size; # negative
798             #
799             # # ascender is positive, descender is negative (above/below baseline)
800             # return ($ascender, $descender, $descender-($leading-1.0)*$font_size);
801             #} # end of get_fv_extents()
802              
803             =head2 get_font
804              
805             @current = $pdf->get_font() # Get
806              
807             $font = $pdf->get_font(%info) # Set
808              
809             =over
810              
811             If no parameters are given (C<@current = $pdf-E<gt>get_font()>), a list
812             (array) is returned giving the I<current> font setting: I<face> name, I<italic>
813             flag 0/1, I<bold> flag 0/1, I<type> ('core', 'ttf', etc.), a hash reference of
814             I<settings>, such as the I<encoding> ('utf8',
815             etc.), I<style> value, I<width> value, and an array reference (list) of
816             variants (roman, bold, etc.). If no font has yet been explicitly set, the
817             current font will be the default font.
818              
819             If at least one parameter is given (C<%info> hash), the font manager will
820             attempt to discover the appropriate font (from within the font list), load it
821             if not already done, and return the C<$font> value. If I<undef> is returned,
822             there was an error.
823              
824             %info fields:
825              
826             =over
827              
828             =item face => face name string
829              
830             This is the font family (face) name loaded up with the core fonts (e.g., Times),
831             or by C<$pdf-E<gt>add_font()> calls. In addition, the I<current> font face or
832             the I<default> face can be
833             requested, the I<serif> generic serif face, the I<sans-serif> generic sans-serif
834             face, the I<constant> generic constant width face, or the I<script> generic
835             script (cursive) face (B<if defined>) may be requested.
836              
837             If you give the C<face> entry, the other settings (C<italic>, C<bold>, etc.)
838             are I<not> reset, unless it is impossible to use the existing setting.
839             If you do I<not> give the C<face> entry, the I<current> entry will be updated
840             (bold, italic switched on/off, etc.). You may always explicitly give
841             I<current> to make it clear in your code that you I<don't> want to change
842             the face.
843              
844             =item italic => flag
845              
846             This requests use of the italic (slanted, oblique) variant of the font, in
847             either the current face (C<face> not given in this call) or the new face. The
848             value is 0 or 1 for "off" (Roman/upright posture) and "on" (italic posture).
849              
850             =item bold => flag
851              
852             This requests use of the bold (heavy weight) variant of the font, in
853             either the current face (C<face> not given in this call) or the new face. The
854             value is 0 or 1 for "off" (medium weight) and "on" (heavy weight).
855              
856             =back
857              
858             =back
859              
860             =cut
861              
862             sub get_font {
863 0     0 1   my ($self, %info) = @_;
864              
865 0           my $font = undef; # means NOT GOOD
866 0           my $index;
867             my @list;
868              
869 0 0         if (!keys %info) {
870             # Get request for whatever the "current" (last selected) entry is
871 0           push @list, $self->{' current-font'}->{'face'}; # [0] s
872 0           push @list, $self->{' current-font'}->{'italic'}; # [1] b
873 0           push @list, $self->{' current-font'}->{'bold'}; # [2] b
874 0           $index = $self->{' current-font'}->{'index'};
875              
876 0           push @list, $self->{' font-list'}->[$index]->{'type'}; # [3] s
877             # note that settings will be a hashref, not a string
878 0 0         if (defined $self->{' font-list'}->[$index]->{'settings'}) {
879 0           push @list, $self->{' font-list'}->[$index]->{'settings'}; # [4] hr
880             } else {
881 0           push @list, {};
882             }
883 0           push @list, $self->{' font-list'}->[$index]->{'style'}; # [5] s
884 0           push @list, $self->{' font-list'}->[$index]->{'width'}; # [6] s
885              
886             # what variants are defined? just the key names
887 0           my @variants = keys %{ $self->{' font-list'}->[$index]->{'entry'} };
  0            
888 0           push @list, \@variants; # [7] ar
889              
890 0           return @list;
891             }
892              
893             # if we're here, the user is requesting a font, given some combination of
894             # face, type, italic, and bold flags. keys %info > 0.
895 0           my $face_name = $self->{' current-font'}->{'face'};
896 0           my $current_italic = $self->{' current-font'}->{'italic'};
897 0           my $current_bold = $self->{' current-font'}->{'bold'};
898 0           my $current_index = $self->{' current-font'}->{'index'};
899 0           $index = -1;
900 0 0         if (defined $info{'face'}) {
901             # face = current, default, serif, sans-serif, constant, script, symbol,
902             # or actual path/name
903 0 0         if ($info{'face'} eq 'current') {
    0          
    0          
    0          
    0          
    0          
    0          
904             # not really a change, but to make sure some font is loaded!
905 0           $face_name = $self->{' current-font'}->{'face'};
906 0           $index = $self->{' current-font'}->{'index'};
907             } elsif ($info{'face'} eq 'default') {
908             # change selected font to the default face
909 0           $face_name = $self->{' default-font'}->{'face'};
910 0           $index = $self->{' default-font'}->{'index'};
911             } elsif ($info{'face'} eq 'serif') {
912             # change selected font to the generic (default) serif face
913 0           $face_name = $self->{' default-serif'}->{'face'};
914 0           $index = $self->{' default-serif'}->{'index'};
915             } elsif ($info{'face'} eq 'sans-serif') {
916             # change selected font to the generic (default) sans serif face
917 0           $face_name = $self->{' default-sansserif'}->{'face'};
918 0           $index = $self->{' default-sansserif'}->{'index'};
919             } elsif ($info{'face'} eq 'constant') {
920             # change selected font to the generic (default) constant width face
921 0           $face_name = $self->{' default-constant'}->{'face'};
922 0           $index = $self->{' default-constant'}->{'index'};
923             } elsif ($info{'face'} eq 'script') {
924             # change selected font to the generic (default) script face
925             # this is the only 'default' not initialized by Font Manager
926 0 0         if (defined $self->{' default-script'}->{'face'}) {
927 0           $face_name = $self->{' default-script'}->{'face'};
928 0           $index = $self->{' default-script'}->{'index'};
929             } else {
930 0           carp "get_font has no default set for 'script'. ignored.";
931 0           $index = $current_index; # face_name leave at current
932             }
933             } elsif ($info{'face'} eq 'symbol') {
934             # change selected font to the generic (default) symbol face
935 0           $face_name = $self->{' default-symbol'}->{'face'};
936 0           $index = $self->{' default-symbol'}->{'index'};
937             } else {
938             # info{face} must be a named face. search list of defined faces
939 0           $index = $self->_face2index($info{'face'});
940 0 0         if ($index >= 0) {
941 0           $face_name = $info{'face'};
942             } else {
943 0           carp "get_font can't find requested face '$info{'face'}'. ignored.";
944 0           $index = $current_index; # leave face_name unchanged
945             }
946             }
947             # if 'face' given, $face_name and $index are set
948            
949             } else {
950 0           $index = $current_index;
951             # face not defined, so use current face, possibly modified by
952             # italic or bold. $face_name is left at current, as is index
953             }
954              
955             # reset current font entry
956 0           $self->{' current-font'}->{'face'} = $face_name;
957             # $index is new face's index
958 0           $self->{' current-font'}->{'index'} = $index;
959             # italic flag given? info{italic}
960 0 0         if (defined $info{'italic'}) {
961 0           $current_italic = $info{'italic'};
962 0           $self->{' current-font'}->{'italic'} = $current_italic;
963             }
964             # bold flag given? info{bold}
965 0 0         if (defined $info{'bold'}) {
966 0           $current_bold = $info{'bold'};
967 0           $self->{' current-font'}->{'bold'} = $current_bold;
968             }
969              
970 0           my $type = $self->{' font-list'}->[$index]->{'type'};
971 0           my $style = $self->{' font-list'}->[$index]->{'style'};
972 0           my $which;
973 0 0         if ($style eq 'symbol') {
974 0           $which = 'symbol'; # currently no bold or italic for symbols
975             } else {
976 0 0         if ($current_italic) {
977 0 0         if ($current_bold) {
978 0           $which = 'bold-italic';
979             } else {
980 0           $which = 'italic';
981             }
982             } else {
983 0 0         if ($current_bold) {
984 0           $which = 'bold';
985             } else {
986 0           $which = 'roman';
987             }
988             }
989             }
990              
991             # assuming proper face and/or italic and/or bold, current-font updated
992 0 0         if (!defined $self->{' font-list'}->[$index]->{'file'}->{$which}) {
993             # requested a variant (bold, etc.) not available!
994             # just pick first one available (there is at least one)
995 0           my @keys = keys %{ $self->{' font-list'}->[$index]->{'file'} };
  0            
996 0           my $key = shift @keys;
997 0           carp "Requested unavailable variant for face $face_name. Use $key in its place.";
998 0           $which = $key;
999             }
1000              
1001 0           $font = $self->{' font-list'}->[$index]->{'entry'}->{$which};
1002             # already loaded this one?
1003 0 0         if (defined $font) { return $font; }
  0            
1004              
1005             # need to first load the new font
1006 0           my $file = $self->{' font-list'}->[$index]->{'file'}->{$which};
1007 0 0         if (!defined $file) { return $file; } # no file entry for these variants
  0            
1008              
1009 0           my $settings = $self->{' font-list'}->[$index]->{'settings'};
1010              
1011             # loop through font-paths list until find a file, or failure
1012 0 0         if ($type eq 'core') {
    0          
    0          
    0          
    0          
1013             # no paths to search for core fonts
1014 0           $font = $self->{' pdf'}->corefont($file, %$settings);
1015              
1016             } elsif ($type eq 'ttf') {
1017 0 0         if (ref($file) eq 'Font::TTF::Font') {
1018             # it's a Font::TTF::Font object, not a real file
1019             # may be used as input to ttfont() to get a real font out of it
1020 0           $font = $self->{' pdf'}->ttfont($file, %$settings);
1021             } else {
1022             # it's a regular real file
1023 0           foreach my $filepath ($self->_filepath($file)) {
1024 0 0 0       if (!(-f $filepath && -r $filepath)) { next; }
  0            
1025 0           $font = $self->{' pdf'}->ttfont($filepath, %$settings);
1026 0 0         if (defined $font) { last; }
  0            
1027             }
1028             }
1029              
1030             } elsif ($type eq 'type1') {
1031             # filepath is glyph file itself (.pfa or .pfb).
1032             # metrics file is specified as afmfile or pfmfile, subject to the
1033             # same search paths
1034 0           my @glyphs = $self->_filepath($file);
1035 0           my (@metrics, $met_type, $metricf, $filepath);
1036 0 0         if (defined $self->{' font-list'}->[$index]->{'settings'}->{'afmfile'}) {
    0          
1037 0           @metrics = $self->_filepath($self->{' font-list'}->[$index]->{'settings'}->{'afmfile'});
1038 0           $met_type = 'afmfile';
1039             } elsif (defined $self->{' font-list'}->[$index]->{'settings'}->{'pfmfile'}) {
1040 0           @metrics = $self->_filepath($self->{' font-list'}->[$index]->{'settings'}->{'pfmfile'});
1041 0           $met_type = 'pfmfile';
1042             } else {
1043 0           carp "get_font: metrics file (afmfile or pfmfile) not defined for Type1 font!";
1044 0           $met_type = '';
1045             }
1046 0           for (my $i = 0; $i < @glyphs; $i++) {
1047 0           $filepath = $glyphs[$i];
1048 0 0 0       if (!(-f $filepath && -r $filepath)) { next; }
  0            
1049 0           $metricf = $metrics[$i];
1050 0 0 0       if (!(-f $metricf && -r $metricf)) { next; }
  0            
1051 0 0         if ($met_type ne '') {
1052             # note that settings will still have an afmfile or pfmfile,
1053             # but met_type should override it (with the full path version)
1054 0           $font = $self->{' pdf'}->psfont($filepath, %$settings, $met_type => $metricf);
1055 0 0         if (defined $font) { last; }
  0            
1056             }
1057             }
1058              
1059             } elsif ($type eq 'cjk') {
1060 0           foreach my $filepath ($self->_filepath($file)) {
1061 0 0 0       if (!(-f $filepath && -r $filepath)) { next; }
  0            
1062 0           $font = $self->{' pdf'}->cjkfont($filepath, %$settings);
1063 0 0         if (defined $font) { last; }
  0            
1064             }
1065              
1066             } elsif ($type eq 'bdf') {
1067 0           foreach my $filepath ($self->_filepath($file)) {
1068 0 0 0       if (!(-f $filepath && -r $filepath)) { next; }
  0            
1069 0           $font = $self->{' pdf'}->bdfont($filepath, %$settings);
1070 0 0         if (defined $font) { last; }
  0            
1071             }
1072              
1073             } else {
1074             # TBD: synfont variants?
1075             }
1076              
1077 0 0         if (defined $font) {
1078             # cache it so we don't have to create another copy
1079 0           $self->{' font-list'}->[$index]->{'entry'}->{$which} = $font;
1080             } else {
1081 0           carp "get_font: unable to find or load $type font $file.";
1082             }
1083              
1084 0           return $font; # undef if unable to find or successfully load
1085             } # end of get_font()
1086              
1087             # input: face name
1088             # output: index of array element with matching face, -1 if no match
1089             sub _face2index {
1090 0     0     my ($self, $face) = @_;
1091              
1092 0           for (my $index = 0; $index < scalar(@{$self->{' font-list'}}); $index++) {
  0            
1093 0 0         if ($self->{' font-list'}->[$index]->{'face'} eq $face) { return $index; }
  0            
1094             }
1095              
1096 0           return -1; # failed to match
1097             }
1098              
1099             # input: file name (may include full or partial path)
1100             # output: list of file name appended to each font-paths entry
1101             sub _filepath {
1102 0     0     my ($self, $file) = @_;
1103              
1104             # if absolute path or dotted relative path, use as-is
1105 0 0         if (substr($file, 0, 1) eq '/') { return $file; }
  0            
1106 0 0         if (substr($file, 0, 2) eq './') { return $file; }
  0            
1107 0 0         if (substr($file, 0, 3) eq '../') { return $file; }
  0            
1108 0 0         if ($file =~ m#^[a-z]:/#i) { return $file; } # Windows drive letter
  0            
1109             # .../ actually go up one from font-path (trim to ../, prepend path/)
1110 0 0         if (substr($file, 0, 4) eq '.../') { $file = substr($file, 1); }
  0            
1111              
1112 0           my @out_list = @{ $self->{' font-paths'} };
  0            
1113 0           for (my $i = 0; $i < @out_list; $i++) {
1114             # we know that file does NOT start with a /, so append / to
1115             # font-path element if missing, before appending file
1116 0 0         if (substr($out_list[$i], -1, 1) eq '/') {
1117 0           $out_list[$i] .= $file;
1118             } else {
1119 0           $out_list[$i] .= "/$file";
1120             }
1121             }
1122              
1123 0           return @out_list;
1124             }
1125              
1126             =head2 get_external_font
1127              
1128             $rc = $pdf->get_external_font($text)
1129              
1130             =over
1131              
1132             If the user has already defined a font outside of C<FontManager>, in the
1133             C<$text> text context, this call permits it to be retrieved as the
1134             I<current font>, named B<-external->. If no font has been defined already,
1135             nothing is changed and the return code is 1.
1136              
1137             If C<$text-E<gt>{' font'}> has been defined, that font is stored in the
1138             internal cache (as an "already read" font) in a new "-external-" font, and
1139             it is made the current font. The return code is 0.
1140              
1141             If there is no existing preloaded font,
1142             nothing is done and the return code is 1.
1143              
1144             This is a way for those using "markdown" formatting to define the font used,
1145             as an alternative to using C<'style'=E<gt>'body { font-family: ... '}> to
1146             define the body font.
1147              
1148             =back
1149              
1150             =cut
1151              
1152             sub get_external_font {
1153 0     0 1   my ($self, $text) = @_;
1154              
1155 0 0         if (!defined $text->{' font'}) {
1156             # there is no existing font defined
1157 0           return 1;
1158             }
1159 0           my $font = $text->{' font'};
1160             # does -external- already exist? search list of defined faces
1161 0           my $index = $self->_face2index('-external-');
1162             # $index == -1 if not found
1163              
1164 0 0         if ($index == -1) {
1165             # not yet added
1166 0           $self->add_font(
1167             'face' => '-external-', # special reserved name
1168             'type' => '?', # we know nothing about the actual font!
1169             'style' => '?',
1170             'width' => '?',
1171             # will never be looking at for a filepath
1172             'file' => { 'roman' => '?',
1173             'italic' => '?',
1174             'bold' => '?',
1175             'bold-italic' => '?' }
1176             );
1177 0           $index = $self->_face2index('-external-');
1178             }
1179              
1180             # -external- exists at $index, update $font entries
1181             # unlike regular fonts, all variants point to the same font entry
1182 0           foreach my $key (qw/roman italic bold bold-italic/) {
1183 0           $self->{' font-list'}->[$index]->{'entry'}->{$key} = $font;
1184             }
1185             # set current font to -external-. italic and bold irrelevant
1186 0           $self->{' current-font'} = {'face' => '-external-', 'index' => $index,
1187             'italic' => 0, 'bold' => 0};
1188              
1189 0           return 0;
1190             } # end of get_external_font()
1191              
1192             =head2 dump_font_tables
1193              
1194             $pdf->dump_font_tables()
1195              
1196             =over
1197              
1198             Print (to STDOUT) all the Font Manager font information on hand.
1199              
1200             =back
1201              
1202             =cut
1203              
1204             # a debug routine to dump everything about defined fonts
1205             sub dump_font_tables {
1206 0     0 1   my $self = shift;
1207              
1208             # dump font table
1209 0           print "-------------------- fonts\n";
1210 0           for (my $i = 0; $i < @{ $self->{' font-list'} }; $i++) {
  0            
1211 0           print " font table entry ".($i+1).":\n";
1212              
1213 0           print " face = '".($self->{' font-list'}->[$i]->{'face'})."'\n";
1214             #print " italic flag = ".($self->{' font-list'}->[$i]->{'italic'})."\n";
1215             #print " bold flag = ".($self->{' font-list'}->[$i]->{'bold'})."\n";
1216 0           print " type = '".($self->{' font-list'}->[$i]->{'type'})."'\n";
1217 0           print " settings = {\n";
1218 0           my @keys = keys %{ $self->{' font-list'}->[$i]->{'settings'} };
  0            
1219 0           foreach my $key (@keys) {
1220 0           print " $key => '".($self->{' font-list'}->[$i]->{'settings'}->{$key})."'\n";
1221             }
1222 0           print " }\n";
1223 0           print " style = '".($self->{' font-list'}->[$i]->{'style'})."'\n";
1224 0           print " width = '".($self->{' font-list'}->[$i]->{'width'})."'\n";
1225              
1226             # what variants are defined?
1227 0           print " files = {\n";
1228 0           @keys = keys %{ $self->{' font-list'}->[$i]->{'file'} };
  0            
1229 0           foreach my $key (@keys) {
1230 0           print " $key => '".($self->{' font-list'}->[$i]->{'file'}->{$key})."',";
1231 0 0         if (defined $self->{' font-list'}->[$i]->{'entry'}->{$key}) {
1232 0           print " [font HAS been loaded]\n";
1233             } else {
1234 0           print " [font has NOT been loaded]\n";
1235             }
1236             }
1237 0           print " }\n";
1238             }
1239              
1240             # dump font path list
1241 0           print "-------------------- font search paths\n";
1242 0           for (my $i = 0; $i < @{ $self->{' font-paths'} }; $i++) {
  0            
1243 0           print " path ".($i+1).": ".($self->{' font-paths'}->[$i])."\n";
1244             }
1245              
1246             # dump current font
1247 0           print "-------------------- current font\n";
1248 0           print " face = ".($self->{' current-font'}->{'face'})."\n";
1249 0           print " index = ".($self->{' current-font'}->{'index'})."\n";
1250 0           print " italic flag = ".($self->{' current-font'}->{'italic'})."\n";
1251 0           print " bold flag = ".($self->{' current-font'}->{'bold'})."\n";
1252              
1253             # dump current defaults
1254 0           print "-------------------- current defaults\n";
1255 0           print " default font: face = '".($self->{' default-font'}->{'face'})."',";
1256 0           print " index = ".($self->{' default-font'}->{'index'})."\n";
1257 0           print " default serif font: face = '".($self->{' default-serif'}->{'face'})."',";
1258 0           print " index = ".($self->{' default-serif'}->{'index'})."\n";
1259 0           print " default sans serif font: face = '".($self->{' default-sansserif'}->{'face'})."',";
1260 0           print " index = ".($self->{' default-sansserif'}->{'index'})."\n";
1261 0           print " default constant width font: face = '".($self->{' default-constant'}->{'face'})."',";
1262 0           print " index = ".($self->{' default-constant'}->{'index'})."\n";
1263 0           print " default symbol font: face = '".($self->{' default-symbol'}->{'face'})."',";
1264 0           print " index = ".($self->{' default-symbol'}->{'index'})."\n";
1265             # no script font loaded by default
1266 0 0         if (defined $self->{' default-script'}->{'face'}) {
1267 0           print " default script font: face = '".($self->{' default-script'}->{'face'})."',";
1268 0           print " index = ".($self->{' default-script'}->{'index'})."\n";
1269             } else {
1270 0           print " no default script font defined\n";
1271             }
1272              
1273             # lots of output once 'entry' points start getting filled!
1274             #use Data::Dumper;
1275             #print Dumper($self->{' font-list'});
1276              
1277 0           return;
1278             } # end of dump_font_tables()
1279              
1280             1;