hexapdf 0.5.0 → 0.6.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 (122) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +76 -2
  3. data/CONTRIBUTERS +1 -1
  4. data/Rakefile +1 -1
  5. data/VERSION +1 -1
  6. data/examples/boxes.rb +68 -0
  7. data/examples/graphics.rb +12 -12
  8. data/examples/{text_box_alignment.rb → text_layouter_alignment.rb} +14 -14
  9. data/examples/text_layouter_inline_boxes.rb +66 -0
  10. data/examples/{text_box_line_wrapping.rb → text_layouter_line_wrapping.rb} +9 -10
  11. data/examples/{text_box_shapes.rb → text_layouter_shapes.rb} +58 -54
  12. data/examples/text_layouter_styling.rb +125 -0
  13. data/examples/truetype.rb +5 -7
  14. data/lib/hexapdf/cli/command.rb +1 -0
  15. data/lib/hexapdf/configuration.rb +170 -106
  16. data/lib/hexapdf/content/canvas.rb +41 -36
  17. data/lib/hexapdf/content/graphics_state.rb +15 -0
  18. data/lib/hexapdf/content/operator.rb +1 -1
  19. data/lib/hexapdf/dictionary.rb +20 -8
  20. data/lib/hexapdf/dictionary_fields.rb +8 -6
  21. data/lib/hexapdf/document.rb +25 -26
  22. data/lib/hexapdf/document/fonts.rb +4 -4
  23. data/lib/hexapdf/document/images.rb +2 -2
  24. data/lib/hexapdf/document/pages.rb +16 -16
  25. data/lib/hexapdf/encryption/security_handler.rb +41 -9
  26. data/lib/hexapdf/filter/flate_decode.rb +1 -1
  27. data/lib/hexapdf/filter/lzw_decode.rb +1 -1
  28. data/lib/hexapdf/filter/predictor.rb +7 -1
  29. data/lib/hexapdf/font/true_type/font.rb +20 -0
  30. data/lib/hexapdf/font/type1/font.rb +23 -0
  31. data/lib/hexapdf/font_loader.rb +1 -0
  32. data/lib/hexapdf/font_loader/from_configuration.rb +2 -3
  33. data/lib/hexapdf/font_loader/from_file.rb +65 -0
  34. data/lib/hexapdf/image_loader/png.rb +2 -2
  35. data/lib/hexapdf/layout.rb +3 -2
  36. data/lib/hexapdf/layout/box.rb +146 -0
  37. data/lib/hexapdf/layout/inline_box.rb +40 -31
  38. data/lib/hexapdf/layout/{line_fragment.rb → line.rb} +12 -13
  39. data/lib/hexapdf/layout/style.rb +630 -41
  40. data/lib/hexapdf/layout/text_fragment.rb +80 -12
  41. data/lib/hexapdf/layout/{text_box.rb → text_layouter.rb} +164 -109
  42. data/lib/hexapdf/number_tree_node.rb +1 -1
  43. data/lib/hexapdf/parser.rb +4 -1
  44. data/lib/hexapdf/revisions.rb +11 -4
  45. data/lib/hexapdf/stream.rb +8 -9
  46. data/lib/hexapdf/tokenizer.rb +5 -3
  47. data/lib/hexapdf/type.rb +3 -0
  48. data/lib/hexapdf/type/action.rb +56 -0
  49. data/lib/hexapdf/type/actions.rb +52 -0
  50. data/lib/hexapdf/type/actions/go_to.rb +52 -0
  51. data/lib/hexapdf/type/actions/go_to_r.rb +54 -0
  52. data/lib/hexapdf/type/actions/launch.rb +73 -0
  53. data/lib/hexapdf/type/actions/uri.rb +65 -0
  54. data/lib/hexapdf/type/annotation.rb +85 -0
  55. data/lib/hexapdf/type/annotations.rb +51 -0
  56. data/lib/hexapdf/type/annotations/link.rb +70 -0
  57. data/lib/hexapdf/type/annotations/markup_annotation.rb +70 -0
  58. data/lib/hexapdf/type/annotations/text.rb +81 -0
  59. data/lib/hexapdf/type/catalog.rb +3 -1
  60. data/lib/hexapdf/type/embedded_file.rb +6 -11
  61. data/lib/hexapdf/type/file_specification.rb +4 -6
  62. data/lib/hexapdf/type/font.rb +3 -1
  63. data/lib/hexapdf/type/font_descriptor.rb +18 -16
  64. data/lib/hexapdf/type/form.rb +3 -1
  65. data/lib/hexapdf/type/graphics_state_parameter.rb +3 -1
  66. data/lib/hexapdf/type/image.rb +4 -2
  67. data/lib/hexapdf/type/info.rb +2 -5
  68. data/lib/hexapdf/type/names.rb +2 -5
  69. data/lib/hexapdf/type/object_stream.rb +2 -1
  70. data/lib/hexapdf/type/page.rb +14 -1
  71. data/lib/hexapdf/type/page_tree_node.rb +9 -6
  72. data/lib/hexapdf/type/resources.rb +2 -5
  73. data/lib/hexapdf/type/trailer.rb +2 -5
  74. data/lib/hexapdf/type/viewer_preferences.rb +2 -5
  75. data/lib/hexapdf/type/xref_stream.rb +3 -1
  76. data/lib/hexapdf/version.rb +1 -1
  77. data/test/hexapdf/common_tokenizer_tests.rb +3 -1
  78. data/test/hexapdf/content/test_canvas.rb +29 -3
  79. data/test/hexapdf/content/test_graphics_state.rb +11 -0
  80. data/test/hexapdf/content/test_operator.rb +3 -2
  81. data/test/hexapdf/document/test_fonts.rb +8 -8
  82. data/test/hexapdf/document/test_images.rb +4 -12
  83. data/test/hexapdf/document/test_pages.rb +7 -7
  84. data/test/hexapdf/encryption/test_security_handler.rb +1 -5
  85. data/test/hexapdf/filter/test_predictor.rb +40 -12
  86. data/test/hexapdf/font/true_type/test_font.rb +16 -0
  87. data/test/hexapdf/font/type1/test_font.rb +30 -0
  88. data/test/hexapdf/font_loader/test_from_file.rb +29 -0
  89. data/test/hexapdf/font_loader/test_standard14.rb +4 -3
  90. data/test/hexapdf/layout/test_box.rb +104 -0
  91. data/test/hexapdf/layout/test_inline_box.rb +24 -10
  92. data/test/hexapdf/layout/{test_line_fragment.rb → test_line.rb} +9 -9
  93. data/test/hexapdf/layout/test_style.rb +519 -31
  94. data/test/hexapdf/layout/test_text_fragment.rb +136 -15
  95. data/test/hexapdf/layout/{test_text_box.rb → test_text_layouter.rb} +224 -144
  96. data/test/hexapdf/layout/test_text_shaper.rb +1 -1
  97. data/test/hexapdf/test_configuration.rb +12 -6
  98. data/test/hexapdf/test_dictionary.rb +27 -2
  99. data/test/hexapdf/test_dictionary_fields.rb +10 -1
  100. data/test/hexapdf/test_document.rb +14 -13
  101. data/test/hexapdf/test_parser.rb +12 -0
  102. data/test/hexapdf/test_revisions.rb +34 -0
  103. data/test/hexapdf/test_stream.rb +1 -1
  104. data/test/hexapdf/test_type.rb +18 -0
  105. data/test/hexapdf/test_writer.rb +2 -2
  106. data/test/hexapdf/type/actions/test_launch.rb +24 -0
  107. data/test/hexapdf/type/actions/test_uri.rb +23 -0
  108. data/test/hexapdf/type/annotations/test_link.rb +19 -0
  109. data/test/hexapdf/type/annotations/test_markup_annotation.rb +22 -0
  110. data/test/hexapdf/type/annotations/test_text.rb +38 -0
  111. data/test/hexapdf/type/test_annotation.rb +38 -0
  112. data/test/hexapdf/type/test_file_specification.rb +0 -7
  113. data/test/hexapdf/type/test_info.rb +0 -5
  114. data/test/hexapdf/type/test_page.rb +14 -0
  115. data/test/hexapdf/type/test_page_tree_node.rb +4 -1
  116. data/test/hexapdf/type/test_trailer.rb +0 -4
  117. data/test/test_helper.rb +6 -3
  118. metadata +36 -15
  119. data/examples/text_box_inline_boxes.rb +0 -56
  120. data/examples/text_box_styling.rb +0 -72
  121. data/test/hexapdf/type/test_embedded_file.rb +0 -16
  122. data/test/hexapdf/type/test_names.rb +0 -9
