hexapdf 0.12.0 → 0.14.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.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +126 -0
  3. data/examples/019-acro_form.rb +41 -4
  4. data/lib/hexapdf/cli/command.rb +4 -2
  5. data/lib/hexapdf/cli/image2pdf.rb +2 -1
  6. data/lib/hexapdf/cli/info.rb +51 -2
  7. data/lib/hexapdf/cli/inspect.rb +30 -8
  8. data/lib/hexapdf/cli/merge.rb +1 -1
  9. data/lib/hexapdf/cli/split.rb +74 -14
  10. data/lib/hexapdf/configuration.rb +15 -0
  11. data/lib/hexapdf/content/graphic_object/arc.rb +3 -3
  12. data/lib/hexapdf/content/parser.rb +1 -1
  13. data/lib/hexapdf/dictionary.rb +4 -4
  14. data/lib/hexapdf/dictionary_fields.rb +1 -9
  15. data/lib/hexapdf/document.rb +41 -16
  16. data/lib/hexapdf/document/files.rb +0 -1
  17. data/lib/hexapdf/encryption/fast_arc4.rb +1 -1
  18. data/lib/hexapdf/encryption/security_handler.rb +1 -0
  19. data/lib/hexapdf/encryption/standard_security_handler.rb +1 -0
  20. data/lib/hexapdf/font/cmap.rb +1 -4
  21. data/lib/hexapdf/font/encoding/base.rb +8 -0
  22. data/lib/hexapdf/font/encoding/difference_encoding.rb +6 -0
  23. data/lib/hexapdf/font/true_type/table/head.rb +1 -0
  24. data/lib/hexapdf/font/true_type/table/os2.rb +2 -0
  25. data/lib/hexapdf/font/type1_wrapper.rb +1 -1
  26. data/lib/hexapdf/image_loader/png.rb +3 -2
  27. data/lib/hexapdf/layout/line.rb +1 -1
  28. data/lib/hexapdf/layout/style.rb +23 -23
  29. data/lib/hexapdf/layout/text_layouter.rb +2 -2
  30. data/lib/hexapdf/layout/text_shaper.rb +3 -2
  31. data/lib/hexapdf/object.rb +52 -25
  32. data/lib/hexapdf/parser.rb +87 -3
  33. data/lib/hexapdf/pdf_array.rb +11 -4
  34. data/lib/hexapdf/revisions.rb +29 -21
  35. data/lib/hexapdf/serializer.rb +1 -1
  36. data/lib/hexapdf/task/optimize.rb +6 -4
  37. data/lib/hexapdf/tokenizer.rb +4 -3
  38. data/lib/hexapdf/type/acro_form/appearance_generator.rb +132 -28
  39. data/lib/hexapdf/type/acro_form/button_field.rb +21 -13
  40. data/lib/hexapdf/type/acro_form/choice_field.rb +68 -14
  41. data/lib/hexapdf/type/acro_form/field.rb +35 -5
  42. data/lib/hexapdf/type/acro_form/form.rb +139 -14
  43. data/lib/hexapdf/type/acro_form/text_field.rb +70 -4
  44. data/lib/hexapdf/type/actions/uri.rb +3 -2
  45. data/lib/hexapdf/type/annotations/widget.rb +3 -4
  46. data/lib/hexapdf/type/catalog.rb +2 -2
  47. data/lib/hexapdf/type/cid_font.rb +1 -1
  48. data/lib/hexapdf/type/file_specification.rb +1 -1
  49. data/lib/hexapdf/type/font.rb +1 -1
  50. data/lib/hexapdf/type/font_simple.rb +4 -2
  51. data/lib/hexapdf/type/font_true_type.rb +6 -2
  52. data/lib/hexapdf/type/font_type0.rb +4 -4
  53. data/lib/hexapdf/type/form.rb +15 -2
  54. data/lib/hexapdf/type/image.rb +2 -2
  55. data/lib/hexapdf/type/page.rb +37 -13
  56. data/lib/hexapdf/type/page_tree_node.rb +29 -5
  57. data/lib/hexapdf/type/resources.rb +1 -0
  58. data/lib/hexapdf/type/trailer.rb +2 -3
  59. data/lib/hexapdf/utils/object_hash.rb +0 -1
  60. data/lib/hexapdf/utils/sorted_tree_node.rb +18 -15
  61. data/lib/hexapdf/version.rb +1 -1
  62. data/test/hexapdf/common_tokenizer_tests.rb +6 -1
  63. data/test/hexapdf/content/graphic_object/test_arc.rb +4 -4
  64. data/test/hexapdf/content/test_canvas.rb +3 -3
  65. data/test/hexapdf/content/test_color_space.rb +1 -1
  66. data/test/hexapdf/encryption/test_aes.rb +4 -4
  67. data/test/hexapdf/encryption/test_standard_security_handler.rb +11 -11
  68. data/test/hexapdf/filter/test_ascii85_decode.rb +1 -1
  69. data/test/hexapdf/filter/test_ascii_hex_decode.rb +1 -1
  70. data/test/hexapdf/font/encoding/test_base.rb +10 -0
  71. data/test/hexapdf/font/encoding/test_difference_encoding.rb +8 -0
  72. data/test/hexapdf/font/test_type1_wrapper.rb +4 -3
  73. data/test/hexapdf/layout/test_style.rb +1 -1
  74. data/test/hexapdf/layout/test_text_layouter.rb +12 -5
  75. data/test/hexapdf/test_configuration.rb +2 -2
  76. data/test/hexapdf/test_dictionary.rb +3 -1
  77. data/test/hexapdf/test_dictionary_fields.rb +2 -2
  78. data/test/hexapdf/test_document.rb +18 -10
  79. data/test/hexapdf/test_object.rb +71 -26
  80. data/test/hexapdf/test_parser.rb +159 -53
  81. data/test/hexapdf/test_pdf_array.rb +8 -1
  82. data/test/hexapdf/test_revisions.rb +35 -0
  83. data/test/hexapdf/test_writer.rb +2 -2
  84. data/test/hexapdf/type/acro_form/test_appearance_generator.rb +296 -38
  85. data/test/hexapdf/type/acro_form/test_button_field.rb +22 -2
  86. data/test/hexapdf/type/acro_form/test_choice_field.rb +92 -9
  87. data/test/hexapdf/type/acro_form/test_field.rb +39 -0
  88. data/test/hexapdf/type/acro_form/test_form.rb +87 -15
  89. data/test/hexapdf/type/acro_form/test_text_field.rb +77 -1
  90. data/test/hexapdf/type/test_font_simple.rb +2 -1
  91. data/test/hexapdf/type/test_font_true_type.rb +6 -0
  92. data/test/hexapdf/type/test_form.rb +26 -1
  93. data/test/hexapdf/type/test_page.rb +45 -7
  94. data/test/hexapdf/type/test_page_tree_node.rb +42 -0
  95. data/test/hexapdf/utils/test_bit_field.rb +2 -0
  96. data/test/hexapdf/utils/test_object_hash.rb +5 -0
  97. data/test/hexapdf/utils/test_sorted_tree_node.rb +10 -9
  98. data/test/test_helper.rb +2 -0
  99. metadata +6 -11
