prawn 0.12.0 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (282) hide show
  1. checksums.yaml +7 -0
  2. data/COPYING +2 -2
  3. data/Gemfile +18 -0
  4. data/LICENSE +1 -1
  5. data/README.md +17 -4
  6. data/Rakefile +18 -22
  7. data/data/images/indexed_color.dat +0 -0
  8. data/data/images/indexed_color.png +0 -0
  9. data/data/pdfs/nested_pages.pdf +13 -13
  10. data/lib/pdf/core.rb +35 -0
  11. data/lib/{prawn → pdf}/core/annotations.rb +6 -7
  12. data/lib/{prawn → pdf}/core/byte_string.rb +1 -1
  13. data/lib/{prawn → pdf}/core/destinations.rb +23 -23
  14. data/lib/{prawn → pdf}/core/document_state.rb +8 -8
  15. data/lib/pdf/core/filter_list.rb +51 -0
  16. data/lib/pdf/core/filters.rb +36 -0
  17. data/lib/pdf/core/graphics_state.rb +68 -0
  18. data/lib/{prawn → pdf}/core/literal_string.rb +1 -1
  19. data/lib/{prawn → pdf}/core/name_tree.rb +14 -2
  20. data/lib/{prawn → pdf}/core/object_store.rb +80 -24
  21. data/lib/pdf/core/outline.rb +315 -0
  22. data/lib/{prawn → pdf}/core/page.rb +23 -26
  23. data/lib/{prawn/document → pdf/core}/page_geometry.rb +11 -21
  24. data/lib/{prawn → pdf}/core/pdf_object.rb +48 -32
  25. data/lib/{prawn → pdf}/core/reference.rb +35 -44
  26. data/lib/pdf/core/stream.rb +98 -0
  27. data/lib/{prawn → pdf}/core/text.rb +24 -17
  28. data/lib/prawn.rb +95 -17
  29. data/lib/prawn/compatibility.rb +66 -26
  30. data/lib/prawn/document.rb +48 -30
  31. data/lib/prawn/document/bounding_box.rb +3 -3
  32. data/lib/prawn/document/column_box.rb +46 -8
  33. data/lib/prawn/document/graphics_state.rb +10 -73
  34. data/lib/prawn/document/internals.rb +24 -23
  35. data/lib/prawn/document/snapshot.rb +6 -7
  36. data/lib/prawn/document/span.rb +10 -10
  37. data/lib/prawn/encoding.rb +7 -7
  38. data/lib/prawn/errors.rb +18 -29
  39. data/lib/prawn/font.rb +64 -28
  40. data/lib/prawn/font/afm.rb +32 -74
  41. data/lib/prawn/font/dfont.rb +2 -2
  42. data/lib/prawn/font/ttf.rb +28 -57
  43. data/lib/prawn/font_metric_cache.rb +45 -0
  44. data/lib/prawn/graphics.rb +307 -41
  45. data/lib/prawn/graphics/cap_style.rb +3 -3
  46. data/lib/prawn/graphics/color.rb +12 -5
  47. data/lib/prawn/graphics/dash.rb +52 -31
  48. data/lib/prawn/graphics/join_style.rb +7 -7
  49. data/lib/prawn/graphics/patterns.rb +137 -0
  50. data/lib/prawn/graphics/transformation.rb +9 -9
  51. data/lib/prawn/graphics/transparency.rb +1 -1
  52. data/lib/prawn/image_handler.rb +30 -0
  53. data/lib/prawn/images.rb +86 -105
  54. data/lib/prawn/images/image.rb +48 -0
  55. data/lib/prawn/images/jpg.rb +14 -10
  56. data/lib/prawn/images/png.rb +50 -37
  57. data/lib/prawn/layout.rb +2 -2
  58. data/lib/prawn/layout/grid.rb +51 -51
  59. data/lib/prawn/measurement_extensions.rb +5 -5
  60. data/lib/prawn/measurements.rb +25 -21
  61. data/lib/prawn/outline.rb +4 -308
  62. data/lib/prawn/repeater.rb +8 -8
  63. data/lib/prawn/security.rb +50 -36
  64. data/lib/prawn/soft_mask.rb +94 -0
  65. data/lib/prawn/stamp.rb +3 -3
  66. data/lib/prawn/table.rb +292 -118
  67. data/lib/prawn/table/cell.rb +272 -45
  68. data/lib/prawn/table/cell/image.rb +70 -0
  69. data/lib/prawn/table/cell/in_table.rb +2 -2
  70. data/lib/prawn/table/cell/span_dummy.rb +92 -0
  71. data/lib/prawn/table/cell/subtable.rb +2 -2
  72. data/lib/prawn/table/cell/text.rb +42 -24
  73. data/lib/prawn/table/cells.rb +137 -48
  74. data/lib/prawn/text.rb +35 -23
  75. data/lib/prawn/text/box.rb +18 -5
  76. data/lib/prawn/text/formatted.rb +5 -4
  77. data/lib/prawn/text/formatted/arranger.rb +292 -0
  78. data/lib/prawn/text/formatted/box.rb +52 -13
  79. data/lib/prawn/text/formatted/fragment.rb +37 -22
  80. data/lib/prawn/text/formatted/line_wrap.rb +286 -0
  81. data/lib/prawn/text/formatted/parser.rb +14 -6
  82. data/lib/prawn/text/formatted/wrap.rb +151 -0
  83. data/lib/prawn/utilities.rb +44 -0
  84. data/manual/basic_concepts/adding_pages.rb +27 -0
  85. data/manual/basic_concepts/basic_concepts.rb +34 -0
  86. data/manual/basic_concepts/creation.rb +39 -0
  87. data/manual/basic_concepts/cursor.rb +33 -0
  88. data/manual/basic_concepts/measurement.rb +25 -0
  89. data/manual/basic_concepts/origin.rb +38 -0
  90. data/manual/basic_concepts/other_cursor_helpers.rb +40 -0
  91. data/manual/bounding_box/bounding_box.rb +39 -0
  92. data/manual/bounding_box/bounds.rb +49 -0
  93. data/manual/bounding_box/canvas.rb +24 -0
  94. data/manual/bounding_box/creation.rb +23 -0
  95. data/manual/bounding_box/indentation.rb +46 -0
  96. data/manual/bounding_box/nesting.rb +45 -0
  97. data/manual/bounding_box/russian_boxes.rb +40 -0
  98. data/manual/bounding_box/stretchy.rb +31 -0
  99. data/manual/document_and_page_options/background.rb +27 -0
  100. data/manual/document_and_page_options/document_and_page_options.rb +31 -0
  101. data/manual/document_and_page_options/metadata.rb +23 -0
  102. data/manual/document_and_page_options/page_margins.rb +38 -0
  103. data/manual/document_and_page_options/page_size.rb +34 -0
  104. data/manual/example_file.rb +116 -0
  105. data/manual/example_helper.rb +411 -0
  106. data/manual/example_package.rb +53 -0
  107. data/manual/example_section.rb +46 -0
  108. data/manual/graphics/circle_and_ellipse.rb +22 -0
  109. data/manual/graphics/color.rb +24 -0
  110. data/manual/graphics/common_lines.rb +28 -0
  111. data/manual/graphics/fill_and_stroke.rb +42 -0
  112. data/manual/graphics/fill_rules.rb +37 -0
  113. data/manual/graphics/gradients.rb +37 -0
  114. data/manual/graphics/graphics.rb +58 -0
  115. data/manual/graphics/helper.rb +24 -0
  116. data/manual/graphics/line_width.rb +35 -0
  117. data/manual/graphics/lines_and_curves.rb +41 -0
  118. data/manual/graphics/polygon.rb +29 -0
  119. data/manual/graphics/rectangle.rb +21 -0
  120. data/manual/graphics/rotate.rb +28 -0
  121. data/manual/graphics/scale.rb +41 -0
  122. data/manual/graphics/soft_masks.rb +46 -0
  123. data/manual/graphics/stroke_cap.rb +31 -0
  124. data/manual/graphics/stroke_dash.rb +48 -0
  125. data/manual/graphics/stroke_join.rb +30 -0
  126. data/manual/graphics/translate.rb +29 -0
  127. data/manual/graphics/transparency.rb +35 -0
  128. data/manual/images/absolute_position.rb +23 -0
  129. data/manual/images/fit.rb +21 -0
  130. data/manual/images/horizontal.rb +25 -0
  131. data/manual/images/images.rb +40 -0
  132. data/manual/images/plain_image.rb +18 -0
  133. data/manual/images/scale.rb +22 -0
  134. data/manual/images/vertical.rb +28 -0
  135. data/manual/images/width_and_height.rb +25 -0
  136. data/manual/layout/boxes.rb +27 -0
  137. data/manual/layout/content.rb +25 -0
  138. data/manual/layout/layout.rb +28 -0
  139. data/manual/layout/simple_grid.rb +23 -0
  140. data/manual/manual/cover.rb +35 -0
  141. data/manual/manual/foreword.rb +85 -0
  142. data/manual/manual/how_to_read_this_manual.rb +41 -0
  143. data/manual/manual/manual.rb +35 -0
  144. data/manual/outline/add_subsection_to.rb +61 -0
  145. data/manual/outline/insert_section_after.rb +47 -0
  146. data/manual/outline/outline.rb +32 -0
  147. data/manual/outline/sections_and_pages.rb +67 -0
  148. data/manual/repeatable_content/page_numbering.rb +54 -0
  149. data/manual/repeatable_content/repeatable_content.rb +31 -0
  150. data/manual/repeatable_content/repeater.rb +55 -0
  151. data/manual/repeatable_content/stamp.rb +41 -0
  152. data/manual/security/encryption.rb +31 -0
  153. data/manual/security/permissions.rb +38 -0
  154. data/manual/security/security.rb +28 -0
  155. data/manual/syntax_highlight.rb +52 -0
  156. data/manual/table/basic_block.rb +53 -0
  157. data/manual/table/before_rendering_page.rb +26 -0
  158. data/manual/table/cell_border_lines.rb +24 -0
  159. data/manual/table/cell_borders_and_bg.rb +31 -0
  160. data/manual/table/cell_dimensions.rb +30 -0
  161. data/manual/table/cell_text.rb +38 -0
  162. data/manual/table/column_widths.rb +30 -0
  163. data/manual/table/content_and_subtables.rb +39 -0
  164. data/manual/table/creation.rb +27 -0
  165. data/manual/table/filtering.rb +36 -0
  166. data/manual/table/flow_and_header.rb +17 -0
  167. data/manual/table/image_cells.rb +33 -0
  168. data/manual/table/position.rb +29 -0
  169. data/manual/table/row_colors.rb +20 -0
  170. data/manual/table/span.rb +30 -0
  171. data/manual/table/style.rb +22 -0
  172. data/manual/table/table.rb +52 -0
  173. data/manual/table/width.rb +27 -0
  174. data/manual/templates/full_template.rb +25 -0
  175. data/manual/templates/page_template.rb +48 -0
  176. data/manual/templates/templates.rb +27 -0
  177. data/manual/text/alignment.rb +44 -0
  178. data/manual/text/color.rb +24 -0
  179. data/manual/text/column_box.rb +32 -0
  180. data/manual/text/fallback_fonts.rb +37 -0
  181. data/manual/text/font.rb +41 -0
  182. data/manual/text/font_size.rb +45 -0
  183. data/manual/text/font_style.rb +23 -0
  184. data/manual/text/formatted_callbacks.rb +60 -0
  185. data/manual/text/formatted_text.rb +54 -0
  186. data/manual/text/free_flowing_text.rb +51 -0
  187. data/manual/text/group.rb +29 -0
  188. data/manual/text/inline.rb +43 -0
  189. data/manual/text/kerning_and_character_spacing.rb +39 -0
  190. data/manual/text/leading.rb +25 -0
  191. data/manual/text/line_wrapping.rb +41 -0
  192. data/manual/text/paragraph_indentation.rb +26 -0
  193. data/manual/text/positioned_text.rb +38 -0
  194. data/manual/text/registering_families.rb +48 -0
  195. data/manual/text/rendering_and_color.rb +37 -0
  196. data/manual/text/right_to_left_text.rb +43 -0
  197. data/manual/text/rotation.rb +43 -0
  198. data/manual/text/single_usage.rb +37 -0
  199. data/manual/text/text.rb +75 -0
  200. data/manual/text/text_box_excess.rb +32 -0
  201. data/manual/text/text_box_extensions.rb +45 -0
  202. data/manual/text/text_box_overflow.rb +44 -0
  203. data/manual/text/utf8.rb +28 -0
  204. data/{examples/m17n → manual/text}/win_ansi_charset.rb +14 -10
  205. data/prawn.gemspec +18 -12
  206. data/spec/acceptance/png.rb +23 -0
  207. data/spec/annotations_spec.rb +16 -32
  208. data/spec/bounding_box_spec.rb +128 -15
  209. data/spec/cell_spec.rb +169 -38
  210. data/spec/column_box_spec.rb +33 -0
  211. data/spec/destinations_spec.rb +5 -5
  212. data/spec/document_spec.rb +150 -104
  213. data/spec/extensions/encoding_helpers.rb +10 -0
  214. data/spec/extensions/mocha.rb +1 -0
  215. data/spec/filters_spec.rb +34 -0
  216. data/spec/font_metric_cache_spec.rb +52 -0
  217. data/spec/font_spec.rb +183 -97
  218. data/spec/formatted_text_arranger_spec.rb +43 -43
  219. data/spec/formatted_text_box_spec.rb +30 -20
  220. data/spec/formatted_text_fragment_spec.rb +8 -8
  221. data/spec/graphics_spec.rb +158 -69
  222. data/spec/grid_spec.rb +15 -15
  223. data/spec/image_handler_spec.rb +42 -0
  224. data/spec/images_spec.rb +49 -24
  225. data/spec/inline_formatted_text_parser_spec.rb +73 -19
  226. data/spec/jpg_spec.rb +4 -4
  227. data/spec/line_wrap_spec.rb +26 -26
  228. data/spec/measurement_units_spec.rb +6 -6
  229. data/spec/name_tree_spec.rb +21 -21
  230. data/spec/object_store_spec.rb +39 -39
  231. data/spec/outline_spec.rb +93 -53
  232. data/spec/pdf_object_spec.rb +88 -86
  233. data/spec/png_spec.rb +31 -28
  234. data/spec/reference_spec.rb +32 -32
  235. data/spec/repeater_spec.rb +25 -11
  236. data/spec/security_spec.rb +44 -12
  237. data/spec/snapshot_spec.rb +8 -9
  238. data/spec/soft_mask_spec.rb +117 -0
  239. data/spec/span_spec.rb +10 -15
  240. data/spec/spec_helper.rb +25 -8
  241. data/spec/stamp_spec.rb +29 -30
  242. data/spec/stream_spec.rb +58 -0
  243. data/spec/stroke_styles_spec.rb +36 -18
  244. data/spec/table/span_dummy_spec.rb +17 -0
  245. data/spec/table_spec.rb +697 -105
  246. data/spec/template_spec.rb +108 -54
  247. data/spec/text_at_spec.rb +18 -17
  248. data/spec/text_box_spec.rb +111 -62
  249. data/spec/text_rendering_mode_spec.rb +5 -5
  250. data/spec/text_spacing_spec.rb +4 -4
  251. data/spec/text_spec.rb +57 -49
  252. data/spec/transparency_spec.rb +5 -5
  253. metadata +421 -213
  254. data/data/fonts/Action Man.dfont +0 -0
  255. data/data/fonts/Activa.ttf +0 -0
  256. data/data/fonts/Chalkboard.ttf +0 -0
  257. data/data/fonts/DejaVuSans.ttf +0 -0
  258. data/data/fonts/Dustismo_Roman.ttf +0 -0
  259. data/data/fonts/comicsans.ttf +0 -0
  260. data/data/fonts/gkai00mp.ttf +0 -0
  261. data/data/images/rails.dat +0 -0
  262. data/data/images/rails.png +0 -0
  263. data/examples/bounding_box/russian_boxes.rb +0 -37
  264. data/examples/example_helper.rb +0 -11
  265. data/examples/general/context_sensitive_headers.rb +0 -38
  266. data/examples/graphics/cmyk.rb +0 -13
  267. data/examples/graphics/gradient.rb +0 -23
  268. data/examples/graphics/png_types.rb +0 -23
  269. data/examples/graphics/remote_images.rb +0 -13
  270. data/examples/m17n/full_win_ansi_character_list.rb +0 -20
  271. data/examples/m17n/sjis.rb +0 -29
  272. data/examples/table/bill.rb +0 -54
  273. data/examples/table/header.rb +0 -15
  274. data/examples/text/font_calculations.rb +0 -92
  275. data/examples/text/hyphenation.rb +0 -45
  276. data/examples/text/indent_paragraphs.rb +0 -24
  277. data/lib/prawn/core.rb +0 -85
  278. data/lib/prawn/core/text/formatted/arranger.rb +0 -294
  279. data/lib/prawn/core/text/formatted/line_wrap.rb +0 -273
  280. data/lib/prawn/core/text/formatted/wrap.rb +0 -153
  281. data/lib/prawn/graphics/gradient.rb +0 -84
  282. data/lib/prawn/security/arcfour.rb +0 -51
