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 )