PDF-Kit
view release on metacpan or search on metacpan
lib/PDF/Kit.pm view on Meta::CPAN
# These may be used, as is, in another L<format_paragraph()> call.
#
sub format_paragraph {
# flatten makes things easier
my $mut = flatten( @_ );
# remove leading spaces in first text item
$mut->[1] =~ s{ \A \s+ }{}msx if @$mut > 1;
# save the indent
my $indent = 0;
if( @$mut && exists( $mut->[0][0]{-indent} ) ){
$indent = $mut->[0][0]{-indent} || 0;
}
my $lines = [];
my $space_pending = 0;
my $space_width = 0;
my $trailing_width = 0;
my $trailing_spaces = '';
my $two_spaces = 0;
my $add_p_end = 1;
MUT_LOOP:
while( @$mut ){
my %opts = %{ $mut->[0][0] };
my $text = $mut->[0][1];
shift @$mut;
# add a new segment
if( @$lines ){
push @{ $lines->[-1]{-segments} }, {
%opts,
-offset => $lines->[-1]{-segments}[-1]{-offset} + $lines->[-1]{-segments}[-1]{-length},
-length => 0,
-text => '',
};
}else{
push @{ $lines->[0]{-segments} }, {
%opts,
-offset => $indent,
-length => 0,
-text => '',
};
}
if( $space_pending ){
$trailing_spaces = $SPACE;
$trailing_width = $space_width;
if( $two_spaces ){
$trailing_spaces .= $SPACE;
$trailing_width .= $space_width;
}
}
$space_width = &{$opts{-compute_length}}( { %opts, -print=>0, }, $SPACE ); # must redo every time since might have changed from previous
# process the text
my @text = split m{ ( \s+ ) }msx, $text;
while( @text ){
my $word = shift @text;
if( $word =~ m{ \A \s }msx ){
$space_pending = 1;
next;
}
my $word_length = &{$opts{-compute_length}}( { %opts, -print=>0, }, $word );
my $extended_length = $word_length;
# a word at end of text may be joined to next
unless( @text ){
for my $item ( @$mut ){
last if $item->[1] =~ m{ \A \s }msx;
if( $item->[1] =~ m{ \A (\S+) (?=\s) }msx ){
my $look_ahead = $1;
$extended_length += &{$opts{-compute_length}}( { %opts, -print=>0, }, $look_ahead );
last;
}
$extended_length += &{$opts{-compute_length}}( { %opts, -print=>0, }, $item->[1] );
}
}
my $right = $lines->[-1]{-segments}[-1]{-offset} + $lines->[-1]{-segments}[-1]{-length} + $extended_length;
my $new_line = 0;
if( $trailing_width ){
if( $trailing_width + $right > $lines->[-1]{-segments}[-1]{-width} ){
$new_line = 1;
}
}elsif( $space_pending ){
my $spw = $space_width;
$spw += $space_width if $two_spaces;
if( $spw + $right > $lines->[-1]{-segments}[-1]{-width} ){
$new_line = 1;
}
}
# add a new line
if( $new_line ){
$lines->[-1]{-width} = $lines->[-1]{-segments}[-1]{-width};
if( exists( $opts{-max_lines} ) && @$lines >= $opts{-max_lines} ){
delete $opts{-offset};
delete $opts{-length};
delete $opts{-text};
$opts{-indent} = 0; # everything left over is still part of this paragraph, so it's indent must be zero.
unshift @$mut, [ { %opts }, join( '', $word, @text ) ];
$add_p_end = 0;
last MUT_LOOP;
}
push @$lines, {
-length => 0,
-segments =>[{
%opts,
-offset => 0,
-length => 0,
-text => '',
}],
};
$space_pending = 0;
$trailing_width = 0;
( run in 2.735 seconds using v1.01-cache-2.11-cpan-71847e10f99 )