hexapdf 0.6.0 → 0.7.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 (257) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +33 -0
  3. data/CONTRIBUTERS +1 -1
  4. data/LICENSE +1 -1
  5. data/Rakefile +1 -1
  6. data/VERSION +1 -1
  7. data/bin/hexapdf +1 -1
  8. data/examples/text_layouter_styling.rb +1 -2
  9. data/lib/hexapdf.rb +2 -2
  10. data/lib/hexapdf/cli.rb +3 -3
  11. data/lib/hexapdf/cli/batch.rb +5 -5
  12. data/lib/hexapdf/cli/command.rb +15 -17
  13. data/lib/hexapdf/cli/files.rb +3 -3
  14. data/lib/hexapdf/cli/images.rb +3 -4
  15. data/lib/hexapdf/cli/info.rb +5 -5
  16. data/lib/hexapdf/cli/inspect.rb +6 -6
  17. data/lib/hexapdf/cli/merge.rb +6 -6
  18. data/lib/hexapdf/cli/modify.rb +4 -4
  19. data/lib/hexapdf/cli/optimize.rb +3 -3
  20. data/lib/hexapdf/configuration.rb +4 -5
  21. data/lib/hexapdf/content.rb +2 -2
  22. data/lib/hexapdf/content/canvas.rb +35 -36
  23. data/lib/hexapdf/content/color_space.rb +9 -14
  24. data/lib/hexapdf/content/graphic_object.rb +2 -2
  25. data/lib/hexapdf/content/graphic_object/arc.rb +3 -3
  26. data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +2 -2
  27. data/lib/hexapdf/content/graphic_object/solid_arc.rb +4 -8
  28. data/lib/hexapdf/content/graphics_state.rb +4 -13
  29. data/lib/hexapdf/content/operator.rb +33 -35
  30. data/lib/hexapdf/content/parser.rb +28 -18
  31. data/lib/hexapdf/content/processor.rb +4 -5
  32. data/lib/hexapdf/content/transformation_matrix.rb +2 -2
  33. data/lib/hexapdf/data_dir.rb +2 -2
  34. data/lib/hexapdf/dictionary.rb +8 -9
  35. data/lib/hexapdf/dictionary_fields.rb +7 -10
  36. data/lib/hexapdf/document.rb +18 -18
  37. data/lib/hexapdf/document/files.rb +12 -10
  38. data/lib/hexapdf/document/fonts.rb +2 -2
  39. data/lib/hexapdf/document/images.rb +3 -3
  40. data/lib/hexapdf/document/pages.rb +4 -4
  41. data/lib/hexapdf/encryption.rb +2 -2
  42. data/lib/hexapdf/encryption/aes.rb +2 -2
  43. data/lib/hexapdf/encryption/arc4.rb +4 -4
  44. data/lib/hexapdf/encryption/fast_aes.rb +2 -2
  45. data/lib/hexapdf/encryption/fast_arc4.rb +4 -4
  46. data/lib/hexapdf/encryption/identity.rb +5 -4
  47. data/lib/hexapdf/encryption/ruby_aes.rb +147 -139
  48. data/lib/hexapdf/encryption/ruby_arc4.rb +4 -4
  49. data/lib/hexapdf/encryption/security_handler.rb +11 -12
  50. data/lib/hexapdf/encryption/standard_security_handler.rb +6 -9
  51. data/lib/hexapdf/error.rb +7 -9
  52. data/lib/hexapdf/filter.rb +2 -3
  53. data/lib/hexapdf/filter/ascii85_decode.rb +3 -3
  54. data/lib/hexapdf/filter/ascii_hex_decode.rb +2 -2
  55. data/lib/hexapdf/filter/dct_decode.rb +2 -2
  56. data/lib/hexapdf/filter/encryption.rb +2 -2
  57. data/lib/hexapdf/filter/flate_decode.rb +16 -33
  58. data/lib/hexapdf/filter/jpx_decode.rb +2 -2
  59. data/lib/hexapdf/filter/lzw_decode.rb +4 -4
  60. data/lib/hexapdf/filter/predictor.rb +2 -6
  61. data/lib/hexapdf/filter/run_length_decode.rb +2 -2
  62. data/lib/hexapdf/font/cmap.rb +2 -3
  63. data/lib/hexapdf/font/cmap/parser.rb +11 -11
  64. data/lib/hexapdf/font/cmap/writer.rb +25 -25
  65. data/lib/hexapdf/font/encoding.rb +2 -2
  66. data/lib/hexapdf/font/encoding/base.rb +2 -2
  67. data/lib/hexapdf/font/encoding/difference_encoding.rb +2 -2
  68. data/lib/hexapdf/font/encoding/glyph_list.rb +6 -6
  69. data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +2 -2
  70. data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +2 -2
  71. data/lib/hexapdf/font/encoding/standard_encoding.rb +2 -2
  72. data/lib/hexapdf/font/encoding/symbol_encoding.rb +2 -2
  73. data/lib/hexapdf/font/encoding/win_ansi_encoding.rb +2 -2
  74. data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +2 -2
  75. data/lib/hexapdf/font/invalid_glyph.rb +7 -7
  76. data/lib/hexapdf/font/true_type.rb +2 -2
  77. data/lib/hexapdf/font/true_type/builder.rb +13 -7
  78. data/lib/hexapdf/font/true_type/font.rb +2 -3
  79. data/lib/hexapdf/font/true_type/optimizer.rb +2 -2
  80. data/lib/hexapdf/font/true_type/subsetter.rb +4 -4
  81. data/lib/hexapdf/font/true_type/table.rb +3 -5
  82. data/lib/hexapdf/font/true_type/table/cmap.rb +2 -2
  83. data/lib/hexapdf/font/true_type/table/cmap_subtable.rb +9 -16
  84. data/lib/hexapdf/font/true_type/table/directory.rb +4 -4
  85. data/lib/hexapdf/font/true_type/table/glyf.rb +2 -2
  86. data/lib/hexapdf/font/true_type/table/head.rb +3 -2
  87. data/lib/hexapdf/font/true_type/table/hhea.rb +2 -2
  88. data/lib/hexapdf/font/true_type/table/hmtx.rb +2 -2
  89. data/lib/hexapdf/font/true_type/table/kern.rb +3 -3
  90. data/lib/hexapdf/font/true_type/table/loca.rb +3 -3
  91. data/lib/hexapdf/font/true_type/table/maxp.rb +2 -2
  92. data/lib/hexapdf/font/true_type/table/name.rb +3 -5
  93. data/lib/hexapdf/font/true_type/table/os2.rb +4 -3
  94. data/lib/hexapdf/font/true_type/table/post.rb +3 -7
  95. data/lib/hexapdf/font/true_type_wrapper.rb +20 -22
  96. data/lib/hexapdf/font/type1.rb +2 -2
  97. data/lib/hexapdf/font/type1/afm_parser.rb +7 -7
  98. data/lib/hexapdf/font/type1/character_metrics.rb +2 -2
  99. data/lib/hexapdf/font/type1/font.rb +3 -3
  100. data/lib/hexapdf/font/type1/font_metrics.rb +2 -4
  101. data/lib/hexapdf/font/type1/pfb_parser.rb +2 -2
  102. data/lib/hexapdf/font/type1_wrapper.rb +8 -9
  103. data/lib/hexapdf/font_loader.rb +2 -2
  104. data/lib/hexapdf/font_loader/from_configuration.rb +2 -2
  105. data/lib/hexapdf/font_loader/from_file.rb +2 -2
  106. data/lib/hexapdf/font_loader/standard14.rb +2 -2
  107. data/lib/hexapdf/image_loader.rb +2 -2
  108. data/lib/hexapdf/image_loader/jpeg.rb +6 -4
  109. data/lib/hexapdf/image_loader/pdf.rb +2 -2
  110. data/lib/hexapdf/image_loader/png.rb +6 -6
  111. data/lib/hexapdf/importer.rb +6 -4
  112. data/lib/hexapdf/layout.rb +2 -2
  113. data/lib/hexapdf/layout/box.rb +4 -4
  114. data/lib/hexapdf/layout/inline_box.rb +2 -2
  115. data/lib/hexapdf/layout/line.rb +6 -6
  116. data/lib/hexapdf/layout/numeric_refinements.rb +2 -2
  117. data/lib/hexapdf/layout/style.rb +17 -8
  118. data/lib/hexapdf/layout/text_fragment.rb +86 -48
  119. data/lib/hexapdf/layout/text_layouter.rb +40 -21
  120. data/lib/hexapdf/layout/text_shaper.rb +2 -2
  121. data/lib/hexapdf/name_tree_node.rb +2 -2
  122. data/lib/hexapdf/number_tree_node.rb +2 -2
  123. data/lib/hexapdf/object.rb +6 -8
  124. data/lib/hexapdf/parser.rb +10 -10
  125. data/lib/hexapdf/rectangle.rb +4 -4
  126. data/lib/hexapdf/reference.rb +2 -2
  127. data/lib/hexapdf/revision.rb +4 -4
  128. data/lib/hexapdf/revisions.rb +5 -5
  129. data/lib/hexapdf/serializer.rb +27 -24
  130. data/lib/hexapdf/stream.rb +4 -4
  131. data/lib/hexapdf/task.rb +2 -2
  132. data/lib/hexapdf/task/dereference.rb +4 -4
  133. data/lib/hexapdf/task/optimize.rb +5 -4
  134. data/lib/hexapdf/tokenizer.rb +12 -14
  135. data/lib/hexapdf/type.rb +2 -2
  136. data/lib/hexapdf/type/action.rb +3 -3
  137. data/lib/hexapdf/type/actions.rb +2 -2
  138. data/lib/hexapdf/type/actions/go_to.rb +2 -2
  139. data/lib/hexapdf/type/actions/go_to_r.rb +2 -2
  140. data/lib/hexapdf/type/actions/launch.rb +2 -2
  141. data/lib/hexapdf/type/actions/uri.rb +3 -3
  142. data/lib/hexapdf/type/annotation.rb +3 -3
  143. data/lib/hexapdf/type/annotations.rb +2 -2
  144. data/lib/hexapdf/type/annotations/link.rb +2 -2
  145. data/lib/hexapdf/type/annotations/markup_annotation.rb +2 -2
  146. data/lib/hexapdf/type/annotations/text.rb +2 -2
  147. data/lib/hexapdf/type/catalog.rb +4 -4
  148. data/lib/hexapdf/type/cid_font.rb +4 -5
  149. data/lib/hexapdf/type/embedded_file.rb +3 -3
  150. data/lib/hexapdf/type/file_specification.rb +6 -7
  151. data/lib/hexapdf/type/font.rb +4 -4
  152. data/lib/hexapdf/type/font_descriptor.rb +3 -4
  153. data/lib/hexapdf/type/font_simple.rb +12 -16
  154. data/lib/hexapdf/type/font_true_type.rb +2 -2
  155. data/lib/hexapdf/type/font_type0.rb +5 -5
  156. data/lib/hexapdf/type/font_type1.rb +4 -4
  157. data/lib/hexapdf/type/form.rb +3 -3
  158. data/lib/hexapdf/type/graphics_state_parameter.rb +3 -3
  159. data/lib/hexapdf/type/image.rb +13 -14
  160. data/lib/hexapdf/type/info.rb +2 -2
  161. data/lib/hexapdf/type/names.rb +2 -2
  162. data/lib/hexapdf/type/object_stream.rb +5 -5
  163. data/lib/hexapdf/type/page.rb +9 -10
  164. data/lib/hexapdf/type/page_tree_node.rb +5 -6
  165. data/lib/hexapdf/type/resources.rb +11 -11
  166. data/lib/hexapdf/type/trailer.rb +3 -3
  167. data/lib/hexapdf/type/viewer_preferences.rb +2 -2
  168. data/lib/hexapdf/type/xref_stream.rb +8 -4
  169. data/lib/hexapdf/utils/bit_field.rb +4 -4
  170. data/lib/hexapdf/utils/bit_stream.rb +4 -4
  171. data/lib/hexapdf/utils/graphics_helpers.rb +2 -2
  172. data/lib/hexapdf/utils/lru_cache.rb +2 -2
  173. data/lib/hexapdf/utils/math_helpers.rb +2 -2
  174. data/lib/hexapdf/utils/object_hash.rb +3 -3
  175. data/lib/hexapdf/utils/pdf_doc_encoding.rb +3 -3
  176. data/lib/hexapdf/utils/sorted_tree_node.rb +12 -11
  177. data/lib/hexapdf/version.rb +3 -3
  178. data/lib/hexapdf/writer.rb +8 -8
  179. data/lib/hexapdf/xref_section.rb +3 -3
  180. data/test/hexapdf/common_tokenizer_tests.rb +6 -7
  181. data/test/hexapdf/content/graphic_object/test_endpoint_arc.rb +0 -1
  182. data/test/hexapdf/content/test_canvas.rb +28 -36
  183. data/test/hexapdf/content/test_color_space.rb +4 -0
  184. data/test/hexapdf/content/test_graphics_state.rb +2 -0
  185. data/test/hexapdf/content/test_operator.rb +6 -7
  186. data/test/hexapdf/content/test_parser.rb +2 -2
  187. data/test/hexapdf/content/test_processor.rb +1 -1
  188. data/test/hexapdf/document/test_files.rb +1 -0
  189. data/test/hexapdf/document/test_images.rb +1 -1
  190. data/test/hexapdf/encryption/common.rb +3 -3
  191. data/test/hexapdf/encryption/test_aes.rb +10 -4
  192. data/test/hexapdf/encryption/test_identity.rb +1 -1
  193. data/test/hexapdf/encryption/test_security_handler.rb +13 -17
  194. data/test/hexapdf/encryption/test_standard_security_handler.rb +12 -12
  195. data/test/hexapdf/filter/test_ascii85_decode.rb +2 -3
  196. data/test/hexapdf/filter/test_ascii_hex_decode.rb +6 -1
  197. data/test/hexapdf/filter/test_flate_decode.rb +2 -2
  198. data/test/hexapdf/filter/test_lzw_decode.rb +10 -10
  199. data/test/hexapdf/filter/test_predictor.rb +10 -2
  200. data/test/hexapdf/filter/test_run_length_decode.rb +1 -1
  201. data/test/hexapdf/font/cmap/test_parser.rb +40 -40
  202. data/test/hexapdf/font/cmap/test_writer.rb +29 -29
  203. data/test/hexapdf/font/test_true_type_wrapper.rb +3 -2
  204. data/test/hexapdf/font/true_type/common.rb +2 -0
  205. data/test/hexapdf/font/true_type/table/test_cmap.rb +1 -1
  206. data/test/hexapdf/font/true_type/table/test_cmap_subtable.rb +5 -4
  207. data/test/hexapdf/font/true_type/table/test_glyf.rb +2 -2
  208. data/test/hexapdf/font/true_type/table/test_head.rb +2 -2
  209. data/test/hexapdf/font/true_type/table/test_name.rb +9 -6
  210. data/test/hexapdf/font/true_type/test_builder.rb +8 -3
  211. data/test/hexapdf/font/true_type/test_optimizer.rb +1 -2
  212. data/test/hexapdf/font/type1/test_afm_parser.rb +2 -2
  213. data/test/hexapdf/image_loader/test_jpeg.rb +1 -1
  214. data/test/hexapdf/image_loader/test_pdf.rb +1 -1
  215. data/test/hexapdf/image_loader/test_png.rb +3 -3
  216. data/test/hexapdf/layout/test_inline_box.rb +10 -1
  217. data/test/hexapdf/layout/test_line.rb +4 -4
  218. data/test/hexapdf/layout/test_style.rb +19 -7
  219. data/test/hexapdf/layout/test_text_fragment.rb +73 -27
  220. data/test/hexapdf/layout/test_text_layouter.rb +84 -68
  221. data/test/hexapdf/layout/test_text_shaper.rb +4 -6
  222. data/test/hexapdf/task/test_dereference.rb +2 -2
  223. data/test/hexapdf/task/test_optimize.rb +16 -7
  224. data/test/hexapdf/test_configuration.rb +1 -1
  225. data/test/hexapdf/test_data_dir.rb +2 -2
  226. data/test/hexapdf/test_dictionary.rb +6 -3
  227. data/test/hexapdf/test_dictionary_fields.rb +15 -14
  228. data/test/hexapdf/test_document.rb +47 -48
  229. data/test/hexapdf/test_filter.rb +30 -26
  230. data/test/hexapdf/test_importer.rb +14 -0
  231. data/test/hexapdf/test_object.rb +16 -4
  232. data/test/hexapdf/test_parser.rb +36 -36
  233. data/test/hexapdf/test_reference.rb +7 -5
  234. data/test/hexapdf/test_revision.rb +1 -1
  235. data/test/hexapdf/test_revisions.rb +90 -90
  236. data/test/hexapdf/test_serializer.rb +3 -2
  237. data/test/hexapdf/test_stream.rb +2 -4
  238. data/test/hexapdf/test_tokenizer.rb +2 -2
  239. data/test/hexapdf/test_writer.rb +80 -80
  240. data/test/hexapdf/test_xref_section.rb +1 -1
  241. data/test/hexapdf/type/annotations/test_link.rb +1 -1
  242. data/test/hexapdf/type/annotations/test_text.rb +3 -3
  243. data/test/hexapdf/type/test_font_descriptor.rb +1 -1
  244. data/test/hexapdf/type/test_font_simple.rb +2 -2
  245. data/test/hexapdf/type/test_font_type0.rb +0 -1
  246. data/test/hexapdf/type/test_image.rb +0 -3
  247. data/test/hexapdf/type/test_object_stream.rb +2 -1
  248. data/test/hexapdf/type/test_page.rb +5 -1
  249. data/test/hexapdf/type/test_page_tree_node.rb +4 -4
  250. data/test/hexapdf/type/test_trailer.rb +1 -1
  251. data/test/hexapdf/type/test_xref_stream.rb +4 -0
  252. data/test/hexapdf/utils/test_bit_field.rb +2 -0
  253. data/test/hexapdf/utils/test_bit_stream.rb +1 -1
  254. data/test/hexapdf/utils/test_lru_cache.rb +1 -1
  255. data/test/hexapdf/utils/test_sorted_tree_node.rb +10 -4
  256. data/test/test_helper.rb +3 -6
  257. metadata +3 -3