@@ -7,6 +7,7 @@
7
7
  # This is free software. Please see the LICENSE and COPYING files for details.
8
8
 
9
9
  require 'prawn/encoding'
10
+ require 'afm'
10
11
 
11
12
  module Prawn
12
13
  class Font
@@ -27,8 +28,8 @@ module Prawn
27
28
  @metrics_path ||= [
28
29
  ".", "/usr/lib/afm",
29
30
  "/usr/local/lib/afm",
30
- "/usr/openwin/lib/fonts/afm/",
31
- Prawn::BASEDIR+'/data/fonts/']
31
+ "/usr/openwin/lib/fonts/afm",
32
+ Prawn::DATADIR+'/fonts']
32
33
  end
33
34
  end
34
35
 
@@ -41,26 +42,28 @@ module Prawn
41
42
 
42
43
  super
43
44
 
44
- @attributes = {}
45
- @glyph_widths = {}
46
- @bounding_boxes = {}
47
- @kern_pairs = {}
45
+ @@winansi ||= Prawn::Encoding::WinAnsi.new # parse data/encodings/win_ansi.txt once only
46
+ @@font_data ||= SynchronizedCache.new # parse each ATM font file once only
48
47
 
49
48
  file_name = @name.dup
50
49
  file_name << ".afm" unless file_name =~ /\.afm$/
