File Coverage

blib/lib/Font/GlyphNames.pm
Criterion Covered Total %
statement 138 138 100.0
branch 90 94 95.7
condition 5 6 83.3
subroutine 14 14 100.0
pod 6 6 100.0
total 253 258 98.0


line stmt bran cond sub pod time code
1             package Font::GlyphNames;
2              
3             require 5.008;
4 2     2   89783 use strict;
  2         5  
  2         70  
5 2     2   12 use warnings;
  2         3  
  2         78  
6              
7 2     2   1790 use File::Spec::Functions 'catfile';
  2         2184  
  2         194  
8 2     2   4344 use Encode 'decode';
  2         49436  
  2         676  
9              
10             require Exporter;
11              
12             our($VERSION) = '1.00000';
13             our(@ISA) = 'Exporter';
14             our(@EXPORT_OK) = qw[
15             name2str
16             name2ord
17             str2name
18             ord2name
19             ord2ligname
20             ];
21             our %EXPORT_TAGS = (all => \@EXPORT_OK);
22              
23             our $_obj; # object used by the function-oriented interface
24             our @LISTS = qw[ zapfdingbats.txt
25             glyphlist.txt ];
26             our @PATH = split /::/, __PACKAGE__;
27              
28 2         11 use subs qw[
29             _read_glyphlist
30 2     2   2068 ];
  2         61  
