hexapdf 0.17.1 → 0.17.2

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.
Files changed (255) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1024 -0
  3. data/LICENSE +29 -0
  4. data/README.md +129 -0
  5. data/Rakefile +109 -0
  6. data/agpl-3.0.txt +661 -0
  7. data/examples/001-hello_world.rb +16 -0
  8. data/examples/002-graphics.rb +275 -0
  9. data/examples/003-arcs.rb +50 -0
  10. data/examples/004-optimizing.rb +23 -0
  11. data/examples/005-merging.rb +27 -0
  12. data/examples/006-standard_pdf_fonts.rb +73 -0
  13. data/examples/007-truetype.rb +42 -0
  14. data/examples/008-show_char_bboxes.rb +55 -0
  15. data/examples/009-text_layouter_alignment.rb +47 -0
  16. data/examples/010-text_layouter_inline_boxes.rb +64 -0
  17. data/examples/011-text_layouter_line_wrapping.rb +57 -0
  18. data/examples/012-text_layouter_styling.rb +122 -0
  19. data/examples/013-text_layouter_shapes.rb +176 -0
  20. data/examples/014-text_in_polygon.rb +60 -0
  21. data/examples/015-boxes.rb +76 -0
  22. data/examples/016-frame_automatic_box_placement.rb +90 -0
  23. data/examples/017-frame_text_flow.rb +60 -0
  24. data/examples/018-composer.rb +44 -0
  25. data/examples/019-acro_form.rb +88 -0
  26. data/examples/emoji-smile.png +0 -0
  27. data/examples/emoji-wink.png +0 -0
  28. data/examples/machupicchu.jpg +0 -0
  29. data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +66 -0
  30. data/lib/hexapdf/content/graphic_object/geom2d.rb +13 -0
  31. data/lib/hexapdf/version.rb +1 -1
  32. data/test/data/aes-test-vectors/CBCGFSbox-128-decrypt.data.gz +0 -0
  33. data/test/data/aes-test-vectors/CBCGFSbox-128-encrypt.data.gz +0 -0
  34. data/test/data/aes-test-vectors/CBCGFSbox-192-decrypt.data.gz +0 -0
  35. data/test/data/aes-test-vectors/CBCGFSbox-192-encrypt.data.gz +0 -0
  36. data/test/data/aes-test-vectors/CBCGFSbox-256-decrypt.data.gz +0 -0
  37. data/test/data/aes-test-vectors/CBCGFSbox-256-encrypt.data.gz +0 -0
  38. data/test/data/aes-test-vectors/CBCKeySbox-128-decrypt.data.gz +0 -0
  39. data/test/data/aes-test-vectors/CBCKeySbox-128-encrypt.data.gz +0 -0
  40. data/test/data/aes-test-vectors/CBCKeySbox-192-decrypt.data.gz +0 -0
  41. data/test/data/aes-test-vectors/CBCKeySbox-192-encrypt.data.gz +0 -0
  42. data/test/data/aes-test-vectors/CBCKeySbox-256-decrypt.data.gz +0 -0
  43. data/test/data/aes-test-vectors/CBCKeySbox-256-encrypt.data.gz +0 -0
  44. data/test/data/aes-test-vectors/CBCVarKey-128-decrypt.data.gz +0 -0
  45. data/test/data/aes-test-vectors/CBCVarKey-128-encrypt.data.gz +0 -0
  46. data/test/data/aes-test-vectors/CBCVarKey-192-decrypt.data.gz +0 -0
  47. data/test/data/aes-test-vectors/CBCVarKey-192-encrypt.data.gz +0 -0
  48. data/test/data/aes-test-vectors/CBCVarKey-256-decrypt.data.gz +0 -0
  49. data/test/data/aes-test-vectors/CBCVarKey-256-encrypt.data.gz +0 -0
  50. data/test/data/aes-test-vectors/CBCVarTxt-128-decrypt.data.gz +0 -0
  51. data/test/data/aes-test-vectors/CBCVarTxt-128-encrypt.data.gz +0 -0
  52. data/test/data/aes-test-vectors/CBCVarTxt-192-decrypt.data.gz +0 -0
  53. data/test/data/aes-test-vectors/CBCVarTxt-192-encrypt.data.gz +0 -0
  54. data/test/data/aes-test-vectors/CBCVarTxt-256-decrypt.data.gz +0 -0
  55. data/test/data/aes-test-vectors/CBCVarTxt-256-encrypt.data.gz +0 -0
  56. data/test/data/fonts/Ubuntu-Title.ttf +0 -0
  57. data/test/data/images/cmyk.jpg +0 -0
  58. data/test/data/images/fillbytes.jpg +0 -0
  59. data/test/data/images/gray.jpg +0 -0
  60. data/test/data/images/greyscale-1bit.png +0 -0
  61. data/test/data/images/greyscale-2bit.png +0 -0
  62. data/test/data/images/greyscale-4bit.png +0 -0
  63. data/test/data/images/greyscale-8bit.png +0 -0
  64. data/test/data/images/greyscale-alpha-8bit.png +0 -0
  65. data/test/data/images/greyscale-trns-8bit.png +0 -0
  66. data/test/data/images/greyscale-with-gamma1.0.png +0 -0
  67. data/test/data/images/greyscale-with-gamma1.5.png +0 -0
  68. data/test/data/images/indexed-1bit.png +0 -0
  69. data/test/data/images/indexed-2bit.png +0 -0
  70. data/test/data/images/indexed-4bit.png +0 -0
  71. data/test/data/images/indexed-8bit.png +0 -0
  72. data/test/data/images/indexed-alpha-4bit.png +0 -0
  73. data/test/data/images/indexed-alpha-8bit.png +0 -0
  74. data/test/data/images/rgb.jpg +0 -0
  75. data/test/data/images/truecolour-8bit.png +0 -0
  76. data/test/data/images/truecolour-alpha-8bit.png +0 -0
  77. data/test/data/images/truecolour-gama-chrm-8bit.png +0 -0
  78. data/test/data/images/truecolour-srgb-8bit.png +0 -0
  79. data/test/data/images/ycck.jpg +0 -0
  80. data/test/data/minimal.pdf +44 -0
  81. data/test/data/standard-security-handler/README +9 -0
  82. data/test/data/standard-security-handler/bothpwd-aes-128bit-V4.pdf +44 -0
  83. data/test/data/standard-security-handler/bothpwd-aes-256bit-V5.pdf +0 -0
  84. data/test/data/standard-security-handler/bothpwd-arc4-128bit-V2.pdf +43 -0
  85. data/test/data/standard-security-handler/bothpwd-arc4-128bit-V4.pdf +43 -0
  86. data/test/data/standard-security-handler/bothpwd-arc4-40bit-V1.pdf +0 -0
  87. data/test/data/standard-security-handler/nopwd-aes-128bit-V4.pdf +43 -0
  88. data/test/data/standard-security-handler/nopwd-aes-256bit-V5.pdf +0 -0
  89. data/test/data/standard-security-handler/nopwd-arc4-128bit-V2.pdf +43 -0
  90. data/test/data/standard-security-handler/nopwd-arc4-128bit-V4.pdf +43 -0
  91. data/test/data/standard-security-handler/nopwd-arc4-40bit-V1.pdf +43 -0
  92. data/test/data/standard-security-handler/ownerpwd-aes-128bit-V4.pdf +0 -0
  93. data/test/data/standard-security-handler/ownerpwd-aes-256bit-V5.pdf +43 -0
  94. data/test/data/standard-security-handler/ownerpwd-arc4-128bit-V2.pdf +43 -0
  95. data/test/data/standard-security-handler/ownerpwd-arc4-128bit-V4.pdf +43 -0
  96. data/test/data/standard-security-handler/ownerpwd-arc4-40bit-V1.pdf +43 -0
  97. data/test/data/standard-security-handler/userpwd-aes-128bit-V4.pdf +43 -0
  98. data/test/data/standard-security-handler/userpwd-aes-256bit-V5.pdf +43 -0
  99. data/test/data/standard-security-handler/userpwd-arc4-128bit-V2.pdf +0 -0
  100. data/test/data/standard-security-handler/userpwd-arc4-128bit-V4.pdf +0 -0
  101. data/test/data/standard-security-handler/userpwd-arc4-40bit-V1.pdf +43 -0
  102. data/test/hexapdf/common_tokenizer_tests.rb +236 -0
  103. data/test/hexapdf/content/common.rb +39 -0
  104. data/test/hexapdf/content/graphic_object/test_arc.rb +102 -0
  105. data/test/hexapdf/content/graphic_object/test_endpoint_arc.rb +90 -0
  106. data/test/hexapdf/content/graphic_object/test_geom2d.rb +79 -0
  107. data/test/hexapdf/content/graphic_object/test_solid_arc.rb +86 -0
  108. data/test/hexapdf/content/test_canvas.rb +1279 -0
  109. data/test/hexapdf/content/test_color_space.rb +176 -0
  110. data/test/hexapdf/content/test_graphics_state.rb +151 -0
  111. data/test/hexapdf/content/test_operator.rb +619 -0
  112. data/test/hexapdf/content/test_parser.rb +99 -0
  113. data/test/hexapdf/content/test_processor.rb +163 -0
  114. data/test/hexapdf/content/test_transformation_matrix.rb +64 -0
  115. data/test/hexapdf/document/test_files.rb +72 -0
  116. data/test/hexapdf/document/test_fonts.rb +60 -0
  117. data/test/hexapdf/document/test_images.rb +72 -0
  118. data/test/hexapdf/document/test_pages.rb +130 -0
  119. data/test/hexapdf/encryption/common.rb +87 -0
  120. data/test/hexapdf/encryption/test_aes.rb +129 -0
  121. data/test/hexapdf/encryption/test_arc4.rb +39 -0
  122. data/test/hexapdf/encryption/test_fast_aes.rb +17 -0
  123. data/test/hexapdf/encryption/test_fast_arc4.rb +12 -0
  124. data/test/hexapdf/encryption/test_identity.rb +21 -0
  125. data/test/hexapdf/encryption/test_ruby_aes.rb +23 -0
  126. data/test/hexapdf/encryption/test_ruby_arc4.rb +20 -0
  127. data/test/hexapdf/encryption/test_security_handler.rb +380 -0
  128. data/test/hexapdf/encryption/test_standard_security_handler.rb +322 -0
  129. data/test/hexapdf/filter/common.rb +53 -0
  130. data/test/hexapdf/filter/test_ascii85_decode.rb +59 -0
  131. data/test/hexapdf/filter/test_ascii_hex_decode.rb +38 -0
  132. data/test/hexapdf/filter/test_crypt.rb +21 -0
  133. data/test/hexapdf/filter/test_encryption.rb +24 -0
  134. data/test/hexapdf/filter/test_flate_decode.rb +44 -0
  135. data/test/hexapdf/filter/test_lzw_decode.rb +52 -0
  136. data/test/hexapdf/filter/test_predictor.rb +219 -0
  137. data/test/hexapdf/filter/test_run_length_decode.rb +32 -0
  138. data/test/hexapdf/font/cmap/test_parser.rb +102 -0
  139. data/test/hexapdf/font/cmap/test_writer.rb +66 -0
  140. data/test/hexapdf/font/encoding/test_base.rb +45 -0
  141. data/test/hexapdf/font/encoding/test_difference_encoding.rb +29 -0
  142. data/test/hexapdf/font/encoding/test_glyph_list.rb +59 -0
  143. data/test/hexapdf/font/encoding/test_zapf_dingbats_encoding.rb +16 -0
  144. data/test/hexapdf/font/test_cmap.rb +104 -0
  145. data/test/hexapdf/font/test_encoding.rb +27 -0
  146. data/test/hexapdf/font/test_invalid_glyph.rb +34 -0
  147. data/test/hexapdf/font/test_true_type_wrapper.rb +186 -0
  148. data/test/hexapdf/font/test_type1_wrapper.rb +107 -0
  149. data/test/hexapdf/font/true_type/common.rb +17 -0
  150. data/test/hexapdf/font/true_type/table/common.rb +27 -0
  151. data/test/hexapdf/font/true_type/table/test_cmap.rb +47 -0
  152. data/test/hexapdf/font/true_type/table/test_cmap_subtable.rb +141 -0
  153. data/test/hexapdf/font/true_type/table/test_directory.rb +30 -0
  154. data/test/hexapdf/font/true_type/table/test_glyf.rb +58 -0
  155. data/test/hexapdf/font/true_type/table/test_head.rb +56 -0
  156. data/test/hexapdf/font/true_type/table/test_hhea.rb +26 -0
  157. data/test/hexapdf/font/true_type/table/test_hmtx.rb +30 -0
  158. data/test/hexapdf/font/true_type/table/test_kern.rb +61 -0
  159. data/test/hexapdf/font/true_type/table/test_loca.rb +33 -0
  160. data/test/hexapdf/font/true_type/table/test_maxp.rb +50 -0
  161. data/test/hexapdf/font/true_type/table/test_name.rb +76 -0
  162. data/test/hexapdf/font/true_type/table/test_os2.rb +55 -0
  163. data/test/hexapdf/font/true_type/table/test_post.rb +78 -0
  164. data/test/hexapdf/font/true_type/test_builder.rb +42 -0
  165. data/test/hexapdf/font/true_type/test_font.rb +116 -0
  166. data/test/hexapdf/font/true_type/test_optimizer.rb +26 -0
  167. data/test/hexapdf/font/true_type/test_subsetter.rb +73 -0
  168. data/test/hexapdf/font/true_type/test_table.rb +48 -0
  169. data/test/hexapdf/font/type1/common.rb +6 -0
  170. data/test/hexapdf/font/type1/test_afm_parser.rb +65 -0
  171. data/test/hexapdf/font/type1/test_font.rb +104 -0
  172. data/test/hexapdf/font/type1/test_font_metrics.rb +22 -0
  173. data/test/hexapdf/font/type1/test_pfb_parser.rb +37 -0
  174. data/test/hexapdf/font_loader/test_from_configuration.rb +43 -0
  175. data/test/hexapdf/font_loader/test_from_file.rb +36 -0
  176. data/test/hexapdf/font_loader/test_standard14.rb +33 -0
  177. data/test/hexapdf/image_loader/test_jpeg.rb +93 -0
  178. data/test/hexapdf/image_loader/test_pdf.rb +47 -0
  179. data/test/hexapdf/image_loader/test_png.rb +259 -0
  180. data/test/hexapdf/layout/test_box.rb +154 -0
  181. data/test/hexapdf/layout/test_frame.rb +350 -0
  182. data/test/hexapdf/layout/test_image_box.rb +73 -0
  183. data/test/hexapdf/layout/test_inline_box.rb +71 -0
  184. data/test/hexapdf/layout/test_line.rb +206 -0
  185. data/test/hexapdf/layout/test_style.rb +790 -0
  186. data/test/hexapdf/layout/test_text_box.rb +140 -0
  187. data/test/hexapdf/layout/test_text_fragment.rb +375 -0
  188. data/test/hexapdf/layout/test_text_layouter.rb +758 -0
  189. data/test/hexapdf/layout/test_text_shaper.rb +62 -0
  190. data/test/hexapdf/layout/test_width_from_polygon.rb +109 -0
  191. data/test/hexapdf/task/test_dereference.rb +51 -0
  192. data/test/hexapdf/task/test_optimize.rb +162 -0
  193. data/test/hexapdf/test_composer.rb +258 -0
  194. data/test/hexapdf/test_configuration.rb +93 -0
  195. data/test/hexapdf/test_data_dir.rb +32 -0
  196. data/test/hexapdf/test_dictionary.rb +340 -0
  197. data/test/hexapdf/test_dictionary_fields.rb +269 -0
  198. data/test/hexapdf/test_document.rb +641 -0
  199. data/test/hexapdf/test_filter.rb +100 -0
  200. data/test/hexapdf/test_importer.rb +106 -0
  201. data/test/hexapdf/test_object.rb +258 -0
  202. data/test/hexapdf/test_parser.rb +645 -0
  203. data/test/hexapdf/test_pdf_array.rb +169 -0
  204. data/test/hexapdf/test_rectangle.rb +73 -0
  205. data/test/hexapdf/test_reference.rb +50 -0
  206. data/test/hexapdf/test_revision.rb +188 -0
  207. data/test/hexapdf/test_revisions.rb +196 -0
  208. data/test/hexapdf/test_serializer.rb +195 -0
  209. data/test/hexapdf/test_stream.rb +274 -0
  210. data/test/hexapdf/test_tokenizer.rb +80 -0
  211. data/test/hexapdf/test_type.rb +18 -0
  212. data/test/hexapdf/test_writer.rb +140 -0
  213. data/test/hexapdf/test_xref_section.rb +61 -0
  214. data/test/hexapdf/type/acro_form/test_appearance_generator.rb +795 -0
  215. data/test/hexapdf/type/acro_form/test_button_field.rb +308 -0
  216. data/test/hexapdf/type/acro_form/test_choice_field.rb +220 -0
  217. data/test/hexapdf/type/acro_form/test_field.rb +259 -0
  218. data/test/hexapdf/type/acro_form/test_form.rb +357 -0
  219. data/test/hexapdf/type/acro_form/test_signature_field.rb +38 -0
  220. data/test/hexapdf/type/acro_form/test_text_field.rb +201 -0
  221. data/test/hexapdf/type/acro_form/test_variable_text_field.rb +88 -0
  222. data/test/hexapdf/type/actions/test_launch.rb +24 -0
  223. data/test/hexapdf/type/actions/test_uri.rb +23 -0
  224. data/test/hexapdf/type/annotations/test_markup_annotation.rb +22 -0
  225. data/test/hexapdf/type/annotations/test_text.rb +34 -0
  226. data/test/hexapdf/type/annotations/test_widget.rb +225 -0
  227. data/test/hexapdf/type/test_annotation.rb +97 -0
  228. data/test/hexapdf/type/test_catalog.rb +48 -0
  229. data/test/hexapdf/type/test_cid_font.rb +61 -0
  230. data/test/hexapdf/type/test_file_specification.rb +141 -0
  231. data/test/hexapdf/type/test_font.rb +67 -0
  232. data/test/hexapdf/type/test_font_descriptor.rb +61 -0
  233. data/test/hexapdf/type/test_font_simple.rb +176 -0
  234. data/test/hexapdf/type/test_font_true_type.rb +31 -0
  235. data/test/hexapdf/type/test_font_type0.rb +120 -0
  236. data/test/hexapdf/type/test_font_type1.rb +142 -0
  237. data/test/hexapdf/type/test_font_type3.rb +26 -0
  238. data/test/hexapdf/type/test_form.rb +120 -0
  239. data/test/hexapdf/type/test_image.rb +261 -0
  240. data/test/hexapdf/type/test_info.rb +9 -0
  241. data/test/hexapdf/type/test_object_stream.rb +117 -0
  242. data/test/hexapdf/type/test_page.rb +598 -0
  243. data/test/hexapdf/type/test_page_tree_node.rb +315 -0
  244. data/test/hexapdf/type/test_resources.rb +209 -0
  245. data/test/hexapdf/type/test_trailer.rb +116 -0
  246. data/test/hexapdf/type/test_xref_stream.rb +143 -0
  247. data/test/hexapdf/utils/test_bit_field.rb +63 -0
  248. data/test/hexapdf/utils/test_bit_stream.rb +69 -0
  249. data/test/hexapdf/utils/test_graphics_helpers.rb +37 -0
  250. data/test/hexapdf/utils/test_lru_cache.rb +22 -0
  251. data/test/hexapdf/utils/test_object_hash.rb +120 -0
  252. data/test/hexapdf/utils/test_pdf_doc_encoding.rb +18 -0
  253. data/test/hexapdf/utils/test_sorted_tree_node.rb +239 -0
  254. data/test/test_helper.rb +58 -0
  255. metadata +263 -3
