hexapdf 0.42.0 → 0.44.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 +46 -0
- data/Rakefile +1 -1
- data/examples/030-pdfa.rb +1 -0
- data/lib/hexapdf/composer.rb +1 -0
- data/lib/hexapdf/dictionary.rb +3 -3
- data/lib/hexapdf/document/files.rb +7 -2
- data/lib/hexapdf/document/metadata.rb +12 -1
- data/lib/hexapdf/document.rb +14 -1
- data/lib/hexapdf/encryption.rb +17 -0
- data/lib/hexapdf/layout/box.rb +161 -61
- data/lib/hexapdf/layout/box_fitter.rb +4 -3
- data/lib/hexapdf/layout/column_box.rb +23 -25
- data/lib/hexapdf/layout/container_box.rb +3 -3
- data/lib/hexapdf/layout/frame.rb +13 -95
- data/lib/hexapdf/layout/image_box.rb +4 -4
- data/lib/hexapdf/layout/line.rb +4 -0
- data/lib/hexapdf/layout/list_box.rb +12 -20
- data/lib/hexapdf/layout/style.rb +5 -1
- data/lib/hexapdf/layout/table_box.rb +48 -55
- data/lib/hexapdf/layout/text_box.rb +38 -39
- data/lib/hexapdf/parser.rb +23 -17
- data/lib/hexapdf/type/acro_form/form.rb +78 -27
- data/lib/hexapdf/type/file_specification.rb +9 -5
- data/lib/hexapdf/type/graphics_state_parameter.rb +1 -1
- data/lib/hexapdf/version.rb +1 -1
- data/test/hexapdf/document/test_files.rb +5 -0
- data/test/hexapdf/document/test_metadata.rb +21 -0
- data/test/hexapdf/layout/test_box.rb +82 -37
- data/test/hexapdf/layout/test_box_fitter.rb +10 -3
- 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 +0 -48
- data/test/hexapdf/layout/test_image_box.rb +14 -6
- data/test/hexapdf/layout/test_list_box.rb +25 -26
- data/test/hexapdf/layout/test_table_box.rb +39 -53
- data/test/hexapdf/layout/test_text_box.rb +65 -67
- data/test/hexapdf/test_composer.rb +6 -0
- data/test/hexapdf/test_dictionary.rb +6 -4
- data/test/hexapdf/test_parser.rb +20 -0
- data/test/hexapdf/type/acro_form/test_form.rb +63 -2
- data/test/hexapdf/type/test_file_specification.rb +2 -1
- metadata +2 -2
@@ -138,31 +138,29 @@ module HexaPDF
|
|
138
138
|
super && (!@box_fitter || @box_fitter.fit_results.empty?)
|
139
139
|
end
|
140
140
|
|
141
|
+
private
|
142
|
+
|
141
143
|
# Fits the column box into the current region of the frame.
|
142
144
|
#
|
143
|
-
|
144
|
-
# arbitrary (sets of) polygons since the +frame+s shape is taken into account.
|
145
|
-
def fit(available_width, available_height, frame)
|
146
|
-
return false if @initial_height > available_height || @initial_width > available_width
|
147
|
-
|
145
|
+
def fit_content(available_width, available_height, frame)
|
148
146
|
initial_fit_successful = (@equal_height && @columns.size > 1 ? nil : false)
|
149
147
|
tries = 0
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
148
|
+
width = if style.position == :flow
|
149
|
+
(@initial_width > 0 ? @initial_width : frame.width) - reserved_width
|
150
|
+
else
|
151
|
+
(@initial_width > 0 ? @initial_width : available_width) - reserved_width
|
152
|
+
end
|
155
153
|
height = if style.position == :flow
|
156
|
-
(@initial_height > 0 ? @initial_height : frame.
|
154
|
+
(@initial_height > 0 ? @initial_height : frame.y - frame.bottom) - reserved_height
|
157
155
|
else
|
158
156
|
(@initial_height > 0 ? @initial_height : available_height) - reserved_height
|
159
157
|
end
|
160
158
|
|
161
|
-
columns = calculate_columns(
|
162
|
-
return
|
159
|
+
columns = calculate_columns(width)
|
160
|
+
return if columns.empty?
|
163
161
|
|
164
162
|
left = (style.position == :flow ? frame.left : frame.x) + reserved_width_left
|
165
|
-
top =
|
163
|
+
top = frame.y - reserved_height_top
|
166
164
|
successful_height = height
|
167
165
|
unsuccessful_height = 0
|
168
166
|
|
@@ -186,7 +184,7 @@ module HexaPDF
|
|
186
184
|
|
187
185
|
children.each {|box| @box_fitter.fit(box) }
|
188
186
|
|
189
|
-
fit_successful = @box_fitter.
|
187
|
+
fit_successful = @box_fitter.success?
|
190
188
|
initial_fit_successful = fit_successful if initial_fit_successful.nil?
|
191
189
|
|
192
190
|
if fit_successful
|
@@ -206,16 +204,16 @@ module HexaPDF
|
|
206
204
|
tries += 1
|
207
205
|
end
|
208
206
|
|
209
|
-
|
210
|
-
|
211
|
-
@draw_pos_x = frame.x + reserved_width_left
|
212
|
-
@draw_pos_y = frame.y - @height + reserved_height_bottom
|
207
|
+
update_content_width { columns[-1].sum }
|
208
|
+
update_content_height { @box_fitter.content_heights.max }
|
213
209
|
|
214
|
-
@box_fitter.
|
210
|
+
if @box_fitter.success?
|
211
|
+
fit_result.success!
|
212
|
+
elsif !@box_fitter.fit_results.empty?
|
213
|
+
fit_result.overflow!
|
214
|
+
end
|
215
215
|
end
|
216
216
|
|
217
|
-
private
|
218
|
-
|
219
217
|
# Calculates the x-coordinates and widths of all columns based on the given total available
|
220
218
|
# width.
|
221
219
|
#
|
@@ -241,7 +239,7 @@ module HexaPDF
|
|
241
239
|
end
|
242
240
|
|
243
241
|
# Splits the content of the column box. This method is called from Box#split.
|
244
|
-
def split_content
|
242
|
+
def split_content
|
245
243
|
box = create_split_box
|
246
244
|
box.instance_variable_set(:@children, @box_fitter.remaining_boxes)
|
247
245
|
[self, box]
|
@@ -249,8 +247,8 @@ module HexaPDF
|
|
249
247
|
|
250
248
|
# Draws the child boxes onto the canvas at position [x, y].
|
251
249
|
def draw_content(canvas, x, y)
|
252
|
-
if style.position != :flow && (x != @
|
253
|
-
canvas.translate(x - @
|
250
|
+
if style.position != :flow && (x != @fit_x || y != @fit_y)
|
251
|
+
canvas.translate(x - @fit_x, y - @fit_y) do
|
254
252
|
@box_fitter.fit_results.each {|result| result.draw(canvas) }
|
255
253
|
end
|
256
254
|
else
|
@@ -137,17 +137,17 @@ module HexaPDF
|
|
137
137
|
@box_fitter = BoxFitter.new([my_frame])
|
138
138
|
children.each {|box| @box_fitter.fit(box) }
|
139
139
|
|
140
|
-
if @box_fitter.
|
140
|
+
if @box_fitter.success?
|
141
141
|
update_content_width do
|
142
142
|
result = @box_fitter.fit_results.max_by {|r| r.mask.x + r.mask.width }
|
143
143
|
children.empty? ? 0 : result.mask.x + result.mask.width - my_frame.left
|
144
144
|
end
|
145
145
|
update_content_height { @box_fitter.content_heights.max }
|
146
|
-
|
146
|
+
fit_result.success!
|
147
147
|
end
|
148
148
|
end
|
149
149
|
|
150
|
-
# Draws the
|
150
|
+
# Draws the children onto the canvas at position [x, y].
|
151
151
|
def draw_content(canvas, x, y)
|
152
152
|
dx = x - @fit_x
|
153
153
|
dy = y - @fit_y
|
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
|
#
|
@@ -54,7 +54,7 @@ module HexaPDF
|
|
54
54
|
#
|
55
55
|
# The method #fit is also called for absolutely positioned boxes but since these boxes are not
|
56
56
|
# subject to the normal constraints, the provided available width and height are the width and
|
57
|
-
# height inside the frame to the right and top of the bottom
|
57
|
+
# height inside the frame to the right and top of the bottom left corner of the box.
|
58
58
|
#
|
59
59
|
# * If the box didn't fit, call #find_next_region to determine the next region for placing the
|
60
60
|
# box. If a new region was found, start over with #fit. Otherwise the frame has no more space
|
@@ -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,84 +84,10 @@ module HexaPDF
|
|
88
84
|
|
89
85
|
include HexaPDF::Utils
|
90
86
|
|
91
|
-
#
|
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
|
-
# The x-coordinate of the bottom-left corner.
|
87
|
+
# The x-coordinate of the bottom left corner.
|
166
88
|
attr_reader :left
|
167
89
|
|
168
|
-
# The y-coordinate of the bottom
|
90
|
+
# The y-coordinate of the bottom left corner.
|
169
91
|
attr_reader :bottom
|
170
92
|
|
171
93
|
# The width of the frame.
|
@@ -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,7 @@ 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)
|
298
219
|
|
299
220
|
width = box.width
|
300
221
|
height = box.height
|
@@ -372,27 +293,24 @@ module HexaPDF
|
|
372
293
|
create_rectangle(@x, @y - available_height, @x + available_width, @y)
|
373
294
|
end
|
374
295
|
|
375
|
-
fit_result.available_width = aw
|
376
|
-
fit_result.available_height = ah
|
377
296
|
fit_result.x = x
|
378
297
|
fit_result.y = y
|
379
298
|
fit_result.mask = rectangle
|
380
299
|
fit_result
|
381
300
|
end
|
382
301
|
|
383
|
-
# Tries to split the box of the given FitResult into two parts and returns both parts.
|
302
|
+
# Tries to split the box of the given Box::FitResult into two parts and returns both parts.
|
384
303
|
#
|
385
304
|
# See Box#split for further details.
|
386
305
|
def split(fit_result)
|
387
|
-
fit_result.box.split
|
306
|
+
fit_result.box.split
|
388
307
|
end
|
389
308
|
|
390
|
-
# Draws the box of the given FitResult onto the canvas at the fitted position.
|
309
|
+
# Draws the box of the given Box::FitResult onto the canvas at the fitted position.
|
391
310
|
#
|
392
311
|
# After a box is successfully drawn, the frame's shape is adjusted to remove the occupied
|
393
312
|
# area.
|
394
313
|
def draw(canvas, fit_result)
|
395
|
-
return if fit_result.box.height == 0 || fit_result.box.width == 0
|
396
314
|
fit_result.draw(canvas)
|
397
315
|
remove_area(fit_result.mask)
|
398
316
|
end
|
@@ -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)
|
data/lib/hexapdf/layout/line.rb
CHANGED
@@ -173,6 +173,10 @@ module HexaPDF
|
|
173
173
|
attr_accessor :items
|
174
174
|
|
175
175
|
# An optional horizontal offset that should be taken into account when positioning the line.
|
176
|
+
#
|
177
|
+
# This offset always describes the offset from the left side (and not, for example, the offset
|
178
|
+
# from the right side of another line even if those two lines are actually on the same
|
179
|
+
# horizontal level).
|
176
180
|
attr_accessor :x_offset
|
177
181
|
|
178
182
|
# An optional vertical offset that should be taken into account when positioning the line.
|
@@ -186,8 +186,10 @@ module HexaPDF
|
|
186
186
|
super && (!@results || @results.all? {|result| result.box_fitter.fit_results.empty? })
|
187
187
|
end
|
188
188
|
|
189
|
+
private
|
190
|
+
|
189
191
|
# Fits the list box into the current region of the frame.
|
190
|
-
def
|
192
|
+
def fit_content(available_width, available_height, frame)
|
191
193
|
@width = if @initial_width > 0
|
192
194
|
@initial_width
|
193
195
|
else
|
@@ -248,20 +250,18 @@ module HexaPDF
|
|
248
250
|
top -= item_result.height + item_spacing
|
249
251
|
height -= item_result.height + item_spacing
|
250
252
|
|
251
|
-
break if !box_fitter.
|
253
|
+
break if !box_fitter.success? || height <= 0
|
252
254
|
end
|
253
255
|
|
254
256
|
@height = @results.sum(&:height) + (@results.count - 1) * item_spacing + reserved_height
|
255
257
|
|
256
|
-
@
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
258
|
+
if @results.size == @children.size && @results.all? {|r| r.box_fitter.success? }
|
259
|
+
fit_result.success!
|
260
|
+
elsif !@results.empty? && !@results[0].box_fitter.fit_results.empty?
|
261
|
+
fit_result.overflow!
|
262
|
+
end
|
261
263
|
end
|
262
264
|
|
263
|
-
private
|
264
|
-
|
265
265
|
# Removes the +content_indentation+ from the left side of the given shape (a Geom2D::PolygonSet).
|
266
266
|
def remove_indent_from_frame_shape(shape)
|
267
267
|
polygon_index = 0
|
@@ -307,7 +307,7 @@ module HexaPDF
|
|
307
307
|
end
|
308
308
|
|
309
309
|
# Splits the content of the list box. This method is called from Box#split.
|
310
|
-
def split_content
|
310
|
+
def split_content
|
311
311
|
remaining_boxes = @results[-1].box_fitter.remaining_boxes
|
312
312
|
first_is_split_box = !remaining_boxes.empty?
|
313
313
|
children = (remaining_boxes.empty? ? [] : [remaining_boxes]) + @children[@results.size..-1]
|
@@ -361,17 +361,9 @@ module HexaPDF
|
|
361
361
|
|
362
362
|
# Draws the list items onto the canvas at position [x, y].
|
363
363
|
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
|
364
|
+
translate = style.position != :flow && (x != @fit_x || y != @fit_y)
|
368
365
|
|
369
|
-
translate
|
370
|
-
|
371
|
-
if translate
|
372
|
-
canvas.save_graphics_state
|
373
|
-
canvas.translate(x - @draw_pos_x, y - @draw_pos_y)
|
374
|
-
end
|
366
|
+
canvas.save_graphics_state.translate(x - @fit_x, y - @fit_y) if translate
|
375
367
|
|
376
368
|
@results.each do |item_result|
|
377
369
|
box_fitter = item_result.box_fitter
|
data/lib/hexapdf/layout/style.rb
CHANGED
@@ -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
|
#
|
@@ -211,21 +211,27 @@ 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
|
-
@preferred_width =
|
226
|
-
@height = @preferred_height =
|
227
|
-
@fit_results = [
|
228
|
-
|
230
|
+
child_result = frame.fit(children)
|
231
|
+
@preferred_width = child_result.x + child_result.box.width + reserved_width
|
232
|
+
@height = @preferred_height = child_result.box.height + reserved_height
|
233
|
+
@fit_results = [child_result]
|
234
|
+
fit_result.success! if child_result.success?
|
229
235
|
when Array
|
230
236
|
box_fitter = BoxFitter.new([frame])
|
231
237
|
children.each {|box| box_fitter.fit(box) }
|
@@ -233,34 +239,23 @@ module HexaPDF
|
|
233
239
|
@preferred_width = max_x_result.x + max_x_result.box.width + reserved_width
|
234
240
|
@height = @preferred_height = box_fitter.content_heights[0] + reserved_height
|
235
241
|
@fit_results = box_fitter.fit_results
|
236
|
-
|
242
|
+
fit_result.success! if box_fitter.success?
|
237
243
|
else
|
238
244
|
@preferred_width = reserved_width
|
239
245
|
@height = @preferred_height = reserved_height
|
240
246
|
@fit_results = []
|
241
|
-
|
247
|
+
fit_result.success!
|
242
248
|
end
|
243
249
|
end
|
244
250
|
|
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
251
|
# Draws the content of the cell.
|
253
252
|
def draw_content(canvas, x, y)
|
254
253
|
return if @fit_results.empty?
|
255
254
|
|
256
255
|
# available_width is always equal to content_width but we need to adjust for the
|
257
256
|
# 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
|
257
|
+
y -= (@used_height - content_height)
|
258
|
+
@fit_results.each {|fit_result| fit_result.draw(canvas, dx: x, dy: y) }
|
264
259
|
end
|
265
260
|
|
266
261
|
end
|
@@ -393,7 +388,7 @@ module HexaPDF
|
|
393
388
|
else
|
394
389
|
column_info[cell.column].last
|
395
390
|
end
|
396
|
-
unless cell.fit(available_cell_width, available_height, frame)
|
391
|
+
unless cell.fit(available_cell_width, available_height, frame).success?
|
397
392
|
row_fit = false
|
398
393
|
break
|
399
394
|
end
|
@@ -589,24 +584,23 @@ module HexaPDF
|
|
589
584
|
super && (!@last_fitted_row_index || @last_fitted_row_index < 0)
|
590
585
|
end
|
591
586
|
|
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)
|
587
|
+
private
|
596
588
|
|
589
|
+
# Fits the table into the current region of the frame.
|
590
|
+
def fit_content(_available_width, _available_height, frame)
|
597
591
|
# Adjust reserved width/height to include space used by the edge cells for their border
|
598
592
|
# since cell borders are drawn on the bounds and not inside.
|
599
|
-
# This uses the top
|
593
|
+
# This uses the top left and bottom right cells and so might not be correct in all cases.
|
600
594
|
@cell_tl_border_width = @cells[0, 0].style.border.width
|
601
595
|
cell_br_border_width = @cells[-1, -1].style.border.width
|
602
|
-
rw =
|
603
|
-
rh =
|
596
|
+
rw = (@cell_tl_border_width.left + cell_br_border_width.right) / 2.0
|
597
|
+
rh = (@cell_tl_border_width.top + cell_br_border_width.bottom) / 2.0
|
604
598
|
|
605
|
-
width =
|
606
|
-
height =
|
599
|
+
width = @width - reserved_width - rw
|
600
|
+
height = @height - reserved_height - rh
|
607
601
|
used_height = 0
|
608
602
|
columns = calculate_column_widths(width)
|
609
|
-
return
|
603
|
+
return if columns.empty?
|
610
604
|
|
611
605
|
frame = frame.child_frame(box: self)
|
612
606
|
@special_cells_fit_not_successful = false
|
@@ -616,18 +610,21 @@ module HexaPDF
|
|
616
610
|
height -= special_used_height
|
617
611
|
used_height += special_used_height
|
618
612
|
@special_cells_fit_not_successful = (last_fitted_row_index != special_cells.number_of_rows - 1)
|
619
|
-
return
|
613
|
+
return nil if @special_cells_fit_not_successful
|
620
614
|
end
|
621
615
|
|
622
616
|
main_used_height, @last_fitted_row_index = @cells.fit_rows(@start_row_index, height, columns, frame)
|
623
617
|
used_height += main_used_height
|
624
618
|
|
625
|
-
|
626
|
-
|
627
|
-
@fit_successful = (@last_fitted_row_index == @cells.number_of_rows - 1)
|
628
|
-
end
|
619
|
+
update_content_width { columns[-1].sum + rw }
|
620
|
+
update_content_height { used_height + rh }
|
629
621
|
|
630
|
-
|
622
|
+
if @last_fitted_row_index == @cells.number_of_rows - 1
|
623
|
+
fit_result.success!
|
624
|
+
elsif @last_fitted_row_index >= 0
|
625
|
+
fit_result.overflow!
|
626
|
+
end
|
627
|
+
end
|
631
628
|
|
632
629
|
# Calculates and returns the x-coordinates and widths of all columns based on the given total
|
633
630
|
# available width.
|
@@ -649,20 +646,16 @@ module HexaPDF
|
|
649
646
|
end
|
650
647
|
|
651
648
|
# 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
|
649
|
+
def split_content
|
650
|
+
box = create_split_box
|
651
|
+
box.instance_variable_set(:@start_row_index, @last_fitted_row_index + 1)
|
652
|
+
box.instance_variable_set(:@last_fitted_row_index, -1)
|
653
|
+
box.instance_variable_set(:@special_cells_fit_not_successful, nil)
|
654
|
+
header_cells = @header ? Cells.new(@header.call(self), cell_style: @cell_style) : nil
|
655
|
+
box.instance_variable_set(:@header_cells, header_cells)
|
656
|
+
footer_cells = @footer ? Cells.new(@footer.call(self), cell_style: @cell_style) : nil
|
657
|
+
box.instance_variable_set(:@footer_cells, footer_cells)
|
658
|
+
[self, box]
|
666
659
|
end
|
667
660
|
|
668
661
|
# Draws the child boxes onto the canvas at position [x, y].
|