hexapdf 0.38.0 → 0.39.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b6df8bc8bdf189f60287c3dc0a0eccb1e1bca2a8b4310c1d5c2bb5d6661bae11
4
- data.tar.gz: a28fc9d3319f596774bda74476fbc77fe40ba8e29a2dcd1e588c18f0928e8538
3
+ metadata.gz: d0a43d232528df9bfc4a2c9baddd9cd1ddbd33fe7cce9d146b4e25760f25429b
4
+ data.tar.gz: 37cb10752d22bbc89fd18a779152ef7b5e02e6237318006a4b0e0a420d2890e2
5
5
  SHA512:
6
- metadata.gz: 11a382eceaa702705fe15484314e8d8b21c26ce2bf50d082be5e4ae27749251562474bfe1f4d410e53008120b37b6f43b42b1f9ecaca0ce123a672a6868a0515
7
- data.tar.gz: ef98043f0d6460bbfd4819ba34fd2fab4d9e7426b04d0005f1f65ae88d813ff92db6f9cb89cb3e88997c8b68dea7e7631ceb873f5091a6c1b8bd6aa72075ab32
6
+ metadata.gz: 79a27b101c502261e1bca7a25fa26fa434d38cec09a2ccb28a698a4364d8ed337ee63d82ce8cd4dd3097334ed54f0877565c25e20c2494c0ae7029156dc188ef
7
+ data.tar.gz: 69befc3a7066eb90a58ad4a65243939930f26ecc461e0f6f7c9bf0894ddfa58bf1a02567563caa453b0c6e745421de75e7dd433926d2a56b96aa4d71557059f5
data/CHANGELOG.md CHANGED
@@ -1,3 +1,21 @@
1
+ ## 0.39.0 - 2024-03-18
2
+
3
+ ### Added
4
+
5
+ * Hierarchical box information to the document layout engine
6
+ * Style property 'text_overflow' for controlling how overflowing text should be
7
+ handled
8
+
9
+ ### Changed
10
+
11
+ * [HexaPDF::Layout::Frame::FitResult#draw] to provide better optional content
12
+ group names
13
+
14
+ ### Fixed
15
+
16
+ * [HexaPDF::Layout::TextBox] to correctly respect a set height
17
+
18
+
1
19
  ## 0.38.0 - 2024-03-10
2
20
 
3
21
  ### Added
data/examples/030-pdfa.rb CHANGED
@@ -1,4 +1,4 @@
1
- # # PDF/A Compliance
1
+ # # PDF/A Conformance
2
2
  #
3
3
  # This example shows how to create a PDF file that is PDF/A compliant.
4
4
  #
@@ -179,8 +179,8 @@ module HexaPDF
179
179
  [column_left, column_bottom + height])
180
180
  shape = Geom2D::Algorithms::PolygonOperation.run(frame.shape, rect, :intersection)
181
181
  end
182
- column_frame = Frame.new(column_left, column_bottom, column_width, height,
183
- shape: shape, context: frame.context)
182
+ column_frame = frame.child_frame(column_left, column_bottom, column_width, height,
183
+ shape: shape, box: self)
184
184
  @box_fitter << column_frame
185
185
  end
186
186
 
@@ -131,8 +131,9 @@ module HexaPDF
131
131
 
132
132
  # Fits the children into the container.
133
133
  def fit_content(_available_width, _available_height, frame)
134
- my_frame = Frame.new(frame.x + reserved_width_left, frame.y - @height + reserved_height_bottom,
135
- content_width, content_height, context: frame.context)
134
+ my_frame = frame.child_frame(frame.x + reserved_width_left,
135
+ frame.y - @height + reserved_height_bottom,
136
+ content_width, content_height, box: self)
136
137
  @box_fitter = BoxFitter.new([my_frame])
137
138
  children.each {|box| @box_fitter.fit(box) }
138
139
 
@@ -91,6 +91,9 @@ module HexaPDF
91
91
  # Stores the result of fitting a box in a Frame.
92
92
  class FitResult
93
93
 
94
+ # The frame into which the box was fitted.
95
+ attr_accessor :frame
96
+
94
97
  # The box that was fitted into the frame.
95
98
  attr_accessor :box
96
99
 
@@ -110,8 +113,9 @@ module HexaPDF
110
113
  # drawing the box.
111
114
  attr_accessor :mask
