1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
|
# frozen_string_literal: true
# wrap.rb: Handles text wrapping for for formatted text
#
# Contributed by Daniel Nelson
#
# This is free software. Please see the LICENSE and COPYING files for details.
require_relative 'line_wrap'
require_relative 'arranger'
module Prawn
module Text
module Formatted #:nodoc:
# @private
module Wrap #:nodoc:
def initialize(_array, options)
@line_wrap = Prawn::Text::Formatted::LineWrap.new
@arranger = Prawn::Text::Formatted::Arranger.new(
@document,
kerning: options[:kerning]
)
@disable_wrap_by_char = options[:disable_wrap_by_char]
end
# See the developer documentation for PDF::Core::Text#wrap
#
# Formatted#wrap should set the following variables:
# <tt>@line_height</tt>::
# the height of the tallest fragment in the last printed line
# <tt>@descender</tt>::
# the descender height of the tallest fragment in the last
# printed line
# <tt>@ascender</tt>::
# the ascender heigth of the tallest fragment in the last
# printed line
# <tt>@baseline_y</tt>::
# the baseline of the current line
# <tt>@nothing_printed</tt>::
# set to true until something is printed, then false
# <tt>@everything_printed</tt>::
# set to false until everything printed, then true
#
# Returns any formatted text that was not printed
#
def wrap(array) #:nodoc:
initialize_wrap(array)
stop = false
until stop
# wrap before testing if enough height for this line because the
# height of the highest fragment on this line will be used to
# determine the line height
@line_wrap.wrap_line(
document: @document,
kerning: @kerning,
width: available_width,
arranger: @arranger,
disable_wrap_by_char: @disable_wrap_by_char
)
if enough_height_for_this_line?
move_baseline_down
print_line
else
stop = true
end
stop ||= @single_line || @arranger.finished?
end
@text = @printed_lines.join("\n")
@everything_printed = @arranger.finished?
@arranger.unconsumed
end
private
def print_line
@nothing_printed = false
printed_fragments = []
fragments_this_line = []
word_spacing = word_spacing_for_this_line
@arranger.fragments.each do |fragment|
fragment.word_spacing = word_spacing
if fragment.text == "\n"
printed_fragments << "\n" if @printed_lines.last == ''
break
end
printed_fragments << fragment.text
fragments_this_line << fragment
end
@arranger.fragments.replace []
accumulated_width = 0
fragments_this_line.reverse! if @direction == :rtl
fragments_this_line.each do |fragment_this_line|
fragment_this_line.default_direction = @direction
format_and_draw_fragment(
fragment_this_line, accumulated_width,
@line_wrap.width, word_spacing
)
accumulated_width += fragment_this_line.width
end
@printed_lines << printed_fragments.map do |s|
s.dup.force_encoding(::Encoding::UTF_8)
end.join
end
def word_spacing_for_this_line
if @align == :justify && @line_wrap.space_count.positive? &&
!@line_wrap.paragraph_finished?
(available_width - @line_wrap.width) / @line_wrap.space_count
else
0
end
end
def enough_height_for_this_line?
@line_height = @arranger.max_line_height
@descender = @arranger.max_descender
@ascender = @arranger.max_ascender
diff = if @baseline_y.zero?
@ascender + @descender
else
@descender + @line_height + @leading
end
require_relatived_total_height = @baseline_y.abs + diff
if require_relatived_total_height > @height + 0.0001
# no room for the full height of this line
@arranger.repack_unretrieved
false
else
true
end
end
def initialize_wrap(array)
@text = nil
@arranger.format_array = array
# these values will depend on the maximum value within a given line
@line_height = 0
@descender = 0
@ascender = 0
@baseline_y = 0
@printed_lines = []
@nothing_printed = true
@everything_printed = false
end
def format_and_draw_fragment(fragment, accumulated_width,
line_width, word_spacing)
@arranger.apply_color_and_font_settings(fragment) do
draw_fragment(
fragment, accumulated_width,
line_width, word_spacing
)
end
end
end
end
end
end
|