idml 0.8.6 → 0.8.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '04038941020b897a48513a0386fe33c4108384351a40e47e4ea50c2f09709611'
4
- data.tar.gz: 5e79b2dc7e0ec38818d06b74196bfb61227e4cb80c2e5989f8b836858469db70
3
+ metadata.gz: ea725628da813f202ff5f6c8c9659e1de20b24d8eb9d92c6cd8cc43aad12948c
4
+ data.tar.gz: 3ae66c7b8c22ba9660da4a8bae4a8f2314cb13e90aa72f0c673350415ab77cfc
5
5
  SHA512:
6
- metadata.gz: 115565aeb1f5c1da58d7a94337b3a8243da2303b4e12b25516582a7cc94065752d54df398a4f02632067b3a2b9495449911b43ee85b410d23b6a90d27e33c2ca
7
- data.tar.gz: 3754116e6abce4fb0481f8fdb02edb3452df9a0a6f7ff0417ca9500ab80155b91ceea0336a37d9defe41c75963c7040b75a2774f096fc5217285d57e19e6a41a
6
+ metadata.gz: e6ec5c19fb106644c373ee8a3cd21526cfaff1ce88c7d56d7c65b6376fe508ba984203d2d7d7249d426fc9486d21f5d7dbc1f758c026dd6f60c923631e31a4d8
7
+ data.tar.gz: 82cd84ff102aafce7c0766e1bb3aea5393a20f4d959753273ad163f15a9b83ab22a323c8b369548b45a3cc6d3e0ec5857eac1663ccdb601e9adb093c7067121e
@@ -1,12 +1,20 @@
1
1
  # TODO PDF 114: Text wrap around shapes (TextWrapPreference)
2
2
 
3
- ## Status: PARTIAL — `Render::TextWrapResolver` computes BoundingBox-mode
4
- contours from page items declaring TextWrapPreference.
5
- `overlap_width(line_y, line_height, frame_x, frame_right)` returns the
6
- horizontal overlap for a text line. Rectangle now carries the
7
- TextWrapPreference child. Integration with TextFrameRenderer
8
- (per-line wrap width adjustment during layout) is the remaining work —
9
- requires line-by-line contour queries in the layout pipeline.
3
+ ## Status: DONE for BoundingBox mode — `Render::TextWrapResolver` computes
4
+ wrap contours from page items declaring TextWrapPreference with
5
+ TextWrapMode != "None". SpreadRenderer builds the resolver and passes
6
+ it via RenderContext. TextFrameRenderer's `text_wrap_overlap` queries
7
+ overlap at each run's y position and reduces the wrap width — text
8
+ flows around the shape instead of running over it.
9
+
10
+ Shape page items (Rectangle, Oval, Polygon, GraphicLine, Path) all
11
+ carry the TextWrapPreference child element. Non-shape items (Page,
12
+ Link) are filtered by WRAPPABLE_TYPES to avoid NoMethodError.
13
+
14
+ Per-run approximation: all lines in a run get the same reduced width.
15
+ True per-line adjustment (when a run spans the contour boundary)
16
+ requires line-count-aware layout. Shape mode (contour following) and
17
+ Inverse mode remain unsupported.
10
18
 
11
19
  ## Problem
12
20
 
@@ -18,6 +18,7 @@ module Idml
18
18
  attribute :item_layer, :string
19
19
  attribute :properties, Idml::Elements::Properties, collection: true
20
20
  attribute :transparency_setting, Idml::Elements::TransparencySetting
21
+ attribute :text_wrap_preference, Idml::Elements::TextWrapPreference
21
22
 
22
23
  xml do
23
24
  root "GraphicLine"
@@ -34,6 +35,7 @@ module Idml
34
35
  map_attribute "ItemLayer", to: :item_layer
35
36
  map_element "Properties", to: :properties
36
37
  map_element "TransparencySetting", to: :transparency_setting
38
+ map_element "TextWrapPreference", to: :text_wrap_preference
37
39
  end
38
40
 
39
41
  def geometric_bounds
@@ -29,6 +29,7 @@ module Idml
29
29
  attribute :item_layer, :string
30
30
  attribute :properties, Idml::Elements::Properties, collection: true
31
31
  attribute :transparency_setting, Idml::Elements::TransparencySetting
32
+ attribute :text_wrap_preference, Idml::Elements::TextWrapPreference
32
33
  attribute :image, Idml::Elements::Image, collection: true
33
34
 
34
35
  xml do
@@ -50,6 +51,7 @@ module Idml
50
51
  map_attribute "ItemLayer", to: :item_layer
51
52
  map_element "Properties", to: :properties
52
53
  map_element "TransparencySetting", to: :transparency_setting
54
+ map_element "TextWrapPreference", to: :text_wrap_preference
53
55
  map_element "Image", to: :image
54
56
  end
55
57
 
@@ -25,6 +25,7 @@ module Idml
25
25
  attribute :item_layer, :string
26
26
  attribute :properties, Idml::Elements::Properties, collection: true
27
27
  attribute :transparency_setting, Idml::Elements::TransparencySetting
28
+ attribute :text_wrap_preference, Idml::Elements::TextWrapPreference
28
29
 
29
30
  xml do
30
31
  root "Path"
@@ -41,6 +42,7 @@ module Idml
41
42
  map_attribute "ItemLayer", to: :item_layer
42
43
  map_element "Properties", to: :properties
43
44
  map_element "TransparencySetting", to: :transparency_setting
45
+ map_element "TextWrapPreference", to: :text_wrap_preference
44
46
  end