@@ -107,6 +107,13 @@ describe HexaPDF::PDFArray do
107
107
  assert_equal([1, :data, @array[2]], @array[0, 5])
108
108
  end
109
109
 
110
+ it "allows deleting an object" do
111
+ obj = @array.value[1]
112
+ assert_same(obj, @array.delete(obj))
113
+ ref = HexaPDF::Object.new(:test, oid: 1)
114
+ assert_equal(ref, @array.delete(ref))
115
+ end
116
+
110
117
  describe "slice!" do
111
118
  it "allows deleting a single element" do
112
119
  @array.slice!(2)
@@ -157,6 +164,6 @@ describe HexaPDF::PDFArray do
157
164
  end
158
165
 
159
166
  it "can be converted to a simple array" do
160
- assert_equal(@array.value, @array.to_ary)
167
+ assert_equal([1, :data, "deref", @array[3]], @array.to_ary)
161
168
  end
162
169
  end
@@ -158,4 +158,39 @@ describe HexaPDF::Revisions do
158
158
  doc = HexaPDF::Document.new(io: io)
159
159
  assert_equal(2, doc.revisions.count)
160
160
  end
161
+
162
+ it "uses the reconstructed revision if errors are found when loading from an IO" do
163
+ io = StringIO.new(<<~EOF)
164
+ %PDF-1.7
165
+ 1 0 obj
166
+ 10
167
+ endobj
168
+
169
+ xref
170
+ 0 2
171
+ 0000000000 65535 f
172
+ 0000000009 00000 n
173
+ trailer
174
+ << /Size 5 >>
175
+ startxref
176
+ 28
177
+ %%EOF
178
+
179
+ 2 0 obj
180
+ 300
181
+ endobj
182
+
183
+ xref
184
+ 2 1
185
+ 0000000301 00000 n
186
+ trailer
187
+ << /Size 3 /Prev 100>>
188
+ startxref
189
+ 139
190
+ %%EOF
191
+ EOF
192
+ doc = HexaPDF::Document.new(io: io)
193
+ assert_equal(2, doc.revisions.count)
194
+ assert_same(doc.revisions[0].trailer.value, doc.revisions[1].trailer.value)
195
+ end
161
196
  end