112
115
 
113
- # Initialize the result object for the given box.
114
- def initialize(box)
116
+ # Initialize the result object for the given frame and box.
117
+ def initialize(frame, box)
118
+ @frame = frame
115
119
  @box = box
116
120
  @available_width = 0
117
121
  @available_height = 0
@@ -138,7 +142,10 @@ module HexaPDF
138
142
  def draw(canvas, dx: 0, dy: 0)
139
143
  doc = canvas.context.document
140
144
  if doc.config['debug']
141
- name = "#{box.class} (#{x.to_i},#{y.to_i}-#{box.width.to_i}x#{box.height.to_i})"
145
+ name = (frame.parent_boxes + [box]).map do |box|
146
+ box.class.to_s.sub(/.*::/, '')
147
+ end.join('-') << "##{box.object_id}"
148
+ name = "#{name} (#{(x + dx).to_i},#{(y + dy).to_i}-#{mask.width.to_i}x#{mask.height.to_i})"
142
149
  ocg = doc.optional_content.ocg(name)
143
150
  canvas.optional_content(ocg) do
144
151
  canvas.translate(dx, dy) do
@@ -147,7 +154,8 @@ module HexaPDF
147
154
  draw(:geom2d, object: mask, path_only: true).fill_stroke
148
155
  end
149
156
  end
150
- doc.optional_content.default_configuration.add_ocg_to_ui(ocg, path: 'Debug')
157
+ page = "Page #{canvas.context.index + 1}" rescue "XObject"
158
+ doc.optional_content.default_configuration.add_ocg_to_ui(ocg, path: ['Debug', page])
151
159
  end
152
160
  box.draw(canvas, x + dx, y + dy)
153
161
  end
@@ -195,14 +203,21 @@ module HexaPDF
195
203
  # should be used.
196
204
  attr_reader :context
197
205
 
206
+ # An array of box objects representing the parent boxes.
207
+ #
208
+ # The immediate parent is the last array entry, the top most parent the first one. All boxes
209
+ # that are fitted into this frame have to be child boxes of the immediate parent box.
210
+ attr_reader :parent_boxes
211
+
198
212
  # Creates a new Frame object for the given rectangular area.
199
- def initialize(left, bottom, width, height, shape: nil, context: nil)
213
+ def initialize(left, bottom, width, height, shape: nil, context: nil, parent_boxes: [])
200
214
  @left = left
201
215
  @bottom = bottom
202
216
  @width = width
203
217
  @height = height
204
218
  @shape = shape || create_rectangle(left, bottom, left + width, bottom + height)
205
219
  @context = context
220
+ @parent_boxes = parent_boxes.freeze
206
221
 
207
222
  @x = left
208
223
  @y = bottom + height
@@ -213,6 +228,25 @@ module HexaPDF
213
228
  @region_selection = :max_height
214
229
  end
215
230
 
231
+ # Creates a new Frame object based on this one.
232
+ #
233
+ # If the +init_args+ arguments are provided, a new Frame is created using the constructor. The
234
+ # optional +shape+ argument is then also passed to the constructor.
235
+ #
236
+ # Otherwise, this frame is duplicated. This kind of invocation is only useful if the +box+
237
+ # argument is provided (because otherwise there would be no difference to this frame).
238
+ #
239
+ # The +box+ argument can be used to add the appropriate parent box to the list of
240
+ # #parent_boxes for the newly created frame.
241
+ def child_frame(*init_args, shape: nil, box: nil)
242
+ parent_boxes = (box ? @parent_boxes.dup << box : @parent_boxes)
243
+ if init_args.empty?
244
+ dup.tap {|result| result.instance_variable_set(:@parent_boxes, parent_boxes) }
245
+ else
246
+ self.class.new(*init_args, shape: shape, context: @context, parent_boxes: parent_boxes)
247
+ end
248
+ end
249
+
216
250
  # Returns the HexaPDF::Document instance (through #context) that is associated with this Frame
217
251
  # object or +nil+ if no context object has been set.
218
252
  def document
@@ -227,7 +261,7 @@ module HexaPDF
227
261
  #
228
262
  # Use the FitResult#success? method to determine whether fitting was successful.
229
263
  def fit(box)
230
- fit_result = FitResult.new(box)
264
+ fit_result = FitResult.new(self, box)
231
265
  return fit_result if full?
232
266
 
