lib/prawn/text/formatted/arranger.rb in prawn-2.4.0 vs lib/prawn/text/formatted/arranger.rb in prawn-2.5.0
- old
+ new
@@ -1,33 +1,32 @@
# frozen_string_literal: true
-# core/text/formatted/arranger.rb : Implements a data structure for 2-stage
-# processing of lines of formatted text
-#
-# Copyright February 2010, Daniel Nelson. All Rights Reserved.
-#
-# This is free software. Please see the LICENSE and COPYING files for details.
-
module Prawn
module Text
- module Formatted #:nodoc:
+ module Formatted
+ # D data structure for 2-stage processing of lines of formatted text.
# @private
-
- class Arranger #:nodoc:
+ class Arranger
+ # You're getting this because you're trying to get some information from
+ # the arranger before it finished processing text.
class NotFinalized < StandardError
+ # @private
DEFAULT_MESSAGE = 'Lines must be finalized'
+
+ # @private
MESSAGE_WITH_METHOD = 'Lines must be finalized before calling #%<method>s'
def initialize(message = DEFAULT_MESSAGE, method: nil)
if method && message == DEFAULT_MESSAGE
- super format(MESSAGE_WITH_METHOD, method: method)
+ super(format(MESSAGE_WITH_METHOD, method: method))
else
- super message
+ super(message)
end
end
end
+ # You're getting this because a font doesn't have a family name.
class BadFontFamily < StandardError
def initialize(message = 'Bad font family')
super
end
end
@@ -48,43 +47,59 @@
@fragments = []
@unconsumed = []
@kerning = options[:kerning]
end
+ # Number of spaces in the text.
+ #
+ # @return [Integer]
+ # @raise [NotFinalized]
def space_count
unless finalized
raise NotFinalized.new(method: 'space_count')
end
@fragments.reduce(0) do |sum, fragment|
sum + fragment.space_count
end
end
+ # Line width.
+ #
+ # @return [Number]
+ # @raise [NotFinalized]
def line_width
unless finalized
raise raise NotFinalized.new(method: 'line_width')
end
@fragments.reduce(0) do |sum, fragment|
sum + fragment.width
end
end
+ # Line text.
+ #
+ # @return [String]
+ # @raise [NotFinalized]
def line
unless finalized
raise NotFinalized.new(method: 'line')
end
- @fragments.map do |fragment|
- fragment.text.dup.encode(::Encoding::UTF_8)
- rescue ::Encoding::InvalidByteSequenceError,
- ::Encoding::UndefinedConversionError
- fragment.text.dup.force_encoding(::Encoding::UTF_8)
- end.join
+ @fragments.map { |fragment|
+ begin
+ fragment.text.dup.encode(::Encoding::UTF_8)
+ rescue ::Encoding::InvalidByteSequenceError, ::Encoding::UndefinedConversionError
+ fragment.text.dup.force_encoding(::Encoding::UTF_8)
+ end
+ }.join
end
+ # Finish laying out current line.
+ #
+ # @return [void]
def finalize_line
@finalized = true
omit_trailing_whitespace_from_line_width
@fragments = []
@@ -93,42 +108,56 @@
format_state = hash.dup
format_state.delete(:text)
fragment = Prawn::Text::Formatted::Fragment.new(
text,
format_state,
- @document
+ @document,
)
@fragments << fragment
self.fragment_measurements = fragment
self.line_measurement_maximums = fragment
end
end
+ # Set new fragment array.
+ #
+ # @param array [Array<Hash>]
+ # @return [void]
def format_array=(array)
initialize_line
@unconsumed = []
array.each do |hash|
hash[:text].scan(/[^\n]+|\n/) do |line|
@unconsumed << hash.merge(text: line)
end
end
end
+ # Prepare for new line layout.
+ #
+ # @return [void]
def initialize_line
@finalized = false
@max_line_height = 0
@max_descender = 0
@max_ascender = 0
@consumed = []
@fragments = []
end
+ # Were all fragments processed?
+ #
+ # @return [Boolean]
def finished?
@unconsumed.empty?
end
+ # Get the next unprocessed string.
+ #
+ # @return [String, nil]
+ # @raise [NotFinalized]
def next_string
if finalized
raise NotFinalized.new(method: 'next_string')
end
@@ -141,18 +170,26 @@
next_unconsumed_hash[:text]
end
end
+ # Get the next unprocessed string keeping it in the queue.
+ #
+ # @return [String, nil]
def preview_next_string
next_unconsumed_hash = @unconsumed.first
if next_unconsumed_hash
next_unconsumed_hash[:text]
end
end
+ # Apply color and font settings.
+ #
+ # @param fragment [Prawn::Text::Formatted::Fragment]
+ # @yield
+ # @return [void]
def apply_color_and_font_settings(fragment, &block)
if fragment.color
original_fill_color = @document.fill_color
original_stroke_color = @document.stroke_color
@document.fill_color(*fragment.color)
@@ -163,10 +200,15 @@
else
apply_font_settings(fragment, &block)
end
end
+ # Apply font settings.
+ #
+ # @param fragment [Prawn::Text::Formatted::Fragment]
+ # @yield
+ # @return [void]
def apply_font_settings(fragment = nil, &block)
if fragment.nil?
font = current_format_state[:font]
size = current_format_state[:size]
character_spacing = current_format_state[:character_spacing] ||
@@ -183,20 +225,26 @@
@document.character_spacing(character_spacing) do
if font || font_style != :normal
raise BadFontFamily unless @document.font.family
@document.font(
- font || @document.font.family, style: font_style
+ font || @document.font.family, style: font_style,
) do
apply_font_size(size, styles, &block)
end
else
apply_font_size(size, styles, &block)
end
end
end
+ # Update last fragment's text.
+ #
+ # @param printed [String]
+ # @param unprinted [String]
+ # @param normalized_soft_hyphen [Boolean]
+ # @return [void]
def update_last_string(printed, unprinted, normalized_soft_hyphen = nil)
return if printed.nil?
if printed.empty?
@consumed.pop
@@ -212,18 +260,25 @@
end
load_previous_format_state if printed.empty?
end
+ # Get the next fragment.
+ #
+ # @return [Prawn::Text::Formatted::Fragment]
+ # @raise [NotFinalized]
def retrieve_fragment
unless finalized
raise NotFinalized, 'Lines must be finalized before fragments can be retrieved'
end
@fragments.shift
end
+ # Repack remaining fragments.
+ #
+ # @return [void]
def repack_unretrieved
new_unconsumed = []
# rubocop: disable Lint/AssignmentInCondition
while fragment = retrieve_fragment
# rubocop: enable Lint/AssignmentInCondition
@@ -231,10 +286,14 @@
new_unconsumed << fragment.format_state.merge(text: fragment.text)
end
@unconsumed = new_unconsumed.concat(@unconsumed)
end
+ # Get font variant from fragment styles.
+ #
+ # @param styles [Array<Symbol>]
+ # @return [Symbol]
def font_style(styles)
styles = Array(styles)
if styles.include?(:bold) && styles.include?(:italic)
:bold_italic
elsif styles.include?(:bold)
@@ -275,17 +334,19 @@
end
end
def subscript?(styles)
if styles.nil? then false
- else styles.include?(:subscript)
+ else
+ styles.include?(:subscript)
end
end
def superscript?(styles)
if styles.nil? then false
- else styles.include?(:superscript)
+ else
+ styles.include?(:superscript)
end
end
def omit_trailing_whitespace_from_line_width
@consumed.reverse_each do |hash|
@@ -305,29 +366,29 @@
def fragment_measurements=(fragment)
apply_font_settings(fragment) do
fragment.width = @document.width_of(
fragment.text,
- kerning: @kerning
+ kerning: @kerning,
)
fragment.line_height = @document.font.height
fragment.descender = @document.font.descender
fragment.ascender = @document.font.ascender
end
end
def line_measurement_maximums=(fragment)
@max_line_height = [
defined?(@max_line_height) && @max_line_height,
- fragment.line_height
+ fragment.line_height,
].compact.max
@max_descender = [
defined?(@max_descender) && @max_descender,
- fragment.descender
+ fragment.descender,
].compact.max
@max_ascender = [
defined?(@max_ascender) && @max_ascender,
- fragment.ascender
+ fragment.ascender,
].compact.max
end
end
end
end