@@ -40,7 +40,7 @@ describe HexaPDF::Writer do
40
40
  219
41
41
  %%EOF
42
42
  3 0 obj
43
- <</Producer(HexaPDF version 0.12.0)>>
43
+ <</Producer(HexaPDF version 0.14.0)>>
44
44
  endobj
45
45
  xref
46
46
  3 1
@@ -72,7 +72,7 @@ describe HexaPDF::Writer do
72
72
  141
73
73
  %%EOF
74
74
  6 0 obj
75
- <</Producer(HexaPDF version 0.12.0)>>
75
+ <</Producer(HexaPDF version 0.14.0)>>
76
76
  endobj
77
77
  2 0 obj
78
78
  <</Length 10>>stream
@@ -25,14 +25,6 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
25
25
  assert_raises(HexaPDF::Error) { @generator.create_appearances }
26
26
  end
27
27
 
28
- it "fails for unsupported choice fields" do
29
- @field = @doc.wrap(@field, type: :XXAcroFormField, subtype: :Ch)
30
- @field[:FT] = :Ch
31
- @field.initialize_as_list_box
32
- @generator = HexaPDF::Type::AcroForm::AppearanceGenerator.new(@widget)
33
- assert_raises(HexaPDF::Error) { @generator.create_appearances }
34
- end
35
-
36
28
  it "fails for unsupported field types" do
37
29
  @field[:FT] = :Unknown
38
30
  assert_raises(HexaPDF::Error) { @generator.create_appearances }
@@ -121,6 +113,24 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
121
113
  [:curve_to, [8.236068, 7.249543, 9.0, 8.572712, 9.0, 10.0]],
122
114
  [:stroke_path], [:restore_graphics_state]])
123
115
  end
116
+
117
+ it "handles the special case of a comb field" do
118
+ @field = @doc.add({FT: :Tx, MaxLen: 4}, type: :XXAcroFormField, subtype: :Tx)
119
+ @field.initialize_as_comb_text_field
120
+ @widget = @field.create_widget(@page, Rect: [0, 0, 10, 20])
121
+ @xform = @doc.add({Type: :XObject, Subtype: :Form, BBox: @widget[:Rect]})
122
+ @generator = HexaPDF::Type::AcroForm::AppearanceGenerator.new(@widget)
123
+ @widget.border_style(width: 2)
124
+ execute
125
+ assert_operators(@xform.stream,
126
+ [[:save_graphics_state],
127
+ [:set_line_width, [2]],
128
+ [:append_rectangle, [1, 1, 8, 18]],
129
+ [:move_to, [2.5, 2]], [:line_to, [2.5, 20.0]],
130
+ [:move_to, [5.0, 2]], [:line_to, [5.0, 20.0]],
131
+ [:move_to, [7.5, 2]], [:line_to, [7.5, 20.0]],
132
+ [:stroke_path], [:restore_graphics_state]])
133
+ end
124
134
  end
