hexapdf 0.32.2 → 0.33.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 (202) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +63 -1
  3. data/README.md +9 -0
  4. data/examples/002-graphics.rb +15 -17
  5. data/examples/003-arcs.rb +9 -9
  6. data/examples/009-text_layouter_alignment.rb +1 -1
  7. data/examples/010-text_layouter_inline_boxes.rb +2 -2
  8. data/examples/011-text_layouter_line_wrapping.rb +1 -1
  9. data/examples/012-text_layouter_styling.rb +7 -7
  10. data/examples/013-text_layouter_shapes.rb +1 -1
  11. data/examples/014-text_in_polygon.rb +1 -1
  12. data/examples/015-boxes.rb +8 -7
  13. data/examples/016-frame_automatic_box_placement.rb +2 -2
  14. data/examples/017-frame_text_flow.rb +2 -1
  15. data/examples/018-composer.rb +1 -1
  16. data/examples/020-column_box.rb +2 -1
  17. data/examples/025-table_box.rb +46 -0
  18. data/lib/hexapdf/cli/command.rb +5 -2
  19. data/lib/hexapdf/cli/form.rb +5 -5
  20. data/lib/hexapdf/cli/inspect.rb +3 -3
  21. data/lib/hexapdf/composer.rb +104 -52
  22. data/lib/hexapdf/configuration.rb +44 -39
  23. data/lib/hexapdf/content/canvas.rb +393 -267
  24. data/lib/hexapdf/content/color_space.rb +72 -25
  25. data/lib/hexapdf/content/graphic_object/arc.rb +57 -24
  26. data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +66 -23
  27. data/lib/hexapdf/content/graphic_object/geom2d.rb +47 -6
  28. data/lib/hexapdf/content/graphic_object/solid_arc.rb +58 -36
  29. data/lib/hexapdf/content/graphic_object.rb +6 -7
  30. data/lib/hexapdf/content/graphics_state.rb +54 -45
  31. data/lib/hexapdf/content/operator.rb +52 -54
  32. data/lib/hexapdf/content/parser.rb +2 -2
  33. data/lib/hexapdf/content/processor.rb +15 -15
  34. data/lib/hexapdf/content/transformation_matrix.rb +1 -1
  35. data/lib/hexapdf/content.rb +5 -0
  36. data/lib/hexapdf/dictionary.rb +6 -5
  37. data/lib/hexapdf/dictionary_fields.rb +42 -14
  38. data/lib/hexapdf/digital_signature/cms_handler.rb +2 -2
  39. data/lib/hexapdf/digital_signature/handler.rb +1 -1
  40. data/lib/hexapdf/digital_signature/pkcs1_handler.rb +2 -3
  41. data/lib/hexapdf/digital_signature/signature.rb +6 -6
  42. data/lib/hexapdf/digital_signature/signatures.rb +13 -12
  43. data/lib/hexapdf/digital_signature/signing/default_handler.rb +14 -5
  44. data/lib/hexapdf/digital_signature/signing/signed_data_creator.rb +2 -4
  45. data/lib/hexapdf/digital_signature/signing/timestamp_handler.rb +4 -4
  46. data/lib/hexapdf/digital_signature/signing.rb +4 -0
  47. data/lib/hexapdf/digital_signature/verification_result.rb +2 -2
  48. data/lib/hexapdf/digital_signature.rb +7 -2
  49. data/lib/hexapdf/document/destinations.rb +12 -11
  50. data/lib/hexapdf/document/files.rb +1 -1
  51. data/lib/hexapdf/document/fonts.rb +1 -1
  52. data/lib/hexapdf/document/layout.rb +167 -39
  53. data/lib/hexapdf/document/pages.rb +3 -2
  54. data/lib/hexapdf/document.rb +89 -55
  55. data/lib/hexapdf/encryption/aes.rb +5 -5
  56. data/lib/hexapdf/encryption/arc4.rb +1 -1
  57. data/lib/hexapdf/encryption/fast_aes.rb +2 -2
  58. data/lib/hexapdf/encryption/fast_arc4.rb +1 -1
  59. data/lib/hexapdf/encryption/identity.rb +1 -1
  60. data/lib/hexapdf/encryption/ruby_aes.rb +1 -1
  61. data/lib/hexapdf/encryption/ruby_arc4.rb +1 -1
  62. data/lib/hexapdf/encryption/security_handler.rb +31 -24
  63. data/lib/hexapdf/encryption/standard_security_handler.rb +45 -36
  64. data/lib/hexapdf/encryption.rb +7 -2
  65. data/lib/hexapdf/error.rb +18 -0
  66. data/lib/hexapdf/filter/ascii85_decode.rb +1 -1
  67. data/lib/hexapdf/filter/ascii_hex_decode.rb +1 -1
  68. data/lib/hexapdf/filter/flate_decode.rb +1 -1
  69. data/lib/hexapdf/filter/lzw_decode.rb +1 -1
  70. data/lib/hexapdf/filter/pass_through.rb +1 -1
  71. data/lib/hexapdf/filter/predictor.rb +1 -1
  72. data/lib/hexapdf/filter/run_length_decode.rb +1 -1
  73. data/lib/hexapdf/filter.rb +55 -6
  74. data/lib/hexapdf/font/cmap/parser.rb +2 -2
  75. data/lib/hexapdf/font/cmap.rb +1 -1
  76. data/lib/hexapdf/font/encoding/difference_encoding.rb +1 -1
  77. data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +1 -1
  78. data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +2 -2
  79. data/lib/hexapdf/font/encoding/standard_encoding.rb +1 -1
  80. data/lib/hexapdf/font/encoding/symbol_encoding.rb +1 -1
  81. data/lib/hexapdf/font/encoding/win_ansi_encoding.rb +3 -3
  82. data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +1 -1
  83. data/lib/hexapdf/font/invalid_glyph.rb +3 -0
  84. data/lib/hexapdf/font/true_type_wrapper.rb +17 -4
  85. data/lib/hexapdf/font/type1_wrapper.rb +19 -4
  86. data/lib/hexapdf/font_loader/from_configuration.rb +5 -2
  87. data/lib/hexapdf/font_loader/from_file.rb +5 -5
  88. data/lib/hexapdf/font_loader/standard14.rb +3 -3
  89. data/lib/hexapdf/font_loader.rb +3 -0
  90. data/lib/hexapdf/image_loader/jpeg.rb +2 -2
  91. data/lib/hexapdf/image_loader/pdf.rb +1 -1
  92. data/lib/hexapdf/image_loader/png.rb +2 -2
  93. data/lib/hexapdf/image_loader.rb +1 -1
  94. data/lib/hexapdf/importer.rb +13 -0
  95. data/lib/hexapdf/layout/box.rb +9 -2
  96. data/lib/hexapdf/layout/box_fitter.rb +2 -2
  97. data/lib/hexapdf/layout/column_box.rb +18 -4
  98. data/lib/hexapdf/layout/frame.rb +30 -12
  99. data/lib/hexapdf/layout/image_box.rb +5 -0
  100. data/lib/hexapdf/layout/inline_box.rb +1 -0
  101. data/lib/hexapdf/layout/list_box.rb +17 -1
  102. data/lib/hexapdf/layout/page_style.rb +4 -4
  103. data/lib/hexapdf/layout/style.rb +18 -3
  104. data/lib/hexapdf/layout/table_box.rb +682 -0
  105. data/lib/hexapdf/layout/text_box.rb +5 -3
  106. data/lib/hexapdf/layout/text_fragment.rb +1 -1
  107. data/lib/hexapdf/layout/text_layouter.rb +12 -4
  108. data/lib/hexapdf/layout.rb +1 -0
  109. data/lib/hexapdf/name_tree_node.rb +1 -1
  110. data/lib/hexapdf/number_tree_node.rb +1 -1
  111. data/lib/hexapdf/object.rb +18 -7
  112. data/lib/hexapdf/parser.rb +7 -7
  113. data/lib/hexapdf/pdf_array.rb +1 -1
  114. data/lib/hexapdf/rectangle.rb +1 -1
  115. data/lib/hexapdf/reference.rb +1 -1
  116. data/lib/hexapdf/revision.rb +1 -1
  117. data/lib/hexapdf/revisions.rb +3 -3
  118. data/lib/hexapdf/serializer.rb +15 -15
  119. data/lib/hexapdf/stream.rb +4 -2
  120. data/lib/hexapdf/tokenizer.rb +14 -14
  121. data/lib/hexapdf/type/acro_form/appearance_generator.rb +22 -22
  122. data/lib/hexapdf/type/acro_form/button_field.rb +1 -1
  123. data/lib/hexapdf/type/acro_form/choice_field.rb +1 -1
  124. data/lib/hexapdf/type/acro_form/field.rb +2 -2
  125. data/lib/hexapdf/type/acro_form/form.rb +1 -1
  126. data/lib/hexapdf/type/acro_form/signature_field.rb +4 -4
  127. data/lib/hexapdf/type/acro_form/text_field.rb +1 -1
  128. data/lib/hexapdf/type/acro_form/variable_text_field.rb +1 -1
  129. data/lib/hexapdf/type/acro_form.rb +1 -1
  130. data/lib/hexapdf/type/action.rb +1 -1
  131. data/lib/hexapdf/type/actions/go_to.rb +1 -1
  132. data/lib/hexapdf/type/actions/go_to_r.rb +1 -1
  133. data/lib/hexapdf/type/actions/launch.rb +1 -1
  134. data/lib/hexapdf/type/actions/uri.rb +1 -1
  135. data/lib/hexapdf/type/actions.rb +1 -1
  136. data/lib/hexapdf/type/annotation.rb +3 -3
  137. data/lib/hexapdf/type/annotations/link.rb +1 -1
  138. data/lib/hexapdf/type/annotations/markup_annotation.rb +1 -1
  139. data/lib/hexapdf/type/annotations/text.rb +1 -1
  140. data/lib/hexapdf/type/annotations/widget.rb +2 -2
  141. data/lib/hexapdf/type/annotations.rb +1 -1
  142. data/lib/hexapdf/type/catalog.rb +1 -1
  143. data/lib/hexapdf/type/cid_font.rb +3 -3
  144. data/lib/hexapdf/type/embedded_file.rb +1 -1
  145. data/lib/hexapdf/type/file_specification.rb +2 -2
  146. data/lib/hexapdf/type/font_descriptor.rb +1 -1
  147. data/lib/hexapdf/type/font_simple.rb +2 -2
  148. data/lib/hexapdf/type/font_type0.rb +3 -3
  149. data/lib/hexapdf/type/font_type3.rb +1 -1
  150. data/lib/hexapdf/type/form.rb +1 -1
  151. data/lib/hexapdf/type/graphics_state_parameter.rb +1 -1
  152. data/lib/hexapdf/type/icon_fit.rb +1 -1
  153. data/lib/hexapdf/type/image.rb +1 -1
  154. data/lib/hexapdf/type/info.rb +1 -1
  155. data/lib/hexapdf/type/mark_information.rb +1 -1
  156. data/lib/hexapdf/type/names.rb +2 -2
  157. data/lib/hexapdf/type/object_stream.rb +2 -1
  158. data/lib/hexapdf/type/outline.rb +1 -1
  159. data/lib/hexapdf/type/outline_item.rb +1 -1
  160. data/lib/hexapdf/type/page.rb +19 -10
  161. data/lib/hexapdf/type/page_label.rb +1 -1
  162. data/lib/hexapdf/type/page_tree_node.rb +1 -1
  163. data/lib/hexapdf/type/resources.rb +1 -1
  164. data/lib/hexapdf/type/trailer.rb +2 -2
  165. data/lib/hexapdf/type/viewer_preferences.rb +1 -1
  166. data/lib/hexapdf/type/xref_stream.rb +2 -2
  167. data/lib/hexapdf/utils/pdf_doc_encoding.rb +1 -1
  168. data/lib/hexapdf/version.rb +1 -1
  169. data/lib/hexapdf/writer.rb +4 -4
  170. data/lib/hexapdf/xref_section.rb +2 -2
  171. data/test/hexapdf/content/graphic_object/test_endpoint_arc.rb +11 -1
  172. data/test/hexapdf/content/graphic_object/test_geom2d.rb +7 -0
  173. data/test/hexapdf/content/test_canvas.rb +0 -1
  174. data/test/hexapdf/digital_signature/test_signatures.rb +22 -0
  175. data/test/hexapdf/document/test_files.rb +2 -2
  176. data/test/hexapdf/document/test_layout.rb +98 -0
  177. data/test/hexapdf/encryption/test_security_handler.rb +12 -11
  178. data/test/hexapdf/encryption/test_standard_security_handler.rb +35 -23
  179. data/test/hexapdf/font/test_true_type_wrapper.rb +18 -1
  180. data/test/hexapdf/font/test_type1_wrapper.rb +15 -1
  181. data/test/hexapdf/layout/test_box.rb +1 -1
  182. data/test/hexapdf/layout/test_column_box.rb +65 -21
  183. data/test/hexapdf/layout/test_frame.rb +14 -14
  184. data/test/hexapdf/layout/test_image_box.rb +4 -0
  185. data/test/hexapdf/layout/test_inline_box.rb +5 -0
  186. data/test/hexapdf/layout/test_list_box.rb +40 -6
  187. data/test/hexapdf/layout/test_page_style.rb +3 -2
  188. data/test/hexapdf/layout/test_style.rb +50 -0
  189. data/test/hexapdf/layout/test_table_box.rb +722 -0
  190. data/test/hexapdf/layout/test_text_box.rb +18 -0
  191. data/test/hexapdf/layout/test_text_layouter.rb +4 -0
  192. data/test/hexapdf/test_dictionary_fields.rb +4 -1
  193. data/test/hexapdf/test_document.rb +1 -0
  194. data/test/hexapdf/test_filter.rb +8 -0
  195. data/test/hexapdf/test_importer.rb +9 -0
  196. data/test/hexapdf/test_object.rb +16 -5
  197. data/test/hexapdf/test_stream.rb +7 -0
  198. data/test/hexapdf/test_writer.rb +3 -3
  199. data/test/hexapdf/type/acro_form/test_appearance_generator.rb +13 -5
  200. data/test/hexapdf/type/acro_form/test_form.rb +4 -3
  201. data/test/hexapdf/type/test_page.rb +18 -4
  202. metadata +17 -8