@@ -1,10 +1,10 @@
1
- # -*- encoding: utf-8 -*-
1
+ # -*- encoding: utf-8; frozen_string_literal: true -*-
2
2
  #
3
3
  #--
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2017 Thomas Leitner
7
+ # Copyright (C) 2014-2018 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -113,6 +113,11 @@ module HexaPDF
113
113
  @shrinkability = shrinkability
114
114
  end
115
115
 
116
+ # The width of the item.
117
+ def width
118
+ @item.width
119
+ end
120
+
116
121
  # Returns :glue.
117
122
  def type
118
123
  :glue
@@ -219,38 +224,39 @@ module HexaPDF
219
224
  end
220
225
 
221
226
  # A hyphen belongs to the text fragment
222
- box_items << glyph if glyph && !glyph.kind_of?(Numeric) && glyph.str == '-'.freeze
227
+ box_items << glyph if glyph && !glyph.kind_of?(Numeric) && glyph.str == '-'
223
228
 
224
229
  unless box_items.empty?
225
- result << Box.new(TextFragment.new(items: box_items.freeze, style: item.style))
230
+ result << Box.new(TextFragment.new(box_items.freeze, item.style))
226
231
  end
227
232
 
228
233
  if glyph
229
234
  case glyph.str
230
235
  when ' '
