hexapdf 0.34.1 → 0.35.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 +59 -0
- data/examples/009-text_layouter_alignment.rb +7 -7
- data/examples/010-text_layouter_inline_boxes.rb +1 -1
- data/examples/011-text_layouter_line_wrapping.rb +2 -4
- data/examples/013-text_layouter_shapes.rb +9 -11
- data/examples/014-text_in_polygon.rb +2 -2
- data/examples/016-frame_automatic_box_placement.rb +6 -7
- data/examples/017-frame_text_flow.rb +2 -2
- data/examples/018-composer.rb +5 -6
- data/examples/020-column_box.rb +2 -2
- data/examples/021-list_box.rb +1 -1
- data/examples/027-composer_optional_content.rb +5 -5
- data/examples/028-frame_mask_mode.rb +23 -0
- data/examples/029-composer_fallback_fonts.rb +22 -0
- data/lib/hexapdf/cli/info.rb +1 -0
- data/lib/hexapdf/cli/inspect.rb +55 -2
- data/lib/hexapdf/composer.rb +2 -2
- data/lib/hexapdf/configuration.rb +61 -1
- data/lib/hexapdf/content/canvas.rb +63 -0
- data/lib/hexapdf/content/canvas_composer.rb +142 -0
- data/lib/hexapdf/content.rb +1 -0
- data/lib/hexapdf/dictionary.rb +14 -3
- data/lib/hexapdf/document/layout.rb +35 -13
- data/lib/hexapdf/encryption/standard_security_handler.rb +15 -0
- data/lib/hexapdf/error.rb +2 -1
- data/lib/hexapdf/font/invalid_glyph.rb +22 -6
- data/lib/hexapdf/font/true_type_wrapper.rb +48 -20
- data/lib/hexapdf/font/type1_wrapper.rb +48 -24
- data/lib/hexapdf/layout/box.rb +11 -8
- data/lib/hexapdf/layout/column_box.rb +5 -3
- data/lib/hexapdf/layout/frame.rb +77 -39
- data/lib/hexapdf/layout/image_box.rb +3 -3
- data/lib/hexapdf/layout/list_box.rb +20 -19
- data/lib/hexapdf/layout/style.rb +173 -68
- data/lib/hexapdf/layout/table_box.rb +3 -3
- data/lib/hexapdf/layout/text_box.rb +5 -5
- data/lib/hexapdf/layout/text_fragment.rb +50 -0
- data/lib/hexapdf/layout/text_layouter.rb +7 -6
- data/lib/hexapdf/object.rb +5 -2
- data/lib/hexapdf/pdf_array.rb +5 -0
- data/lib/hexapdf/type/acro_form/appearance_generator.rb +16 -11
- data/lib/hexapdf/utils/sorted_tree_node.rb +0 -10
- data/lib/hexapdf/version.rb +1 -1
- data/test/hexapdf/content/test_canvas.rb +37 -0
- data/test/hexapdf/content/test_canvas_composer.rb +112 -0
- data/test/hexapdf/document/test_layout.rb +40 -12
- data/test/hexapdf/encryption/test_standard_security_handler.rb +43 -0
- data/test/hexapdf/font/test_invalid_glyph.rb +13 -1
- data/test/hexapdf/font/test_true_type_wrapper.rb +15 -2
- data/test/hexapdf/font/test_type1_wrapper.rb +21 -2
- data/test/hexapdf/layout/test_column_box.rb +14 -0
- data/test/hexapdf/layout/test_frame.rb +181 -95
- data/test/hexapdf/layout/test_list_box.rb +7 -7
- data/test/hexapdf/layout/test_style.rb +14 -10
- data/test/hexapdf/layout/test_table_box.rb +3 -3
- data/test/hexapdf/layout/test_text_box.rb +2 -2
- data/test/hexapdf/layout/test_text_fragment.rb +37 -0
- data/test/hexapdf/layout/test_text_layouter.rb +10 -10
- data/test/hexapdf/test_configuration.rb +49 -0
- data/test/hexapdf/test_dictionary.rb +1 -1
- data/test/hexapdf/test_object.rb +13 -12
- data/test/hexapdf/test_pdf_array.rb +9 -0
- data/test/hexapdf/test_writer.rb +3 -3
- data/test/hexapdf/type/acro_form/test_appearance_generator.rb +41 -13
- data/test/hexapdf/utils/test_sorted_tree_node.rb +1 -1
- metadata +7 -3
|
@@ -114,15 +114,22 @@ describe HexaPDF::Layout::Frame do
|
|
|
114
114
|
when :left then Geom2D::Rectangle(10, 10, 10, 100)
|
|
115
115
|
when :right then Geom2D::Rectangle(100, 10, 10, 100)
|
|
116
116
|
when :top then Geom2D::Rectangle(10, 100, 100, 10)
|
|
117
|
+
when :bottom then Geom2D::Rectangle(10, 10, 100, 10)
|
|
117
118
|
end
|
|
118
119
|
)
|
|
119
120
|
end
|
|
120
121
|
end
|
|
121
122
|
|
|
123
|
+
it "fails if an unkown position value is provided" do
|
|
124
|
+
box = HexaPDF::Layout::Box.create(position: :unknown)
|
|
125
|
+
exception = assert_raises(HexaPDF::Error) { @frame.fit(box) }
|
|
126
|
+
assert_match(/Invalid value 'unknown'/, exception.message)
|
|
127
|
+
end
|
|
128
|
+
|
|
122
129
|
describe "absolute position" do
|
|
123
130
|
it "draws the box at the given absolute position" do
|
|
124
131
|
check_box(
|
|
125
|
-
{width: 50, height: 50, position:
|
|
132
|
+
{width: 50, height: 50, position: [10, 10]},
|
|
126
133
|
[20, 20],
|
|
127
134
|
[20, 20, 70, 70],
|
|
128
135
|
[[[10, 10], [110, 10], [110, 110], [10, 110]],
|
|
@@ -132,22 +139,12 @@ describe HexaPDF::Layout::Frame do
|
|
|
132
139
|
|
|
133
140
|
it "determines the available space for #fit by using the space to the right and above" do
|
|
134
141
|
check_box(
|
|
135
|
-
{position:
|
|
142
|
+
{position: [10, 10]},
|
|
136
143
|
[20, 20],
|
|
137
144
|
[20, 20, 110, 110],
|
|
138
145
|
[[[10, 10], [110, 10], [110, 20], [20, 20], [20, 110], [10, 110]]]
|
|
139
146
|
)
|
|
140
147
|
end
|
|
141
|
-
|
|
142
|
-
it "always removes the whole margin box from the frame" do
|
|
143
|
-
check_box(
|
|
144
|
-
{width: 50, height: 50, position: :absolute, position_hint: [10, 10],
|
|
145
|
-
margin: [10, 20, 30, 40]},
|
|
146
|
-
[20, 20],
|
|
147
|
-
[-20, -10, 90, 80],
|
|
148
|
-
[[[10, 80], [90, 80], [90, 10], [110, 10], [110, 110], [10, 110]]]
|
|
149
|
-
)
|
|
150
|
-
end
|
|
151
148
|
end
|
|
152
149
|
|
|
153
150
|
describe "default position" do
|
|
@@ -159,40 +156,52 @@ describe HexaPDF::Layout::Frame do
|
|
|
159
156
|
end
|
|
160
157
|
|
|
161
158
|
it "draws the box on the right side" do
|
|
162
|
-
check_box({width: 50, height: 50,
|
|
159
|
+
check_box({width: 50, height: 50, align: :right},
|
|
163
160
|
[60, 60],
|
|
164
161
|
[10, 60, 110, 110],
|
|
165
162
|
[[[10, 10], [110, 10], [110, 60], [10, 60]]])
|
|
166
163
|
end
|
|
167
164
|
|
|
168
165
|
it "draws the box in the center" do
|
|
169
|
-
check_box({width: 50, height: 50,
|
|
166
|
+
check_box({width: 50, height: 50, align: :center},
|
|
170
167
|
[35, 60],
|
|
171
168
|
[10, 60, 110, 110],
|
|
172
169
|
[[[10, 10], [110, 10], [110, 60], [10, 60]]])
|
|
173
170
|
end
|
|
174
171
|
|
|
172
|
+
it "draws the box vertically in the center" do
|
|
173
|
+
check_box({width: 50, height: 50, valign: :center},
|
|
174
|
+
[10, 35],
|
|
175
|
+
[10, 35, 110, 110],
|
|
176
|
+
[[[10, 10], [110, 10], [110, 35], [10, 35]]])
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
it "draws the box vertically at the bottom" do
|
|
180
|
+
check_box({width: 50, height: 50, valign: :bottom},
|
|
181
|
+
[10, 10], [10, 10, 110, 110], [])
|
|
182
|
+
end
|
|
183
|
+
|
|
175
184
|
describe "with margin" do
|
|
176
185
|
[:left, :center, :right].each do |hint|
|
|
177
|
-
it "ignores all margins if the box fills the whole frame, with
|
|
178
|
-
check_box({margin: 10,
|
|
186
|
+
it "ignores all margins if the box fills the whole frame, with alignment #{hint}" do
|
|
187
|
+
check_box({margin: 10, align: hint},
|
|
179
188
|
[10, 10], [10, 10, 110, 110], [])
|
|
180
189
|
assert_equal(100, @box.width)
|
|
181
190
|
assert_equal(100, @box.height)
|
|
182
191
|
end
|
|
183
192
|
|
|
184
193
|
it "ignores the left/top/right margin if the available bounds coincide with the " \
|
|
185
|
-
"frame's, with
|
|
186
|
-
check_box({height: 50, margin: 10,
|
|
194
|
+
"frame's, with alignment #{hint}" do
|
|
195
|
+
check_box({height: 50, margin: 10, align: hint},
|
|
187
196
|
[10, 60],
|
|
188
197
|
[10, 50, 110, 110],
|
|
189
198
|
[[[10, 10], [110, 10], [110, 50], [10, 50]]])
|
|
190
199
|
end
|
|
191
200
|
|
|
192
201
|
it "doesn't ignore top margin if the available bounds' top doesn't coincide with the " \
|
|
193
|
-
"frame's top, with
|
|
202
|
+
"frame's top, with alignment #{hint}" do
|
|
194
203
|
remove_area(:top)
|
|
195
|
-
check_box({height: 50, margin: 10,
|
|
204
|
+
check_box({height: 50, margin: 10, align: hint},
|
|
196
205
|
[10, 40],
|
|
197
206
|
[10, 30, 110, 100],
|
|
198
207
|
[[[10, 10], [110, 10], [110, 30], [10, 30]]])
|
|
@@ -200,9 +209,9 @@ describe HexaPDF::Layout::Frame do
|
|
|
200
209
|
end
|
|
201
210
|
|
|
202
211
|
it "doesn't ignore left margin if the available bounds' left doesn't coincide with the " \
|
|
203
|
-
"frame's left, with
|
|
212
|
+
"frame's left, with alignment #{hint}" do
|
|
204
213
|
remove_area(:left)
|
|
205
|
-
check_box({height: 50, margin: 10,
|
|
214
|
+
check_box({height: 50, margin: 10, align: hint},
|
|
206
215
|
[30, 60],
|
|
207
216
|
[10, 50, 110, 110],
|
|
208
217
|
[[[20, 10], [110, 10], [110, 50], [20, 50]]])
|
|
@@ -210,9 +219,9 @@ describe HexaPDF::Layout::Frame do
|
|
|
210
219
|
end
|
|
211
220
|
|
|
212
221
|
it "doesn't ignore right margin if the available bounds' right doesn't coincide with " \
|
|
213
|
-
"the frame's right, with
|
|
222
|
+
"the frame's right, with alignment #{hint}" do
|
|
214
223
|
remove_area(:right)
|
|
215
|
-
check_box({height: 50, margin: 10,
|
|
224
|
+
check_box({height: 50, margin: 10, align: hint},
|
|
216
225
|
[10, 60],
|
|
217
226
|
[10, 50, 110, 110],
|
|
218
227
|
[[[10, 10], [100, 10], [100, 50], [10, 50]]])
|
|
@@ -220,117 +229,194 @@ describe HexaPDF::Layout::Frame do
|
|
|
220
229
|
end
|
|
221
230
|
end
|
|
222
231
|
|
|
223
|
-
|
|
224
|
-
|
|
232
|
+
[:top, :center, :bottom].each do |hint|
|
|
233
|
+
it "ignores all margins if the box fills the whole frame, with vertical alignment #{hint}" do
|
|
234
|
+
check_box({margin: 10, valign: hint},
|
|
235
|
+
[10, 10], [10, 10, 110, 110], [])
|
|
236
|
+
assert_equal(100, @box.width)
|
|
237
|
+
assert_equal(100, @box.height)
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
it "ignores the left/top/bottom margin if the available bounds coincide with the " \
|
|
241
|
+
"frame's, with vertical alignment #{hint}" do
|
|
242
|
+
check_box({width: 50, margin: 10, valign: hint},
|
|
243
|
+
[10, 10], [10, 10, 110, 110], [])
|
|
244
|
+
assert_equal(100, @box.height)
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
it "doesn't ignore top margin if the available bounds' top doesn't coincide with the " \
|
|
248
|
+
"frame's top, with vertical alignment #{hint}" do
|
|
249
|
+
remove_area(:top)
|
|
250
|
+
check_box({width: 50, margin: 10, valign: hint},
|
|
251
|
+
[10, 10], [10, 10, 110, 100], [])
|
|
252
|
+
assert_equal(80, @box.height)
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
it "doesn't ignore left margin if the available bounds' left doesn't coincide with the " \
|
|
256
|
+
"frame's left, with vertical alignment #{hint}" do
|
|
257
|
+
remove_area(:left)
|
|
258
|
+
check_box({width: 50, margin: 10, valign: hint},
|
|
259
|
+
[30, 10], [10, 10, 110, 110], [])
|
|
260
|
+
assert_equal(100, @box.height)
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
it "doesn't ignore bottom margin if the available bounds' bottom doesn't coincide with " \
|
|
264
|
+
"the frame's bottom, with vertical alignment #{hint}" do
|
|
265
|
+
remove_area(:bottom)
|
|
266
|
+
check_box({width: 50, margin: 10, valign: hint},
|
|
267
|
+
[10, 30], [10, 20, 110, 110], [])
|
|
268
|
+
assert_equal(80, @box.height)
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
it "perfectly centers a box horizontally if possible, margins ignored" do
|
|
273
|
+
check_box({width: 50, height: 10, margin: [10, 10, 10, 20], align: :center},
|
|
225
274
|
[35, 100],
|
|
226
275
|
[10, 90, 110, 110],
|
|
227
276
|
[[[10, 10], [110, 10], [110, 90], [10, 90]]])
|
|
228
277
|
end
|
|
229
278
|
|
|
230
|
-
it "perfectly centers a box if possible, margins not ignored" do
|
|
279
|
+
it "perfectly centers a box horizontally if possible, margins not ignored" do
|
|
231
280
|
remove_area(:left, :right)
|
|
232
|
-
check_box({width: 40, height: 10, margin: [10, 10, 10, 20],
|
|
281
|
+
check_box({width: 40, height: 10, margin: [10, 10, 10, 20], align: :center},
|
|
233
282
|
[40, 100],
|
|
234
283
|
[10, 90, 110, 110],
|
|
235
284
|
[[[20, 10], [100, 10], [100, 90], [20, 90]]])
|
|
236
285
|
end
|
|
237
286
|
|
|
238
|
-
it "centers a box as good as possible when margins aren't equal" do
|
|
287
|
+
it "horizontally centers a box as good as possible when margins aren't equal" do
|
|
239
288
|
remove_area(:left, :right)
|
|
240
|
-
check_box({width: 20, height: 10, margin: [10, 10, 10, 40],
|
|
289
|
+
check_box({width: 20, height: 10, margin: [10, 10, 10, 40], align: :center},
|
|
241
290
|
[65, 100],
|
|
242
291
|
[10, 90, 110, 110],
|
|
243
292
|
[[[20, 10], [100, 10], [100, 90], [20, 90]]])
|
|
244
293
|
end
|
|
294
|
+
|
|
295
|
+
it "perfectly centers a box vertically if possible, margins ignored" do
|
|
296
|
+
check_box({width: 10, height: 50, margin: [10, 10, 20, 10], valign: :center},
|
|
297
|
+
[10, 35],
|
|
298
|
+
[10, 15, 110, 110],
|
|
299
|
+
[[[10, 10], [110, 10], [110, 15], [10, 15]]])
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
it "perfectly centers a box vertically if possible, margins not ignored" do
|
|
303
|
+
remove_area(:top, :bottom)
|
|
304
|
+
check_box({width: 10, height: 40, margin: [10, 10, 20, 10], valign: :center},
|
|
305
|
+
[10, 40], [10, 20, 110, 100], [])
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
it "vertically centers a box as good as possible when margins aren't equal" do
|
|
309
|
+
remove_area(:top, :bottom)
|
|
310
|
+
check_box({width: 10, height: 20, margin: [10, 10, 40, 10], valign: :center},
|
|
311
|
+
[10, 65],
|
|
312
|
+
[10, 25, 110, 100],
|
|
313
|
+
[[[10, 20], [110, 20], [110, 25], [10, 25]]])
|
|
314
|
+
end
|
|
245
315
|
end
|
|
246
316
|
end
|
|
247
317
|
|
|
248
|
-
describe "
|
|
249
|
-
it "
|
|
250
|
-
check_box({width:
|
|
251
|
-
[
|
|
252
|
-
[10,
|
|
253
|
-
[[[10, 10], [110, 10], [110,
|
|
318
|
+
describe "flowing boxes" do
|
|
319
|
+
it "flows inside the frame's outline" do
|
|
320
|
+
check_box({width: 10, height: 20, margin: 10, position: :flow},
|
|
321
|
+
[0, 90],
|
|
322
|
+
[10, 80, 110, 110],
|
|
323
|
+
[[[10, 10], [110, 10], [110, 80], [10, 80]]])
|
|
254
324
|
end
|
|
255
325
|
|
|
256
|
-
it "
|
|
257
|
-
check_box({width:
|
|
258
|
-
[
|
|
259
|
-
[
|
|
260
|
-
[[[10, 10], [110, 10], [110,
|
|
326
|
+
it "uses position=default if the box indicates it doesn't support flowing contents" do
|
|
327
|
+
check_box({width: 10, height: 20, margin: 10, position: :flow, doesnt_support_position_flow: true},
|
|
328
|
+
[10, 90],
|
|
329
|
+
[10, 80, 110, 110],
|
|
330
|
+
[[[10, 10], [110, 10], [110, 80], [10, 80]]])
|
|
261
331
|
end
|
|
332
|
+
end
|
|
262
333
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
[
|
|
334
|
+
describe "mask mode" do
|
|
335
|
+
describe "none" do
|
|
336
|
+
it "doesn't remove any area" do
|
|
337
|
+
check_box({width: 50, height: 50, mask_mode: :none},
|
|
338
|
+
[10, 60],
|
|
339
|
+
[10, 60, 10, 60],
|
|
340
|
+
[[[10, 10], [110, 10], [110, 110], [10, 110]]]
|
|
341
|
+
)
|
|
342
|
+
end
|
|
269
343
|
end
|
|
270
344
|
|
|
271
|
-
describe "
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
assert_equal(100, @box.height)
|
|
278
|
-
end
|
|
345
|
+
describe "box" do
|
|
346
|
+
it "removes the box area" do
|
|
347
|
+
check_box({width: 50, height: 50, mask_mode: :box},
|
|
348
|
+
[10, 60],
|
|
349
|
+
[10, 60, 60, 110],
|
|
350
|
+
[[[10, 10], [110, 10], [110, 110], [60, 110], [60, 60], [10, 60]]])
|
|
279
351
|
end
|
|
280
352
|
|
|
281
|
-
it "ignores the
|
|
282
|
-
check_box({
|
|
283
|
-
[10,
|
|
284
|
-
[10, 50, 70, 110],
|
|
285
|
-
[[[10, 10], [110, 10], [110, 110], [70, 110], [70, 50], [10, 50]]])
|
|
353
|
+
it "ignores the margin if sides are on the frame border" do
|
|
354
|
+
check_box({margin: 10, mask_mode: :box},
|
|
355
|
+
[10, 10], [10, 10, 110, 110], [])
|
|
286
356
|
end
|
|
287
357
|
|
|
288
|
-
it "uses the
|
|
289
|
-
remove_area(:left)
|
|
290
|
-
check_box({
|
|
291
|
-
[30,
|
|
292
|
-
[20, 50, 90, 110],
|
|
293
|
-
[[[20, 10], [110, 10], [110, 110], [90, 110], [90, 50], [20, 50]]])
|
|
358
|
+
it "uses the margin if sides are not on the frame border" do
|
|
359
|
+
remove_area(:left, :right, :top, :bottom)
|
|
360
|
+
check_box({margin: 10, mask_mode: :box},
|
|
361
|
+
[30, 30], [20, 20, 100, 100], [])
|
|
294
362
|
end
|
|
363
|
+
end
|
|
295
364
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
[
|
|
301
|
-
|
|
365
|
+
describe "fill_horizontal" do
|
|
366
|
+
it "removes the horizontal part to the bottom of the box in the current region" do
|
|
367
|
+
remove_area(:left, :right)
|
|
368
|
+
check_box({width: 50, height: 50, mask_mode: :fill_horizontal},
|
|
369
|
+
[20, 60],
|
|
370
|
+
[20, 60, 100, 110],
|
|
371
|
+
[[[20, 10], [100, 10], [100, 60], [20, 60]]])
|
|
302
372
|
end
|
|
303
373
|
|
|
304
|
-
it "
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
[
|
|
308
|
-
|
|
374
|
+
it "respects the top and bottom margins for the mask" do
|
|
375
|
+
remove_area(:top, :bottom)
|
|
376
|
+
check_box({width: 50, margin: 10, mask_mode: :fill_horizontal},
|
|
377
|
+
[10, 30], [10, 20, 110, 100], [])
|
|
378
|
+
end
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
describe "fill_frame_horizontal" do
|
|
382
|
+
it "removes the horizontal part to the bottom of the box in the frame" do
|
|
383
|
+
remove_area(:left, :right)
|
|
384
|
+
check_box({width: 50, height: 50, mask_mode: :fill_frame_horizontal},
|
|
385
|
+
[20, 60],
|
|
386
|
+
[10, 60, 110, 110],
|
|
387
|
+
[[[20, 10], [100, 10], [100, 60], [20, 60]]])
|
|
309
388
|
end
|
|
310
389
|
|
|
311
|
-
it "
|
|
312
|
-
remove_area(:right)
|
|
313
|
-
check_box({width: 50,
|
|
314
|
-
[
|
|
315
|
-
[30, 50, 100, 110],
|
|
316
|
-
[[[10, 10], [100, 10], [100, 50], [30, 50], [30, 110], [10, 110]]])
|
|
390
|
+
it "respects the bottom margin for the mask" do
|
|
391
|
+
remove_area(:left, :right, :top, :bottom)
|
|
392
|
+
check_box({width: 50, margin: 10, mask_mode: :fill_frame_horizontal},
|
|
393
|
+
[30, 30], [10, 20, 110, 100], [])
|
|
317
394
|
end
|
|
318
395
|
end
|
|
319
|
-
end
|
|
320
396
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
397
|
+
describe "fill_vertical" do
|
|
398
|
+
it "removes the vertical part covering the box in the current region" do
|
|
399
|
+
check_box({width: 50, height: 50, mask_mode: :fill_vertical, align: :center},
|
|
400
|
+
[35, 60],
|
|
401
|
+
[35, 10, 85, 110],
|
|
402
|
+
[[[10, 10], [35, 10], [35, 110], [10, 110]],
|
|
403
|
+
[[85, 10], [110, 10], [110, 110], [85, 110]]])
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
it "respects the left and right margins for the mask" do
|
|
407
|
+
check_box({width: 50, height: 50, margin: 10, mask_mode: :fill_vertical, align: :center},
|
|
408
|
+
[35, 60],
|
|
409
|
+
[25, 10, 95, 110],
|
|
410
|
+
[[[10, 10], [25, 10], [25, 110], [10, 110]],
|
|
411
|
+
[[95, 10], [110, 10], [110, 110], [95, 110]]])
|
|
412
|
+
end
|
|
327
413
|
end
|
|
328
414
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
415
|
+
describe "fill" do
|
|
416
|
+
it "removes the current region completely" do
|
|
417
|
+
check_box({width: 50, height: 50, mask_mode: :fill},
|
|
418
|
+
[10, 60], [10, 10, 110, 110], [])
|
|
419
|
+
end
|
|
334
420
|
end
|
|
335
421
|
end
|
|
336
422
|
|
|
@@ -38,10 +38,10 @@ describe HexaPDF::Layout::ListBox do
|
|
|
38
38
|
|
|
39
39
|
describe "initialize" do
|
|
40
40
|
it "creates a new instance with the given arguments" do
|
|
41
|
-
box = create_box(children: [:a],
|
|
41
|
+
box = create_box(children: [:a], marker_type: :circle, content_indentation: 15,
|
|
42
42
|
start_number: 4, item_spacing: 20)
|
|
43
43
|
assert_equal([:a], box.children)
|
|
44
|
-
assert_equal(:circle, box.
|
|
44
|
+
assert_equal(:circle, box.marker_type)
|
|
45
45
|
assert_equal(15, box.content_indentation)
|
|
46
46
|
assert_equal(4, box.start_number)
|
|
47
47
|
assert_equal(20, box.item_spacing)
|
|
@@ -109,7 +109,7 @@ describe HexaPDF::Layout::ListBox do
|
|
|
109
109
|
end
|
|
110
110
|
|
|
111
111
|
it "fails for unknown item types" do
|
|
112
|
-
box = create_box(children: @text_boxes[0, 1],
|
|
112
|
+
box = create_box(children: @text_boxes[0, 1], marker_type: :unknown)
|
|
113
113
|
assert_raises(HexaPDF::Error) { box.fit(100, 100, @frame) }
|
|
114
114
|
end
|
|
115
115
|
end
|
|
@@ -179,7 +179,7 @@ describe HexaPDF::Layout::ListBox do
|
|
|
179
179
|
end
|
|
180
180
|
|
|
181
181
|
it "draws a circle as marker" do
|
|
182
|
-
box = create_box(children: @fixed_size_boxes[0, 1],
|
|
182
|
+
box = create_box(children: @fixed_size_boxes[0, 1], marker_type: :circle,
|
|
183
183
|
style: {font_size: 11, fill_color: 0.5})
|
|
184
184
|
box.fit(100, 100, @frame)
|
|
185
185
|
box.draw(@canvas, 0, 100 - box.height)
|
|
@@ -201,7 +201,7 @@ describe HexaPDF::Layout::ListBox do
|
|
|
201
201
|
end
|
|
202
202
|
|
|
203
203
|
it "draws a square as marker" do
|
|
204
|
-
box = create_box(children: @fixed_size_boxes[0, 1],
|
|
204
|
+
box = create_box(children: @fixed_size_boxes[0, 1], marker_type: :square,
|
|
205
205
|
style: {font_size: 11, fill_color: 0.5})
|
|
206
206
|
box.fit(100, 100, @frame)
|
|
207
207
|
box.draw(@canvas, 0, 100 - box.height)
|
|
@@ -223,7 +223,7 @@ describe HexaPDF::Layout::ListBox do
|
|
|
223
223
|
end
|
|
224
224
|
|
|
225
225
|
it "draws decimal numbers as marker" do
|
|
226
|
-
box = create_box(children: @fixed_size_boxes[0, 2],
|
|
226
|
+
box = create_box(children: @fixed_size_boxes[0, 2], marker_type: :decimal,
|
|
227
227
|
style: {font_size: 11, fill_color: 0.5},
|
|
228
228
|
content_indentation: 20)
|
|
229
229
|
box.fit(100, 100, @frame)
|
|
@@ -260,7 +260,7 @@ describe HexaPDF::Layout::ListBox do
|
|
|
260
260
|
marker = lambda do |_doc, _list_box, _index|
|
|
261
261
|
HexaPDF::Layout::Box.create(width: 10, height: 10) {}
|
|
262
262
|
end
|
|
263
|
-
box = create_box(children: @fixed_size_boxes[0, 1],
|
|
263
|
+
box = create_box(children: @fixed_size_boxes[0, 1], marker_type: marker)
|
|
264
264
|
box.fit(100, 100, @frame)
|
|
265
265
|
box.draw(@canvas, 0, 100 - box.height)
|
|
266
266
|
operators = [
|
|
@@ -767,8 +767,8 @@ describe HexaPDF::Layout::Style do
|
|
|
767
767
|
assert_equal(HexaPDF::Content::LineCapStyle::BUTT_CAP, @style.stroke_cap_style)
|
|
768
768
|
assert_equal(HexaPDF::Content::LineJoinStyle::MITER_JOIN, @style.stroke_join_style)
|
|
769
769
|
assert_equal(10.0, @style.stroke_miter_limit)
|
|
770
|
-
assert_equal(:left, @style.
|
|
771
|
-
assert_equal(:top, @style.
|
|
770
|
+
assert_equal(:left, @style.text_align)
|
|
771
|
+
assert_equal(:top, @style.text_valign)
|
|
772
772
|
assert_equal(0, @style.text_indent)
|
|
773
773
|
assert_nil(@style.background_color)
|
|
774
774
|
assert_equal(1, @style.background_alpha)
|
|
@@ -785,6 +785,10 @@ describe HexaPDF::Layout::Style do
|
|
|
785
785
|
refute(@style.fill_horizontal)
|
|
786
786
|
assert_kind_of(HexaPDF::Layout::Style::Layers, @style.underlays)
|
|
787
787
|
assert_kind_of(HexaPDF::Layout::Style::Layers, @style.overlays)
|
|
788
|
+
assert_equal(:default, @style.position)
|
|
789
|
+
assert_equal(:left, @style.align)
|
|
790
|
+
assert_equal(:top, @style.valign)
|
|
791
|
+
assert_equal(:default, @style.mask_mode)
|
|
788
792
|
end
|
|
789
793
|
|
|
790
794
|
it "allows using a non-standard setter for generated properties" do
|
|
@@ -800,18 +804,18 @@ describe HexaPDF::Layout::Style do
|
|
|
800
804
|
end
|
|
801
805
|
|
|
802
806
|
it "allows checking for valid values" do
|
|
803
|
-
error = assert_raises(ArgumentError) { @style.
|
|
804
|
-
assert_match(/not a valid
|
|
807
|
+
error = assert_raises(ArgumentError) { @style.text_align = :none }
|
|
808
|
+
assert_match(/not a valid text_align value \(:left, :center, :right, :justify\)/, error.message)
|
|
805
809
|
end
|
|
806
810
|
|
|
807
811
|
it "allows checking whether a property has been set or accessed" do
|
|
808
|
-
refute(@style.
|
|
809
|
-
assert_equal(:left, @style.
|
|
810
|
-
assert(@style.
|
|
812
|
+
refute(@style.text_align?)
|
|
813
|
+
assert_equal(:left, @style.text_align)
|
|
814
|
+
assert(@style.text_align?)
|
|
811
815
|
|
|
812
|
-
refute(@style.
|
|
813
|
-
@style.
|
|
814
|
-
assert(@style.
|
|
816
|
+
refute(@style.text_valign?)
|
|
817
|
+
@style.text_valign = :bottom
|
|
818
|
+
assert(@style.text_valign?)
|
|
815
819
|
end
|
|
816
820
|
|
|
817
821
|
it "has several dynamically generated properties with default values that take blocks" do
|
|
@@ -83,7 +83,7 @@ describe HexaPDF::Layout::TableBox::Cell do
|
|
|
83
83
|
end
|
|
84
84
|
|
|
85
85
|
it "fits a single box with horizontal aligning not being :left" do
|
|
86
|
-
cell = create_cell(children: HexaPDF::Layout::Box.create(width: 20, height: 10,
|
|
86
|
+
cell = create_cell(children: HexaPDF::Layout::Box.create(width: 20, height: 10, align: :center))
|
|
87
87
|
cell.fit(100, 100, @frame)
|
|
88
88
|
assert_equal(66, cell.preferred_width)
|
|
89
89
|
end
|
|
@@ -100,7 +100,7 @@ describe HexaPDF::Layout::TableBox::Cell do
|
|
|
100
100
|
end
|
|
101
101
|
|
|
102
102
|
it "fits multiple boxes with horizontal aligning not being :left" do
|
|
103
|
-
box1 = HexaPDF::Layout::Box.create(width: 20, height: 10,
|
|
103
|
+
box1 = HexaPDF::Layout::Box.create(width: 20, height: 10, align: :center)
|
|
104
104
|
box2 = HexaPDF::Layout::Box.create(width: 50, height: 15)
|
|
105
105
|
cell = create_cell(children: [box1, box2])
|
|
106
106
|
cell.fit(100, 100, @frame)
|
|
@@ -130,7 +130,7 @@ describe HexaPDF::Layout::TableBox::Cell do
|
|
|
130
130
|
|
|
131
131
|
it "draws the boxes at the correct location" do
|
|
132
132
|
draw_block = lambda {|canvas, _| canvas.move_to(0, 0).end_path }
|
|
133
|
-
box1 = HexaPDF::Layout::Box.create(width: 20, height: 10,
|
|
133
|
+
box1 = HexaPDF::Layout::Box.create(width: 20, height: 10, align: :center, &draw_block)
|
|
134
134
|
box2 = HexaPDF::Layout::Box.create(width: 50, height: 15, &draw_block)
|
|
135
135
|
box = create_cell(children: [box1, box2])
|
|
136
136
|
box.fit(100, 100, @frame)
|
|
@@ -66,7 +66,7 @@ describe HexaPDF::Layout::TextBox do
|
|
|
66
66
|
|
|
67
67
|
it "uses the whole available width when aligning to the center or right" do
|
|
68
68
|
[:center, :right].each do |align|
|
|
69
|
-
box = create_box([@inline_box], style: {
|
|
69
|
+
box = create_box([@inline_box], style: {text_align: align})
|
|
70
70
|
assert(box.fit(100, 100, @frame))
|
|
71
71
|
assert_equal(100, box.width)
|
|
72
72
|
end
|
|
@@ -74,7 +74,7 @@ describe HexaPDF::Layout::TextBox do
|
|
|
74
74
|
|
|
75
75
|
it "uses the whole available height when vertically aligning to the center or bottom" do
|
|
76
76
|
[:center, :bottom].each do |valign|
|
|
77
|
-
box = create_box([@inline_box], style: {
|
|
77
|
+
box = create_box([@inline_box], style: {text_valign: valign})
|
|
78
78
|
assert(box.fit(100, 100, @frame))
|
|
79
79
|
assert_equal(100, box.height)
|
|
80
80
|
end
|
|
@@ -34,6 +34,43 @@ describe HexaPDF::Layout::TextFragment do
|
|
|
34
34
|
end
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
+
describe "create_with_fallback_glyphs" do
|
|
38
|
+
it "creates an array with a single fragment object if no block is given" do
|
|
39
|
+
frags = HexaPDF::Layout::TextFragment.create_with_fallback_glyphs("Tom", font: @font, font_size: 20)
|
|
40
|
+
assert_equal(1, frags.size)
|
|
41
|
+
assert_equal(37.78, frags[0].width)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "allows using a style object instead of directly specifying style properties" do
|
|
45
|
+
style = HexaPDF::Layout::Style.new(font: @font, font_size: 20)
|
|
46
|
+
frags = HexaPDF::Layout::TextFragment.create_with_fallback_glyphs("Tom", style)
|
|
47
|
+
assert_equal(37.78, frags[0].width)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "replaces invalid glyphs with the result of the block" do
|
|
51
|
+
zapf_dingbats = @doc.fonts.add('ZapfDingbats')
|
|
52
|
+
i = 0
|
|
53
|
+
fallback = lambda do |codepoint, invalid_glyph|
|
|
54
|
+
case (i += 1) % 3
|
|
55
|
+
when 0 then []
|
|
56
|
+
when 1 then [zapf_dingbats.decode_codepoint(codepoint)]
|
|
57
|
+
when 2 then @font.decode_utf8("Tom")
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
style = HexaPDF::Layout::Style.new(font: @font, font_size: 20, font_features: {kern: true})
|
|
61
|
+
|
|
62
|
+
frags = HexaPDF::Layout::TextFragment.create_with_fallback_glyphs("✂Tom✂✂Tom✂", style, &fallback)
|
|
63
|
+
assert_equal(5, frags.size)
|
|
64
|
+
assert_equal(zapf_dingbats, frags[0].style.font)
|
|
65
|
+
assert_equal(:a2, frags[0].items[0].name)
|
|
66
|
+
assert_equal(@font, frags[2].style.font)
|
|
67
|
+
|
|
68
|
+
frags = HexaPDF::Layout::TextFragment.create_with_fallback_glyphs("Tom✂Tom", style, &fallback)
|
|
69
|
+
assert_equal(3, frags.size)
|
|
70
|
+
assert_equal(frags[0].width, frags[1].width)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
37
74
|
describe "initialize" do
|
|
38
75
|
before do
|
|
39
76
|
@items = @font.decode_utf8("Tom")
|