hexapdf 0.42.0 → 0.44.0
Sign up to get free protection for your applications and to get access to all the features.
- 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].
|