Class: Idml::TextEngine::Justifier

Inherits:
Object
  • Object
show all
Defined in:
lib/idml/text_engine/justifier.rb

Overview

Distributes slack space within a line per the paragraph's alignment. Adjusts x_offset and optionally scales inter-word spaces for justified text. last_line: (the paragraph's final line) keeps ragged right under :justified, as InDesign does.

Defined Under Namespace

Classes: SpacingLimits

Constant Summary collapse

DEFAULT_MAX_WORD_SPACING =
133.0
DEFAULT_MAX_LETTER_SPACING =
0.0
DEFAULT_MAX_GLYPH_SCALING =
100.0
DEFAULT_MIN_GLYPH_SCALING =
100.0
RTL_ALIGNMENT_MIRROR =
{
  left: :right, right: :left,
  start: :end, end: :start
}.freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(frame_width, alignment, last_line, limits, direction) ⇒ Justifier



28
29
30
31
32
33
# File 'lib/idml/text_engine/justifier.rb', line 28

def initialize(frame_width, alignment, last_line, limits, direction)
  @frame_width = frame_width
  @alignment = mirrored_alignment(alignment, direction)
  @last_line = last_line
  @limits = limits
end

Class Method Details

.justify(line:, frame_width:, alignment: :left, last_line: false, limits: nil, direction: nil) ⇒ Object



23
24
25
26
# File 'lib/idml/text_engine/justifier.rb', line 23

def self.justify(line:, frame_width:, alignment: :left,
                 last_line: false, limits: nil, direction: nil)
  new(frame_width, alignment, last_line, limits, direction).justify(line)
end

Instance Method Details

#effective_alignmentObject

The paragraph's last line stays ragged under full justification.



62
63
64
65
66
# File 'lib/idml/text_engine/justifier.rb', line 62

def effective_alignment
  return :left if @alignment == :justified && @last_line

  @alignment
end

#justify(line) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
# File 'lib/idml/text_engine/justifier.rb', line 35

def justify(line)
  case effective_alignment
  when :left, :start then line.x_offset = 0
  when :center, :middle
    line.x_offset = (@frame_width - line.width) / 2
  when :right, :end
    line.x_offset = @frame_width - line.width
  when :justified then justify_line(line)
  end
  line
end

#justify_line(line) ⇒ Object



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/idml/text_engine/justifier.rb', line 68

def justify_line(line)
  spaces = line.glyphs.count(&:is_space)
  slack = @frame_width - line.width
  return compress_glyphs(line, slack) if slack.negative?

  return if spaces.zero? || slack <= 0

  word_share = [slack, word_capacity(line, spaces)].min
  extra = word_share / spaces
  line.glyphs.each do |glyph|
    next unless glyph.is_space

    glyph.width += extra
  end
  residual = slack - word_share
  return unless residual.positive?

  before = line.glyphs.sum(&:width)
  distribute_letter_spacing(line, residual)
  residual -= (line.glyphs.sum(&:width) - before)
  distribute_glyph_scaling(line, residual) if residual.positive?
end

#mirrored_alignment(alignment, direction) ⇒ Object

RightToLeftDirection mirrors the visual alignment: what is "left" in an LTR paragraph sits right in an RTL one.



54
55
56
57
58
# File 'lib/idml/text_engine/justifier.rb', line 54

def mirrored_alignment(alignment, direction)
  return alignment unless direction == "RightToLeftDirection"

  RTL_ALIGNMENT_MIRROR[alignment] || alignment
end