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