prawn 2.0.2 → 2.3.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 (277) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/GPLv2 +20 -21
  5. data/Gemfile +3 -9
  6. data/Rakefile +20 -23
  7. data/lib/prawn.rb +37 -49
  8. data/lib/prawn/document.rb +181 -133
  9. data/lib/prawn/document/bounding_box.rb +41 -29
  10. data/lib/prawn/document/column_box.rb +7 -7
  11. data/lib/prawn/document/internals.rb +18 -8
  12. data/lib/prawn/document/span.rb +21 -16
  13. data/lib/prawn/encoding.rb +69 -68
  14. data/lib/prawn/errors.rb +12 -7
  15. data/lib/prawn/font.rb +115 -69
  16. data/lib/prawn/font_metric_cache.rb +14 -8
  17. data/lib/prawn/{font → fonts}/afm.rb +102 -68
  18. data/lib/prawn/{font → fonts}/dfont.rb +5 -11
  19. data/lib/prawn/fonts/otf.rb +11 -0
  20. data/lib/prawn/fonts/ttc.rb +36 -0
  21. data/lib/prawn/{font → fonts}/ttf.rb +87 -68
  22. data/lib/prawn/graphics.rb +120 -80
  23. data/lib/prawn/graphics/blend_mode.rb +65 -0
  24. data/lib/prawn/graphics/cap_style.rb +3 -3
  25. data/lib/prawn/graphics/color.rb +27 -25
  26. data/lib/prawn/graphics/dash.rb +23 -11
  27. data/lib/prawn/graphics/join_style.rb +9 -3
  28. data/lib/prawn/graphics/patterns.rb +197 -67
  29. data/lib/prawn/graphics/transformation.rb +17 -8
  30. data/lib/prawn/graphics/transparency.rb +17 -13
  31. data/lib/prawn/grid.rb +48 -47
  32. data/lib/prawn/image_handler.rb +5 -5
  33. data/lib/prawn/images.rb +39 -30
  34. data/lib/prawn/images/image.rb +2 -1
  35. data/lib/prawn/images/jpg.rb +28 -22
  36. data/lib/prawn/images/png.rb +107 -66
  37. data/lib/prawn/measurement_extensions.rb +10 -9
  38. data/lib/prawn/measurements.rb +19 -15
  39. data/lib/prawn/outline.rb +97 -77
  40. data/lib/prawn/repeater.rb +14 -10
  41. data/lib/prawn/security.rb +81 -61
  42. data/lib/prawn/security/arcfour.rb +2 -2
  43. data/lib/prawn/soft_mask.rb +26 -26
  44. data/lib/prawn/stamp.rb +20 -13
  45. data/lib/prawn/text.rb +68 -52
  46. data/lib/prawn/text/box.rb +11 -8
  47. data/lib/prawn/text/formatted.rb +5 -5
  48. data/lib/prawn/text/formatted/arranger.rb +78 -49
  49. data/lib/prawn/text/formatted/box.rb +134 -100
  50. data/lib/prawn/text/formatted/fragment.rb +11 -14
  51. data/lib/prawn/text/formatted/line_wrap.rb +121 -63
  52. data/lib/prawn/text/formatted/parser.rb +139 -117
  53. data/lib/prawn/text/formatted/wrap.rb +43 -31
  54. data/lib/prawn/transformation_stack.rb +44 -0
  55. data/lib/prawn/utilities.rb +7 -22
  56. data/lib/prawn/version.rb +2 -2
  57. data/lib/prawn/view.rb +17 -7
  58. data/manual/basic_concepts/adding_pages.rb +6 -7
  59. data/manual/basic_concepts/basic_concepts.rb +31 -22
  60. data/manual/basic_concepts/creation.rb +10 -11
  61. data/manual/basic_concepts/cursor.rb +4 -5
  62. data/manual/basic_concepts/measurement.rb +6 -7
  63. data/manual/basic_concepts/origin.rb +5 -6
  64. data/manual/basic_concepts/other_cursor_helpers.rb +11 -12
  65. data/manual/basic_concepts/view.rb +22 -16
  66. data/manual/bounding_box/bounding_box.rb +29 -24
  67. data/manual/bounding_box/bounds.rb +11 -12
  68. data/manual/bounding_box/canvas.rb +4 -5
  69. data/manual/bounding_box/creation.rb +6 -7
  70. data/manual/bounding_box/indentation.rb +14 -15
  71. data/manual/bounding_box/nesting.rb +24 -17
  72. data/manual/bounding_box/russian_boxes.rb +14 -13
  73. data/manual/bounding_box/stretchy.rb +12 -13
  74. data/manual/contents.rb +28 -22
  75. data/manual/cover.rb +33 -28
  76. data/manual/document_and_page_options/background.rb +11 -13
  77. data/manual/document_and_page_options/document_and_page_options.rb +25 -20
  78. data/manual/document_and_page_options/metadata.rb +18 -16
  79. data/manual/document_and_page_options/page_margins.rb +18 -20
  80. data/manual/document_and_page_options/page_size.rb +13 -12
  81. data/manual/document_and_page_options/print_scaling.rb +17 -15
  82. data/manual/example_helper.rb +5 -4
  83. data/manual/graphics/blend_mode.rb +52 -0
  84. data/manual/graphics/circle_and_ellipse.rb +4 -5
  85. data/manual/graphics/color.rb +7 -9
  86. data/manual/graphics/common_lines.rb +7 -8
  87. data/manual/graphics/fill_and_stroke.rb +4 -5
  88. data/manual/graphics/fill_rules.rb +9 -10
  89. data/manual/graphics/gradients.rb +27 -21
  90. data/manual/graphics/graphics.rb +48 -39
  91. data/manual/graphics/helper.rb +12 -9
  92. data/manual/graphics/line_width.rb +8 -7
  93. data/manual/graphics/lines_and_curves.rb +7 -8
  94. data/manual/graphics/polygon.rb +6 -8
  95. data/manual/graphics/rectangle.rb +4 -5
  96. data/manual/graphics/rotate.rb +6 -7
  97. data/manual/graphics/scale.rb +14 -15
  98. data/manual/graphics/soft_masks.rb +4 -5
  99. data/manual/graphics/stroke_cap.rb +6 -7
  100. data/manual/graphics/stroke_dash.rb +11 -12
  101. data/manual/graphics/stroke_join.rb +5 -6
  102. data/manual/graphics/translate.rb +9 -10
  103. data/manual/graphics/transparency.rb +7 -8
  104. data/manual/how_to_read_this_manual.rb +6 -6
  105. data/manual/images/absolute_position.rb +6 -7
  106. data/manual/images/fit.rb +7 -8
  107. data/manual/images/horizontal.rb +9 -10
  108. data/manual/images/images.rb +28 -24
  109. data/manual/images/plain_image.rb +5 -6
  110. data/manual/images/scale.rb +9 -10
  111. data/manual/images/vertical.rb +13 -14
  112. data/manual/images/width_and_height.rb +10 -11
  113. data/manual/layout/boxes.rb +5 -6
  114. data/manual/layout/content.rb +7 -8
  115. data/manual/layout/layout.rb +18 -16
  116. data/manual/layout/simple_grid.rb +6 -7
  117. data/manual/outline/add_subsection_to.rb +20 -21
  118. data/manual/outline/insert_section_after.rb +15 -16
  119. data/manual/outline/outline.rb +21 -17
  120. data/manual/outline/sections_and_pages.rb +17 -18
  121. data/manual/repeatable_content/alternate_page_numbering.rb +21 -17
  122. data/manual/repeatable_content/page_numbering.rb +17 -16
  123. data/manual/repeatable_content/repeatable_content.rb +25 -19
  124. data/manual/repeatable_content/repeater.rb +14 -15
  125. data/manual/repeatable_content/stamp.rb +14 -15
  126. data/manual/security/encryption.rb +9 -10
  127. data/manual/security/permissions.rb +19 -14
  128. data/manual/security/security.rb +19 -16
  129. data/manual/table.rb +3 -3
  130. data/manual/text/alignment.rb +16 -17
  131. data/manual/text/color.rb +12 -11
  132. data/manual/text/column_box.rb +9 -10
  133. data/manual/text/fallback_fonts.rb +25 -21
  134. data/manual/text/font.rb +11 -12
  135. data/manual/text/font_size.rb +13 -14
  136. data/manual/text/font_style.rb +7 -8
  137. data/manual/text/formatted_callbacks.rb +25 -21
  138. data/manual/text/formatted_text.rb +33 -25
  139. data/manual/text/free_flowing_text.rb +20 -21
  140. data/manual/text/inline.rb +18 -19
  141. data/manual/text/kerning_and_character_spacing.rb +14 -15
  142. data/manual/text/leading.rb +7 -8
  143. data/manual/text/line_wrapping.rb +37 -18
  144. data/manual/text/paragraph_indentation.rb +13 -14
  145. data/manual/text/positioned_text.rb +15 -16
  146. data/manual/text/registering_families.rb +20 -21
  147. data/manual/text/rendering_and_color.rb +9 -10
  148. data/manual/text/right_to_left_text.rb +26 -19
  149. data/manual/text/rotation.rb +28 -23
  150. data/manual/text/single_usage.rb +8 -9
  151. data/manual/text/text.rb +57 -52
  152. data/manual/text/text_box_excess.rb +20 -17
  153. data/manual/text/text_box_extensions.rb +18 -15
  154. data/manual/text/text_box_overflow.rb +18 -19
  155. data/manual/text/utf8.rb +11 -12
  156. data/manual/text/win_ansi_charset.rb +21 -19
  157. data/prawn.gemspec +45 -33
  158. data/spec/extensions/encoding_helpers.rb +3 -3
  159. data/spec/prawn/document/bounding_box_spec.rb +546 -0
  160. data/spec/prawn/document/column_box_spec.rb +75 -0
  161. data/spec/prawn/document/security_spec.rb +176 -0
  162. data/spec/prawn/document_annotations_spec.rb +76 -0
  163. data/spec/prawn/document_destinations_spec.rb +15 -0
  164. data/spec/prawn/document_grid_spec.rb +99 -0
  165. data/spec/prawn/document_reference_spec.rb +27 -0
  166. data/spec/prawn/document_span_spec.rb +36 -0
  167. data/spec/prawn/document_spec.rb +802 -0
  168. data/spec/prawn/font_metric_cache_spec.rb +54 -0
  169. data/spec/prawn/font_spec.rb +542 -0
  170. data/spec/prawn/graphics/blend_mode_spec.rb +63 -0
  171. data/spec/prawn/graphics/transparency_spec.rb +81 -0
  172. data/spec/prawn/graphics_spec.rb +837 -0
  173. data/spec/prawn/graphics_stroke_styles_spec.rb +229 -0
  174. data/spec/prawn/image_handler_spec.rb +53 -0
  175. data/spec/prawn/images/jpg_spec.rb +20 -0
  176. data/spec/prawn/images/png_spec.rb +283 -0
  177. data/spec/prawn/images_spec.rb +224 -0
  178. data/spec/prawn/measurements_extensions_spec.rb +24 -0
  179. data/spec/prawn/outline_spec.rb +412 -0
  180. data/spec/prawn/repeater_spec.rb +165 -0
  181. data/spec/prawn/soft_mask_spec.rb +74 -0
  182. data/spec/prawn/stamp_spec.rb +172 -0
  183. data/spec/prawn/text/box_spec.rb +1112 -0
  184. data/spec/prawn/text/formatted/arranger_spec.rb +466 -0
  185. data/spec/prawn/text/formatted/box_spec.rb +846 -0
  186. data/spec/prawn/text/formatted/fragment_spec.rb +343 -0
  187. data/spec/prawn/text/formatted/line_wrap_spec.rb +494 -0
  188. data/spec/prawn/text/formatted/parser_spec.rb +697 -0
  189. data/spec/prawn/text_draw_text_spec.rb +149 -0
  190. data/spec/prawn/text_rendering_mode_spec.rb +48 -0
  191. data/spec/prawn/text_spacing_spec.rb +95 -0
  192. data/spec/prawn/text_spec.rb +603 -0
  193. data/spec/prawn/text_with_inline_formatting_spec.rb +35 -0
  194. data/spec/prawn/transformation_stack_spec.rb +66 -0
  195. data/spec/prawn/view_spec.rb +63 -0
  196. data/spec/prawn_manual_spec.rb +35 -0
  197. data/spec/spec_helper.rb +19 -23
  198. metadata +145 -185
  199. metadata.gz.sig +4 -0
  200. data/data/images/16bit.alpha +0 -0
  201. data/data/images/16bit.color +0 -0
  202. data/data/images/16bit.png +0 -0
  203. data/data/images/arrow.png +0 -0
  204. data/data/images/arrow2.png +0 -0
  205. data/data/images/dice.alpha +0 -0
  206. data/data/images/dice.color +0 -0
  207. data/data/images/dice.png +0 -0
  208. data/data/images/dice_interlaced.png +0 -0
  209. data/data/images/fractal.jpg +0 -0
  210. data/data/images/indexed_color.dat +0 -0
  211. data/data/images/indexed_color.png +0 -0
  212. data/data/images/letterhead.jpg +0 -0
  213. data/data/images/license.md +0 -8
  214. data/data/images/page_white_text.alpha +0 -0
  215. data/data/images/page_white_text.color +0 -0
  216. data/data/images/page_white_text.png +0 -0
  217. data/data/images/pal_bk.png +0 -0
  218. data/data/images/pigs.jpg +0 -0
  219. data/data/images/prawn.png +0 -0
  220. data/data/images/ruport.png +0 -0
  221. data/data/images/ruport_data.dat +0 -0
  222. data/data/images/ruport_transparent.png +0 -0
  223. data/data/images/ruport_type0.png +0 -0
  224. data/data/images/stef.jpg +0 -0
  225. data/data/images/tru256.bmp +0 -0
  226. data/data/images/web-links.dat +0 -1
  227. data/data/images/web-links.png +0 -0
  228. data/data/pdfs/complex_template.pdf +0 -0
  229. data/data/pdfs/contains_ttf_font.pdf +0 -0
  230. data/data/pdfs/encrypted.pdf +0 -0
  231. data/data/pdfs/form.pdf +1 -819
  232. data/data/pdfs/hexagon.pdf +0 -61
  233. data/data/pdfs/indirect_reference.pdf +0 -86
  234. data/data/pdfs/multipage_template.pdf +0 -127
  235. data/data/pdfs/nested_pages.pdf +0 -118
  236. data/data/pdfs/page_without_mediabox.pdf +0 -193
  237. data/data/pdfs/resources_as_indirect_object.pdf +0 -83
  238. data/data/pdfs/two_hexagons.pdf +0 -90
  239. data/data/pdfs/version_1_6.pdf +0 -61
  240. data/data/shift_jis_text.txt +0 -1
  241. data/spec/acceptance/png.rb +0 -24
  242. data/spec/annotations_spec.rb +0 -67
  243. data/spec/bounding_box_spec.rb +0 -501
  244. data/spec/column_box_spec.rb +0 -59
  245. data/spec/destinations_spec.rb +0 -13
  246. data/spec/document_spec.rb +0 -742
  247. data/spec/extensions/mocha.rb +0 -45
  248. data/spec/font_metric_cache_spec.rb +0 -52
  249. data/spec/font_spec.rb +0 -475
  250. data/spec/formatted_text_arranger_spec.rb +0 -423
  251. data/spec/formatted_text_box_spec.rb +0 -716
  252. data/spec/formatted_text_fragment_spec.rb +0 -299
  253. data/spec/graphics_spec.rb +0 -666
  254. data/spec/grid_spec.rb +0 -95
  255. data/spec/image_handler_spec.rb +0 -53
  256. data/spec/images_spec.rb +0 -167
  257. data/spec/inline_formatted_text_parser_spec.rb +0 -568
  258. data/spec/jpg_spec.rb +0 -23
  259. data/spec/line_wrap_spec.rb +0 -366
  260. data/spec/measurement_units_spec.rb +0 -22
  261. data/spec/outline_spec.rb +0 -409
  262. data/spec/png_spec.rb +0 -235
  263. data/spec/reference_spec.rb +0 -25
  264. data/spec/repeater_spec.rb +0 -154
  265. data/spec/security_spec.rb +0 -151
  266. data/spec/soft_mask_spec.rb +0 -78
  267. data/spec/span_spec.rb +0 -43
  268. data/spec/stamp_spec.rb +0 -179
  269. data/spec/stroke_styles_spec.rb +0 -208
  270. data/spec/text_at_spec.rb +0 -142
  271. data/spec/text_box_spec.rb +0 -1038
  272. data/spec/text_rendering_mode_spec.rb +0 -45
  273. data/spec/text_spacing_spec.rb +0 -93
  274. data/spec/text_spec.rb +0 -549
  275. data/spec/text_with_inline_formatting_spec.rb +0 -35
  276. data/spec/transparency_spec.rb +0 -91
  277. data/spec/view_spec.rb +0 -42
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Prawn::Text do
6
+ describe '#draw_text' do
7
+ let(:pdf) { create_pdf }
8
+
9
+ it 'raise_errors ArgumentError if :at option omitted' do
10
+ expect { pdf.draw_text('hai', {}) }.to raise_error(ArgumentError)
11
+ end
12
+
13
+ it 'raise_errors ArgumentError if :align option included' do
14
+ expect do
15
+ pdf.draw_text('hai', at: [0, 0], align: :center)
16
+ end.to raise_error(ArgumentError)
17
+ end
18
+
19
+ it 'allows drawing empty strings to the page' do
20
+ pdf.draw_text(' ', at: [100, 100])
21
+ text = PDF::Inspector::Text.analyze(pdf.render)
22
+ expect(text.strings.first).to eq(' ')
23
+ end
24
+
25
+ it 'defaults to 12 point helvetica' do
26
+ pdf.draw_text('Blah', at: [100, 100])
27
+ text = PDF::Inspector::Text.analyze(pdf.render)
28
+ expect(text.font_settings[0][:name]).to eq(:Helvetica)
29
+ expect(text.font_settings[0][:size]).to eq(12)
30
+ expect(text.strings.first).to eq('Blah')
31
+ end
32
+
33
+ it 'allows setting font size' do
34
+ pdf.draw_text('Blah', at: [100, 100], size: 16)
35
+ text = PDF::Inspector::Text.analyze(pdf.render)
36
+ expect(text.font_settings[0][:size]).to eq(16)
37
+ end
38
+
39
+ it 'allows setting a default font size' do
40
+ pdf.font_size = 16
41
+ pdf.draw_text('Blah', at: [0, 0])
42
+
43
+ text = PDF::Inspector::Text.analyze(pdf.render)
44
+ expect(text.font_settings[0][:size]).to eq(16)
45
+ end
46
+
47
+ # rubocop: disable Naming/AccessorMethodName
48
+ rotated_text_inspector = Class.new(PDF::Inspector) do
49
+ attr_reader :tm_operator_used
50
+
51
+ def initialize
52
+ @tm_operator_used = false
53
+ end
54
+
55
+ def set_text_matrix_and_text_line_matrix(*_arguments)
56
+ @tm_operator_used = true
57
+ end
58
+ end
59
+ # rubocop: enable Naming/AccessorMethodName
60
+
61
+ it 'allows rotation' do
62
+ pdf.draw_text('Test', at: [100, 100], rotate: 90)
63
+
64
+ text = rotated_text_inspector.analyze(pdf.render)
65
+
66
+ expect(text.tm_operator_used).to eq true
67
+ end
68
+
69
+ it 'does not use rotation matrix by default' do
70
+ pdf.draw_text('Test', at: [100, 100])
71
+
72
+ text = rotated_text_inspector.analyze(pdf.render)
73
+
74
+ expect(text.tm_operator_used).to eq false
75
+ end
76
+
77
+ it 'allows overriding default font for a single instance' do
78
+ pdf.font_size = 16
79
+
80
+ pdf.draw_text('Blah', size: 11, at: [0, 0])
81
+ pdf.draw_text('Blaz', at: [0, 0])
82
+ text = PDF::Inspector::Text.analyze(pdf.render)
83
+ expect(text.font_settings[0][:size]).to eq(11)
84
+ expect(text.font_settings[1][:size]).to eq(16)
85
+ end
86
+
87
+ it 'allows setting a font size transaction with a block' do
88
+ pdf.font_size 16 do
89
+ pdf.draw_text('Blah', at: [0, 0])
90
+ end
91
+
92
+ pdf.draw_text('blah', at: [0, 0])
93
+
94
+ text = PDF::Inspector::Text.analyze(pdf.render)
95
+ expect(text.font_settings[0][:size]).to eq(16)
96
+ expect(text.font_settings[1][:size]).to eq(12)
97
+ end
98
+
99
+ it 'allows manual setting the font size when in a font size block' do
100
+ pdf.font_size(16) do
101
+ pdf.draw_text('Foo', at: [0, 0])
102
+ pdf.draw_text('Blah', size: 11, at: [0, 0])
103
+ pdf.draw_text('Blaz', at: [0, 0])
104
+ end
105
+ text = PDF::Inspector::Text.analyze(pdf.render)
106
+ expect(text.font_settings[0][:size]).to eq(16)
107
+ expect(text.font_settings[1][:size]).to eq(11)
108
+ expect(text.font_settings[2][:size]).to eq(16)
109
+ end
110
+
111
+ it 'allows registering of built-in font_settings on the fly' do
112
+ pdf.font 'Times-Roman'
113
+ pdf.draw_text('Blah', at: [100, 100])
114
+ pdf.font 'Courier'
115
+ pdf.draw_text('Blaz', at: [150, 150])
116
+ text = PDF::Inspector::Text.analyze(pdf.render)
117
+ expect(text.font_settings[0][:name]).to eq(:"Times-Roman")
118
+ expect(text.font_settings[1][:name]).to eq(:Courier)
119
+ end
120
+
121
+ it 'raise_errors an exception when an unknown font is used' do
122
+ expect { pdf.font 'Pao bu' }.to raise_error(Prawn::Errors::UnknownFont)
123
+ end
124
+
125
+ it 'correctlies render a utf-8 string when using a built-in font' do
126
+ str = '©' # copyright symbol
127
+ pdf.draw_text(str, at: [0, 0])
128
+
129
+ # grab the text from the rendered PDF and ensure it matches
130
+ text = PDF::Inspector::Text.analyze(pdf.render)
131
+ expect(text.strings.first).to eq(str)
132
+ end
133
+
134
+ it 'raises an exception when a utf-8 incompatible string is rendered' do
135
+ str = "Blah \xDD"
136
+ expect { pdf.draw_text(str, at: [0, 0]) }.to raise_error(
137
+ Prawn::Errors::IncompatibleStringEncoding
138
+ )
139
+ end
140
+
141
+ it 'does not raise an exception when a shift-jis string is rendered' do
142
+ datafile = "#{Prawn::DATADIR}/shift_jis_text.txt"
143
+ sjis_str = File.open(datafile, 'r:shift_jis', &:gets)
144
+ pdf.font("#{Prawn::DATADIR}/fonts/gkai00mp.ttf")
145
+
146
+ pdf.draw_text(sjis_str, at: [0, 0])
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Prawn::Text do
6
+ let(:pdf) { create_pdf }
7
+
8
+ describe '#text_rendering_mode' do
9
+ it 'draws the text rendering mode to the document' do
10
+ pdf.text_rendering_mode(:stroke) do
11
+ pdf.text('hello world')
12
+ end
13
+ contents = PDF::Inspector::Text.analyze(pdf.render)
14
+ expect(contents.text_rendering_mode.first).to eq(1)
15
+ end
16
+
17
+ it 'does not draw the text rendering mode to the document' \
18
+ ' when the new mode matches the old' do
19
+ pdf.text_rendering_mode(:fill) do
20
+ pdf.text('hello world')
21
+ end
22
+ contents = PDF::Inspector::Text.analyze(pdf.render)
23
+ expect(contents.text_rendering_mode).to be_empty
24
+ end
25
+
26
+ it 'restores character spacing to 0' do
27
+ pdf.text_rendering_mode(:stroke) do
28
+ pdf.text('hello world')
29
+ end
30
+ contents = PDF::Inspector::Text.analyze(pdf.render)
31
+ expect(contents.text_rendering_mode).to eq([1, 0])
32
+ end
33
+
34
+ it 'functions as an accessor when no parameter given' do
35
+ pdf.text_rendering_mode(:fill_stroke) do
36
+ pdf.text('hello world')
37
+ expect(pdf.text_rendering_mode).to eq(:fill_stroke)
38
+ end
39
+ expect(pdf.text_rendering_mode).to eq(:fill)
40
+ end
41
+
42
+ it 'raise_errors an exception when passed an invalid mode' do
43
+ expect { pdf.text_rendering_mode(-1) }.to raise_error(ArgumentError)
44
+ expect { pdf.text_rendering_mode(8) }.to raise_error(ArgumentError)
45
+ expect { pdf.text_rendering_mode(:flil) }.to raise_error(ArgumentError)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Prawn::Text do
6
+ let(:pdf) { create_pdf }
7
+
8
+ describe '#character_spacing' do
9
+ it 'draws the character spacing to the document' do
10
+ pdf.character_spacing(10.555555) do
11
+ pdf.text('hello world')
12
+ end
13
+ contents = PDF::Inspector::Text.analyze(pdf.render)
14
+ expect(contents.character_spacing.first).to eq(10.5556)
15
+ end
16
+
17
+ it 'does not draw the character spacing to the document' \
18
+ ' when the new character spacing matches the old' do
19
+ pdf.character_spacing(0) do
20
+ pdf.text('hello world')
21
+ end
22
+ contents = PDF::Inspector::Text.analyze(pdf.render)
23
+ expect(contents.character_spacing).to be_empty
24
+ end
25
+
26
+ it 'restores character spacing to 0' do
27
+ pdf.character_spacing(10.555555) do
28
+ pdf.text('hello world')
29
+ end
30
+ contents = PDF::Inspector::Text.analyze(pdf.render)
31
+ expect(contents.character_spacing.last).to eq(0)
32
+ end
33
+
34
+ it 'functions as an accessor when no parameter given' do
35
+ pdf.character_spacing(10.555555) do
36
+ pdf.text('hello world')
37
+ expect(pdf.character_spacing).to eq(10.555555)
38
+ end
39
+ expect(pdf.character_spacing).to eq(0)
40
+ end
41
+
42
+ # ensure that we properly internationalize by using the number of characters
43
+ # in a string, not the number of bytes, to insert character spaces
44
+ #
45
+ it 'calculates character spacing widths by characters, not bytes' do
46
+ pdf.font("#{Prawn::DATADIR}/fonts/gkai00mp.ttf")
47
+
48
+ str = 'こんにちは世界'
49
+ raw_width = nil
50
+ pdf.character_spacing(0) do
51
+ raw_width = pdf.width_of(str)
52
+ end
53
+
54
+ pdf.character_spacing(10) do
55
+ # the new width should include six 10-pt character spaces.
56
+ expect(pdf.width_of(str)).to be_within(0.001).of(raw_width + (10 * 6))
57
+ end
58
+ end
59
+ end
60
+
61
+ describe '#word_spacing' do
62
+ it 'draws the word spacing to the document' do
63
+ pdf.word_spacing(10.555555) do
64
+ pdf.text('hello world')
65
+ end
66
+ contents = PDF::Inspector::Text.analyze(pdf.render)
67
+ expect(contents.word_spacing.first).to eq(10.5556)
68
+ end
69
+
70
+ it 'draws the word spacing to the document' \
71
+ ' when the new word spacing matches the old' do
72
+ pdf.word_spacing(0) do
73
+ pdf.text('hello world')
74
+ end
75
+ contents = PDF::Inspector::Text.analyze(pdf.render)
76
+ expect(contents.word_spacing).to be_empty
77
+ end
78
+
79
+ it 'restores word spacing to 0' do
80
+ pdf.word_spacing(10.555555) do
81
+ pdf.text('hello world')
82
+ end
83
+ contents = PDF::Inspector::Text.analyze(pdf.render)
84
+ expect(contents.word_spacing.last).to eq(0)
85
+ end
86
+
87
+ it 'functions as an accessor when no parameter given' do
88
+ pdf.word_spacing(10.555555) do
89
+ pdf.text('hello world')
90
+ expect(pdf.word_spacing).to eq(10.555555)
91
+ end
92
+ expect(pdf.word_spacing).to eq(0)
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,603 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Prawn::Text do
6
+ describe 'NBSP' do
7
+ it 'is defined' do
8
+ expect(Prawn::Text::NBSP).to eq("\u00a0")
9
+ end
10
+ end
11
+
12
+ describe '#height_of' do
13
+ let(:pdf) { create_pdf }
14
+
15
+ it 'returns the height that would be required to print a' \
16
+ 'particular string of text' do
17
+ original_y = pdf.y
18
+ pdf.text('Foo')
19
+ new_y = pdf.y
20
+ expect(pdf.height_of('Foo')).to be_within(0.0001).of(original_y - new_y)
21
+ end
22
+
23
+ it 'omits the gap below the last descender if :final_gap => false ' \
24
+ 'is given' do
25
+ original_y = pdf.y
26
+ pdf.text('Foo', final_gap: false)
27
+ new_y = pdf.y
28
+ expect(pdf.height_of('Foo', final_gap: false))
29
+ .to be_within(0.0001).of(original_y - new_y)
30
+ end
31
+
32
+ it 'raise_errors CannotFit if a too-small width is given' do
33
+ expect do
34
+ pdf.height_of('text', width: 1)
35
+ end.to raise_error(Prawn::Errors::CannotFit)
36
+ end
37
+
38
+ it 'raises NotImplementedError if :indent_paragraphs option is provided' do
39
+ expect do
40
+ pdf.height_of(
41
+ 'hai',
42
+ width: 300,
43
+ indent_paragraphs: 60
44
+ )
45
+ end.to raise_error(NotImplementedError)
46
+ end
47
+
48
+ it 'does not raise Prawn::Errors::UnknownOption if :final_gap option '\
49
+ 'is provided' do
50
+ expect do
51
+ pdf.height_of('hai', width: 300, final_gap: true)
52
+ end.to_not raise_error
53
+ end
54
+ end
55
+
56
+ describe '#text' do
57
+ let(:pdf) { create_pdf }
58
+
59
+ it 'does not fail when @output is nil when '\
60
+ 'PDF::Core::Text::LineWrap#finalize_line is called' do
61
+ # need a document with margins for these particulars to produce the
62
+ # condition that was throwing the error
63
+ pdf = Prawn::Document.new
64
+ pdf.text 'transparency ' * 150, size: 18
65
+ end
66
+
67
+ it 'allows drawing empty strings to the page' do
68
+ pdf.text ' '
69
+ text = PDF::Inspector::Text.analyze(pdf.render)
70
+ # If anything is rendered to the page, it should be whitespace.
71
+ expect(text.strings).to all(match(/\A\s*\z/))
72
+ end
73
+
74
+ it 'ignores call when string is nil' do
75
+ expect(pdf.text(nil)).to eq false
76
+ end
77
+
78
+ it 'correctlies render empty paragraphs' do
79
+ pdf.text "text\n\ntext"
80
+ text = PDF::Inspector::Text.analyze(pdf.render)
81
+ expect(pdf.page_count).to eq(1)
82
+ expect(text.strings.reject(&:empty?)).to eq(%w[text text])
83
+ end
84
+
85
+ it 'correctlies render empty paragraphs with :indent_paragraphs' do
86
+ pdf.text "text\n\ntext", indent_paragraphs: 5
87
+ text = PDF::Inspector::Text.analyze(pdf.render)
88
+ expect(pdf.page_count).to eq(1)
89
+ expect(text.strings.reject(&:empty?)).to eq(%w[text text])
90
+ end
91
+
92
+ it 'correctly renders strings ending with empty paragraphs and ' \
93
+ ':inline_format and :indent_paragraphs' do
94
+ pdf.text "text\n\n", inline_format: true, indent_paragraphs: 5
95
+ text = PDF::Inspector::Text.analyze(pdf.render)
96
+ expect(pdf.page_count).to eq(1)
97
+ expect(text.strings).to eq(['text'])
98
+ end
99
+
100
+ it 'defaults to use kerning information' do
101
+ pdf.text 'hello world'
102
+ text = PDF::Inspector::Text.analyze(pdf.render)
103
+ expect(text.kerned[0]).to eq true
104
+ end
105
+
106
+ it 'is able to disable kerning with an option' do
107
+ pdf.text 'hello world', kerning: false
108
+ text = PDF::Inspector::Text.analyze(pdf.render)
109
+ expect(text.kerned[0]).to eq false
110
+ end
111
+
112
+ it 'is able to disable kerning document-wide' do
113
+ pdf.default_kerning(false)
114
+ pdf.default_kerning = false
115
+ pdf.text 'hello world'
116
+ text = PDF::Inspector::Text.analyze(pdf.render)
117
+ expect(text.kerned[0]).to eq false
118
+ end
119
+
120
+ it 'option should be able to override document-wide kerning disabling' do
121
+ pdf.default_kerning = false
122
+ pdf.text 'hello world', kerning: true
123
+ text = PDF::Inspector::Text.analyze(pdf.render)
124
+ expect(text.kerned[0]).to eq true
125
+ end
126
+
127
+ it 'raise_errors ArgumentError if :at option included' do
128
+ expect { pdf.text('hai', at: [0, 0]) }.to raise_error(ArgumentError)
129
+ end
130
+
131
+ it 'advances down the document based on font_height' do
132
+ position = pdf.y
133
+ pdf.text 'Foo'
134
+
135
+ expect(pdf.y).to be_within(0.0001).of(position - pdf.font.height)
136
+
137
+ position = pdf.y
138
+ pdf.text "Foo\nBar\nBaz"
139
+ expect(pdf.y).to be_within(0.0001).of(position - 3 * pdf.font.height)
140
+ end
141
+
142
+ it 'advances down the document based on font_height with size option' do
143
+ position = pdf.y
144
+ pdf.text 'Foo', size: 15
145
+
146
+ pdf.font_size = 15
147
+ expect(pdf.y).to be_within(0.0001).of(position - pdf.font.height)
148
+
149
+ position = pdf.y
150
+ pdf.text "Foo\nBar\nBaz"
151
+ expect(pdf.y).to be_within(0.0001).of(position - 3 * pdf.font.height)
152
+ end
153
+
154
+ it 'advances down the document based on font_height with leading option' do
155
+ position = pdf.y
156
+ leading = 2
157
+ pdf.text 'Foo', leading: leading
158
+
159
+ expect(pdf.y).to be_within(0.0001)
160
+ .of(position - pdf.font.height - leading)
161
+
162
+ position = pdf.y
163
+ pdf.text "Foo\nBar\nBaz"
164
+ expect(pdf.y).to be_within(0.0001).of(position - 3 * pdf.font.height)
165
+ end
166
+
167
+ it 'advances only to the bottom of the final descender if final_gap '\
168
+ 'is false' do
169
+ position = pdf.y
170
+ pdf.text 'Foo', final_gap: false
171
+
172
+ expect(pdf.y).to be_within(0.0001)
173
+ .of(position - pdf.font.ascender - pdf.font.descender)
174
+
175
+ position = pdf.y
176
+ pdf.text "Foo\nBar\nBaz", final_gap: false
177
+ expect(pdf.y).to be_within(0.0001)
178
+ .of(
179
+ position - 2 * pdf.font.height - pdf.font.ascender -
180
+ pdf.font.descender
181
+ )
182
+ end
183
+
184
+ it 'is able to print text starting at the last line of a page' do
185
+ pdf.move_cursor_to(pdf.font.height)
186
+ pdf.text('hello world')
187
+ pages = PDF::Inspector::Page.analyze(pdf.render).pages
188
+ expect(pages.size).to eq(1)
189
+ end
190
+
191
+ it 'defaults to 12 point helvetica' do
192
+ pdf.text 'Blah'
193
+ text = PDF::Inspector::Text.analyze(pdf.render)
194
+ expect(text.font_settings[0][:name]).to eq(:Helvetica)
195
+ expect(text.font_settings[0][:size]).to eq(12)
196
+ expect(text.strings.first).to eq('Blah')
197
+ end
198
+
199
+ it 'allows setting font size' do
200
+ pdf.text 'Blah', size: 16
201
+ text = PDF::Inspector::Text.analyze(pdf.render)
202
+ expect(text.font_settings[0][:size]).to eq(16)
203
+ end
204
+
205
+ it 'allows setting a default font size' do
206
+ pdf.font_size = 16
207
+ pdf.text 'Blah'
208
+ text = PDF::Inspector::Text.analyze(pdf.render)
209
+ expect(text.font_settings[0][:size]).to eq(16)
210
+ end
211
+
212
+ it 'allows overriding default font for a single instance' do
213
+ pdf.font_size = 16
214
+
215
+ pdf.text 'Blah', size: 11
216
+ pdf.text 'Blaz'
217
+ text = PDF::Inspector::Text.analyze(pdf.render)
218
+ expect(text.font_settings[0][:size]).to eq(11)
219
+ expect(text.font_settings[1][:size]).to eq(16)
220
+ end
221
+
222
+ it 'allows setting a font size transaction with a block' do
223
+ pdf.font_size 16 do
224
+ pdf.text 'Blah'
225
+ end
226
+
227
+ pdf.text 'blah'
228
+
229
+ text = PDF::Inspector::Text.analyze(pdf.render)
230
+ expect(text.font_settings[0][:size]).to eq(16)
231
+ expect(text.font_settings[1][:size]).to eq(12)
232
+ end
233
+
234
+ it 'allows manual setting the font size when in a font size block' do
235
+ pdf.font_size(16) do
236
+ pdf.text 'Foo'
237
+ pdf.text 'Blah', size: 11
238
+ pdf.text 'Blaz'
239
+ end
240
+ text = PDF::Inspector::Text.analyze(pdf.render)
241
+ expect(text.font_settings[0][:size]).to eq(16)
242
+ expect(text.font_settings[1][:size]).to eq(11)
243
+ expect(text.font_settings[2][:size]).to eq(16)
244
+ end
245
+
246
+ it 'allows registering of built-in font_settings on the fly' do
247
+ pdf.font 'Times-Roman'
248
+ pdf.text 'Blah'
249
+ pdf.font 'Courier'
250
+ pdf.text 'Blaz'
251
+ text = PDF::Inspector::Text.analyze(pdf.render)
252
+ expect(text.font_settings[0][:name]).to eq(:"Times-Roman")
253
+ expect(text.font_settings[1][:name]).to eq(:Courier)
254
+ end
255
+
256
+ it 'utilises the same default font across multiple pages' do
257
+ pdf.text 'Blah'
258
+ pdf.start_new_page
259
+ pdf.text 'Blaz'
260
+ text = PDF::Inspector::Text.analyze(pdf.render)
261
+
262
+ expect(text.font_settings.size).to eq(2)
263
+ expect(text.font_settings[0][:name]).to eq(:Helvetica)
264
+ expect(text.font_settings[1][:name]).to eq(:Helvetica)
265
+ end
266
+
267
+ it 'raise_errors an exception when an unknown font is used' do
268
+ expect { pdf.font 'Pao bu' }.to raise_error(Prawn::Errors::UnknownFont)
269
+ end
270
+
271
+ it 'does not raise an exception when providing Pathname instance as font' do
272
+ pdf.font Pathname.new("#{Prawn::DATADIR}/fonts/DejaVuSans.ttf")
273
+ end
274
+
275
+ it 'correctlies render a utf-8 string when using a built-in font' do
276
+ str = '©' # copyright symbol
277
+ pdf.text str
278
+
279
+ # grab the text from the rendered PDF and ensure it matches
280
+ text = PDF::Inspector::Text.analyze(pdf.render)
281
+ expect(text.strings.first).to eq(str)
282
+ end
283
+
284
+ it 'correctlies render a utf-8 string when using a TTF font' do
285
+ str = '©' # copyright symbol
286
+ pdf.font "#{Prawn::DATADIR}/fonts/DejaVuSans.ttf"
287
+ pdf.text str
288
+
289
+ # grab the text from the rendered PDF and ensure it matches
290
+ text = PDF::Inspector::Text.analyze(pdf.render)
291
+ expect(text.strings.first).to eq(str)
292
+ end
293
+
294
+ it 'subsets mixed low-ASCII and non-ASCII characters when they can '\
295
+ 'be subsetted together' do
296
+ str = 'It’s super effective!'
297
+ pdf.font "#{Prawn::DATADIR}/fonts/DejaVuSans.ttf"
298
+ pdf.text str
299
+
300
+ text = PDF::Inspector::Text.analyze(pdf.render)
301
+ expect(text.strings.first).to eq(str)
302
+ end
303
+
304
+ it 'correctly renders a string with higher bit characters across a page '\
305
+ 'break when using a built-in font' do
306
+ str = '©'
307
+ pdf.move_cursor_to(pdf.font.height)
308
+ pdf.text(str + "\n" + str)
309
+
310
+ pages = PDF::Inspector::Page.analyze(pdf.render).pages
311
+ expect(pages.size).to eq(2)
312
+ expect(pages[0][:strings]).to eq([str])
313
+ expect(pages[1][:strings]).to eq([str])
314
+ end
315
+
316
+ it 'correctly renders a string with higher bit characters across ' \
317
+ 'a page break when using a built-in font and :indent_paragraphs option' do
318
+ str = '©'
319
+ pdf.move_cursor_to(pdf.font.height)
320
+ pdf.text(str + "\n" + str, indent_paragraphs: 20)
321
+
322
+ pages = PDF::Inspector::Page.analyze(pdf.render).pages
323
+ expect(pages.size).to eq(2)
324
+ expect(pages[0][:strings]).to eq([str])
325
+ expect(pages[1][:strings]).to eq([str])
326
+ end
327
+
328
+ it 'raises an exception when a utf-8 incompatible string is rendered' do
329
+ str = "Blah \xDD"
330
+ expect { pdf.text str }.to raise_error(
331
+ Prawn::Errors::IncompatibleStringEncoding
332
+ )
333
+ end
334
+
335
+ it 'does not raise an exception when a shift-jis string is rendered' do
336
+ datafile = "#{Prawn::DATADIR}/shift_jis_text.txt"
337
+ sjis_str = File.open(datafile, 'r:shift_jis', &:gets)
338
+ pdf.font("#{Prawn::DATADIR}/fonts/gkai00mp.ttf")
339
+
340
+ # Expect that the call to text will not raise an encoding error
341
+ pdf.text(sjis_str)
342
+ end
343
+
344
+ it 'calls move_past_bottom when printing more text than can fit' \
345
+ ' between the current document.y and bounds.bottom' do
346
+ pdf.y = pdf.font.height
347
+ pdf.text 'Hello'
348
+ pdf.text 'World'
349
+ pages = PDF::Inspector::Page.analyze(pdf.render).pages
350
+ expect(pages.size).to eq(2)
351
+ expect(pages[0][:strings]).to eq(['Hello'])
352
+ expect(pages[1][:strings]).to eq(['World'])
353
+ end
354
+
355
+ describe 'with :indent_paragraphs option' do
356
+ it 'indents the paragraphs' do
357
+ hello = 'hello ' * 50
358
+ hello2 = 'hello ' * 50
359
+ pdf.text(hello + "\n" + hello2, indent_paragraphs: 60)
360
+ text = PDF::Inspector::Text.analyze(pdf.render)
361
+ expect(text.strings[0]).to eq(('hello ' * 19).strip)
362
+ expect(text.strings[1]).to eq(('hello ' * 21).strip)
363
+ expect(text.strings[3]).to eq(('hello ' * 19).strip)
364
+ expect(text.strings[4]).to eq(('hello ' * 21).strip)
365
+ end
366
+
367
+ it 'indents from right side when using :rtl direction' do
368
+ para1 = 'The rain in spain falls mainly on the plains ' * 3
369
+ para2 = 'The rain in spain falls mainly on the plains ' * 3
370
+
371
+ pdf.text(para1 + "\n" + para2, indent_paragraphs: 60, direction: :rtl)
372
+
373
+ text = PDF::Inspector::Text.analyze(pdf.render)
374
+
375
+ lines = text.strings
376
+ x_positions = text.positions.map { |e| e[0] }
377
+
378
+ # NOTE: The code below reflects Prawn's current kerning behavior for RTL
379
+ # text, which isn't necessarily correct. If we change that behavior,
380
+ # this test will need to be updated.
381
+
382
+ expect(x_positions[0]).to(
383
+ be_within(0.001).of(pdf.bounds.absolute_right - 60 -
384
+ pdf.width_of(lines[0].reverse, kerning: true))
385
+ )
386
+
387
+ expect(x_positions[1]).to(
388
+ be_within(0.001).of(pdf.bounds.absolute_right -
389
+ pdf.width_of(lines[1].reverse, kerning: true))
390
+ )
391
+
392
+ expect(x_positions[2]).to(
393
+ be_within(0.001).of(pdf.bounds.absolute_right - 60 -
394
+ pdf.width_of(lines[2].reverse, kerning: true))
395
+ )
396
+
397
+ expect(x_positions[3]).to(
398
+ be_within(0.001).of(pdf.bounds.absolute_right -
399
+ pdf.width_of(lines[3].reverse, kerning: true))
400
+ )
401
+ end
402
+
403
+ it 'indents from right side when document has :rtl direction' do
404
+ para1 = 'The rain in spain falls mainly on the plains ' * 3
405
+ para2 = 'The rain in spain falls mainly on the plains ' * 3
406
+
407
+ pdf.text_direction = :rtl
408
+ pdf.text(para1 + "\n" + para2, indent_paragraphs: 60)
409
+
410
+ text = PDF::Inspector::Text.analyze(pdf.render)
411
+
412
+ lines = text.strings
413
+ x_positions = text.positions.map { |e| e[0] }
414
+
415
+ # NOTE: The code below reflects Prawn's current kerning behavior for RTL
416
+ # text, which isn't necessarily correct. If we change that behavior,
417
+ # this test will need to be updated.
418
+
419
+ expect(x_positions[0]).to(
420
+ be_within(0.001).of(pdf.bounds.absolute_right - 60 -
421
+ pdf.width_of(lines[0].reverse, kerning: true))
422
+ )
423
+
424
+ expect(x_positions[1]).to(
425
+ be_within(0.001).of(pdf.bounds.absolute_right -
426
+ pdf.width_of(lines[1].reverse, kerning: true))
427
+ )
428
+
429
+ expect(x_positions[2]).to(
430
+ be_within(0.001).of(pdf.bounds.absolute_right - 60 -
431
+ pdf.width_of(lines[2].reverse, kerning: true))
432
+ )
433
+
434
+ expect(x_positions[3]).to(
435
+ be_within(0.001).of(pdf.bounds.absolute_right -
436
+ pdf.width_of(lines[3].reverse, kerning: true))
437
+ )
438
+ end
439
+
440
+ it 'indents from left side when using :ltr direction' do
441
+ para1 = 'The rain in spain falls mainly on the plains ' * 3
442
+ para2 = 'The rain in spain falls mainly on the plains ' * 3
443
+
444
+ pdf.text(para1 + "\n" + para2, indent_paragraphs: 60, direction: :ltr)
445
+
446
+ text = PDF::Inspector::Text.analyze(pdf.render)
447
+
448
+ x_positions = text.positions.map { |e| e[0] }
449
+
450
+ expect(x_positions[0]).to eq(60)
451
+ expect(x_positions[1]).to eq(0)
452
+
453
+ expect(x_positions[2]).to eq(60)
454
+ expect(x_positions[3]).to eq(0)
455
+ end
456
+
457
+ it 'indents from left side when document has :ltr direction' do
458
+ para1 = 'The rain in spain falls mainly on the plains ' * 3
459
+ para2 = 'The rain in spain falls mainly on the plains ' * 3
460
+
461
+ pdf.text_direction = :ltr
462
+ pdf.text(para1 + "\n" + para2, indent_paragraphs: 60)
463
+
464
+ text = PDF::Inspector::Text.analyze(pdf.render)
465
+
466
+ x_positions = text.positions.map { |e| e[0] }
467
+
468
+ expect(x_positions[0]).to eq(60)
469
+ expect(x_positions[1]).to eq(0)
470
+
471
+ expect(x_positions[2]).to eq(60)
472
+ expect(x_positions[3]).to eq(0)
473
+ end
474
+
475
+ describe 'when paragraph has only one line, it should not add ' \
476
+ 'additional leading' do
477
+ let(:leading) { 100 }
478
+
479
+ it 'adds leading only once' do
480
+ original_y = pdf.y
481
+ pdf.text('hello', indent_paragraphs: 10, leading: leading)
482
+ expect(original_y - pdf.y).to be < leading * 2
483
+ end
484
+ end
485
+
486
+ describe 'when wrap to new page, and first line of new page' \
487
+ ' is not the start of a new paragraph, that line should' \
488
+ ' not be indented' do
489
+ it 'indents the paragraphs' do
490
+ hello = 'hello ' * 50
491
+ hello2 = 'hello ' * 50
492
+ pdf.move_cursor_to(pdf.font.height)
493
+ pdf.text(hello + "\n" + hello2, indent_paragraphs: 60)
494
+ text = PDF::Inspector::Text.analyze(pdf.render)
495
+ expect(text.strings[0]).to eq(('hello ' * 19).strip)
496
+ expect(text.strings[1]).to eq(('hello ' * 21).strip)
497
+ expect(text.strings[3]).to eq(('hello ' * 19).strip)
498
+ expect(text.strings[4]).to eq(('hello ' * 21).strip)
499
+ end
500
+ end
501
+
502
+ describe 'when wrap to new page, and first line of new page' \
503
+ ' is the start of a new paragraph, that line should' \
504
+ ' be indented' do
505
+ it 'indents the paragraphs' do
506
+ hello = 'hello ' * 50
507
+ hello2 = 'hello ' * 50
508
+ pdf.move_cursor_to(pdf.font.height * 3)
509
+ pdf.text(hello + "\n" + hello2, indent_paragraphs: 60)
510
+ text = PDF::Inspector::Text.analyze(pdf.render)
511
+ expect(text.strings[0]).to eq(('hello ' * 19).strip)
512
+ expect(text.strings[1]).to eq(('hello ' * 21).strip)
513
+ expect(text.strings[3]).to eq(('hello ' * 19).strip)
514
+ expect(text.strings[4]).to eq(('hello ' * 21).strip)
515
+ end
516
+ end
517
+ end
518
+
519
+ describe 'kerning' do
520
+ it 'respects text kerning setting (document default)' do
521
+ allow(pdf.font).to receive(:compute_width_of)
522
+ .with('VAT', hash_including(kerning: true))
523
+ .and_return(10)
524
+
525
+ pdf.text 'VAT'
526
+
527
+ expect(pdf.font).to have_received(:compute_width_of)
528
+ .with('VAT', hash_including(kerning: true))
529
+ end
530
+
531
+ it 'respects text kerning setting (kerning=true)' do
532
+ allow(pdf.font).to receive(:compute_width_of)
533
+ .with('VAT', hash_including(kerning: true))
534
+ .at_least(:once)
535
+ .and_return(10)
536
+ pdf.text 'VAT', kerning: true
537
+
538
+ expect(pdf.font).to have_received(:compute_width_of)
539
+ .with('VAT', hash_including(kerning: true))
540
+ .at_least(:once)
541
+ end
542
+
543
+ it 'respects text kerning setting (kerning=false)' do
544
+ allow(pdf.font).to receive(:compute_width_of)
545
+ .with('VAT', hash_including(kerning: false))
546
+ .at_least(:once)
547
+ .and_return(10)
548
+ pdf.text 'VAT', kerning: false
549
+
550
+ expect(pdf.font).to have_received(:compute_width_of)
551
+ .with('VAT', hash_including(kerning: false))
552
+ .at_least(:once)
553
+ end
554
+ end
555
+
556
+ describe '#shrink_to_fit with special utf-8 text' do
557
+ it 'does not throw an exception', :unresolved, issue: 603 do
558
+ expect do
559
+ Prawn::Document.new(page_size: 'A4', margin: [2, 2, 2, 2]) do |pdf|
560
+ add_unicode_fonts(pdf)
561
+ pdf.bounding_box([1, 1], width: 90, height: 50) do
562
+ pdf.text(
563
+ "Sample Text\nSAMPLE SAMPLE SAMPLEoddělení ZMĚN\nSAMPLE",
564
+ overflow: :shrink_to_fit
565
+ )
566
+ end
567
+ end
568
+ end.to_not raise_error
569
+ end
570
+ end
571
+
572
+ def add_unicode_fonts(pdf)
573
+ dejavu = "#{::Prawn::BASEDIR}/data/fonts/DejaVuSans.ttf"
574
+ pdf.font_families.update(
575
+ 'dejavu' => {
576
+ normal: dejavu,
577
+ italic: dejavu,
578
+ bold: dejavu,
579
+ bold_italic: dejavu
580
+ }
581
+ )
582
+ pdf.fallback_fonts = ['dejavu']
583
+ end
584
+
585
+ describe 'fallback_fonts' do
586
+ it 'preserves font style' do
587
+ create_pdf
588
+
589
+ pdf.fallback_fonts ['Helvetica']
590
+ pdf.font 'Times-Roman', style: :italic do
591
+ pdf.text 'hello'
592
+ end
593
+
594
+ text = PDF::Inspector::Text.analyze(pdf.render)
595
+ fonts_used = text.font_settings.map { |e| e[:name] }
596
+
597
+ expect(fonts_used.length).to eq(1)
598
+ expect(fonts_used[0]).to eq(:"Times-Italic")
599
+ expect(text.strings[0]).to eq('hello')
600
+ end
601
+ end
602
+ end
603
+ end