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
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
require 'hexapdf/content/canvas_composer'
|
|
5
|
+
require 'hexapdf/document'
|
|
6
|
+
|
|
7
|
+
describe HexaPDF::Content::CanvasComposer do
|
|
8
|
+
before do
|
|
9
|
+
@doc = HexaPDF::Document.new
|
|
10
|
+
@page = @doc.pages.add
|
|
11
|
+
@canvas = @page.canvas
|
|
12
|
+
@composer = @canvas.composer
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
describe "initialize" do
|
|
16
|
+
it "creates the necessary objects like frame for doing the work" do
|
|
17
|
+
assert_equal(@page.box.width, @composer.frame.width)
|
|
18
|
+
assert_equal(@page.box.height, @composer.frame.height)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'allows specifying a value for the margin' do
|
|
22
|
+
composer = @canvas.composer(margin: [10, 30])
|
|
23
|
+
assert_equal(@page.box.width - 60, composer.frame.width)
|
|
24
|
+
assert_equal(@page.box.height - 20, composer.frame.height)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "provides easy access to the global styles" do
|
|
29
|
+
assert_same(@doc.layout.style(:base), @composer.style(:base))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
describe "draw_box" do
|
|
33
|
+
def create_box(**kwargs)
|
|
34
|
+
HexaPDF::Layout::Box.new(**kwargs) {}
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "draws the box if it completely fits" do
|
|
38
|
+
@composer.draw_box(create_box(height: 100))
|
|
39
|
+
@composer.draw_box(create_box)
|
|
40
|
+
assert_operators(@composer.canvas.contents,
|
|
41
|
+
[[:save_graphics_state],
|
|
42
|
+
[:concatenate_matrix, [1, 0, 0, 1, 0, 742]],
|
|
43
|
+
[:restore_graphics_state],
|
|
44
|
+
[:save_graphics_state],
|
|
45
|
+
[:concatenate_matrix, [1, 0, 0, 1, 0, 0]],
|
|
46
|
+
[:restore_graphics_state]])
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "splits the box if possible" do
|
|
50
|
+
@composer.draw_box(create_box(width: 400, style: {position: :float}))
|
|
51
|
+
box = create_box(width: 400, height: 100)
|
|
52
|
+
box.define_singleton_method(:split) do |*|
|
|
53
|
+
[box, HexaPDF::Layout::Box.new(height: 100) {}]
|
|
54
|
+
end
|
|
55
|
+
@composer.draw_box(box)
|
|
56
|
+
assert_operators(@composer.canvas.contents,
|
|
57
|
+
[[:save_graphics_state],
|
|
58
|
+
[:concatenate_matrix, [1, 0, 0, 1, 0, 0]],
|
|
59
|
+
[:restore_graphics_state],
|
|
60
|
+
[:save_graphics_state],
|
|
61
|
+
[:concatenate_matrix, [1, 0, 0, 1, 400, 742]],
|
|
62
|
+
[:restore_graphics_state],
|
|
63
|
+
[:save_graphics_state],
|
|
64
|
+
[:concatenate_matrix, [1, 0, 0, 1, 400, 642]],
|
|
65
|
+
[:restore_graphics_state]])
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it "finds a new region if splitting doesn't work" do
|
|
69
|
+
@composer.draw_box(create_box(width: 400, height: 100, style: {position: :float}))
|
|
70
|
+
@composer.draw_box(create_box(width: 400, height: 100))
|
|
71
|
+
assert_operators(@composer.canvas.contents,
|
|
72
|
+
[[:save_graphics_state],
|
|
73
|
+
[:concatenate_matrix, [1, 0, 0, 1, 0, 742]],
|
|
74
|
+
[:restore_graphics_state],
|
|
75
|
+
[:save_graphics_state],
|
|
76
|
+
[:concatenate_matrix, [1, 0, 0, 1, 0, 642]],
|
|
77
|
+
[:restore_graphics_state]])
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "returns the last drawn box" do
|
|
81
|
+
box = create_box(height: 400)
|
|
82
|
+
assert_same(box, @composer.draw_box(box))
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "raises an error if the frame is full" do
|
|
86
|
+
@composer.draw_box(create_box)
|
|
87
|
+
exception = assert_raises(HexaPDF::Error) { @composer.draw_box(create_box(height: 10)) }
|
|
88
|
+
assert_match(/Frame.*full/, exception.message)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it "raises an error if a new region cannot be found after splitting" do
|
|
92
|
+
@composer.draw_box(create_box(height: 400))
|
|
93
|
+
exception = assert_raises(HexaPDF::Error) { @composer.draw_box(create_box(height: 500)) }
|
|
94
|
+
assert_match(/Frame.*full/, exception.message)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
describe "method_missing" do
|
|
99
|
+
it "delegates box methods to @document.layout" do
|
|
100
|
+
box = @composer.column(width: 100)
|
|
101
|
+
assert_equal(100, box.width)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
it "fails for missing methods that can't be delegated to @document.layout" do
|
|
105
|
+
assert_raises(NameError) { @composer.unknown_box }
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it "can be asked whether a missing method is supported" do
|
|
110
|
+
assert(@composer.respond_to?(:column))
|
|
111
|
+
end
|
|
112
|
+
end
|
|
@@ -110,6 +110,9 @@ end
|
|
|
110
110
|
describe HexaPDF::Document::Layout do
|
|
111
111
|
before do
|
|
112
112
|
@doc = HexaPDF::Document.new
|
|
113
|
+
@doc.config['font.on_invalid_glyph'] = lambda do |codepoint, invalid_glyph|
|
|
114
|
+
[@doc.fonts.add('ZapfDingbats').decode_codepoint(codepoint)]
|
|
115
|
+
end
|
|
113
116
|
@layout = @doc.layout
|
|
114
117
|
end
|
|
115
118
|
|
|
@@ -177,14 +180,37 @@ describe HexaPDF::Document::Layout do
|
|
|
177
180
|
end
|
|
178
181
|
end
|
|
179
182
|
|
|
183
|
+
describe "text_fragments" do
|
|
184
|
+
it "creates an array of text fragments with fallback glyph support" do
|
|
185
|
+
result = @layout.text_fragments("Tomā")
|
|
186
|
+
assert_equal(2, result.size)
|
|
187
|
+
assert_equal(@doc.fonts.add('ZapfDingbats'), result[1].style.font)
|
|
188
|
+
|
|
189
|
+
@doc.config['font.on_invalid_glyph'] = nil
|
|
190
|
+
assert_equal(1, @layout.text_fragments("Tomā").size)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
it "uses the standard rules for creating the style object" do
|
|
194
|
+
@layout.style(:named, font_size: 20)
|
|
195
|
+
result = @layout.text_fragments("Test", style: :named)
|
|
196
|
+
assert_equal(20, result[0].style.font_size)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
it "optionally assigns the properties to all fragments" do
|
|
200
|
+
result = @layout.text_fragments("Tomā", properties: {key: :value})
|
|
201
|
+
assert_equal(:value, result[0].properties[:key])
|
|
202
|
+
assert_equal(:value, result[1].properties[:key])
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
180
206
|
describe "text_box" do
|
|
181
207
|
it "creates a text box" do
|
|
182
|
-
box = @layout.text_box("Test", width: 10, height: 15, properties: {key: :value})
|
|
208
|
+
box = @layout.text_box("Testā", width: 10, height: 15, properties: {key: :value})
|
|
183
209
|
assert_equal(10, box.width)
|
|
184
210
|
assert_equal(15, box.height)
|
|
185
211
|
assert_same(@doc.fonts.add("Times"), box.style.font)
|
|
186
212
|
items = box.instance_variable_get(:@items)
|
|
187
|
-
assert_equal(
|
|
213
|
+
assert_equal(2, items.length)
|
|
188
214
|
assert_same(box.style, items.first.style)
|
|
189
215
|
assert_equal({key: :value}, box.properties)
|
|
190
216
|
end
|
|
@@ -227,20 +253,22 @@ describe HexaPDF::Document::Layout do
|
|
|
227
253
|
|
|
228
254
|
describe "formatted_text" do
|
|
229
255
|
it "creates a text box with the given text" do
|
|
230
|
-
box = @layout.formatted_text_box(["Test"], width: 10, height: 15)
|
|
256
|
+
box = @layout.formatted_text_box(["Testā"], width: 10, height: 15)
|
|
231
257
|
assert_equal(10, box.width)
|
|
232
258
|
assert_equal(15, box.height)
|
|
233
|
-
assert_equal(
|
|
259
|
+
assert_equal(2, box.instance_variable_get(:@items).length)
|
|
234
260
|
end
|
|
235
261
|
|
|
236
262
|
it "allows setting custom properties on the whole box" do
|
|
237
|
-
box = @layout.formatted_text_box(["Test"
|
|
263
|
+
box = @layout.formatted_text_box([{text: "Test", properties: {key: :novalue}}],
|
|
264
|
+
properties: {key: :value})
|
|
238
265
|
assert_equal({key: :value}, box.properties)
|
|
239
266
|
end
|
|
240
267
|
|
|
241
268
|
it "allows using a hash with :text key instead of a simple string" do
|
|
242
|
-
box = @layout.formatted_text_box([{text: "Test"}])
|
|
269
|
+
box = @layout.formatted_text_box([{text: "Testā"}])
|
|
243
270
|
items = box.instance_variable_get(:@items)
|
|
271
|
+
assert_equal(2, items.length)
|
|
244
272
|
assert_equal(4, items[0].items.length)
|
|
245
273
|
end
|
|
246
274
|
|
|
@@ -259,29 +287,29 @@ describe HexaPDF::Document::Layout do
|
|
|
259
287
|
end
|
|
260
288
|
|
|
261
289
|
it "allows using custom style properties for a single part" do
|
|
262
|
-
box = @layout.formatted_text_box([{text: "Test", font_size: 20}, "test"],
|
|
290
|
+
box = @layout.formatted_text_box([{text: "Test", font_size: 20}, "test"], text_align: :center)
|
|
263
291
|
items = box.instance_variable_get(:@items)
|
|
264
292
|
assert_equal(10, box.style.font_size)
|
|
265
293
|
|
|
266
294
|
assert_equal(20, items[0].style.font_size)
|
|
267
|
-
assert_equal(:center, items[0].style.
|
|
295
|
+
assert_equal(:center, items[0].style.text_align)
|
|
268
296
|
|
|
269
297
|
assert_equal(10, items[1].style.font_size)
|
|
270
|
-
assert_equal(:center, items[1].style.
|
|
298
|
+
assert_equal(:center, items[1].style.text_align)
|
|
271
299
|
end
|
|
272
300
|
|
|
273
301
|
it "allows using a custom style as basis for a single part" do
|
|
274
302
|
box = @layout.formatted_text_box([{text: "Test", style: {font_size: 20}, subscript: true},
|
|
275
|
-
"test"],
|
|
303
|
+
"test"], text_align: :center)
|
|
276
304
|
items = box.instance_variable_get(:@items)
|
|
277
305
|
assert_equal(10, box.style.font_size)
|
|
278
306
|
|
|
279
307
|
assert_equal(20, items[0].style.font_size)
|
|
280
|
-
assert_equal(:left, items[0].style.
|
|
308
|
+
assert_equal(:left, items[0].style.text_align)
|
|
281
309
|
assert(items[0].style.subscript)
|
|
282
310
|
|
|
283
311
|
assert_equal(10, items[1].style.font_size)
|
|
284
|
-
assert_equal(:center, items[1].style.
|
|
312
|
+
assert_equal(:center, items[1].style.text_align)
|
|
285
313
|
refute(items[1].style.subscript)
|
|
286
314
|
end
|
|
287
315
|
|
|
@@ -301,6 +301,49 @@ describe HexaPDF::Encryption::StandardSecurityHandler do
|
|
|
301
301
|
assert_equal([:copy_content, :extract_content, :modify_content], @handler.permissions.sort)
|
|
302
302
|
end
|
|
303
303
|
|
|
304
|
+
test_files = Dir[File.join(TEST_DATA_DIR, 'standard-security-handler', '*.pdf')].sort
|
|
305
|
+
user_password = 'uhexapdf'
|
|
306
|
+
owner_password = 'ohexapdf'
|
|
307
|
+
|
|
308
|
+
describe "decryption_password_type" do
|
|
309
|
+
it "doesn't need a password for encrypted files without a password" do
|
|
310
|
+
file = test_files.find {|name| name =~ /nopwd-aes-256bit-V5.pdf/}
|
|
311
|
+
HexaPDF::Document.open(file) do |doc|
|
|
312
|
+
assert_equal(:none, doc.security_handler.decryption_password_type)
|
|
313
|
+
end
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
it "doesn't need a password for owner encrypted files" do
|
|
317
|
+
file = test_files.find {|name| name =~ /ownerpwd-aes-256bit-V5.pdf/}
|
|
318
|
+
HexaPDF::Document.open(file) do |doc|
|
|
319
|
+
assert_equal(:none, doc.security_handler.decryption_password_type)
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
it "needs the user password for user encrypted files" do
|
|
324
|
+
file = test_files.find {|name| name =~ /userpwd-aes-256bit-V5.pdf/}
|
|
325
|
+
HexaPDF::Document.open(file, decryption_opts: {password: user_password}) do |doc|
|
|
326
|
+
assert_equal(:user, doc.security_handler.decryption_password_type)
|
|
327
|
+
end
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
it "can user either the user or owner password for user+owner encrypted files" do
|
|
331
|
+
file = test_files.find {|name| name =~ /bothpwd-aes-256bit-V5.pdf/}
|
|
332
|
+
HexaPDF::Document.open(file, decryption_opts: {password: user_password}) do |doc|
|
|
333
|
+
assert_equal(:user, doc.security_handler.decryption_password_type)
|
|
334
|
+
end
|
|
335
|
+
HexaPDF::Document.open(file, decryption_opts: {password: owner_password}) do |doc|
|
|
336
|
+
assert_equal(:owner, doc.security_handler.decryption_password_type)
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
it "returns :unknown for loaded or created and then encrypted PDF documents" do
|
|
341
|
+
doc = HexaPDF::Document.new
|
|
342
|
+
doc.encrypt
|
|
343
|
+
assert_equal(:unknown, doc.security_handler.decryption_password_type)
|
|
344
|
+
end
|
|
345
|
+
end
|
|
346
|
+
|
|
304
347
|
describe "handling of metadata streams" do
|
|
305
348
|
before do
|
|
306
349
|
@doc = HexaPDF::Document.new
|
|
@@ -8,7 +8,9 @@ describe HexaPDF::Font::InvalidGlyph do
|
|
|
8
8
|
font = Object.new
|
|
9
9
|
font.define_singleton_method(:missing_glyph_id) { 0 }
|
|
10
10
|
font.define_singleton_method(:full_name) { "Test Roman" }
|
|
11
|
-
|
|
11
|
+
font_wrapper = Object.new
|
|
12
|
+
font_wrapper.define_singleton_method(:wrapped_font) { font }
|
|
13
|
+
@glyph = HexaPDF::Font::InvalidGlyph.new(font_wrapper, "str")
|
|
12
14
|
end
|
|
13
15
|
|
|
14
16
|
it "returns the missing glyph id for id/name" do
|
|
@@ -27,6 +29,16 @@ describe HexaPDF::Font::InvalidGlyph do
|
|
|
27
29
|
refute(@glyph.apply_word_spacing?)
|
|
28
30
|
end
|
|
29
31
|
|
|
32
|
+
it "returns false when asked whether it is valid" do
|
|
33
|
+
refute(@glyph.valid?)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "returns true if the glyph represents a control character" do
|
|
37
|
+
refute(@glyph.control_char?)
|
|
38
|
+
assert(HexaPDF::Font::InvalidGlyph.new(nil, "\n"))
|
|
39
|
+
assert(HexaPDF::Font::InvalidGlyph.new(nil, "\u{8203}"))
|
|
40
|
+
end
|
|
41
|
+
|
|
30
42
|
it "can represent itself for debug purposes" do
|
|
31
43
|
assert_equal('#<HexaPDF::Font::InvalidGlyph font="Test Roman" id=0 "str">',
|
|
32
44
|
@glyph.inspect)
|
|
@@ -24,17 +24,29 @@ describe HexaPDF::Font::TrueTypeWrapper do
|
|
|
24
24
|
end
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
+
it "can be asked whether the font is a bold one" do
|
|
28
|
+
refute(@font_wrapper.bold?)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "can be asked whether the font is an italic one" do
|
|
32
|
+
refute(@font_wrapper.italic?)
|
|
33
|
+
end
|
|
34
|
+
|
|
27
35
|
it "can be asked whether font wil be subset" do
|
|
28
36
|
assert(@font_wrapper.subset?)
|
|
29
37
|
refute(HexaPDF::Font::TrueTypeWrapper.new(@doc, @font, subset: false).subset?)
|
|
30
38
|
end
|
|
31
39
|
|
|
32
|
-
describe "
|
|
33
|
-
it "returns an array of glyph objects" do
|
|
40
|
+
describe "decode_*" do
|
|
41
|
+
it "decode_utf8 returns an array of glyph objects" do
|
|
34
42
|
assert_equal("Test",
|
|
35
43
|
@font_wrapper.decode_utf8("Test").map {|g| @cmap.gid_to_code(g.id) }.pack('U*'))
|
|
36
44
|
end
|
|
37
45
|
|
|
46
|
+
it "decode_codepoint returns a single glyph object" do
|
|
47
|
+
assert_equal("A", @font_wrapper.decode_codepoint(65).str)
|
|
48
|
+
end
|
|
49
|
+
|
|
38
50
|
it "invokes font.on_missing_glyph for UTF-8 characters for which no glyph exists" do
|
|
39
51
|
glyphs = @font_wrapper.decode_utf8("š")
|
|
40
52
|
assert_equal(1, glyphs.length)
|
|
@@ -54,6 +66,7 @@ describe HexaPDF::Font::TrueTypeWrapper do
|
|
|
54
66
|
assert_equal(584, glyph.x_max)
|
|
55
67
|
assert_equal(696, glyph.y_max)
|
|
56
68
|
refute(glyph.apply_word_spacing?)
|
|
69
|
+
assert(glyph.valid?)
|
|
57
70
|
assert_equal('#<HexaPDF::Font::TrueTypeWrapper::Glyph font="Ubuntu-Title" id=17 "0">',
|
|
58
71
|
glyph.inspect)
|
|
59
72
|
end
|
|
@@ -21,15 +21,33 @@ describe HexaPDF::Font::Type1Wrapper do
|
|
|
21
21
|
assert_equal("A", wrapper.encode(wrapper.glyph(:B)))
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
+
it "can be asked whether the font is a bold one" do
|
|
25
|
+
refute(@times_wrapper.bold?)
|
|
26
|
+
refute(@symbol_wrapper.bold?)
|
|
27
|
+
assert(@doc.fonts.add("Times", variant: :bold).bold?)
|
|
28
|
+
refute(@doc.fonts.add("Helvetica").bold?)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "can be asked whether the font is an italic one" do
|
|
32
|
+
refute(@times_wrapper.italic?)
|
|
33
|
+
refute(@symbol_wrapper.italic?)
|
|
34
|
+
assert(@doc.fonts.add("Times", variant: :italic).italic?)
|
|
35
|
+
assert(@doc.fonts.add("Helvetica", variant: :bold_italic).italic?)
|
|
36
|
+
end
|
|
37
|
+
|
|
24
38
|
it "returns 1 for the scaling factor" do
|
|
25
39
|
assert_equal(1, @times_wrapper.scaling_factor)
|
|
26
40
|
end
|
|
27
41
|
|
|
28
|
-
describe "
|
|
29
|
-
it "returns an array of glyph objects" do
|
|
42
|
+
describe "decode_*" do
|
|
43
|
+
it "decode_utf8 returns an array of glyph objects" do
|
|
30
44
|
assert_equal([:T, :e, :s, :t], @times_wrapper.decode_utf8("Test").map(&:name))
|
|
31
45
|
end
|
|
32
46
|
|
|
47
|
+
it "decode_codepoint returns a single glyph object" do
|
|
48
|
+
assert_equal(:A, @times_wrapper.decode_codepoint(65).name)
|
|
49
|
+
end
|
|
50
|
+
|
|
33
51
|
it "falls back to the internal font encoding if the Unicode codepoint is not mapped" do
|
|
34
52
|
assert_equal([:Delta, :Delta], @symbol_wrapper.decode_utf8("Dā").map(&:name))
|
|
35
53
|
end
|
|
@@ -53,6 +71,7 @@ describe HexaPDF::Font::Type1Wrapper do
|
|
|
53
71
|
assert_equal(706, glyph.x_max)
|
|
54
72
|
assert_equal(674, glyph.y_max)
|
|
55
73
|
refute(glyph.apply_word_spacing?)
|
|
74
|
+
assert(glyph.valid?)
|
|
56
75
|
assert_equal('#<HexaPDF::Font::Type1Wrapper::Glyph font="Times Roman" id=:A "A">',
|
|
57
76
|
glyph.inspect)
|
|
58
77
|
end
|
|
@@ -69,12 +69,26 @@ describe HexaPDF::Layout::ColumnBox do
|
|
|
69
69
|
it "respects the set initial width, position #{position}" do
|
|
70
70
|
box = create_box(children: @text_boxes[0..1], width: 50, style: {position: position})
|
|
71
71
|
check_box(box, 50, 80)
|
|
72
|
+
|
|
73
|
+
box = create_box(columns: 1, children: @fixed_size_boxes[0..0], width: 50,
|
|
74
|
+
style: {position: position})
|
|
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))
|
|
72
79
|
end
|
|
73
80
|
|
|
74
81
|
it "respects the set initial height, position #{position}" do
|
|
75
82
|
box = create_box(children: @text_boxes[0..1], height: 50, equal_height: false,
|
|
76
83
|
style: {position: position})
|
|
77
84
|
check_box(box, 100, 50)
|
|
85
|
+
|
|
86
|
+
box = create_box(children: @text_boxes[0..1], height: 50, equal_height: true,
|
|
87
|
+
style: {position: position})
|
|
88
|
+
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))
|
|
78
92
|
end
|
|
79
93
|
|
|
80
94
|
it "respects the border and padding around all columns, position #{position}" do
|