125
135
 
126
136
  describe "draw_marker" do
@@ -342,7 +352,7 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
342
352
  end
343
353
  end
344
354
 
345
- describe "text field" do
355
+ describe "text fields" do
346
356
  before do
347
357
  @form.set_default_appearance_string
348
358
  @field = @doc.add({FT: :Tx}, type: :XXAcroFormField, subtype: :Tx)
@@ -392,35 +402,58 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
392
402
  assert_equal(@doc.acro_form.default_resources[:Font][:F1], form[:Resources][:Font][:F1])
393
403
  end
394
404
 
395
- describe "single line text fields" do
396
- describe "font size calculation" do
397
- before do
398
- @widget[:Rect].height = 20
399
- @widget[:Rect].width = 100
400
- @field.field_value = ''
401
- end
405
+ it "re-uses the existing form XObject" do
406
+ @field[:V] = 'test'
407
+ @generator.create_appearances
408
+ form = @widget[:AP][:N]
409
+ form[:key] = :value
402
410
 
403
- it "uses the non-zero font size" do
404
- @field.set_default_appearance_string(font_size: 10)
405
- @generator.create_appearances
406
- assert_operators(@widget[:AP][:N].stream,
407
- [:set_font_and_size, [:F1, 10]],
408
- range: 5)
409
- end
411
+ @field[:V] = 'test1'
412
+ @generator.create_appearances
413
+ assert_same(form, @widget[:AP][:N])
414
+ refute(form.key?(:key))
415
+ assert_match(/test1/, form.contents)
416
+ end
410
417
 
411
- it "calculates the font size based on the rectangle height and border width" do
412
- @generator.create_appearances
413
- assert_operators(@widget[:AP][:N].stream,
414
- [:set_font_and_size, [:F1, 12.923875]],
415
- range: 5)
416
- @widget.border_style(width: 2, color: :transparent)
417
- @generator.create_appearances
418
- assert_operators(@widget[:AP][:N].stream,
419
- [:set_font_and_size, [:F1, 11.487889]],
420
- range: 5)
421
- end
418
+ describe "font size calculation" do
419
+ before do
420
+ @widget[:Rect].height = 20
421
+ @widget[:Rect].width = 100
422
+ @field.field_value = ''
423
+ end
424
+
425
+ it "uses the non-zero font size" do
426
+ @field.set_default_appearance_string(font_size: 10)
427
+ @generator.create_appearances
428
+ assert_operators(@widget[:AP][:N].stream,
429
+ [:set_font_and_size, [:F1, 10]],
430
+ range: 5)
431
+ end
432
+
433
+ it "calculates the font size based on the rectangle height and border width" do
434
+ @generator.create_appearances
435
+ assert_operators(@widget[:AP][:N].stream,
436
+ [:set_font_and_size, [:F1, 12.923875]],
437
+ range: 5)
438
+ @widget.border_style(width: 2, color: :transparent)
439
+ @generator.create_appearances
440
+ assert_operators(@widget[:AP][:N].stream,
441
+ [:set_font_and_size, [:F1, 11.487889]],
442
+ range: 5)
443
+ end
444
+
445
+ it " in case of mulitline auto-sizing" do
446
+ @field.initialize_as_multiline_text_field
447
+ @field[:V] = 'a'
448
+ @field.set_default_appearance_string(font_size: 0)
449
+ @generator.create_appearances
450
+ assert_operators(@widget[:AP][:N].stream,
451
+ [:set_font_and_size, [:F1, 12]],
452
+ range: 6)
422
453
  end
454
+ end
423
455
 