231
236
  glues[item.style] ||=
232
- Glue.new(TextFragment.new(items: [glyph].freeze, style: item.style))
237
+ Glue.new(TextFragment.new([glyph].freeze, item.style))
233
238
  result << glues[item.style]
234
239
  when "\n", "\v", "\f", "\u{85}", "\u{2029}"
235
240
  result << Penalty::MandatoryParagraphBreak
236
241
  when "\u{2028}"
237
242
  result << Penalty::MandatoryLineBreak
238
243
  when "\r"
239
- if item.items[i + 1]&.kind_of?(Numeric) || item.items[i + 1].str != "\n"
244
+ if !item.items[i + 1] || item.items[i + 1].kind_of?(Numeric) ||
245
+ item.items[i + 1].str != "\n"
240
246
  result << Penalty::MandatoryParagraphBreak
241
247
  end
242
248
  when '-'
243
249
  result << Penalty::Standard
244
250
  when "\t"
245
251
  spaces = [item.style.font.decode_utf8(" ").first] * 8
246
- result << Glue.new(TextFragment.new(items: spaces.freeze, style: item.style))
252
+ result << Glue.new(TextFragment.new(spaces.freeze, item.style))
247
253
  when "\u{00AD}"
248
254
  hyphen = item.style.font.decode_utf8("-").first