@@ -46,31 +46,33 @@ module HexaPDF
46
46
 
47
47
  extend Utils::BitField
48
48
 
49
- define_field :Type, type: Symbol, required: true, default: :FontDescriptor
50
- define_field :FontName, type: Symbol, required: true
49
+ define_type :FontDescriptor
50
+
51
+ define_field :Type, type: Symbol, required: true, default: self.type
52
+ define_field :FontName, type: Symbol, required: true
51
53
  define_field :FontFamily, type: PDFByteString, version: '1.5'
52
- define_field :FontStretch, type: Symbol, version: '1.5'
53
- define_field :FontWeight, type: Numeric, version: '1.5'
54
- define_field :Flags, type: Integer, required: true
54
+ define_field :FontStretch, type: Symbol, version: '1.5'
55
+ define_field :FontWeight, type: Numeric, version: '1.5'
56
+ define_field :Flags, type: Integer, required: true
55
57
  define_field :FontBBox, type: Rectangle
56
- define_field :ItalicAngle, type: Numeric, required: true
58
+ define_field :ItalicAngle, type: Numeric, required: true
57
59
  define_field :Ascent, type: Numeric
58
60
  define_field :Descent, type: Numeric
59
- define_field :Leading, type: Numeric, default: 0
61
+ define_field :Leading, type: Numeric, default: 0
60
62
  define_field :CapHeight, type: Numeric
61
- define_field :XHeight, type: Numeric, default: 0
63
+ define_field :XHeight, type: Numeric, default: 0
62
64
  define_field :StemV, type: Numeric
63
- define_field :StemH, type: Numeric, default: 0
64
- define_field :AvgWidth, type: Numeric, default: 0
65
- define_field :MaxWidth, type: Numeric, default: 0
66
- define_field :MissingWidth, type: Numeric, default: 0
65
+ define_field :StemH, type: Numeric, default: 0
66
+ define_field :AvgWidth, type: Numeric, default: 0
67
+ define_field :MaxWidth, type: Numeric, default: 0
68
+ define_field :MissingWidth, type: Numeric, default: 0
67
69
  define_field :FontFile, type: Stream
68
- define_field :FontFile2, type: Stream, version: '1.1'
69
- define_field :FontFile3, type: Stream, version: '1.2'
70
- define_field :CharSet, type: [String, PDFByteString], version: '1.1'
70
+ define_field :FontFile2, type: Stream, version: '1.1'
71
+ define_field :FontFile3, type: Stream, version: '1.2'
72
+ define_field :CharSet, type: [String, PDFByteString], version: '1.1'
71
73
 
72
74
  define_field :Style, type: Dictionary
73
- define_field :Lang, type: Symbol, version: '1.5'
75
+ define_field :Lang, type: Symbol, version: '1.5'
74
76
  define_field :FD, type: Dictionary
75
77
  define_field :CIDSet, type: Stream
76
78
 
@@ -42,7 +42,9 @@ module HexaPDF
42
42
  # See: PDF1.7 s8.10
43
43
  class Form < Stream
44
44
 
45
- define_field :Type, type: Symbol, default: :XObject
45
+ define_type :XObject
46
+
47
+ define_field :Type, type: Symbol, default: self.type
46
48
  define_field :Subtype, type: Symbol, required: true, default: :Form
47
49
  define_field :FormType, type: Integer, default: 1
48
50
  define_field :BBox, type: Rectangle, required: true
@@ -45,7 +45,9 @@ module HexaPDF
45
45
  # See: PDF1.7 s8.4.5, s8.1
46
46
  class GraphicsStateParameter < Dictionary
47
47
 
48
- define_field :Type, type: Symbol, required: true, default: :ExtGState
48
+ define_type :ExtGState
49
+
50
+ define_field :Type, type: Symbol, required: true, default: self.type
49
51
  define_field :LW, type: Numeric, version: "1.3"
50
52
  define_field :LC, type: Integer, version: "1.3"
51
53
  define_field :LJ, type: Integer, version: "1.3"
@@ -48,7 +48,9 @@ module HexaPDF
48
48
  Info = Struct.new(:type, :width, :height, :color_space, :indexed, :components,
49
49
  :bits_per_component, :writable, :extension)
50
50
 
51
- define_field :Type, type: Symbol, default: :XObject
51
+ define_type :XObject
52
+
53
+ define_field :Type, type: Symbol, default: self.type
52
54
  define_field :Subtype, type: Symbol, required: true, default: :Image
53
55
  define_field :Width, type: Integer, required: true
54
56
  define_field :Height, type: Integer, required: true
@@ -238,7 +240,7 @@ module HexaPDF
238
240
  if filter == :FlateDecode && self[:DecodeParms] && self[:DecodeParms][:Predictor].to_i >= 10
239
241
  data = stream_source
240
242
  else
241
- flate_decode = GlobalConfiguration.constantize('filter.map', :FlateDecode)
243
+ flate_decode = config.constantize('filter.map', :FlateDecode)
242
244
  data = flate_decode.encoder(stream_decoder, Predictor: 15, Colors: 1, Columns: info.width,
243
245
  BitsPerComponent: info.bits_per_component)
244
246
  end
@@ -44,6 +44,8 @@ module HexaPDF
44
44
  # See: PDF1.7 s14.3.3, Trailer
45
45
  class Info < Dictionary
46
46
 
47
+ define_type :XXInfo
48
+
47
49
  define_field :Title, type: String, version: '1.1'
48
50
  define_field :Author, type: String
49
51
  define_field :Subject, type: String, version: '1.1'
@@ -59,11 +61,6 @@ module HexaPDF
59
61
  true
60
62
  end
61
63
 
62
- # Returns +:XXInfo+.
63
- def type
64
- :XXInfo
65
- end
66
-
67
64
  end
68
65
 
69
66
  end
@@ -47,6 +47,8 @@ module HexaPDF
47
47
  # See: PDF1.7 s7.7.4, HexaPDF::Catalog, HexaPDF::NameTreeNode
48
48
  class Names < Dictionary
49
49
 
50
+ define_type :XXNames
51
+
50
52
  define_field :Dests, type: NameTreeNode, version: '1.2'
51
53
  define_field :AP, type: NameTreeNode, version: '1.3'
52
54
  define_field :JavaScript, type: NameTreeNode, version: '1.3'
@@ -58,11 +60,6 @@ module HexaPDF
58
60
  define_field :AlternatePresentations, type: NameTreeNode, version: '1.4'
59
61
  define_field :Renditions, type: NameTreeNode, version: '1.5'
60
62
 
61
- # Returns +:XXNames+.
62
- def type
63
- :XXNames
64
- end
65
-
66
63
  end
67
64
 
68
65
  end
@@ -95,8 +95,9 @@ module HexaPDF
95
95
 
96
96
  end
97
97
 
98
+ define_type :ObjStm
98
99
 
99
- define_field :Type, type: Symbol, required: true, default: :ObjStm, version: '1.5'
100
+ define_field :Type, type: Symbol, required: true, default: self.type, version: '1.5'
100
101
  define_field :N, type: Integer # not required, will be auto-filled on #write_objects
101
102
  define_field :First, type: Integer # not required, will be auto-filled on #write_objects
102
103
  define_field :Extends, type: Stream
@@ -31,6 +31,7 @@
31
31
  # is created or manipulated using HexaPDF.
32
32
  #++
33
33
 
34
+ require 'hexapdf/error'
34
35
  require 'hexapdf/dictionary'
35
36
  require 'hexapdf/stream'
36
37
  require 'hexapdf/type/page_tree_node'
@@ -99,14 +100,26 @@ module HexaPDF
99
100
  Executive: [0, 0, 522, 756].freeze,
100
101
  }.freeze
101
102
 
103
+ # Returns the media box for the given paper size. See PAPER_SIZE for the defined paper sizes.
104
+ def self.media_box(paper_size, orientation: :portrait)
105
+ unless PAPER_SIZE.key?(paper_size)
106
+ raise HexaPDF::Error, "Invalid paper size specified: #{paper_size}"
107
+ end
108
+
109
+ media_box = PAPER_SIZE[paper_size].dup
110
+ media_box[2], media_box[3] = media_box[3], media_box[2] if orientation == :landscape
111
+ media_box
112
+ end
113
+
102
114
  # The inheritable fields.
103
115
  INHERITABLE_FIELDS = [:Resources, :MediaBox, :CropBox, :Rotate].freeze
104
116
 
105
117
  # The required inheritable fields.
106
118
  REQUIRED_INHERITABLE_FIELDS = [:Resources, :MediaBox].freeze
107
119
 
120
+ define_type :Page
108
121
 
109
- define_field :Type, type: Symbol, required: true, default: :Page
122
+ define_field :Type, type: Symbol, required: true, default: self.type
110
123
  define_field :Parent, type: :Pages, required: true, indirect: true
111
124
  define_field :LastModified, type: PDFDate, version: '1.3'
112
125
  define_field :Resources, type: :XXResources
@@ -59,7 +59,9 @@ module HexaPDF
59
59
  # See: PDF1.7 s7.7.3.2, Page
60
60
  class PageTreeNode < Dictionary
61
61
 
62
- define_field :Type, type: Symbol, required: true, default: :Pages
62
+ define_type :Pages
63
+
64
+ define_field :Type, type: Symbol, required: true, default: self.type
63
65
  define_field :Parent, type: Dictionary, indirect: true
64
66
  define_field :Kids, type: Array, required: true, default: []
65
67
  define_field :Count, type: Integer, required: true, default: 0
@@ -212,12 +214,13 @@ module HexaPDF
212
214
 
213
215
  private
214
216
 
215
- # Returns a new page object, correctly initialized using the document's configuration
216
- # options.
217
+ # Returns a new page object, correctly initialized using the document's configuration options.
217
218
  def new_page
218
- media_box = config['page.default_media_box']
219
- media_box = Page::PAPER_SIZE[media_box].dup if Page::PAPER_SIZE.key?(media_box)
220
- document.add(Type: :Page, MediaBox: media_box)
219
+ box = config['page.default_media_box']
220
+ if box.kind_of?(Symbol)
221
+ box = Page.media_box(box, orientation: config['page.default_media_orientation'])
222
+ end
223
+ document.add(Type: :Page, MediaBox: box)
221
224
  end
222
225
 
223
226
  # Ensures that the /Count and /Parent fields of the whole page tree are set up correctly and
@@ -44,6 +44,8 @@ module HexaPDF
44
44
  # See: PDF1.7 s7.8.3
45
45
  class Resources < Dictionary
46
46
 
47
+ define_type :XXResources
48
+
47
49
  define_field :ExtGState, type: Dictionary
48
50
  define_field :ColorSpace, type: Dictionary
49
51
  define_field :Pattern, type: Dictionary
@@ -53,11 +55,6 @@ module HexaPDF
53
55
  define_field :ProcSet, type: Array
54
56
  define_field :Properties, type: Dictionary, version: '1.2'
55
57
 
56
- # Returns +:XXResources+.
57
- def type
58
- :XXResources
59
- end
60
-
61
58
  # Returns the color space stored under the given name.
62
59
  #
63
60
  # If the color space is not found, an error is raised.
@@ -55,6 +55,8 @@ module HexaPDF
55
55
  # XRefStream
56
56
  class Trailer < Dictionary
57
57
 
58
+ define_type :XXTrailer
59
+
58
60
  define_field :Size, type: Integer, indirect: false # will be auto-set when written
59
61
  define_field :Prev, type: Integer
60
62
  define_field :Root, type: :Catalog, indirect: true
@@ -63,11 +65,6 @@ module HexaPDF
63
65
  define_field :ID, type: Array
64
66
  define_field :XRefStm, type: Integer, version: '1.5'
65
67
 
66
- # Returns +:XXTrailer+.
67
- def type
68
- :XXTrailer
69
- end
70
-
71
68
  # Returns the document's Catalog (see Type::Catalog), creating it if needed.
72
69
  def catalog
73
70
  self[:Root] ||= document.add(Type: :Catalog)
@@ -44,6 +44,8 @@ module HexaPDF
44
44
  # See: PDF1.7 s12.2, Catalog
45
45
  class ViewerPreferences < Dictionary
46
46
 
47
+ define_type :XXViewerPreferences
48
+
47
49
  define_field :HideToolbar, type: Boolean, default: false
48
50
  define_field :HideMenubar, type: Boolean, default: false
49
51
  define_field :HideWindowUI, type: Boolean, default: false
@@ -62,11 +64,6 @@ module HexaPDF
62
64
  define_field :PrintPageRange, type: Array, version: '1.7'
63
65
  define_field :NumCopies, type: Integer, version: '1.7'
64
66
 
65
- # Returns +:XXViewerPreferences+.
66
- def type
67
- :XXViewerPreferences
68
- end
69
-
70
67
  end
71
68
 
72
69
  end
@@ -65,7 +65,9 @@ module HexaPDF
65
65
  # See: PDF1.7 s7.5.8
66
66
  class XRefStream < HexaPDF::Stream
67
67
 
68
- define_field :Type, type: Symbol, default: :XRef, required: true, indirect: false, version: '1.5'
68
+ define_type :XRef
69
+
70
+ define_field :Type, type: Symbol, default: self.type, required: true, indirect: false, version: '1.5'
69
71
  # Size is not required because it will be auto-filled before the object is written
70
72
  define_field :Size, type: Integer, indirect: false
71
73
  define_field :Index, type: Array, indirect: false
@@ -34,6 +34,6 @@
34
34
  module HexaPDF
35
35
 
36
36
  # The version of HexaPDF.
37
- VERSION = '0.5.0'.freeze
37
+ VERSION = '0.6.0'.freeze
38
38
 
39
39
  end
@@ -206,6 +206,8 @@ module CommonTokenizerTests
206
206
 
207
207
  it "next_xref_entry: fails on invalidly formatted entries" do
208
208
  create_tokenizer("0000000001 00001 g \n")
209
- assert_raises(HexaPDF::MalformedPDFError) { @tokenizer.next_xref_entry }
209
+ assert_raises(RuntimeError) { @tokenizer.next_xref_entry { raise }}
210
+ create_tokenizer("0000000001 00001 n\n")
211
+ assert_raises(RuntimeError) { @tokenizer.next_xref_entry { raise }}
210
212
  end
