hexapdf 0.42.0 → 0.44.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +46 -0
  3. data/Rakefile +1 -1
  4. data/examples/030-pdfa.rb +1 -0
  5. data/lib/hexapdf/composer.rb +1 -0
  6. data/lib/hexapdf/dictionary.rb +3 -3
  7. data/lib/hexapdf/document/files.rb +7 -2
  8. data/lib/hexapdf/document/metadata.rb +12 -1
  9. data/lib/hexapdf/document.rb +14 -1
  10. data/lib/hexapdf/encryption.rb +17 -0
  11. data/lib/hexapdf/layout/box.rb +161 -61
  12. data/lib/hexapdf/layout/box_fitter.rb +4 -3
  13. data/lib/hexapdf/layout/column_box.rb +23 -25
  14. data/lib/hexapdf/layout/container_box.rb +3 -3
  15. data/lib/hexapdf/layout/frame.rb +13 -95
  16. data/lib/hexapdf/layout/image_box.rb +4 -4
  17. data/lib/hexapdf/layout/line.rb +4 -0
  18. data/lib/hexapdf/layout/list_box.rb +12 -20
  19. data/lib/hexapdf/layout/style.rb +5 -1
  20. data/lib/hexapdf/layout/table_box.rb +48 -55
  21. data/lib/hexapdf/layout/text_box.rb +38 -39
  22. data/lib/hexapdf/parser.rb +23 -17
  23. data/lib/hexapdf/type/acro_form/form.rb +78 -27
  24. data/lib/hexapdf/type/file_specification.rb +9 -5
  25. data/lib/hexapdf/type/graphics_state_parameter.rb +1 -1
  26. data/lib/hexapdf/version.rb +1 -1
  27. data/test/hexapdf/document/test_files.rb +5 -0
  28. data/test/hexapdf/document/test_metadata.rb +21 -0
  29. data/test/hexapdf/layout/test_box.rb +82 -37
  30. data/test/hexapdf/layout/test_box_fitter.rb +10 -3
  31. data/test/hexapdf/layout/test_column_box.rb +7 -13
  32. data/test/hexapdf/layout/test_container_box.rb +1 -1
  33. data/test/hexapdf/layout/test_frame.rb +0 -48
  34. data/test/hexapdf/layout/test_image_box.rb +14 -6
  35. data/test/hexapdf/layout/test_list_box.rb +25 -26
  36. data/test/hexapdf/layout/test_table_box.rb +39 -53
  37. data/test/hexapdf/layout/test_text_box.rb +65 -67
  38. data/test/hexapdf/test_composer.rb +6 -0
  39. data/test/hexapdf/test_dictionary.rb +6 -4
  40. data/test/hexapdf/test_parser.rb +20 -0
  41. data/test/hexapdf/type/acro_form/test_form.rb +63 -2
  42. data/test/hexapdf/type/test_file_specification.rb +2 -1
  43. metadata +2 -2
@@ -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 "returns false if the box doesn't fit" do
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
- refute(box.fit(100, 100, @frame))
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
- true
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
- true
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
- assert_equal([@box, nil], @box.split(100, 100, @frame))
145
- end
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 "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))
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 "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))
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 (completely) fit as the default implementation " \
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
- @box.style.position = :flow # make sure we would generally be splitable
170
- @box.fit(90, 100, nil)
171
- assert_equal([nil, @box], @box.split(150, 150, @frame))
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
- refute(cloned_box.instance_variable_get(:@fit_successful))
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)
@@ -20,13 +20,13 @@ describe HexaPDF::Layout::BoxFitter do
20
20
  @box_fitter.fit(HexaPDF::Layout::TextBox.new(items: [ibox] * count))
21
21
  end
22
22
 
23
- def check_result(*pos, content_heights:, successful: true, boxes_remain: false)
23
+ def check_result(*pos, content_heights:, success: true, boxes_remain: false)
24
24
  pos.each_slice(2).with_index do |(x, y), index|
25
25
  assert_equal(x, @box_fitter.fit_results[index].x, "x #{index}")
26
26
  assert_equal(y, @box_fitter.fit_results[index].y, "y #{index}")
27
27
  end
28
28
  assert_equal(content_heights, @box_fitter.content_heights)
29
- successful ? assert(@box_fitter.fit_successful?) : refute(@box_fitter.fit_successful?)
29
+ success ? assert(@box_fitter.success?) : refute(@box_fitter.success?)
30
30
  rboxes = @box_fitter.remaining_boxes.empty?
31
31
  boxes_remain ? refute(rboxes) : assert(rboxes)
32
32
  end
@@ -50,12 +50,19 @@ 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)
56
63
  fit_box(40)
57
64
  fit_box(20)
58
- check_result(10, 80, 0, 10, 0, 0, 100, 100, successful: false, boxes_remain: true,
65
+ check_result(10, 80, 0, 10, 0, 0, 100, 100, success: false, boxes_remain: true,
59
66
  content_heights: [90, 50])
60
67
  assert_equal(2, @box_fitter.remaining_boxes.size)
61
68
  end
@@ -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), "box didn't fit")
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
- refute(box.fit(100, 100, @frame))
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, height: 50)
160
- box.fit(100, 100, @frame)
161
- box_a, box_b = box.split(100, 100, @frame)
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), "box didn't fit")
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, nil))
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, nil))
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, nil))
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, nil))
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, nil))
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, nil)
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 = nil)
23
- assert(box.fit(@frame.available_width, @frame.available_height, @frame), "box didn't fit")
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 and the property overflow=:truncate" do
77
- box = create_box(children: @text_boxes[0, 2], height: 20,
78
- style: {overflow: :truncate, position: position})
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], height: 20)
133
- box.fit(100, 100, @frame)
134
- box_a, box_b = box.split(100, 100, @frame)
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], height: 10)
144
- box.fit(100, 100, @frame)
145
- box_a, box_b = box.split(100, 100, @frame)
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(100, 40, @frame)
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