31              
32              
33             =encoding utf-8
34              
35             =head1 NAME
36              
37             Font::GlyphNames - Convert between glyph names and characters
38              
39             =head1 VERSION
40              
41             Version 1.00000
42              
43             =head1 SYNOPSIS
44              
45             use Font::GlyphNames qw[
46             name2str
47             name2ord
48             str2name
49             ord2name
50             ord2ligname
51             ];
52             # or:
53             use Font::GlyphNames ':all';
54            
55             name2str qw[one two three s_t Psi uni00D4];
56             name2ord qw[one two three s_t Psi uni00D4];
57             str2name qw[1 2 3 st Ψ Ô];
58             ord2name qw[49 50 51 115 116 936 212];
59             ord2ligname qw[49 50 51 115 116 936 212];
60              
61             # Or you can use the OO interface:
62            
63             use Font::GlyphNames;
64            
65             $gn = new Font::GlyphNames; # use default glyph list
66             $gn = new Font::GlyphNames 'my-glyphs.txt'; # custom list
67              
68             $gn->name2ord(qw[ a slong_slong_i s_t.alt ]);
69             # etc.
70            
71             =head1 DESCRIPTION
72              
73             This module uses the Adobe Glyph Naming convention (see L) for converting
74             between glyph names and characters (or character codes).
75              
76             =head1 METHODS/FUNCTIONS
77              
78             Except for C (which is only a method), each item listed
79             here is
80             both a function and a method.
81              
82             =over 4
83              
84             =item new ( LIST )
85              
86             This class method constructs and returns a new Font::GlyphNames object.
87             If an error occurs, it returns undef (check C<$@> for the error; note
88             also that C clobbers any existing value of C<$@>, whether there
89             is an error or not). LIST is a
90             list of files to use as a glyph list. If LIST is
91             omitted, the Zapf Dingbats Glyph List and the Adobe
92             Glyph List (see L) will be used instead.
93              
94             =item new \%options
95              
96             C can also take a hashref of options, which are as follows:
97              
98             =over 4
99              
100             =item lists
101              
102             =item list
103              
104             (You can specify it with or without the 's'.) Either the name of the file
105             containing the glyph list, or a reference to an array of file names. In
106             fact, if you want an object with no glyph list (not that you would), you
107             can use S [] >>>.
108              
109             =item search_inc
110              
111             If this is set to true, 'Font/GlyphNames/' will be added to the beginning
112             of each file name, and the files will then be searched for in the folders
113             listed in C<@INC>.
114              
115             =item substitute
116              
117             Set this to a string that you want C to output for each invalid
118             glyph name. The default is C. (Actually, it doesn't have to be a
119             string; it could be anything, but it will be stringified if C is
120             called in scalar context with more than one argument.)
121              
122             =back
123              
124             =cut
125              
126             sub new {
127 11 100   11 1 66 my($class, $self, $search_inc) = (@_ ? shift : __PACKAGE__, {});
128 11         21 my(@lists,$found_list);
129 11 100 100     87 if(@_ and ref $_[0] eq 'HASH') {
    100          
130 4         8 for (qw 'lists list') {
131 8 100       29 next unless exists $_[0]{$_};
132 3         4 ++$found_list;
133 1         4 push @lists, ref $_[0]{$_} eq 'ARRAY'
134 3 100       17 ? @{$_[0]{$_}}
135             : $_[0]{$_};
136             }
137 4 100       16 $search_inc = delete $_[0]{search_inc} if $found_list;
138 4         17 $$self{subst} = delete $_[0]{substitute};
139             }
140             elsif(@_) {
141 1         2 $found_list++;
142 1         4 @lists = @_;
143             }
144 11 100       34 unless($found_list) {
145 7         11 @lists = @{$search_inc = 1, \@LISTS};
  7         31  
146             }
147              
148             # read the glyph list(s) into $self;
149 11         38 $$self{name2ord} = {};
150 11         27 $$self{str2name} = {};
151 11         27 for my $file (@lists) {
152 17         113 my(@h,$fh);
153            
154 17 100       43 if($search_inc) {
155 16         18 my $f;
156             # I pilfered this code from Unicode::Collate (and
157             # modified it slightly).
158 16         39 for (@INC) {
159 53         321 $f = catfile $_, @PATH, $file;
160 53 100       2194 last if open $fh, $f;
161 38         78 $f = undef;
162             }
163 16 100       68 defined $f or
164             $@ = __PACKAGE__ . ": Can't locate " .
165             catfile(@PATH, $file) .
166             " in \@INC (\@INC contains @INC).\n",
167             return
168             }
169             else {
170 1 50       19 open $fh, $file
171             or $@= "$file could not be opened: $!",
172             return
173             }
174            
175 16         41 local *_;
176 16         21 my $line; for ($line) {
  16         38  
177 16         387 while (<$fh>) {
178 31541 100       99518 next if /^\s*(?:#|\z)/;
179 31382         35871 s/^\cj//; # for Mac Classic compatibility
180 31382 50       150539 /^([^;]+);\s*([0-9a-f][0-9a-f\s]+)\z/i
181             or $@ = "Invalid glyph list line in $file: $_",
182             return;
183 31382         212407 my($name,$codes) = ($1,[map hex, split ' ', $2]);
184 31382 50       177923 exists $$self{name2ord}{$name} or
185             $$self{name2ord}{$name} = $codes;
186 31382 100       52973 if(@$codes == 1) {
187 30813         58610 my $key = chr $$codes[0];
188 30813 100       220630 exists $$self{str2name}{$key} or
189             $$self{str2name}{$key} = $name;
190             } else {
191 569         2042 my $key = join '', map chr, @$codes;
192 569 100       3604 exists $$self{str2name}{$key}
193             or $$self{str2name}{$key} = $name
194             }
195             }}
196             }
197 10         28 $ @= '';
198            
199 10         134 bless $self, $class;
200             }
201              
202             =item name2str ( LIST )
203              
204             LIST is a list of glyph names. This function returns a list of the
205             string equivalents of the glyphs in list context. In scalar context the
206             individual elements of the list are concatenated. Invalid glyph
207             names and names beginning with a dot (chr 0x2E) produce undef. Some
208             examples:
209              
210             name2str 's_t' # returns 'st'
211             name2str qw/Psi uni00D4/ # returns ("\x{3a8}", "\xd4")
212             name2str '.notdef' # returns undef
213             name2str 'uni12345678' # returns "\x{1234}\x{5678}"
214             name2str qw/one uni32 three/ # returns ('1', undef, '3')
215              
216             If, for invalid glyph names, you would like something other than undef
217             (the null char, for instance), you can either use the OO interface and the
218             C option to L, or replace it afterwards like this:
219              
220             map +("\0",$_)[defined], name2str ...
221              
222             =cut
223              
224             sub name2str {
225 72     72 1 19616 my $self = &_get_self;
226 72         202 my(@names,@ret,$str) = @_;
227 72         150 for(@names) {
228 141         287 s/\..*//s;
229 141         169 $str = undef;
230 141         680 for (split /_/) {
231             # Here we check each type of glyph name
232 154 100       6116 if (exists $$self{name2ord}{$_}) {
    100          
    100          
233 32         193 $str .= join '', map chr,
234 32         38 @{$$self{name2ord}{$_}};
235             }
236             elsif (/^uni(
237             (?: #non-surrogate codepoints:
238             [0-9A-CEF][0-9A-F]{3}
239             |
240             D[0-7][0-9A-F]{2}
241             )+
242             )\z/x) {
243 39         238 $str .= decode 'UTF-16BE', pack 'H*', $1;
244             }
245             elsif (/^u(
246             0{0,2}[0-9A-CEF][0-9A-F]{3}
247             |
248             0{0,2}D[0-7][0-9A-F]{2}
249             |
250             (?:0?(?!0)|1(?=0))[0-9A-F]{5}
251             )\z/x) {
252 39         214 $str .= chr hex $1;
253             }
254             else {
255 2     2   2244 no warnings 'uninitialized';
  2         4  
  2         213  
256 44 50       154 defined $str ? $str .= $$self{subst} :
257             ($str = $$self{subst});
258             }
259             }
260 141 100       1054 push @ret, defined $str ? $str : $$self{subst};
261             }
262 2     2   16 no warnings 'uninitialized';
  2         4  
  2         2617  
263 72 100       569 wantarray ? @ret : @ret > 1 ? join '', @ret : $ret[-1];
    100          
264             }
265              
266              
267             =item name2ord ( LIST )
268              
269             LIST is a list of glyph names. This function returns a list of the
270             character codes that the glyphs represent. If called in scalar context
271             with more than one argument, the behaviour is undefined (and subject to
272             change in future releases). Invalid glyph
273             names and names beginning with a dot (chr 0x2E) produce -1. Some
274             examples:
275              
276             name2ord 's_t' # returns 115, 116
277             name2ord qw/Psi uni00D4/ # returns 0x3a8, 0xd4
278             name2ord '.notdef' # returns -1
279             name2ord 'uni12345678' # returns 0x1234, 0x5678
280             name2ord qw/one uni32 three/ # returns 49, -1, 51
281              
282             =cut
283              
284             sub name2ord {
285 24     24 1 79 my $self = &_get_self;
286 24         59 my(@names,@ret) = @_;
287 24         80 for(@names) {
288 42         87 s/\..*//s;
289 42 100       90 $_ = ' ' unless $_; # make sure split returns something
290 42         102 for (split /_/) {
291             # Here we check each type of glyph name
292             # It would be nice to avoid duplicating this logic,
293             # but I think it runs faster this way.
294 50 100       281 if (exists $$self{name2ord}{$_}) {
    100          
    100          
295 9         13 push @ret, @{$$self{name2ord}{$_}};
  9         34  
296             }
297             elsif (/^uni(
298             (?: #non-surrogate codepoints:
299             [0-9A-CEF][0-9A-F]{3}
300             |
301             D[0-7][0-9A-F]{2}
302             )+
303             )\z/x) {
304 12         66 push @ret, unpack 'n*', pack 'H*', $1;
305             }
306             elsif (/^u(
307             0{0,2}[0-9A-CEF][0-9A-F]{3}
308             |
309             0{0,2}D[0-7][0-9A-F]{2}
310             |
311             (?:0?(?!0)|1(?=0))[0-9A-F]{5}
312             )\z/x) {
313 12         46 push @ret, hex $1;
314             }
315             else {
316 17         54 push @ret, -1;
317             }
318             }
319             }
320 24 100       202 @ret == 1 ? $ret[-1] : @ret ;
321             }
322              
323              
324             =item str2name ( LIST )
325              
326             LIST is a list of strings. This function returns a list of glyph names that
327             correspond to all the arguments passed to it. If a string is more than one
328             character long, the resulting glyph name will be a ligature name. An empty
329             string will return '.notdef'. If called
330             in scalar context
331             with more than one argument, the behaviour is undefined (and subject to
332             change in future releases).
333              
334             str2name 'st' # returns 's_t'
335             str2name "\x{3a8}", "\xd4" # returns qw/Psi Ocircumflex/
336             str2name "\x{3a8}\xd4" # returns 'Psi_Ocircumflex'
337             str2name "\x{1234}\x{5678}" # returns 'uni12345678'
338             str2name "\x{05D3}\x{05B9}" # returns 'daletholam'
339              
340             =cut
341              
342             sub str2name {
343 20     20 1 3941 my $self = &_get_self;
344 20         102 my(@strs,@ret) = @_;
345 20         26 my $map = $$self{str2name};
346 20         35 for(@strs) {
347 36 100       105 if(length > 1) {
    100          
348 20 100       47 if (exists $$map{$_}) {
349 4         13 push @ret, $$map{$_};
350             }else{
351 16         20 my @components;
352             my $uni_component; # whether the previous
353 16         40 for(split //) { # component was a ‘uni-’
354 44 100       132 if (exists $$map{$_}){
    100          
    100          
355 12         21 push @components,
356             $$map{$_} ;
357 12         23 $uni_component =0;
358             } elsif((my $ord = ord) > 0xffff) {
359 4         11 push @components,
360             sprintf "u%X",$ord;
361 4         9 $uni_component =0;
362             } elsif($uni_component) {
363 16         43 $components[-1] .=
364             sprintf"%04X",ord;
365             } else {
366 12         30 push @components,
367             sprintf"uni%04X",
368             ord;
369 12         19 ++$uni_component;
370             }
371             }
372 16         51 push @ret, join '_', @components;
373             }
374             }
375             elsif(length) {
376 12         14 my $ord = ord;
377 12 100       76 push @ret, exists $$map{$_}
    100          
378             ? $$map{$_}
379             : sprintf $ord > 0xffff ?"u%X":"uni%04X",
380             $ord;
381 4         17 }else { push @ret, '.notdef' }
382             }
383 20 100       152 @ret == 1 ? $ret[-1] : @ret ;
384             }
385              
386              
387             =item ord2name ( LIST )
388              
389             LIST is a list of character codes. This function returns a list of glyph
390             names that
391             correspond to all the arguments passed to it. If called
392             in scalar context
393             with more than one argument, the behaviour is undefined (and subject to
394             change in future releases).
395              
396             ord2name 115 # returns 's'
397             ord2name 0x3a8, 0xd4 # returns 'Psi', 'Ocircumflex'
398             ord2name 0x1234, 0x5678 # returns 'uni1234', 'uni5678'
399              
400             =cut
401              
402             sub ord2name {
403 8     8 1 4268 my $self = &_get_self;
404 8         22 my(@codes,@ret) = @_;
405 8         11 my $map = $$self{str2name};
406 8         21 for(@codes) {
407 12         31 my $char = chr;
408 12 100       68 push @ret, exists $$map{$char}
    100          
409             ? $$map{$char}
410             : sprintf $_ > 0xffff ?"u%X":"uni%04X",
411             $_;
412             }
413 8 100       65 @ret == 1 ? $ret[-1] : @ret ;
414             }
415              
416              
417             =item ord2ligname ( LIST )
418              
419             LIST is a list of character codes. This function returns a glyph
420             name for a ligature that
421             corresponds to the arguments passed to it, or '.notdef' if there are none.
422              
423             ord2ligname 115, 116 # returns 's_t'
424             ord2ligname 0x3a8, 0xd4 # returns 'Psi_Ocircumflex'
425             ord2ligname 0x1234, 0x5678 # returns 'uni12345678'
426             ord2ligname 0x05D3, 0x05B9 # returns 'daletholam'
427              
428             =cut
429              
430             sub ord2ligname {
431 20     20 1 4891 my $self = &_get_self;
432 20         101 my(@codes) = @_;
433 20         41 my $map = $$self{str2name};
434 20         118 my $str = join '', map chr, @codes;
435 20 100       122 exists $$map{$str} and return $$map{$str};
436 16         25 my @components;
437             my $uni_component; # whether the previous
438 16         32 for(@codes) { # component was a ‘uni-’
439 44         68 my $char = chr;
440 44 100       148 if (exists $$map{$char}){
    100          
    100          
441 16         37 push @components,
442             $$map{$char} ;
443 16         28 $uni_component =0;
444             } elsif( $_ > 0xffff ) {
445 6         17 push @components,
446             sprintf "u%X",$_;
447 6         15 $uni_component =0;
448             } elsif($uni_component) {
449 12         36 $components[-1] .=
450             sprintf"%04X",$_;
451             } else {
452 10         38 push @components,
453             sprintf"uni%04X",
454             $_;
455 10         17 ++$uni_component;
456             }
457             }
458 16 100       138 return @components ? join '_', @components : '.notdef';
459             }
460              
461              
462             =back
463              
464             =cut
465            
466              
467              
468              
469             #----------- A PRIVATE SUBROUTINE ---------------#
470              
471             # _get_self helps the methods act as functions as well.
472             # Each function should call it thusly:
473             # my $self = &_get_self;
474             # The object (if any) will be shifted off @_.
475             # If there was no object in @_, $self will refer to $_obj (a
476             # package var.)
477              
478             sub _get_self {
479 144 100 66 144   923 UNIVERSAL::isa($_[0], __PACKAGE__)
480             ? shift
481             : ($_obj ||= new);
482             }
483              
484              
485             #----------- THE REST OF THE DOCUMENTATION ---------------#
486              
487             =pod
488              
489             =head1 THE GLYPH LIST FILE FORMAT
490              
491             B This section is not intended to be normative. It simply
492             describes how this module parses glyph list files--which works with
493             those provided by Adobe.
494              
495             All lines that consist solely of
496             whitespace or that have a sharp sign (#) preceded only by whitespace
497             (if any) are ignored. All others lines must consist of the glyph name
498             followed by a semicolon, and the character numbers in hex, separated
499             and optionally
500             surrounded by whitespace. If there are multiple character numbers, the
501             glyph is understood to represent a sequence of characters. The line
502             breaks must be either CRLF sequences
503             (as in
504             Adobe's
505             lists) or native line breaks.
506             If a glyph name occurs more than once, the first instance
507             will be
508             used.
509              
510              
511             =head1 COMPATIBILITY
512              
513             This module requires perl 5.8.0 or later.
514              
515             =head1 BUGS
516              
517             Please e-mail me if you find any.
518              
519             =head1 AUTHOR & COPYRIGHT
520              
521             Copyright (C) 2006-8, Father Chrysostomos
522             period o r g]>
523              
524             =head1 SEE ALSO
525              
526             =over 4
527              
528             =item B
529              
530             L
531              
532             =item B
533              
534             L
535              
536             =item B
537              
538             L
539              
540             =item B
541              
542             L
543              
544             =cut
545              
546              
547              
548