Subject: | PDF::Table infinite loop fix |
We discovered a subtle problem with the way word sizes are cached in
PDF::Table. It wasn't taking into account font changes, which would
trigger an infinite loop in certain scenarios. Basically, the calculated
max column size would never be large enough to fit the contents if the
new font was larger than the old, so it would try to create a new row,
which would have the same problem and keep repeating that process.
Subject: | PDF-Table-cache.patch |
--- Table.pm.bak 2011-10-18 22:24:50.000000000 -0400
+++ Table.pm 2012-05-15 17:42:35.000000000 -0400
@@ -339,18 +339,29 @@
{
# look for font information for this column
$col_fnt_size = $col_props->[$j]->{'font_size'} || $fnt_size;
+ ($cell_font, $cell_font_size);
if( !$rows_counter and ref $header_props)
{
- $txt->font( $header_props->{'font'}, $header_props->{'font_size'} );
+ $cell_font = $header_props->{'font'};
+ $cell_font_size = $header_props->{'font_size'};
+ }
+ elsif( $cell_props->[$rows_counter][$j]->{'font'} )
+ {
+ $cell_font = $cell_props->[$rows_counter][$j]->{'font'};
+ $cell_font_size = $col_fnt_size;
}
elsif( $col_props->[$j]->{'font'} )
{
- $txt->font( $col_props->[$j]->{'font'}, $col_fnt_size );
+ $cell_font = $col_props->[$j]->{'font'};
+ $cell_font_size = $col_fnt_size;
}
else
{
- $txt->font( $fnt_name, $col_fnt_size );
+ $cell_font = $fnt_name;
+ $cell_font_size = $col_fnt_size;
}
+ $txt->font( $cell_font, $cell_font_size );
+ my $cell_font_name = ref($cell_font) ? $cell_font->name : $cell_font;
# This should fix a bug with very long word like serial numbers etc.
$row->[$j] =~ s#(\S{$max_word_len}?)(?=\S)#$1 #g if ($max_word_len > 0);
@@ -364,13 +375,14 @@
foreach( @words )
{
- unless( exists $word_w->{$_} )
+ unless( exists $word_w->{$_}{$cell_font_name}{$cell_font_size} )
{ # Calculate the width of every word and add the space width to it
- $word_w->{$_} = $txt->advancewidth( $_ ) + $space_w;
+ $word_w->{$_}{$cell_font_name}{$cell_font_size} = $txt->advancewidth( $_ ) + $space_w;
}
- $column_widths->[$j] += $word_w->{$_};
- $min_col_w = $word_w->{$_} if $word_w->{$_} > $min_col_w;
- $max_col_w += $word_w->{$_};
+ my $cached_word_w = $word_w->{$_}{$cell_font_name}{$cell_font_size};
+ $column_widths->[$j] += $cached_word_w;
+ $min_col_w = $cached_word_w if $cached_word_w > $min_col_w;
+ $max_col_w += $cached_word_w;
}
$min_col_w += $pad_w;
$max_col_w += $pad_w;