class Krill::LineWrap
Attributes
soft_hyphen[R]
space_count[R]
The number of spaces in the last wrapped line
zero_width_space[R]
Public Instance Methods
paragraph_finished?()
click to toggle source
Whether this line is the last line in the paragraph
# File lib/krill/line_wrap.rb, line 16 def paragraph_finished? @newline_encountered || is_next_string_newline? || @arranger.finished? end
tokenize(fragment)
click to toggle source
# File lib/krill/line_wrap.rb, line 20 def tokenize(fragment) fragment.scan(scan_pattern) end
width()
click to toggle source
The width of the last wrapped line
# File lib/krill/line_wrap.rb, line 6 def width @accumulated_width || 0 end
wrap_line(width:, arranger:, kerning: nil, disable_wrap_by_char: nil)
click to toggle source
Work in conjunction with the PDF::Formatted::Arranger defined in the :arranger option to determine what formatted text will fit within the width defined by the :width option
# File lib/krill/line_wrap.rb, line 28 def wrap_line(width:, arranger:, kerning: nil, disable_wrap_by_char: nil) initialize_line( kerning: kerning, width: width, arranger: arranger, disable_wrap_by_char: disable_wrap_by_char) while fragment = @arranger.next_string @fragment_output = "" next if empty_line?(fragment) break unless apply_font_settings_and_add_fragment_to_line(fragment) end @arranger.finalize_line @accumulated_width = @arranger.line_width @space_count = @arranger.space_count @arranger.line end
Private Instance Methods
add_fragment_to_line(fragment, formatter)
click to toggle source
returns true if all text was printed without running into the end of the line
# File lib/krill/line_wrap.rb, line 76 def add_fragment_to_line(fragment, formatter) if fragment == "" true elsif fragment == "\n" @newline_encountered = true false else tokenize(fragment).each do |segment| if segment == zero_width_space segment_width = 0 else segment_width = formatter.width_of(segment, kerning: @kerning) end if @accumulated_width + segment_width <= @width @accumulated_width += segment_width if segment[-1] == soft_hyphen sh_width = formatter.width_of("#{soft_hyphen}", kerning: @kerning) @accumulated_width -= sh_width end @fragment_output += segment else end_of_the_line_reached(formatter, segment) fragment_finished(fragment) return false end end fragment_finished(fragment) true end end
append_char(char, formatter)
click to toggle source
# File lib/krill/line_wrap.rb, line 272 def append_char(char, formatter) # kerning doesn't make sense in the context of a single character char_width = formatter.compute_width_of(char, kerning: false) if @accumulated_width + char_width <= @width @accumulated_width += char_width @fragment_output << char true else false end end
apply_font_settings_and_add_fragment_to_line(fragment)
click to toggle source
# File lib/krill/line_wrap.rb, line 65 def apply_font_settings_and_add_fragment_to_line(fragment) # if font has changed from Unicode to non-Unicode, or vice versa, # the characters used for soft hyphens and zero-width spaces will # be different. set_soft_hyphen_and_zero_width_space(@arranger.current_formatter) add_fragment_to_line(fragment, @arranger.current_formatter) end
break_chars(encoding = ::Encoding::UTF_8)
click to toggle source
# File lib/krill/line_wrap.rb, line 158 def break_chars(encoding = ::Encoding::UTF_8) [ whitespace(encoding), soft_hyphen(encoding), hyphen(encoding) ].join('') end
determine_whether_to_pull_preceding_fragment_to_join_this_one(current_fragment)
click to toggle source
# File lib/krill/line_wrap.rb, line 226 def determine_whether_to_pull_preceding_fragment_to_join_this_one(current_fragment) if @fragment_output.empty? && !current_fragment.empty? && @line_contains_more_than_one_word unless previous_fragment_ended_with_breakable? || fragment_begins_with_breakable?(current_fragment) @fragment_output = @previous_fragment_output_without_last_word update_output_based_on_last_fragment(@previous_fragment) end end end
empty_line?(fragment)
click to toggle source
# File lib/krill/line_wrap.rb, line 55 def empty_line?(fragment) empty = line_empty? && fragment.empty? && is_next_string_newline? @arranger.update_last_string("", "", soft_hyphen) if empty empty end
end_of_the_line_reached(formatter, segment)
click to toggle source
# File lib/krill/line_wrap.rb, line 260 def end_of_the_line_reached(formatter, segment) update_line_status_based_on_last_output wrap_by_char(formatter, segment) unless @disable_wrap_by_char || @line_contains_more_than_one_word @line_full = true end
first_fragment_on_this_line?(fragment)
click to toggle source
# File lib/krill/line_wrap.rb, line 51 def first_fragment_on_this_line?(fragment) line_empty? && fragment != "\n" end
fragment_begins_with_breakable?(fragment)
click to toggle source
# File lib/krill/line_wrap.rb, line 248 def fragment_begins_with_breakable?(fragment) fragment =~ /^[#{break_chars}]/ end
fragment_finished(fragment)
click to toggle source
# File lib/krill/line_wrap.rb, line 208 def fragment_finished(fragment) if fragment == "\n" @newline_encountered = true @line_empty = false else update_output_based_on_last_fragment(fragment, soft_hyphen) update_line_status_based_on_last_output determine_whether_to_pull_preceding_fragment_to_join_this_one(fragment) end remember_this_fragment_for_backward_looking_ops end
hyphen(_encoding = ::Encoding::UTF_8)
click to toggle source
# File lib/krill/line_wrap.rb, line 174 def hyphen(_encoding = ::Encoding::UTF_8) '-' end
initialize_line(kerning:, width:, arranger:, disable_wrap_by_char:)
click to toggle source
# File lib/krill/line_wrap.rb, line 184 def initialize_line(kerning:, width:, arranger:, disable_wrap_by_char:) @kerning = kerning @width = width @disable_wrap_by_char = disable_wrap_by_char @accumulated_width = 0 @line_empty = true @line_contains_more_than_one_word = false @arranger = arranger @arranger.initialize_line @newline_encountered = false @line_full = false end
is_next_string_newline?()
click to toggle source
# File lib/krill/line_wrap.rb, line 61 def is_next_string_newline? @arranger.preview_next_string == "\n" end
line_empty?()
click to toggle source
# File lib/krill/line_wrap.rb, line 180 def line_empty? @line_empty && @accumulated_width == 0 end
line_finished?()
click to toggle source
# File lib/krill/line_wrap.rb, line 252 def line_finished? @line_full || paragraph_finished? end
previous_fragment_ended_with_breakable?()
click to toggle source
# File lib/krill/line_wrap.rb, line 244 def previous_fragment_ended_with_breakable? @previous_fragment_ended_with_breakable end
remember_this_fragment_for_backward_looking_ops()
click to toggle source
# File lib/krill/line_wrap.rb, line 235 def remember_this_fragment_for_backward_looking_ops @previous_fragment = @fragment_output.dup pf = @previous_fragment @previous_fragment_ended_with_breakable = pf =~ /[#{break_chars}]$/ last_word = pf.slice(/[^#{break_chars}]*$/) last_word_length = last_word.nil? ? 0 : last_word.length @previous_fragment_output_without_last_word = pf.slice(0, pf.length - last_word_length) end
scan_pattern(encoding = ::Encoding::UTF_8)
click to toggle source
The pattern used to determine chunks of text to place on a given line
# File lib/krill/line_wrap.rb, line 113 def scan_pattern(encoding = ::Encoding::UTF_8) ebc = break_chars(encoding) eshy = soft_hyphen(encoding) ehy = hyphen(encoding) ews = whitespace(encoding) patterns = [ "[^#{ebc}]+#{eshy}", "[^#{ebc}]+#{ehy}+", "[^#{ebc}]+", "[#{ews}]+", "#{ehy}+[^#{ebc}]*", eshy.to_s ] pattern = patterns .map { |p| p.encode(encoding) } .join('|') Regexp.new(pattern) end
set_soft_hyphen_and_zero_width_space(formatter)
click to toggle source
# File lib/krill/line_wrap.rb, line 201 def set_soft_hyphen_and_zero_width_space(formatter) # this is done once per fragment, after the font settings for the fragment are applied -- # it could actually be skipped if the font hasn't changed @soft_hyphen = formatter.normalize_encoding(SHY) @zero_width_space = formatter.unicode? ? ZWSP : "" end
update_line_status_based_on_last_output()
click to toggle source
# File lib/krill/line_wrap.rb, line 256 def update_line_status_based_on_last_output @line_contains_more_than_one_word = true if @fragment_output =~ word_division_scan_pattern end
update_output_based_on_last_fragment(fragment, normalized_soft_hyphen = nil)
click to toggle source
# File lib/krill/line_wrap.rb, line 220 def update_output_based_on_last_fragment(fragment, normalized_soft_hyphen = nil) remaining_text = fragment.slice(@fragment_output.length..fragment.length).lstrip fail CannotFit if line_finished? && line_empty? && @fragment_output.empty? && !fragment.strip.empty? @arranger.update_last_string(@fragment_output, remaining_text, normalized_soft_hyphen) end
whitespace(encoding = ::Encoding::UTF_8)
click to toggle source
# File lib/krill/line_wrap.rb, line 170 def whitespace(encoding = ::Encoding::UTF_8) "\s\t#{zero_width_space(encoding)}".encode(encoding) end
word_division_scan_pattern(encoding = ::Encoding::UTF_8)
click to toggle source
The pattern used to determine whether any word breaks exist on a current line, which in turn determines whether character level word breaking is needed
# File lib/krill/line_wrap.rb, line 139 def word_division_scan_pattern(encoding = ::Encoding::UTF_8) common_whitespaces = ["\t", "\n", "\v", "\r", ' '].map do |c| c.encode(encoding) end Regexp.union( common_whitespaces + [ zero_width_space(encoding), soft_hyphen(encoding), hyphen(encoding) ].compact ) end
wrap_by_char(formatter, segment)
click to toggle source
# File lib/krill/line_wrap.rb, line 266 def wrap_by_char(formatter, segment) segment.each_char do |char| break unless append_char(char, formatter) end end