51
50
  file_name = file_name[0] == ?/ ? file_name : find_font(file_name)
52
51
 
53
- parse_afm(file_name)
52
+ font_data = @@font_data[file_name] ||= ::AFM::Font.new(file_name)
53
+ @glyph_table = build_glyph_table(font_data)
54
+ @kern_pairs = font_data.kern_pairs
55
+ @kern_pair_table = build_kern_pair_table(@kern_pairs)
56
+ @attributes = font_data.metadata
54
57
 
55
- @ascender = @attributes["ascender"].to_i
56
- @descender = @attributes["descender"].to_i
58
+ @ascender = @attributes["Ascender"].to_i
59
+ @descender = @attributes["Descender"].to_i
57
60
  @line_gap = Float(bbox[3] - bbox[1]) - (@ascender - @descender)
58
61
  end
59
62
 
60
63
  # The font bbox, as an array of integers
61
64
  #
62
65
  def bbox
63
- @bbox ||= @attributes['fontbbox'].split(/\s+/).map { |e| Integer(e) }
66
+ @bbox ||= @attributes['FontBBox'].split(/\s+/).map { |e| Integer(e) }
64
67
  end
65
68
 
66
69
  # NOTE: String *must* be encoded as WinAnsi
@@ -87,7 +90,7 @@ module Prawn
87
90
  # is replaced with a string in WinAnsi encoding.
