prawn 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +2 -0
- data.tar.gz.sig +0 -0
- data/Gemfile +1 -9
- data/Rakefile +12 -22
- data/lib/prawn.rb +29 -48
- data/lib/prawn/document.rb +148 -123
- data/lib/prawn/document/bounding_box.rb +33 -26
- data/lib/prawn/document/column_box.rb +5 -7
- data/lib/prawn/document/internals.rb +6 -6
- data/lib/prawn/document/span.rb +20 -17
- data/lib/prawn/encoding.rb +65 -67
- data/lib/prawn/errors.rb +10 -7
- data/lib/prawn/font.rb +78 -62
- data/lib/prawn/font/afm.rb +93 -66
- data/lib/prawn/font/dfont.rb +2 -10
- data/lib/prawn/font/ttc.rb +34 -0
- data/lib/prawn/font/ttf.rb +73 -65
- data/lib/prawn/font_metric_cache.rb +9 -8
- data/lib/prawn/graphics.rb +110 -70
- data/lib/prawn/graphics/blend_mode.rb +7 -8
- data/lib/prawn/graphics/cap_style.rb +2 -4
- data/lib/prawn/graphics/color.rb +23 -26
- data/lib/prawn/graphics/dash.rb +22 -12
- data/lib/prawn/graphics/join_style.rb +8 -4
- data/lib/prawn/graphics/patterns.rb +185 -96
- data/lib/prawn/graphics/transformation.rb +11 -9
- data/lib/prawn/graphics/transparency.rb +15 -13
- data/lib/prawn/grid.rb +20 -20
- data/lib/prawn/image_handler.rb +4 -6
- data/lib/prawn/images.rb +22 -15
- data/lib/prawn/images/image.rb +0 -1
- data/lib/prawn/images/jpg.rb +26 -22
- data/lib/prawn/images/png.rb +60 -57
- data/lib/prawn/measurement_extensions.rb +8 -9
- data/lib/prawn/measurements.rb +14 -15
- data/lib/prawn/outline.rb +96 -78
- data/lib/prawn/repeater.rb +12 -10
- data/lib/prawn/security.rb +66 -48
- data/lib/prawn/security/arcfour.rb +1 -3
- data/lib/prawn/soft_mask.rb +23 -25
- data/lib/prawn/stamp.rb +16 -12
- data/lib/prawn/text.rb +59 -45
- data/lib/prawn/text/box.rb +9 -8
- data/lib/prawn/text/formatted.rb +4 -6
- data/lib/prawn/text/formatted/arranger.rb +51 -30
- data/lib/prawn/text/formatted/box.rb +112 -88
- data/lib/prawn/text/formatted/fragment.rb +10 -15
- data/lib/prawn/text/formatted/line_wrap.rb +118 -61
- data/lib/prawn/text/formatted/parser.rb +134 -110
- data/lib/prawn/text/formatted/wrap.rb +42 -32
- data/lib/prawn/transformation_stack.rb +3 -4
- data/lib/prawn/utilities.rb +6 -21
- data/lib/prawn/version.rb +1 -3
- data/lib/prawn/view.rb +4 -2
- data/manual/basic_concepts/adding_pages.rb +4 -7
- data/manual/basic_concepts/basic_concepts.rb +29 -22
- data/manual/basic_concepts/creation.rb +8 -11
- data/manual/basic_concepts/cursor.rb +2 -5
- data/manual/basic_concepts/measurement.rb +3 -6
- data/manual/basic_concepts/origin.rb +3 -6
- data/manual/basic_concepts/other_cursor_helpers.rb +9 -12
- data/manual/basic_concepts/view.rb +20 -16
- data/manual/bounding_box/bounding_box.rb +27 -24
- data/manual/bounding_box/bounds.rb +9 -12
- data/manual/bounding_box/canvas.rb +2 -5
- data/manual/bounding_box/creation.rb +4 -7
- data/manual/bounding_box/indentation.rb +12 -15
- data/manual/bounding_box/nesting.rb +22 -17
- data/manual/bounding_box/russian_boxes.rb +8 -9
- data/manual/bounding_box/stretchy.rb +10 -13
- data/manual/contents.rb +26 -22
- data/manual/cover.rb +22 -20
- data/manual/document_and_page_options/background.rb +9 -13
- data/manual/document_and_page_options/document_and_page_options.rb +23 -20
- data/manual/document_and_page_options/metadata.rb +16 -16
- data/manual/document_and_page_options/page_margins.rb +16 -20
- data/manual/document_and_page_options/page_size.rb +11 -12
- data/manual/document_and_page_options/print_scaling.rb +15 -15
- data/manual/example_helper.rb +2 -4
- data/manual/graphics/blend_mode.rb +10 -9
- data/manual/graphics/circle_and_ellipse.rb +2 -5
- data/manual/graphics/color.rb +5 -9
- data/manual/graphics/common_lines.rb +5 -8
- data/manual/graphics/fill_and_stroke.rb +2 -5
- data/manual/graphics/fill_rules.rb +7 -10
- data/manual/graphics/gradients.rb +25 -21
- data/manual/graphics/graphics.rb +49 -43
- data/manual/graphics/helper.rb +10 -9
- data/manual/graphics/line_width.rb +5 -7
- data/manual/graphics/lines_and_curves.rb +5 -8
- data/manual/graphics/polygon.rb +4 -8
- data/manual/graphics/rectangle.rb +2 -5
- data/manual/graphics/rotate.rb +4 -7
- data/manual/graphics/scale.rb +12 -15
- data/manual/graphics/soft_masks.rb +1 -4
- data/manual/graphics/stroke_cap.rb +3 -6
- data/manual/graphics/stroke_dash.rb +9 -12
- data/manual/graphics/stroke_join.rb +2 -5
- data/manual/graphics/translate.rb +7 -10
- data/manual/graphics/transparency.rb +5 -8
- data/manual/how_to_read_this_manual.rb +4 -6
- data/manual/images/absolute_position.rb +4 -7
- data/manual/images/fit.rb +5 -8
- data/manual/images/horizontal.rb +6 -9
- data/manual/images/images.rb +25 -23
- data/manual/images/plain_image.rb +3 -6
- data/manual/images/scale.rb +7 -10
- data/manual/images/vertical.rb +10 -13
- data/manual/images/width_and_height.rb +8 -11
- data/manual/layout/boxes.rb +3 -6
- data/manual/layout/content.rb +5 -8
- data/manual/layout/layout.rb +16 -16
- data/manual/layout/simple_grid.rb +4 -7
- data/manual/outline/add_subsection_to.rb +18 -21
- data/manual/outline/insert_section_after.rb +13 -16
- data/manual/outline/outline.rb +19 -17
- data/manual/outline/sections_and_pages.rb +15 -18
- data/manual/repeatable_content/alternate_page_numbering.rb +19 -17
- data/manual/repeatable_content/page_numbering.rb +15 -16
- data/manual/repeatable_content/repeatable_content.rb +23 -19
- data/manual/repeatable_content/repeater.rb +12 -15
- data/manual/repeatable_content/stamp.rb +12 -15
- data/manual/security/encryption.rb +7 -10
- data/manual/security/permissions.rb +17 -14
- data/manual/security/security.rb +17 -16
- data/manual/table.rb +2 -4
- data/manual/text/alignment.rb +14 -17
- data/manual/text/color.rb +10 -11
- data/manual/text/column_box.rb +5 -8
- data/manual/text/fallback_fonts.rb +23 -21
- data/manual/text/font.rb +9 -12
- data/manual/text/font_size.rb +11 -14
- data/manual/text/font_style.rb +4 -7
- data/manual/text/formatted_callbacks.rb +23 -21
- data/manual/text/formatted_text.rb +31 -25
- data/manual/text/free_flowing_text.rb +18 -21
- data/manual/text/inline.rb +16 -19
- data/manual/text/kerning_and_character_spacing.rb +12 -15
- data/manual/text/leading.rb +5 -8
- data/manual/text/line_wrapping.rb +33 -17
- data/manual/text/paragraph_indentation.rb +11 -14
- data/manual/text/positioned_text.rb +13 -16
- data/manual/text/registering_families.rb +16 -19
- data/manual/text/rendering_and_color.rb +7 -10
- data/manual/text/right_to_left_text.rb +24 -19
- data/manual/text/rotation.rb +26 -23
- data/manual/text/single_usage.rb +6 -9
- data/manual/text/text.rb +56 -52
- data/manual/text/text_box_excess.rb +18 -17
- data/manual/text/text_box_extensions.rb +16 -15
- data/manual/text/text_box_overflow.rb +15 -18
- data/manual/text/utf8.rb +9 -12
- data/manual/text/win_ansi_charset.rb +18 -19
- data/prawn.gemspec +37 -27
- data/spec/extensions/encoding_helpers.rb +0 -2
- data/spec/manual_spec.rb +33 -0
- data/spec/prawn/document/bounding_box_spec.rb +546 -0
- data/spec/prawn/document/column_box_spec.rb +73 -0
- data/spec/prawn/document/security_spec.rb +173 -0
- data/spec/prawn/document_annotations_spec.rb +74 -0
- data/spec/prawn/document_destinations_spec.rb +13 -0
- data/spec/prawn/document_grid_spec.rb +96 -0
- data/spec/prawn/document_reference_spec.rb +25 -0
- data/spec/prawn/document_span_spec.rb +34 -0
- data/spec/prawn/document_spec.rb +751 -0
- data/spec/prawn/font_metric_cache_spec.rb +52 -0
- data/spec/prawn/font_spec.rb +513 -0
- data/spec/prawn/graphics/blend_mode_spec.rb +61 -0
- data/spec/prawn/graphics/transparency_spec.rb +79 -0
- data/spec/prawn/graphics_spec.rb +817 -0
- data/spec/prawn/graphics_stroke_styles_spec.rb +227 -0
- data/spec/{image_handler_spec.rb → prawn/image_handler_spec.rb} +13 -15
- data/spec/prawn/images/jpg_spec.rb +18 -0
- data/spec/prawn/images/png_spec.rb +281 -0
- data/spec/prawn/images_spec.rb +170 -0
- data/spec/prawn/measurements_extensions_spec.rb +22 -0
- data/spec/prawn/outline_spec.rb +408 -0
- data/spec/prawn/repeater_spec.rb +163 -0
- data/spec/prawn/soft_mask_spec.rb +72 -0
- data/spec/prawn/stamp_spec.rb +168 -0
- data/spec/prawn/text/box_spec.rb +1113 -0
- data/spec/prawn/text/formatted/arranger_spec.rb +464 -0
- data/spec/prawn/text/formatted/box_spec.rb +825 -0
- data/spec/prawn/text/formatted/fragment_spec.rb +341 -0
- data/spec/prawn/text/formatted/line_wrap_spec.rb +491 -0
- data/spec/prawn/text/formatted/parser_spec.rb +667 -0
- data/spec/prawn/text_draw_text_spec.rb +147 -0
- data/spec/prawn/text_rendering_mode_spec.rb +42 -0
- data/spec/prawn/text_spacing_spec.rb +93 -0
- data/spec/prawn/text_spec.rb +601 -0
- data/spec/prawn/text_with_inline_formatting_spec.rb +33 -0
- data/spec/{transformation_stack_spec.rb → prawn/transformation_stack_spec.rb} +21 -20
- data/spec/prawn/view_spec.rb +45 -0
- data/spec/spec_helper.rb +16 -16
- metadata +96 -151
- metadata.gz.sig +1 -0
- data/data/images/16bit.alpha +0 -0
- data/data/images/16bit.color +0 -0
- data/data/images/16bit.png +0 -0
- data/data/images/arrow.png +0 -0
- data/data/images/arrow2.png +0 -0
- data/data/images/blend_modes_bottom_layer.jpg +0 -0
- data/data/images/blend_modes_top_layer.jpg +0 -0
- data/data/images/dice.alpha +0 -0
- data/data/images/dice.color +0 -0
- data/data/images/dice.png +0 -0
- data/data/images/dice_interlaced.png +0 -0
- data/data/images/fractal.jpg +0 -0
- data/data/images/indexed_color.dat +0 -0
- data/data/images/indexed_color.png +0 -0
- data/data/images/indexed_transparency.png +0 -0
- data/data/images/indexed_transparency_alpha.dat +0 -0
- data/data/images/indexed_transparency_color.dat +0 -0
- data/data/images/letterhead.jpg +0 -0
- data/data/images/license.md +0 -8
- data/data/images/page_white_text.alpha +0 -0
- data/data/images/page_white_text.color +0 -0
- data/data/images/page_white_text.png +0 -0
- data/data/images/pigs.jpg +0 -0
- data/data/images/prawn.png +0 -0
- data/data/images/ruport.png +0 -0
- data/data/images/ruport_data.dat +0 -0
- data/data/images/ruport_transparent.png +0 -0
- data/data/images/ruport_type0.png +0 -0
- data/data/images/stef.jpg +0 -0
- data/data/images/tru256.bmp +0 -0
- data/data/images/web-links.dat +0 -1
- data/data/images/web-links.png +0 -0
- data/data/pdfs/complex_template.pdf +0 -0
- data/data/pdfs/contains_ttf_font.pdf +0 -0
- data/data/pdfs/encrypted.pdf +0 -0
- data/data/pdfs/form.pdf +1 -819
- data/data/pdfs/hexagon.pdf +0 -61
- data/data/pdfs/indirect_reference.pdf +0 -86
- data/data/pdfs/multipage_template.pdf +0 -127
- data/data/pdfs/nested_pages.pdf +0 -118
- data/data/pdfs/page_without_mediabox.pdf +0 -193
- data/data/pdfs/resources_as_indirect_object.pdf +0 -83
- data/data/pdfs/two_hexagons.pdf +0 -90
- data/data/pdfs/version_1_6.pdf +0 -61
- data/data/shift_jis_text.txt +0 -1
- data/spec/acceptance/png_spec.rb +0 -35
- data/spec/annotations_spec.rb +0 -67
- data/spec/blend_mode_spec.rb +0 -71
- data/spec/bounding_box_spec.rb +0 -501
- data/spec/column_box_spec.rb +0 -59
- data/spec/destinations_spec.rb +0 -13
- data/spec/document_spec.rb +0 -738
- data/spec/font_metric_cache_spec.rb +0 -52
- data/spec/font_spec.rb +0 -475
- data/spec/formatted_text_arranger_spec.rb +0 -452
- data/spec/formatted_text_box_spec.rb +0 -716
- data/spec/formatted_text_fragment_spec.rb +0 -299
- data/spec/graphics_spec.rb +0 -705
- data/spec/grid_spec.rb +0 -95
- data/spec/images_spec.rb +0 -167
- data/spec/inline_formatted_text_parser_spec.rb +0 -568
- data/spec/jpg_spec.rb +0 -23
- data/spec/line_wrap_spec.rb +0 -366
- data/spec/measurement_units_spec.rb +0 -22
- data/spec/outline_spec.rb +0 -409
- data/spec/png_spec.rb +0 -257
- data/spec/reference_spec.rb +0 -25
- data/spec/repeater_spec.rb +0 -154
- data/spec/security_spec.rb +0 -151
- data/spec/soft_mask_spec.rb +0 -78
- data/spec/span_spec.rb +0 -43
- data/spec/stamp_spec.rb +0 -179
- data/spec/stroke_styles_spec.rb +0 -208
- data/spec/text_at_spec.rb +0 -142
- data/spec/text_box_spec.rb +0 -1042
- data/spec/text_rendering_mode_spec.rb +0 -45
- data/spec/text_spacing_spec.rb +0 -93
- data/spec/text_spec.rb +0 -543
- data/spec/text_with_inline_formatting_spec.rb +0 -35
- data/spec/transparency_spec.rb +0 -91
- data/spec/view_spec.rb +0 -42
data/lib/prawn/font.rb
CHANGED
@@ -1,15 +1,14 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
#
|
3
1
|
# font.rb : The Prawn font class
|
4
2
|
#
|
5
3
|
# Copyright May 2008, Gregory Brown / James Healy. All Rights Reserved.
|
6
4
|
#
|
7
5
|
# This is free software. Please see the LICENSE and COPYING files for details.
|
8
6
|
#
|
9
|
-
require_relative
|
10
|
-
require_relative
|
11
|
-
require_relative
|
12
|
-
require_relative
|
7
|
+
require_relative 'font/afm'
|
8
|
+
require_relative 'font/ttf'
|
9
|
+
require_relative 'font/dfont'
|
10
|
+
require_relative 'font/ttc'
|
11
|
+
require_relative 'font_metric_cache'
|
13
12
|
|
14
13
|
module Prawn
|
15
14
|
class Document
|
@@ -35,8 +34,8 @@ module Prawn
|
|
35
34
|
# end
|
36
35
|
#
|
37
36
|
# The :name parameter must be a string. It can be one of the 14 built-in
|
38
|
-
# fonts supported by PDF, or the location of a TTF file. The
|
39
|
-
# array specifies the valid built in font values.
|
37
|
+
# fonts supported by PDF, or the location of a TTF file. The
|
38
|
+
# Font::AFM::BUILT_INS array specifies the valid built in font values.
|
40
39
|
#
|
41
40
|
# If a ttf font is specified, the glyphs necessary to render your document
|
42
41
|
# will be embedded in the rendered PDF. This should be your preferred option
|
@@ -44,14 +43,15 @@ module Prawn
|
|
44
43
|
# make it more portable.
|
45
44
|
#
|
46
45
|
# The options parameter is an optional hash providing size and style. To use
|
47
|
-
# the :style option you need to map those font styles to their respective
|
46
|
+
# the :style option you need to map those font styles to their respective
|
47
|
+
# font files.
|
48
48
|
# See font_families for more information.
|
49
49
|
#
|
50
50
|
def font(name = nil, options = {})
|
51
|
-
return((defined?(@font) && @font) || font(
|
51
|
+
return((defined?(@font) && @font) || font('Helvetica')) if name.nil?
|
52
52
|
|
53
53
|
if state.pages.empty? && !state.page.in_stamp_stream?
|
54
|
-
|
54
|
+
raise Prawn::Errors::NotOnPage
|
55
55
|
end
|
56
56
|
|
57
57
|
new_font = find_font(name.to_s, options)
|
@@ -107,33 +107,35 @@ module Prawn
|
|
107
107
|
font_size(size)
|
108
108
|
end
|
109
109
|
|
110
|
-
# Returns the width of the given string using the given font. If :size is
|
111
|
-
# specified as one of the options, the string is measured using the
|
112
|
-
# font size. You can also pass :kerning as an option to indicate
|
113
|
-
# kerning should be used when measuring the width (defaults to
|
110
|
+
# Returns the width of the given string using the given font. If :size is
|
111
|
+
# not specified as one of the options, the string is measured using the
|
112
|
+
# current font size. You can also pass :kerning as an option to indicate
|
113
|
+
# whether kerning should be used when measuring the width (defaults to
|
114
|
+
# +false+).
|
114
115
|
#
|
115
116
|
# Note that the string _must_ be encoded properly for the font being used.
|
116
117
|
# For AFM fonts, this is WinAnsi. For TTF, make sure the font is encoded as
|
117
118
|
# UTF-8. You can use the Font#normalize_encoding method to make sure strings
|
118
119
|
# are in an encoding appropriate for the current font.
|
119
120
|
#--
|
120
|
-
# For the record, this method used to be a method of Font (and still
|
121
|
-
# to width computations on Font). However, having the primary
|
122
|
-
# calculating string widths exist on Font made it tricky to
|
123
|
-
# for Prawn in which widths are computed differently (e.g.,
|
124
|
-
# tags into account, or the like).
|
125
|
-
#
|
126
|
-
# By putting width_of here, on Document itself, extensions may easily
|
127
|
-
# it and redefine the width calculation behavior.
|
121
|
+
# For the record, this method used to be a method of Font (and still
|
122
|
+
# delegates to width computations on Font). However, having the primary
|
123
|
+
# interface for calculating string widths exist on Font made it tricky to
|
124
|
+
# write extensions for Prawn in which widths are computed differently (e.g.,
|
125
|
+
# taking formatting tags into account, or the like).
|
126
|
+
#
|
127
|
+
# By putting width_of here, on Document itself, extensions may easily
|
128
|
+
# override it and redefine the width calculation behavior.
|
128
129
|
#++
|
129
130
|
def width_of(string, options = {})
|
130
|
-
if
|
131
|
+
if options.key? :inline_format
|
132
|
+
p = options[:inline_format]
|
131
133
|
p = [] unless p.is_a?(Array)
|
132
134
|
|
133
135
|
# Build up an Arranger with the entire string on one line, finalize it,
|
134
136
|
# and find its width.
|
135
137
|
arranger = Prawn::Text::Formatted::Arranger.new(self, options)
|
136
|
-
arranger.consumed =
|
138
|
+
arranger.consumed = text_formatter.format(string, *p)
|
137
139
|
arranger.finalize_line
|
138
140
|
|
139
141
|
arranger.line_width
|
@@ -169,20 +171,26 @@ module Prawn
|
|
169
171
|
#
|
170
172
|
def font_families
|
171
173
|
@font_families ||= {}.merge!(
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
174
|
+
'Courier' => {
|
175
|
+
bold: 'Courier-Bold',
|
176
|
+
italic: 'Courier-Oblique',
|
177
|
+
bold_italic: 'Courier-BoldOblique',
|
178
|
+
normal: 'Courier'
|
179
|
+
},
|
180
|
+
|
181
|
+
'Times-Roman' => {
|
182
|
+
bold: 'Times-Bold',
|
183
|
+
italic: 'Times-Italic',
|
184
|
+
bold_italic: 'Times-BoldItalic',
|
185
|
+
normal: 'Times-Roman'
|
186
|
+
},
|
187
|
+
|
188
|
+
'Helvetica' => {
|
189
|
+
bold: 'Helvetica-Bold',
|
190
|
+
italic: 'Helvetica-Oblique',
|
191
|
+
bold_italic: 'Helvetica-BoldOblique',
|
192
|
+
normal: 'Helvetica'
|
193
|
+
}
|
186
194
|
)
|
187
195
|
end
|
188
196
|
|
@@ -200,7 +208,7 @@ module Prawn
|
|
200
208
|
# finishes, the original font is restored.
|
201
209
|
#
|
202
210
|
def save_font
|
203
|
-
@font ||= find_font(
|
211
|
+
@font ||= find_font('Helvetica')
|
204
212
|
original_font = @font
|
205
213
|
original_size = @font_size
|
206
214
|
|
@@ -210,26 +218,27 @@ module Prawn
|
|
210
218
|
end
|
211
219
|
|
212
220
|
# Looks up the given font using the given criteria. Once a font has been
|
213
|
-
# found by that matches the criteria, it will be cached to subsequent
|
214
|
-
# for that font will return the same object.
|
215
|
-
|
221
|
+
# found by that matches the criteria, it will be cached to subsequent
|
222
|
+
# lookups for that font will return the same object.
|
223
|
+
# --
|
216
224
|
# Challenges involved: the name alone is not sufficient to uniquely identify
|
217
225
|
# a font (think dfont suitcases that can hold multiple different fonts in a
|
218
226
|
# single file). Thus, the :name key is included in the cache key.
|
219
227
|
#
|
220
228
|
# It is further complicated, however, since fonts in some formats (like the
|
221
229
|
# dfont suitcases) can be identified either by numeric index, OR by their
|
222
|
-
# name within the suitcase, and both should hash to the same font object
|
223
|
-
#
|
224
|
-
# which means if someone selects a font both by name, and by
|
225
|
-
# font will be embedded twice. Since we do font subsetting, this
|
226
|
-
# embedding won't be catastrophic, just annoying.
|
230
|
+
# name within the suitcase, and both should hash to the same font object (to
|
231
|
+
# avoid the font being embedded multiple times). This is not yet
|
232
|
+
# implemented, which means if someone selects a font both by name, and by
|
233
|
+
# index, the font will be embedded twice. Since we do font subsetting, this
|
234
|
+
# double embedding won't be catastrophic, just annoying.
|
227
235
|
# ++
|
228
236
|
#
|
229
237
|
# @private
|
230
238
|
def find_font(name, options = {}) #:nodoc:
|
231
239
|
if font_families.key?(name)
|
232
|
-
family
|
240
|
+
family = name
|
241
|
+
name = font_families[name][options[:style] || :normal]
|
233
242
|
if name.is_a?(::Hash)
|
234
243
|
options = options.merge(name)
|
235
244
|
name = options[:file]
|
@@ -240,7 +249,8 @@ module Prawn
|
|
240
249
|
if name.is_a? Prawn::Font
|
241
250
|
font_registry[key] = name
|
242
251
|
else
|
243
|
-
font_registry[key] ||=
|
252
|
+
font_registry[key] ||=
|
253
|
+
Font.load(self, name, options.merge(family: family))
|
244
254
|
end
|
245
255
|
end
|
246
256
|
|
@@ -280,12 +290,14 @@ module Prawn
|
|
280
290
|
attr_reader :options
|
281
291
|
|
282
292
|
# Shortcut interface for constructing a font object. Filenames of the form
|
283
|
-
# *.ttf will call Font::TTF.new, *.dfont Font::DFont.new,
|
284
|
-
# will be passed through to
|
293
|
+
# *.ttf will call Font::TTF.new, *.dfont Font::DFont.new, *.ttc goes to
|
294
|
+
# Font::TTC.new, and anything else will be passed through to
|
295
|
+
# Font::AFM.new()
|
285
296
|
def self.load(document, src, options = {})
|
286
297
|
case font_format(src, options)
|
287
298
|
when 'ttf' then TTF.new(document, src, options)
|
288
299
|
when 'dfont' then DFont.new(document, src, options)
|
300
|
+
when 'ttc' then TTC.new(document, src, options)
|
289
301
|
else AFM.new(document, src, options)
|
290
302
|
end
|
291
303
|
end
|
@@ -296,16 +308,17 @@ module Prawn
|
|
296
308
|
case src.to_s
|
297
309
|
when /\.ttf$/i then return 'ttf'
|
298
310
|
when /\.dfont$/i then return 'dfont'
|
311
|
+
when /\.ttc$/i then return 'ttc'
|
299
312
|
else return 'afm'
|
300
313
|
end
|
301
314
|
end
|
302
315
|
|
303
316
|
def initialize(document, name, options = {}) #:nodoc:
|
304
|
-
@document
|
305
|
-
@name
|
306
|
-
@options
|
317
|
+
@document = document
|
318
|
+
@name = name
|
319
|
+
@options = options
|
307
320
|
|
308
|
-
@family
|
321
|
+
@family = options[:family]
|
309
322
|
|
310
323
|
@identifier = generate_unique_id
|
311
324
|
|
@@ -334,8 +347,9 @@ module Prawn
|
|
334
347
|
# font. The string is expected to be UTF-8 going in. It will be re-encoded
|
335
348
|
# and the new string will be returned. For an in-place (destructive)
|
336
349
|
# version, see normalize_encoding!.
|
337
|
-
def normalize_encoding(
|
338
|
-
|
350
|
+
def normalize_encoding(_string)
|
351
|
+
raise NotImplementedError,
|
352
|
+
'subclasses of Prawn::Font must implement #normalize_encoding'
|
339
353
|
end
|
340
354
|
|
341
355
|
# Destructive version of normalize_encoding; normalizes the encoding of a
|
@@ -364,7 +378,9 @@ module Prawn
|
|
364
378
|
#
|
365
379
|
def add_to_current_page(subset)
|
366
380
|
@references[subset] ||= register(subset)
|
367
|
-
@document.state.page.fonts.merge!(
|
381
|
+
@document.state.page.fonts.merge!(
|
382
|
+
identifier_for(subset) => @references[subset]
|
383
|
+
)
|
368
384
|
end
|
369
385
|
|
370
386
|
def identifier_for(subset) #:nodoc:
|
@@ -381,14 +397,14 @@ module Prawn
|
|
381
397
|
# Prawn::Table::Text#styled_with_of_single_character)
|
382
398
|
#
|
383
399
|
def hash #:nodoc:
|
384
|
-
[
|
400
|
+
[self.class, name, family, size].hash
|
385
401
|
end
|
386
402
|
|
387
403
|
# Compliments the #hash implementation above
|
388
404
|
#
|
389
405
|
def eql?(other) #:nodoc:
|
390
|
-
self.class == other.class &&
|
391
|
-
|
406
|
+
self.class == other.class && name == other.name &&
|
407
|
+
family == other.family && size == other.send(:size)
|
392
408
|
end
|
393
409
|
|
394
410
|
private
|
data/lib/prawn/font/afm.rb
CHANGED
@@ -1,12 +1,10 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
# prawn/font/afm.rb : Implements AFM font support for Prawn
|
4
2
|
#
|
5
3
|
# Copyright May 2008, Gregory Brown / James Healy. All Rights Reserved.
|
6
4
|
#
|
7
5
|
# This is free software. Please see the LICENSE and COPYING files for details.
|
8
6
|
|
9
|
-
require_relative
|
7
|
+
require_relative '../encoding'
|
10
8
|
|
11
9
|
module Prawn
|
12
10
|
class Font
|
@@ -19,54 +17,59 @@ module Prawn
|
|
19
17
|
|
20
18
|
self.hide_m17n_warning = false
|
21
19
|
|
22
|
-
BUILT_INS = %w[
|
23
|
-
|
24
|
-
|
25
|
-
|
20
|
+
BUILT_INS = %w[
|
21
|
+
Courier Helvetica Times-Roman Symbol ZapfDingbats
|
22
|
+
Courier-Bold Courier-Oblique Courier-BoldOblique
|
23
|
+
Times-Bold Times-Italic Times-BoldItalic
|
24
|
+
Helvetica-Bold Helvetica-Oblique Helvetica-BoldOblique
|
25
|
+
].freeze
|
26
26
|
|
27
27
|
def unicode?
|
28
28
|
false
|
29
29
|
end
|
30
30
|
|
31
31
|
def self.metrics_path
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
32
|
+
@metrics_path ||= if ENV['METRICS']
|
33
|
+
ENV['METRICS'].split(':')
|
34
|
+
else
|
35
|
+
[
|
36
|
+
'.', '/usr/lib/afm',
|
37
|
+
'/usr/local/lib/afm',
|
38
|
+
'/usr/openwin/lib/fonts/afm',
|
39
|
+
Prawn::DATADIR + '/fonts'
|
40
|
+
]
|
41
|
+
end
|
42
42
|
end
|
43
43
|
|
44
44
|
attr_reader :attributes #:nodoc:
|
45
45
|
|
46
|
+
# parse each ATM font file once only
|
47
|
+
def self.font_data
|
48
|
+
@font_data ||= SynchronizedCache.new
|
49
|
+
end
|
50
|
+
|
46
51
|
def initialize(document, name, options = {}) #:nodoc:
|
47
52
|
unless BUILT_INS.include?(name)
|
48
|
-
|
53
|
+
raise Prawn::Errors::UnknownFont, "#{name} is not a known font."
|
49
54
|
end
|
50
55
|
|
51
56
|
super
|
52
57
|
|
53
|
-
@@font_data ||= SynchronizedCache.new # parse each ATM font file once only
|
54
|
-
|
55
58
|
file_name = @name.dup
|
56
|
-
file_name <<
|
59
|
+
file_name << '.afm' unless file_name =~ /\.afm$/
|
57
60
|
file_name = file_name[0] == '/' ? file_name : find_font(file_name)
|
58
61
|
|
59
|
-
font_data =
|
60
|
-
@glyph_widths
|
61
|
-
@glyph_table
|
62
|
-
@bounding_boxes
|
63
|
-
@kern_pairs
|
62
|
+
font_data = self.class.font_data[file_name] ||= parse_afm(file_name)
|
63
|
+
@glyph_widths = font_data[:glyph_widths]
|
64
|
+
@glyph_table = font_data[:glyph_table]
|
65
|
+
@bounding_boxes = font_data[:bounding_boxes]
|
66
|
+
@kern_pairs = font_data[:kern_pairs]
|
64
67
|
@kern_pair_table = font_data[:kern_pair_table]
|
65
|
-
@attributes
|
68
|
+
@attributes = font_data[:attributes]
|
66
69
|
|
67
|
-
@ascender
|
68
|
-
@descender = @attributes[
|
69
|
-
@line_gap
|
70
|
+
@ascender = @attributes['ascender'].to_i
|
71
|
+
@descender = @attributes['descender'].to_i
|
72
|
+
@line_gap = Float(bbox[3] - bbox[1]) - (@ascender - @descender)
|
70
73
|
end
|
71
74
|
|
72
75
|
# The font bbox, as an array of integers
|
@@ -81,7 +84,7 @@ module Prawn
|
|
81
84
|
|
82
85
|
if options[:kerning]
|
83
86
|
strings, numbers = kern(string).partition { |e| e.is_a?(String) }
|
84
|
-
total_kerning_offset = numbers.inject(0.0) { |
|
87
|
+
total_kerning_offset = numbers.inject(0.0) { |a, e| a + e }
|
85
88
|
(unscaled_width_of(strings.join) - total_kerning_offset) * scale
|
86
89
|
else
|
87
90
|
unscaled_width_of(string) * scale
|
@@ -99,17 +102,19 @@ module Prawn
|
|
99
102
|
# is replaced with a string in WinAnsi encoding.
|
100
103
|
#
|
101
104
|
def normalize_encoding(text)
|
102
|
-
text.encode(
|
105
|
+
text.encode('windows-1252')
|
103
106
|
rescue ::Encoding::InvalidByteSequenceError,
|
104
107
|
::Encoding::UndefinedConversionError
|
105
108
|
|
106
109
|
raise Prawn::Errors::IncompatibleStringEncoding,
|
107
|
-
|
108
|
-
|
110
|
+
"Your document includes text that's not compatible with the " \
|
111
|
+
"Windows-1252 character set.\n" \
|
112
|
+
"If you need full UTF-8 support, use TTF fonts instead of PDF's " \
|
113
|
+
"built-in fonts.\n"
|
109
114
|
end
|
110
115
|
|
111
116
|
def to_utf8(text)
|
112
|
-
text.encode(
|
117
|
+
text.encode('UTF-8')
|
113
118
|
end
|
114
119
|
|
115
120
|
# Returns the number of characters in +str+ (a WinAnsi-encoded string).
|
@@ -135,45 +140,52 @@ module Prawn
|
|
135
140
|
end
|
136
141
|
|
137
142
|
def glyph_present?(char)
|
138
|
-
|
143
|
+
!normalize_encoding(char).nil?
|
139
144
|
rescue Prawn::Errors::IncompatibleStringEncoding
|
140
145
|
false
|
141
146
|
end
|
142
147
|
|
143
148
|
private
|
144
149
|
|
145
|
-
def register(
|
150
|
+
def register(_subset)
|
146
151
|
font_dict = {
|
147
|
-
:
|
148
|
-
:
|
149
|
-
:
|
152
|
+
Type: :Font,
|
153
|
+
Subtype: :Type1,
|
154
|
+
BaseFont: name.to_sym
|
150
155
|
}
|
151
156
|
|
152
157
|
# Symbolic AFM fonts (Symbol, ZapfDingbats) have their own encodings
|
153
|
-
font_dict
|
158
|
+
font_dict[:Encoding] = :WinAnsiEncoding unless symbolic?
|
154
159
|
|
155
160
|
@document.ref!(font_dict)
|
156
161
|
end
|
157
162
|
|
158
163
|
def symbolic?
|
159
|
-
attributes[
|
164
|
+
attributes['characterset'] == 'Special'
|
160
165
|
end
|
161
166
|
|
162
167
|
def find_font(file)
|
163
|
-
self.class.metrics_path.find { |f| File.exist? "#{f}/#{file}" } +
|
168
|
+
self.class.metrics_path.find { |f| File.exist? "#{f}/#{file}" } +
|
169
|
+
"/#{file}"
|
164
170
|
rescue NoMethodError
|
165
171
|
raise Prawn::Errors::UnknownFont,
|
166
|
-
|
172
|
+
"Couldn't find the font: #{file} in any of:\n" +
|
173
|
+
self.class.metrics_path.join("\n")
|
167
174
|
end
|
168
175
|
|
169
176
|
def parse_afm(file_name)
|
170
|
-
data
|
177
|
+
data = {
|
178
|
+
glyph_widths: {},
|
179
|
+
bounding_boxes: {},
|
180
|
+
kern_pairs: {},
|
181
|
+
attributes: {}
|
182
|
+
}
|
171
183
|
section = []
|
172
184
|
|
173
185
|
File.foreach(file_name) do |line|
|
174
186
|
case line
|
175
187
|
when /^Start(\w+)/
|
176
|
-
section.push
|
188
|
+
section.push Regexp.last_match(1)
|
177
189
|
next
|
178
190
|
when /^End(\w+)/
|
179
191
|
section.pop
|
@@ -181,17 +193,18 @@ module Prawn
|
|
181
193
|
end
|
182
194
|
|
183
195
|
case section
|
184
|
-
when [
|
196
|
+
when %w[FontMetrics CharMetrics]
|
185
197
|
next unless line =~ /^CH?\s/
|
186
198
|
|
187
|
-
name
|
188
|
-
data[:glyph_widths][name]
|
199
|
+
name = line[/\bN\s+(\.?\w+)\s*;/, 1]
|
200
|
+
data[:glyph_widths][name] = line[/\bWX\s+(\d+)\s*;/, 1].to_i
|
189
201
|
data[:bounding_boxes][name] = line[/\bB\s+([^;]+);/, 1].to_s.rstrip
|
190
|
-
when [
|
202
|
+
when %w[FontMetrics KernData KernPairs]
|
191
203
|
next unless line =~ /^KPX\s+(\.?\w+)\s+(\.?\w+)\s+(-?\d+)/
|
192
|
-
data[:kern_pairs][[
|
193
|
-
|
194
|
-
|
204
|
+
data[:kern_pairs][[Regexp.last_match(1), Regexp.last_match(2)]] =
|
205
|
+
Regexp.last_match(3).to_i
|
206
|
+
when %w[FontMetrics KernData TrackKern],
|
207
|
+
%w[FontMetrics Composites]
|
195
208
|
next
|
196
209
|
else
|
197
210
|
parse_generic_afm_attribute(line, data)
|
@@ -204,10 +217,15 @@ module Prawn
|
|
204
217
|
data[:glyph_widths][Encoding::WinAnsi::CHARACTERS[i]].to_i
|
205
218
|
end
|
206
219
|
|
207
|
-
character_hash = Hash[
|
208
|
-
|
209
|
-
|
210
|
-
|
220
|
+
character_hash = Hash[
|
221
|
+
Encoding::WinAnsi::CHARACTERS.zip(
|
222
|
+
(0..Encoding::WinAnsi::CHARACTERS.size).to_a
|
223
|
+
)
|
224
|
+
]
|
225
|
+
data[:kern_pair_table] =
|
226
|
+
data[:kern_pairs].each_with_object({}) do |p, h|
|
227
|
+
h[p[0].map { |n| character_hash[n] }] = p[1]
|
228
|
+
end
|
211
229
|
|
212
230
|
data.each_value(&:freeze)
|
213
231
|
data.freeze
|
@@ -215,9 +233,15 @@ module Prawn
|
|
215
233
|
|
216
234
|
def parse_generic_afm_attribute(line, hash)
|
217
235
|
line =~ /(^\w+)\s+(.*)/
|
218
|
-
key
|
236
|
+
key = Regexp.last_match(1).to_s.downcase
|
237
|
+
value = Regexp.last_match(2)
|
219
238
|
|
220
|
-
hash[:attributes][key] =
|
239
|
+
hash[:attributes][key] =
|
240
|
+
if hash[:attributes][key]
|
241
|
+
Array(hash[:attributes][key]) << value
|
242
|
+
else
|
243
|
+
value
|
244
|
+
end
|
221
245
|
end
|
222
246
|
|
223
247
|
# converts a string into an array with spacing offsets
|
@@ -230,7 +254,8 @@ module Prawn
|
|
230
254
|
last_byte = nil
|
231
255
|
|
232
256
|
string.each_byte do |byte|
|
233
|
-
|
257
|
+
k = last_byte && @kern_pair_table[[last_byte, byte]]
|
258
|
+
if k
|
234
259
|
kerned << -k << [byte]
|
235
260
|
else
|
236
261
|
kerned.last << byte
|
@@ -238,14 +263,16 @@ module Prawn
|
|
238
263
|
last_byte = byte
|
239
264
|
end
|
240
265
|
|
241
|
-
kerned.map
|
242
|
-
e = (Array
|
243
|
-
e.respond_to?(:force_encoding)
|
244
|
-
|
266
|
+
kerned.map do |e|
|
267
|
+
e = e.is_a?(Array) ? e.pack('C*') : e
|
268
|
+
if e.respond_to?(:force_encoding)
|
269
|
+
e.force_encoding(::Encoding::Windows_1252)
|
270
|
+
else
|
271
|
+
e
|
272
|
+
end
|
273
|
+
end
|
245
274
|
end
|
246
275
|
|
247
|
-
private
|
248
|
-
|
249
276
|
def unscaled_width_of(string)
|
250
277
|
string.bytes.inject(0) do |s, r|
|
251
278
|
s + @glyph_table[r]
|