davebenvenuti-prawn 0.11.1.pre

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 (291) hide show
  1. data/COPYING +340 -0
  2. data/HACKING +50 -0
  3. data/LICENSE +56 -0
  4. data/README +141 -0
  5. data/Rakefile +52 -0
  6. data/data/encodings/win_ansi.txt +29 -0
  7. data/data/fonts/Action Man.dfont +0 -0
  8. data/data/fonts/Activa.ttf +0 -0
  9. data/data/fonts/Chalkboard.ttf +0 -0
  10. data/data/fonts/Courier-Bold.afm +342 -0
  11. data/data/fonts/Courier-BoldOblique.afm +342 -0
  12. data/data/fonts/Courier-Oblique.afm +342 -0
  13. data/data/fonts/Courier.afm +342 -0
  14. data/data/fonts/DejaVuSans.ttf +0 -0
  15. data/data/fonts/Dustismo_Roman.ttf +0 -0
  16. data/data/fonts/Helvetica-Bold.afm +2827 -0
  17. data/data/fonts/Helvetica-BoldOblique.afm +2827 -0
  18. data/data/fonts/Helvetica-Oblique.afm +3051 -0
  19. data/data/fonts/Helvetica.afm +3051 -0
  20. data/data/fonts/MustRead.html +19 -0
  21. data/data/fonts/Symbol.afm +213 -0
  22. data/data/fonts/Times-Bold.afm +2588 -0
  23. data/data/fonts/Times-BoldItalic.afm +2384 -0
  24. data/data/fonts/Times-Italic.afm +2667 -0
  25. data/data/fonts/Times-Roman.afm +2419 -0
  26. data/data/fonts/ZapfDingbats.afm +225 -0
  27. data/data/fonts/comicsans.ttf +0 -0
  28. data/data/fonts/gkai00mp.ttf +0 -0
  29. data/data/images/16bit.alpha +0 -0
  30. data/data/images/16bit.dat +0 -0
  31. data/data/images/16bit.png +0 -0
  32. data/data/images/arrow.png +0 -0
  33. data/data/images/arrow2.png +0 -0
  34. data/data/images/barcode_issue.png +0 -0
  35. data/data/images/dice.alpha +0 -0
  36. data/data/images/dice.dat +0 -0
  37. data/data/images/dice.png +0 -0
  38. data/data/images/dice_interlaced.png +0 -0
  39. data/data/images/fractal.jpg +0 -0
  40. data/data/images/letterhead.jpg +0 -0
  41. data/data/images/page_white_text.alpha +0 -0
  42. data/data/images/page_white_text.dat +0 -0
  43. data/data/images/page_white_text.png +0 -0
  44. data/data/images/pigs.jpg +0 -0
  45. data/data/images/rails.dat +0 -0
  46. data/data/images/rails.png +0 -0
  47. data/data/images/ruport.png +0 -0
  48. data/data/images/ruport_data.dat +0 -0
  49. data/data/images/ruport_transparent.png +0 -0
  50. data/data/images/ruport_type0.png +0 -0
  51. data/data/images/stef.jpg +0 -0
  52. data/data/images/tru256.bmp +0 -0
  53. data/data/images/web-links.dat +1 -0
  54. data/data/images/web-links.png +0 -0
  55. data/data/pdfs/complex_template.pdf +0 -0
  56. data/data/pdfs/contains_ttf_font.pdf +0 -0
  57. data/data/pdfs/encrypted.pdf +0 -0
  58. data/data/pdfs/hexagon.pdf +61 -0
  59. data/data/pdfs/indirect_reference.pdf +86 -0
  60. data/data/pdfs/nested_pages.pdf +118 -0
  61. data/data/pdfs/page_without_mediabox.pdf +193 -0
  62. data/data/pdfs/resources_as_indirect_object.pdf +83 -0
  63. data/data/pdfs/two_hexagons.pdf +90 -0
  64. data/data/pdfs/version_1_6.pdf +61 -0
  65. data/data/shift_jis_text.txt +1 -0
  66. data/examples/bounding_box/bounding_boxes.rb +44 -0
  67. data/examples/bounding_box/indentation.rb +35 -0
  68. data/examples/bounding_box/russian_boxes.rb +37 -0
  69. data/examples/bounding_box/stretched_nesting.rb +68 -0
  70. data/examples/example_helper.rb +8 -0
  71. data/examples/general/background.rb +24 -0
  72. data/examples/general/canvas.rb +16 -0
  73. data/examples/general/context_sensitive_headers.rb +38 -0
  74. data/examples/general/float.rb +12 -0
  75. data/examples/general/margin.rb +37 -0
  76. data/examples/general/measurement_units.rb +52 -0
  77. data/examples/general/metadata-info.rb +17 -0
  78. data/examples/general/multi_page_layout.rb +19 -0
  79. data/examples/general/outlines.rb +67 -0
  80. data/examples/general/page_geometry.rb +32 -0
  81. data/examples/general/page_numbering.rb +16 -0
  82. data/examples/general/repeaters.rb +48 -0
  83. data/examples/general/stamp.rb +42 -0
  84. data/examples/general/templates.rb +14 -0
  85. data/examples/graphics/basic_images.rb +24 -0
  86. data/examples/graphics/cmyk.rb +13 -0
  87. data/examples/graphics/curves.rb +12 -0
  88. data/examples/graphics/hexagon.rb +14 -0
  89. data/examples/graphics/image_fit.rb +16 -0
  90. data/examples/graphics/image_flow.rb +38 -0
  91. data/examples/graphics/image_position.rb +18 -0
  92. data/examples/graphics/line.rb +33 -0
  93. data/examples/graphics/png_types.rb +23 -0
  94. data/examples/graphics/polygons.rb +17 -0
  95. data/examples/graphics/remote_images.rb +13 -0
  96. data/examples/graphics/rounded_polygons.rb +20 -0
  97. data/examples/graphics/rounded_rectangle.rb +21 -0
  98. data/examples/graphics/ruport_style_helpers.rb +20 -0
  99. data/examples/graphics/stroke_bounds.rb +21 -0
  100. data/examples/graphics/stroke_cap_and_join.rb +46 -0
  101. data/examples/graphics/stroke_dash.rb +43 -0
  102. data/examples/graphics/transformations.rb +53 -0
  103. data/examples/graphics/transparency.rb +27 -0
  104. data/examples/grid/bounding_boxes.rb +22 -0
  105. data/examples/grid/column_gutter_grid.rb +21 -0
  106. data/examples/grid/multi_boxes.rb +52 -0
  107. data/examples/grid/show_grid.rb +14 -0
  108. data/examples/grid/simple_grid.rb +21 -0
  109. data/examples/m17n/chinese_text_wrapping.rb +18 -0
  110. data/examples/m17n/euro.rb +16 -0
  111. data/examples/m17n/sjis.rb +29 -0
  112. data/examples/m17n/utf8.rb +14 -0
  113. data/examples/m17n/win_ansi_charset.rb +55 -0
  114. data/examples/security/hello_foo.rb +9 -0
  115. data/examples/table/bill.rb +54 -0
  116. data/examples/table/cell.rb +13 -0
  117. data/examples/table/checkerboard.rb +23 -0
  118. data/examples/table/header.rb +15 -0
  119. data/examples/table/inline_format_table.rb +13 -0
  120. data/examples/table/multi_page_table.rb +10 -0
  121. data/examples/table/simple_table.rb +25 -0
  122. data/examples/table/subtable.rb +13 -0
  123. data/examples/table/widths.rb +21 -0
  124. data/examples/text/alignment.rb +19 -0
  125. data/examples/text/character_spacing.rb +13 -0
  126. data/examples/text/dfont.rb +49 -0
  127. data/examples/text/family_based_styling.rb +25 -0
  128. data/examples/text/font_calculations.rb +92 -0
  129. data/examples/text/font_size.rb +34 -0
  130. data/examples/text/hyphenation.rb +46 -0
  131. data/examples/text/indent_paragraphs.rb +23 -0
  132. data/examples/text/inline_format.rb +104 -0
  133. data/examples/text/kerning.rb +31 -0
  134. data/examples/text/rotated.rb +99 -0
  135. data/examples/text/shaped_text_box.rb +32 -0
  136. data/examples/text/simple_text.rb +18 -0
  137. data/examples/text/simple_text_ttf.rb +18 -0
  138. data/examples/text/span.rb +30 -0
  139. data/examples/text/text_box.rb +89 -0
  140. data/examples/text/text_box_returning_excess.rb +52 -0
  141. data/examples/text/text_flow.rb +68 -0
  142. data/lib/prawn.rb +26 -0
  143. data/lib/prawn/compatibility.rb +51 -0
  144. data/lib/prawn/core.rb +85 -0
  145. data/lib/prawn/core/annotations.rb +61 -0
  146. data/lib/prawn/core/byte_string.rb +9 -0
  147. data/lib/prawn/core/destinations.rb +90 -0
  148. data/lib/prawn/core/document_state.rb +78 -0
  149. data/lib/prawn/core/literal_string.rb +16 -0
  150. data/lib/prawn/core/name_tree.rb +165 -0
  151. data/lib/prawn/core/object_store.rb +236 -0
  152. data/lib/prawn/core/page.rb +199 -0
  153. data/lib/prawn/core/pdf_object.rb +108 -0
  154. data/lib/prawn/core/reference.rb +112 -0
  155. data/lib/prawn/core/text.rb +140 -0
  156. data/lib/prawn/core/text/formatted/arranger.rb +266 -0
  157. data/lib/prawn/core/text/formatted/line_wrap.rb +127 -0
  158. data/lib/prawn/core/text/formatted/wrap.rb +112 -0
  159. data/lib/prawn/core/text/line_wrap.rb +211 -0
  160. data/lib/prawn/core/text/wrap.rb +82 -0
  161. data/lib/prawn/document.rb +575 -0
  162. data/lib/prawn/document/bounding_box.rb +428 -0
  163. data/lib/prawn/document/graphics_state.rb +48 -0
  164. data/lib/prawn/document/internals.rb +170 -0
  165. data/lib/prawn/document/page_geometry.rb +136 -0
  166. data/lib/prawn/document/snapshot.rb +87 -0
  167. data/lib/prawn/document/span.rb +55 -0
  168. data/lib/prawn/encoding.rb +121 -0
  169. data/lib/prawn/errors.rb +86 -0
  170. data/lib/prawn/font.rb +368 -0
  171. data/lib/prawn/font/afm.rb +225 -0
  172. data/lib/prawn/font/dfont.rb +42 -0
  173. data/lib/prawn/font/ttf.rb +350 -0
  174. data/lib/prawn/graphics.rb +325 -0
  175. data/lib/prawn/graphics/cap_style.rb +38 -0
  176. data/lib/prawn/graphics/color.rb +205 -0
  177. data/lib/prawn/graphics/dash.rb +71 -0
  178. data/lib/prawn/graphics/join_style.rb +38 -0
  179. data/lib/prawn/graphics/transformation.rb +156 -0
  180. data/lib/prawn/graphics/transparency.rb +99 -0
  181. data/lib/prawn/images.rb +217 -0
  182. data/lib/prawn/images/jpg.rb +85 -0
  183. data/lib/prawn/images/png.rb +356 -0
  184. data/lib/prawn/layout.rb +20 -0
  185. data/lib/prawn/layout/grid.rb +259 -0
  186. data/lib/prawn/measurement_extensions.rb +46 -0
  187. data/lib/prawn/measurements.rb +71 -0
  188. data/lib/prawn/outline.rb +326 -0
  189. data/lib/prawn/repeater.rb +129 -0
  190. data/lib/prawn/security.rb +262 -0
  191. data/lib/prawn/security/arcfour.rb +51 -0
  192. data/lib/prawn/stamp.rb +126 -0
  193. data/lib/prawn/table.rb +451 -0
  194. data/lib/prawn/table/cell.rb +395 -0
  195. data/lib/prawn/table/cell/in_table.rb +27 -0
  196. data/lib/prawn/table/cell/subtable.rb +65 -0
  197. data/lib/prawn/table/cell/text.rb +135 -0
  198. data/lib/prawn/table/cells.rb +206 -0
  199. data/lib/prawn/text.rb +449 -0
  200. data/lib/prawn/text/box.rb +397 -0
  201. data/lib/prawn/text/formatted.rb +4 -0
  202. data/lib/prawn/text/formatted/box.rb +222 -0
  203. data/lib/prawn/text/formatted/fragment.rb +181 -0
  204. data/lib/prawn/text/formatted/parser.rb +213 -0
  205. data/prawn.gemspec +28 -0
  206. data/spec/annotations_spec.rb +90 -0
  207. data/spec/bounding_box_spec.rb +190 -0
  208. data/spec/cell_spec.rb +430 -0
  209. data/spec/destinations_spec.rb +15 -0
  210. data/spec/document_spec.rb +476 -0
  211. data/spec/extensions/mocha.rb +32 -0
  212. data/spec/font_spec.rb +324 -0
  213. data/spec/formatted_text_arranger_spec.rb +426 -0
  214. data/spec/formatted_text_box_spec.rb +756 -0
  215. data/spec/formatted_text_fragment_spec.rb +211 -0
  216. data/spec/graphics_spec.rb +446 -0
  217. data/spec/grid_spec.rb +85 -0
  218. data/spec/images_spec.rb +119 -0
  219. data/spec/inline_formatted_text_parser_spec.rb +502 -0
  220. data/spec/jpg_spec.rb +25 -0
  221. data/spec/line_wrap_spec.rb +341 -0
  222. data/spec/measurement_units_spec.rb +23 -0
  223. data/spec/name_tree_spec.rb +112 -0
  224. data/spec/object_store_spec.rb +160 -0
  225. data/spec/outline_spec.rb +404 -0
  226. data/spec/pdf_object_spec.rb +170 -0
  227. data/spec/png_spec.rb +237 -0
  228. data/spec/reference_spec.rb +82 -0
  229. data/spec/repeater_spec.rb +96 -0
  230. data/spec/security_spec.rb +120 -0
  231. data/spec/snapshot_spec.rb +154 -0
  232. data/spec/span_spec.rb +49 -0
  233. data/spec/spec_helper.rb +34 -0
  234. data/spec/stamp_spec.rb +108 -0
  235. data/spec/stroke_styles_spec.rb +163 -0
  236. data/spec/table_spec.rb +687 -0
  237. data/spec/template_spec.rb +165 -0
  238. data/spec/text_at_spec.rb +125 -0
  239. data/spec/text_box_spec.rb +777 -0
  240. data/spec/text_spacing_spec.rb +75 -0
  241. data/spec/text_spec.rb +349 -0
  242. data/spec/text_with_inline_formatting_spec.rb +193 -0
  243. data/spec/transparency_spec.rb +89 -0
  244. data/vendor/pdf-inspector/README +18 -0
  245. data/vendor/pdf-inspector/lib/pdf/inspector.rb +26 -0
  246. data/vendor/pdf-inspector/lib/pdf/inspector/extgstate.rb +18 -0
  247. data/vendor/pdf-inspector/lib/pdf/inspector/graphics.rb +131 -0
  248. data/vendor/pdf-inspector/lib/pdf/inspector/page.rb +25 -0
  249. data/vendor/pdf-inspector/lib/pdf/inspector/text.rb +46 -0
  250. data/vendor/pdf-inspector/lib/pdf/inspector/xobject.rb +19 -0
  251. data/vendor/ttfunk/data/fonts/DejaVuSans.ttf +0 -0
  252. data/vendor/ttfunk/data/fonts/comicsans.ttf +0 -0
  253. data/vendor/ttfunk/example.rb +45 -0
  254. data/vendor/ttfunk/lib/ttfunk.rb +102 -0
  255. data/vendor/ttfunk/lib/ttfunk/directory.rb +17 -0
  256. data/vendor/ttfunk/lib/ttfunk/encoding/mac_roman.rb +88 -0
  257. data/vendor/ttfunk/lib/ttfunk/encoding/windows_1252.rb +69 -0
  258. data/vendor/ttfunk/lib/ttfunk/reader.rb +44 -0
  259. data/vendor/ttfunk/lib/ttfunk/resource_file.rb +78 -0
  260. data/vendor/ttfunk/lib/ttfunk/subset.rb +18 -0
  261. data/vendor/ttfunk/lib/ttfunk/subset/base.rb +141 -0
  262. data/vendor/ttfunk/lib/ttfunk/subset/mac_roman.rb +50 -0
  263. data/vendor/ttfunk/lib/ttfunk/subset/unicode.rb +48 -0
  264. data/vendor/ttfunk/lib/ttfunk/subset/unicode_8bit.rb +63 -0
  265. data/vendor/ttfunk/lib/ttfunk/subset/windows_1252.rb +55 -0
  266. data/vendor/ttfunk/lib/ttfunk/subset_collection.rb +72 -0
  267. data/vendor/ttfunk/lib/ttfunk/table.rb +46 -0
  268. data/vendor/ttfunk/lib/ttfunk/table/cmap.rb +34 -0
  269. data/vendor/ttfunk/lib/ttfunk/table/cmap/format00.rb +54 -0
  270. data/vendor/ttfunk/lib/ttfunk/table/cmap/format04.rb +126 -0
  271. data/vendor/ttfunk/lib/ttfunk/table/cmap/subtable.rb +79 -0
  272. data/vendor/ttfunk/lib/ttfunk/table/glyf.rb +64 -0
  273. data/vendor/ttfunk/lib/ttfunk/table/glyf/compound.rb +81 -0
  274. data/vendor/ttfunk/lib/ttfunk/table/glyf/simple.rb +37 -0
  275. data/vendor/ttfunk/lib/ttfunk/table/head.rb +44 -0
  276. data/vendor/ttfunk/lib/ttfunk/table/hhea.rb +41 -0
  277. data/vendor/ttfunk/lib/ttfunk/table/hmtx.rb +47 -0
  278. data/vendor/ttfunk/lib/ttfunk/table/kern.rb +79 -0
  279. data/vendor/ttfunk/lib/ttfunk/table/kern/format0.rb +62 -0
  280. data/vendor/ttfunk/lib/ttfunk/table/loca.rb +43 -0
  281. data/vendor/ttfunk/lib/ttfunk/table/maxp.rb +40 -0
  282. data/vendor/ttfunk/lib/ttfunk/table/name.rb +125 -0
  283. data/vendor/ttfunk/lib/ttfunk/table/os2.rb +78 -0
  284. data/vendor/ttfunk/lib/ttfunk/table/post.rb +91 -0
  285. data/vendor/ttfunk/lib/ttfunk/table/post/format10.rb +43 -0
  286. data/vendor/ttfunk/lib/ttfunk/table/post/format20.rb +35 -0
  287. data/vendor/ttfunk/lib/ttfunk/table/post/format25.rb +23 -0
  288. data/vendor/ttfunk/lib/ttfunk/table/post/format30.rb +17 -0
  289. data/vendor/ttfunk/lib/ttfunk/table/post/format40.rb +17 -0
  290. data/vendor/ttfunk/lib/ttfunk/table/simple.rb +14 -0
  291. metadata +379 -0
