hexapdf 0.43.0 → 0.45.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 +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
|