hexapdf 0.38.0 → 0.39.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 +18 -0
- data/examples/030-pdfa.rb +1 -1
- data/lib/hexapdf/layout/column_box.rb +2 -2
- data/lib/hexapdf/layout/container_box.rb +3 -2
- data/lib/hexapdf/layout/frame.rb +40 -6
- data/lib/hexapdf/layout/inline_box.rb +11 -4
- data/lib/hexapdf/layout/list_box.rb +3 -3
- data/lib/hexapdf/layout/style.rb +20 -0
- data/lib/hexapdf/layout/table_box.rb +2 -1
- data/lib/hexapdf/layout/text_box.rb +11 -2
- data/lib/hexapdf/layout/text_layouter.rb +12 -3
- data/lib/hexapdf/version.rb +1 -1
- data/test/hexapdf/layout/test_frame.rb +31 -2
- data/test/hexapdf/layout/test_inline_box.rb +8 -1
- data/test/hexapdf/layout/test_style.rb +1 -0
- data/test/hexapdf/layout/test_text_box.rb +22 -5
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d0a43d232528df9bfc4a2c9baddd9cd1ddbd33fe7cce9d146b4e25760f25429b
|
|
4
|
+
data.tar.gz: 37cb10752d22bbc89fd18a779152ef7b5e02e6237318006a4b0e0a420d2890e2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
@@ -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 =
|
|
183
|
-
|
|
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 =
|
|
135
|
-
|
|
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
|
|
data/lib/hexapdf/layout/frame.rb
CHANGED
|
@@ -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 =
|
|
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
|
-
|
|
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
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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 =
|
|
231
|
-
|
|
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 =
|
|
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
|
data/lib/hexapdf/layout/style.rb
CHANGED
|
@@ -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 =
|
|
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
|
|
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
|
|
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)
|
data/lib/hexapdf/version.rb
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
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,
|
|
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.
|
|
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-
|
|
11
|
+
date: 2024-03-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: cmdparse
|