@@ -11,7 +11,7 @@ describe HexaPDF::Layout::Frame do
11
11
  canvas = doc.pages.add.canvas
12
12
  box = HexaPDF::Layout::Box.create(width: 20, height: 20) {}
13
13
  result = HexaPDF::Layout::Frame::FitResult.new(box)
14
- result.mask = Geom2D::Polygon([0, 0], [0, 20], [20, 20], [20, 0])
14
+ result.mask = Geom2D::Rectangle(0, 0, 20, 20)
15
15
  result.x = result.y = 0
16
16
  result.draw(canvas)
17
17
  assert_equal(<<~CONTENTS, canvas.contents)
@@ -19,11 +19,7 @@ describe HexaPDF::Layout::Frame do
19
19
  0.0 0.501961 0.0 rg
20
20
  0.0 0.392157 0.0 RG
21
21
  /GS1 gs
22
- 0 0 m
23
- 0 20 l
24
- 20 20 l
25
- 20 0 l
26
- h
22
+ 0 0 20 20 re
27
23
  B
28
24
  Q
29
25
  q
@@ -90,7 +86,11 @@ describe HexaPDF::Layout::Frame do
90
86
  refute_nil(fit_result)
91
87
  @frame.draw(@canvas, fit_result)
92
88
  assert_equal(mask, fit_result.mask.bbox.to_a)