211
213
  end
@@ -87,6 +87,17 @@ describe HexaPDF::Content::Canvas do
87
87
  assert_operators(@canvas.contents, [[:save_graphics_state], [:restore_graphics_state]])
88
88
  end
89
89
 
90
+ it "saves needed font state information not stored in the graphics state" do
91
+ @canvas.save_graphics_state do
92
+ @canvas.font("Times", size: 12)
93
+ @canvas.save_graphics_state do
94
+ @canvas.font("Helvetica")
95
+ end
96
+ assert_equal("Times-Roman", @canvas.font.wrapped_font.font_name)
97
+ end
98
+ assert_nil(@canvas.font)
99
+ end
100
+
90
101
  it "fails if invoked while in an unsupported graphics objects" do
91
102
  assert_raises_in_graphics_object(:path, :clipping_path) { @canvas.save_graphics_state }
92
103
  end
@@ -999,9 +1010,9 @@ describe HexaPDF::Content::Canvas do
999
1010
  it "returns the set font" do
1000
1011
  assert_nil(@canvas.font)
1001
1012
  @canvas.font("Times", size: 10)
1002
- assert_same(@doc.fonts.load("Times"), @canvas.font)
1013
+ assert_same(@doc.fonts.add("Times"), @canvas.font)
1003
1014
  @canvas.font(@canvas.font)
1004
- assert_same(@doc.fonts.load("Times"), @canvas.font)
1015
+ assert_same(@doc.fonts.add("Times"), @canvas.font)
1005
1016
  @canvas.font("Helvetica", size: 10)
1006
1017
  assert_operators(@canvas.contents, [[:set_font_and_size, [:F1, 10]],
1007
1018
  [:set_leading, [12.0]],
@@ -1010,7 +1021,7 @@ describe HexaPDF::Content::Canvas do
1010
1021
 
1011
1022
  it "sets the font and optionally the font size" do
1012
1023
  @canvas.font("Times", size: 12, variant: :italic)
1013
- assert_same(@doc.fonts.load("Times", variant: :italic), @canvas.font)
1024
+ assert_same(@doc.fonts.add("Times", variant: :italic), @canvas.font)
1014
1025
  assert_equal(12, @canvas.font_size)
1015
1026
  @canvas.font("Helvetica")
1016
1027
  assert_equal(12, @canvas.font_size)
@@ -1066,6 +1077,11 @@ describe HexaPDF::Content::Canvas do
1066
1077
  [:show_text_with_positioning, [["Hal"]]],
1067
1078
  ])
1068
1079
  end
1080
+
1081
+ it "fails if no valid font is set" do
1082
+ error = assert_raises(HexaPDF::Error) { @canvas.show_glyphs([]) }
1083
+ assert_match(/if a font is set/, error.message)
1084
+ end
1069
1085
  end
1070
1086
 
1071
1087
  describe "show_glyphs_only" do
@@ -1081,6 +1097,11 @@ describe HexaPDF::Content::Canvas do
1081
1097
  [:show_text_with_positioning, [["Ha", -35, "l lo"]]],
1082
1098
  ])
1083
1099
  end
1100
+
1101
+ it "fails if no valid font is set" do
1102
+ error = assert_raises(HexaPDF::Error) { @canvas.show_glyphs([]) }
1103
+ assert_match(/if a font is set/, error.message)
1104
+ end
1084
1105
  end
1085
1106
 
1086
1107
  describe "text" do
@@ -1112,6 +1133,11 @@ describe HexaPDF::Content::Canvas do
1112
1133
  [:show_text_with_positioning, [["H"]]],
1113
1134
  ])
1114
1135
  end
1136
+
1137
+ it "fails if no valid font is set" do
1138
+ error = assert_raises(HexaPDF::Error) { @canvas.show_glyphs([]) }
1139
+ assert_match(/if a font is set/, error.message)
1140
+ end
1115
1141
  end
