hexapdf 0.43.0 → 0.45.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 +36 -0
- data/examples/027-composer_optional_content.rb +6 -4
- data/examples/030-pdfa.rb +13 -11
- data/lib/hexapdf/composer.rb +23 -0
- data/lib/hexapdf/content/canvas.rb +3 -3
- data/lib/hexapdf/content/canvas_composer.rb +1 -0
- data/lib/hexapdf/document/files.rb +7 -2
- data/lib/hexapdf/document/layout.rb +15 -3
- data/lib/hexapdf/document/metadata.rb +12 -1
- data/lib/hexapdf/font/type1/character_metrics.rb +1 -1
- data/lib/hexapdf/font/type1/font_metrics.rb +1 -1
- data/lib/hexapdf/layout/box.rb +180 -66
- data/lib/hexapdf/layout/box_fitter.rb +1 -0
- data/lib/hexapdf/layout/column_box.rb +18 -28
- data/lib/hexapdf/layout/container_box.rb +6 -6
- data/lib/hexapdf/layout/frame.rb +13 -94
- data/lib/hexapdf/layout/image_box.rb +4 -4
- data/lib/hexapdf/layout/list_box.rb +13 -31
- data/lib/hexapdf/layout/style.rb +8 -4
- data/lib/hexapdf/layout/table_box.rb +55 -58
- data/lib/hexapdf/layout/text_box.rb +84 -71
- data/lib/hexapdf/layout/text_fragment.rb +1 -1
- data/lib/hexapdf/layout/text_layouter.rb +7 -8
- data/lib/hexapdf/parser.rb +5 -2
- data/lib/hexapdf/rectangle.rb +4 -4
- data/lib/hexapdf/type/file_specification.rb +9 -5
- data/lib/hexapdf/type/form.rb +2 -2
- data/lib/hexapdf/type/graphics_state_parameter.rb +1 -1
- data/lib/hexapdf/version.rb +1 -1
- data/test/hexapdf/content/test_canvas_composer.rb +13 -8
- data/test/hexapdf/document/test_files.rb +5 -0
- data/test/hexapdf/document/test_layout.rb +16 -0
- data/test/hexapdf/document/test_metadata.rb +21 -0
- data/test/hexapdf/layout/test_box.rb +93 -37
- data/test/hexapdf/layout/test_box_fitter.rb +7 -0
- data/test/hexapdf/layout/test_column_box.rb +7 -13
- data/test/hexapdf/layout/test_container_box.rb +1 -1
- data/test/hexapdf/layout/test_frame.rb +7 -46
- data/test/hexapdf/layout/test_image_box.rb +14 -6
- data/test/hexapdf/layout/test_list_box.rb +26 -27
- data/test/hexapdf/layout/test_table_box.rb +47 -54
- data/test/hexapdf/layout/test_text_box.rb +83 -83
- data/test/hexapdf/test_composer.rb +20 -5
- data/test/hexapdf/test_parser.rb +8 -0
- data/test/hexapdf/test_serializer.rb +1 -0
- data/test/hexapdf/type/test_file_specification.rb +2 -1
- metadata +2 -2
@@ -4,11 +4,45 @@ 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
|
10
41
|
def @frame.x; 0; end
|
11
42
|
def @frame.y; 100; end
|
43
|
+
def @frame.bottom; 40; end
|
44
|
+
def @frame.width; 150; end
|
45
|
+
def @frame.height; 150; end
|
12
46
|
end
|
13
47
|
|
14
48
|
def create_box(**args, &block)
|
@@ -78,7 +112,7 @@ describe HexaPDF::Layout::Box do
|
|
78
112
|
describe "fit" do
|
79
113
|
it "fits a fixed sized box" do
|
80
114
|
box = create_box(width: 50, height: 50, style: {padding: 5})
|
81
|
-
assert(box.fit(100, 100, @frame))
|
115
|
+
assert(box.fit(100, 100, @frame).success?)
|
82
116
|
assert_equal(50, box.width)
|
83
117
|
assert_equal(50, box.height)
|
84
118
|
assert_equal(5, box.instance_variable_get(:@fit_x))
|
@@ -87,28 +121,53 @@ describe HexaPDF::Layout::Box do
|
|
87
121
|
|
88
122
|
it "uses the maximum available width" do
|
89
123
|
box = create_box(height: 50)
|
90
|
-
assert(box.fit(100, 100, @frame))
|
124
|
+
assert(box.fit(100, 100, @frame).success?)
|
91
125
|
assert_equal(100, box.width)
|
92
126
|
assert_equal(50, box.height)
|
93
127
|
end
|
94
128
|
|
95
129
|
it "uses the maximum available height" do
|
96
130
|
box = create_box(width: 50)
|
97
|
-
assert(box.fit(100, 100, @frame))
|
131
|
+
assert(box.fit(100, 100, @frame).success?)
|
98
132
|
assert_equal(50, box.width)
|
99
133
|
assert_equal(100, box.height)
|
100
134
|
end
|
101
135
|
|
136
|
+
it "use the frame's width and its remaining height for position=:flow boxes" do
|
137
|
+
box = create_box(style: {position: :flow})
|
138
|
+
box.define_singleton_method(:supports_position_flow?) { true }
|
139
|
+
assert(box.fit(100, 100, @frame).success?)
|
140
|
+
assert_equal(150, box.width)
|
141
|
+
assert_equal(60, box.height)
|
142
|
+
end
|
143
|
+
|
102
144
|
it "uses float comparison" do
|
103
145
|
box = create_box(width: 50.0000002, height: 49.9999996)
|
104
|
-
assert(box.fit(50, 50, @frame))
|
146
|
+
assert(box.fit(50, 50, @frame).success?)
|
105
147
|
assert_equal(50.0000002, box.width)
|
106
148
|
assert_equal(49.9999996, box.height)
|
107
149
|
end
|
108
150
|
|
109
|
-
it "
|
151
|
+
it "fails if the box doesn't fit, position != :flow and its width is greater than the available width" do
|
110
152
|
box = create_box(width: 101)
|
111
|
-
|
153
|
+
assert(box.fit(100, 100, @frame).failure?)
|
154
|
+
end
|
155
|
+
|
156
|
+
it "fails if the box doesn't fit, position != :flow and its width is greater than the available width" do
|
157
|
+
box = create_box(height: 101)
|
158
|
+
assert(box.fit(100, 100, @frame).failure?)
|
159
|
+
end
|
160
|
+
|
161
|
+
it "fails if its content width is zero" do
|
162
|
+
box = create_box(height: 100)
|
163
|
+
box.style.padding = [0, 100]
|
164
|
+
assert(box.fit(150, 150, @frame).failure?)
|
165
|
+
end
|
166
|
+
|
167
|
+
it "fails if its content height is zero" do
|
168
|
+
box = create_box(width: 100)
|
169
|
+
box.style.padding = [100, 0]
|
170
|
+
assert(box.fit(150, 150, @frame).failure?)
|
112
171
|
end
|
113
172
|
|
114
173
|
it "can use the #content_width/#content_height helper methods" do
|
@@ -116,9 +175,9 @@ describe HexaPDF::Layout::Box do
|
|
116
175
|
box.define_singleton_method(:fit_content) do |_aw, _ah, _frame|
|
117
176
|
update_content_width { 10 }
|
118
177
|
update_content_height { 20 }
|
119
|
-
|
178
|
+
fit_result.success!
|
120
179
|
end
|
121
|
-
assert(box.fit(100, 100, @frame))
|
180
|
+
assert(box.fit(100, 100, @frame).success?)
|
122
181
|
assert_equal(10, box.width)
|
123
182
|
assert_equal(20, box.height)
|
124
183
|
|
@@ -126,49 +185,40 @@ describe HexaPDF::Layout::Box do
|
|
126
185
|
box.define_singleton_method(:fit_content) do |_aw, _ah, _frame|
|
127
186
|
update_content_width { 10 }
|
128
187
|
update_content_height { 20 }
|
129
|
-
|
188
|
+
fit_result.success!
|
130
189
|
end
|
131
|
-
assert(box.fit(100, 100, @frame))
|
190
|
+
assert(box.fit(100, 100, @frame).success?)
|
132
191
|
assert_equal(30, box.width)
|
133
192
|
assert_equal(50, box.height)
|
134
193
|
end
|
135
194
|
end
|
136
195
|
|
137
196
|
describe "split" do
|
138
|
-
before do
|
139
|
-
@box = create_box(width: 100, height: 100)
|
140
|
-
@box.fit(100, 100, @frame)
|
141
|
-
end
|
142
|
-
|
143
197
|
it "doesn't need to be split if it completely fits" do
|
144
|
-
|
198
|
+
box = create_box(width: 100, height: 100)
|
199
|
+
box.fit(100, 100, @frame)
|
200
|
+
assert_equal([box, nil], box.split)
|
145
201
|
end
|
146
202
|
|
147
|
-
it "
|
148
|
-
|
149
|
-
|
203
|
+
it "is not split if no part of it fits" do
|
204
|
+
box = create_box(width: 150)
|
205
|
+
box.fit(100, 100, @frame)
|
206
|
+
assert_equal([nil, box], box.split)
|
150
207
|
end
|
151
208
|
|
152
|
-
it "
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
it "can't be split if it doesn't (completely) fit and its content width is zero" do
|
158
|
-
box = create_box(width: 0, height: 100)
|
159
|
-
assert_equal([nil, box], box.split(150, 150, @frame))
|
160
|
-
end
|
161
|
-
|
162
|
-
it "can't be split if it doesn't (completely) fit and its content height is zero" do
|
163
|
-
box = create_box(width: 100, height: 0)
|
164
|
-
assert_equal([nil, box], box.split(150, 150, @frame))
|
209
|
+
it "is not split if a height for the box is specified and it doesn't completely fit" do
|
210
|
+
box = create_box(height: 50)
|
211
|
+
box.define_singleton_method(:fit_content) {|*| fit_result.overflow! }
|
212
|
+
box.fit(100, 100, @frame)
|
213
|
+
assert_equal([box, nil], box.split)
|
165
214
|
end
|
166
215
|
|
167
|
-
it "can't be split if it doesn't
|
216
|
+
it "can't be split if it doesn't completely fit as the default implementation " \
|
168
217
|
"knows nothing about the content" do
|
169
|
-
|
170
|
-
|
171
|
-
|
218
|
+
box = create_box
|
219
|
+
box.define_singleton_method(:fit_content) {|*| fit_result.overflow! }
|
220
|
+
box.fit(100, 100, @frame)
|
221
|
+
assert_equal([nil, box], box.split)
|
172
222
|
end
|
173
223
|
end
|
174
224
|
|
@@ -177,7 +227,7 @@ describe HexaPDF::Layout::Box do
|
|
177
227
|
box.fit(100, 100, @frame)
|
178
228
|
cloned_box = box.send(:create_split_box)
|
179
229
|
assert(cloned_box.split_box?)
|
180
|
-
|
230
|
+
refute_same(box.fit_result, cloned_box.fit_result)
|
181
231
|
assert_equal(0, cloned_box.width)
|
182
232
|
assert_equal(0, cloned_box.height)
|
183
233
|
end
|
@@ -240,6 +290,12 @@ describe HexaPDF::Layout::Box do
|
|
240
290
|
refute(box.style.overlays?)
|
241
291
|
end
|
242
292
|
|
293
|
+
it "raises an error if the style property :overflow is set to error and the box doesn't completely fit" do
|
294
|
+
box = create_box(height: 50, style: {overflow: :error})
|
295
|
+
box.fit_result.overflow!
|
296
|
+
assert_raises(HexaPDF::Error) { box.draw(@canvas, 0, 0) }
|
297
|
+
end
|
298
|
+
|
243
299
|
it "wraps the box in optional content markers if the optional_content property is set" do
|
244
300
|
box = create_box(properties: {'optional_content' => 'Text'})
|
245
301
|
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)
|
@@ -455,21 +424,13 @@ describe HexaPDF::Layout::Frame do
|
|
455
424
|
refute(@frame.fit(box).success?)
|
456
425
|
end
|
457
426
|
|
458
|
-
it "
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
result.
|
463
|
-
|
464
|
-
|
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
|
427
|
+
it "doesn't do post-fitting tasks if fitting is a failure" do
|
428
|
+
box = HexaPDF::Layout::Box.create(width: 400)
|
429
|
+
result = @frame.fit(box)
|
430
|
+
assert(result.failure?)
|
431
|
+
assert_nil(result.x)
|
432
|
+
assert_nil(result.y)
|
433
|
+
assert_nil(result.mask)
|
473
434
|
end
|
474
435
|
end
|
475
436
|
|
@@ -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,20 +134,20 @@ 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,
|
133
|
-
box.fit(100,
|
134
|
-
box_a, box_b = box.split
|
137
|
+
box = create_box(children: @text_boxes[0, 3])
|
138
|
+
assert(box.fit(100, 22, @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)
|
138
|
-
assert_equal(
|
143
|
+
assert_equal(2, box_b.children.size)
|
139
144
|
assert_equal(2, box_b.start_number)
|
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
|