249
- frag = TextFragment.new(items: [hyphen].freeze, style: item.style)
255
+ frag = TextFragment.new([hyphen].freeze, item.style)
250
256
  result << Penalty.new(Penalty::Standard.penalty, frag.width, item: frag)
251
257
  when "\u{00A0}"
252
258
  space = item.style.font.decode_utf8(" ").first
253
- frag = TextFragment.new(items: [space].freeze, style: item.style)
259
+ frag = TextFragment.new([space].freeze, item.style)
254
260
  result << Penalty.new(Penalty::ProhibitedBreak.penalty, frag.width, item: frag)
255
261
  when "\u{200B}"
256
262
  result << Penalty.new(0)
@@ -358,7 +364,7 @@ module HexaPDF
358
364
  if item_fits_on_line?(item)
359
365
  next_index = index + 1
360
366
  next_item = @items[next_index]
361
- next_item = @items[next_index += 1] while next_item && next_item.type == :penalty
367
+ next_item = @items[next_index += 1] while next_item&.type == :penalty
362
368
  if next_item && !item_fits_on_line?(next_item)
363
369
  @line_items.concat(@glue_items).push(item.item)
364
370
  @width += item.width
@@ -421,7 +427,7 @@ module HexaPDF
421
427
  if item_fits_on_line?(item)