456
+ describe "single line text fields" do
424
457
  describe "quadding e.g. text alignment" do
425
458
  before do
426
459
  @field.field_value = 'Test'
@@ -478,7 +511,166 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
478
511
  [:restore_graphics_state],
479
512
  [:end_marked_content]])
480
513
  end
514
+ end
515
+
516
+ describe "multiline text fields" do
517
+ before do
518
+ @field.set_default_appearance_string(font_size: 10)
519
+ @field.initialize_as_multiline_text_field
520
+ @widget[:Rect].height = 30
521
+ @widget[:Rect].width = 100
522
+ end
523
+
524
+ describe "quadding e.g. text alignment" do
525
+ before do
526
+ @field[:V] = "Test\nValue"
527
+ end
481
528
 
529
+ it "works for left aligned text" do
530
+ @field.text_alignment(:left)
531
+ @generator.create_appearances
532
+ assert_operators(@widget[:AP][:N].stream,
533
+ [:set_text_matrix, [1, 0, 0, 1, 2, 16.195]],
534
+ range: 9)
535
+ end
536
+
537
+ it "works for right aligned text" do
538
+ @field.text_alignment(:right)
539
+ @generator.create_appearances
540
+ assert_operators(@widget[:AP][:N].stream,
541
+ [:set_text_matrix, [1, 0, 0, 1, 78.55, 16.195]],
542
+ range: 9)
543
+ end
544
+
545
+ it "works for center aligned text" do
546
+ @field.text_alignment(:center)
547
+ @generator.create_appearances
548
+ assert_operators(@widget[:AP][:N].stream,
549
+ [:set_text_matrix, [1, 0, 0, 1, 40.275, 16.195]],
550
+ range: 9)
551
+ end
552
+ end
553
+
554
+ it "creates the /N appearance stream according to the set string" do
555
+ @field.field_value = "Test\nValue"
556
+ @generator.create_appearances
557
+ assert_operators(@widget[:AP][:N].stream,
558
+ [[:begin_marked_content, [:Tx]],
559
+ [:save_graphics_state],
560
+ [:append_rectangle, [1, 1, 98, 28]],
561
+ [:clip_path_non_zero],
562
+ [:end_path],
563
+ [:save_graphics_state],
564
+ [:set_leading, [11.5625]],
565
+ [:set_font_and_size, [:F1, 10]],
566
+ [:begin_text],
567
+ [:set_text_matrix, [1, 0, 0, 1, 2, 16.195]],
568
+ [:show_text, ['Test']],
569
+ [:move_text_next_line],
570
+ [:show_text, ['Value']],
571
+ [:end_text],
572
+ [:restore_graphics_state],
573
+ [:restore_graphics_state],
574
+ [:end_marked_content]])
575
+
576
+ @field.field_value = "Test\nTest\nTest"
577
+ @field.set_default_appearance_string(font_size: 0)
578
+ @generator.create_appearances
579
+ assert_operators(@widget[:AP][:N].stream,
580
+ [[:begin_marked_content, [:Tx]],
581
+ [:save_graphics_state],
582
+ [:append_rectangle, [1, 1, 98, 28]],
583
+ [:clip_path_non_zero],
584
+ [:end_path],
585
+ [:save_graphics_state],
586
+ [:set_leading, [9.25]],
587
+ [:set_font_and_size, [:F1, 8]],
588
+ [:begin_text],
589
+ [:set_text_matrix, [1, 0, 0, 1, 2, 18.556]],
590
+ [:show_text, ['Test']],
591
+ [:move_text_next_line],
592
+ [:show_text, ['Test']],
593
+ [:move_text_next_line],
594
+ [:show_text, ['Test']],
595
+ [:end_text],
596
+ [:restore_graphics_state],
597
+ [:restore_graphics_state],
598
+ [:end_marked_content]],
599
+ )
600
+ end
601
+ end
602
+
603
+ describe "comb text fields" do
604
+ before do
605
+ @field.set_default_appearance_string(font_size: 10)
606
+ @field.initialize_as_comb_text_field
607
+ @field[:MaxLen] = 10
608
+ @widget[:Rect].height = 20
609
+ @widget[:Rect].width = 100
610
+ end
611
+
612
+ describe "quadding e.g. text alignment" do
613
+ before do
614
+ @field[:V] = 'Test'
615
+ end
616
+
617
+ it "works for left aligned text" do
618
+ @field.text_alignment(:left)
619
+ @generator.create_appearances
620
+ assert_operators(@widget[:AP][:N].stream,
621
+ [:set_text_matrix, [1, 0, 0, 1, 2.945, 6.41]],
622
+ range: 7)
623
+ end
624
+
625
+ it "works for right aligned text" do
626
+ @field.text_alignment(:right)
627
+ @generator.create_appearances
628
+ assert_operators(@widget[:AP][:N].stream,
629
+ [:set_text_matrix, [1, 0, 0, 1, 62.945, 6.41]],
630
+ range: 7)
631
+ end
632
+
633
+ it "works for center aligned text" do
634
+ @field.text_alignment(:center)
635
+ @generator.create_appearances
636
+ assert_operators(@widget[:AP][:N].stream,
637
+ [:set_text_matrix, [1, 0, 0, 1, 32.945, 6.41]],
638
+ range: 7)
639
+ end
640
+
641
+ it "handles centering like Adobe, e.g. shift left, when text cannot be completely centered" do
642
+ @field.field_value = 'Hello'
643
+ @field.text_alignment(:center)
644
+ @generator.create_appearances
645
+ assert_operators(@widget[:AP][:N].stream,
646
+ [:set_text_matrix, [1, 0, 0, 1, 22.39, 6.41]],
647
+ range: 7)
648
+ end
649
+ end
650
+
651
+ it "creates the /N appearance stream according to the set string" do
652
+ @field.field_value = 'Text'
653
+ @generator.create_appearances
654
+ assert_operators(@widget[:AP][:N].stream,
655
+ [[:begin_marked_content, [:Tx]],
656
+ [:save_graphics_state],
657
+ [:append_rectangle, [1, 1, 98, 18]],
658
+ [:clip_path_non_zero],
659
+ [:end_path],
660
+ [:set_font_and_size, [:F1, 10]],
661
+ [:begin_text],
662
+ [:set_text_matrix, [1, 0, 0, 1, 2.945, 6.41]],
663
+ [:show_text_with_positioning, [['T', -416.5, 'e', -472, 'x', -611, 't']]],
664
+ [:end_text],
665
+ [:restore_graphics_state],
666
+ [:end_marked_content]])
667
+ end
668
+
669
+ it "fails if the /MaxLen key is not set" do
670
+ @field.delete(:MaxLen)
671
+ @field[:V] = 't'
672
+ assert_raises(HexaPDF::Error) { @generator.create_appearances }
673
+ end
482
674
  end
