Class: Idml::Render::TextWrapResolver
- Inherits:
-
Object
- Object
- Idml::Render::TextWrapResolver
- Defined in:
- lib/idml/render/text_wrap_resolver.rb
Overview
Resolves text-wrap contours from page items that declare TextWrapPreference. For BoundingBox mode (the common case), the contour is the item's geometric bounds expanded by the wrap offsets. TextFrameRenderer queries this resolver per text line to compute the effective wrap width — lines that overlap a contour get their width reduced by the overlap.
Supported: BoundingBox mode (rectangle intersection) with TextWrapSide awareness (LeftSide / RightSide / LargestArea pick the side text flows on; BothSides and the spine variants narrow by the full overlap). Shape contours (Contour mode) narrow by polygon overlap without side awareness. Unsupported: Inverse mode's side behavior.
Defined Under Namespace
Classes: Contour
Constant Summary collapse
- OFFSET_ATTRS =
i[ offset_top offset_left offset_bottom offset_right ].freeze
- JUMP_MODES =
The wrap shape for an item: a bounding-box rectangle (BoundingBoxTextWrap — the legacy "BoundingBox" spelling is also accepted from early synthetic fixtures) or a flattened PathGeometry polygon (Contour mode). JumpObject moves text below the object; NextColumn approximates as the same jump-below in a single-column frame (true column jumping needs chain integration, documented in TODO.pdf/61).
%w[JumpObjectTextWrap NextColumnTextWrap].freeze
- WRAPPABLE_TYPES =
Page item types that can declare TextWrapPreference per the Spread schema. Used to guard the attribute read — querying non-shape items (Page, Link) would raise NoMethodError.
[ Idml::Elements::Rectangle, Idml::Elements::Oval, Idml::Elements::Polygon, Idml::Elements::GraphicLine, Idml::Elements::Path, Idml::Elements::Group, ].freeze
Instance Attribute Summary collapse
-
#contours ⇒ Object
readonly
Returns the value of attribute contours.
Class Method Summary collapse
Instance Method Summary collapse
-
#initialize(contours) ⇒ TextWrapResolver
constructor
A new instance of TextWrapResolver.
-
#jump_contour_bottom(line_y, line_height, frame_x, frame_right) ⇒ Object
Bottom edge of the lowest jump contour overlapping the given band — where text resumes below a JumpObject.
-
#next_column_block?(line_y, line_height, frame_x, frame_right) ⇒ Boolean
True when a NextColumn contour blocks the given band: in a multi-column frame the renderer abandons the column and the chain resumes in the next one.
-
#wrap_adjustment(line_y, line_height, frame_x, frame_right) ⇒ Object
Side-aware adjustment for a text line: returns [width_reduction, x_shift].
- #x_overlap?(contour, frame_x, frame_right) ⇒ Boolean
- #x_overlap_width(contour, frame_x, frame_right) ⇒ Object
- #y_overlap?(contour, line_y, line_height) ⇒ Boolean
Constructor Details
#initialize(contours) ⇒ TextWrapResolver
Returns a new instance of TextWrapResolver.
38 39 40 |
# File 'lib/idml/render/text_wrap_resolver.rb', line 38 def initialize(contours) @contours = contours end |
Instance Attribute Details
#contours ⇒ Object (readonly)
Returns the value of attribute contours.
42 43 44 |
# File 'lib/idml/render/text_wrap_resolver.rb', line 42 def contours @contours end |
Class Method Details
.build(spread, page_height: 792) ⇒ Object
29 30 31 32 33 34 35 36 |
# File 'lib/idml/render/text_wrap_resolver.rb', line 29 def self.build(spread, page_height: 792) contours = [] spread.each_page_item do |item| contour = contour_for(item, page_height) contours << contour if contour end new(contours) end |
Instance Method Details
#jump_contour_bottom(line_y, line_height, frame_x, frame_right) ⇒ Object
Bottom edge of the lowest jump contour overlapping the given band — where text resumes below a JumpObject. nil when no jump contour blocks the band.
117 118 119 120 121 122 123 124 125 126 |
# File 'lib/idml/render/text_wrap_resolver.rb', line 117 def jump_contour_bottom(line_y, line_height, frame_x, frame_right) bottoms = @contours.filter_map do |contour| next unless skip_contour?(contour) next unless y_overlap?(contour, line_y, line_height) && x_overlap?(contour, frame_x, frame_right) contour.y end bottoms.min end |
#next_column_block?(line_y, line_height, frame_x, frame_right) ⇒ Boolean
True when a NextColumn contour blocks the given band: in a multi-column frame the renderer abandons the column and the chain resumes in the next one.
139 140 141 142 143 144 145 |
# File 'lib/idml/render/text_wrap_resolver.rb', line 139 def next_column_block?(line_y, line_height, frame_x, frame_right) @contours.any? do |contour| box_contour?(contour) && contour.next_column && y_overlap?(contour, line_y, line_height) && x_overlap?(contour, frame_x, frame_right) end end |
#wrap_adjustment(line_y, line_height, frame_x, frame_right) ⇒ Object
Side-aware adjustment for a text line: returns [width_reduction, x_shift]. LeftSide keeps text left of the contour (reduce, no shift); RightSide moves text past the contour's right edge (reduce + shift); LargestArea picks the roomier side; BothSides and the spine variants (which need binding-side context) reduce by the full overlap. Multiple contours combine by max — the per-run approximation.
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/idml/render/text_wrap_resolver.rb', line 51 def wrap_adjustment(line_y, line_height, frame_x, frame_right) reduction = 0.0 shift = 0.0 @contours.each do |contour| unless contour.is_a?(WrapContour::Shape) r, s = box_adjustment(contour, line_y, line_height, frame_x, frame_right) reduction = [reduction, r].max shift = [shift, s].max next end width = WrapContour.overlap_width(contour, line_y, line_height, frame_x, frame_right) if contour.inverse reduction = [reduction, (frame_right - frame_x) - width].max next end # Side-aware shapes (TODO 147): the side dispatch uses # the polygon's bounding box; narrowing itself keeps the # exact polygon overlap for BothSides. bbox_left, _bottom, bbox_right, = WrapContour.bounding_box( contour, ) r, s = interval_side_adjustment(contour.side, bbox_left, bbox_right, width, frame_x, frame_right) reduction = [reduction, r].max shift = [shift, s].max end [reduction, shift] end |
#x_overlap?(contour, frame_x, frame_right) ⇒ Boolean
269 270 271 |
# File 'lib/idml/render/text_wrap_resolver.rb', line 269 def x_overlap?(contour, frame_x, frame_right) contour.x < frame_right && contour.x + contour.width > frame_x end |
#x_overlap_width(contour, frame_x, frame_right) ⇒ Object
273 274 275 276 277 |
# File 'lib/idml/render/text_wrap_resolver.rb', line 273 def x_overlap_width(contour, frame_x, frame_right) left = [contour.x, frame_x].max right = [contour.x + contour.width, frame_right].min [right - left, 0].max end |
#y_overlap?(contour, line_y, line_height) ⇒ Boolean
261 262 263 264 265 266 267 |
# File 'lib/idml/render/text_wrap_resolver.rb', line 261 def y_overlap?(contour, line_y, line_height) line_top = line_y + line_height line_bottom = line_y contour_top = contour.y + contour.height contour_bottom = contour.y line_top > contour_bottom && line_bottom < contour_top end |