45
47
 
46
48
  def geometric_bounds
@@ -20,6 +20,7 @@ module Idml
20
20
  attribute :item_layer, :string
21
21
  attribute :properties, Idml::Elements::Properties, collection: true
22
22
  attribute :transparency_setting, Idml::Elements::TransparencySetting
23
+ attribute :text_wrap_preference, Idml::Elements::TextWrapPreference
23
24
  attribute :image, Idml::Elements::Image, collection: true
24
25
 
25
26
  xml do
@@ -39,6 +40,7 @@ module Idml
39
40
  map_attribute "ItemLayer", to: :item_layer
40
41
  map_element "Properties", to: :properties
41
42
  map_element "TransparencySetting", to: :transparency_setting
43
+ map_element "TextWrapPreference", to: :text_wrap_preference
42
44
  map_element "Image", to: :image
43
45
  end
44
46
 
@@ -23,6 +23,7 @@ module Idml
23
23
  :chain_controller,
24
24
  :condition_filter,
25
25
  :style_lookup,
26
+ :text_wrap_resolver,
26
27
  keyword_init: true,
27
28
  )
28
29
  end
@@ -436,6 +436,8 @@ module Idml
436
436
  rendered_count)
437
437
  run_wrap = drop_cap_wrap_width(wrap_width, dc_width,
438
438
  dc_lines, rendered_count)
439
+ run_wrap -= text_wrap_overlap(context, layout_frame, cursor_y,
440
+ run)
439
441
  positioned, next_y = layout_run(
440
442
  canvas, run, paragraph, context, layout_frame, font,
441
443
  run_wrap, cursor_y, space_before,
@@ -450,6 +452,27 @@ module Idml
450
452
  end
451
453
  private_class_method :iterate_paragraph_runs
452
454
 
455
+ # Computes the text-wrap overlap for a run at its current y
456
+ # position. Uses the run's point_size as the line height
457
+ # approximation. Returns 0.0 when no resolver is wired or no
458
+ # contours overlap. Per-run approximation: all lines in the
459
+ # run get the same reduced width (correct when the run is
460
+ # fully inside or outside the contour; approximate when it
461
+ # spans the boundary).
462
+ def self.text_wrap_overlap(context, layout_frame, cursor_y, run)
463
+ resolver = context.text_wrap_resolver
464
+ return 0.0 unless resolver
465
+
466
+ size = run.point_size || DEFAULT_SIZE
467
+ frame_x = layout_frame.x + (layout_frame.inset_left || 0)
468
+ frame_right = layout_frame.x + layout_frame.width -
469
+ (layout_frame.inset_right || 0)
470
+ overlap = resolver.overlap_width(cursor_y, size,
471
+ frame_x, frame_right)
472
+ [overlap, 0.0].max
473
+ end
474
+ private_class_method :text_wrap_overlap
475
+
453
476
  # Strips drop cap characters from the first run so they don't
454
477
  # render twice (once as the enlarged drop cap, once as normal
455
478
  # text). Returns a new run list with the first run's text
@@ -39,6 +39,7 @@ module Idml
39
39
  chain_controller: StoryChainController.new,
40
40
  condition_filter: @condition_filter,
41
41
  style_lookup: @style_lookup,
42
+ text_wrap_resolver: build_text_wrap_resolver(spread, page_height),
42
43
  }
43
44
  images_by_parent = group_images_by_parent(image_refs)
44
45
 
@@ -144,6 +145,10 @@ module Idml
144
145
 
145
146
  ColorResolver.new(@package.graphic)
146
147
  end
148
+
149
+ def build_text_wrap_resolver(spread, page_height)
150
+ TextWrapResolver.build(spread, page_height: page_height)
151
+ end
147
152
  end
148
153
  end
149
154
  end
@@ -66,16 +66,35 @@ module Idml
66
66
  end
67
67
  private_class_method :contour_for
68
68
 
69
+ # Page item types that can declare TextWrapPreference per the
70
+ # Spread schema. Used to guard the attribute read — querying
71
+ # non-shape items (Page, Link) would raise NoMethodError.
72
+ WRAPPABLE_TYPES = [
73
+ Idml::Elements::Rectangle,
74
+ Idml::Elements::Oval,
75
+ Idml::Elements::Polygon,
76
+ Idml::Elements::GraphicLine,
77
+ Idml::Elements::Path,
78
+ Idml::Elements::Group,
79
+ ].freeze
80
+
69
81
  def self.wrap_preference(item)
70
- pref = item.text_wrap_preference if item.is_a?(Lutaml::Model::Serializable)
71
- return nil unless pref
72
- return nil if pref.text_wrap_mode.nil? ||
82
+ return nil unless wrappable?(item)
83
+
84
+ pref = item.text_wrap_preference
85
+ return nil if pref.nil? ||
86
+ pref.text_wrap_mode.nil? ||
73
87
  pref.text_wrap_mode == "None"
74
88
 
75
89
  pref
76
90
  end
77
91
  private_class_method :wrap_preference
78
92
 
93
+ def self.wrappable?(item)
94
+ WRAPPABLE_TYPES.any? { |type| item.is_a?(type) }
95
+ end
96
+ private_class_method :wrappable?
97
+
79
98
  def self.bounding_box_mode?(pref)
80
99
  pref.text_wrap_mode == "BoundingBox"
81
100
  end
data/lib/idml/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Idml
4
- VERSION = "0.8.6"
4
+ VERSION = "0.8.7"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: idml
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.6
4
+ version: 0.8.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose