prawn-git 2.0.1

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 (252) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +10 -0
  3. data/COPYING +2 -0
  4. data/GPLv2 +340 -0
  5. data/GPLv3 +674 -0
  6. data/Gemfile +11 -0
  7. data/LICENSE +56 -0
  8. data/Rakefile +55 -0
  9. data/data/fonts/Courier-Bold.afm +342 -0
  10. data/data/fonts/Courier-BoldOblique.afm +342 -0
  11. data/data/fonts/Courier-Oblique.afm +342 -0
  12. data/data/fonts/Courier.afm +342 -0
  13. data/data/fonts/Helvetica-Bold.afm +2827 -0
  14. data/data/fonts/Helvetica-BoldOblique.afm +2827 -0
  15. data/data/fonts/Helvetica-Oblique.afm +3051 -0
  16. data/data/fonts/Helvetica.afm +3051 -0
  17. data/data/fonts/MustRead.html +19 -0
  18. data/data/fonts/Symbol.afm +213 -0
  19. data/data/fonts/Times-Bold.afm +2588 -0
  20. data/data/fonts/Times-BoldItalic.afm +2384 -0
  21. data/data/fonts/Times-Italic.afm +2667 -0
  22. data/data/fonts/Times-Roman.afm +2419 -0
  23. data/data/fonts/ZapfDingbats.afm +225 -0
  24. data/data/images/16bit.alpha +0 -0
  25. data/data/images/16bit.color +0 -0
  26. data/data/images/16bit.png +0 -0
  27. data/data/images/arrow.png +0 -0
  28. data/data/images/arrow2.png +0 -0
  29. data/data/images/dice.alpha +0 -0
  30. data/data/images/dice.color +0 -0
  31. data/data/images/dice.png +0 -0
  32. data/data/images/dice_interlaced.png +0 -0
  33. data/data/images/fractal.jpg +0 -0
  34. data/data/images/indexed_color.dat +0 -0
  35. data/data/images/indexed_color.png +0 -0
  36. data/data/images/letterhead.jpg +0 -0
  37. data/data/images/license.md +8 -0
  38. data/data/images/page_white_text.alpha +0 -0
  39. data/data/images/page_white_text.color +0 -0
  40. data/data/images/page_white_text.png +0 -0
  41. data/data/images/pal_bk.png +0 -0
  42. data/data/images/pigs.jpg +0 -0
  43. data/data/images/prawn.png +0 -0
  44. data/data/images/ruport.png +0 -0
  45. data/data/images/ruport_data.dat +0 -0
  46. data/data/images/ruport_transparent.png +0 -0
  47. data/data/images/ruport_type0.png +0 -0
  48. data/data/images/stef.jpg +0 -0
  49. data/data/images/tru256.bmp +0 -0
  50. data/data/images/web-links.dat +1 -0
  51. data/data/images/web-links.png +0 -0
  52. data/data/pdfs/complex_template.pdf +0 -0
  53. data/data/pdfs/contains_ttf_font.pdf +0 -0
  54. data/data/pdfs/encrypted.pdf +0 -0
  55. data/data/pdfs/form.pdf +820 -0
  56. data/data/pdfs/hexagon.pdf +61 -0
  57. data/data/pdfs/indirect_reference.pdf +86 -0
  58. data/data/pdfs/multipage_template.pdf +127 -0
  59. data/data/pdfs/nested_pages.pdf +118 -0
  60. data/data/pdfs/page_without_mediabox.pdf +193 -0
  61. data/data/pdfs/resources_as_indirect_object.pdf +83 -0
  62. data/data/pdfs/two_hexagons.pdf +90 -0
  63. data/data/pdfs/version_1_6.pdf +61 -0
  64. data/data/shift_jis_text.txt +1 -0
  65. data/lib/prawn.rb +89 -0
  66. data/lib/prawn/document.rb +706 -0
  67. data/lib/prawn/document/bounding_box.rb +539 -0
  68. data/lib/prawn/document/column_box.rb +144 -0
  69. data/lib/prawn/document/internals.rb +58 -0
  70. data/lib/prawn/document/span.rb +57 -0
  71. data/lib/prawn/encoding.rb +87 -0
  72. data/lib/prawn/errors.rb +80 -0
  73. data/lib/prawn/font.rb +413 -0
  74. data/lib/prawn/font/afm.rb +256 -0
  75. data/lib/prawn/font/dfont.rb +43 -0
  76. data/lib/prawn/font/ttf.rb +355 -0
  77. data/lib/prawn/font_metric_cache.rb +46 -0
  78. data/lib/prawn/graphics.rb +646 -0
  79. data/lib/prawn/graphics/cap_style.rb +47 -0
  80. data/lib/prawn/graphics/color.rb +232 -0
  81. data/lib/prawn/graphics/dash.rb +109 -0
  82. data/lib/prawn/graphics/join_style.rb +49 -0
  83. data/lib/prawn/graphics/patterns.rb +126 -0
  84. data/lib/prawn/graphics/transformation.rb +157 -0
  85. data/lib/prawn/graphics/transparency.rb +101 -0
  86. data/lib/prawn/grid.rb +279 -0
  87. data/lib/prawn/image_handler.rb +44 -0
  88. data/lib/prawn/images.rb +199 -0
  89. data/lib/prawn/images/image.rb +49 -0
  90. data/lib/prawn/images/jpg.rb +91 -0
  91. data/lib/prawn/images/png.rb +290 -0
  92. data/lib/prawn/measurement_extensions.rb +50 -0
  93. data/lib/prawn/measurements.rb +77 -0
  94. data/lib/prawn/outline.rb +289 -0
  95. data/lib/prawn/repeater.rb +124 -0
  96. data/lib/prawn/security.rb +288 -0
  97. data/lib/prawn/security/arcfour.rb +54 -0
  98. data/lib/prawn/soft_mask.rb +94 -0
  99. data/lib/prawn/stamp.rb +136 -0
  100. data/lib/prawn/text.rb +437 -0
  101. data/lib/prawn/text/box.rb +141 -0
  102. data/lib/prawn/text/formatted.rb +7 -0
  103. data/lib/prawn/text/formatted/arranger.rb +290 -0
  104. data/lib/prawn/text/formatted/box.rb +614 -0
  105. data/lib/prawn/text/formatted/fragment.rb +264 -0
  106. data/lib/prawn/text/formatted/line_wrap.rb +277 -0
  107. data/lib/prawn/text/formatted/parser.rb +224 -0
  108. data/lib/prawn/text/formatted/wrap.rb +160 -0
  109. data/lib/prawn/utilities.rb +46 -0
  110. data/lib/prawn/version.rb +5 -0
  111. data/lib/prawn/view.rb +91 -0
  112. data/manual/absolute_position.pdf +0 -0
  113. data/manual/basic_concepts/adding_pages.rb +27 -0
  114. data/manual/basic_concepts/basic_concepts.rb +36 -0
  115. data/manual/basic_concepts/creation.rb +39 -0
  116. data/manual/basic_concepts/cursor.rb +33 -0
  117. data/manual/basic_concepts/measurement.rb +25 -0
  118. data/manual/basic_concepts/origin.rb +38 -0
  119. data/manual/basic_concepts/other_cursor_helpers.rb +40 -0
  120. data/manual/basic_concepts/view.rb +42 -0
  121. data/manual/bounding_box/bounding_box.rb +39 -0
  122. data/manual/bounding_box/bounds.rb +49 -0
  123. data/manual/bounding_box/canvas.rb +24 -0
  124. data/manual/bounding_box/creation.rb +23 -0
  125. data/manual/bounding_box/indentation.rb +46 -0
  126. data/manual/bounding_box/nesting.rb +45 -0
  127. data/manual/bounding_box/russian_boxes.rb +40 -0
  128. data/manual/bounding_box/stretchy.rb +31 -0
  129. data/manual/contents.rb +29 -0
  130. data/manual/cover.rb +39 -0
  131. data/manual/document_and_page_options/background.rb +27 -0
  132. data/manual/document_and_page_options/document_and_page_options.rb +32 -0
  133. data/manual/document_and_page_options/metadata.rb +23 -0
  134. data/manual/document_and_page_options/page_margins.rb +38 -0
  135. data/manual/document_and_page_options/page_size.rb +34 -0
  136. data/manual/document_and_page_options/print_scaling.rb +20 -0
  137. data/manual/example_helper.rb +7 -0
  138. data/manual/graphics/circle_and_ellipse.rb +22 -0
  139. data/manual/graphics/color.rb +24 -0
  140. data/manual/graphics/common_lines.rb +30 -0
  141. data/manual/graphics/fill_and_stroke.rb +42 -0
  142. data/manual/graphics/fill_rules.rb +37 -0
  143. data/manual/graphics/gradients.rb +37 -0
  144. data/manual/graphics/graphics.rb +58 -0
  145. data/manual/graphics/helper.rb +24 -0
  146. data/manual/graphics/line_width.rb +35 -0
  147. data/manual/graphics/lines_and_curves.rb +41 -0
  148. data/manual/graphics/polygon.rb +29 -0
  149. data/manual/graphics/rectangle.rb +21 -0
  150. data/manual/graphics/rotate.rb +28 -0
  151. data/manual/graphics/scale.rb +41 -0
  152. data/manual/graphics/soft_masks.rb +46 -0
  153. data/manual/graphics/stroke_cap.rb +31 -0
  154. data/manual/graphics/stroke_dash.rb +48 -0
  155. data/manual/graphics/stroke_join.rb +30 -0
  156. data/manual/graphics/translate.rb +29 -0
  157. data/manual/graphics/transparency.rb +35 -0
  158. data/manual/how_to_read_this_manual.rb +40 -0
  159. data/manual/images/absolute_position.rb +23 -0
  160. data/manual/images/fit.rb +21 -0
  161. data/manual/images/horizontal.rb +25 -0
  162. data/manual/images/images.rb +40 -0
  163. data/manual/images/plain_image.rb +18 -0
  164. data/manual/images/scale.rb +22 -0
  165. data/manual/images/vertical.rb +28 -0
  166. data/manual/images/width_and_height.rb +25 -0
  167. data/manual/layout/boxes.rb +27 -0
  168. data/manual/layout/content.rb +25 -0
  169. data/manual/layout/layout.rb +28 -0
  170. data/manual/layout/simple_grid.rb +23 -0
  171. data/manual/outline/add_subsection_to.rb +61 -0
  172. data/manual/outline/insert_section_after.rb +47 -0
  173. data/manual/outline/outline.rb +32 -0
  174. data/manual/outline/sections_and_pages.rb +67 -0
  175. data/manual/repeatable_content/alternate_page_numbering.rb +32 -0
  176. data/manual/repeatable_content/page_numbering.rb +54 -0
  177. data/manual/repeatable_content/repeatable_content.rb +32 -0
  178. data/manual/repeatable_content/repeater.rb +55 -0
  179. data/manual/repeatable_content/stamp.rb +41 -0
  180. data/manual/security/encryption.rb +31 -0
  181. data/manual/security/permissions.rb +38 -0
  182. data/manual/security/security.rb +28 -0
  183. data/manual/table.rb +16 -0
  184. data/manual/text/alignment.rb +44 -0
  185. data/manual/text/color.rb +24 -0
  186. data/manual/text/column_box.rb +32 -0
  187. data/manual/text/fallback_fonts.rb +37 -0
  188. data/manual/text/font.rb +41 -0
  189. data/manual/text/font_size.rb +45 -0
  190. data/manual/text/font_style.rb +23 -0
  191. data/manual/text/formatted_callbacks.rb +60 -0
  192. data/manual/text/formatted_text.rb +50 -0
  193. data/manual/text/free_flowing_text.rb +51 -0
  194. data/manual/text/inline.rb +41 -0
  195. data/manual/text/kerning_and_character_spacing.rb +39 -0
  196. data/manual/text/leading.rb +25 -0
  197. data/manual/text/line_wrapping.rb +41 -0
  198. data/manual/text/paragraph_indentation.rb +34 -0
  199. data/manual/text/positioned_text.rb +38 -0
  200. data/manual/text/registering_families.rb +48 -0
  201. data/manual/text/rendering_and_color.rb +37 -0
  202. data/manual/text/right_to_left_text.rb +47 -0
  203. data/manual/text/rotation.rb +43 -0
  204. data/manual/text/single_usage.rb +37 -0
  205. data/manual/text/text.rb +73 -0
  206. data/manual/text/text_box_excess.rb +32 -0
  207. data/manual/text/text_box_extensions.rb +45 -0
  208. data/manual/text/text_box_overflow.rb +48 -0
  209. data/manual/text/utf8.rb +28 -0
  210. data/manual/text/win_ansi_charset.rb +60 -0
  211. data/prawn.gemspec +45 -0
  212. data/spec/acceptance/png.rb +25 -0
  213. data/spec/annotations_spec.rb +74 -0
  214. data/spec/bounding_box_spec.rb +510 -0
  215. data/spec/column_box_spec.rb +65 -0
  216. data/spec/data/curves.pdf +66 -0
  217. data/spec/destinations_spec.rb +15 -0
  218. data/spec/document_spec.rb +748 -0
  219. data/spec/extensions/encoding_helpers.rb +11 -0
  220. data/spec/extensions/mocha.rb +46 -0
  221. data/spec/font_metric_cache_spec.rb +52 -0
  222. data/spec/font_spec.rb +474 -0
  223. data/spec/formatted_text_arranger_spec.rb +421 -0
  224. data/spec/formatted_text_box_spec.rb +705 -0
  225. data/spec/formatted_text_fragment_spec.rb +298 -0
  226. data/spec/graphics_spec.rb +683 -0
  227. data/spec/grid_spec.rb +96 -0
  228. data/spec/image_handler_spec.rb +54 -0
  229. data/spec/images_spec.rb +153 -0
  230. data/spec/inline_formatted_text_parser_spec.rb +564 -0
  231. data/spec/jpg_spec.rb +25 -0
  232. data/spec/line_wrap_spec.rb +367 -0
  233. data/spec/measurement_units_spec.rb +25 -0
  234. data/spec/outline_spec.rb +430 -0
  235. data/spec/png_spec.rb +245 -0
  236. data/spec/reference_spec.rb +25 -0
  237. data/spec/repeater_spec.rb +160 -0
  238. data/spec/security_spec.rb +158 -0
  239. data/spec/soft_mask_spec.rb +79 -0
  240. data/spec/span_spec.rb +44 -0
  241. data/spec/spec_helper.rb +54 -0
  242. data/spec/stamp_spec.rb +160 -0
  243. data/spec/stroke_styles_spec.rb +211 -0
  244. data/spec/text_at_spec.rb +143 -0
  245. data/spec/text_box_spec.rb +1043 -0
  246. data/spec/text_rendering_mode_spec.rb +45 -0
  247. data/spec/text_spacing_spec.rb +93 -0
  248. data/spec/text_spec.rb +557 -0
  249. data/spec/text_with_inline_formatting_spec.rb +35 -0
  250. data/spec/transparency_spec.rb +91 -0
  251. data/spec/view_spec.rb +43 -0
  252. metadata +509 -0