483
675
 
484
676
  describe "choice fields" do
@@ -486,27 +678,93 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
486
678
  @form.set_default_appearance_string
487
679
  field = @doc.add({FT: :Ch}, type: :XXAcroFormField, subtype: :Ch)
488
680
  field.initialize_as_combo_box
681
+ field.flag(:edit)
682
+ field.field_value = 'Test'
489
683
  widget = field.create_widget(@page, Rect: [0, 0, 0, 0])
490
684
  generator = HexaPDF::Type::AcroForm::AppearanceGenerator.new(widget)
491
685
  generator.create_appearances
492
686
  assert_kind_of(HexaPDF::Type::Form, widget[:AP][:N])
493
687
  end
688
+
689
+ describe "list boxes" do
690
+ before do
691
+ @field = @doc.add({FT: :Ch}, type: :XXAcroFormField, subtype: :Ch)
692
+ @field.initialize_as_list_box
693
+ @field.flag(:multi_select)
694
+ @field.option_items = ['a', 'b', 'c']
695
+ @widget = @field.create_widget(@page, Rect: [0, 0, 90, 36])
696
+ @generator = HexaPDF::Type::AcroForm::AppearanceGenerator.new(@widget)
697
+ end
698
+
699
+ it "uses a fixed font size for list box items if auto-sizing is used" do
700
+ @field.set_default_appearance_string(font_size: 0)
701
+ @generator.create_appearances
702
+ assert_operators(@widget[:AP][:N].stream,
703
+ [:set_font_and_size, [:F1, 12]],
704
+ range: 8)
705
+ end
706
+
707
+ it "uses the set values instead of the ones from /I if in conflict" do
708
+ @field[:I] = [0, 1]
709
+ @field[:V] = ['b']
710
+ @generator.create_appearances
711
+ assert_operators(@widget[:AP][:N].stream,
712
+ [[:set_device_rgb_non_stroking_color, [0.6, 0.756863, 0.854902]],
713
+ [:append_rectangle, [1, 7.25, 88, 13.875]],
714
+ [:fill_path_non_zero]],
715
+ range: 5..7)
716
+ end
717
+
718
+ it "creates the /N appearance stream" do
719
+ @field[:I] = [1, 2]
720
+ @field[:V] = ['b', 'c']
721
+ @generator.create_appearances
722
+ assert_operators(@widget[:AP][:N].stream,
723
+ [[:begin_marked_content, [:Tx]],
724
+ [:save_graphics_state],
725
+ [:append_rectangle, [1, 1, 88, 34]],
726
+ [:clip_path_non_zero], [:end_path],
727
+ [:set_device_rgb_non_stroking_color, [0.6, 0.756863, 0.854902]],
728
+ [:append_rectangle, [1, 7.25, 88, 13.875]],
729
+ [:append_rectangle, [1, -6.625, 88, 13.875]],
730
+ [:fill_path_non_zero],
731
+ [:save_graphics_state],
732
+ [:set_leading, [13.875]],
733
+ [:set_font_and_size, [:F1, 12]],
734
+ [:set_device_gray_non_stroking_color, [0.0]],
735
+ [:begin_text],
736
+ [:set_text_matrix, [1, 0, 0, 1, 2, 23.609]],
737
+ [:show_text, ["a"]],
738
+ [:move_text_next_line],
739
+ [:show_text, ["b"]],
740
+ [:end_text],
741
+ [:restore_graphics_state], [:restore_graphics_state],
742
+ [:end_marked_content]])
743
+ end
744
+ end
494
745
  end