1116
1142
 
1117
1143
  describe "marked_content_point" do
@@ -77,6 +77,17 @@ class GraphicsStateWrapper < Minitest::Spec
77
77
  end
78
78
 
79
79
  describe LineDashPattern do
80
+ it "returns a normalized line dash pattern from various values" do
81
+ assert_equal([[], 0], LineDashPattern.normalize(0).to_operands)
82
+ assert_equal([[5], 0], LineDashPattern.normalize(5).to_operands)
83
+ assert_equal([[5, 3], 2], LineDashPattern.normalize([5, 3], 2).to_operands)
84
+ assert_equal([[5], 1], LineDashPattern.normalize(LineDashPattern.normalize(5, 1)).to_operands)
85
+ end
86
+
87
+ it "fails on normalization if an invalid array argument is provided" do
88
+ assert_raises(ArgumentError) { LineDashPattern.normalize(:bla) }
89
+ end
90
+
80
91
  it "fails on initialization if the phase is negative" do
81
92
  assert_raises(ArgumentError) { LineDashPattern.new([], -1) }
82
93
  end
@@ -463,8 +463,9 @@ end
463
463
 
464
464
  describe_operator :SetTextRenderingMode, :Tr do
465
465
  it "modifies the text rendering mode" do
466
- invoke(127)
467
- assert_equal(127, @processor.graphics_state.text_rendering_mode)
466
+ invoke(HexaPDF::Content::TextRenderingMode::FILL_STROKE)
467
+ assert_equal(HexaPDF::Content::TextRenderingMode::FILL_STROKE,
468
+ @processor.graphics_state.text_rendering_mode)
468
469
  end
469
470
  end
470
471
 
@@ -9,7 +9,7 @@ describe HexaPDF::Document::Fonts do
9
9
  @doc.config['font_loader'] = []
10
10
  end
11
11
 
12
- describe "load" do
12
+ describe "add" do
13
13
  before do
14
14
  @doc.config['font_loader'] << lambda do |doc, name, **options|
15
15
  assert_equal(@doc, doc)
@@ -26,23 +26,23 @@ describe HexaPDF::Document::Fonts do
26
26
  end
27
27
 
28
28
  it "loads the specified font" do
29
- assert_equal(:NormalFont, @doc.fonts.load(:TestFont).name)
30
- assert_equal(:BoldFont, @doc.fonts.load(:TestFont, variant: :bold).name)
29
+ assert_equal(:NormalFont, @doc.fonts.add(:TestFont).name)
30
+ assert_equal(:BoldFont, @doc.fonts.add(:TestFont, variant: :bold).name)
31
31
  end
32
32
 
33
33
  it "caches loaded fonts" do
34
- font = @doc.fonts.load(:TestFont)
35
- assert_same(font, @doc.fonts.load(:TestFont))
36
- assert_same(font, @doc.fonts.load(:TestFont, variant: :none))
34
+ font = @doc.fonts.add(:TestFont)
35
+ assert_same(font, @doc.fonts.add(:TestFont))
36
+ assert_same(font, @doc.fonts.add(:TestFont, variant: :none))
37
37
  end
38
38
 
39
39
  it "fails if the requested font is not found" do
40
- assert_raises(HexaPDF::Error) { @doc.fonts.load("Unknown") }
40
+ assert_raises(HexaPDF::Error) { @doc.fonts.add("Unknown") }
41
41
  end
42
42
 
43
43
  it "raises an error if a font loader cannot be correctly retrieved" do
44
44
  @doc.config['font_loader'][0] = 'UnknownFontLoader'
45
- assert_raises(HexaPDF::Error) { @doc.fonts.load(:Other) }
45
+ assert_raises(HexaPDF::Error) { @doc.fonts.add(:Other) }
46
46
  end
47
47
  end
48
48
  end