Class: Idml::Render::PositionTracker

Inherits:
Object
  • Object
show all
Defined in:
lib/idml/render/position_tracker.rb

Overview

Accumulates positioned text ranges during TextFrame rendering. Used by HyperlinkEmitter to compute precise per-source link rects when text contains IDML hyperlinks.

Lifecycle:

1. Pipeline constructs one tracker per render.
2. RenderContext carries it to renderers.
3. TextFrameRenderer records each line's range after layout.
4. HyperlinkEmitter queries for ranges overlapping each
 hyperlink source's character range.

PositionedRange is a plain Struct so the data is trivially shareable without coupling to any renderer implementation.

Defined Under Namespace

Classes: PositionedRange

Instance Method Summary collapse

Constructor Details

#initializePositionTracker

Returns a new instance of PositionTracker.



24
25
26
# File 'lib/idml/render/position_tracker.rb', line 24

def initialize
  @ranges_by_frame = {}
end

Instance Method Details

#add(frame_self, start_char:, end_char:, x:, y:, width:, height:) ⇒ Object

Records a positioned range for a frame. frame_self is the Self attribute of the TextFrame so multiple frames on the same spread don't collide.



31
32
33
34
35
36
37
38
39
40
41
# File 'lib/idml/render/position_tracker.rb', line 31

def add(frame_self, start_char:, end_char:, x:, y:, width:, height:)
  bucket = @ranges_by_frame[frame_self] ||= []
  bucket << PositionedRange.new(
    start_char: start_char,
    end_char: end_char,
    x: x,
    y: y,
    width: width,
    height: height,
  )
end

#clearObject

Test helper: clears all recorded ranges.



63
64
65
# File 'lib/idml/render/position_tracker.rb', line 63

def clear
  @ranges_by_frame.clear
end

#ranges_for(frame_self) ⇒ Object

Returns the list of positioned ranges for a frame, or [].



44
45
46
# File 'lib/idml/render/position_tracker.rb', line 44

def ranges_for(frame_self)
  @ranges_by_frame[frame_self] || []
end

#rect_for_range(frame_self, from:, to:) ⇒ Object

Returns the bounding rect [x1, y1, x2, y2] covering all ranges whose [start_char, end_char] intersects [from, to]. Returns nil when no range overlaps.



51
52
53
54
55
56
57
58
59
60
# File 'lib/idml/render/position_tracker.rb', line 51

def rect_for_range(frame_self, from:, to:)
  matching = ranges_for(frame_self).select do |range|
    range.start_char < to && range.end_char > from
  end
  return nil if matching.empty?

  xs = matching.flat_map { |r| [r.x, r.x + r.width] }
  ys = matching.flat_map { |r| [r.y, r.y + r.height] }
  [xs.min, ys.min, xs.max, ys.max]
end