@@ -0,0 +1,201 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require_relative '../../content/common'
5
+ require 'hexapdf/document'
6
+ require 'hexapdf/type/acro_form/text_field'
7
+
8
+ describe HexaPDF::Type::AcroForm::TextField do
9
+ before do
10
+ @doc = HexaPDF::Document.new
11
+ @field = @doc.add({FT: :Tx}, type: :XXAcroFormField, subtype: :Tx)
12
+ end
13
+
14
+ it "resolves /MaxLen as inheritable field" do
15
+ assert_nil(@field[:MaxLen])
16
+
17
+ @field[:Parent] = {MaxLen: 5}
18
+ assert_equal(5, @field[:MaxLen])
19
+
20
+ @field[:MaxLen] = 6
21
+ assert_equal(6, @field[:MaxLen])
22
+ end
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
+
74
+ describe "field_value" do
75
+ it "handles unset values" do
76
+ assert_nil(@field.field_value)
77
+ end
78
+
79
+ it "handles string values" do
80
+ @field[:V] = "str"
81
+ assert_equal("str", @field.field_value)
82
+ end
83
+
84
+ it "handles stream values" do
85
+ @field[:V] = @doc.wrap({}, stream: "str")
86
+ assert_equal("str", @field.field_value)
87
+ end
88
+ end
89
+
90
+ describe "field_value=" do
91
+ it "sets the field to the given value" do
92
+ @field.field_value = 'str'
93
+ assert_equal('str', @field.field_value)
94
+ end
95
+
96
+ it "converts whitespace characters to simple spaces for single line text fields" do
97
+ @field.field_value = "str\ning"
98
+ assert_equal('str ing', @field.field_value)
99
+ end
100
+
101
+ it "allows unsetting the value using +nil+" do
102
+ @field[:V] = "test"
103
+ @field.field_value = nil
104
+ assert_nil(@field.field_value)
105
+ end
106
+
107
+ it "updates the widgets to reflect the changed value" do
108
+ widget = @field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
109
+ @field.set_default_appearance_string
110
+ @field.field_value = 'str'
111
+ assert(widget[:AP][:N])
112
+ end
113
+
114
+ it "fails if the :password flag is set" do
115
+ @field.flag(:password)
116
+ assert_raises(HexaPDF::Error) { @field.field_value = 'test' }
117
+ end
118
+ end
119
+
120
+ it "sets and returns the default field value" do
121
+ @field.default_field_value = 'hallo'
122
+ assert_equal('hallo', @field.default_field_value)
123
+ end
124
+
125
+ it "returns the correct concrete field type" do
126
+ assert_equal(:single_line_text_field, @field.concrete_field_type)
127
+ @field.flag(:multiline, clear_existing: true)
128
+ assert_equal(:multiline_text_field, @field.concrete_field_type)
129
+ @field.flag(:password, clear_existing: true)
130
+ assert_equal(:password_field, @field.concrete_field_type)
131
+ @field.flag(:file_select, clear_existing: true)
132
+ assert_equal(:file_select_field, @field.concrete_field_type)
133
+ @field.flag(:comb, clear_existing: true)
134
+ assert_equal(:comb_text_field, @field.concrete_field_type)
135
+ @field.flag(:rich_text, clear_existing: true)
136
+ assert_equal(:rich_text_field, @field.concrete_field_type)
137
+ end
138
+
139
+ describe "create_appearances" do
140
+ before do
141
+ @doc.acro_form(create: true)
142
+ @field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
143
+ @field.set_default_appearance_string
144
+ end
145
+
146
+ it "creates the needed streams" do
147
+ @field.create_appearances
148
+ assert(@field[:AP][:N])
149
+ end
150
+
151
+ it "doesn't create a new appearance stream if the field value hasn't changed, checked per widget" do
152
+ @field.create_appearances
153
+ stream = @field[:AP][:N].raw_stream
154
+ @field.create_appearances
155
+ assert_same(stream, @field[:AP][:N].raw_stream)
156
+ @field.field_value = 'test'
157
+ refute_same(stream, @field[:AP][:N].raw_stream)
158
+
159
+ widget = @field.create_widget(@doc.pages.add, Rect: [0, 0, 0, 0])
160
+ assert_nil(widget[:AP])
161
+ @field.create_appearances
162
+ refute_nil(widget[:AP][:N])
163
+ end
164
+
165
+ it "always creates a new appearance stream if force is true" do
166
+ @field.create_appearances
167
+ stream = @field[:AP][:N].raw_stream
168
+ @field.create_appearances(force: true)
169
+ refute_same(stream, @field[:AP][:N].raw_stream)
170
+ end
171
+
172
+ it "uses the configuration option acro_form.appearance_generator" do
173
+ @doc.config['acro_form.appearance_generator'] = 'NonExistent'
174
+ assert_raises(Exception) { @field.create_appearances }
175
+ end
176
+ end
177
+
178
+ describe "validation" do
179
+ it "checks the value of the /FT field" do
180
+ @field.delete(:FT)
181
+ refute(@field.validate(auto_correct: false))
182
+ assert(@field.validate)
183
+ assert_equal(:Tx, @field.field_type)
184
+ end
185
+
186
+ it "checks that the field value has a valid type" do
187
+ assert(@field.validate) # no field value
188
+ @field[:V] = :sym
189
+ refute(@field.validate)
190
+ end
191
+
192
+ it "checks the field value against /MaxLen" do
193
+ @field[:V] = 'Test'
194
+ assert(@field.validate)
195
+ @field[:MaxLen] = 2
196
+ refute(@field.validate)
197
+ @field[:V] = nil
198
+ assert(@field.validate)
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,88 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/document'
5
+ require 'hexapdf/type/acro_form/variable_text_field'
6
+
7
+ describe HexaPDF::Type::AcroForm::VariableTextField do
8
+ before do
9
+ @doc = HexaPDF::Document.new
10
+ @doc.acro_form(create: true).set_default_appearance_string
11
+ @field = @doc.add({}, type: HexaPDF::Type::AcroForm::VariableTextField)
12
+ end
13
+
14
+ describe "text_alignment" do
15
+ it "returns the alignment value for displaying text" do
16
+ assert_equal(:left, @field.text_alignment)
17
+ @field[:Q] = 1
18
+ assert_equal(:center, @field.text_alignment)
19
+ @field[:Q] = 2
20
+ assert_equal(:right, @field.text_alignment)
21
+ end
22
+
23
+ it "sets the alignment value for displaying text to a given value" do
24
+ @field.text_alignment(:center)
25
+ assert_equal(1, @field[:Q])
26
+ @field.text_alignment(:right)
27
+ assert_equal(2, @field[:Q])
28
+ @field.text_alignment(:left)
29
+ assert_equal(0, @field[:Q])
30
+ assert_raises(ArgumentError) { @field.text_alignment(:unknown) }
31
+ end
32
+ end
33
+
34
+ describe "set_default_appearance_string" do
35
+ it "creates the AcroForm object if it doesn't exist" do
36
+ @doc.catalog.delete(:AcroForm)
37
+ @field.set_default_appearance_string
38
+ assert(@doc.acro_form)
39
+ end
40
+
41
+ it "uses sane default values if no arguments are provided" do
42
+ @field.set_default_appearance_string
43
+ assert_equal("0 g /F1 0 Tf", @field[:DA])
44
+ font = @doc.acro_form.default_resources.font(:F1)
45
+ assert(font)
46
+ assert_equal(:Helvetica, font[:BaseFont])
47
+ end
48
+
49
+ it "allows specifying the font" do
50
+ @field.set_default_appearance_string(font: 'Times')
51
+ assert_equal("0 g /F2 0 Tf", @field[:DA])
52
+ assert_equal(:'Times-Roman', @doc.acro_form.default_resources.font(:F2)[:BaseFont])
53
+ end
54
+
55
+ it "allows specifying the font options" do
56
+ @field.set_default_appearance_string(font_options: {variant: :italic})
57
+ assert_equal("0 g /F2 0 Tf", @field[:DA])
58
+ assert_equal(:'Helvetica-Oblique', @doc.acro_form.default_resources.font(:F2)[:BaseFont])
59
+ end
60
+
61
+ it "allows specifying the font size" do
62
+ @field.set_default_appearance_string(font_size: 10)
63
+ assert_equal("0 g /F1 10 Tf", @field[:DA])
64
+ end
65
+ end
66
+
67
+ describe "parse_default_appearance_string" do
68
+ it "parses the default appearance string of the field" do
69
+ @field[:DA] = "1 g //F1 20 Tf 5 w /F2 10 Tf"
70
+ assert_equal([:F2, 10], @field.parse_default_appearance_string)
71
+ end
72
+
73
+ it "uses the default appearance string of a parent field" do
74
+ parent = @doc.add({DA: "/F1 15 Tf"}, type: :XXAcroFormField)
75
+ @field[:Parent] = parent
76
+ assert_equal([:F1, 15], @field.parse_default_appearance_string)
77
+ end
78
+
79
+ it "uses the global default appearance string" do
80
+ assert_equal([:F1, 0], @field.parse_default_appearance_string)
81
+ end
82
+
83
+ it "fails if no /DA value is set" do
84
+ @doc.acro_form.delete(:DA)
85
+ assert_raises(HexaPDF::Error) { @field.parse_default_appearance_string }
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/document'
5
+ require 'hexapdf/type/actions/launch'
6
+
7
+ describe HexaPDF::Type::Actions::Launch do
8
+ before do
9
+ @doc = HexaPDF::Document.new
10
+ @action = HexaPDF::Type::Actions::Launch.new({}, document: @doc)
11
+ end
12
+
13
+ describe "validation" do
14
+ it "needs a launch target" do
15
+ refute(@action.validate)
16
+
17
+ @action.value = {F: {}}
18
+ assert(@action.validate)
19
+
20
+ @action.value = {Win: {F: "test.exe"}}
21
+ assert(@action.validate)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/document'
5
+ require 'hexapdf/type/actions/uri'
6
+
7
+ describe HexaPDF::Type::Actions::URI do
8
+ before do
9
+ @doc = HexaPDF::Document.new
10
+ @action = HexaPDF::Type::Actions::URI.new({}, document: @doc)
11
+ end
12
+
13
+ describe "validation" do
14
+ it "URI needs to be ASCII only" do
15
+ refute(@action.validate)
16
+
17
+ @action[:URI] = "hellö"
18
+ refute(@action.validate(auto_correct: false))
19
+ assert(@action.validate(auto_correct: true))
20
+ assert_equal("hell%C3%B6", @action[:URI])
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/document'
5
+ require 'hexapdf/type/annotations/markup_annotation'
6
+
7
+ describe HexaPDF::Type::Annotations::MarkupAnnotation do
8
+ before do
9
+ @doc = HexaPDF::Document.new
10
+ @annot = HexaPDF::Type::Annotations::MarkupAnnotation.new({Subtype: :Text, Rect: [0, 0, 1, 1]},
11
+ document: @doc)
12
+ end
13
+
14
+ describe "validation" do
15
+ it "needs IRT set if RT is set" do
16
+ assert(@annot.validate)
17
+
18
+ @annot[:RT] = :R
19
+ refute(@annot.validate)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,34 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/document'
5
+ require 'hexapdf/type/annotations/text'
6
+
7
+ describe HexaPDF::Type::Annotations::Text do
8
+ before do
9
+ @doc = HexaPDF::Document.new
10
+ @doc.version = '1.5'
11
+ @annot = HexaPDF::Type::Annotations::Text.new({Rect: [0, 0, 1, 1]}, document: @doc, oid: 1)
12
+ end
13
+
14
+ describe "validation" do
15
+ it "checks for correct /StateModel values" do
16
+ @annot[:StateModel] = 'Invalid'
17
+ refute(@annot.validate {|msg| assert_match(/does not contain an allowed value/, msg) })
18
+ end
19
+
20
+ it "automatically sets /StateModel based on the /State entry" do
21
+ @annot[:State] = 'Marked'
22
+ assert(@annot.validate)
23
+ assert_equal('Marked', @annot[:StateModel])
24
+ end
25
+
26
+ it "checks whether /State and /StateModel match" do
27
+ @annot[:State] = 'Marked'
28
+ @annot[:StateModel] = 'Marked'
29
+ assert(@annot.validate)
30
+ @annot[:StateModel] = 'Review'
31
+ refute(@annot.validate {|msg| assert_match(/\/State and \/StateModel don't agree/, msg) })
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,225 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/document'
5
+ require 'hexapdf/type/annotations/widget'
6
+
7
+ describe HexaPDF::Type::Annotations::Widget::AppearanceCharacteristics do
8
+ before do
9
+ @doc = HexaPDF::Document.new
10
+ @annot = @doc.wrap({}, type: :XXAppearanceCharacteristics)
11
+ end
12
+
13
+ describe "validation" do
14
+ it "needs /R to be a multiple of 90" do
15
+ assert(@annot.validate)
16
+
17
+ @annot[:R] = 45
18
+ refute(@annot.validate)
19
+
20
+ @annot[:R] = 90
21
+ assert(@annot.validate)
22
+ end
23
+ end
24
+ end
25
+
26
+ describe HexaPDF::Type::Annotations::Widget do
27
+ before do
28
+ @doc = HexaPDF::Document.new
29
+ @widget = @doc.wrap({Type: :Annot, Subtype: :Widget})
30
+ end
31
+
32
+ describe "form_field" do
33
+ it "works for the field and widget being the same object" do
34
+ @widget[:FT] = :Tx
35
+ @widget[:T] = 'field'
36
+ result = @widget.form_field
37
+ assert_kind_of(HexaPDF::Type::AcroForm::TextField, result)
38
+ assert_same(@widget.data, result.data)
39
+ end
40
+
41
+ it "works for a field with a parent field and the widget being the same object" do
42
+ @widget[:Parent] = {FT: :Tx, T: 'parent', Kids: [@widget]}
43
+ @widget[:T] = 'field'
44
+ result = @widget.form_field
45
+ assert_kind_of(HexaPDF::Type::AcroForm::TextField, result)
46
+ assert_same(@widget.data, result.data)
47
+ end
48
+
49
+ it "works for the widget being in the /Kids array of the field" do
50
+ @widget[:Parent] = {FT: :Tx, T: 'parent', Kids: [@widget]}
51
+ result = @widget.form_field
52
+ assert_kind_of(HexaPDF::Type::AcroForm::TextField, result)
53
+ refute_same(@widget.data, result.data)
54
+ end
55
+ end
56
+
57
+ describe "background_color" do
58
+ it "returns the current background color" do
59
+ assert_nil(@widget.background_color)
60
+ @widget[:MK] = {BG: []}
61
+ assert_nil(@widget.background_color)
62
+ @widget[:MK] = {BG: [1]}
63
+ assert_equal([1], @widget.background_color.components)
64
+ end
65
+
66
+ it "sets the color and returns self" do
67
+ assert_same(@widget, @widget.background_color(51))
68
+ assert_equal([0.2], @widget.background_color.components)
69
+ end
70
+ end
71
+
72
+ describe "border_style" do
73
+ before do
74
+ @widget[:MK] = {BC: [1, 0, 1]}
75
+ @color = HexaPDF::Content::ColorSpace.prenormalized_device_color([1, 0, 1])
76
+ end
77
+
78
+ describe "getter" do
79
+ it "no /Border, /BS or /MK set" do
80
+ @widget.delete(:MK)
81
+ assert_equal([1, nil, :solid, 0, 0], @widget.border_style.to_a)
82
+ end
83
+
84
+ it "no /Border, /BS but with /MK empty" do
85
+ @widget[:MK].delete(:BC)
86
+ assert_equal([1, nil, :solid, 0, 0], @widget.border_style.to_a)
87
+ end
88
+
89
+ it "uses the color from /MK" do
90
+ assert_equal([1, @color, :solid, 0, 0], @widget.border_style.to_a)
91
+ @widget[:MK][:BC] = []
92
+ assert_equal([1, nil, :solid, 0, 0], @widget.border_style.to_a)
93
+ end
94
+
95
+ it "uses the data from /Border" do
96
+ @widget[:Border] = [1, 2, 3, [1, 2]]
97
+ assert_equal([3, @color, [1, 2], 1, 2], @widget.border_style.to_a)
98
+ end
99
+
100
+ it "uses the data from /BS, overriding /Border values" do
101
+ @widget[:Border] = [1, 2, 3, [1, 2]]
102
+ @widget[:BS] = {W: 5, S: :D, D: [5, 6]}
103
+ assert_equal([5, @color, [5, 6], 0, 0], @widget.border_style.to_a)
104
+
105
+ [[:S, :solid], [:D, [5, 6]], [:B, :beveled], [:I, :inset],
106
+ [:U, :underlined], [:Unknown, :solid]].each do |val, result|
107
+ @widget[:BS] = {S: val, D: [5, 6]}
108
+ assert_equal([1, @color, result, 0, 0], @widget.border_style.to_a)
109
+ end
110
+ end
111
+ end
112
+
113
+ describe "setter" do
114
+ it "returns self" do
115
+ assert_equal(@widget, @widget.border_style(width: 1))
116
+ end
117
+
118
+ it "sets the color" do
119
+ @widget.border_style(color: [1.0, 51, 1.0])
120
+ assert_equal([1, 0.2, 1], @widget[:MK][:BC].value)
121
+
122
+ @widget.border_style(color: :transparent)
123
+ assert_equal([], @widget[:MK][:BC].value)
124
+ end
125
+
126
+ it "sets the width" do
127
+ @widget.border_style(width: 2)
128
+ assert_equal(2, @widget[:BS][:W])
129
+ end
130
+
131
+ it "sets the style" do
132
+ [[:solid, :S], [[5, 6], :D], [:beveled, :B], [:inset, :I], [:underlined, :U]].each do |val, r|
133
+ @widget.border_style(style: val)
134
+ assert_equal(r, @widget[:BS][:S])
135
+ assert_equal(val, @widget[:BS][:D].value) if r == :D
136
+ end
137
+ end
138
+
139
+ it "overrides all priorly set values" do
140
+ @widget.border_style(width: 3, style: :inset, color: [1])
141
+ @widget.border_style(width: 5)
142
+ border_style = @widget.border_style
143
+ assert_equal(:solid, border_style.style)
144
+ assert_equal([0], border_style.color.components)
145
+ end
146
+
147
+ it "raises an error for an unknown style" do
148
+ assert_raises(ArgumentError) { @widget.border_style(style: :unknown) }
149
+ end
150
+ end
151
+ end
152
+
153
+ describe "marker_style" do
154
+ before do
155
+ @chars = %w[4 l 8 u n H S]
156
+ @values = [:check, :circle, :cross, :diamond, :square, :star, 'S']
157
+ @widget[:Parent] = {FT: :Btn}
158
+ end
159
+
160
+ describe "style" do
161
+ it "returns the style" do
162
+ @chars.zip(@values) do |char, result|
163
+ @widget[:MK] = {CA: char}
164
+ assert_equal(result, @widget.marker_style.style)
165
+ end
166
+ end
167
+
168
+ it "returns the correct default button style depending on the field" do
169
+ @widget.form_field.initialize_as_check_box
170
+ assert_equal(:check, @widget.marker_style.style)
171
+ @widget.form_field.initialize_as_radio_button
172
+ assert_equal(:circle, @widget.marker_style.style)
173
+ end
174
+
175
+ it "sets the button style" do
176
+ @values.zip(@chars) do |argument, char|
177
+ @widget.marker_style(style: argument)
178
+ assert_equal(char, @widget[:MK][:CA])
179
+ end
180
+ end
181
+
182
+ it "fails if an invalid argument is provided" do
183
+ assert_raises(ArgumentError) { @widget.marker_style(style: 5) }
184
+ end
185
+ end
186
+
187
+ describe "size" do
188
+ it "returns the size" do
189
+ @widget.form_field[:DA] = "/F 15 Tf"
190
+ assert_equal(15, @widget.marker_style.size)
191
+ @widget[:DA] = "/F 10 Tf"
192
+ assert_equal(10, @widget.marker_style.size)
193
+ end
194
+
195
+ it "returns the default size if none is set" do
196
+ assert_equal(0, @widget.marker_style.size)
197
+ end
198
+
199
+ it "sets the given size" do
200
+ @widget.marker_style(size: 10)
201
+ assert_equal('/ZaDb 10 Tf 0.0 g', @widget[:DA])
202
+ end
203
+ end
204
+
205
+ describe "color" do
206
+ it "returns the color" do
207
+ @widget.form_field[:DA] = "0 1 0 rg"
208
+ assert_equal([0, 1, 0], @widget.marker_style.color.components)
209
+ @widget[:DA] = "0 0 1 rg"
210
+ assert_equal([0, 0, 1], @widget.marker_style.color.components)
211
+ end
212
+
213
+ it "returns the default color if none is set" do
214
+ assert_equal([0], @widget.marker_style.color.components)
215
+ end
216
+
217
+ it "sets the given color" do
218
+ @widget.marker_style(color: [1.0, 51, 1.0])
219
+ assert_equal([1, 0.2, 1], @widget.marker_style.color.components)
220
+ @widget.marker_style(color: [1.0, 20, 1.0, 1.0])
221
+ assert_equal([1, 0.2, 1, 1], @widget.marker_style.color.components)
222
+ end
223
+ end
224
+ end
225
+ end