Class: Arrolio::Flowables::TextFlowable

Inherits:
Arrolio::Flowable show all
Defined in:
lib/arrolio/flowables/text_flowable.rb

Overview

A paragraph of flowing text. Selects a line-breaking strategy based on the style's line_break attribute (:greedy or :knuth_plass). Both strategies produce TextLayout::Line with the same shape, so the rest of the pipeline is agnostic.

Direct Known Subclasses

HeadingFlowable

Constant Summary collapse

MATH_OPERATOR =

Inline math with relational operators lays out stacked in the reference (JEuclid gives the formula box roughly two text lines of vertical extent); simple sub/superscripts stay compact. The operators only ever come from math content.

/[\u2264\u2265\u00d7\u00f7\u00b1\u2212\u2260]|\+\d/
MATH_LINE_FACTOR =
1.9

Instance Attribute Summary collapse

Attributes inherited from Arrolio::Flowable

#style

Instance Method Summary collapse

Methods inherited from Arrolio::Flowable

#keep_together?, #keep_with_next?, #page_break_after?, #page_break_before?, #space_after, #space_before, #split

Constructor Details

#initialize(runs, style: Style::Definition.new, measurer: nil, hanging_indent: 0.0) ⇒ TextFlowable

Returns a new instance of TextFlowable.



12
13
14
15
16
17
18
# File 'lib/arrolio/flowables/text_flowable.rb', line 12

def initialize(runs, style: Style::Definition.new, measurer: nil,
               hanging_indent: 0.0)
  super(style: style)
  @runs = Array(runs)
  @measurer = measurer || GlyphMeasurer.new(font_name: style.font_name)
  @hanging_indent = hanging_indent.to_f
end

Instance Attribute Details

#hanging_indentObject (readonly)

Returns the value of attribute hanging_indent.



10
11
12
# File 'lib/arrolio/flowables/text_flowable.rb', line 10

def hanging_indent
  @hanging_indent
end

#measurerObject (readonly)

Returns the value of attribute measurer.



10
11
12
# File 'lib/arrolio/flowables/text_flowable.rb', line 10

def measurer
  @measurer
end

#runsObject (readonly)

Returns the value of attribute runs.



10
11
12
# File 'lib/arrolio/flowables/text_flowable.rb', line 10

def runs
  @runs
end

Instance Method Details

#do_split(width, remaining_height, _context = nil) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/arrolio/flowables/text_flowable.rb', line 71

def do_split(width, remaining_height, _context = nil)
  lines = laid_out(width)
  line_h = line_height
  available = remaining_height - space_before
  head_count = (available.to_f / line_h).floor
  head_count = [head_count, lines.length].min
  head_count = 1 if head_count < 1 && lines.any?

  head_lines = lines[0...head_count]
  tail_lines = lines[head_count..] || []

  head_runs = collect_runs(head_lines)
  tail_runs = collect_runs(tail_lines)

  head = head_runs.empty? ? nil : self.class.new(head_runs, style: @style, measurer: @measurer)
  tail = tail_runs.empty? ? nil : self.class.new(tail_runs, style: @style, measurer: @measurer)
  [head, tail]
end

#emit(x, y, width, _context = nil) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/arrolio/flowables/text_flowable.rb', line 35

def emit(x, y, width, _context = nil)
  effective_width = width - @hanging_indent
  lines = laid_out(effective_width)
  text_height = (lines.length * line_height) +
                (math_line_count(lines) * line_height * (MATH_LINE_FACTOR - 1.0))
  total = text_height + space_before + space_after
  return [[], total] if lines.empty?

  text_y = y - space_before
  heights = lines.map do |line|
    math = line.placed_runs.any? { |pr| pr.run.text.match?(MATH_OPERATOR) }
    line_height * (math ? MATH_LINE_FACTOR : 1.0)
  end
  box = Output::PlacedBox.text(
    x: x, y: text_y - text_height,
    width: width, height: text_height,
    lines: lines, line_height: line_height, style: @style,
    hanging_indent: @hanging_indent, line_heights: heights
  )
  [[box], total]
end

#height(width, _context = nil) ⇒ Object



27
28
29
30
31
32
33
# File 'lib/arrolio/flowables/text_flowable.rb', line 27

def height(width, _context = nil)
  effective_width = width - @hanging_indent
  laid = laid_out(effective_width)
  text_height = (laid.length * line_height) +
                (math_line_count(laid) * line_height * (MATH_LINE_FACTOR - 1.0))
  text_height + space_before + space_after
end

#min_keep_height(_width, _context = nil) ⇒ Object

Widows for keep-with-next predecessors: how many lines must follow when the paragraph starts after a kept block.



63
64
65
# File 'lib/arrolio/flowables/text_flowable.rb', line 63

def min_keep_height(_width, _context = nil)
  space_before + ([widows_count, 1].max * line_height)
end

#splittable?Boolean

Returns:

  • (Boolean)


57
58
59
# File 'lib/arrolio/flowables/text_flowable.rb', line 57

def splittable?
  true
end

#widows_countObject



67
68
69
# File 'lib/arrolio/flowables/text_flowable.rb', line 67

def widows_count
  @style.widows ? @style.widows.to_i : 1
end