93
- assert_equal(points, @frame.shape.polygons.map(&:to_a))
89
+ if @frame.shape.respond_to?(:polygons)
90
+ assert_equal(points, @frame.shape.polygons.map(&:to_a))
91
+ else
92
+ assert_equal(points, [@frame.shape.to_a])
93
+ end
94
94
  @canvas.verify
95
95
  end
96
96
 
@@ -99,9 +99,9 @@ describe HexaPDF::Layout::Frame do
99
99
  areas.each do |area|
100
100
  @frame.remove_area(
101
101
  case area
102
- when :left then Geom2D::Polygon([10, 10], [10, 110], [20, 110], [20, 10])
103
- when :right then Geom2D::Polygon([100, 10], [100, 110], [110, 110], [110, 10])
104
- when :top then Geom2D::Polygon([10, 110], [110, 110], [110, 100], [10, 100])
102
+ when :left then Geom2D::Rectangle(10, 10, 10, 100)
103
+ when :right then Geom2D::Rectangle(100, 10, 10, 100)
104
+ when :top then Geom2D::Rectangle(10, 100, 100, 10)
105
105
  end
106
106
  )
107
107
  end
@@ -323,7 +323,7 @@ describe HexaPDF::Layout::Frame do
323
323
  end
324
324
 
325
325
  it "can't fit the box if there is no available space" do