@@ -0,0 +1,27 @@
1
+ # encoding: utf-8
2
+
3
+ # Accessors for using a Cell inside a Table.
4
+
5
+ module Prawn
6
+ class Table
7
+ class Cell
8
+
9
+ # This module extends Cell objects when they are used in a table (as
10
+ # opposed to standalone). Its properties apply to cells-in-tables but not
11
+ # cells themselves.
12
+ #
13
+ module InTable
14
+
15
+ # Row number (0-based).
16
+ #
17
+ attr_accessor :row
18
+
19
+ # Column number (0-based).
20
+ #
21
+ attr_accessor :column
22
+
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,65 @@
1
+ # encoding: utf-8
2
+
3
+ # subtable.rb: Yo dawg.
4
+ #
5
+ # Copyright January 2010, Brad Ediger. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+ module Prawn
9
+ class Table
10
+ class Cell
11
+
12
+ # A Cell that contains another table.
13
+ #
14
+ class Subtable < Cell
15
+
16
+ attr_reader :subtable
17
+
18
+ def initialize(pdf, point, options={})
19
+ super
20
+ @subtable = options[:content]
21
+
22
+ # Subtable padding defaults to zero
23
+ @padding = [0, 0, 0, 0]
24
+ end
25
+
26
+ # Sets the text color of the entire subtable.
27
+ #
28
+ def text_color=(color)
29
+ @subtable.cells.text_color = color
30
+ end
31
+
32
+ # Proxied to subtable.
33
+ #
34
+ def natural_content_width
35
+ @subtable.cells.width
36
+ end
37
+
38
+ # Proxied to subtable.
39
+ #
40
+ def min_width
41
+ @subtable.cells.min_width
42
+ end
43
+
44
+ # Proxied to subtable.
45
+ #
46
+ def max_width
47
+ @subtable.cells.max_width
48
+ end
49
+
50
+ # Proxied to subtable.
51
+ #
52
+ def natural_content_height
53
+ @subtable.cells.height
54
+ end
55
+
56
+ # Draws the subtable.
57
+ #
58
+ def draw_content
59
+ @subtable.draw
60
+ end
61
+
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,135 @@
1
+ # encoding: utf-8
2
+
3
+ # text.rb: Text table cells.
4
+ #
5
+ # Copyright December 2009, Gregory Brown and Brad Ediger. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+ module Prawn
9
+ class Table
10
+ class Cell
11
+
12
+ # A Cell that contains text. Has some limited options to set font family,
13
+ # size, and style.
14
+ #
15
+ class Text < Cell
16
+
17
+ TextOptions = [:inline_format, :kerning, :size, :align, :valign,
18
+ :rotate, :rotate_around, :leading, :single_line, :skip_encoding,
19
+ :overflow, :min_font_size]
20
+
21
+ TextOptions.each do |option|
22
+ define_method("#{option}=") { |v| @text_options[option] = v }
23
+ define_method(option) { @text_options[option] }
24
+ end
25
+
26
+ attr_writer :font, :text_color
27
+
28
+ def initialize(pdf, point, options={})
29
+ @text_options = {}
30
+ super
31
+ end
32
+
33
+ # Returns the font that will be used to draw this cell.
34
+ #
35
+ def font
36
+ with_font { @pdf.font }
37
+ end
38
+
39
+ # Sets the style of the font in use. Equivalent to the Text::Box
40
+ # +style+ option, but we already have a style method.
41
+ #
42
+ def font_style=(style)
43
+ @text_options[:style] = style
44
+ end
45
+
46
+ # Returns the width of this text with no wrapping. This will be far off
47
+ # from the final width if the text is long.
48
+ #
49
+ def natural_content_width
50
+ [styled_width_of(@content), @pdf.bounds.width].min
51
+ end
52
+
53
+ # Returns the natural height of this block of text, wrapped to the
54
+ # preset width.
55
+ #
56
+ def natural_content_height
57
+ with_font do
58
+ b = text_box(:width => content_width + FPTolerance)
59
+ b.render(:dry_run => true)
60
+ b.height
61
+ end
62
+ end
63
+
64
+ # Draws the text content into its bounding box.
65
+ #
66
+ def draw_content
67
+ with_font do
68
+ @pdf.move_down((@pdf.font.line_gap + @pdf.font.descender)/2)
69
+ with_text_color do
70
+ text_box(:width => content_width + FPTolerance,
71
+ :height => content_height + FPTolerance,
72
+ :at => [0, @pdf.cursor]).render
73
+ end
74
+ end
75
+ end
76
+
77
+ protected
78
+
79
+ def set_width_constraints
80
+ # Sets a reasonable minimum width. If the cell has any content, make
81
+ # sure we have enough width to be at least one character wide. This is
82
+ # a bit of a hack, but it should work well enough.
83
+ min_content_width = [natural_content_width, styled_width_of("M")].min
84
+ @min_width ||= padding_left + padding_right + min_content_width
85
+ super
86
+ end
87
+
88
+ def with_font
89
+ @pdf.save_font do
90
+ options = {}
91
+ options[:style] = @text_options[:style] if @text_options[:style]
92
+
93
+ @pdf.font(@font || @pdf.font.name, options)
94
+
95
+ yield
96
+ end
97
+ end
98
+
99
+ def with_text_color
100
+ old_color = @pdf.fill_color || '000000'
101
+ @pdf.fill_color(@text_color) if @text_color
102
+ yield
103
+ ensure
104
+ @pdf.fill_color(old_color)
105
+ end
106
+
107
+ def text_box(extra_options={})
108
+ if @text_options[:inline_format]
109
+ options = @text_options.dup
110
+ options.delete(:inline_format)
111
+
112
+ array = ::Prawn::Text::Formatted::Parser.to_array(@content)
113
+ ::Prawn::Text::Formatted::Box.new(array,
114
+ options.merge(extra_options).merge(:document => @pdf))
115
+ else
116
+ ::Prawn::Text::Box.new(@content, @text_options.merge(extra_options).
117
+ merge(:document => @pdf))
118
+ end
119
+ end
120
+
121
+ # Returns the width of +text+ under the given text options.
122
+ #
123
+ def styled_width_of(text)
124
+ with_font do
125
+ options = {}
126
+ options[:size] = @text_options[:size] if @text_options[:size]
127
+
128
+ @pdf.font.compute_width_of(text, options)
129
+ end
130
+ end
131
+
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,206 @@
1
+ # encoding: utf-8
2
+
3
+ # cells.rb: Methods for accessing rows, columns, and cells of a Prawn::Table.
4
+ #
5
+ # Copyright December 2009, Brad Ediger. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+
9
+ module Prawn
10
+ class Table
11
+
12
+ # Returns a Cells object that can be used to select and style cells. See
13
+ # the Cells documentation for things you can do with cells.
14
+ #
15
+ def cells
16
+ @cell_proxy ||= Cells.new(@cells)
17
+ end
18
+
19
+ # Selects the given rows (0-based) for styling. Returns a Cells object --
20
+ # see the documentation on Cells for things you can do with cells.
21
+ #
22
+ def rows(row_spec)
23
+ cells.rows(row_spec)
24
+ end
25
+ alias_method :row, :rows
26
+
27
+ # Selects the given columns (0-based) for styling. Returns a Cells object
28
+ # -- see the documentation on Cells for things you can do with cells.
29
+ #
30
+ def columns(col_spec)
31
+ cells.columns(col_spec)
32
+ end
33
+ alias_method :column, :columns
34
+
35
+ # Represents a selection of cells to be styled. Operations on a CellProxy
36
+ # can be chained, and cell properties can be set one-for-all on the proxy.
37
+ #
38
+ # To set vertical borders only:
39
+ #
40
+ # table.cells.borders = [:left, :right]
41
+ #
42
+ # To highlight a rectangular area of the table:
43
+ #
44
+ # table.rows(1..3).columns(2..4).background_color = 'ff0000'
45
+ #
46
+ class Cells < Array
47
+
48
+ # Limits selection to the given row or rows. +row_spec+ can be anything
49
+ # that responds to the === operator selecting a set of 0-based row
50
+ # numbers; most commonly a number or a range.
51
+ #
52
+ # table.row(0) # selects first row
53
+ # table.rows(3..4) # selects rows four and five
54
+ #
55
+ def rows(row_spec)
56
+ index_cells unless @indexed
57
+ row_spec = transform_spec(row_spec, @row_count)
58
+ Cells.new(@rows[row_spec] ||= select{ |c| row_spec === c.row })
59
+ end
60
+ alias_method :row, :rows
61
+
62
+ # Limits selection to the given column or columns. +col_spec+ can be
63
+ # anything that responds to the === operator selecting a set of 0-based
64
+ # column numbers; most commonly a number or a range.
65
+ #
66
+ # table.column(0) # selects first column
67
+ # table.columns(3..4) # selects columns four and five
68
+ #
69
+ def columns(col_spec)
70
+ index_cells unless @indexed
71
+ col_spec = transform_spec(col_spec, @column_count)
72
+ Cells.new(@columns[col_spec] ||= select{ |c| col_spec === c.column })
73
+ end
74
+ alias_method :column, :columns
75
+
76
+ # Allows you to filter the given cells by arbitrary properties.
77
+ #
78
+ # table.column(4).filter { |cell| cell.content =~ /Yes/ }.
79
+ # background_color = '00ff00'
80
+ #
81
+ def filter(&block)
82
+ Cells.new(select(&block))
83
+ end
84
+
85
+ # Retrieves a cell based on its 0-based row and column. Returns an
86
+ # individual Cell, not a Cells collection.
87
+ #
88
+ # table.cells[0, 0].content # => "First cell content"
89
+ #
90
+ def [](row, col)
91
+ find { |c| c.row == row && c.column == col }
92
+ end
93
+
94
+ # Supports setting multiple properties at once.
95
+ #
96
+ # table.cells.style(:padding => 0, :border_width => 2)
97
+ #
98
+ # is the same as:
99
+ #
100
+ # table.cells.padding = 0
101
+ # table.cells.border_width = 2
102
+ #
103
+ # You can also pass a block, which will be called for each cell in turn.
104
+ # This allows you to set more complicated properties:
105
+ #
106
+ # table.cells.style { |cell| cell.border_width += 12 }
107
+ #
108
+ def style(options={}, &block)
109
+ each { |cell| cell.style(options, &block) }
110
+ end
111
+
112
+ # Returns the total width of all columns in the selected set.
113
+ #
114
+ def width
115
+ column_widths = {}
116
+ each do |cell|
117
+ column_widths[cell.column] =
118
+ [column_widths[cell.column], cell.width].compact.max
119
+ end
120
+ column_widths.values.inject(0) { |sum, width| sum + width }
121
+ end
122
+
123
+ # Returns minimum width required to contain cells in the set.
124
+ #
125
+ def min_width
126
+ column_min_widths = {}
127
+ each do |cell|
128
+ column_min_widths[cell.column] =
129
+ [column_min_widths[cell.column], cell.min_width].compact.max
130
+ end
131
+ column_min_widths.values.inject(0) { |sum, width| sum + width }
132
+ end
133
+
134
+ # Returns maximum width that can contain cells in the set.
135
+ #
136
+ def max_width
137
+ column_max_widths = {}
138
+ each do |cell|
139
+ column_max_widths[cell.column] =
140
+ [column_max_widths[cell.column], cell.max_width].compact.min
141
+ end
142
+ column_max_widths.values.inject(0) { |sum, width| sum + width }
143
+ end
144
+
145
+ # Returns the total height of all rows in the selected set.
146
+ #
147
+ def height
148
+ row_heights = {}
149
+ each do |cell|
150
+ row_heights[cell.row] =
151
+ [row_heights[cell.row], cell.height].compact.max
152
+ end
153
+ row_heights.values.inject(0) { |sum, width| sum + width }
154
+ end
155
+
156
+ # Supports setting arbitrary properties on a group of cells.
157
+ #
158
+ # table.cells.row(3..6).background_color = 'cc0000'
159
+ #
160
+ def method_missing(id, *args, &block)
161
+ each { |c| c.send(id, *args, &block) }
162
+ end
163
+
164
+ protected
165
+
166
+ # Defers indexing until rows() or columns() is actually called on the
167
+ # Cells object. Without this, we would needlessly index the leaf nodes of
168
+ # the object graph, the ones that are only there to be iterated over.
169
+ #
170
+ # Make sure to call this before using @rows or @columns.
171
+ #
172
+ def index_cells
173
+ @rows = {}
174
+ @columns = {}
175
+
176
+ each do |cell|
177
+ @rows[cell.row] ||= []
178
+ @rows[cell.row] << cell
179
+
180
+ @columns[cell.column] ||= []
181
+ @columns[cell.column] << cell
182
+ end
183
+
184
+ @row_count = @rows.size
185
+ @column_count = @columns.size
186
+
187
+ @indexed = true
188
+ end
189
+
190
+ # Transforms +spec+, a column / row specification, into an object that
191
+ # can be compared against a row or column number using ===. Normalizes
192
+ # negative indices to be positive, given a total size of +total+.
193
+ #
194
+ def transform_spec(spec, total)
195
+ case spec
196
+ when Range
197
+ transform_spec(spec.begin, total)..transform_spec(spec.end, total)
198
+ when Integer
199
+ spec < 0 ? (total + spec) : spec
200
+ else # pass through
201
+ spec
202
+ end
203
+ end
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,449 @@
1
+ # encoding: utf-8
2
+
3
+ # text.rb : Implements PDF text primitives
4
+ #
5
+ # Copyright May 2008, Gregory Brown. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+ require "prawn/core/text"
9
+ require "prawn/core/text/wrap"
10
+ require "prawn/text/box"
11
+ require "prawn/text/formatted"
12
+ require "zlib"
13
+
14
+ module Prawn
15
+ module Text
16
+
17
+ include Prawn::Core::Text
18
+ include Prawn::Text::Formatted
19
+
20
+ Prawn::Text::NBSP = " "
21
+
22
+ # If you want text to flow onto a new page or between columns, this is the
23
+ # method to use. If, instead, if you want to place bounded text outside of
24
+ # the flow of a document (for captions, labels, charts, etc.), use Text::Box
25
+ # or its convenience method text_box.
26
+ #
27
+ # Draws text on the page. Prawn attempts to wrap the text to fit within your
28
+ # current bounding box (or margin_box if no bounding box is being used).
29
+ # Text will flow onto the next page when it reaches the bottom of the
30
+ # bounding box. Text wrap in Prawn does not re-flow linebreaks, so if you
31
+ # want fully automated text wrapping, be sure to remove newlines before
32
+ # attempting to draw your string.
33
+ #
34
+ # == Examples
35
+ #
36
+ # pdf.text "Will be wrapped when it hits the edge of your bounding box"
37
+ # pdf.text "This will be centered", :align => :center
38
+ # pdf.text "This will be right aligned", :align => :right
39
+ # pdf.text "This <i>includes <b>inline</b></i> <font size='24'>" +
40
+ # "formatting</font>", :inline_format => true
41
+ #
42
+ # If your font contains kerning pair data that Prawn can parse, the
43
+ # text will be kerned by default. You can disable kerning by including
44
+ # a false <tt>:kerning</tt> option. If you want to disable kerning on an
45
+ # entire document, set default_kerning = false for that document
46
+ #
47
+ # === Text Positioning Details
48
+ #
49
+ # The text is positioned at font.ascender below the baseline,
50
+ # making it easy to use this method within bounding boxes and spans.
51
+ #
52
+ # == Encoding
53
+ #
54
+ # Note that strings passed to this function should be encoded as UTF-8.
55
+ # If you get unexpected characters appearing in your rendered document,
56
+ # check this.
57
+ #
58
+ # If the current font is a built-in one, although the string must be
59
+ # encoded as UTF-8, only characters that are available in WinAnsi
60
+ # are allowed.
61
+ #
62
+ # If an empty box is rendered to your PDF instead of the character you
63
+ # wanted it usually means the current font doesn't include that character.
64
+ #
65
+ # == Options (default values marked in [])
66
+ #
67
+ # <tt>:inline_format</tt>::
68
+ # <tt>boolean</tt>. If true, then the string parameter is interpreted
69
+ # as a HTML-esque string that recognizes the following tags:
70
+ # <tt>\<b></b></tt>:: bold
71
+ # <tt>\<i></i></tt>:: italic
72
+ # <tt>\<u></u></tt>:: underline
73
+ # <tt>\<strikethrough></strikethrough></tt>:: strikethrough
74
+ # <tt>\<sub></sub></tt>:: subscript
75
+ # <tt>\<sup></sup></tt>:: superscript
76
+ # <tt>\<font></font></tt>::
77
+ # with the following attributes (using double or single quotes)
78
+ # <tt>size="24"</tt>::
79
+ # attribute for setting size
80
+ # <tt>character_spacing="2.5"</tt>::
81
+ # attribute for setting character spacing
82
+ # <tt>name="Helvetica"</tt>::
83
+ # attribute for setting the font. The font name must be an
84
+ # AFM font with the desired faces or must be a font that is
85
+ # already registered using Prawn::Document#font_families
86
+ # <tt>\<color></color></tt>::
87
+ # with the following attributes
88
+ # <tt>rgb="ffffff" or rgb="#ffffff"</tt>::
89
+ # <tt>c="100" m="100" y="100" k="100"</tt>::
90
+ # <tt>\<link></link></tt>::
91
+ # with the following attributes
92
+ # <tt>href="http://example.com"</tt>:: an external link
93
+ # <tt>anchor="ToC"</tt>::
94
+ # where the value of the anchor attribute is the name of a
95
+ # destination that has already been or will be registered
96
+ # using Prawn::Core::Destinations#add_dest. A clickable link
97
+ # will be created to that destination.
98
+ # Note that you must explicitly underline and color using the
99
+ # appropriate tags if you which to draw attention to the link
100
+ #
101
+ # <tt>:kerning</tt>:: <tt>boolean</tt>. Whether or not to use kerning (if it
102
+ # is available with the current font)
103
+ # [value of default_kerning?]
104
+ # <tt>:size</tt>:: <tt>number</tt>. The font size to use. [current font
105
+ # size]
106
+ # <tt>:character_spacing</tt>:: <tt>number</tt>. The amount of space to add
107
+ # to or remove from the default character
108
+ # spacing. [0]
109
+ # <tt>:style</tt>:: The style to use. The requested style must be part of
110
+ # the current font familly. [current style]
111
+ # <tt>:indent_paragraphs</tt>:: <tt>number</tt>. The amount to indent the
112
+ # first line of each paragraph. Omit this
113
+ # option if you do not want indenting
114
+ # <tt>:align</tt>:: <tt>:left</tt>, <tt>:center</tt>, <tt>:right</tt>, or
115
+ # <tt>:justify</tt> Alignment within the bounding box [:left]
116
+ # <tt>:valign</tt>:: <tt>:top</tt>, <tt>:center</tt>, or <tt>:bottom</tt>.
117
+ # Vertical alignment within the bounding box [:top]
118
+ # <tt>:leading</tt>:: <tt>number</tt>. Additional space between lines [0]
119
+ # <tt>:final_gap</tt>:: <tt>boolean</tt>. If true, then the space between
120
+ # each line is included below the last line;
121
+ # otherwise, document.y is placed just below the
122
+ # descender of the last line printed [true]
123
+ #
124
+ # == Exceptions
125
+ #
126
+ # Raises <tt>ArgumentError</tt> if <tt>:at</tt> option included
127
+ #
128
+ # Raises <tt>Prawn::Errrors::CannotFit</tt> if not wide enough to print
129
+ # any text
130
+ #
131
+ def text(string, options={})
132
+ # we modify the options. don't change the user's hash
133
+ options = options.dup
134
+
135
+ if options[:inline_format]
136
+ options.delete(:inline_format)
137
+ array = Text::Formatted::Parser.to_array(string)
138
+ formatted_text(array, options)
139
+ return
140
+ end
141
+
142
+ inspect_options_for_text(options)
143
+
144
+ if @indent_paragraphs
145
+ string.split("\n").each do |paragraph|
146
+ options[:skip_encoding] = false
147
+ remaining_text = draw_indented_line(paragraph, options)
148
+ options[:skip_encoding] = true
149
+ if remaining_text == paragraph
150
+ # we were too close to the bottom of the page to print even one line
151
+ @bounding_box.move_past_bottom
152
+ remaining_text = draw_indented_line(paragraph, options)
153
+ end
154
+ remaining_text = fill_text_box(remaining_text, options)
155
+ draw_remaining_text_on_new_pages(remaining_text, options)
156
+ end
157
+ else
158
+ remaining_text = fill_text_box(string, options)
159
+ options[:skip_encoding] = true
160
+ draw_remaining_text_on_new_pages(remaining_text, options)
161
+ end
162
+ end
163
+
164
+
165
+ # Draws formatted text to the page.
166
+ # Formatted text is comprised of an array of hashes, where each hash defines
167
+ # text and format information. See Text::Formatted#formatted_text_box for
168
+ # more information on the structure of this array
169
+ #
170
+ # == Example
171
+ #
172
+ # text([{ :text => "hello" },
173
+ # { :text => "world",
174
+ # :size => 24,
175
+ # :style => [:bold, :italic] }])
176
+ #
177
+ # == Options
178
+ #
179
+ # Accepts the same options as #text
180
+ #
181
+ # == Exceptions
182
+ #
183
+ # Same as for #text
184
+ #
185
+ def formatted_text(array, options={})
186
+ # we modify the options. don't change the user's hash
187
+ options = options.dup
188
+
189
+ inspect_options_for_text(options)
190
+
191
+ if @indent_paragraphs
192
+ Text::Formatted::Parser.array_paragraphs(array).each do |paragraph|
193
+ options[:skip_encoding] = false
194
+ remaining_text = draw_indented_formatted_line(paragraph, options)
195
+ options[:skip_encoding] = true
196
+ if remaining_text == paragraph
197
+ # we were too close to the bottom of the page to print even one line
198
+ @bounding_box.move_past_bottom
199
+ remaining_text = draw_indented_formatted_line(paragraph, options)
200
+ end
201
+ remaining_text = fill_formatted_text_box(remaining_text, options)
202
+ draw_remaining_formatted_text_on_new_pages(remaining_text, options)
203
+ end
204
+ else
205
+ remaining_text = fill_formatted_text_box(array, options)
206
+ options[:skip_encoding] = true
207
+ draw_remaining_formatted_text_on_new_pages(remaining_text, options)
208
+ end
209
+ end
210
+
211
+ # Draws text on the page, beginning at the point specified by the :at option
212
+ # the string is assumed to be pre-formatted to properly fit the page.
213
+ #
214
+ # pdf.draw_text "Hello World", :at => [100,100]
215
+ # pdf.draw_text "Goodbye World", :at => [50,50], :size => 16
216
+ #
217
+ # If your font contains kerning pair data that Prawn can parse, the
218
+ # text will be kerned by default. You can disable kerning by including
219
+ # a false <tt>:kerning</tt> option. If you want to disable kerning on an
220
+ # entire document, set default_kerning = false for that document
221
+ #
222
+ # === Text Positioning Details:
223
+ #
224
+ # Prawn will position your text by the left-most edge of its baseline, and
225
+ # flow along a single line. (This means that :align will not work)
226
+ #
227
+ # == Rotation
228
+ #
229
+ # Text can be rotated before it is placed on the canvas by specifying the
230
+ # <tt>:rotate</tt> option with a given angle. Rotation occurs counter-clockwise.
231
+ #
232
+ # == Encoding
233
+ #
234
+ # Note that strings passed to this function should be encoded as UTF-8.
235
+ # If you get unexpected characters appearing in your rendered document,
236
+ # check this.
237
+ #
238
+ # If the current font is a built-in one, although the string must be
239
+ # encoded as UTF-8, only characters that are available in WinAnsi
240
+ # are allowed.
241
+ #
242
+ # If an empty box is rendered to your PDF instead of the character you
243
+ # wanted it usually means the current font doesn't include that character.
244
+ #
245
+ # == Options (default values marked in [])
246
+ #
247
+ # <tt>:at</tt>:: <tt>[x, y]</tt>(required). The position at which to start the text
248
+ # <tt>:kerning</tt>:: <tt>boolean</tt>. Whether or not to use kerning (if it
249
+ # is available with the current font)
250
+ # [value of default_kerning?]
251
+ # <tt>:size</tt>:: <tt>number</tt>. The font size to use. [current font
252
+ # size]
253
+ # <tt>:style</tt>:: The style to use. The requested style must be part of
254
+ # the current font familly. [current style]
255
+ #
256
+ # <tt>:rotate</tt>:: <tt>number</tt>. The angle to which to rotate text
257
+ #
258
+ # == Exceptions
259
+ #
260
+ # Raises <tt>ArgumentError</tt> if <tt>:at</tt> option omitted
261
+ #
262
+ # Raises <tt>ArgumentError</tt> if <tt>:align</tt> option included
263
+ #
264
+ def draw_text(text, options)
265
+ # we modify the options. don't change the user's hash
266
+ options = options.dup
267
+ inspect_options_for_draw_text(options)
268
+ # dup because normalize_encoding changes the string
269
+ text = text.to_s.dup
270
+ save_font do
271
+ process_text_options(options)
272
+ font.normalize_encoding!(text) unless @skip_encoding
273
+ font_size(options[:size]) { draw_text!(text, options) }
274
+ end
275
+ end
276
+
277
+ # Gets height of text in PDF points.
278
+ # Same options as #text, except as noted.
279
+ # Not compatible with :indent_paragraphs option
280
+ #
281
+ # ==Example
282
+ #
283
+ # height_of("hello\nworld")
284
+ #
285
+ # == Exceptions
286
+ #
287
+ # Raises <tt>NotImplementedError</tt> if <tt>:indent_paragraphs</tt>
288
+ # option included
289
+ #
290
+ # Raises <tt>Prawn::Errrors::CannotFit</tt> if not wide enough to print
291
+ # any text
292
+ #
293
+ def height_of(string, options={})
294
+ if options[:indent_paragraphs]
295
+ raise NotImplementedError, ":indent_paragraphs option not available" +
296
+ "with height_of"
297
+ end
298
+ process_final_gap_option(options)
299
+ box = Text::Box.new(string,
300
+ options.merge(:height => 100000000,
301
+ :document => self))
302
+ printed = box.render(:dry_run => true)
303
+
304
+ height = box.height - (box.line_height - box.ascender)
305
+ height += box.line_height + box.leading - box.ascender if @final_gap
306
+ height
307
+ end
308
+
309
+ # Gets height of formatted text in PDF points.
310
+ # See documentation for #height_of.
311
+ #
312
+ # ==Example
313
+ #
314
+ # height_of_formatted([{ :text => "hello" },
315
+ # { :text => "world",
316
+ # :size => 24,
317
+ # :style => [:bold, :italic] }])
318
+ #
319
+ def height_of_formatted(array, options={})
320
+ if options[:indent_paragraphs]
321
+ raise NotImplementedError, ":indent_paragraphs option not available" +
322
+ "with height_of"
323
+ end
324
+ process_final_gap_option(options)
325
+ box = Text::Formatted::Box.new(array,
326
+ options.merge(:height => 100000000,
327
+ :document => self))
328
+ printed = box.render(:dry_run => true)
329
+
330
+ height = box.height - (box.line_height - box.ascender)
331
+ height += box.line_height + box.leading - box.ascender if @final_gap
332
+ height
333
+ end
334
+
335
+ private
336
+
337
+ def draw_remaining_text_on_new_pages(remaining_text, options)
338
+ while remaining_text.length > 0
339
+ @bounding_box.move_past_bottom
340
+ previous_remaining_text = remaining_text
341
+ remaining_text = fill_text_box(remaining_text, options)
342
+ break if remaining_text == previous_remaining_text
343
+ end
344
+ end
345
+
346
+ def draw_indented_line(string, options)
347
+ indent(@indent_paragraphs) do
348
+ fill_text_box(string, options.dup.merge(:single_line => true))
349
+ end
350
+ end
351
+
352
+ def fill_text_box(text, options)
353
+ merge_text_box_positioning_options(options)
354
+
355
+ box = Text::Box.new(text, options)
356
+ remaining_text = box.render
357
+
358
+ self.y -= box.height - (box.line_height - box.ascender)
359
+ if @final_gap
360
+ self.y -= box.line_height + box.leading - box.ascender
361
+ end
362
+ remaining_text
363
+ end
364
+
365
+
366
+
367
+
368
+ def draw_remaining_formatted_text_on_new_pages(remaining_text, options)
369
+ while remaining_text.length > 0
370
+ @bounding_box.move_past_bottom
371
+ previous_remaining_text = remaining_text
372
+ remaining_text = fill_formatted_text_box(remaining_text, options)
373
+ break if remaining_text == previous_remaining_text
374
+ end
375
+ end
376
+
377
+ def draw_indented_formatted_line(string, options)
378
+ indent(@indent_paragraphs) do
379
+ fill_formatted_text_box(string, options.dup.merge(:single_line => true))
380
+ end
381
+ end
382
+
383
+ def fill_formatted_text_box(text, options)
384
+ merge_text_box_positioning_options(options)
385
+ box = Text::Formatted::Box.new(text, options)
386
+ remaining_text = box.render
387
+
388
+ self.y -= box.height - (box.line_height - box.ascender)
389
+ if @final_gap
390
+ self.y -= box.line_height + box.leading - box.ascender
391
+ end
392
+ remaining_text
393
+ end
394
+
395
+
396
+
397
+ def merge_text_box_positioning_options(options)
398
+ bottom = @bounding_box.stretchy? ? @margin_box.absolute_bottom :
399
+ @bounding_box.absolute_bottom
400
+
401
+ options[:height] = y - bottom
402
+ options[:width] = bounds.width
403
+ options[:at] = [@bounding_box.left_side - @bounding_box.absolute_left,
404
+ y - @bounding_box.absolute_bottom]
405
+ end
406
+
407
+ def inspect_options_for_draw_text(options)
408
+ if options[:at].nil?
409
+ raise ArgumentError, "The :at option is required for draw_text"
410
+ elsif options[:align]
411
+ raise ArgumentError, "The :align option does not work with draw_text"
412
+ end
413
+ if options[:kerning].nil? then
414
+ options[:kerning] = default_kerning?
415
+ end
416
+ valid_options = Prawn::Core::Text::VALID_OPTIONS + [:at, :rotate]
417
+ Prawn.verify_options(valid_options, options)
418
+ end
419
+
420
+ def inspect_options_for_text(options)
421
+ if options[:at]
422
+ raise ArgumentError, ":at is no longer a valid option with text." +
423
+ "use draw_text or text_box instead"
424
+ end
425
+ process_final_gap_option(options)
426
+ process_indent_paragraphs_option(options)
427
+ options[:document] = self
428
+ end
429
+
430
+ def process_final_gap_option(options)
431
+ @final_gap = options[:final_gap].nil? || options[:final_gap]
432
+ options.delete(:final_gap)
433
+ end
434
+
435
+ def process_indent_paragraphs_option(options)
436
+ @indent_paragraphs = options[:indent_paragraphs]
437
+ options.delete(:indent_paragraphs)
438
+ end
439
+
440
+ def move_text_position(dy)
441
+ bottom = @bounding_box.stretchy? ? @margin_box.absolute_bottom :
442
+ @bounding_box.absolute_bottom
443
+
444
+ @bounding_box.move_past_bottom if (y - dy) < bottom
445
+
446
+ self.y -= dy
447
+ end
448
+ end
449
+ end