233
267
  margin = box.style.margin if box.style.margin?
@@ -126,10 +126,17 @@ module HexaPDF
126
126
  height
127
127
  end
128
128
 
129
- # Fits the wrapped box, using the given context (see Frame#context).
130
- def fit_wrapped_box(context)
131
- @fit_result = Frame.new(0, 0, box.width, box.height == 0 ? 100_000 : box.height,
132
- context: context).fit(box)
129
+ # Fits the wrapped box.
130
+ #
131
+ # If the +frame+ argument is +nil+, a custom frame is created. Otherwise the given +frame+ is
132
+ # used for the fitting operation.
133
+ def fit_wrapped_box(frame)
134
+ frame = if frame
135
+ frame.child_frame(0, 0, box.width, box.height == 0 ? 100_000 : box.height)
136
+ else
137
+ Frame.new(0, 0, box.width, box.height == 0 ? 100_000 : box.height)
138
+ end
139
+ @fit_result = frame.fit(box)
133
140
  if !@fit_result.success?
134
141
  raise HexaPDF::Error, "Box for inline use could not be fit"
135
142
  elsif box.height > 99_000
@@ -227,12 +227,12 @@ module HexaPDF
227
227
  remove_indent_from_frame_shape(shape) unless shape.polygons.empty?
228
228
  end
229
229
 
230
- item_frame = Frame.new(item_frame_left, top - height, item_frame_width, height,
231
- shape: shape, context: frame.context)
230
+ item_frame = frame.child_frame(item_frame_left, top - height, item_frame_width, height,
231
+ shape: shape, box: self)
232
232
 
233
233
  if index != 0 || !split_box? || @split_box == :show_first_marker
234
234
  box = item_marker_box(frame.document, index)
235
- marker_frame = Frame.new(0, 0, content_indentation, height, context: frame.context)
235
+ marker_frame = frame.child_frame(0, 0, content_indentation, height, box: self)
236
236
  break unless box.fit(content_indentation, height, marker_frame)
237
237
  item_result.marker = box
238
238
  item_result.marker_pos_x = item_frame.x - content_indentation
@@ -1084,6 +1084,25 @@ module HexaPDF
1084
1084
  # 'Centered',
1085
1085
  # {text: "\u{00a0}", fill_horizontal: 1, overlays: overlays}])
1086
1086
 
1087
+ ##
1088
+ # :method: text_overflow
1089
+ # :call-seq:
1090
+ # text_overflow(mode = nil)
1091
+ #
1092
+ # Specifies how text overflowing a box with a given initial height should be handled:
1093
+ #
1094
+ # Possible values:
1095
+ #
1096
+ # :error:: An error is raised (default).
1097
+ # :truncate:: Truncates the overflowing text.
1098
+ #
1099
+ # Examples:
1100
+ #
1101
+ # #>pdf-composer100
1102
+ # composer.text("This is some longer text that does appear in two lines.")
1103
+ # composer.text("This is some longer text that does not appear in two lines.",
1104
+ # height: 15, text_overflow: :truncate)
1105
+
1087
1106
  ##
1088
1107
  # :method: background_color
1089
1108
  # :call-seq:
@@ -1435,6 +1454,7 @@ module HexaPDF
1435
1454
  extra_args: ", extra_arg = nil"}],
1436
1455
  [:last_line_gap, false, {valid_values: [true, false]}],
1437
1456
  [:fill_horizontal, nil],
1457
+ [:text_overflow, :error],
1438
1458
  [:background_color, nil],
1439
1459
  [:background_alpha, 1],
1440
1460
  [:padding, "Quad.new(0)", {setter: "Quad.new(value)"}],
@@ -218,7 +218,7 @@ module HexaPDF
218
218
  height = available_height - reserved_height
219
219
  return false if width <= 0 || height <= 0
220
220
 
221
- frame = Frame.new(0, 0, width, height, context: frame.context)
221
+ frame = frame.child_frame(0, 0, width, height, box: self)
222
222
  case children
223
223
  when Box
224
224
  fit_result = frame.fit(children)
@@ -607,6 +607,7 @@ module HexaPDF
607
607
  columns = calculate_column_widths(width)
608
608
  return false if columns.empty?
609
609
 
610
+ frame = frame.child_frame(box: self)
610
611
  @special_cells_fit_not_successful = false