326
- @frame.remove_area(Geom2D::Polygon([0, 0], [110, 0], [110, 110], [0, 110]))
326
+ @frame.remove_area(Geom2D::Rectangle(0, 0, 110, 110))
327
327
  box = HexaPDF::Layout::Box.create
328
328
  refute(@frame.fit(box).success?)
329
329
  end
@@ -388,7 +388,7 @@ describe HexaPDF::Layout::Frame do
388
388
  # +--------+
389
389
  it "works for a region with a hole" do
390
390
  frame = HexaPDF::Layout::Frame.new(0, 0, 100, 100)
391
- frame.remove_area(Geom2D::Polygon([20, 20], [80, 20], [80, 80], [20, 80]))
391
+ frame.remove_area(Geom2D::Rectangle(20, 20, 60, 60))
392
392
  check_regions(frame, [[0, 100, 100, 20], [0, 100, 20, 100],
393
393
  [0, 80, 20, 80], [0, 20, 100, 20]])
394
394
  end
@@ -400,7 +400,7 @@ describe HexaPDF::Layout::Frame do
400
400
  # +--------+
401
401
  it "works for a u-shaped frame" do
402
402
  frame = HexaPDF::Layout::Frame.new(0, 0, 100, 100)
403
- frame.remove_area(Geom2D::Polygon([30, 100], [70, 100], [70, 60], [30, 60]))
403
+ frame.remove_area(Geom2D::Rectangle(30, 60, 40, 40))
404
404
  check_regions(frame, [[0, 100, 30, 100], [0, 60, 100, 60]])
