hexapdf 0.43.0 → 0.45.0
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 +4 -4
- data/CHANGELOG.md +36 -0
- data/examples/027-composer_optional_content.rb +6 -4
- data/examples/030-pdfa.rb +13 -11
- data/lib/hexapdf/composer.rb +23 -0
- data/lib/hexapdf/content/canvas.rb +3 -3
- data/lib/hexapdf/content/canvas_composer.rb +1 -0
- data/lib/hexapdf/document/files.rb +7 -2
- data/lib/hexapdf/document/layout.rb +15 -3
- data/lib/hexapdf/document/metadata.rb +12 -1
- data/lib/hexapdf/font/type1/character_metrics.rb +1 -1
- data/lib/hexapdf/font/type1/font_metrics.rb +1 -1
- data/lib/hexapdf/layout/box.rb +180 -66
- data/lib/hexapdf/layout/box_fitter.rb +1 -0
- data/lib/hexapdf/layout/column_box.rb +18 -28
- data/lib/hexapdf/layout/container_box.rb +6 -6
- data/lib/hexapdf/layout/frame.rb +13 -94
- data/lib/hexapdf/layout/image_box.rb +4 -4
- data/lib/hexapdf/layout/list_box.rb +13 -31
- data/lib/hexapdf/layout/style.rb +8 -4
- data/lib/hexapdf/layout/table_box.rb +55 -58
- data/lib/hexapdf/layout/text_box.rb +84 -71
- data/lib/hexapdf/layout/text_fragment.rb +1 -1
- data/lib/hexapdf/layout/text_layouter.rb +7 -8
- data/lib/hexapdf/parser.rb +5 -2
- data/lib/hexapdf/rectangle.rb +4 -4
- data/lib/hexapdf/type/file_specification.rb +9 -5
- data/lib/hexapdf/type/form.rb +2 -2
- data/lib/hexapdf/type/graphics_state_parameter.rb +1 -1
- data/lib/hexapdf/version.rb +1 -1
- data/test/hexapdf/content/test_canvas_composer.rb +13 -8
- data/test/hexapdf/document/test_files.rb +5 -0
- data/test/hexapdf/document/test_layout.rb +16 -0
- data/test/hexapdf/document/test_metadata.rb +21 -0
- data/test/hexapdf/layout/test_box.rb +93 -37
- data/test/hexapdf/layout/test_box_fitter.rb +7 -0
- data/test/hexapdf/layout/test_column_box.rb +7 -13
- data/test/hexapdf/layout/test_container_box.rb +1 -1
- data/test/hexapdf/layout/test_frame.rb +7 -46
- data/test/hexapdf/layout/test_image_box.rb +14 -6
- data/test/hexapdf/layout/test_list_box.rb +26 -27
- data/test/hexapdf/layout/test_table_box.rb +47 -54
- data/test/hexapdf/layout/test_text_box.rb +83 -83
- data/test/hexapdf/test_composer.rb +20 -5
- data/test/hexapdf/test_parser.rb +8 -0
- data/test/hexapdf/test_serializer.rb +1 -0
- data/test/hexapdf/type/test_file_specification.rb +2 -1
- metadata +2 -2
data/lib/hexapdf/layout/frame.rb
CHANGED
@@ -45,7 +45,7 @@ module HexaPDF
|
|
45
45
|
#
|
46
46
|
# == Usage
|
47
47
|
#
|
48
|
-
# After a Frame object is initialized, it is ready for
|
48
|
+
# After a Frame object is initialized, it is ready for fitting boxes in it and drawing them.
|
49
49
|
#
|
50
50
|
# The explicit way of drawing a box follows these steps:
|
51
51
|
#
|
@@ -65,10 +65,6 @@ module HexaPDF
|
|
65
65
|
# splitting is successful, the first box can be drawn (Make sure that the second box is
|
66
66
|
# handled correctly). Otherwise, start over with #find_next_region.
|
67
67
|
#
|
68
|
-
# For applications where splitting is not necessary, an easier way is to just use #draw and
|
69
|
-
# #find_next_region together, as #draw calls #fit if the box was not fit into the current
|
70
|
-
# region.
|
71
|
-
#
|
72
68
|
# == Used Box Properties
|
73
69
|
#
|
74
70
|
# The style properties 'position', 'align', 'valign', 'margin' and 'mask_mode' are taken into
|
@@ -88,80 +84,6 @@ module HexaPDF
|
|
88
84
|
|
89
85
|
include HexaPDF::Utils
|
90
86
|
|
91
|
-
# Stores the result of fitting a box in a Frame.
|
92
|
-
class FitResult
|
93
|
-
|
94
|
-
# The frame into which the box was fitted.
|
95
|
-
attr_accessor :frame
|
96
|
-
|
97
|
-
# The box that was fitted into the frame.
|
98
|
-
attr_accessor :box
|
99
|
-
|
100
|
-
# The horizontal position where the box will be drawn.
|
101
|
-
attr_accessor :x
|
102
|
-
|
103
|
-
# The vertical position where the box will be drawn.
|
104
|
-
attr_accessor :y
|
105
|
-
|
106
|
-
# The available width in the frame for this particular box.
|
107
|
-
attr_accessor :available_width
|
108
|
-
|
109
|
-
# The available height in the frame for this particular box.
|
110
|
-
attr_accessor :available_height
|
111
|
-
|
112
|
-
# The rectangle (a Geom2D::Rectangle object) that will be removed from the frame when
|
113
|
-
# drawing the box.
|
114
|
-
attr_accessor :mask
|
115
|
-
|
116
|
-
# Initialize the result object for the given frame and box.
|
117
|
-
def initialize(frame, box)
|
118
|
-
@frame = frame
|
119
|
-
@box = box
|
120
|
-
@available_width = 0
|
121
|
-
@available_height = 0
|
122
|
-
@success = false
|
123
|
-
end
|
124
|
-
|
125
|
-
# Marks the fitting status as success.
|
126
|
-
def success!
|
127
|
-
@success = true
|
128
|
-
end
|
129
|
-
|
130
|
-
# Returns +true+ if fitting was successful.
|
131
|
-
def success?
|
132
|
-
@success
|
133
|
-
end
|
134
|
-
|
135
|
-
# Draws the #box onto the canvas at (#x + *dx*, #y + *dy*).
|
136
|
-
#
|
137
|
-
# The relative offset (dx, dy) is useful when rendering results that were accumulated and
|
138
|
-
# then need to be moved because the container holding them changes its position.
|
139
|
-
#
|
140
|
-
# The configuration option "debug" can be used to add visual debug output with respect to
|
141
|
-
# box placement.
|
142
|
-
def draw(canvas, dx: 0, dy: 0)
|
143
|
-
doc = canvas.context.document
|
144
|
-
if doc.config['debug']
|
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})"
|
149
|
-
ocg = doc.optional_content.ocg(name)
|
150
|
-
canvas.optional_content(ocg) do
|
151
|
-
canvas.translate(dx, dy) do
|
152
|
-
canvas.fill_color("green").stroke_color("darkgreen").
|
153
|
-
opacity(fill_alpha: 0.1, stroke_alpha: 0.2).
|
154
|
-
draw(:geom2d, object: mask, path_only: true).fill_stroke
|
155
|
-
end
|
156
|
-
end
|
157
|
-
page = "Page #{canvas.context.index + 1}" rescue "XObject"
|
158
|
-
doc.optional_content.default_configuration.add_ocg_to_ui(ocg, path: ['Debug', page])
|
159
|
-
end
|
160
|
-
box.draw(canvas, x + dx, y + dy)
|
161
|
-
end
|
162
|
-
|
163
|
-
end
|
164
|
-
|
165
87
|
# The x-coordinate of the bottom-left corner.
|
166
88
|
attr_reader :left
|
167
89
|
|
@@ -205,7 +127,7 @@ module HexaPDF
|
|
205
127
|
|
206
128
|
# An array of box objects representing the parent boxes.
|
207
129
|
#
|
208
|
-
# The immediate parent is the last array entry, the top
|
130
|
+
# The immediate parent is the last array entry, the top-most parent the first one. All boxes
|
209
131
|
# that are fitted into this frame have to be child boxes of the immediate parent box.
|
210
132
|
attr_reader :parent_boxes
|
211
133
|
|
@@ -253,16 +175,15 @@ module HexaPDF
|
|
253
175
|
@context&.document
|
254
176
|
end
|
255
177
|
|
256
|
-
# Fits the given box into the current region of available space and returns
|
257
|
-
# object.
|
178
|
+
# Fits the given box into the current region of available space and returns the associated
|
179
|
+
# Box::FitResult object.
|
258
180
|
#
|
259
181
|
# Fitting a box takes the style properties 'position', 'align', 'valign', 'margin', and
|
260
182
|
# 'mask_mode' into account.
|
261
183
|
#
|
262
|
-
# Use the FitResult#success? method to determine whether fitting was successful.
|
184
|
+
# Use the Box::FitResult#success? method to determine whether fitting was successful.
|
263
185
|
def fit(box)
|
264
|
-
|
265
|
-
return fit_result if full?
|
186
|
+
return Box::FitResult.new(box, frame: self) if full?
|
266
187
|
|
267
188
|
margin = box.style.margin if box.style.margin?
|
268
189
|
|
@@ -277,7 +198,7 @@ module HexaPDF
|
|
277
198
|
|
278
199
|
aw = width - x
|
279
200
|
ah = height - y
|
280
|
-
box.fit(aw, ah, self)
|
201
|
+
fit_result = box.fit(aw, ah, self)
|
281
202
|
fit_result.success!
|
282
203
|
|
283
204
|
x += left
|
@@ -294,7 +215,8 @@ module HexaPDF
|
|
294
215
|
ah -= margin_top = margin.top unless float_equal(@y, @bottom + @height)
|
295
216
|
end
|
296
217
|
|
297
|
-
fit_result
|
218
|
+
fit_result = box.fit(aw, ah, self)
|
219
|
+
return fit_result if fit_result.failure?
|
298
220
|
|
299
221
|
width = box.width
|
300
222
|
height = box.height
|
@@ -372,27 +294,24 @@ module HexaPDF
|
|
372
294
|
create_rectangle(@x, @y - available_height, @x + available_width, @y)
|
373
295
|
end
|
374
296
|
|
375
|
-
fit_result.available_width = aw
|
376
|
-
fit_result.available_height = ah
|
377
297
|
fit_result.x = x
|
378
298
|
fit_result.y = y
|
379
299
|
fit_result.mask = rectangle
|
380
300
|
fit_result
|
381
301
|
end
|
382
302
|
|
383
|
-
# Tries to split the box of the given FitResult into two parts and returns both parts.
|
303
|
+
# Tries to split the box of the given Box::FitResult into two parts and returns both parts.
|
384
304
|
#
|
385
305
|
# See Box#split for further details.
|
386
306
|
def split(fit_result)
|
387
|
-
fit_result.box.split
|
307
|
+
fit_result.box.split
|
388
308
|
end
|
389
309
|
|
390
|
-
# Draws the box of the given FitResult onto the canvas at the fitted position.
|
310
|
+
# Draws the box of the given Box::FitResult onto the canvas at the fitted position.
|
391
311
|
#
|
392
312
|
# After a box is successfully drawn, the frame's shape is adjusted to remove the occupied
|
393
313
|
# area.
|
394
314
|
def draw(canvas, fit_result)
|
395
|
-
return if fit_result.box.height == 0 || fit_result.box.width == 0
|
396
315
|
fit_result.draw(canvas)
|
397
316
|
remove_area(fit_result.mask)
|
398
317
|
end
|
@@ -464,7 +383,7 @@ module HexaPDF
|
|
464
383
|
# Since not all text may start at the top of the frame, the offset argument can be used to
|
465
384
|
# specify a vertical offset from the top of the frame where layouting should start.
|
466
385
|
#
|
467
|
-
# To be compatible with TextLayouter, the top
|
386
|
+
# To be compatible with TextLayouter, the top-left corner of the bounding box of the frame's
|
468
387
|
# shape is the origin of the coordinate system for the width specification, with positive
|
469
388
|
# x-values to the right and positive y-values downwards.
|
470
389
|
#
|
@@ -79,9 +79,11 @@ module HexaPDF
|
|
79
79
|
false
|
80
80
|
end
|
81
81
|
|
82
|
+
private
|
83
|
+
|
82
84
|
# Fits the image into the current region of the frame, taking the initially set width and
|
83
85
|
# height into account (see the class description for details).
|
84
|
-
def
|
86
|
+
def fit_content(available_width, available_height, _frame)
|
85
87
|
image_width = @image.width.to_f
|
86
88
|
image_height = @image.height.to_f
|
87
89
|
image_ratio = image_width / image_height
|
@@ -103,12 +105,10 @@ module HexaPDF
|
|
103
105
|
@height = image_height * ratio + rh
|
104
106
|
end
|
105
107
|
|
106
|
-
|
108
|
+
fit_result.success! if float_compare(@width, available_width) <= 0 &&
|
107
109
|
float_compare(@height, available_height) <= 0
|
108
110
|
end
|
109
111
|
|
110
|
-
private
|
111
|
-
|
112
112
|
# Draws the image onto the canvas at position [x, y].
|
113
113
|
def draw_content(canvas, x, y)
|
114
114
|
canvas.image(@image, at: [x, y], width: content_width, height: content_height)
|
@@ -186,20 +186,12 @@ module HexaPDF
|
|
186
186
|
super && (!@results || @results.all? {|result| result.box_fitter.fit_results.empty? })
|
187
187
|
end
|
188
188
|
|
189
|
-
|
190
|
-
def fit(available_width, available_height, frame)
|
191
|
-
@width = if @initial_width > 0
|
192
|
-
@initial_width
|
193
|
-
else
|
194
|
-
(style.position == :flow ? frame.width : available_width)
|
195
|
-
end
|
196
|
-
height = if @initial_height > 0
|
197
|
-
@initial_height - reserved_height
|
198
|
-
else
|
199
|
-
(style.position == :flow ? frame.y - frame.bottom : available_height) - reserved_height
|
200
|
-
end
|
189
|
+
private
|
201
190
|
|
191
|
+
# Fits the list box into the current region of the frame.
|
192
|
+
def fit_content(_available_width, _available_height, frame)
|
202
193
|
width = @width - reserved_width
|
194
|
+
height = @height - reserved_height
|
203
195
|
left = (style.position == :flow ? frame.left : frame.x) + reserved_width_left
|
204
196
|
top = frame.y - reserved_height_top
|
205
197
|
|
@@ -243,7 +235,7 @@ module HexaPDF
|
|
243
235
|
Array(child).each {|ibox| box_fitter.fit(ibox) }
|
244
236
|
item_result.box_fitter = box_fitter
|
245
237
|
item_result.height = [item_result.height.to_i, box_fitter.content_heights[0]].max
|
246
|
-
@results << item_result
|
238
|
+
@results << item_result unless box_fitter.fit_results.empty?
|
247
239
|
|
248
240
|
top -= item_result.height + item_spacing
|
249
241
|
height -= item_result.height + item_spacing
|
@@ -253,15 +245,13 @@ module HexaPDF
|
|
253
245
|
|
254
246
|
@height = @results.sum(&:height) + (@results.count - 1) * item_spacing + reserved_height
|
255
247
|
|
256
|
-
@
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
248
|
+
if @results.size == @children.size && @results.all? {|r| r.box_fitter.success? }
|
249
|
+
fit_result.success!
|
250
|
+
elsif !@results.empty? && !@results[0].box_fitter.fit_results.empty?
|
251
|
+
fit_result.overflow!
|
252
|
+
end
|
261
253
|
end
|
262
254
|
|
263
|
-
private
|
264
|
-
|
265
255
|
# Removes the +content_indentation+ from the left side of the given shape (a Geom2D::PolygonSet).
|
266
256
|
def remove_indent_from_frame_shape(shape)
|
267
257
|
polygon_index = 0
|
@@ -307,7 +297,7 @@ module HexaPDF
|
|
307
297
|
end
|
308
298
|
|
309
299
|
# Splits the content of the list box. This method is called from Box#split.
|
310
|
-
def split_content
|
300
|
+
def split_content
|
311
301
|
remaining_boxes = @results[-1].box_fitter.remaining_boxes
|
312
302
|
first_is_split_box = !remaining_boxes.empty?
|
313
303
|
children = (remaining_boxes.empty? ? [] : [remaining_boxes]) + @children[@results.size..-1]
|
@@ -361,17 +351,9 @@ module HexaPDF
|
|
361
351
|
|
362
352
|
# Draws the list items onto the canvas at position [x, y].
|
363
353
|
def draw_content(canvas, x, y)
|
364
|
-
|
365
|
-
raise HexaPDF::Error, "Some items don't fit into box with limited height and " \
|
366
|
-
"style property overflow is set to :error"
|
367
|
-
end
|
354
|
+
translate = style.position != :flow && (x != @fit_x || y != @fit_y)
|
368
355
|
|
369
|
-
translate
|
370
|
-
|
371
|
-
if translate
|
372
|
-
canvas.save_graphics_state
|
373
|
-
canvas.translate(x - @draw_pos_x, y - @draw_pos_y)
|
374
|
-
end
|
356
|
+
canvas.save_graphics_state.translate(x - @fit_x, y - @fit_y) if translate
|
375
357
|
|
376
358
|
@results.each do |item_result|
|
377
359
|
box_fitter = item_result.box_fitter
|
data/lib/hexapdf/layout/style.rb
CHANGED
@@ -393,7 +393,7 @@ module HexaPDF
|
|
393
393
|
# The object resolved in this way needs to respond to #call(canvas, box) where +canvas+ is the
|
394
394
|
# HexaPDF::Content::Canvas object on which it should be drawn and +box+ is a box-like object
|
395
395
|
# (e.g. Box or TextFragment). The coordinate system is translated so that the origin is at the
|
396
|
-
# bottom
|
396
|
+
# bottom-left corner of the box during the drawing operations.
|
397
397
|
class Layers
|
398
398
|
|
399
399
|
# Creates a new Layers object popuplated with the given +layers+.
|
@@ -1254,7 +1254,11 @@ module HexaPDF
|
|
1254
1254
|
# doesn't. If a box doesn't support this value, it is positioned as if the value :default
|
1255
1255
|
# was set.
|
1256
1256
|
#
|
1257
|
-
#
|
1257
|
+
# Notes:
|
1258
|
+
#
|
1259
|
+
# * The properties #align and #valign are not used with this value.
|
1260
|
+
# * The rectangular area of the box is the rectangle containing all the flowed content.
|
1261
|
+
# That rectangle is used for drawing the border, background and so on.
|
1258
1262
|
#
|
1259
1263
|
# Examples:
|
1260
1264
|
#
|
@@ -1264,8 +1268,8 @@ module HexaPDF
|
|
1264
1268
|
# composer.lorem_ipsum(position: :flow)
|
1265
1269
|
#
|
1266
1270
|
# [x, y]::
|
1267
|
-
# Position the box with the bottom
|
1268
|
-
# the bottom
|
1271
|
+
# Position the box with the bottom-left corner at the given absolute position relative to
|
1272
|
+
# the bottom-left corner of the frame.
|
1269
1273
|
#
|
1270
1274
|
# Examples:
|
1271
1275
|
#
|
@@ -211,56 +211,55 @@ module HexaPDF
|
|
211
211
|
@height = height
|
212
212
|
end
|
213
213
|
|
214
|
+
# :nodoc:
|
215
|
+
def inspect
|
216
|
+
"<Cell (#{row},#{column}) #{row_span}x#{col_span} #{Array(children).map(&:class)}>"
|
217
|
+
end
|
218
|
+
|
219
|
+
private
|
220
|
+
|
214
221
|
# Fits the children of the table cell into the given rectangular area.
|
215
|
-
def
|
216
|
-
@width = available_width
|
222
|
+
def fit_content(available_width, available_height, frame)
|
217
223
|
width = available_width - reserved_width
|
218
|
-
height = available_height - reserved_height
|
219
|
-
return
|
224
|
+
height = @used_height = available_height - reserved_height
|
225
|
+
return if width <= 0 || height <= 0
|
220
226
|
|
221
227
|
frame = frame.child_frame(0, 0, width, height, box: self)
|
222
228
|
case children
|
223
229
|
when Box
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
230
|
+
child_result = frame.fit(children)
|
231
|
+
if child_result.success?
|
232
|
+
@preferred_width = child_result.x + child_result.box.width + reserved_width
|
233
|
+
@height = @preferred_height = child_result.box.height + reserved_height
|
234
|
+
@fit_results = [child_result]
|
235
|
+
fit_result.success!
|
236
|
+
end
|
229
237
|
when Array
|
230
238
|
box_fitter = BoxFitter.new([frame])
|
231
239
|
children.each {|box| box_fitter.fit(box) }
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
240
|
+
if box_fitter.success?
|
241
|
+
max_x_result = box_fitter.fit_results.max_by {|result| result.x + result.box.width }
|
242
|
+
@preferred_width = max_x_result.x + max_x_result.box.width + reserved_width
|
243
|
+
@height = @preferred_height = box_fitter.content_heights[0] + reserved_height
|
244
|
+
@fit_results = box_fitter.fit_results
|
245
|
+
fit_result.success!
|
246
|
+
end
|
237
247
|
else
|
238
248
|
@preferred_width = reserved_width
|
239
249
|
@height = @preferred_height = reserved_height
|
240
250
|
@fit_results = []
|
241
|
-
|
251
|
+
fit_result.success!
|
242
252
|
end
|
243
253
|
end
|
244
254
|
|
245
|
-
# :nodoc:
|
246
|
-
def inspect
|
247
|
-
"<Cell (#{row},#{column}) #{row_span}x#{col_span} #{Array(children).map(&:class)}>"
|
248
|
-
end
|
249
|
-
|
250
|
-
private
|
251
|
-
|
252
255
|
# Draws the content of the cell.
|
253
256
|
def draw_content(canvas, x, y)
|
254
257
|
return if @fit_results.empty?
|
255
258
|
|
256
259
|
# available_width is always equal to content_width but we need to adjust for the
|
257
260
|
# difference in the y direction between fitting and drawing
|
258
|
-
y -= (@
|
259
|
-
@fit_results.each
|
260
|
-
#fit_result.x += x
|
261
|
-
#fit_result.y += y
|
262
|
-
fit_result.draw(canvas, dx: x, dy: y)
|
263
|
-
end
|
261
|
+
y -= (@used_height - content_height)
|
262
|
+
@fit_results.each {|fit_result| fit_result.draw(canvas, dx: x, dy: y) }
|
264
263
|
end
|
265
264
|
|
266
265
|
end
|
@@ -393,7 +392,7 @@ module HexaPDF
|
|
393
392
|
else
|
394
393
|
column_info[cell.column].last
|
395
394
|
end
|
396
|
-
unless cell.fit(available_cell_width, available_height, frame)
|
395
|
+
unless cell.fit(available_cell_width, available_height, frame).success?
|
397
396
|
row_fit = false
|
398
397
|
break
|
399
398
|
end
|
@@ -589,24 +588,23 @@ module HexaPDF
|
|
589
588
|
super && (!@last_fitted_row_index || @last_fitted_row_index < 0)
|
590
589
|
end
|
591
590
|
|
592
|
-
|
593
|
-
def fit(available_width, available_height, frame)
|
594
|
-
return false if (@initial_width > 0 && @initial_width > available_width) ||
|
595
|
-
(@initial_height > 0 && @initial_height > available_height)
|
591
|
+
private
|
596
592
|
|
593
|
+
# Fits the table into the current region of the frame.
|
594
|
+
def fit_content(_available_width, _available_height, frame)
|
597
595
|
# Adjust reserved width/height to include space used by the edge cells for their border
|
598
596
|
# since cell borders are drawn on the bounds and not inside.
|
599
597
|
# This uses the top-left and bottom-right cells and so might not be correct in all cases.
|
600
598
|
@cell_tl_border_width = @cells[0, 0].style.border.width
|
601
599
|
cell_br_border_width = @cells[-1, -1].style.border.width
|
602
|
-
rw =
|
603
|
-
rh =
|
600
|
+
rw = (@cell_tl_border_width.left + cell_br_border_width.right) / 2.0
|
601
|
+
rh = (@cell_tl_border_width.top + cell_br_border_width.bottom) / 2.0
|
604
602
|
|
605
|
-
width =
|
606
|
-
height =
|
603
|
+
width = @width - reserved_width - rw
|
604
|
+
height = @height - reserved_height - rh
|
607
605
|
used_height = 0
|
608
606
|
columns = calculate_column_widths(width)
|
609
|
-
return
|
607
|
+
return if columns.empty?
|
610
608
|
|
611
609
|
frame = frame.child_frame(box: self)
|
612
610
|
@special_cells_fit_not_successful = false
|
@@ -616,18 +614,21 @@ module HexaPDF
|
|
616
614
|
height -= special_used_height
|
617
615
|
used_height += special_used_height
|
618
616
|
@special_cells_fit_not_successful = (last_fitted_row_index != special_cells.number_of_rows - 1)
|
619
|
-
return
|
617
|
+
return nil if @special_cells_fit_not_successful
|
620
618
|
end
|
621
619
|
|
622
620
|
main_used_height, @last_fitted_row_index = @cells.fit_rows(@start_row_index, height, columns, frame)
|
623
621
|
used_height += main_used_height
|
624
622
|
|
625
|
-
|
626
|
-
|
627
|
-
@fit_successful = (@last_fitted_row_index == @cells.number_of_rows - 1)
|
628
|
-
end
|
623
|
+
update_content_width { columns[-1].sum + rw }
|
624
|
+
update_content_height { used_height + rh }
|
629
625
|
|
630
|
-
|
626
|
+
if @last_fitted_row_index == @cells.number_of_rows - 1
|
627
|
+
fit_result.success!
|
628
|
+
elsif @last_fitted_row_index >= 0
|
629
|
+
fit_result.overflow!
|
630
|
+
end
|
631
|
+
end
|
631
632
|
|
632
633
|
# Calculates and returns the x-coordinates and widths of all columns based on the given total
|
633
634
|
# available width.
|
@@ -649,20 +650,16 @@ module HexaPDF
|
|
649
650
|
end
|
650
651
|
|
651
652
|
# Splits the content of the table box. This method is called from Box#split.
|
652
|
-
def split_content
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
footer_cells = @footer ? Cells.new(@footer.call(self), cell_style: @cell_style) : nil
|
663
|
-
box.instance_variable_set(:@footer_cells, footer_cells)
|
664
|
-
[self, box]
|
665
|
-
end
|
653
|
+
def split_content
|
654
|
+
box = create_split_box
|
655
|
+
box.instance_variable_set(:@start_row_index, @last_fitted_row_index + 1)
|
656
|
+
box.instance_variable_set(:@last_fitted_row_index, -1)
|
657
|
+
box.instance_variable_set(:@special_cells_fit_not_successful, nil)
|
658
|
+
header_cells = @header ? Cells.new(@header.call(self), cell_style: @cell_style) : nil
|
659
|
+
box.instance_variable_set(:@header_cells, header_cells)
|
660
|
+
footer_cells = @footer ? Cells.new(@footer.call(self), cell_style: @cell_style) : nil
|
661
|
+
box.instance_variable_set(:@footer_cells, footer_cells)
|
662
|
+
[self, box]
|
666
663
|
end
|
667
664
|
|
668
665
|
# Draws the child boxes onto the canvas at position [x, y].
|