611
612
  [@header_cells, @footer_cells].each do |special_cells|
612
613
  next unless special_cells
@@ -79,6 +79,7 @@ module HexaPDF
79
79
  return false if (@initial_width > 0 && @initial_width > available_width) ||
80
80
  (@initial_height > 0 && @initial_height > available_height)
81
81
 
82
+ frame = frame.child_frame(box: self)
82
83
  @width = @height = 0
83
84
  @result = if style.position == :flow
84
85
  @tl.fit(@items, frame.width_specification, frame.shape.bbox.height,
@@ -104,7 +105,8 @@ module HexaPDF
104
105
  @height += style.line_spacing.gap(@result.lines.last, @result.lines.last)
105
106
  end
106
107
 
107
- @result.status == :success
108
+ @result.status == :success ||
109
+ (@result.status == :height && @initial_height > 0 && style.text_overflow == :truncate)
108
110
  end
109
111
 
110
112
  # Splits the text box into two boxes if necessary and possible.
@@ -132,7 +134,14 @@ module HexaPDF
132
134
 
133
135
  # Draws the text into the box.
134
136
  def draw_content(canvas, x, y)
135
- return unless @result && !@result.lines.empty?
137
+ return unless @result
138
+
139
+ if @result.status == :height && @initial_height > 0 && style.text_overflow == :error
140
+ raise HexaPDF::Error, "Text doesn't fit into box with limited height and " \
141
+ "style property text_overflow is set to :error"
142
+ end
143
+
144
+ return if @result.lines.empty?
136
145
  @result.draw(canvas, x, y + content_height)
137
146
  end
138
147
 
@@ -307,10 +307,15 @@ module HexaPDF
307
307
  class SimpleLineWrapping
308
308
 
309
309
  # :call-seq:
310
- # SimpleLineWrapping.call(items, width_block) {|line, item| block } -> rest
310
+ # SimpleLineWrapping.call(items, width_block, frame = nil) {|line, item| block } -> rest
311
311
  #
312
312
  # Arranges the items into lines.
313
313
  #
314
+ # The optional +frame+ argument needs to be a Frame object that is used when fitting inline
315
+ # boxes. If not provided, a custom Frame object is used. However, if the items contain
316
+ # inline boxes that need to access a frame's context object, it is mandatory to provide an
317
+ # appropriate Frame object.
318
+ #
314
319
  # The +width_block+ argument has to be a callable object that returns the width of the line:
315
320
  #
316
321
  # * If the line width doesn't depend on the height or the vertical position of the line
@@ -340,7 +345,7 @@ module HexaPDF
340
345
  # current start of the line index should be stored for later use.
341
346
  #
342
347
  # After the algorithm is finished, it returns the unused items.
343
- def self.call(items, width_block, frame, &block)
348
+ def self.call(items, width_block, frame = nil, &block)
344
349
  obj = new(items, width_block, frame)
345
350
  if width_block.arity == 1
346
351
  obj.variable_width_wrapping(&block)
@@ -507,7 +512,7 @@ module HexaPDF
507
512
  #
508
513
  # Returns +true+ if the item could be added and +false+ otherwise.
509
514
  def add_box_item(item)
510
- item.fit_wrapped_box(@frame&.context) if item.kind_of?(InlineBox)
515
+ item.fit_wrapped_box(@frame) if item.kind_of?(InlineBox)
511
516
  return false unless @width + item.width <= @available_width
512
517
  @line_items.concat(@glue_items).push(item)
513
518
  @width += item.width
@@ -718,6 +723,10 @@ module HexaPDF
718
723
  # Specifies whether style.text_indent should be applied to the first line. This should be
719
724
  # set to +false+ if the items start with a continuation of a paragraph instead of starting
720
725
  # a new paragraph (e.g. after a page break).
726
+ #
727
+ # +frame+::
728
+ # If used with the document layout functionality, this should be the frame into which the
729
+ # text is laid out.
721
730
  def fit(items, width, height, apply_first_text_indent: true, frame: nil)
722
731
  unless items.empty? || items[0].respond_to?(:type)
723
732
  items = style.text_segmentation_algorithm.call(items)
@@ -37,6 +37,6 @@
37
37
  module HexaPDF
38
38
 
39
39
  # The version of HexaPDF.
40
- VERSION = '0.38.0'
40
+ VERSION = '0.39.0'
41
41
 
42
42
  end
@@ -10,7 +10,8 @@ describe HexaPDF::Layout::Frame::FitResult do
10
10
  doc = HexaPDF::Document.new(config: {'debug' => true})
11
11
  canvas = doc.pages.add.canvas
12
12
  box = HexaPDF::Layout::Box.create(width: 20, height: 20) {}
13
- result = HexaPDF::Layout::Frame::FitResult.new(box)
13
+ frame = HexaPDF::Layout::Frame.new(5, 10, 100, 150)
14
+ result = HexaPDF::Layout::Frame::FitResult.new(frame, box)
14
15
  result.mask = Geom2D::Rectangle(0, 0, 20, 20)
15
16
  result.x = result.y = 0
16
17
  result.draw(canvas, dx: 10, dy: 15)
@@ -30,7 +31,8 @@ describe HexaPDF::Layout::Frame::FitResult do
30
31
  Q
31
32
  CONTENTS
32
33
  ocg = doc.optional_content.ocgs.first
33
- assert_equal([['Debug', ocg]], doc.optional_content.default_configuration[:Order])
34
+ assert_equal([['Debug', ['Page 1', ocg]]], doc.optional_content.default_configuration[:Order])
35
+ assert_match(/10,15-20x20/, ocg.name)
34
36
  end
35
37
  end
36
38
 
@@ -61,6 +63,11 @@ describe HexaPDF::Layout::Frame do
61
63
  assert_equal(150, @frame.available_height)
62
64
  end
63
65
 
66
+ it "allows access to the frame's parent boxes" do
67
+ frame = HexaPDF::Layout::Frame.new(5, 10, 100, 150, parent_boxes: [:a])
68
+ assert_equal([:a], frame.parent_boxes)
69
+ end
70
+
64
71
  it "allows setting the shape of the frame on initialization" do
65
72
  shape = Geom2D::Polygon([50, 10], [55, 100], [105, 100], [105, 10])
66
73
  frame = HexaPDF::Layout::Frame.new(5, 10, 100, 150, shape: shape)
@@ -71,6 +78,27 @@ describe HexaPDF::Layout::Frame do
71
78
  assert_equal(90, frame.available_height)
72
79
  end
73
80
 
81
+ describe "child_frame" do
82
+ before do
83
+ @frame = HexaPDF::Layout::Frame.new(10, 10, 100, 100, parent_boxes: [:a])
84
+ end
85
+
86
+ it "duplicates the frame setting the parent boxes appropriately" do
87
+ assert_same(@frame.parent_boxes, @frame.child_frame.parent_boxes)
88
+ frame = @frame.child_frame(box: :b)
89
+ assert_equal([:a, :b], frame.parent_boxes)
90
+ end
91
+
92
+ it "creates a new frame, optionally adding a parent box" do
93
+ shape = Geom2D::Rectangle(0, 0, 20, 20)
94
+ frame = @frame.child_frame(0, 0, 20, 20, shape: shape)
95
+ assert_same(@frame.parent_boxes, frame.parent_boxes)
96
+ assert_equal(shape, frame.shape)
97
+ frame = @frame.child_frame(0, 0, 20, 20, box: :b)
98
+ assert_equal([:a, :b], frame.parent_boxes)
99
+ end
100
+ end
101
+
74
102
  it "returns an appropriate width specification object" do
75
103
  ws = @frame.width_specification(10)
76
104
  assert_kind_of(HexaPDF::Layout::WidthFromPolygon, ws)
@@ -97,6 +125,7 @@ describe HexaPDF::Layout::Frame do
97
125
  @canvas.expect(:translate, nil, pos)
98
126
  fit_result = @frame.fit(@box)
99
127
  refute_nil(fit_result)
128
+ assert_same(@frame, fit_result.frame)
100
129
  @frame.draw(@canvas, fit_result)
101
130
  assert_equal(mask, fit_result.mask.bbox.to_a)
102
131
  if @frame.shape.respond_to?(:polygons)
@@ -31,7 +31,14 @@ describe HexaPDF::Layout::InlineBox do
31
31
  end
32
32
 
33
33
  describe "fit_wrapped_box" do
34
- it "automatically fits the provided box into a frame" do
34
+ it "automatically fits the provided box into the given frame" do
35
+ ibox = inline_box(HexaPDF::Document.new.layout.text("test is going good", width: 20))
36
+ ibox.fit_wrapped_box(HexaPDF::Layout::Frame.new(0, 0, 50, 50))
37
+ assert_equal(20, ibox.width)
38
+ assert_equal(45, ibox.height)
39
+ end
40
+
41
+ it "automatically fits the provided box into a custom frame" do
35
42
  ibox = inline_box(HexaPDF::Document.new.layout.text("test is going good", width: 20))
36
43
  ibox.fit_wrapped_box(nil)
37
44
  assert_equal(20, ibox.width)
@@ -783,6 +783,7 @@ describe HexaPDF::Layout::Style do
783
783
  refute(@style.superscript)
784
784
  refute(@style.last_line_gap)
785
785
  refute(@style.fill_horizontal)
786
+ assert_equal(:error, @style.text_overflow)
786
787
  assert_kind_of(HexaPDF::Layout::Style::Layers, @style.underlays)
787
788
  assert_kind_of(HexaPDF::Layout::Style::Layers, @style.overlays)
788
789
  assert_equal(:default, @style.position)
@@ -50,8 +50,7 @@ describe HexaPDF::Layout::TextBox do
50
50
  end
51
51
 
52
52
  it "fits into the frame's outline" do
53
- inline_box = HexaPDF::Layout::InlineBox.create(width: 10, height: 10) {}
54
- box = create_box([inline_box] * 20, style: {position: :flow})
53
+ box = create_box([@inline_box] * 20, style: {position: :flow})
55
54
  assert(box.fit(100, 100, @frame))
56
55
  assert_equal(100, box.width)
57
56
  assert_equal(20, box.height)
@@ -80,6 +79,16 @@ describe HexaPDF::Layout::TextBox do
80
79
  end
81
80
  end
82
81
 
82
+ it "respects the style property text_overflow when fitting too much text" do
83
+ box = create_box([@inline_box] * 20, height: 15)
84
+ refute(box.fit(100, 100, @frame))
85
+ box.style.text_overflow = :truncate
86
+ assert(box.fit(100, 100, @frame))
87
+
88
+ box = create_box([@inline_box] * 20, style: {text_overflow: :truncate})
89
+ refute(box.fit(100, 15, @frame))
90
+ end
91
+
83
92
  it "can't fit the text box if the set width is bigger than the available width" do
84
93
  box = create_box([@inline_box], width: 101)
85
94
  refute(box.fit(100, 100, @frame))
@@ -154,13 +163,16 @@ describe HexaPDF::Layout::TextBox do
154
163
  end
155
164
 
156
165
  describe "draw" do
166
+ before do
167
+ @canvas = HexaPDF::Document.new.pages.add.canvas
168
+ end
169
+
157
170
  it "draws the layed out inline items onto the canvas" do
158
171
  inline_box = HexaPDF::Layout::InlineBox.create(width: 10, height: 10,
159
172
  border: {width: 1})
160
173
  box = create_box([inline_box], width: 100, height: 30, style: {padding: [10, 5]})
161
- box.fit(100, 100, nil)
174
+ box.fit(100, 100, @frame)
162
175
 
163
- @canvas = HexaPDF::Document.new.pages.add.canvas
164
176
  box.draw(@canvas, 0, 0)
165
177
  assert_operators(@canvas.contents, [[:save_graphics_state],
166
178
  [:restore_graphics_state],
@@ -179,11 +191,16 @@ describe HexaPDF::Layout::TextBox do
179
191
  end
180
192
 
181
193
  it "draws nothing onto the canvas if the box is empty" do
182
- @canvas = HexaPDF::Document.new.pages.add.canvas
183
194
  box = create_box([])
184
195
  box.draw(@canvas, 5, 5)
185
196
  assert_operators(@canvas.contents, [])
186
197
  end
198
+
199
+ it "raises an error if there is too much content for a set height with text_overlow=:error" do
200
+ box = create_box([@inline_box] * 20, height: 15)
201
+ box.fit(100, 100, @frame)
202
+ assert_raises(HexaPDF::Error) { box.draw(@canvas, 0, 0) }
203
+ end
187
204
  end
188
205
 
189
206
  it "is empty if there is a result without any text lines" do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hexapdf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.38.0
4
+ version: 0.39.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Leitner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-03-10 00:00:00.000000000 Z
11
+ date: 2024-03-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cmdparse