422
428
  next_index = index + 1
423
429
  next_item = @items[next_index]
424
- next_item = @items[n_index += 1] while next_item && next_item.type == :penalty
430
+ next_item = @items[next_index += 1] while next_item&.type == :penalty
425
431
  new_height = @height_calc.simulate_height(next_item.item)
426
432
  if next_item && @width + next_item.width > @width_block.call(new_height)
427
433
  @line_items.concat(@glue_items).push(item.item)
@@ -521,7 +527,6 @@ module HexaPDF
521
527
 
522
528
  end
523
529
 
524
-
525
530
  # Creates a new TextLayouter object for the given text and returns it.
526
531
  #
527
532
  # See ::new for information on +height+.
@@ -622,7 +627,7 @@ module HexaPDF
622
627
  too_wide_box = nil
623
628
 
624
629
  rest = style.text_line_wrapping_algorithm.call(rest, width_block) do |line, item|
625
- line << TextFragment.new(items: [], style: style) if item&.type != :box && line.items.empty?
630
+ line << TextFragment.new([], style) if item&.type != :box && line.items.empty?
626
631
  new_height = @actual_height + line.height +
627
632
  (@lines.empty? ? 0 : style.line_spacing.gap(@lines.last, line))
628
633
 
@@ -667,10 +672,10 @@ module HexaPDF
667
672
  end
668
673
  end
669
674
 
670
- if too_wide_box && too_wide_box.item.kind_of?(TextFragment) &&
671
- too_wide_box.item.items.size > 1
675
+ if too_wide_box && (too_wide_box.item.kind_of?(TextFragment) &&
676
+ too_wide_box.item.items.size > 1)
672
677
  rest[0..rest.index(too_wide_box)] = too_wide_box.item.items.map do |item|