405
405
  end
406
406
 
@@ -415,7 +415,7 @@ describe HexaPDF::Layout::Frame do
415
415
  it "works for a complicated frame" do
416
416
  frame = HexaPDF::Layout::Frame.new(0, 0, 100, 100)
417
417
  top_cut = Geom2D::Polygon([20, 100], [20, 80], [40, 80], [40, 90], [60, 90], [60, 100])
418
- left_cut = Geom2D::Polygon([0, 20], [30, 20], [30, 40], [0, 40])
418
+ left_cut = Geom2D::Rectangle(0, 20, 30, 20)
419
419
  frame.remove_area(Geom2D::PolygonSet(top_cut, left_cut))
420
420
 
421
421
  check_regions(frame, [[0, 100, 20, 60], [0, 90, 20, 50], [0, 80, 100, 40],
@@ -56,6 +56,10 @@ describe HexaPDF::Layout::ImageBox do
56
56
  end
57
57
  end
58
58
 
59
+ it "always returns false for empty?" do
60
+ refute(create_box.empty?)
61
+ end
62
+
59
63
  describe "draw" do
60
64
  it "draws the image" do
61
65
  box = create_box(height: 40, style: {padding: [10, 4, 6, 2]})
@@ -30,6 +30,11 @@ describe HexaPDF::Layout::InlineBox do
30
30
  assert_equal(45, ibox.height)
31
31
  end
32
32
 
33
+ it "fails if the wrapped box has not width set" do
34
+ box = HexaPDF::Document.new.layout.text("test is not going good")
35
+ assert_raises(HexaPDF::Error) { inline_box(box) }
36
+ end
37
+
33
38
  it "fails if the wrapped box could not be fit" do
34
39
  box = HexaPDF::Document.new.layout.text("test is not going good", width: 1)
35
40
  assert_raises(HexaPDF::Error) { inline_box(box) }
@@ -18,7 +18,7 @@ describe HexaPDF::Layout::ListBox do
18
18
  end
19
19
 
20
20
  def check_box(box, width, height, fit_pos = nil)
21
- assert(box.fit(@frame.available_width, @frame.available_height, @frame), "box fit?")
21
+ assert(box.fit(@frame.available_width, @frame.available_height, @frame), "box didn't fit")
22
22
  assert_equal(width, box.width, "box width")
23
23
  assert_equal(height, box.height, "box height")
24
24
  if fit_pos
@@ -47,6 +47,18 @@ describe HexaPDF::Layout::ListBox do
47
47
  end
48
48
  end
49
49
 
50
+ describe "empty?" do
51
+ it "is empty if nothing was fit yet" do
52
+ assert(create_box.empty?)
53
+ end
54
+
55
+ it "is empty if nothing could be fit" do
56
+ box = create_box(children: [@text_boxes[0]], width: 5)
57
+ box.fit(@frame.available_width, @frame.available_height, @frame)
58
+ assert(create_box.empty?)
59
+ end
60
+ end
61
+
50
62
  describe "fit" do
51
63
  [:default, :flow].each do |position|
52
64
  it "respects the set initial width, position #{position}" do
@@ -123,7 +135,7 @@ describe HexaPDF::Layout::ListBox do
123
135
  it "draws the result" do
124
136
  box = create_box(children: @fixed_size_boxes[0, 2])
125
137
  box.fit(100, 100, @frame)
126
- box.draw(@canvas, 0, 0)
138
+ box.draw(@canvas, 0, 100 - box.height)
127
139
  operators = [
128
140
  [:save_graphics_state],
129
141
  [:set_font_and_size, [:F1, 10]],
@@ -153,7 +165,7 @@ describe HexaPDF::Layout::ListBox do
153
165
  it "draws a cicle as marker" do
154
166
  box = create_box(children: @fixed_size_boxes[0, 1], item_type: :circle)
155
167
  box.fit(100, 100, @frame)
156
- box.draw(@canvas, 0, 0)
168
+ box.draw(@canvas, 0, 100 - box.height)
157
169
  operators = [
158
170
  [:save_graphics_state],
159
171
  [:set_font_and_size, [:F1, 5]],
@@ -173,7 +185,7 @@ describe HexaPDF::Layout::ListBox do
173
185
  it "draws a square as marker" do
174
186
  box = create_box(children: @fixed_size_boxes[0, 1], item_type: :square)
175
187
  box.fit(100, 100, @frame)
176
- box.draw(@canvas, 0, 0)
188
+ box.draw(@canvas, 0, 100 - box.height)
177
189
  operators = [
178
190
  [:save_graphics_state],
179
191
  [:set_font_and_size, [:F1, 5]],
@@ -194,7 +206,7 @@ describe HexaPDF::Layout::ListBox do
194
206
  box = create_box(children: @fixed_size_boxes[0, 2], item_type: :decimal,
195
207
  content_indentation: 20)
196
208
  box.fit(100, 100, @frame)
197
- box.draw(@canvas, 0, 0)
209
+ box.draw(@canvas, 0, 100 - box.height)
198
210
  operators = [
199
211
  [:save_graphics_state],
200
212
  [:set_font_and_size, [:F1, 10]],
@@ -227,7 +239,7 @@ describe HexaPDF::Layout::ListBox do
227
239
  end
228
240
  box = create_box(children: @fixed_size_boxes[0, 1], item_type: marker)
229
241
  box.fit(100, 100, @frame)
230
- box.draw(@canvas, 0, 0)
242
+ box.draw(@canvas, 0, 100 - box.height)
231
243
  operators = [
232
244
  [:save_graphics_state],
233
245
  [:concatenate_matrix, [1, 0, 0, 1, 0, 90]],
@@ -239,6 +251,28 @@ describe HexaPDF::Layout::ListBox do
239
251
  assert_operators(@canvas.contents, operators)
240
252
  end
241
253
 
254
+ it "takes a different final location into account" do
255
+ box = create_box(children: @fixed_size_boxes[0, 1])
256
+ box.fit(100, 100, @frame)
257
+ box.draw(@canvas, 20, 10)
258
+ operators = [
259
+ [:save_graphics_state],
260
+ [:concatenate_matrix, [1, 0, 0, 1, 20, -80]],
261
+ [:save_graphics_state],
262
+ [:set_font_and_size, [:F1, 10]],
263
+ [:begin_text],
264
+ [:set_text_matrix, [1, 0, 0, 1, 1.5, 93.17]],
265
+ [:show_text, ["\x95".b]],
266
+ [:end_text],
267
+ [:restore_graphics_state],
268
+ [:save_graphics_state],
269
+ [:concatenate_matrix, [1, 0, 0, 1, 10, 90]],
270
+ [:restore_graphics_state],
271
+ [:restore_graphics_state],
272
+ ]
273
+ assert_operators(@canvas.contents, operators)
274
+ end
275
+
242
276
  it "fails for unknown item types" do
243
277
  box = create_box(children: @fixed_size_boxes[0, 1], item_type: :unknown)
244
278
  box.fit(100, 100, @frame)
@@ -5,11 +5,12 @@ require 'hexapdf/layout/page_style'
5
5
  require 'hexapdf/document'
6
6
 
7
7
  describe HexaPDF::Layout::PageStyle do
8
- it "allows assigning the page size, orientation and template on initialization" do
8
+ it "allows assigning the page size, orientation, next style and template on initialization" do
9
9
  block = lambda {}
10
- style = HexaPDF::Layout::PageStyle.new(page_size: :A3, orientation: :landscape, &block)
10
+ style = HexaPDF::Layout::PageStyle.new(page_size: :A3, orientation: :landscape, next_style: :a, &block)
11
11
  assert_equal(:A3, style.page_size)
12
12
  assert_equal(:landscape, style.orientation)
13
+ assert_equal(:a, style.next_style)
13
14
  assert_same(block, style.template)
14
15
  end
15
16
 
@@ -156,15 +156,24 @@ describe HexaPDF::Layout::Style::Border do
156
156
  assert_kind_of(HexaPDF::Layout::Style::Quad, border.style)
157
157
  end
158
158
 
159
+ it "has an accessor for the draw-on-bounds option" do
160
+ border = create_border
161
+ refute(border.draw_on_bounds)
162
+ border.draw_on_bounds = true
163
+ assert(border.draw_on_bounds)
164
+ end
165
+
159
166
  it "can be duplicated" do
160
167
  border = create_border
161
168
  copy = border.dup
162
169
  border.width.top = 10
163
170
  border.color.top = :red
164
171
  border.style.top = :dotted
172
+ border.draw_on_bounds = true
165
173
  assert_equal(0, copy.width.top)
166
174
  assert_equal(0, copy.color.top)
167
175
  assert_equal(:solid, copy.style.top)
176
+ refute(copy.draw_on_bounds)
168
177
  end
169
178
 
170
179
  it "can be asked whether a border is defined" do
@@ -259,6 +268,19 @@ describe HexaPDF::Layout::Style::Border do
259
268
  [:restore_graphics_state]]
260
269
  assert_operators(@canvas.contents, ops)
261
270
  end
271
+
272
+ it "works if the border is drawn on the bounds" do
273
+ border = create_border(width: 10, color: 0.5, style: :solid, draw_on_bounds: true)
274
+ border.draw(@canvas, 0, 0, 100, 100)
275
+ assert_operators(@canvas.contents, [[:save_graphics_state],
276
+ [:set_device_gray_stroking_color, [0.5]],
277
+ [:set_line_width, [10]],
278
+ [:append_rectangle, [-5, -5, 110, 110]],
279
+ [:clip_path_non_zero], [:end_path],
280
+ [:append_rectangle, [0, 0, 100, 100]],
281
+ [:stroke_path],
282
+ [:restore_graphics_state]])
283
+ end
262
284
  end
263
285
 
264
286
  describe "complex borders where edges have different width/color/style values" do
@@ -369,6 +391,34 @@ describe HexaPDF::Layout::Style::Border do
369
391
  [:restore_graphics_state], [:restore_graphics_state]]
370
392
  assert_operators(@canvas.contents, ops)
371
393
  end
394
+
395
+ it "works if the border is drawn on the bounds" do
396
+ border = create_border(width: [20, 10, 40, 30], draw_on_bounds: true)
397
+ border.draw(@canvas, 0, 0, 100, 200)
398
+ ops = [[:save_graphics_state],
399
+ [:save_graphics_state],
400
+ [:move_to, [-15, 210]], [:line_to, [105, 210]],
401
+ [:line_to, [95, 190]], [:line_to, [15, 190]], [:clip_path_non_zero], [:end_path],
402
+ [:set_line_width, [20]],
403
+ [:move_to, [-15, 200]], [:line_to, [105, 200]], [:stroke_path],
404
+ [:restore_graphics_state], [:save_graphics_state],
405
+ [:move_to, [105, 210]], [:line_to, [105, -20]],
406
+ [:line_to, [95, 20]], [:line_to, [95, 190]], [:clip_path_non_zero], [:end_path],
407
+ [:set_line_width, [10]],
408
+ [:move_to, [100, 210]], [:line_to, [100, -20]], [:stroke_path],
409
+ [:restore_graphics_state], [:save_graphics_state],
410
+ [:move_to, [105, -20]], [:line_to, [-15, -20]],
411
+ [:line_to, [15, 20]], [:line_to, [95, 20]], [:clip_path_non_zero], [:end_path],
412
+ [:set_line_width, [40]],
413
+ [:move_to, [105, 0]], [:line_to, [-15, 0]], [:stroke_path],
414
+ [:restore_graphics_state], [:save_graphics_state],
415
+ [:move_to, [-15, -20]], [:line_to, [-15, 210]],
416
+ [:line_to, [15, 190]], [:line_to, [15, 20]], [:clip_path_non_zero], [:end_path],
417
+ [:set_line_width, [30]],
418
+ [:move_to, [0, -20]], [:line_to, [0, 210]], [:stroke_path],
419
+ [:restore_graphics_state], [:restore_graphics_state]]
420
+ assert_operators(@canvas.contents, ops)
421
+ end
372
422
  end
373
423
 
374
424
  describe "border width greater than edge length" do