88
91
  #
89
92
  def normalize_encoding(text)
90
- enc = Prawn::Encoding::WinAnsi.new
93
+ enc = @@winansi
91
94
  text.unpack("U*").collect { |i| enc[i] }.pack("C*")
92
95
  rescue ArgumentError
93
96
  raise Prawn::Errors::IncompatibleStringEncoding,
@@ -138,7 +141,7 @@ module Prawn
138
141
  end
139
142
 
140
143
  def symbolic?
141
- attributes["characterset"] == "Special"
144
+ attributes["CharacterSet"] == "Special"
142
145
  end
143
146
 
144
147
  def find_font(file)
@@ -149,46 +152,6 @@ module Prawn
149
152
  self.class.metrics_path.join("\n")
150
153
  end
151
154
 
152
- def parse_afm(file_name)
153
- section = []
154
-
155
- File.foreach(file_name) do |line|
156
- case line
157
- when /^Start(\w+)/
158
- section.push $1
159
- next
160
- when /^End(\w+)/
161
- section.pop
162
- next
163
- end
164
-
165
- case section
166
- when ["FontMetrics", "CharMetrics"]
167
- next unless line =~ /^CH?\s/
168
-
169
- name = line[/\bN\s+(\.?\w+)\s*;/, 1]
170
- @glyph_widths[name] = line[/\bWX\s+(\d+)\s*;/, 1].to_i
171
- @bounding_boxes[name] = line[/\bB\s+([^;]+);/, 1].to_s.rstrip
172
- when ["FontMetrics", "KernData", "KernPairs"]
173
- next unless line =~ /^KPX\s+(\.?\w+)\s+(\.?\w+)\s+(-?\d+)/
174
- @kern_pairs[[$1, $2]] = $3.to_i
175
- when ["FontMetrics", "KernData", "TrackKern"],
176
- ["FontMetrics", "Composites"]
177
- next
178
- else
179
- parse_generic_afm_attribute(line)
180
- end
181
- end
182
- end
183
-
184
- def parse_generic_afm_attribute(line)
185
- line =~ /(^\w+)\s+(.*)/
186
- key, value = $1.to_s.downcase, $2
187
-
188
- @attributes[key] = @attributes[key] ?
189
- Array(@attributes[key]) << value : value
190
- end
191
-
192
155
  # converts a string into an array with spacing offsets
