hexapdf 0.12.1 → 0.14.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +130 -0
- data/examples/019-acro_form.rb +41 -4
- data/lib/hexapdf/cli/command.rb +4 -2
- data/lib/hexapdf/cli/image2pdf.rb +2 -1
- data/lib/hexapdf/cli/info.rb +51 -2
- data/lib/hexapdf/cli/inspect.rb +30 -8
- data/lib/hexapdf/cli/merge.rb +1 -1
- data/lib/hexapdf/cli/split.rb +74 -14
- data/lib/hexapdf/configuration.rb +15 -0
- data/lib/hexapdf/content/graphic_object/arc.rb +3 -3
- data/lib/hexapdf/content/parser.rb +1 -1
- data/lib/hexapdf/dictionary.rb +9 -6
- data/lib/hexapdf/dictionary_fields.rb +1 -9
- data/lib/hexapdf/document.rb +41 -16
- data/lib/hexapdf/document/files.rb +0 -1
- data/lib/hexapdf/encryption/fast_arc4.rb +1 -1
- data/lib/hexapdf/encryption/security_handler.rb +1 -0
- data/lib/hexapdf/encryption/standard_security_handler.rb +1 -0
- data/lib/hexapdf/font/cmap.rb +1 -4
- data/lib/hexapdf/font/true_type/subsetter.rb +12 -3
- data/lib/hexapdf/font/true_type/table/head.rb +1 -0
- data/lib/hexapdf/font/true_type/table/os2.rb +2 -0
- data/lib/hexapdf/font/true_type/table/post.rb +15 -10
- data/lib/hexapdf/font_loader/from_configuration.rb +2 -2
- data/lib/hexapdf/font_loader/from_file.rb +18 -8
- data/lib/hexapdf/image_loader/png.rb +3 -2
- data/lib/hexapdf/importer.rb +3 -2
- data/lib/hexapdf/layout/line.rb +1 -1
- data/lib/hexapdf/layout/style.rb +23 -23
- data/lib/hexapdf/layout/text_layouter.rb +2 -2
- data/lib/hexapdf/layout/text_shaper.rb +3 -2
- data/lib/hexapdf/object.rb +52 -25
- data/lib/hexapdf/parser.rb +96 -4
- data/lib/hexapdf/pdf_array.rb +12 -5
- data/lib/hexapdf/revisions.rb +29 -21
- data/lib/hexapdf/serializer.rb +34 -8
- data/lib/hexapdf/task/optimize.rb +6 -4
- data/lib/hexapdf/tokenizer.rb +4 -3
- data/lib/hexapdf/type/acro_form/appearance_generator.rb +132 -28
- data/lib/hexapdf/type/acro_form/button_field.rb +21 -13
- data/lib/hexapdf/type/acro_form/choice_field.rb +68 -14
- data/lib/hexapdf/type/acro_form/field.rb +35 -5
- data/lib/hexapdf/type/acro_form/form.rb +139 -14
- data/lib/hexapdf/type/acro_form/text_field.rb +70 -4
- data/lib/hexapdf/type/actions/uri.rb +3 -2
- data/lib/hexapdf/type/annotations/widget.rb +3 -4
- data/lib/hexapdf/type/catalog.rb +2 -2
- data/lib/hexapdf/type/cid_font.rb +1 -1
- data/lib/hexapdf/type/file_specification.rb +1 -1
- data/lib/hexapdf/type/font.rb +1 -1
- data/lib/hexapdf/type/font_simple.rb +4 -2
- data/lib/hexapdf/type/font_true_type.rb +6 -2
- data/lib/hexapdf/type/font_type0.rb +4 -4
- data/lib/hexapdf/type/form.rb +15 -2
- data/lib/hexapdf/type/image.rb +2 -2
- data/lib/hexapdf/type/page.rb +37 -13
- data/lib/hexapdf/type/page_tree_node.rb +29 -5
- data/lib/hexapdf/type/resources.rb +1 -0
- data/lib/hexapdf/type/trailer.rb +2 -3
- data/lib/hexapdf/utils/object_hash.rb +0 -1
- data/lib/hexapdf/utils/sorted_tree_node.rb +18 -15
- data/lib/hexapdf/version.rb +1 -1
- data/test/hexapdf/common_tokenizer_tests.rb +6 -1
- data/test/hexapdf/content/graphic_object/test_arc.rb +4 -4
- data/test/hexapdf/content/test_canvas.rb +3 -3
- data/test/hexapdf/content/test_color_space.rb +1 -1
- data/test/hexapdf/encryption/test_aes.rb +4 -4
- data/test/hexapdf/encryption/test_standard_security_handler.rb +11 -11
- data/test/hexapdf/filter/test_ascii85_decode.rb +1 -1
- data/test/hexapdf/filter/test_ascii_hex_decode.rb +1 -1
- data/test/hexapdf/font/true_type/table/test_post.rb +1 -1
- data/test/hexapdf/font/true_type/test_subsetter.rb +5 -0
- data/test/hexapdf/font_loader/test_from_configuration.rb +7 -3
- data/test/hexapdf/font_loader/test_from_file.rb +7 -0
- data/test/hexapdf/layout/test_style.rb +1 -1
- data/test/hexapdf/layout/test_text_layouter.rb +12 -5
- data/test/hexapdf/test_configuration.rb +2 -2
- data/test/hexapdf/test_dictionary.rb +8 -1
- data/test/hexapdf/test_dictionary_fields.rb +2 -2
- data/test/hexapdf/test_document.rb +18 -10
- data/test/hexapdf/test_object.rb +71 -26
- data/test/hexapdf/test_parser.rb +171 -53
- data/test/hexapdf/test_pdf_array.rb +8 -1
- data/test/hexapdf/test_revisions.rb +35 -0
- data/test/hexapdf/test_writer.rb +2 -2
- data/test/hexapdf/type/acro_form/test_appearance_generator.rb +296 -38
- data/test/hexapdf/type/acro_form/test_button_field.rb +22 -2
- data/test/hexapdf/type/acro_form/test_choice_field.rb +92 -9
- data/test/hexapdf/type/acro_form/test_field.rb +39 -0
- data/test/hexapdf/type/acro_form/test_form.rb +87 -15
- data/test/hexapdf/type/acro_form/test_text_field.rb +77 -1
- data/test/hexapdf/type/test_font_simple.rb +2 -1
- data/test/hexapdf/type/test_font_true_type.rb +6 -0
- data/test/hexapdf/type/test_form.rb +26 -1
- data/test/hexapdf/type/test_page.rb +45 -7
- data/test/hexapdf/type/test_page_tree_node.rb +42 -0
- data/test/hexapdf/utils/test_bit_field.rb +2 -0
- data/test/hexapdf/utils/test_object_hash.rb +5 -0
- data/test/hexapdf/utils/test_sorted_tree_node.rb +10 -9
- data/test/test_helper.rb +2 -0
- metadata +6 -11
@@ -140,7 +140,7 @@ describe HexaPDF::Type::AcroForm::ButtonField do
|
|
140
140
|
it "sets a correct field value" do
|
141
141
|
@field.create_widget(@doc.pages.add, value: :button1)
|
142
142
|
|
143
|
-
@field.field_value =
|
143
|
+
@field.field_value = "button1"
|
144
144
|
assert_equal(:button1, @field[:V])
|
145
145
|
@field.field_value = nil
|
146
146
|
assert_equal(:Off, @field[:V])
|
@@ -158,7 +158,7 @@ describe HexaPDF::Type::AcroForm::ButtonField do
|
|
158
158
|
end
|
159
159
|
|
160
160
|
it "returns an array of possible values" do
|
161
|
-
@field.create_widget(@doc.pages.add, value:
|
161
|
+
@field.create_widget(@doc.pages.add, value: "Test")
|
162
162
|
@field.create_widget(@doc.pages.add, value: :x)
|
163
163
|
@field.create_widget(@doc.pages.add, value: :y)
|
164
164
|
assert_equal([:Test, :x, :y], @field.radio_button_values)
|
@@ -172,6 +172,7 @@ describe HexaPDF::Type::AcroForm::ButtonField do
|
|
172
172
|
assert_equal(:solid, border_style.style)
|
173
173
|
assert_equal([1], widget.background_color.components)
|
174
174
|
assert_equal(:circle, widget.marker_style.style)
|
175
|
+
assert_equal({test: nil, Off: nil}, widget[:AP][:N].value)
|
175
176
|
end
|
176
177
|
|
177
178
|
it "always creates standalone widgets" do
|
@@ -181,6 +182,10 @@ describe HexaPDF::Type::AcroForm::ButtonField do
|
|
181
182
|
it "fails if the value argument is not provided for create_widget" do
|
182
183
|
assert_raises(ArgumentError) { @field.create_widget(@doc.pages.add) }
|
183
184
|
end
|
185
|
+
|
186
|
+
it "fails if the value argument for create_widget doesn't respond to to_sym" do
|
187
|
+
assert_raises(ArgumentError) { @field.create_widget(@doc.pages.add, value: 5) }
|
188
|
+
end
|
184
189
|
end
|
185
190
|
|
186
191
|
it "returns a default field value" do
|
@@ -228,6 +233,14 @@ describe HexaPDF::Type::AcroForm::ButtonField do
|
|
228
233
|
refute_same(off, widget.appearance.normal_appearance[:Off])
|
229
234
|
end
|
230
235
|
|
236
|
+
it "always generates appearances if force is true" do
|
237
|
+
widget = @field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
|
238
|
+
@field.create_appearances
|
239
|
+
yes = widget.appearance.normal_appearance[:Yes]
|
240
|
+
@field.create_appearances(force: true)
|
241
|
+
refute_same(yes, widget.appearance.normal_appearance[:Yes])
|
242
|
+
end
|
243
|
+
|
231
244
|
it "fails for unsupported button types" do
|
232
245
|
@field.flag(:push_button)
|
233
246
|
@field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
|
@@ -258,6 +271,13 @@ describe HexaPDF::Type::AcroForm::ButtonField do
|
|
258
271
|
@field.update_widgets
|
259
272
|
assert_equal(:Yes, widget[:AS])
|
260
273
|
end
|
274
|
+
|
275
|
+
it "creates the appearances if necessary" do
|
276
|
+
widget = @field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
|
277
|
+
assert_nil(widget[:AP][:N][:Yes])
|
278
|
+
@field.update_widgets
|
279
|
+
assert(widget[:AP][:N][:Yes])
|
280
|
+
end
|
261
281
|
end
|
262
282
|
|
263
283
|
describe "validation" do
|
@@ -36,23 +36,34 @@ describe HexaPDF::Type::AcroForm::ChoiceField do
|
|
36
36
|
|
37
37
|
describe "field_value=" do
|
38
38
|
before do
|
39
|
-
@field.option_items = ["test", "other"]
|
39
|
+
@field.option_items = ["test", "something", "other", "neu"]
|
40
|
+
end
|
41
|
+
|
42
|
+
it "updates the widgets to reflect the changed value" do
|
43
|
+
@field.initialize_as_combo_box
|
44
|
+
widget = @field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
|
45
|
+
@field.set_default_appearance_string
|
46
|
+
@field.field_value = 'test'
|
47
|
+
assert(widget[:AP][:N])
|
40
48
|
end
|
41
49
|
|
42
50
|
describe "combo_box" do
|
43
51
|
before do
|
44
52
|
@field.initialize_as_combo_box
|
53
|
+
@field[:I] = 2
|
45
54
|
end
|
46
55
|
|
47
56
|
it "can set the value for an uneditable combo box" do
|
48
57
|
@field.field_value = 'test'
|
49
58
|
assert_equal("test", @field[:V])
|
59
|
+
assert_nil(@field[:I])
|
50
60
|
end
|
51
61
|
|
52
62
|
it "can set the value for an editable combo box" do
|
53
63
|
@field.flag(:edit)
|
54
64
|
@field.field_value = 'another'
|
55
65
|
assert_equal("another", @field[:V])
|
66
|
+
assert_nil(@field[:I])
|
56
67
|
end
|
57
68
|
|
58
69
|
it "fails if mulitple values are provided for a combo box" do
|
@@ -76,8 +87,18 @@ describe HexaPDF::Type::AcroForm::ChoiceField do
|
|
76
87
|
|
77
88
|
it "can set a multiple values if the list box is a multi-select" do
|
78
89
|
@field.flag(:multi_select)
|
79
|
-
@field.field_value = ['
|
80
|
-
assert_equal(['
|
90
|
+
@field.field_value = ['other', 'test']
|
91
|
+
assert_equal(['other', 'test'], @field[:V].value)
|
92
|
+
assert_equal([0, 2], @field[:I].value)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "can read and set the top index" do
|
96
|
+
assert_raises(ArgumentError) { @field.list_box_top_index = 4 }
|
97
|
+
@field.delete(:Opt)
|
98
|
+
assert_raises(ArgumentError) { @field.list_box_top_index = 0 }
|
99
|
+
@field.option_items = [1, 2, 3, 4]
|
100
|
+
@field.list_box_top_index = 2
|
101
|
+
assert_equal(2, @field.list_box_top_index)
|
81
102
|
end
|
82
103
|
|
83
104
|
it "fails if mulitple values are provided but the list box is not a multi-select" do
|
@@ -97,10 +118,29 @@ describe HexaPDF::Type::AcroForm::ChoiceField do
|
|
97
118
|
assert_raises(HexaPDF::Error) { @field.default_field_value = 'unknown' }
|
98
119
|
end
|
99
120
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
121
|
+
describe "option items" do
|
122
|
+
before do
|
123
|
+
@items = [["a", "Zx"], "\xFE\xFF".b << "Töne".encode('UTF-16BE').b, "H\xe4llo".b,]
|
124
|
+
end
|
125
|
+
|
126
|
+
it "sets the option items" do
|
127
|
+
@field.option_items = @items
|
128
|
+
assert_equal(@items, @field[:Opt].value)
|
129
|
+
|
130
|
+
@field.flag(:sort)
|
131
|
+
@field.option_items = @items
|
132
|
+
assert_equal(@items.values_at(2, 1, 0), @field[:Opt].value)
|
133
|
+
end
|
134
|
+
|
135
|
+
it "can retrieve the option items" do
|
136
|
+
@field[:Opt] = @items
|
137
|
+
assert_equal(["Zx", "Töne", "Hällo"], @field.option_items)
|
138
|
+
end
|
139
|
+
|
140
|
+
it "can retrieve the export values" do
|
141
|
+
@field[:Opt] = @items
|
142
|
+
assert_equal(["a", "Töne", "Hällo"], @field.export_values)
|
143
|
+
end
|
104
144
|
end
|
105
145
|
|
106
146
|
it "returns the correct concrete field type" do
|
@@ -121,8 +161,51 @@ describe HexaPDF::Type::AcroForm::ChoiceField do
|
|
121
161
|
assert(@field[:AP][:N])
|
122
162
|
end
|
123
163
|
|
124
|
-
it "
|
125
|
-
|
164
|
+
it "works for list box fields" do
|
165
|
+
@field.initialize_as_list_box
|
166
|
+
@field.set_default_appearance_string
|
167
|
+
@field.create_appearances
|
168
|
+
assert(@field[:AP][:N])
|
169
|
+
end
|
170
|
+
|
171
|
+
it "only creates a new appearance if the involved dictionary values have changed per widget" do
|
172
|
+
@field.initialize_as_list_box
|
173
|
+
@field.set_default_appearance_string
|
174
|
+
@field.create_appearances
|
175
|
+
appearance_stream = @field[:AP][:N].raw_stream
|
176
|
+
|
177
|
+
@field.create_appearances
|
178
|
+
assert_same(appearance_stream, @field[:AP][:N].raw_stream)
|
179
|
+
|
180
|
+
do_check = lambda do
|
181
|
+
@field.create_appearances
|
182
|
+
refute_same(appearance_stream, @field[:AP][:N].raw_stream)
|
183
|
+
appearance_stream = @field[:AP][:N].raw_stream
|
184
|
+
end
|
185
|
+
|
186
|
+
@field.option_items = ['a', 'b', 'c']
|
187
|
+
do_check.call
|
188
|
+
|
189
|
+
@field.list_box_top_index = 2
|
190
|
+
do_check.call
|
191
|
+
|
192
|
+
@field.field_value = 'b'
|
193
|
+
do_check.call
|
194
|
+
|
195
|
+
widget = @field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
|
196
|
+
assert_nil(widget[:AP])
|
197
|
+
@field.create_appearances
|
198
|
+
refute_nil(widget[:AP][:N])
|
199
|
+
end
|
200
|
+
|
201
|
+
it "force the creation of appearance streams when force: true" do
|
202
|
+
@field.initialize_as_list_box
|
203
|
+
@field.set_default_appearance_string
|
204
|
+
@field.create_appearances
|
205
|
+
appearance_stream = @field[:AP][:N].raw_stream
|
206
|
+
|
207
|
+
@field.create_appearances(force: true)
|
208
|
+
refute_same(appearance_stream, @field[:AP][:N].raw_stream)
|
126
209
|
end
|
127
210
|
end
|
128
211
|
|
@@ -99,6 +99,12 @@ describe HexaPDF::Type::AcroForm::Field do
|
|
99
99
|
refute(@field.terminal_field?)
|
100
100
|
end
|
101
101
|
|
102
|
+
it "can check whether a widget is embedded in the field" do
|
103
|
+
refute(@field.embedded_widget?)
|
104
|
+
@field[:Subtype] = :Wdiget
|
105
|
+
assert(@field.embedded_widget?)
|
106
|
+
end
|
107
|
+
|
102
108
|
describe "each_widget" do
|
103
109
|
it "yields a wrapped instance of self if a single widget is embedded" do
|
104
110
|
@field[:Subtype] = :Widget
|
@@ -175,6 +181,39 @@ describe HexaPDF::Type::AcroForm::Field do
|
|
175
181
|
end
|
176
182
|
end
|
177
183
|
|
184
|
+
describe "delete_widget" do
|
185
|
+
before do
|
186
|
+
@page = @doc.pages.add
|
187
|
+
end
|
188
|
+
|
189
|
+
it "does nothing if the provided widget doesn't belong to the field" do
|
190
|
+
wrong_widget = @doc.add({Subtype: :Widget})
|
191
|
+
|
192
|
+
@field.create_widget(@page)
|
193
|
+
@field.delete_widget(wrong_widget)
|
194
|
+
assert_equal(:Widget, @field[:Subtype])
|
195
|
+
|
196
|
+
@field.create_widget(@page)
|
197
|
+
@field.delete_widget(wrong_widget)
|
198
|
+
assert_equal(2, @field[:Kids].size)
|
199
|
+
end
|
200
|
+
|
201
|
+
it "deletes the widget if it is embedded" do
|
202
|
+
widget = @field.create_widget(@page)
|
203
|
+
@field.delete_widget(widget)
|
204
|
+
refute(@field.key?(:Subtype))
|
205
|
+
assert(@page[:Annots].empty?)
|
206
|
+
end
|
207
|
+
|
208
|
+
it "deletes the widget if it is not embedded" do
|
209
|
+
@field.create_widget(@page)
|
210
|
+
widget2 = @field.create_widget(@page)
|
211
|
+
@field.delete_widget(widget2)
|
212
|
+
assert_equal(1, @field[:Kids].size)
|
213
|
+
assert_equal(@field[:Kids].value, @page[:Annots].value)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
178
217
|
describe "perform_validation" do
|
179
218
|
before do
|
180
219
|
@field[:FT] = :Tx
|
@@ -7,7 +7,7 @@ require 'hexapdf/type/acro_form/form'
|
|
7
7
|
describe HexaPDF::Type::AcroForm::Form do
|
8
8
|
before do
|
9
9
|
@doc = HexaPDF::Document.new
|
10
|
-
@acro_form = @doc.add({}, type: :XXAcroForm)
|
10
|
+
@acro_form = @doc.add({Fields: []}, type: :XXAcroForm)
|
11
11
|
end
|
12
12
|
|
13
13
|
describe "signature flags" do
|
@@ -49,7 +49,7 @@ describe HexaPDF::Type::AcroForm::Form do
|
|
49
49
|
root_fields = @acro_form.find_root_fields
|
50
50
|
assert_equal(result, root_fields.map(&:value))
|
51
51
|
assert_kind_of(HexaPDF::Type::AcroForm::TextField, root_fields[0])
|
52
|
-
|
52
|
+
assert_equal([], @acro_form[:Fields].value)
|
53
53
|
|
54
54
|
@acro_form.find_root_fields!
|
55
55
|
assert_equal(result, @acro_form[:Fields].value.map(&:value))
|
@@ -115,6 +115,10 @@ describe HexaPDF::Type::AcroForm::Form do
|
|
115
115
|
end
|
116
116
|
|
117
117
|
describe "create fields" do
|
118
|
+
before do
|
119
|
+
@acro_form = @doc.acro_form(create: true)
|
120
|
+
end
|
121
|
+
|
118
122
|
describe "handles the general case" do
|
119
123
|
it "works for names with a dot" do
|
120
124
|
@acro_form[:Fields] = [{T: "root"}]
|
@@ -134,9 +138,57 @@ describe HexaPDF::Type::AcroForm::Form do
|
|
134
138
|
end
|
135
139
|
end
|
136
140
|
|
141
|
+
def applies_variable_text_properties(method, **args)
|
142
|
+
field = @acro_form.send(method, "field", **args, font: 'Times')
|
143
|
+
font_name, font_size = field.parse_default_appearance_string
|
144
|
+
assert_equal(:'Times-Roman', @acro_form.default_resources.font(font_name)[:BaseFont])
|
145
|
+
assert_equal(0, font_size)
|
146
|
+
|
147
|
+
field = @acro_form.send(method, "field", **args, font_size: 10)
|
148
|
+
font_name, font_size = field.parse_default_appearance_string
|
149
|
+
assert_equal(:Helvetica, @acro_form.default_resources.font(font_name)[:BaseFont])
|
150
|
+
assert_equal(10, font_size)
|
151
|
+
|
152
|
+
field = @acro_form.send(method, "field", **args, font: 'Courier', font_size: 10, align: :center)
|
153
|
+
font_name, font_size = field.parse_default_appearance_string
|
154
|
+
assert_equal(:Courier, @acro_form.default_resources.font(font_name)[:BaseFont])
|
155
|
+
assert_equal(10, font_size)
|
156
|
+
assert_equal(:center, field.text_alignment)
|
157
|
+
end
|
158
|
+
|
137
159
|
it "creates a text field" do
|
138
160
|
field = @acro_form.create_text_field("field")
|
139
161
|
assert_equal(:Tx, field.field_type)
|
162
|
+
applies_variable_text_properties(:create_text_field)
|
163
|
+
end
|
164
|
+
|
165
|
+
it "creates a multiline text field" do
|
166
|
+
field = @acro_form.create_multiline_text_field("field")
|
167
|
+
assert_equal(:Tx, field.field_type)
|
168
|
+
assert(field.multiline_text_field?)
|
169
|
+
applies_variable_text_properties(:create_multiline_text_field)
|
170
|
+
end
|
171
|
+
|
172
|
+
it "creates a comb text field" do
|
173
|
+
field = @acro_form.create_comb_text_field("field", max_chars: 9)
|
174
|
+
assert_equal(:Tx, field.field_type)
|
175
|
+
assert_equal(9, field[:MaxLen])
|
176
|
+
assert(field.comb_text_field?)
|
177
|
+
applies_variable_text_properties(:create_comb_text_field, max_chars: 9)
|
178
|
+
end
|
179
|
+
|
180
|
+
it "creates a password field" do
|
181
|
+
field = @acro_form.create_password_field("field")
|
182
|
+
assert_equal(:Tx, field.field_type)
|
183
|
+
assert(field.password_field?)
|
184
|
+
applies_variable_text_properties(:create_password_field)
|
185
|
+
end
|
186
|
+
|
187
|
+
it "creates a file select field" do
|
188
|
+
field = @acro_form.create_file_select_field("field")
|
189
|
+
assert_equal(:Tx, field.field_type)
|
190
|
+
assert(field.file_select_field?)
|
191
|
+
applies_variable_text_properties(:create_file_select_field)
|
140
192
|
end
|
141
193
|
|
142
194
|
it "creates a check box" do
|
@@ -150,13 +202,19 @@ describe HexaPDF::Type::AcroForm::Form do
|
|
150
202
|
end
|
151
203
|
|
152
204
|
it "creates a combo box" do
|
153
|
-
field = @acro_form.create_combo_box("field")
|
205
|
+
field = @acro_form.create_combo_box("field", option_items: ['a', 'b', 'c'], editable: true)
|
154
206
|
assert(field.combo_box?)
|
207
|
+
assert_equal(['a', 'b', 'c'], field.option_items)
|
208
|
+
assert(field.flagged?(:edit))
|
209
|
+
applies_variable_text_properties(:create_combo_box)
|
155
210
|
end
|
156
211
|
|
157
212
|
it "creates a list box" do
|
158
|
-
field = @acro_form.create_list_box("field")
|
213
|
+
field = @acro_form.create_list_box("field", option_items: ['a', 'b', 'c'], multi_select: true)
|
159
214
|
assert(field.list_box?)
|
215
|
+
assert_equal(['a', 'b', 'c'], field.option_items)
|
216
|
+
assert(field.flagged?(:multi_select))
|
217
|
+
applies_variable_text_properties(:create_list_box)
|
160
218
|
end
|
161
219
|
end
|
162
220
|
|
@@ -185,15 +243,29 @@ describe HexaPDF::Type::AcroForm::Form do
|
|
185
243
|
assert(@acro_form[:NeedAppearances])
|
186
244
|
end
|
187
245
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
246
|
+
describe "create_appearances" do
|
247
|
+
before do
|
248
|
+
@tf = @acro_form.create_text_field('test')
|
249
|
+
@tf.set_default_appearance_string
|
250
|
+
@tf.create_widget(@doc.pages.add)
|
251
|
+
@cb = @acro_form.create_check_box('test2')
|
252
|
+
@cb.create_widget(@doc.pages.add)
|
253
|
+
end
|
254
|
+
|
255
|
+
it "creates the appearances of all field widgets if necessary" do
|
256
|
+
@acro_form.create_appearances
|
257
|
+
assert(@tf.each_widget.all? {|w| w.appearance.normal_appearance.kind_of?(HexaPDF::Stream) })
|
258
|
+
assert(@cb.each_widget.all? {|w| w.appearance.normal_appearance[:Yes].kind_of?(HexaPDF::Stream) })
|
259
|
+
end
|
260
|
+
|
261
|
+
it "force the creation of appearances if force is true" do
|
262
|
+
@acro_form.create_appearances
|
263
|
+
text_stream = @tf[:AP][:N].raw_stream
|
264
|
+
@acro_form.create_appearances
|
265
|
+
assert_same(text_stream, @tf[:AP][:N].raw_stream)
|
266
|
+
@acro_form.create_appearances(force: true)
|
267
|
+
refute_same(text_stream, @tf[:AP][:N].raw_stream)
|
268
|
+
end
|
197
269
|
end
|
198
270
|
|
199
271
|
describe "perform_validation" do
|
@@ -204,9 +276,9 @@ describe HexaPDF::Type::AcroForm::Form do
|
|
204
276
|
|
205
277
|
it "checks whether the font used in /DA is available in /DR" do
|
206
278
|
@acro_form[:DA] = '/F2 0 Tf /F1 0 Tf'
|
207
|
-
refute(@acro_form.validate {|msg
|
279
|
+
refute(@acro_form.validate {|msg| assert_match(/DR must also be present/, msg) })
|
208
280
|
@acro_form.default_resources[:Font] = {}
|
209
|
-
refute(@acro_form.validate {|msg
|
281
|
+
refute(@acro_form.validate {|msg| assert_match(/font.*is not.*resource/, msg) })
|
210
282
|
@acro_form.default_resources[:Font][:F1] = :yes
|
211
283
|
assert(@acro_form.validate)
|
212
284
|
end
|
@@ -21,6 +21,56 @@ describe HexaPDF::Type::AcroForm::TextField do
|
|
21
21
|
assert_equal(6, @field[:MaxLen])
|
22
22
|
end
|
23
23
|
|
24
|
+
it "can be initialized as a multiline text field" do
|
25
|
+
@field.flag(:comb)
|
26
|
+
@field.initialize_as_multiline_text_field
|
27
|
+
assert(@field.multiline_text_field?)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "can be initialized as comb text field" do
|
31
|
+
@field.flag(:multiline)
|
32
|
+
@field.initialize_as_comb_text_field
|
33
|
+
assert(@field.comb_text_field?)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "can be initialized as password field" do
|
37
|
+
@field.flag(:multiline)
|
38
|
+
@field[:V] = 'test'
|
39
|
+
@field.initialize_as_password_field
|
40
|
+
assert_nil(@field[:V])
|
41
|
+
assert(@field.password_field?)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "can be initialized as a file select field" do
|
45
|
+
@field.flag(:multiline)
|
46
|
+
@field.initialize_as_file_select_field
|
47
|
+
assert(@field.file_select_field?)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "can check whether the field is a multiline text field" do
|
51
|
+
refute(@field.multiline_text_field?)
|
52
|
+
@field.flag(:multiline)
|
53
|
+
assert(@field.multiline_text_field?)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "can check whether the field is a comb text field" do
|
57
|
+
refute(@field.comb_text_field?)
|
58
|
+
@field.flag(:comb)
|
59
|
+
assert(@field.comb_text_field?)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "can check whether the field is a password field" do
|
63
|
+
refute(@field.password_field?)
|
64
|
+
@field.flag(:password)
|
65
|
+
assert(@field.password_field?)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "can check whether the field is a file select field" do
|
69
|
+
refute(@field.file_select_field?)
|
70
|
+
@field.flag(:file_select)
|
71
|
+
assert(@field.file_select_field?)
|
72
|
+
end
|
73
|
+
|
24
74
|
describe "field_value" do
|
25
75
|
it "handles unset values" do
|
26
76
|
assert_nil(@field.field_value)
|
@@ -81,14 +131,38 @@ describe HexaPDF::Type::AcroForm::TextField do
|
|
81
131
|
end
|
82
132
|
|
83
133
|
describe "create_appearances" do
|
84
|
-
|
134
|
+
before do
|
85
135
|
@doc.acro_form(create: true)
|
86
136
|
@field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
|
87
137
|
@field.set_default_appearance_string
|
138
|
+
end
|
139
|
+
|
140
|
+
it "creates the needed streams" do
|
88
141
|
@field.create_appearances
|
89
142
|
assert(@field[:AP][:N])
|
90
143
|
end
|
91
144
|
|
145
|
+
it "doesn't create a new appearance stream if the field value hasn't changed, checked per widget" do
|
146
|
+
@field.create_appearances
|
147
|
+
stream = @field[:AP][:N].raw_stream
|
148
|
+
@field.create_appearances
|
149
|
+
assert_same(stream, @field[:AP][:N].raw_stream)
|
150
|
+
@field.field_value = 'test'
|
151
|
+
refute_same(stream, @field[:AP][:N].raw_stream)
|
152
|
+
|
153
|
+
widget = @field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
|
154
|
+
assert_nil(widget[:AP])
|
155
|
+
@field.create_appearances
|
156
|
+
refute_nil(widget[:AP][:N])
|
157
|
+
end
|
158
|
+
|
159
|
+
it "always creates a new appearance stream if force is true" do
|
160
|
+
@field.create_appearances
|
161
|
+
stream = @field[:AP][:N].raw_stream
|
162
|
+
@field.create_appearances(force: true)
|
163
|
+
refute_same(stream, @field[:AP][:N].raw_stream)
|
164
|
+
end
|
165
|
+
|
92
166
|
it "uses the configuration option acro_form.appearance_generator" do
|
93
167
|
@doc.config['acro_form.appearance_generator'] = 'NonExistent'
|
94
168
|
assert_raises(Exception) { @field.create_appearances }
|
@@ -114,6 +188,8 @@ describe HexaPDF::Type::AcroForm::TextField do
|
|
114
188
|
assert(@field.validate)
|
115
189
|
@field[:MaxLen] = 2
|
116
190
|
refute(@field.validate)
|
191
|
+
@field[:V] = nil
|
192
|
+
assert(@field.validate)
|
117
193
|
end
|
118
194
|
end
|
119
195
|
end
|