673
- Box.new(TextFragment.new(items: [item], style: too_wide_box.item.style))
678
+ Box.new(TextFragment.new([item], too_wide_box.item.style))
674
679
  end
675
680
  too_wide_box = nil
676
681
  else
@@ -682,6 +687,9 @@ module HexaPDF
682
687
  [rest, reason]
683
688
  end
684
689
 
690
+ # :call-seq:
691
+ # tl.draws(canvas, x, y, fit: :if_needed) -> [remaining_items, reason] or nil
692
+ #
685
693
  # Draws the layed out text onto the canvas with the top-left corner being at [x, y].
686
694
  #
687
695
  # Depending on the value of +fit+ the text may also be fitted:
@@ -689,26 +697,37 @@ module HexaPDF
689
697
  # * If +true+, then #fit is always called.
690
698
  # * If +:if_needed+, then #fit is only called if it has not been called before.
691
699
  # * If +false+, then #fit is never called.
700
+ #
701
+ # If #fit was called, its return value is returned. Otherwise +nil+ is returned.
692
702
  def draw(canvas, x, y, fit: :if_needed)
693
- self.fit if fit == true || (!@actual_height && fit == :if_needed)
694
- return if @lines.empty?
703
+ fit_result = self.fit if fit == true || (!@actual_height && fit == :if_needed)
704
+ return fit_result if @lines.empty?
695
705
 
706
+ last_item = nil
696
707
  canvas.save_graphics_state do
708
+ if @lines.size > 1
709
+ canvas.leading(style.line_spacing.baseline_distance(@lines[0], @lines[1]))
710
+ end
697
711
  y -= initial_baseline_offset + @lines.first.y_offset
698
712
  @lines.each_with_index do |line, index|
699
713
  line_x = x + line.x_offset
700
714
  line.each do |item, item_x, item_y|
701
715
  if item.kind_of?(TextFragment)
702
- item.draw(canvas, line_x + item_x, y + item_y)
716
+ item.draw(canvas, line_x + item_x, y + item_y,
717
+ ignore_text_properties: last_item&.style == item.style)
718
+ last_item = item
703
719
  elsif !item.empty?
704
720
  canvas.restore_graphics_state
705
721
  item.draw(canvas, line_x + item_x, y + item_y)
706
722
  canvas.save_graphics_state
723
+ last_item = nil
707
724
  end
708
725
  end
709
726
  y -= @lines[index + 1].y_offset if @lines[index + 1]
710
727
  end
711
728
  end
729
+
730
+ fit_result
712
731
  end
713
732
 
714
733
  private
@@ -750,7 +769,7 @@ module HexaPDF
750
769
  line.items.each_with_index do |item, item_index|
751
770
  next if item.kind_of?(InlineBox)
752
771
  item.items.each_with_index do |glyph, glyph_index|
753
- if !glyph.kind_of?(Numeric) && glyph.str == ' '.freeze
772
+ if !glyph.kind_of?(Numeric) && glyph.str == ' '
754
773
  sum += glyph.width * item.style.scaled_font_size
755
774
  indexes << item_index << glyph_index
756
775
  end
@@ -764,7 +783,7 @@ module HexaPDF
764
783
  frag = line.items[indexes[i]]
765
784
  value = -frag.items[indexes[i + 1]].width * adjustment
766
785
  if frag.items.frozen?
767
- value = HexaPDF::Layout::TextFragment.new(items: [value], style: frag.style)
786
+ value = HexaPDF::Layout::TextFragment.new([value], frag.style)
768
787
  line.items.insert(indexes[i], value)
769
788
  else
770
789
  frag.items.insert(indexes[i + 1], value)
@@ -1,10 +1,10 @@
1
- # -*- encoding: utf-8 -*-
1
+ # -*- encoding: utf-8; frozen_string_literal: true -*-
2
2
  #
3
3
  #--
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2017 Thomas Leitner
7
+ # Copyright (C) 2014-2018 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -1,10 +1,10 @@
1
- # -*- encoding: utf-8 -*-
1
+ # -*- encoding: utf-8; frozen_string_literal: true -*-
2
2
  #
3
3
  #--
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2017 Thomas Leitner
7
+ # Copyright (C) 2014-2018 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -1,10 +1,10 @@
1
- # -*- encoding: utf-8 -*-
1
+ # -*- encoding: utf-8; frozen_string_literal: true -*-
2
2
  #
3
3
  #--
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2017 Thomas Leitner
7
+ # Copyright (C) 2014-2018 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -1,10 +1,10 @@
1
- # -*- encoding: utf-8 -*-
1
+ # -*- encoding: utf-8; frozen_string_literal: true -*-
2
2
  #
3
3
  #--
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2017 Thomas Leitner
7
+ # Copyright (C) 2014-2018 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -64,7 +64,6 @@ module HexaPDF
64
64
 
65
65
  end
66
66
 
67
-
68
67
  # Objects of the PDF object system.
69
68
  #
