hexapdf 0.43.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 +17 -0
- data/examples/030-pdfa.rb +1 -0
- data/lib/hexapdf/composer.rb +1 -0
- data/lib/hexapdf/document/files.rb +7 -2
- data/lib/hexapdf/document/metadata.rb +12 -1
- data/lib/hexapdf/layout/box.rb +160 -61
- data/lib/hexapdf/layout/box_fitter.rb +1 -0
- data/lib/hexapdf/layout/column_box.rb +22 -24
- data/lib/hexapdf/layout/container_box.rb +2 -2
- data/lib/hexapdf/layout/frame.rb +13 -95
- data/lib/hexapdf/layout/image_box.rb +4 -4
- data/lib/hexapdf/layout/list_box.rb +11 -19
- data/lib/hexapdf/layout/style.rb +5 -1
- data/lib/hexapdf/layout/table_box.rb +48 -55
- data/lib/hexapdf/layout/text_box.rb +27 -42
- data/lib/hexapdf/parser.rb +5 -2
- 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 +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 +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 +38 -66
- data/test/hexapdf/test_composer.rb +6 -0
- data/test/hexapdf/test_parser.rb +8 -0
- data/test/hexapdf/type/test_file_specification.rb +2 -1
- metadata +2 -2
@@ -187,6 +187,27 @@ describe HexaPDF::Document::Metadata do
|
|
187
187
|
assert_equal(metadata, @doc.catalog[:Metadata].stream.sub(/(?<=id=")\w+/, ''))
|
188
188
|
end
|
189
189
|
|
190
|
+
it "writes the custom metadata" do
|
191
|
+
@metadata.delete
|
192
|
+
@metadata.custom_metadata("<rdf:Description>Test</rdf:Description>")
|
193
|
+
@metadata.custom_metadata("<rdf:Description>Test2</rdf:Description>")
|
194
|
+
@doc.write(StringIO.new, update_fields: false)
|
195
|
+
metadata = <<~XMP
|
196
|
+
<?xpacket begin="" id=""?>
|
197
|
+
<x:xmpmeta xmlns:x="adobe:ns:meta/">
|
198
|
+
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
199
|
+
<rdf:Description rdf:about="" xmlns:pdf="http://ns.adobe.com/pdf/1.3/">
|
200
|
+
<pdf:Producer>HexaPDF version #{HexaPDF::VERSION}</pdf:Producer>
|
201
|
+
</rdf:Description>
|
202
|
+
<rdf:Description>Test</rdf:Description>
|
203
|
+
<rdf:Description>Test2</rdf:Description>
|
204
|
+
</rdf:RDF>
|
205
|
+
</x:xmpmeta>
|
206
|
+
<?xpacket end="r"?>
|
207
|
+
XMP
|
208
|
+
assert_equal(metadata, @doc.catalog[:Metadata].stream.sub(/(?<=id=")\w+/, ''))
|
209
|
+
end
|
210
|
+
|
190
211
|
it "writes the XMP metadata" do
|
191
212
|
title = HexaPDF::Document::Metadata::LocalizedString.new('Der Titel')
|
192
213
|
title.language = 'de'
|
@@ -4,6 +4,37 @@ require 'test_helper'
|
|
4
4
|
require 'hexapdf/document'
|
5
5
|
require 'hexapdf/layout/box'
|
6
6
|
|
7
|
+
describe HexaPDF::Layout::Box::FitResult do
|
8
|
+
it "shows the box's mask area on #draw when using debug output" do
|
9
|
+
doc = HexaPDF::Document.new(config: {'debug' => true})
|
10
|
+
canvas = doc.pages.add.canvas
|
11
|
+
box = HexaPDF::Layout::Box.create(width: 20, height: 20) {}
|
12
|
+
frame = HexaPDF::Layout::Frame.new(5, 10, 100, 150)
|
13
|
+
result = HexaPDF::Layout::Box::FitResult.new(box, frame: frame)
|
14
|
+
result.mask = Geom2D::Rectangle(0, 0, 20, 20)
|
15
|
+
result.x = result.y = 0
|
16
|
+
result.draw(canvas, dx: 10, dy: 15)
|
17
|
+
assert_equal(<<~CONTENTS, canvas.contents)
|
18
|
+
/OC /P1 BDC
|
19
|
+
q
|
20
|
+
1 0 0 1 10 15 cm
|
21
|
+
0.0 0.501961 0.0 rg
|
22
|
+
0.0 0.392157 0.0 RG
|
23
|
+
/GS1 gs
|
24
|
+
0 0 20 20 re
|
25
|
+
B
|
26
|
+
Q
|
27
|
+
EMC
|
28
|
+
q
|
29
|
+
1 0 0 1 10 15 cm
|
30
|
+
Q
|
31
|
+
CONTENTS
|
32
|
+
ocg = doc.optional_content.ocgs.first
|
33
|
+
assert_equal([['Debug', ['Page 1', ocg]]], doc.optional_content.default_configuration[:Order])
|
34
|
+
assert_match(/10,15-20x20/, ocg.name)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
7
38
|
describe HexaPDF::Layout::Box do
|
8
39
|
before do
|
9
40
|
@frame = Object.new
|
@@ -78,7 +109,7 @@ describe HexaPDF::Layout::Box do
|
|
78
109
|
describe "fit" do
|
79
110
|
it "fits a fixed sized box" do
|
80
111
|
box = create_box(width: 50, height: 50, style: {padding: 5})
|
81
|
-
assert(box.fit(100, 100, @frame))
|
112
|
+
assert(box.fit(100, 100, @frame).success?)
|
82
113
|
assert_equal(50, box.width)
|
83
114
|
assert_equal(50, box.height)
|
84
115
|
assert_equal(5, box.instance_variable_get(:@fit_x))
|
@@ -87,28 +118,45 @@ describe HexaPDF::Layout::Box do
|
|
87
118
|
|
88
119
|
it "uses the maximum available width" do
|
89
120
|
box = create_box(height: 50)
|
90
|
-
assert(box.fit(100, 100, @frame))
|
121
|
+
assert(box.fit(100, 100, @frame).success?)
|
91
122
|
assert_equal(100, box.width)
|
92
123
|
assert_equal(50, box.height)
|
93
124
|
end
|
94
125
|
|
95
126
|
it "uses the maximum available height" do
|
96
127
|
box = create_box(width: 50)
|
97
|
-
assert(box.fit(100, 100, @frame))
|
128
|
+
assert(box.fit(100, 100, @frame).success?)
|
98
129
|
assert_equal(50, box.width)
|
99
130
|
assert_equal(100, box.height)
|
100
131
|
end
|
101
132
|
|
102
133
|
it "uses float comparison" do
|
103
134
|
box = create_box(width: 50.0000002, height: 49.9999996)
|
104
|
-
assert(box.fit(50, 50, @frame))
|
135
|
+
assert(box.fit(50, 50, @frame).success?)
|
105
136
|
assert_equal(50.0000002, box.width)
|
106
137
|
assert_equal(49.9999996, box.height)
|
107
138
|
end
|
108
139
|
|
109
|
-
it "
|
140
|
+
it "fails if the box doesn't fit, position != :flow and its width is greater than the available width" do
|
110
141
|
box = create_box(width: 101)
|
111
|
-
|
142
|
+
assert(box.fit(100, 100, @frame).failure?)
|
143
|
+
end
|
144
|
+
|
145
|
+
it "fails if the box doesn't fit, position != :flow and its width is greater than the available width" do
|
146
|
+
box = create_box(height: 101)
|
147
|
+
assert(box.fit(100, 100, @frame).failure?)
|
148
|
+
end
|
149
|
+
|
150
|
+
it "fails if its content width is zero" do
|
151
|
+
box = create_box(height: 100)
|
152
|
+
box.style.padding = [0, 100]
|
153
|
+
assert(box.fit(150, 150, @frame).failure?)
|
154
|
+
end
|
155
|
+
|
156
|
+
it "fails if its content height is zero" do
|
157
|
+
box = create_box(width: 100)
|
158
|
+
box.style.padding = [100, 0]
|
159
|
+
assert(box.fit(150, 150, @frame).failure?)
|
112
160
|
end
|
113
161
|
|
114
162
|
it "can use the #content_width/#content_height helper methods" do
|
@@ -116,9 +164,9 @@ describe HexaPDF::Layout::Box do
|
|
116
164
|
box.define_singleton_method(:fit_content) do |_aw, _ah, _frame|
|
117
165
|
update_content_width { 10 }
|
118
166
|
update_content_height { 20 }
|
119
|
-
|
167
|
+
fit_result.success!
|
120
168
|
end
|
121
|
-
assert(box.fit(100, 100, @frame))
|
169
|
+
assert(box.fit(100, 100, @frame).success?)
|
122
170
|
assert_equal(10, box.width)
|
123
171
|
assert_equal(20, box.height)
|
124
172
|
|
@@ -126,49 +174,40 @@ describe HexaPDF::Layout::Box do
|
|
126
174
|
box.define_singleton_method(:fit_content) do |_aw, _ah, _frame|
|
127
175
|
update_content_width { 10 }
|
128
176
|
update_content_height { 20 }
|
129
|
-
|
177
|
+
fit_result.success!
|
130
178
|
end
|
131
|
-
assert(box.fit(100, 100, @frame))
|
179
|
+
assert(box.fit(100, 100, @frame).success?)
|
132
180
|
assert_equal(30, box.width)
|
133
181
|
assert_equal(50, box.height)
|
134
182
|
end
|
135
183
|
end
|
136
184
|
|
137
185
|
describe "split" do
|
138
|
-
before do
|
139
|
-
@box = create_box(width: 100, height: 100)
|
140
|
-
@box.fit(100, 100, @frame)
|
141
|
-
end
|
142
|
-
|
143
186
|
it "doesn't need to be split if it completely fits" do
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
it "can't be split if it doesn't (completely) fit and its width is greater than the available width" do
|
148
|
-
@box.fit(90, 100, nil)
|
149
|
-
assert_equal([nil, @box], @box.split(50, 150, @frame))
|
150
|
-
end
|
151
|
-
|
152
|
-
it "can't be split if it doesn't (completely) fit and its height is greater than the available height" do
|
153
|
-
@box.fit(90, 100, nil)
|
154
|
-
assert_equal([nil, @box], @box.split(150, 50, @frame))
|
187
|
+
box = create_box(width: 100, height: 100)
|
188
|
+
box.fit(100, 100, @frame)
|
189
|
+
assert_equal([box, nil], box.split)
|
155
190
|
end
|
156
191
|
|
157
|
-
it "
|
158
|
-
box = create_box(width:
|
159
|
-
|
192
|
+
it "is not split if no part of it fits" do
|
193
|
+
box = create_box(width: 150)
|
194
|
+
box.fit(100, 100, @frame)
|
195
|
+
assert_equal([nil, box], box.split)
|
160
196
|
end
|
161
197
|
|
162
|
-
it "
|
163
|
-
box = create_box(
|
164
|
-
|
198
|
+
it "is not split if a height for the box is specified and it doesn't completely fit" do
|
199
|
+
box = create_box(height: 50)
|
200
|
+
box.define_singleton_method(:fit_content) {|*| fit_result.overflow! }
|
201
|
+
box.fit(100, 100, @frame)
|
202
|
+
assert_equal([box, nil], box.split)
|
165
203
|
end
|
166
204
|
|
167
|
-
it "can't be split if it doesn't
|
205
|
+
it "can't be split if it doesn't completely fit as the default implementation " \
|
168
206
|
"knows nothing about the content" do
|
169
|
-
|
170
|
-
|
171
|
-
|
207
|
+
box = create_box
|
208
|
+
box.define_singleton_method(:fit_content) {|*| fit_result.overflow! }
|
209
|
+
box.fit(100, 100, @frame)
|
210
|
+
assert_equal([nil, box], box.split)
|
172
211
|
end
|
173
212
|
end
|
174
213
|
|
@@ -177,7 +216,7 @@ describe HexaPDF::Layout::Box do
|
|
177
216
|
box.fit(100, 100, @frame)
|
178
217
|
cloned_box = box.send(:create_split_box)
|
179
218
|
assert(cloned_box.split_box?)
|
180
|
-
|
219
|
+
refute_same(box.fit_result, cloned_box.fit_result)
|
181
220
|
assert_equal(0, cloned_box.width)
|
182
221
|
assert_equal(0, cloned_box.height)
|
183
222
|
end
|
@@ -240,6 +279,12 @@ describe HexaPDF::Layout::Box do
|
|
240
279
|
refute(box.style.overlays?)
|
241
280
|
end
|
242
281
|
|
282
|
+
it "raises an error if the style property :overflow is set to error and the box doesn't completely fit" do
|
283
|
+
box = create_box(height: 50, style: {overflow: :error})
|
284
|
+
box.fit_result.overflow!
|
285
|
+
assert_raises(HexaPDF::Error) { box.draw(@canvas, 0, 0) }
|
286
|
+
end
|
287
|
+
|
243
288
|
it "wraps the box in optional content markers if the optional_content property is set" do
|
244
289
|
box = create_box(properties: {'optional_content' => 'Text'})
|
245
290
|
box.draw(@canvas, 0, 0)
|
@@ -50,6 +50,13 @@ describe HexaPDF::Layout::BoxFitter do
|
|
50
50
|
check_result(10, 20, 0, 0, 100, 130, 100, 110, content_heights: [90, 40])
|
51
51
|
end
|
52
52
|
|
53
|
+
it "correctly handles truncated boxes" do
|
54
|
+
box = HexaPDF::Layout::Box.new(height: 50) {}
|
55
|
+
box.define_singleton_method(:fit_content) {|*| fit_result.overflow! }
|
56
|
+
@box_fitter.fit(box)
|
57
|
+
check_result(10, 40, content_heights: [50, 0])
|
58
|
+
end
|
59
|
+
|
53
60
|
it "fails when some boxes can't be fitted" do
|
54
61
|
fit_box(9)
|
55
62
|
fit_box(70)
|
@@ -22,7 +22,7 @@ describe HexaPDF::Layout::ColumnBox do
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def check_box(box, width, height, fit_pos = nil)
|
25
|
-
assert(box.fit(@frame.available_width, @frame.available_height, @frame)
|
25
|
+
assert(box.fit(@frame.available_width, @frame.available_height, @frame).success?, "box didn't fit")
|
26
26
|
assert_equal(width, box.width, "box width")
|
27
27
|
assert_equal(height, box.height, "box height")
|
28
28
|
if fit_pos
|
@@ -73,9 +73,6 @@ describe HexaPDF::Layout::ColumnBox do
|
|
73
73
|
box = create_box(columns: 1, children: @fixed_size_boxes[0..0], width: 50,
|
74
74
|
style: {position: position})
|
75
75
|
check_box(box, 50, 10)
|
76
|
-
|
77
|
-
box = create_box(children: @fixed_size_boxes[0..0], width: 110)
|
78
|
-
refute(box.fit(@frame.available_width, @frame.available_height, @frame))
|
79
76
|
end
|
80
77
|
|
81
78
|
it "respects the set initial height, position #{position}" do
|
@@ -86,9 +83,6 @@ describe HexaPDF::Layout::ColumnBox do
|
|
86
83
|
box = create_box(children: @text_boxes[0..1], height: 50, equal_height: true,
|
87
84
|
style: {position: position})
|
88
85
|
check_box(box, 100, 50)
|
89
|
-
|
90
|
-
box = create_box(children: @fixed_size_boxes[0..0], height: 110)
|
91
|
-
refute(box.fit(@frame.available_width, @frame.available_height, @frame))
|
92
86
|
end
|
93
87
|
|
94
88
|
it "respects the border and padding around all columns, position #{position}" do
|
@@ -150,15 +144,15 @@ describe HexaPDF::Layout::ColumnBox do
|
|
150
144
|
|
151
145
|
it "fails if the necessary width is larger than the available one" do
|
152
146
|
box = create_box(children: @fixed_size_boxes[0..2], columns: 4, gaps: [40])
|
153
|
-
|
147
|
+
assert(box.fit(100, 100, @frame).failure?)
|
154
148
|
end
|
155
149
|
end
|
156
150
|
end
|
157
151
|
|
158
152
|
it "splits the children if they are too big to fill the colums" do
|
159
|
-
box = create_box(children: @fixed_size_boxes, width: 50
|
160
|
-
box.fit(100,
|
161
|
-
box_a, box_b = box.split
|
153
|
+
box = create_box(children: @fixed_size_boxes, width: 50)
|
154
|
+
assert(box.fit(100, 50, @frame).overflow?)
|
155
|
+
box_a, box_b = box.split
|
162
156
|
assert_same(box, box_a)
|
163
157
|
assert(box_b.split_box?)
|
164
158
|
assert_equal(5, box_b.children.size)
|
@@ -171,7 +165,7 @@ describe HexaPDF::Layout::ColumnBox do
|
|
171
165
|
|
172
166
|
it "draws the result onto the canvas" do
|
173
167
|
box = create_box(children: @fixed_size_boxes)
|
174
|
-
box.fit(100, 100, @frame)
|
168
|
+
assert(box.fit(100, 100, @frame).success?)
|
175
169
|
box.draw(@canvas, 0, 100 - box.height)
|
176
170
|
operators = 90.step(to: 20, by: -10).map do |y|
|
177
171
|
[[:save_graphics_state],
|
@@ -193,7 +187,7 @@ describe HexaPDF::Layout::ColumnBox do
|
|
193
187
|
|
194
188
|
it "takes a different final location into account" do
|
195
189
|
box = create_box(children: @fixed_size_boxes[0, 2], style: {padding: [2, 4, 6, 8]})
|
196
|
-
box.fit(100, 100, @frame)
|
190
|
+
assert(box.fit(100, 100, @frame).success?)
|
197
191
|
box.draw(@canvas, 20, 10)
|
198
192
|
operators = [
|
199
193
|
[:save_graphics_state],
|
@@ -15,7 +15,7 @@ describe HexaPDF::Layout::ContainerBox do
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def check_box(box, width, height, fit_pos = nil)
|
18
|
-
assert(box.fit(@frame.available_width, @frame.available_height, @frame)
|
18
|
+
assert(box.fit(@frame.available_width, @frame.available_height, @frame).success?, "box didn't fit")
|
19
19
|
assert_equal(width, box.width, "box width")
|
20
20
|
assert_equal(height, box.height, "box height")
|
21
21
|
if fit_pos
|
@@ -5,37 +5,6 @@ require 'hexapdf/layout/frame'
|
|
5
5
|
require 'hexapdf/layout/box'
|
6
6
|
require 'hexapdf/document'
|
7
7
|
|
8
|
-
describe HexaPDF::Layout::Frame::FitResult do
|
9
|
-
it "shows the box's mask area on #draw when using debug output" do
|
10
|
-
doc = HexaPDF::Document.new(config: {'debug' => true})
|
11
|
-
canvas = doc.pages.add.canvas
|
12
|
-
box = HexaPDF::Layout::Box.create(width: 20, height: 20) {}
|
13
|
-
frame = HexaPDF::Layout::Frame.new(5, 10, 100, 150)
|
14
|
-
result = HexaPDF::Layout::Frame::FitResult.new(frame, box)
|
15
|
-
result.mask = Geom2D::Rectangle(0, 0, 20, 20)
|
16
|
-
result.x = result.y = 0
|
17
|
-
result.draw(canvas, dx: 10, dy: 15)
|
18
|
-
assert_equal(<<~CONTENTS, canvas.contents)
|
19
|
-
/OC /P1 BDC
|
20
|
-
q
|
21
|
-
1 0 0 1 10 15 cm
|
22
|
-
0.0 0.501961 0.0 rg
|
23
|
-
0.0 0.392157 0.0 RG
|
24
|
-
/GS1 gs
|
25
|
-
0 0 20 20 re
|
26
|
-
B
|
27
|
-
Q
|
28
|
-
EMC
|
29
|
-
q
|
30
|
-
1 0 0 1 10 15 cm
|
31
|
-
Q
|
32
|
-
CONTENTS
|
33
|
-
ocg = doc.optional_content.ocgs.first
|
34
|
-
assert_equal([['Debug', ['Page 1', ocg]]], doc.optional_content.default_configuration[:Order])
|
35
|
-
assert_match(/10,15-20x20/, ocg.name)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
8
|
describe HexaPDF::Layout::Frame do
|
40
9
|
before do
|
41
10
|
@frame = HexaPDF::Layout::Frame.new(5, 10, 100, 150)
|
@@ -454,23 +423,6 @@ describe HexaPDF::Layout::Frame do
|
|
454
423
|
box = HexaPDF::Layout::Box.create
|
455
424
|
refute(@frame.fit(box).success?)
|
456
425
|
end
|
457
|
-
|
458
|
-
it "handles (but doesn't draw) the box if the its height or width is zero" do
|
459
|
-
result = Minitest::Mock.new
|
460
|
-
box = Minitest::Mock.new
|
461
|
-
|
462
|
-
result.expect(:box, box)
|
463
|
-
box.expect(:height, 0)
|
464
|
-
@frame.draw(@canvas, result)
|
465
|
-
|
466
|
-
result.expect(:box, box)
|
467
|
-
box.expect(:height, 5)
|
468
|
-
result.expect(:box, box)
|
469
|
-
box.expect(:width, 0)
|
470
|
-
@frame.draw(@canvas, result)
|
471
|
-
|
472
|
-
result.verify
|
473
|
-
end
|
474
426
|
end
|
475
427
|
|
476
428
|
describe "split" do
|
@@ -9,6 +9,9 @@ describe HexaPDF::Layout::ImageBox do
|
|
9
9
|
@image = HexaPDF::Stream.new({Subtype: :Image}, stream: '')
|
10
10
|
@image.define_singleton_method(:width) { 40 }
|
11
11
|
@image.define_singleton_method(:height) { 20 }
|
12
|
+
@frame = Object.new
|
13
|
+
def @frame.x; 0; end
|
14
|
+
def @frame.y; 100; end
|
12
15
|
end
|
13
16
|
|
14
17
|
def create_box(**kwargs)
|
@@ -25,35 +28,40 @@ describe HexaPDF::Layout::ImageBox do
|
|
25
28
|
describe "fit" do
|
26
29
|
it "fits with fixed dimensions" do
|
27
30
|
box = create_box(width: 50, height: 30, style: {padding: [10, 4, 6, 2]})
|
28
|
-
assert(box.fit(100, 100,
|
31
|
+
assert(box.fit(100, 100, @frame).success?)
|
29
32
|
assert_equal(50, box.width)
|
30
33
|
assert_equal(30, box.height)
|
31
34
|
end
|
32
35
|
|
33
36
|
it "fits with a fixed width" do
|
34
37
|
box = create_box(width: 60, style: {padding: [10, 4, 6, 2]})
|
35
|
-
assert(box.fit(100, 100,
|
38
|
+
assert(box.fit(100, 100, @frame).success?)
|
36
39
|
assert_equal(60, box.width)
|
37
40
|
assert_equal(43, box.height)
|
38
41
|
end
|
39
42
|
|
40
43
|
it "fits with a fixed height" do
|
41
44
|
box = create_box(height: 40, style: {padding: [10, 4, 6, 2]})
|
42
|
-
assert(box.fit(100, 100,
|
45
|
+
assert(box.fit(100, 100, @frame).success?)
|
43
46
|
assert_equal(54, box.width)
|
44
47
|
assert_equal(40, box.height)
|
45
48
|
end
|
46
49
|
|
47
50
|
it "fits with auto-scaling to available space" do
|
48
51
|
box = create_box(style: {padding: [10, 4, 6, 2]})
|
49
|
-
assert(box.fit(100, 100,
|
52
|
+
assert(box.fit(100, 100, @frame).success?)
|
50
53
|
assert_equal(100, box.width)
|
51
54
|
assert_equal(63, box.height)
|
52
55
|
|
53
|
-
assert(box.fit(100, 30,
|
56
|
+
assert(box.fit(100, 30, @frame).success?)
|
54
57
|
assert_equal(34, box.width)
|
55
58
|
assert_equal(30, box.height)
|
56
59
|
end
|
60
|
+
|
61
|
+
it "fails if one of the calculated dimensions is larger than the available space" do
|
62
|
+
box = create_box(height: 60)
|
63
|
+
assert(box.fit(100, 100, @frame).failure?)
|
64
|
+
end
|
57
65
|
end
|
58
66
|
|
59
67
|
it "always returns false for empty?" do
|
@@ -63,7 +71,7 @@ describe HexaPDF::Layout::ImageBox do
|
|
63
71
|
describe "draw" do
|
64
72
|
it "draws the image" do
|
65
73
|
box = create_box(height: 40, style: {padding: [10, 4, 6, 2]})
|
66
|
-
box.fit(100, 100,
|
74
|
+
box.fit(100, 100, @frame)
|
67
75
|
|
68
76
|
@canvas = HexaPDF::Document.new.pages.add.canvas
|
69
77
|
box.draw(@canvas, 0, 0)
|
@@ -19,8 +19,9 @@ describe HexaPDF::Layout::ListBox do
|
|
19
19
|
HexaPDF::Layout::ListBox.new(content_indentation: 10, **kwargs)
|
20
20
|
end
|
21
21
|
|
22
|
-
def check_box(box, width, height, fit_pos
|
23
|
-
|
22
|
+
def check_box(box, width, height, status: :success, fit_pos: nil)
|
23
|
+
result = box.fit(@frame.available_width, @frame.available_height, @frame)
|
24
|
+
assert_equal(result.status, status)
|
24
25
|
assert_equal(width, box.width, "box width")
|
25
26
|
assert_equal(height, box.height, "box height")
|
26
27
|
if fit_pos
|
@@ -73,45 +74,44 @@ describe HexaPDF::Layout::ListBox do
|
|
73
74
|
check_box(box, 100, 40)
|
74
75
|
end
|
75
76
|
|
76
|
-
it "respects the set initial height
|
77
|
-
box = create_box(children: @text_boxes[0, 2], height: 20,
|
78
|
-
|
79
|
-
check_box(box, 100, 20)
|
77
|
+
it "respects the set initial height even when it doesn't fit completely" do
|
78
|
+
box = create_box(children: @text_boxes[0, 2], height: 20, style: {position: position})
|
79
|
+
check_box(box, 100, 20, status: :overflow)
|
80
80
|
end
|
81
81
|
|
82
82
|
it "respects the border and padding around all list items, position #{position}" do
|
83
83
|
box = create_box(children: @text_boxes[0, 2],
|
84
84
|
style: {border: {width: [5, 4, 3, 2]}, padding: [5, 4, 3, 2], position: position})
|
85
|
-
check_box(box, 100, 76, [[14, 60], [14, 30]])
|
85
|
+
check_box(box, 100, 76, fit_pos: [[14, 60], [14, 30]])
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
89
89
|
it "uses the frame's current cursor position and available width/height when position=:default" do
|
90
90
|
@frame.remove_area(Geom2D::Polygon([0, 0], [10, 0], [10, 90], [100, 90], [100, 100], [0, 100]))
|
91
91
|
box = create_box(children: @text_boxes[0, 2])
|
92
|
-
check_box(box, 90, 40, [[20, 70], [20, 50]])
|
92
|
+
check_box(box, 90, 40, fit_pos: [[20, 70], [20, 50]])
|
93
93
|
end
|
94
94
|
|
95
95
|
it "respects the frame's shape when style position=:flow" do
|
96
96
|
@frame.remove_area(Geom2D::Polygon([0, 0], [0, 40], [40, 40], [40, 0]))
|
97
97
|
box = create_box(children: @text_boxes[0, 4], style: {position: :flow})
|
98
|
-
check_box(box, 100, 90, [[10, 80], [10, 60], [10, 40], [50, 10]])
|
98
|
+
check_box(box, 100, 90, fit_pos: [[10, 80], [10, 60], [10, 40], [50, 10]])
|
99
99
|
end
|
100
100
|
|
101
101
|
it "calculates the correct height if the marker is higher than the content" do
|
102
102
|
box = create_box(children: @text_boxes[0, 1], content_indentation: 20,
|
103
103
|
style: {font_size: 30})
|
104
|
-
check_box(box, 100, 27, [[20, 80]])
|
104
|
+
check_box(box, 100, 27, fit_pos: [[20, 80]])
|
105
105
|
end
|
106
106
|
|
107
107
|
it "respects the content indentation" do
|
108
108
|
box = create_box(children: @text_boxes[0, 1], content_indentation: 30)
|
109
|
-
check_box(box, 100, 30, [[30, 70]])
|
109
|
+
check_box(box, 100, 30, fit_pos: [[30, 70]])
|
110
110
|
end
|
111
111
|
|
112
112
|
it "respects the spacing between list items" do
|
113
113
|
box = create_box(children: @text_boxes[0, 2], item_spacing: 30)
|
114
|
-
check_box(box, 100, 70, [[10, 80], [10, 30]])
|
114
|
+
check_box(box, 100, 70, fit_pos: [[10, 80], [10, 30]])
|
115
115
|
end
|
116
116
|
|
117
117
|
it "creates a new box for each marker even if the marker is the same" do
|
@@ -121,6 +121,11 @@ describe HexaPDF::Layout::ListBox do
|
|
121
121
|
refute_same(results[0].marker, results[1].marker)
|
122
122
|
end
|
123
123
|
|
124
|
+
it "fails if not even a part of the first list item fits" do
|
125
|
+
box = create_box(children: @text_boxes[0, 2], height: 5)
|
126
|
+
check_box(box, 100, 0, status: :failure)
|
127
|
+
end
|
128
|
+
|
124
129
|
it "fails for unknown marker types" do
|
125
130
|
box = create_box(children: @text_boxes[0, 1], marker_type: :unknown)
|
126
131
|
assert_raises(HexaPDF::Error) { box.fit(100, 100, @frame) }
|
@@ -129,9 +134,9 @@ describe HexaPDF::Layout::ListBox do
|
|
129
134
|
|
130
135
|
describe "split" do
|
131
136
|
it "splits before a list item if no part of it will fit" do
|
132
|
-
box = create_box(children: @text_boxes[0, 2]
|
133
|
-
box.fit(100,
|
134
|
-
box_a, box_b = box.split
|
137
|
+
box = create_box(children: @text_boxes[0, 2])
|
138
|
+
assert(box.fit(100, 20, @frame).overflow?)
|
139
|
+
box_a, box_b = box.split
|
135
140
|
assert_same(box, box_a)
|
136
141
|
assert_equal(:show_first_marker, box_b.split_box?)
|
137
142
|
assert_equal(1, box_a.instance_variable_get(:@results)[0].box_fitter.fit_results.size)
|
@@ -140,9 +145,9 @@ describe HexaPDF::Layout::ListBox do
|
|
140
145
|
end
|
141
146
|
|
142
147
|
it "splits a list item if some part of it will fit" do
|
143
|
-
box = create_box(children: @text_boxes[0, 2]
|
144
|
-
box.fit(100,
|
145
|
-
box_a, box_b = box.split
|
148
|
+
box = create_box(children: @text_boxes[0, 2])
|
149
|
+
assert(box.fit(100, 10, @frame).overflow?)
|
150
|
+
box_a, box_b = box.split
|
146
151
|
assert_same(box, box_a)
|
147
152
|
assert_equal(:hide_first_marker, box_b.split_box?)
|
148
153
|
assert_equal(1, box_a.instance_variable_get(:@results)[0].box_fitter.fit_results.size)
|
@@ -152,8 +157,8 @@ describe HexaPDF::Layout::ListBox do
|
|
152
157
|
|
153
158
|
it "splits a list item containg multiple boxes along box lines" do
|
154
159
|
box = create_box(children: [@text_boxes[0], @text_boxes[1, 2]])
|
155
|
-
box.fit(100, 40, @frame)
|
156
|
-
box_a, box_b = box.split
|
160
|
+
assert(box.fit(100, 40, @frame).overflow?)
|
161
|
+
box_a, box_b = box.split
|
157
162
|
assert_same(box, box_a)
|
158
163
|
assert_equal(:hide_first_marker, box_b.split_box?)
|
159
164
|
assert_equal(1, box_a.instance_variable_get(:@results)[1].box_fitter.fit_results.size)
|
@@ -338,11 +343,5 @@ describe HexaPDF::Layout::ListBox do
|
|
338
343
|
assert_operators(@canvas.contents, [:set_font_and_size, [:F1, 5]], range: 1)
|
339
344
|
assert_equal(:ZapfDingbats, @canvas.resources.font(:F1)[:BaseFont])
|
340
345
|
end
|
341
|
-
|
342
|
-
it "fails if the initial height is set and property overflow is set to :error" do
|
343
|
-
box = create_box(children: @fixed_size_boxes[0, 2], height: 10)
|
344
|
-
box.fit(100, 100, @frame)
|
345
|
-
assert_raises(HexaPDF::Error) { box.draw(@canvas, 0, 100 - box.height) }
|
346
|
-
end
|
347
346
|
end
|
348
347
|
end
|