File Coverage

blib/lib/HarfBuzz/Shaper.pm
Criterion Covered Total %
statement 74 120 61.6
branch 15 40 37.5
condition 9 25 36.0
subroutine 13 20 65.0
pod 14 14 100.0
total 125 219 57.0


line stmt bran cond sub pod time code
1             #! perl
2              
3             package HarfBuzz::Shaper;
4              
5 4     4   332828 use 5.010001;
  4         38  
6 4     4   22 use strict;
  4         16  
  4         104  
7 4     4   22 use warnings;
  4         9  
  4         136  
8 4     4   23 use Carp;
  4         6  
  4         267  
9 4     4   2505 use Encode;
  4         43878  
  4         5149  
10              
11             our $VERSION = '0.024';
12              
13             require XSLoader;
14             XSLoader::load('HarfBuzz::Shaper', $VERSION);
15              
16             =head1 NAME
17              
18             HarfBuzz::Shaper - Use HarfBuzz for text shaping
19              
20             =head1 SYNOPSIS
21              
22             use HarfBuzz::Shaper;
23             my $hb = HarfBuzz::Shaper->new;
24             $hb->set_font('LiberationSans.ttf');
25             $hb->set_size(36);
26             $hb->set_text("Hello!");
27             my $info = $hb->shaper;
28              
29             The result is an array of hashes, one element for each glyph to be typeset.
30              
31             =head1 DESCRIPTION
32              
33             HarfBuzz::Shaper is a perl module that provides access to a small
34             subset of the native HarfBuzz library.
35              
36             The subset is suitable for typesetting programs that need to deal with
37             complex languages like Devanagari, Hebrew or Arabic.
38              
39             This module is intended to be used with module L. Feel
40             free to (ab)use it for other purposes.
41              
42             Following the above example, the returned info is an array of hashes,
43             one element for each glyph to be typeset. The hash contains the
44             following items:
45              
46             ax: horizontal advance
47             ay: vertical advance
48             dx: horizontal offset
49             dy: vertical offset
50             g: glyph index in font (CId)
51             name: glyph name
52              
53             Note that the number of glyphs does not necessarily match the number
54             of input characters!
55              
56             =head1 DISCLAIMER
57              
58             This module provides a thin interface layer between Perl and the
59             native HarfBuzz library. It is agnostic with regard to the details of
60             multi-language typesetting. HarfBuzz has a friendly community to help
61             you.
62              
63             L
64              
65             =head1 METHODS
66              
67             =head2 $hb = HarfBuzz::Shaper->new( [ options ] )
68              
69             Creates a new shaper object.
70              
71             Options:
72              
73             =over 4
74              
75             =item *
76              
77             B > I
78              
79             =item *
80              
81             B > I
82              
83             =back
84              
85             =cut
86              
87             sub new {
88 3     3 1 407 my ( $pkg, $opts ) = @_;
89              
90 3   50     30 $opts //= {};
91              
92 3         10 my $self = bless {} => $pkg;
93 3         89 $self->{harfbuzz} = hb_version_string();
94 3         325 $self->{buffer} = hb_buffer_create();
95 3         14 $self->{features} = [];
96              
97 3 50       14 if ( $opts->{font} ) {
98 0         0 $self->set_font( delete $opts->{font} );
99             }
100 3 50       12 if ( $opts->{size} ) {
101 0         0 $self->set_size( delete $opts->{size} );
102             }
103              
104 3         14 return $self;
105             }
106              
107             =head2 $hb->reset( [ I ] )
108              
109             Reset (clear) the buffer settings for font, size, language, direction
110             and script. With I, also clears the font cache.
111              
112             =cut
113              
114             sub reset {
115 0     0 1 0 my ( $self, $full ) = @_;
116              
117 0         0 for ( qw ( font size text language direction script ) ) {
118 0         0 delete $self->{$_};
119             }
120 0 0       0 if ( $full ) {
121 0         0 for ( keys %$self ) {
122 0 0       0 next unless /^(font|face)_/;
123 0         0 delete $self->{$_};
124             }
125 0         0 hb_buffer_reset( $self->{buffer} );
126             # So basically we are like freshly created.
127             }
128              
129 0         0 $self;
130             }
131              
132             =head2 $hb->set_font( I [ , I ] )
133              
134             Explicit way to set the font (and, optionally, the size) used for
135             shaping.
136              
137             The settings persist across shaper() calls. Call without arguments to
138             remove the settings.
139              
140             The font must be a TrueType or OpenType font. Font information is
141             cached internally, after the first call subsequent calls with the same
142             font filename are very fast.
143              
144             =cut
145              
146             sub set_font {
147 3     3 1 30 my ( $self, $fontfile, $size ) = @_;
148              
149 3 50 33     14 unless ( defined $fontfile or defined $size ) {
150 0         0 delete $self->{font};
151 0         0 delete $self->{size};
152 0         0 return $self;
153             }
154              
155 3 50       65 croak("$fontfile: $!\n") unless -s -r $fontfile;
156 3         649 my $blob = hb_blob_create_from_file($fontfile);
157 3   33     338 my $face = $self->{"face_$fontfile"} //= hb_face_create( $blob, 0 );
158 3   33     53 $self->{font} = $self->{"font_$fontfile"} //= do {
159             # hb_font_create should default to OT.
160 3         329 my $font = hb_font_create( $face );
161 3         32 hb_ot_font_set_funcs($font);
162 3         16 $font;
163             };
164 3 50       12 $self->set_size($size) if $size;
165              
166 3         19 $self;
167             }
168              
169             =head2 $hb->set_size( I )
170              
171             Explicit way to set the font size used for shaping.
172              
173             Note that the font size will in general affect details of the
174             appearance, A 5 point fontsize magnified 10 times is not identical to
175             50 point font size.
176              
177             The setting persist across shaper() calls. Call without arguments to
178             remove the setting.
179              
180             =cut
181              
182             sub set_size {
183 3     3 1 27 my ( $self, $size ) = @_;
184              
185 3 50       21 unless ( defined $size ) {
186 0         0 delete $self->{size};
187 0         0 return $self;
188             }
189              
190 3         10 $self->{size} = $size;
191              
192 3         7 $self;
193             }
194              
195             =head2 $hb->set_text( I [ , ... ] )
196              
197             Sets the text to shape. Multiple arguments are concatenated.
198              
199             Note that the text must be Perl strings.
200              
201             The setting persist across shaper() calls. Call without arguments to
202             remove the setting.
203              
204             =cut
205              
206             sub set_text {
207 3     3 1 24 my ( $self, @text ) = @_;
208              
209 3 50 33     22 unless ( @_ > 1 and defined $text[0] ) {
210 0         0 delete $self->{text};
211 0         0 return $self;
212             }
213              
214 3         16 $self->{text} = join( "", @text );
215              
216 3         9 $self;
217             }
218              
219             =head2 $hb->set_features( I [ , ... ] )
220              
221             Sets persistent features for shaping. Features are strings as described in
222             L
223             and
224             L.
225              
226             Multiple feature strings may be supplied.
227              
228             Call without arguments to remove the persistent features.
229              
230             =cut
231              
232             sub set_features {
233 1     1 1 705 my ( $self ) = shift;
234 1         4 $self->{features} = [];
235 1 50 33     11 $self->add_features(@_) if @_ && defined($_[0]);
236 1         2 return $self;
237             }
238              
239             =head2 $hb->add_features( I [ , ... ] )
240              
241             Just like set_features, but the specified features are I to the
242             set of persistent features.
243              
244             =cut
245              
246             sub add_features {
247 1     1 1 4 my ( $self, @features ) = @_;
248 1         3 foreach my $feature ( @features ) {
249 1   33     2 push( @{ $self->{features} },
  1         17  
250             hb_feature_from_string($feature)
251             || croak("Unknown shaper feature: \"$feature\"") );
252             }
253             }
254              
255             =head2 $hb->set_language( I )
256              
257             Sets the language for shaping. I must be a string containing a
258             valid BCP-47 language code.
259              
260             The setting persist across shaper() calls. Call without arguments to
261             remove the setting.
262              
263             =cut
264              
265             sub set_language {
266 0     0 1 0 my ( $self, $lang ) = @_;
267              
268 0 0       0 unless ( defined $lang ) {
269 0         0 delete $self->{language};
270 0         0 return $self;
271             }
272              
273 0         0 $self->{language} = $lang;
274             # This is merely for checking validity;
275 0         0 hb_buffer_set_language( $self->{buffer}, $lang );
276             }
277              
278             =head2 $hb->get_language
279              
280             Returns the language currently set for this shaper, as a string.
281              
282             When called after a successful shaper() call, it returns the actual
283             value used by shaper().
284              
285             =cut
286              
287             sub get_language {
288 0     0 1 0 my ( $self ) = @_;
289 0         0 hb_buffer_get_language( $self->{buffer} );
290             }
291              
292             =head2 $hb->set_script( I