70
69
  # == Overview
@@ -130,9 +129,9 @@ module HexaPDF
130
129
  def self.deep_copy(object)
131
130
  case object
132
131
  when Hash
133
- object.each_with_object({}) {|(key, val), memo| memo[key] = deep_copy(val)}
132
+ object.each_with_object({}) {|(key, val), memo| memo[key] = deep_copy(val) }
134
133
  when Array
135
- object.map {|o| deep_copy(o)}
134
+ object.map {|o| deep_copy(o) }
136
135
  when HexaPDF::Object
137
136
  (object.indirect? || object.must_be_indirect? ? object : deep_copy(object.value))
138
137
  when HexaPDF::Reference
@@ -144,7 +143,6 @@ module HexaPDF
144
143
  end
145
144
  end
146
145
 
147
-
148
146
  # The wrapped HexaPDF::PDFData value.
149
147
  #
150
148
  # This attribute is not part of the public API!
@@ -365,9 +363,9 @@ module HexaPDF
365
363
  if obj.kind_of?(HexaPDF::Object) && !obj.indirect?
366
364
  obj.validate(&block)
367
365
  elsif obj.kind_of?(Hash)
368
- obj.each_value {|val| validate_nested(val, &block)}
366
+ obj.each_value {|val| validate_nested(val, &block) }
369
367
  elsif obj.kind_of?(Array)
370
- obj.each {|val| validate_nested(val, &block)}
368
+ obj.each {|val| validate_nested(val, &block) }
371
369
  end
372
370
  end
373
371
 
@@ -1,10 +1,10 @@
1
- # -*- encoding: utf-8 -*-
1
+ # -*- encoding: utf-8; frozen_string_literal: true -*-
2
2
  #
3
3
  #--
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2017 Thomas Leitner
7
+ # Copyright (C) 2014-2018 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -96,11 +96,11 @@ module HexaPDF
96
96
  gen = @tokenizer.next_token
97
97
  tok = @tokenizer.next_token
98
98
  unless oid.kind_of?(Integer) && gen.kind_of?(Integer) &&
99
- tok.kind_of?(Tokenizer::Token) && tok == 'obj'.freeze
99
+ tok.kind_of?(Tokenizer::Token) && tok == 'obj'
100
100
  raise_malformed("No valid object found", pos: offset)
101
101
  end
102
102
 
103
- if (tok = @tokenizer.peek_token) && tok.kind_of?(Tokenizer::Token) && tok == 'endobj'.freeze
103
+ if (tok = @tokenizer.peek_token) && tok.kind_of?(Tokenizer::Token) && tok == 'endobj'
104
104
  maybe_raise("No indirect object value between 'obj' and 'endobj'", pos: @tokenizer.pos)
105
105
  object = nil
106
106
  else
@@ -109,7 +109,7 @@ module HexaPDF
109
109
 
110
110
  tok = @tokenizer.next_token
111
111
 
112
- if tok.kind_of?(Tokenizer::Token) && tok == 'stream'.freeze
112
+ if tok.kind_of?(Tokenizer::Token) && tok == 'stream'
113
113
  unless object.kind_of?(Hash)
114
114
  raise_malformed("A stream needs a dictionary, not a(n) #{object.class}", pos: offset)
115
115
  end
@@ -135,7 +135,7 @@ module HexaPDF
135
135
  @tokenizer.pos = pos + length
136
136
 
137
137
  tok = @tokenizer.next_token
138
- unless tok.kind_of?(Tokenizer::Token) && tok == 'endstream'.freeze
138
+ unless tok.kind_of?(Tokenizer::Token) && tok == 'endstream'
139
139
  maybe_raise("Invalid stream length, keyword endstream not found", pos: @tokenizer.pos)
140
140
  @tokenizer.pos = pos
141
141
  if @tokenizer.scan_until(/(?=\n?endstream)/)
@@ -154,7 +154,7 @@ module HexaPDF
154
154
  decode_parms: @document.unwrap(object[:DecodeParms]))
155
155
  end
156
156
 
157
- unless tok.kind_of?(Tokenizer::Token) && tok == 'endobj'.freeze
157
+ unless tok.kind_of?(Tokenizer::Token) && tok == 'endobj'
158
158
  maybe_raise("Indirect object must be followed by keyword endobj", pos: @tokenizer.pos)
159
159
  end
160
160
 
@@ -234,7 +234,7 @@ module HexaPDF
234
234
  end
235
235
  if xref.entry?(oid)
236
236
  next
237
- elsif type == 'n'.freeze
237
+ elsif type == 'n'
238
238
  if pos == 0 || gen > 65535
239
239
  maybe_raise("Invalid in use cross-reference entry in cross-reference section",
240
240
  pos: @tokenizer.pos)
@@ -255,7 +255,7 @@ module HexaPDF
255
255
 
256
256
  trailer = @tokenizer.next_object
257
257
  unless trailer.kind_of?(Hash)