@@ -0,0 +1,224 @@
1
+ # encoding: utf-8
2
+
3
+ # text/formatted/parser.rb : Implements a bi-directional parser between a subset
4
+ # of html and formatted text arrays
5
+ #
6
+ # Copyright February 2010, Daniel Nelson. All Rights Reserved.
7
+ #
8
+ # This is free software. Please see the LICENSE and COPYING files for details.
9
+ #
10
+
11
+ module Prawn
12
+ module Text
13
+ module Formatted
14
+
15
+ class Parser
16
+ # @group Extension API
17
+
18
+ PARSER_REGEX = begin
19
+ regex_string = "\n|" +
20
+ "<b>|</b>|" +
21
+ "<i>|</i>|" +
22
+ "<u>|</u>|" +
23
+ "<strikethrough>|</strikethrough>|" +
24
+ "<sub>|</sub>|" +
25
+ "<sup>|</sup>|" +
26
+ "<link[^>]*>|</link>|" +
27
+ "<color[^>]*>|</color>|" +
28
+ "<font[^>]*>|</font>|" +
29
+ "<strong>|</strong>|" +
30
+ "<em>|</em>|" +
31
+ "<a[^>]*>|</a>|" +
32
+ "[^<\n]+"
33
+ Regexp.new(regex_string, Regexp::MULTILINE)
34
+ end
35
+
36
+ def self.format(string, *args)
37
+ tokens = string.gsub(/<br\s*\/?>/, "\n").scan(PARSER_REGEX)
38
+ self.array_from_tokens(tokens)
39
+ end
40
+
41
+ def self.to_string(array)
42
+ prefixes = { :bold => "<b>",
43
+ :italic => "<i>",
44
+ :underline => "<u>",
45
+ :strikethrough => "<strikethrough>",
46
+ :subscript => "<sub>",
47
+ :superscript => "<sup>" }
48
+ suffixes = { :bold => "</b>",
49
+ :italic => "</i>",
50
+ :underline => "</u>",
51
+ :strikethrough => "</strikethrough>",
52
+ :subscript => "</sub>",
53
+ :superscript => "</sup>" }
54
+ array.collect do |hash|
55
+ prefix = ""
56
+ suffix = ""
57
+ if hash[:styles]
58
+ hash[:styles].each do |style|
59
+ prefix = prefix + prefixes[style]
60
+ suffix = suffixes[style] + suffix
61
+ end
62
+ end
63
+
64
+ font = hash[:font] ? " name='#{hash[:font]}'" : nil
65
+ size = hash[:size] ? " size='#{hash[:size]}'" : nil
66
+ if hash[:character_spacing]
67
+ character_spacing = " character_spacing='#{hash[:character_spacing]}'"
68
+ else
69
+ character_spacing = nil
70
+ end
71
+ if font || size || character_spacing
72
+ prefix = prefix + "<font#{font}#{size}#{character_spacing}>"
73
+ suffix = "</font>"
74
+ end
75
+
76
+ link = hash[:link] ? " href='#{hash[:link]}'" : nil
77
+ anchor = hash[:anchor] ? " anchor='#{hash[:anchor]}'" : nil
78
+ if link || anchor
79
+ prefix = prefix + "<link#{link}#{anchor}>"
80
+ suffix = "</link>"
81
+ end
82
+
83
+ if hash[:color]
84
+ if hash[:color].kind_of?(Array)
85
+ prefix = prefix + "<color c='#{hash[:color][0]}'" +
86
+ " m='#{hash[:color][1]}'" +
87
+ " y='#{hash[:color][2]}'" +
88
+ " k='#{hash[:color][3]}'>"
89
+ else
90
+ prefix = prefix + "<color rgb='#{hash[:color]}'>"
91
+ end
92
+ suffix = "</color>"
93
+ end
94
+
95
+ string = hash[:text].gsub("&", "&amp;").gsub(">", "&gt;").gsub("<", "&lt;")
96
+ prefix + string + suffix
97
+ end.join
98
+ end
99
+
100
+ def self.array_paragraphs(array) #:nodoc:
101
+ paragraphs = []
102
+ paragraph = []
103
+ previous_string = "\n"
104
+ scan_pattern = /[^\n]+|\n/
105
+ array.each do |hash|
106
+ hash[:text].scan(scan_pattern).each do |string|
107
+ if string == "\n"
108
+ paragraph << hash.dup.merge(:text => "\n") if previous_string == "\n"
109
+ paragraphs << paragraph unless paragraph.empty?
110
+ paragraph = []
111
+ else
112
+ paragraph << hash.dup.merge(:text => string)
113
+ end
114
+ previous_string = string
115
+ end
116
+ end
117
+ paragraphs << paragraph unless paragraph.empty?
118
+ paragraphs
119
+ end
120
+
121
+ private
122
+
123
+ def self.array_from_tokens(tokens)
124
+ array = []
125
+ styles = []
126
+ colors = []
127
+ link = nil
128
+ anchor = nil
129
+ local = nil
130
+ fonts = []
131
+ sizes = []
132
+ character_spacings = []
133
+
134
+ while token = tokens.shift
135
+ case token
136
+ when "<b>", "<strong>"
137
+ styles << :bold
138
+ when "<i>", "<em>"
139
+ styles << :italic
140
+ when "<u>"
141
+ styles << :underline
142
+ when "<strikethrough>"
143
+ styles << :strikethrough
144
+ when "<sub>"
145
+ styles << :subscript
146
+ when "<sup>"
147
+ styles << :superscript
148
+ when "</b>", "</strong>"
149
+ styles.delete(:bold)
150
+ when "</i>", "</em>"
151
+ styles.delete(:italic)
152
+ when "</u>"
153
+ styles.delete(:underline)
154
+ when "</strikethrough>"
155
+ styles.delete(:strikethrough)
156
+ when "</sub>"
157
+ styles.delete(:subscript)
158
+ when "</sup>"
159
+ styles.delete(:superscript)
160
+ when "</link>", "</a>"
161
+ link = nil
162
+ anchor = nil
163
+ local = nil
164
+ when "</color>"
165
+ colors.pop
166
+ when "</font>"
167
+ fonts.pop
168
+ sizes.pop
169
+ character_spacings.pop
170
+ else
171
+ if token =~ /^<link[^>]*>$/ or token =~ /^<a[^>]*>$/
172
+ matches = /href="([^"]*)"/.match(token) || /href='([^']*)'/.match(token)
173
+ link = matches[1] unless matches.nil?
174
+
175
+ matches = /anchor="([^"]*)"/.match(token) || /anchor='([^']*)'/.match(token)
176
+ anchor = matches[1] unless matches.nil?
177
+
178
+ matches = /local="([^"]*)"/.match(token) || /local='([^']*)'/.match(token)
179
+ local = matches[1] unless matches.nil?
180
+ elsif token =~ /^<color[^>]*>$/
181
+ matches = /rgb="#?([^"]*)"/.match(token) || /rgb='#?([^']*)'/.match(token)
182
+ colors << matches[1] if matches
183
+
184
+ matches = /c="#?([^"]*)" +m="#?([^"]*)" +y="#?([^"]*)" +k="#?([^"]*)"/.match(token) ||
185
+ /c='#?([^']*)' +m='#?([^']*)' +y='#?([^']*)' +k='#?([^']*)'/.match(token)
186
+ colors << [matches[1].to_i, matches[2].to_i, matches[3].to_i, matches[4].to_i] if matches
187
+
188
+ # intend to support rgb="#ffffff" or rgb='#ffffff',
189
+ # r="255" g="255" b="255" or r='255' g='255' b='255',
190
+ # and c="100" m="100" y="100" k="100" or
191
+ # c='100' m='100' y='100' k='100'
192
+ # color = { :rgb => "#ffffff" }
193
+ # color = { :r => 255, :g => 255, :b => 255 }
194
+ # color = { :c => 100, :m => 100, :y => 100, :k => 100 }
195
+ elsif token =~ /^<font[^>]*>$/
196
+ matches = /name="([^"]*)"/.match(token) || /name='([^']*)'/.match(token)
197
+ fonts << matches[1] unless matches.nil?
198
+
199
+ matches = /size="([^"]*)"/.match(token) || /size='([^']*)'/.match(token)
200
+ sizes << matches[1].to_f unless matches.nil?
201
+
202
+ matches = /character_spacing="([^"]*)"/.match(token) || /character_spacing='([^']*)'/.match(token)
203
+ character_spacings << matches[1].to_f unless matches.nil?
204
+ else
205
+ string = token.gsub("&lt;", "<").gsub("&gt;", ">").gsub("&amp;", "&")
206
+ array << { :text => string,
207
+ :styles => styles.dup,
208
+ :color => colors.last,
209
+ :local => local,
210
+ :link => link,
211
+ :anchor => anchor,
212
+ :font => fonts.last,
213
+ :size => sizes.last,
214
+ :character_spacing => character_spacings.last }
215
+ end
216
+ end
217
+ end
218
+ array
219
+ end
220
+
221
+ end
222
+ end
223
+ end
224
+ end
@@ -0,0 +1,160 @@
1
+ # encoding: utf-8
2
+
3
+ # wrap.rb: Handles text wrapping for for formatted text
4
+ #
5
+ # Contributed by Daniel Nelson
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+
9
+ require_relative "line_wrap"
10
+ require_relative "arranger"
11
+
12
+ module Prawn
13
+ module Text
14
+ module Formatted #:nodoc:
15
+ # @private
16
+
17
+ module Wrap #:nodoc:
18
+
19
+ def initialize(array, options)
20
+ @line_wrap = Prawn::Text::Formatted::LineWrap.new
21
+ @arranger = Prawn::Text::Formatted::Arranger.new(@document,
22
+ :kerning => options[:kerning])
23
+ @disable_wrap_by_char = options[:disable_wrap_by_char]
24
+ end
25
+
26
+
27
+ # See the developer documentation for PDF::Core::Text#wrap
28
+ #
29
+ # Formatted#wrap should set the following variables:
30
+ # <tt>@line_height</tt>::
31
+ # the height of the tallest fragment in the last printed line
32
+ # <tt>@descender</tt>::
33
+ # the descender height of the tallest fragment in the last
34
+ # printed line
35
+ # <tt>@ascender</tt>::
36
+ # the ascender heigth of the tallest fragment in the last
37
+ # printed line
38
+ # <tt>@baseline_y</tt>::
39
+ # the baseline of the current line
40
+ # <tt>@nothing_printed</tt>::
41
+ # set to true until something is printed, then false
42
+ # <tt>@everything_printed</tt>::
43
+ # set to false until everything printed, then true
44
+ #
45
+ # Returns any formatted text that was not printed
46
+ #
47
+ def wrap(array) #:nodoc:
48
+ initialize_wrap(array)
49
+
50
+ stop = false
51
+ while !stop
52
+ # wrap before testing if enough height for this line because the
53
+ # height of the highest fragment on this line will be used to
54
+ # determine the line height
55
+ @line_wrap.wrap_line(:document => @document,
56
+ :kerning => @kerning,
57
+ :width => available_width,
58
+ :arranger => @arranger,
59
+ :disable_wrap_by_char => @disable_wrap_by_char)
60
+
61
+ if enough_height_for_this_line?
62
+ move_baseline_down
63
+ print_line
64
+ else
65
+ stop = true
66
+ end
67
+
68
+ stop ||= @single_line || @arranger.finished?
69
+ end
70
+ @text = @printed_lines.join("\n")
71
+ @everything_printed = @arranger.finished?
72
+ @arranger.unconsumed
73
+ end
74
+
75
+ private
76
+
77
+ def print_line
78
+ @nothing_printed = false
79
+ printed_fragments = []
80
+ fragments_this_line = []
81
+
82
+ word_spacing = word_spacing_for_this_line
83
+ while fragment = @arranger.retrieve_fragment
84
+ fragment.word_spacing = word_spacing
85
+ if fragment.text == "\n"
86
+ printed_fragments << "\n" if @printed_lines.last == ""
87
+ break
88
+ end
89
+ printed_fragments << fragment.text
90
+ fragments_this_line << fragment
91
+ end
92
+
93
+ accumulated_width = 0
94
+ fragments_this_line.reverse! if @direction == :rtl
95
+ fragments_this_line.each do |fragment_this_line|
96
+ fragment_this_line.default_direction = @direction
97
+ format_and_draw_fragment(fragment_this_line, accumulated_width,
98
+ @line_wrap.width, word_spacing)
99
+ accumulated_width += fragment_this_line.width
100
+ end
101
+
102
+ @printed_lines << printed_fragments.map { |s| s.force_encoding(::Encoding::UTF_8) }.join
103
+ end
104
+
105
+ def word_spacing_for_this_line
106
+ if @align == :justify &&
107
+ @line_wrap.space_count > 0 &&
108
+ !@line_wrap.paragraph_finished?
109
+ (available_width - @line_wrap.width) / @line_wrap.space_count
110
+ else
111
+ 0
112
+ end
113
+ end
114
+
115
+ def enough_height_for_this_line?
116
+ @line_height = @arranger.max_line_height
117
+ @descender = @arranger.max_descender
118
+ @ascender = @arranger.max_ascender
119
+ if @baseline_y == 0
120
+ diff = @ascender + @descender
121
+ else
122
+ diff = @descender + @line_height + @leading
123
+ end
124
+ require_relatived_total_height = @baseline_y.abs + diff
125
+ if require_relatived_total_height > @height + 0.0001
126
+ # no room for the full height of this line
127
+ @arranger.repack_unretrieved
128
+ false
129
+ else
130
+ true
131
+ end
132
+ end
133
+
134
+ def initialize_wrap(array)
135
+ @text = nil
136
+ @arranger.format_array = array
137
+
138
+ # these values will depend on the maximum value within a given line
139
+ @line_height = 0
140
+ @descender = 0
141
+ @ascender = 0
142
+ @baseline_y = 0
143
+
144
+ @printed_lines = []
145
+ @nothing_printed = true
146
+ @everything_printed = false
147
+ end
148
+
149
+ def format_and_draw_fragment(fragment, accumulated_width,
150
+ line_width, word_spacing)
151
+ @arranger.apply_color_and_font_settings(fragment) do
152
+ draw_fragment(fragment, accumulated_width,
153
+ line_width, word_spacing)
154
+ end
155
+ end
156
+
157
+ end
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,46 @@
1
+ # encoding: utf-8
2
+
3
+ # utilities.rb : General-purpose utility classes which don't fit anywhere else
4
+ #
5
+ # Copyright August 2012, Alex Dowad. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+
9
+ require 'thread'
10
+
11
+ module Prawn
12
+
13
+ # Throughout the Prawn codebase, repeated calculations which can benefit from caching are made
14
+ # In some cases, caching and reusing results can not only save CPU cycles but also greatly
15
+ # reduce memory requirements
16
+ # But at the same time, we don't want to throw away thread safety
17
+ # We have two interchangeable thread-safe cache implementations:
18
+
19
+ # @private
20
+ class SynchronizedCache
21
+ # As an optimization, this could access the hash directly on VMs with a global interpreter lock (like MRI)
22
+ def initialize
23
+ @cache = {}
24
+ @mutex = Mutex.new
25
+ end
26
+ def [](key)
27
+ @mutex.synchronize { @cache[key] }
28
+ end
29
+ def []=(key,value)
30
+ @mutex.synchronize { @cache[key] = value }
31
+ end
32
+ end
33
+
34
+ # @private
35
+ class ThreadLocalCache
36
+ def initialize
37
+ @cache_id = "cache_#{self.object_id}".to_sym
38
+ end
39
+ def [](key)
40
+ (Thread.current[@cache_id] ||= {})[key]
41
+ end
42
+ def []=(key,value)
43
+ (Thread.current[@cache_id] ||= {})[key] = value
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,5 @@
1
+ # encoding: utf-8
2
+
3
+ module Prawn
4
+ VERSION = "2.0.1"
5
+ end
@@ -0,0 +1,91 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # prawn/view.rb : Implements a mixin for Prawn's DSL
4
+ #
5
+ # This is free software. Please see the LICENSE and COPYING files for details.
6
+
7
+ module Prawn
8
+ # This mixin allows you to create modular Prawn code without the
9
+ # need to create subclasses of Prawn::Document.
10
+ #
11
+ # class Greeter
12
+ # include Prawn::View
13
+ #
14
+ # def initialize(name)
15
+ # @name = name
16
+ # end
17
+ #
18
+ # def say_hello
19
+ # text "Hello, #{@name}!"
20
+ # end
21
+ #
22
+ # def say_goodbye
23
+ # font("Courier") do
24
+ # text "Goodbye, #{@name}!"
25
+ # end
26
+ # end
27
+ # end
28
+ #
29
+ # greeter = Greeter.new("Gregory")
30
+ #
31
+ # greeter.say_hello
32
+ # greeter.say_goodbye
33
+ #
34
+ # greeter.save_as("greetings.pdf")
35
+ #
36
+ # The short story about why you should use this mixin rather than
37
+ # creating subclasses of +Prawn::Document+ is that it helps
38
+ # prevent accidental conflicts between your code and Prawn's
39
+ # code.
40
+ #
41
+ # Here's the slightly longer story...
42
+ #
43
+ # By using composition rather than inheritance under the hood, this
44
+ # mixin allows you to keep your state separate from +Prawn::Document+'s
45
+ # state, and also will prevent unexpected method name collisions due
46
+ # to late binding effects.
47
+ #
48
+ # This mixin is mostly meant for extending Prawn's functionality
49
+ # with your own additions, but you can also use it to replace or
50
+ # wrap existing Prawn methods. Calling +super+ will still work
51
+ # as expected, and alternatively you can explictly call
52
+ # +document.some_method+ to delegate to Prawn where needed.
53
+ module View
54
+ # @group Experimental API
55
+
56
+ # Lazily instantiates a +Prawn::Document+ object.
57
+ #
58
+ # You can also redefine this method in your own classes to use
59
+ # a custom document class.
60
+ def document
61
+ @document ||= Prawn::Document.new
62
+ end
63
+
64
+ # Delegates all unhandled calls to object returned by +document+ method.
65
+ # (which is an instance of Prawn::Document by default)
66
+ def method_missing(m, *a, &b)
67
+ return super unless document.respond_to?(m)
68
+
69
+ document.send(m, *a, &b)
70
+ end
71
+
72
+ # Syntactic sugar that uses +instance_eval+ under the hood to provide
73
+ # a block-based DSL.
74
+ #
75
+ # greeter.update do
76
+ # say_hello
77
+ # say_goodbye
78
+ # end
79
+ #
80
+ def update(&b)
81
+ instance_eval(&b)
82
+ end
83
+
84
+ # Syntatic sugar that calls +document.render_file+ under the hood.
85
+ #
86
+ # greeter.save_as("greetings.pdf")
87
+ def save_as(filename)
88
+ document.render_file(filename)
89
+ end
90
+ end
91
+ end