| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package PDF::Make::Builder::Text; |
|
2
|
42
|
|
|
42
|
|
246
|
use strict; |
|
|
42
|
|
|
|
|
56
|
|
|
|
42
|
|
|
|
|
1188
|
|
|
3
|
42
|
|
|
42
|
|
149
|
use warnings; |
|
|
42
|
|
|
|
|
54
|
|
|
|
42
|
|
|
|
|
1443
|
|
|
4
|
42
|
|
|
42
|
|
136
|
use Object::Proto; |
|
|
42
|
|
|
|
|
51
|
|
|
|
42
|
|
|
|
|
3210
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
BEGIN { |
|
7
|
42
|
|
|
42
|
|
3706
|
Object::Proto::define('PDF::Make::Builder::Text', |
|
8
|
|
|
|
|
|
|
'text:Str:required', |
|
9
|
|
|
|
|
|
|
'align:Str:default(left)', |
|
10
|
|
|
|
|
|
|
'indent:Int:default(0)', |
|
11
|
|
|
|
|
|
|
'padding:Num:default(0)', |
|
12
|
|
|
|
|
|
|
'spacing:Num:default(0)', |
|
13
|
|
|
|
|
|
|
'pad:Str', |
|
14
|
|
|
|
|
|
|
'pad_end:Str', |
|
15
|
|
|
|
|
|
|
'margin:Num:default(5)', |
|
16
|
|
|
|
|
|
|
'overflow:Bool:default(0)', |
|
17
|
|
|
|
|
|
|
'font:HashRef', |
|
18
|
|
|
|
|
|
|
'x:Num', 'y:Num', 'w:Num', 'h:Num', |
|
19
|
|
|
|
|
|
|
'end_w:Num:default(0)', |
|
20
|
|
|
|
|
|
|
'end_y:Num:default(0)', |
|
21
|
|
|
|
|
|
|
); |
|
22
|
42
|
|
|
|
|
41108
|
Object::Proto::import_accessors('PDF::Make::Builder::Text'); |
|
23
|
|
|
|
|
|
|
} |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
sub _resolve_font { |
|
26
|
352
|
|
|
352
|
|
442
|
my ($self, $builder) = @_; |
|
27
|
352
|
|
|
|
|
542
|
my $base = $builder->font; |
|
28
|
352
|
|
|
|
|
386
|
my $overrides = font $self; |
|
29
|
352
|
100
|
|
|
|
602
|
if ($overrides) { |
|
30
|
|
|
|
|
|
|
my $f = PDF::Make::Builder::Font->new( |
|
31
|
|
|
|
|
|
|
colour => $overrides->{colour} // $base->colour, |
|
32
|
|
|
|
|
|
|
size => $overrides->{size} // $base->size, |
|
33
|
|
|
|
|
|
|
family => $overrides->{family} // $base->family, |
|
34
|
|
|
|
|
|
|
bold => $overrides->{bold} // $base->bold, |
|
35
|
|
|
|
|
|
|
italic => $overrides->{italic} // $base->italic, |
|
36
|
75
|
|
66
|
|
|
998
|
line_height => $overrides->{line_height} // $base->effective_line_height, |
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
37
|
|
|
|
|
|
|
); |
|
38
|
75
|
|
|
|
|
163
|
return $f; |
|
39
|
|
|
|
|
|
|
} |
|
40
|
277
|
|
|
|
|
349
|
return $base; |
|
41
|
|
|
|
|
|
|
} |
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
sub add { |
|
44
|
352
|
|
|
352
|
1
|
532
|
my ($self, $builder) = @_; |
|
45
|
|
|
|
|
|
|
|
|
46
|
352
|
|
|
|
|
695
|
my $page = $builder->page; |
|
47
|
352
|
|
|
|
|
578
|
my $canvas = $page->canvas; |
|
48
|
352
|
|
|
|
|
616
|
my $font = $self->_resolve_font($builder); |
|
49
|
352
|
|
|
|
|
877
|
my $res_name = $font->ensure_loaded($page->xs_page); |
|
50
|
352
|
|
|
|
|
662
|
my $font_size = $font->size; |
|
51
|
352
|
|
|
|
|
567
|
my $lh = $font->effective_line_height; |
|
52
|
352
|
|
|
|
|
431
|
my $line_spacing = spacing $self; |
|
53
|
352
|
50
|
33
|
|
|
963
|
$line_spacing = 0 if !defined($line_spacing) || $line_spacing < 0; |
|
54
|
352
|
|
|
|
|
854
|
my ($cr, $cg, $cb) = $font->hex_to_rgb($font->colour); |
|
55
|
|
|
|
|
|
|
|
|
56
|
352
|
|
|
|
|
425
|
my $pad = padding $self; |
|
57
|
352
|
50
|
33
|
|
|
910
|
$pad = 0 if !defined($pad) || $pad < 0; |
|
58
|
|
|
|
|
|
|
|
|
59
|
352
|
|
66
|
|
|
1065
|
my $text_w = ($self->w // $page->width) - (2 * $pad); |
|
60
|
352
|
50
|
|
|
|
551
|
$text_w = 1 if $text_w < 1; |
|
61
|
352
|
|
66
|
|
|
1026
|
my $cx = ($self->x // $page->content_x) + $pad; |
|
62
|
352
|
|
|
|
|
536
|
my $cy = $self->y; |
|
63
|
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
# Explicit y is already in builder/PDF bottom-left coordinates |
|
65
|
352
|
100
|
|
|
|
499
|
if (!defined $cy) { |
|
66
|
343
|
|
|
|
|
580
|
$cy = $page->cursor_y; |
|
67
|
|
|
|
|
|
|
} |
|
68
|
352
|
|
|
|
|
393
|
$cy -= $pad; |
|
69
|
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
# Apply indent |
|
71
|
352
|
|
|
|
|
357
|
my $indent_w = 0; |
|
72
|
352
|
|
|
|
|
388
|
my $ind = indent $self; |
|
73
|
352
|
100
|
|
|
|
510
|
if ($ind > 0) { |
|
74
|
3
|
|
|
|
|
12
|
$indent_w = $font->space_width * $ind; |
|
75
|
|
|
|
|
|
|
} |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
# Word-wrap |
|
78
|
352
|
|
|
|
|
414
|
my $raw = text $self; |
|
79
|
352
|
|
|
|
|
2957
|
my @words = split /\s+/, $raw; |
|
80
|
352
|
50
|
|
|
|
538
|
return $self unless @words; |
|
81
|
|
|
|
|
|
|
|
|
82
|
352
|
|
|
|
|
347
|
my @lines; |
|
83
|
352
|
|
|
|
|
368
|
my $line = ''; |
|
84
|
352
|
|
|
|
|
371
|
my $line_w = $indent_w; |
|
85
|
352
|
|
|
|
|
363
|
my $first_line = 1; |
|
86
|
|
|
|
|
|
|
|
|
87
|
352
|
|
|
|
|
522
|
for my $word (@words) { |
|
88
|
14574
|
100
|
|
|
|
23399
|
my $candidate = $line eq '' ? $word : ($line . ' ' . $word); |
|
89
|
14574
|
|
|
|
|
21252
|
my $candidate_w = $font->measure_text($candidate); |
|
90
|
14574
|
100
|
|
|
|
19902
|
my $test_w = $candidate_w + ($first_line ? $indent_w : 0); |
|
91
|
14574
|
|
|
|
|
15187
|
my $max_w = $text_w; |
|
92
|
|
|
|
|
|
|
|
|
93
|
14574
|
100
|
66
|
|
|
24750
|
if ($test_w > $max_w && $line ne '') { |
|
94
|
649
|
|
|
|
|
1727
|
push @lines, [$line, $line_w, $first_line]; |
|
95
|
649
|
|
|
|
|
741
|
$first_line = 0; |
|
96
|
649
|
|
|
|
|
816
|
$line = $word; |
|
97
|
649
|
|
|
|
|
1009
|
$line_w = $font->measure_text($line); |
|
98
|
|
|
|
|
|
|
} else { |
|
99
|
13925
|
|
|
|
|
15585
|
$line = $candidate; |
|
100
|
13925
|
|
|
|
|
17654
|
$line_w = $test_w; |
|
101
|
|
|
|
|
|
|
} |
|
102
|
|
|
|
|
|
|
} |
|
103
|
352
|
50
|
|
|
|
917
|
push @lines, [$line, $line_w, $first_line] if $line ne ''; |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
# Render lines |
|
106
|
352
|
|
|
|
|
438
|
my $al = align $self; |
|
107
|
352
|
|
|
|
|
371
|
my $can_overflow = overflow $self; |
|
108
|
|
|
|
|
|
|
|
|
109
|
352
|
|
|
|
|
673
|
for my $idx (0 .. $#lines) { |
|
110
|
1001
|
|
|
|
|
1128
|
my $entry = $lines[$idx]; |
|
111
|
1001
|
|
|
|
|
1321
|
my ($line_text, $lw, $is_first) = @$entry; |
|
112
|
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
# Check if we have room |
|
114
|
1001
|
100
|
|
|
|
1469
|
if ($cy - $lh < $page->bottom_y) { |
|
115
|
|
|
|
|
|
|
# Try next column first |
|
116
|
15
|
100
|
|
|
|
45
|
if ($page->has_next_column) { |
|
|
|
100
|
|
|
|
|
|
|
117
|
3
|
|
|
|
|
15
|
$page->next_column; |
|
118
|
3
|
|
|
|
|
10
|
$cx = $page->content_x + $pad; |
|
119
|
3
|
|
|
|
|
9
|
$cy = $page->cursor_y - $pad; |
|
120
|
3
|
|
|
|
|
6
|
$text_w = $page->width - (2 * $pad); |
|
121
|
3
|
50
|
|
|
|
10
|
$text_w = 1 if $text_w < 1; |
|
122
|
|
|
|
|
|
|
} elsif ($can_overflow) { |
|
123
|
|
|
|
|
|
|
# All columns full — overflow to new page |
|
124
|
|
|
|
|
|
|
# Inherit settings from current page |
|
125
|
4
|
|
|
|
|
18
|
my $cols = $page->columns; |
|
126
|
4
|
|
|
|
|
15
|
my $psz = $page->page_size; |
|
127
|
4
|
|
|
|
|
9
|
my $page_pad = $page->padding; |
|
128
|
4
|
|
|
|
|
13
|
my $bg = $page->background; |
|
129
|
4
|
|
|
|
|
35
|
$builder->add_page( |
|
130
|
|
|
|
|
|
|
page_size => $psz, |
|
131
|
|
|
|
|
|
|
padding => $page_pad, |
|
132
|
|
|
|
|
|
|
columns => $cols, |
|
133
|
|
|
|
|
|
|
background => $bg, |
|
134
|
|
|
|
|
|
|
); |
|
135
|
4
|
|
|
|
|
11
|
$page = $builder->page; |
|
136
|
4
|
|
|
|
|
10
|
$canvas = $page->canvas; |
|
137
|
4
|
|
|
|
|
23
|
$res_name = $font->ensure_loaded($page->xs_page); |
|
138
|
4
|
|
|
|
|
14
|
$cx = $page->content_x + $pad; |
|
139
|
4
|
|
|
|
|
11
|
$cy = $page->cursor_y - $pad; |
|
140
|
4
|
|
|
|
|
13
|
$text_w = $page->width - (2 * $pad); |
|
141
|
4
|
50
|
|
|
|
11
|
$text_w = 1 if $text_w < 1; |
|
142
|
|
|
|
|
|
|
} else { |
|
143
|
8
|
|
|
|
|
13
|
last; |
|
144
|
|
|
|
|
|
|
} |
|
145
|
|
|
|
|
|
|
} |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
# Baseline sits near top of the line slot (font_size below cursor). |
|
148
|
|
|
|
|
|
|
# The full line_height advances the cursor to the bottom of the slot. |
|
149
|
993
|
|
|
|
|
1014
|
my $baseline_y = $cy - $font_size; |
|
150
|
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
# Calculate x based on alignment |
|
152
|
993
|
|
|
|
|
946
|
my $tx = $cx; |
|
153
|
993
|
100
|
|
|
|
1120
|
my $extra_indent = $is_first ? $indent_w : 0; |
|
154
|
993
|
100
|
|
|
|
1425
|
if ($al eq 'center') { |
|
|
|
100
|
|
|
|
|
|
|
155
|
6
|
|
|
|
|
16
|
$tx = $cx + ($text_w - $lw) / 2; |
|
156
|
|
|
|
|
|
|
} elsif ($al eq 'right') { |
|
157
|
4
|
|
|
|
|
10
|
$tx = $cx + $text_w - $lw; |
|
158
|
|
|
|
|
|
|
} else { |
|
159
|
983
|
|
|
|
|
973
|
$tx += $extra_indent; |
|
160
|
|
|
|
|
|
|
} |
|
161
|
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
# Pad support (for TOC dot leaders) |
|
163
|
993
|
|
|
|
|
954
|
my $pad_char = pad $self; |
|
164
|
993
|
100
|
66
|
|
|
1319
|
if ($pad_char && length($pad_char)) { |
|
165
|
4
|
|
100
|
|
|
15
|
my $pad_end_text = pad_end($self) // ''; |
|
166
|
4
|
|
|
|
|
13
|
my $pad_w = $font->measure_word($pad_char); |
|
167
|
4
|
100
|
|
|
|
11
|
my $end_w = length($pad_end_text) ? $font->measure_text($pad_end_text) : 0; |
|
168
|
4
|
|
|
|
|
11
|
my $gap = $text_w - $lw - $end_w; |
|
169
|
4
|
50
|
|
|
|
8
|
if ($gap > $pad_w) { |
|
170
|
4
|
|
|
|
|
7
|
my $num_pads = int($gap / $pad_w); |
|
171
|
4
|
|
|
|
|
12
|
$line_text .= ' ' . ($pad_char x $num_pads); |
|
172
|
4
|
100
|
|
|
|
10
|
$line_text .= $pad_end_text if length($pad_end_text); |
|
173
|
|
|
|
|
|
|
} |
|
174
|
|
|
|
|
|
|
} |
|
175
|
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
$canvas->BT |
|
177
|
993
|
|
|
|
|
9805
|
->rg($cr, $cg, $cb) |
|
178
|
|
|
|
|
|
|
->Tf($res_name, $font_size) |
|
179
|
|
|
|
|
|
|
->Tm(1, 0, 0, 1, $tx, $baseline_y) |
|
180
|
|
|
|
|
|
|
->Tj($line_text) |
|
181
|
|
|
|
|
|
|
->ET; |
|
182
|
|
|
|
|
|
|
|
|
183
|
993
|
|
|
|
|
1007
|
$cy -= $lh; |
|
184
|
993
|
100
|
|
|
|
1668
|
$cy -= $line_spacing if $idx < $#lines; |
|
185
|
|
|
|
|
|
|
} |
|
186
|
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
# Update page cursor - spacing applies after the entire block |
|
188
|
352
|
|
|
|
|
502
|
my $final_y = $cy - (margin $self) - $line_spacing - $pad; |
|
189
|
352
|
|
|
|
|
788
|
$page->y($final_y); |
|
190
|
352
|
50
|
|
|
|
523
|
if (@lines) { |
|
191
|
352
|
|
|
|
|
804
|
end_w $self, $lines[-1][1]; |
|
192
|
352
|
|
|
|
|
411
|
end_y $self, $cy; # bottom of last line slot |
|
193
|
|
|
|
|
|
|
} |
|
194
|
|
|
|
|
|
|
|
|
195
|
352
|
|
|
|
|
1828
|
return $self; |
|
196
|
|
|
|
|
|
|
} |
|
197
|
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
1; |
|
199
|
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
__END__ |