258
- raise_malformed("Trailer is a #{trailer.class} instead of a dictionary ", pos: @tokenizer.pos)
258
+ raise_malformed("Trailer is #{trailer.class} instead of dictionary ", pos: @tokenizer.pos)
259
259
  end
260
260
 
261
261
  [xref, trailer]
@@ -339,7 +339,7 @@ module HexaPDF
339
339
  # HexaPDF::MalformedPDFError. Otherwise the error is corrected and parsing continues.
340
340
  #
341
341
  # If the option +force+ is used, the block is not called and the error is raised immediately.
342
- def maybe_raise(msg, pos: nil, force: false)
342
+ def maybe_raise(msg, pos:, force: false)
343
343
  if force || @document.config['parser.on_correctable_error'].call(@document, msg, pos)
344
344
  error = HexaPDF::MalformedPDFError.new(msg, pos: pos)
345
345
  error.set_backtrace(caller(1))
@@ -1,10 +1,10 @@
1
- # -*- encoding: utf-8 -*-
1
+ # -*- encoding: utf-8; frozen_string_literal: true -*-
2
2
  #
3
3
  #--
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2017 Thomas Leitner
7
+ # Copyright (C) 2014-2018 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -87,7 +87,7 @@ module HexaPDF
87
87
  # upper-right corner.
88
88
  def after_data_change
89
89
  super
90
- unless value.kind_of?(Array) && value.size == 4 && value.all? {|i| i.kind_of?(Numeric)}
90
+ unless value.kind_of?(Array) && value.size == 4 && value.all? {|i| i.kind_of?(Numeric) }
91
91
  raise ArgumentError, "A PDF rectangle structure must contain an array of four numbers"
92
92
  end
93
93
  value[0], value[2] = value[2], value[0] if value[0] > value[2]
@@ -96,7 +96,7 @@ module HexaPDF
96
96
 
97
97
  def perform_validation #:nodoc:
98
98
  super
99
- unless value.kind_of?(Array) && value.size == 4 && value.all? {|i| i.kind_of?(Numeric)}
99
+ unless value.kind_of?(Array) && value.size == 4 && value.all? {|i| i.kind_of?(Numeric) }
100
100
  yield("A PDF rectangle structure must contain an array of four numbers", false)
101
101
  end
102
102
  end
@@ -1,10 +1,10 @@
1
- # -*- encoding: utf-8 -*-
1
+ # -*- encoding: utf-8; frozen_string_literal: true -*-
2
2
  #
3
3
  #--
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2017 Thomas Leitner
7
+ # Copyright (C) 2014-2018 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -1,10 +1,10 @@
1
- # -*- encoding: utf-8 -*-
1
+ # -*- encoding: utf-8; frozen_string_literal: true -*-
2
2
  #
3
3
  #--
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2017 Thomas Leitner
7
+ # Copyright (C) 2014-2018 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -175,10 +175,10 @@ module HexaPDF
175
175
  return to_enum(__method__) unless block_given?
176
176
 
177
177
  if defined?(@all_objects_loaded)
178
- @objects.each {|_oid, _gen, data| yield(data)}
178
+ @objects.each {|_oid, _gen, data| yield(data) }
179
179
  else
180
180
  seen = {}
181
- @objects.each {|oid, _gen, data| seen[oid] = true; yield(data)}
181
+ @objects.each {|oid, _gen, data| seen[oid] = true; yield(data) }
182
182
  @xref_section.each do |oid, _gen, data|
183
183
  next if seen.key?(oid)
184
184
  yield(@objects[oid] || load_object(data))
@@ -1,10 +1,10 @@
1
- # -*- encoding: utf-8 -*-
1
+ # -*- encoding: utf-8; frozen_string_literal: true -*-
2
2
  #
3
3
  #--
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2017 Thomas Leitner
7
+ # Copyright (C) 2014-2018 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -61,7 +61,7 @@ module HexaPDF
61
61
  return new(document) if io.nil?
62
62
 
63
63
  parser = Parser.new(io, document)
64
- object_loader = lambda {|xref_entry| parser.load_object(xref_entry)}
64
+ object_loader = lambda {|xref_entry| parser.load_object(xref_entry) }
65
65
 
66
66
  revisions = []
67
67
  xref_section, trailer = parser.load_revision(parser.startxref_offset)
@@ -116,7 +116,7 @@ module HexaPDF
116
116
  def revision(index)
117
117
  @revisions[index]
118
118
  end
119
- alias :[] :revision
119
+ alias [] revision
120
120
 
121
121
  # Returns the current revision.
122
122
  def current
@@ -181,7 +181,7 @@ module HexaPDF
181
181
  end
182
182
  end
183
183
  _first, *other = *@revisions[range]
184
- other.each {|rev| @revisions.delete(rev)}
184
+ other.each {|rev| @revisions.delete(rev) }
185
185
  self
186
186
  end
187
187