495
746
 
496
747
  describe "font resolution in case the referenced font is not usable" do
497
748
  before do
498
- def (@form.default_resources.font(:F1)).font_wrapper; nil; end
499
- @field.field_value = 'Test'
749
+ @doc.config['acro_form.fallback_font'] = ['Times', {variant: :none}]
750
+ @field[:V] = 'Test'
500
751
  end
501
752
 
502
- it "uses the fallback font if configured" do
503
- @doc.config['acro_form.fallback_font'] = ['Times', variant: :none]
753
+ it "uses the fallback font if the font is not usable" do
754
+ def (@form.default_resources.font(:F1)).font_wrapper; nil; end
504
755
  @generator.create_appearances
505
756
  assert_equal(:'Times-Roman', @widget[:AP][:N][:Resources][:Font][:F2][:BaseFont])
506
757
  end
507
758
 
759
+ it "uses the fallback font if the font is not found" do
760
+ @form.default_resources[:Font].delete(:F1)
761
+ @generator.create_appearances
762
+ assert_equal(:'Times-Roman', @widget[:AP][:N][:Resources][:Font][:F1][:BaseFont])
763
+ end
764
+
508
765
  it "fails if fallback fonts are disabled" do
509
766
  @doc.config['acro_form.fallback_font'] = nil
767
+ @form.default_resources[:Font].delete(:F1)
510
768
  msg = assert_raises(HexaPDF::Error) { @generator.create_appearances }
511
769
  assert_match(/Font.*not usable/, msg.message)
512
770
  end