193
156
  # bewteen characters that need to be kerned
194
157
  #
@@ -198,46 +161,41 @@ module Prawn
198
161
  kerned = [[]]
199
162
  last_byte = nil
200
163
 
201
- kern_pairs = latin_kern_pairs_table
202
-
203
- string.unpack("C*").each do |byte|
204
- if k = last_byte && kern_pairs[[last_byte, byte]]
164
+ string.each_byte do |byte|
165
+ if k = last_byte && @kern_pair_table[[last_byte, byte]]
205
166
  kerned << -k << [byte]
206
167
  else
207
168
  kerned.last << byte
208
- end
169
+ end
209
170
  last_byte = byte
210
171
  end
211
172
 
212
- kerned.map { |e|
173
+ kerned.map { |e|
213
174
  e = (Array === e ? e.pack("C*") : e)
214
- e.respond_to?(:force_encoding) ? e.force_encoding("Windows-1252") : e
175
+ e.respond_to?(:force_encoding) ? e.force_encoding("Windows-1252") : e
215
176
  }
216
177
  end
217
178
 
218
- def latin_kern_pairs_table
219
- return @kern_pairs_table if defined?(@kern_pairs_table)
220
-
179
+ def build_kern_pair_table(kern_pairs)
221
180
  character_hash = Hash[Encoding::WinAnsi::CHARACTERS.zip((0..Encoding::WinAnsi::CHARACTERS.size).to_a)]
222
- @kern_pairs_table = @kern_pairs.inject({}) do |h,p|
223
- h[p[0].map { |n| character_hash[n] }] = p[1]
181
+ kern_pairs.inject({}) do |h,p|
182
+ h[
183
+ [character_hash[p[0]], character_hash[p[1]]]
184
+ ] = p[2]
224
185
  h
225
186
  end
226
187
  end
227
188
 
228
- def latin_glyphs_table
229
- @glyphs_table ||= (0..255).map do |i|
230
- @glyph_widths[Encoding::WinAnsi::CHARACTERS[i]].to_i
189
+ def build_glyph_table(font_data)
190
+ (0..255).map do |char|
191
+ metrics = font_data.metrics_for(char)
192
+ metrics ? metrics[:wx] : 0
231
193
  end
232
194
  end
233
-
234
- private
235
-
195
+
236
196
  def unscaled_width_of(string)
237
- glyph_table = latin_glyphs_table
238
-
239
- string.unpack("C*").inject(0) do |s,r|
240
- s + glyph_table[r]
197
+ string.bytes.inject(0) do |s,r|
198
+ s + @glyph_table[r]
241
199
  end
242
200
  end
243
201
  end
@@ -11,7 +11,7 @@ require 'prawn/font/ttf'
11
11
  module Prawn
12
12
  class Font
13
13
  class DFont < TTF
14
-
14
+
15
15
  # Returns a list of the names of all named fonts in the given dfont file.
16
16
  # Note that fonts are not required to be named in a dfont file, so the
17
17
  # list may be empty even if the file does contain fonts. Also, note that
@@ -32,7 +32,7 @@ module Prawn
32
32
  end
33
33
  end
34
34
 
35
- private
35
+ private
36
36
 
37
37
  def read_ttf_file
38
38
  TTFunk::File.from_dfont(@name, @options[:font] || 0)
@@ -2,7 +2,7 @@
2
2
 
3
3
  # prawn/font/ttf.rb : Implements AFM font support for Prawn
4
4
  #
5
- # Copyright May 2008, Gregory Brown / James Healy / Jamis Buck
5
+ # Copyright May 2008, Gregory Brown / James Healy / Jamis Buck
6
6
  # All Rights Reserved.
7
7
  #
8
8
  # This is free software. Please see the LICENSE and COPYING files for details.
@@ -18,7 +18,7 @@ module Prawn
18
18
  def unicode?
19
19
  true
20
20
  end
21
-
21
+
22
22
  def initialize(document, name, options={})
23
23
  super
24
24
 
@@ -26,8 +26,8 @@ module Prawn
26
26
  @subsets = TTFunk::SubsetCollection.new(@ttf)
27
27
 
28
28
  @attributes = {}
29
- @bounding_boxes = {}
30
- @char_widths = {}
29
+ @bounding_boxes = {}
30
+ @char_widths = {}
31
31
  @has_kerning_data = @ttf.kerning.exists? && @ttf.kerning.tables.any?
32
32
 
33
33
  @ascender = Integer(@ttf.ascent * scale_factor)
@@ -42,26 +42,26 @@ module Prawn
42
42
  kern(string).inject(0) do |s,r|
43
43
  if r.is_a?(Numeric)
44
44
  s - r
45
- else
45
+ else
46
46
  r.inject(s) { |s2, u| s2 + character_width_by_code(u) }
47
47
  end
48
48
  end * scale
49
49
  else
50
- string.unpack("U*").inject(0) do |s,r|
50
+ string.codepoints.inject(0) do |s,r|
51
51
  s + character_width_by_code(r)
52
52
  end * scale
53
53
  end
54
- end
55
-
54
+ end
55
+
56
56
  # The font bbox, as an array of integers
57
- #
57
+ #
58
58
  def bbox
59
59
  @bbox ||= @ttf.bbox.map { |i| Integer(i * scale_factor) }
60
60
  end
61
61
 
62
62
  # Returns true if the font has kerning data, false otherwise
63
63
  def has_kerning_data?
64
- @has_kerning_data
64
+ @has_kerning_data
65
65
  end
66
66
 
67
67
  # Perform any changes to the string that need to happen
@@ -77,7 +77,7 @@ module Prawn
77
77
 
78
78
  if options[:kerning]
79
79
  last_subset = nil
80
- kern(text).inject([]) do |result, element|
80
+ kern(text).inject([]) do |result, element|
81
81
  if element.is_a?(Numeric)
82
82
  result.last[1] = [result.last[1]] unless result.last[1].is_a?(Array)
83
83
  result.last[1] << element
@@ -102,7 +102,7 @@ module Prawn
102
102
  @subsets.encode(text.unpack("U*"))
103
103
  end
104
104
  end
105
-
105
+
106
106
  def basename
107
107
  @basename ||= @ttf.name.postscript_name
108
108
  end
@@ -126,7 +126,7 @@ module Prawn
126
126
  def cap_height
127
127
  @cap_height ||= begin
128
128
  height = @ttf.os2.exists? && @ttf.os2.cap_height || 0
129
- height == 0 ? ascender : height
129
+ height == 0 ? @ascender : height
130
130
  end
131
131
  end
132
132
 
@@ -160,44 +160,18 @@ module Prawn
160
160
  end
161
161
 
162
162
  def normalize_encoding(text)
163
- if text.respond_to?(:encode)
164
- # if we're running under a M17n aware VM, ensure the string provided is
165
- # UTF-8 (by converting it if necessary)
166
- begin
167
- text.encode("UTF-8")
168
- rescue
169
- raise Prawn::Errors::IncompatibleStringEncoding, "Encoding " +
170
- "#{text.encoding} can not be transparently converted to UTF-8. " +
171
- "Please ensure the encoding of the string you are attempting " +
172
- "to use is set correctly"
173
- end
174
- else
175
- # on a non M17N aware VM, use unpack as a hackish way to verify the
176
- # string is valid utf-8. I thought it was better than loading iconv
177
- # though.
178
- begin
179
- text.unpack("U*")
180
- return text.dup
181
- rescue
182
- raise Prawn::Errors::IncompatibleStringEncoding, "The string you " +
183
- "are attempting to render is not encoded in valid UTF-8."
184
- end
185
- end
163
+ text.normalize_to_utf8
186
164
  end
187
165
 
188
166
  def glyph_present?(char)
189
- code = char.unpack("U*").first
167
+ code = char.codepoints.first
190
168
  cmap[code] > 0
191
169
  end
192
170
 
193
171
  # Returns the number of characters in +str+ (a UTF-8-encoded string).
194
172
  #
195
173
  def character_count(str)
196
- if str.respond_to?(:encode)
197
- str.length
198
- else
199
- str.unpack("U*").length
200
- end
174
+ str.unicode_length
201
175
  end
202
176
 
203
177
  private
@@ -205,7 +179,7 @@ module Prawn
205
179
  def cmap
206
180
  @cmap ||= @ttf.cmap.unicode.first or raise("no unicode cmap for font")
207
181
  end
208
-
182
+
209
183
  # +string+ must be UTF8-encoded.
210
184
  #
211
185
  # Returns an array. If an element is a numeric, it represents the
@@ -214,7 +188,7 @@ module Prawn
214
188
  def kern(string)
215
189
  a = []
216
190
 
217
- string.unpack("U*").each do |r|
191
+ string.each_codepoint do |r|
218
192
  if a.empty?
219
193
  a << [r]
220
194
  elsif (kern = kern_pairs_table[[cmap[a.last.last], cmap[r]]])
@@ -241,7 +215,7 @@ module Prawn
241
215
  @hmtx ||= @ttf.horizontal_metrics
242
216
  end
243
217
 
244
- def character_width_by_code(code)
218
+ def character_width_by_code(code)
245
219
  return 0 unless cmap[code]
246
220
 
247
221
  # Some TTF fonts have nonzero widths for \n (UTF-8 / ASCII code: 10).
@@ -249,7 +223,7 @@ module Prawn
249
223
  return 0.0 if code == 10
250
224
 
251
225
  @char_widths[code] ||= Integer(hmtx.widths[cmap[code]] * scale_factor)
252
- end
226
+ end
253
227
 
254
228
  def scale_factor
255
229
  @scale ||= 1000.0 / @ttf.header.units_per_em
@@ -259,7 +233,7 @@ module Prawn
259
233
  temp_name = @ttf.name.postscript_name.gsub("\0","").to_sym
260
234
  ref = @document.ref!(:Type => :Font, :BaseFont => temp_name)
261
235
 
262
- # Embed the font metrics in the document after everything has been
236
+ # Embed the font metrics in the document after everything has been
263
237
  # drawn, just before the document is emitted.
264
238
  @document.before_render { |doc| embed(ref, subset) }
265
239
 
@@ -280,12 +254,9 @@ module Prawn
280
254
 
281
255
  raise "Can't detect a postscript name for #{file}" if basename.nil?
282
256
 
283
- compressed_font = Zlib::Deflate.deflate(font_content)
284
-
285
- fontfile = @document.ref!(:Length => compressed_font.size,
286
- :Length1 => font_content.size,
287
- :Filter => :FlateDecode )
288
- fontfile << compressed_font
257
+ fontfile = @document.ref!(:Length1 => font_content.size)
258
+ fontfile.stream << font_content
259
+ fontfile.stream.compress!
289
260
 
290
261
  descriptor = @document.ref!(:Type => :FontDescriptor,
291
262
  :FontName => basename.to_sym,
@@ -294,8 +265,8 @@ module Prawn
294
265
  :Flags => pdf_flags,
295
266
  :StemV => stemV,
296
267
  :ItalicAngle => italic_angle,
297
- :Ascent => ascender,
298
- :Descent => descender,
268
+ :Ascent => @ascender,
269
+ :Descent => @descender,
299
270
  :CapHeight => cap_height,
300
271
  :XHeight => x_height)
301
272
 
@@ -316,7 +287,7 @@ module Prawn
316
287
  map = @subsets[subset].to_unicode_map
317
288
 
318
289
  ranges = [[]]
319
- lines = map.keys.sort.inject("") do |s, code|
290
+ map.keys.sort.inject("") do |s, code|
320
291
  ranges << [] if ranges.last.length >= 100
321
292
  unicode = map[code]
322
293
  ranges.last << "<%02x><%04x>" % [code, unicode]
@@ -330,7 +301,7 @@ module Prawn
330
301
 
331
302
  cmap = @document.ref!({})
332
303
  cmap << to_unicode_cmap
333
- cmap.compress_stream
304
+ cmap.stream.compress!
334
305
 
335
306
  reference.data.update(:Subtype => :TrueType,
336
307
  :BaseFont => basename.to_sym,
@@ -0,0 +1,45 @@
1
+ # encoding: utf-8
2
+ #
3
+ # font_metric_cache.rb : The Prawn font class
4
+ #
5
+ # Copyright Dec 2012, Kenneth Kalmer. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+ #
9
+
10
+ module Prawn
11
+
12
+ # Cache used internally by Prawn::Document instances to calculate the width
13
+ # of various strings for layout purposes.
14
+ class FontMetricCache
15
+
16
+ CacheEntry = Struct.new( :font, :options, :string )
17
+
18
+ def initialize( document )
19
+ @document = document
20
+
21
+ @cache = {}
22
+ end
23
+
24
+ def width_of( string, options )
25
+ f = if options[:style]
26
+ # override style with :style => :bold
27
+ @document.find_font(@document.font ? @document.font.name : 'Helvetica',
28
+ :style => options[:style])
29
+ else
30
+ @document.font
31
+ end
32
+
33
+ key = CacheEntry.new( f, options, string )
34
+
35
+ unless length = @cache[ key ]
36
+ length = @cache[ key ] = f.compute_width_of(string, options)
37
+ end
38
+
39
+ length +
40
+ (@document.character_spacing * @document.font.character_count(string))
41
+ end
42
+
43
+ end
44
+
45
+ end