class HexaPDF::Layout::Line

A Line describes a line of text and can contain TextFragment objects or InlineBox objects.

The items of a line fragment are aligned along the x-axis which coincides with the text baseline. The vertical alignment is determined by the value of the valign method:

:text_top

Align the top of the box with the top of the text of the Line.

:text_bottom

Align the bottom of the box with the bottom of the text of the Line.

:baseline

Align the bottom of the box with the baseline of the Line.

:top

Align the top of the box with the top of the Line.

:bottom

Align the bottom of the box with the bottom of the Line.

:text

This is a special alignment value for text fragment objects. The text fragment is aligned on the baseline and its minimum and maximum y-coordinates are used when calculating the line's text_y_min and text_y_max.

This value may be used by other objects if they should be handled similar to text fragments, e.g. graphical representation of characters (think: emoji fonts).

Item Requirements

Each item of a line fragment has to respond to the following methods:

x_min

The minimum x-coordinate of the item.

x_max

The maximum x-coordinate of the item.

width

The width of the item.

valign

The vertical alignment of the item (see above).

draw(canvas, x, y)

Should draw the item onto the canvas at the position (x, y).

If an item has a vertical alignment of :text, it additionally has to respond to the following methods:

y_min

The minimum y-coordinate of the item.

y_max

The maximum y-coordinate of the item.

Otherwise (i.e. a vertical alignment different from :text), the following method must be implemented:

height

The height of the item.

Attributes

items[RW]

The items: TextFragment and InlineBox objects

x_offset[RW]

An optional horizontal offset that should be taken into account when positioning the line.

y_offset[RW]

An optional vertical offset that should be taken into account when positioning the line.

For the first line in a paragraph this describes the offset from the top of the box to the baseline of the line. For all other lines it describes the offset from the previous baseline to the baseline of this line.

Public Class Methods

new(items = []) click to toggle source

Creates a new Line object, adding all given items to it.

# File lib/hexapdf/layout/line.rb, line 185
def initialize(items = [])
  @items = []
  items.each {|i| add(i) }
  @x_offset = 0
  @y_offset = 0
end

Public Instance Methods

<<(item)
Alias for: add
add(item) click to toggle source

Adds the given item at the end of the item list.

If both the item and the last item in the item list are TextFragment objects and they have the same style, they are combined.

Note: The cache is not cleared!

# File lib/hexapdf/layout/line.rb, line 198
def add(item)
  last = @items.last
  if last.instance_of?(item.class) && item.kind_of?(TextFragment) && last.style == item.style
    if last.items.frozen?
      @items[-1] = last = last.dup
      last.items = last.items.dup
    end
    last.items[last.items.length, 0] = item.items
    last.clear_cache
  else
    @items << item
  end
  self
end
Also aliased as: <<
clear_cache → line click to toggle source

Clears all cached values.

This method needs to be called if the line's items are changed!

# File lib/hexapdf/layout/line.rb, line 296
def clear_cache
  @x_max = @y_min = @y_max = @text_y_min = @text_y_max = @width = nil
  self
end
each {|item, x, y| block } click to toggle source

Yields each item together with its horizontal offset from 0 and vertical offset from the baseline.

# File lib/hexapdf/layout/line.rb, line 219
def each
  x = 0
  @items.each do |item|
    y = case item.valign
        when :text, :baseline then 0
        when :top then y_max - item.height
        when :text_top then text_y_max - item.height
        when :text_bottom then text_y_min
        when :bottom then y_min
        else
          raise HexaPDF::Error, "Unknown inline box alignment #{item.valign}"
        end
    yield(item, x, y)
    x += item.width
  end
end
height() click to toggle source

The height of the line fragment.

# File lib/hexapdf/layout/line.rb, line 276
def height
  y_max - y_min
end
ignore_justification!() click to toggle source

Specifies that this line should not be justified if line justification is used.

# File lib/hexapdf/layout/line.rb, line 281
def ignore_justification!
  @ignore_justification = true
end
ignore_justification?() click to toggle source

Returns true if justification should be ignored for this line.

# File lib/hexapdf/layout/line.rb, line 286
def ignore_justification?
  defined?(@ignore_justification) && @ignore_justification
end
text_y_max() click to toggle source

The maximum y-coordinate of any TextFragment item of the line.

# File lib/hexapdf/layout/line.rb, line 266
def text_y_max
  @text_y_max ||= calculate_y_dimensions[3]
end
text_y_min() click to toggle source

The minimum y-coordinate of any TextFragment item of the line.

# File lib/hexapdf/layout/line.rb, line 254
def text_y_min
  @text_y_min ||= calculate_y_dimensions[2]
end
width() click to toggle source

The width of the line fragment.

# File lib/hexapdf/layout/line.rb, line 271
def width
  @width ||= @items.sum(&:width)
end
x_max() click to toggle source

The maximum x-coordinate of the whole line.

# File lib/hexapdf/layout/line.rb, line 242
def x_max
  @x_max ||= width + (items[-1].x_max - items[-1].width)
end
x_min() click to toggle source

The minimum x-coordinate of the whole line.

# File lib/hexapdf/layout/line.rb, line 237
def x_min
  @items[0].x_min
end
y_max() click to toggle source

The maximum y-coordinate of any item of the line.

It is always greater than or equal to zero.

# File lib/hexapdf/layout/line.rb, line 261
def y_max
  @y_max ||= calculate_y_dimensions[1]
end
y_min() click to toggle source

The minimum y-coordinate of any item of the line.

It is always lower than or equal to zero.

# File lib/hexapdf/layout/line.rb, line 249
def y_min
  @y_min ||= calculate_y_dimensions[0]
end

Private Instance Methods

calculate_y_dimensions → [y_min, y_max, text_y_min, text_y_max] click to toggle source

Calculates all y-values and returns them as array.

The following algorithm is used for the calculations:

  1. Calculate text_y_min and text_y_max by using only the items with valign :text.

  2. Calculate the temporary y_min by using either the maximum height of all items with valign :text_top subtraced from text_y_max, or text_y_min, whichever is smaller.

    For the temporary y_max, use either the maximum height of all items with valign equal to :text_bottom added to text_y_min, or the maximum height of all items with valign :baseline, or text_y_max, whichever is larger.

  3. Calculate the final y_min by using either the maximum height of all items with valign :top subtracted from the temporary y_min, or the temporary y_min, whichever is smaller.

    Calculate the final y_max by using either the maximum height of all items with valign :bottom added to y_min, or the temporary y_max, whichever is larger.

In certain cases there is no unique solution to the values of y_min and y_max, for example, it depends on the order of the calculations in part 3.

# File lib/hexapdf/layout/line.rb, line 327
def calculate_y_dimensions
  @y_min, @y_max, @text_y_min, @text_y_max = HeightCalculator.new(@items).result
end