prawn 2.1.0 → 2.4.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 +5 -5
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/GPLv2 +20 -21
- data/Gemfile +3 -9
- data/Rakefile +9 -41
- data/lib/prawn.rb +37 -49
- data/lib/prawn/document.rb +193 -141
- data/lib/prawn/document/bounding_box.rb +50 -30
- data/lib/prawn/document/column_box.rb +7 -7
- data/lib/prawn/document/internals.rb +8 -6
- data/lib/prawn/document/span.rb +22 -16
- data/lib/prawn/encoding.rb +69 -68
- data/lib/prawn/errors.rb +12 -7
- data/lib/prawn/font.rb +104 -69
- data/lib/prawn/font_metric_cache.rb +20 -13
- data/lib/prawn/{font → fonts}/afm.rb +108 -72
- data/lib/prawn/{font → fonts}/dfont.rb +5 -11
- data/lib/prawn/fonts/otf.rb +11 -0
- data/lib/prawn/fonts/ttc.rb +36 -0
- data/lib/prawn/{font → fonts}/ttf.rb +126 -81
- data/lib/prawn/graphics.rb +119 -81
- data/lib/prawn/graphics/blend_mode.rb +9 -8
- data/lib/prawn/graphics/cap_style.rb +3 -3
- data/lib/prawn/graphics/color.rb +43 -39
- data/lib/prawn/graphics/dash.rb +23 -11
- data/lib/prawn/graphics/join_style.rb +9 -3
- data/lib/prawn/graphics/patterns.rb +204 -102
- data/lib/prawn/graphics/transformation.rb +15 -9
- data/lib/prawn/graphics/transparency.rb +17 -13
- data/lib/prawn/grid.rb +84 -48
- data/lib/prawn/image_handler.rb +5 -5
- data/lib/prawn/images.rb +60 -49
- data/lib/prawn/images/image.rb +2 -1
- data/lib/prawn/images/jpg.rb +31 -22
- data/lib/prawn/images/png.rb +67 -63
- data/lib/prawn/measurement_extensions.rb +10 -9
- data/lib/prawn/measurements.rb +19 -15
- data/lib/prawn/outline.rb +98 -77
- data/lib/prawn/repeater.rb +15 -11
- data/lib/prawn/security.rb +93 -70
- data/lib/prawn/security/arcfour.rb +2 -2
- data/lib/prawn/soft_mask.rb +26 -26
- data/lib/prawn/stamp.rb +20 -13
- data/lib/prawn/text.rb +76 -60
- data/lib/prawn/text/box.rb +18 -14
- data/lib/prawn/text/formatted.rb +5 -5
- data/lib/prawn/text/formatted/arranger.rb +80 -40
- data/lib/prawn/text/formatted/box.rb +140 -101
- data/lib/prawn/text/formatted/fragment.rb +11 -14
- data/lib/prawn/text/formatted/line_wrap.rb +128 -67
- data/lib/prawn/text/formatted/parser.rb +147 -123
- data/lib/prawn/text/formatted/wrap.rb +48 -32
- data/lib/prawn/transformation_stack.rb +7 -5
- data/lib/prawn/utilities.rb +7 -22
- data/lib/prawn/version.rb +2 -2
- data/lib/prawn/view.rb +17 -7
- data/manual/basic_concepts/adding_pages.rb +6 -7
- data/manual/basic_concepts/basic_concepts.rb +31 -22
- data/manual/basic_concepts/creation.rb +10 -11
- data/manual/basic_concepts/cursor.rb +4 -5
- data/manual/basic_concepts/measurement.rb +7 -8
- data/manual/basic_concepts/origin.rb +5 -6
- data/manual/basic_concepts/other_cursor_helpers.rb +11 -12
- data/manual/basic_concepts/view.rb +22 -16
- data/manual/bounding_box/bounding_box.rb +29 -24
- data/manual/bounding_box/bounds.rb +11 -12
- data/manual/bounding_box/canvas.rb +7 -8
- data/manual/bounding_box/creation.rb +6 -7
- data/manual/bounding_box/indentation.rb +14 -15
- data/manual/bounding_box/nesting.rb +25 -18
- data/manual/bounding_box/russian_boxes.rb +14 -13
- data/manual/bounding_box/stretchy.rb +12 -13
- data/manual/contents.rb +28 -22
- data/manual/cover.rb +33 -28
- data/manual/document_and_page_options/background.rb +15 -13
- data/manual/document_and_page_options/document_and_page_options.rb +25 -20
- data/manual/document_and_page_options/metadata.rb +18 -16
- data/manual/document_and_page_options/page_margins.rb +18 -20
- data/manual/document_and_page_options/page_size.rb +13 -12
- data/manual/document_and_page_options/print_scaling.rb +18 -15
- data/manual/example_helper.rb +5 -4
- data/manual/graphics/blend_mode.rb +12 -9
- data/manual/graphics/circle_and_ellipse.rb +4 -5
- data/manual/graphics/color.rb +7 -9
- data/manual/graphics/common_lines.rb +7 -8
- data/manual/graphics/fill_and_stroke.rb +5 -6
- data/manual/graphics/fill_rules.rb +10 -10
- data/manual/graphics/gradients.rb +27 -21
- data/manual/graphics/graphics.rb +48 -40
- data/manual/graphics/helper.rb +19 -9
- data/manual/graphics/line_width.rb +8 -7
- data/manual/graphics/lines_and_curves.rb +7 -8
- data/manual/graphics/polygon.rb +6 -8
- data/manual/graphics/rectangle.rb +4 -5
- data/manual/graphics/rotate.rb +6 -7
- data/manual/graphics/scale.rb +14 -15
- data/manual/graphics/soft_masks.rb +3 -4
- data/manual/graphics/stroke_cap.rb +6 -7
- data/manual/graphics/stroke_dash.rb +15 -16
- data/manual/graphics/stroke_join.rb +5 -6
- data/manual/graphics/translate.rb +10 -10
- data/manual/graphics/transparency.rb +7 -8
- data/manual/how_to_read_this_manual.rb +6 -6
- data/manual/images/absolute_position.rb +6 -7
- data/manual/images/fit.rb +7 -8
- data/manual/images/horizontal.rb +10 -11
- data/manual/images/images.rb +28 -24
- data/manual/images/plain_image.rb +5 -6
- data/manual/images/scale.rb +9 -10
- data/manual/images/vertical.rb +16 -14
- data/manual/images/width_and_height.rb +10 -11
- data/manual/layout/boxes.rb +5 -6
- data/manual/layout/content.rb +7 -8
- data/manual/layout/layout.rb +18 -16
- data/manual/layout/simple_grid.rb +6 -7
- data/manual/outline/add_subsection_to.rb +20 -21
- data/manual/outline/insert_section_after.rb +15 -16
- data/manual/outline/outline.rb +21 -17
- data/manual/outline/sections_and_pages.rb +17 -18
- data/manual/repeatable_content/alternate_page_numbering.rb +21 -17
- data/manual/repeatable_content/page_numbering.rb +17 -16
- data/manual/repeatable_content/repeatable_content.rb +25 -19
- data/manual/repeatable_content/repeater.rb +14 -15
- data/manual/repeatable_content/stamp.rb +14 -15
- data/manual/security/encryption.rb +9 -10
- data/manual/security/permissions.rb +21 -14
- data/manual/security/security.rb +19 -16
- data/manual/table.rb +3 -3
- data/manual/text/alignment.rb +16 -17
- data/manual/text/color.rb +12 -11
- data/manual/text/column_box.rb +9 -10
- data/manual/text/fallback_fonts.rb +25 -21
- data/manual/text/font.rb +11 -12
- data/manual/text/font_size.rb +13 -14
- data/manual/text/font_style.rb +10 -8
- data/manual/text/formatted_callbacks.rb +33 -24
- data/manual/text/formatted_text.rb +36 -25
- data/manual/text/free_flowing_text.rb +22 -23
- data/manual/text/inline.rb +18 -19
- data/manual/text/kerning_and_character_spacing.rb +14 -15
- data/manual/text/leading.rb +7 -8
- data/manual/text/line_wrapping.rb +37 -18
- data/manual/text/paragraph_indentation.rb +12 -14
- data/manual/text/positioned_text.rb +15 -16
- data/manual/text/registering_families.rb +20 -21
- data/manual/text/rendering_and_color.rb +9 -10
- data/manual/text/right_to_left_text.rb +26 -19
- data/manual/text/rotation.rb +33 -23
- data/manual/text/single_usage.rb +8 -9
- data/manual/text/text.rb +57 -52
- data/manual/text/text_box_excess.rb +20 -17
- data/manual/text/text_box_extensions.rb +18 -15
- data/manual/text/text_box_overflow.rb +20 -19
- data/manual/text/utf8.rb +11 -12
- data/manual/text/win_ansi_charset.rb +27 -25
- data/prawn.gemspec +41 -34
- data/spec/extensions/encoding_helpers.rb +3 -3
- data/spec/prawn/document/bounding_box_spec.rb +550 -0
- data/spec/prawn/document/column_box_spec.rb +75 -0
- data/spec/prawn/document/security_spec.rb +176 -0
- data/spec/prawn/document_annotations_spec.rb +76 -0
- data/spec/prawn/document_destinations_spec.rb +15 -0
- data/spec/prawn/document_grid_spec.rb +99 -0
- data/spec/prawn/document_reference_spec.rb +27 -0
- data/spec/prawn/document_span_spec.rb +44 -0
- data/spec/prawn/document_spec.rb +805 -0
- data/spec/prawn/font_metric_cache_spec.rb +54 -0
- data/spec/prawn/font_spec.rb +544 -0
- data/spec/prawn/graphics/blend_mode_spec.rb +63 -0
- data/spec/prawn/graphics/transparency_spec.rb +81 -0
- data/spec/prawn/graphics_spec.rb +872 -0
- data/spec/prawn/graphics_stroke_styles_spec.rb +229 -0
- data/spec/{image_handler_spec.rb → prawn/image_handler_spec.rb} +14 -14
- data/spec/prawn/images/jpg_spec.rb +20 -0
- data/spec/prawn/images/png_spec.rb +283 -0
- data/spec/prawn/images_spec.rb +229 -0
- data/spec/prawn/measurements_extensions_spec.rb +24 -0
- data/spec/prawn/outline_spec.rb +512 -0
- data/spec/prawn/repeater_spec.rb +166 -0
- data/spec/prawn/soft_mask_spec.rb +74 -0
- data/spec/prawn/stamp_spec.rb +173 -0
- data/spec/prawn/text/box_spec.rb +1110 -0
- data/spec/prawn/text/formatted/arranger_spec.rb +466 -0
- data/spec/prawn/text/formatted/box_spec.rb +849 -0
- data/spec/prawn/text/formatted/fragment_spec.rb +343 -0
- data/spec/prawn/text/formatted/line_wrap_spec.rb +495 -0
- data/spec/prawn/text/formatted/parser_spec.rb +697 -0
- data/spec/prawn/text_draw_text_spec.rb +150 -0
- data/spec/prawn/text_rendering_mode_spec.rb +48 -0
- data/spec/prawn/text_spacing_spec.rb +95 -0
- data/spec/prawn/text_spec.rb +603 -0
- data/spec/prawn/text_with_inline_formatting_spec.rb +35 -0
- data/spec/{transformation_stack_spec.rb → prawn/transformation_stack_spec.rb} +22 -19
- data/spec/prawn/view_spec.rb +63 -0
- data/spec/prawn_manual_spec.rb +35 -0
- data/spec/spec_helper.rb +18 -19
- metadata +102 -222
- metadata.gz.sig +0 -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/errors.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
3
|
# errors.rb : Implements custom error classes for Prawn
|
4
4
|
#
|
5
5
|
# Copyright April 2008, Gregory Brown. All Rights Reserved.
|
@@ -43,9 +43,9 @@ module Prawn
|
|
43
43
|
#
|
44
44
|
UnknownOption = Class.new(StandardError)
|
45
45
|
|
46
|
-
# this error is raised when a user attempts to embed an image of an
|
47
|
-
# type. This can either a completely unsupported format, or
|
48
|
-
# supported format (ie. some types of PNG)
|
46
|
+
# this error is raised when a user attempts to embed an image of an
|
47
|
+
# unsupported type. This can either a completely unsupported format, or
|
48
|
+
# a dialect of a supported format (ie. some types of PNG)
|
49
49
|
UnsupportedImageType = Class.new(StandardError)
|
50
50
|
|
51
51
|
# This error is raised when a named element has alredy been
|
@@ -63,17 +63,22 @@ module Prawn
|
|
63
63
|
# This error is raised when a required option has not been set
|
64
64
|
RequiredOption = Class.new(StandardError)
|
65
65
|
|
66
|
-
# This error is raised when a requested outline item with a given title does
|
66
|
+
# This error is raised when a requested outline item with a given title does
|
67
|
+
# not exist
|
67
68
|
UnknownOutlineTitle = Class.new(StandardError)
|
68
69
|
|
69
70
|
# This error is raised when a block is required, but not provided
|
70
71
|
BlockRequired = Class.new(StandardError)
|
71
72
|
|
72
|
-
# This error is rased when a graphics method is called with improper
|
73
|
+
# This error is rased when a graphics method is called with improper
|
74
|
+
# arguments
|
73
75
|
InvalidGraphicsPath = Class.new(StandardError)
|
74
76
|
|
75
77
|
# Raised when unrecognized content is provided for a table cell.
|
76
78
|
#
|
77
79
|
UnrecognizedTableContent = Class.new(StandardError)
|
80
|
+
|
81
|
+
# This error is raised when an incompatible join style is specified
|
82
|
+
InvalidJoinStyle = Class.new(StandardError)
|
78
83
|
end
|
79
84
|
end
|
data/lib/prawn/font.rb
CHANGED
@@ -1,15 +1,12 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
3
|
# font.rb : The Prawn font class
|
4
4
|
#
|
5
5
|
# Copyright May 2008, Gregory Brown / James Healy. All Rights Reserved.
|
6
6
|
#
|
7
7
|
# This is free software. Please see the LICENSE and COPYING files for details.
|
8
8
|
#
|
9
|
-
require_relative
|
10
|
-
require_relative "font/ttf"
|
11
|
-
require_relative "font/dfont"
|
12
|
-
require_relative "font_metric_cache"
|
9
|
+
require_relative 'font_metric_cache'
|
13
10
|
|
14
11
|
module Prawn
|
15
12
|
class Document
|
@@ -35,8 +32,8 @@ module Prawn
|
|
35
32
|
# end
|
36
33
|
#
|
37
34
|
# 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.
|
35
|
+
# fonts supported by PDF, or the location of a TTF file. The
|
36
|
+
# Fonts::AFM::BUILT_INS array specifies the valid built in font values.
|
40
37
|
#
|
41
38
|
# If a ttf font is specified, the glyphs necessary to render your document
|
42
39
|
# will be embedded in the rendered PDF. This should be your preferred option
|
@@ -44,14 +41,15 @@ module Prawn
|
|
44
41
|
# make it more portable.
|
45
42
|
#
|
46
43
|
# 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
|
44
|
+
# the :style option you need to map those font styles to their respective
|
45
|
+
# font files.
|
48
46
|
# See font_families for more information.
|
49
47
|
#
|
50
48
|
def font(name = nil, options = {})
|
51
|
-
return((defined?(@font) && @font) || font(
|
49
|
+
return((defined?(@font) && @font) || font('Helvetica')) if name.nil?
|
52
50
|
|
53
51
|
if state.pages.empty? && !state.page.in_stamp_stream?
|
54
|
-
|
52
|
+
raise Prawn::Errors::NotOnPage
|
55
53
|
end
|
56
54
|
|
57
55
|
new_font = find_font(name.to_s, options)
|
@@ -96,6 +94,7 @@ module Prawn
|
|
96
94
|
#
|
97
95
|
def font_size(points = nil)
|
98
96
|
return @font_size unless points
|
97
|
+
|
99
98
|
size_before_yield = @font_size
|
100
99
|
@font_size = points
|
101
100
|
block_given? ? yield : return
|
@@ -107,33 +106,35 @@ module Prawn
|
|
107
106
|
font_size(size)
|
108
107
|
end
|
109
108
|
|
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
|
109
|
+
# Returns the width of the given string using the given font. If :size is
|
110
|
+
# not specified as one of the options, the string is measured using the
|
111
|
+
# current font size. You can also pass :kerning as an option to indicate
|
112
|
+
# whether kerning should be used when measuring the width (defaults to
|
113
|
+
# +false+).
|
114
114
|
#
|
115
115
|
# Note that the string _must_ be encoded properly for the font being used.
|
116
116
|
# For AFM fonts, this is WinAnsi. For TTF, make sure the font is encoded as
|
117
117
|
# UTF-8. You can use the Font#normalize_encoding method to make sure strings
|
118
118
|
# are in an encoding appropriate for the current font.
|
119
119
|
#--
|
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.
|
120
|
+
# For the record, this method used to be a method of Font (and still
|
121
|
+
# delegates to width computations on Font). However, having the primary
|
122
|
+
# interface for calculating string widths exist on Font made it tricky to
|
123
|
+
# write extensions for Prawn in which widths are computed differently (e.g.,
|
124
|
+
# taking formatting tags into account, or the like).
|
125
|
+
#
|
126
|
+
# By putting width_of here, on Document itself, extensions may easily
|
127
|
+
# override it and redefine the width calculation behavior.
|
128
128
|
#++
|
129
129
|
def width_of(string, options = {})
|
130
|
-
if
|
130
|
+
if options.key? :inline_format
|
131
|
+
p = options[:inline_format]
|
131
132
|
p = [] unless p.is_a?(Array)
|
132
133
|
|
133
134
|
# Build up an Arranger with the entire string on one line, finalize it,
|
134
135
|
# and find its width.
|
135
136
|
arranger = Prawn::Text::Formatted::Arranger.new(self, options)
|
136
|
-
arranger.consumed =
|
137
|
+
arranger.consumed = text_formatter.format(string, *p)
|
137
138
|
arranger.finalize_line
|
138
139
|
|
139
140
|
arranger.line_width
|
@@ -169,20 +170,26 @@ module Prawn
|
|
169
170
|
#
|
170
171
|
def font_families
|
171
172
|
@font_families ||= {}.merge!(
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
173
|
+
'Courier' => {
|
174
|
+
bold: 'Courier-Bold',
|
175
|
+
italic: 'Courier-Oblique',
|
176
|
+
bold_italic: 'Courier-BoldOblique',
|
177
|
+
normal: 'Courier'
|
178
|
+
},
|
179
|
+
|
180
|
+
'Times-Roman' => {
|
181
|
+
bold: 'Times-Bold',
|
182
|
+
italic: 'Times-Italic',
|
183
|
+
bold_italic: 'Times-BoldItalic',
|
184
|
+
normal: 'Times-Roman'
|
185
|
+
},
|
186
|
+
|
187
|
+
'Helvetica' => {
|
188
|
+
bold: 'Helvetica-Bold',
|
189
|
+
italic: 'Helvetica-Oblique',
|
190
|
+
bold_italic: 'Helvetica-BoldOblique',
|
191
|
+
normal: 'Helvetica'
|
192
|
+
}
|
186
193
|
)
|
187
194
|
end
|
188
195
|
|
@@ -200,7 +207,7 @@ module Prawn
|
|
200
207
|
# finishes, the original font is restored.
|
201
208
|
#
|
202
209
|
def save_font
|
203
|
-
@font ||= find_font(
|
210
|
+
@font ||= find_font('Helvetica')
|
204
211
|
original_font = @font
|
205
212
|
original_size = @font_size
|
206
213
|
|
@@ -210,26 +217,27 @@ module Prawn
|
|
210
217
|
end
|
211
218
|
|
212
219
|
# 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
|
-
|
220
|
+
# found by that matches the criteria, it will be cached to subsequent
|
221
|
+
# lookups for that font will return the same object.
|
222
|
+
# --
|
216
223
|
# Challenges involved: the name alone is not sufficient to uniquely identify
|
217
224
|
# a font (think dfont suitcases that can hold multiple different fonts in a
|
218
225
|
# single file). Thus, the :name key is included in the cache key.
|
219
226
|
#
|
220
227
|
# It is further complicated, however, since fonts in some formats (like the
|
221
228
|
# 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.
|
229
|
+
# name within the suitcase, and both should hash to the same font object (to
|
230
|
+
# avoid the font being embedded multiple times). This is not yet
|
231
|
+
# implemented, which means if someone selects a font both by name, and by
|
232
|
+
# index, the font will be embedded twice. Since we do font subsetting, this
|
233
|
+
# double embedding won't be catastrophic, just annoying.
|
227
234
|
# ++
|
228
235
|
#
|
229
236
|
# @private
|
230
237
|
def find_font(name, options = {}) #:nodoc:
|
231
238
|
if font_families.key?(name)
|
232
|
-
family
|
239
|
+
family = name
|
240
|
+
name = font_families[name][options[:style] || :normal]
|
233
241
|
if name.is_a?(::Hash)
|
234
242
|
options = options.merge(name)
|
235
243
|
name = options[:file]
|
@@ -240,7 +248,8 @@ module Prawn
|
|
240
248
|
if name.is_a? Prawn::Font
|
241
249
|
font_registry[key] = name
|
242
250
|
else
|
243
|
-
font_registry[key] ||=
|
251
|
+
font_registry[key] ||=
|
252
|
+
Font.load(self, name, options.merge(family: family))
|
244
253
|
end
|
245
254
|
end
|
246
255
|
|
@@ -270,6 +279,18 @@ module Prawn
|
|
270
279
|
# Provides font information and helper functions.
|
271
280
|
#
|
272
281
|
class Font
|
282
|
+
require_relative 'fonts/afm'
|
283
|
+
require_relative 'fonts/ttf'
|
284
|
+
require_relative 'fonts/dfont'
|
285
|
+
require_relative 'fonts/otf'
|
286
|
+
require_relative 'fonts/ttc'
|
287
|
+
|
288
|
+
# @deprecated
|
289
|
+
AFM = Fonts::AFM
|
290
|
+
TTF = Fonts::TTF
|
291
|
+
DFont = Fonts::DFont
|
292
|
+
TTC = Fonts::TTC
|
293
|
+
|
273
294
|
# The current font name
|
274
295
|
attr_reader :name
|
275
296
|
|
@@ -280,12 +301,15 @@ module Prawn
|
|
280
301
|
attr_reader :options
|
281
302
|
|
282
303
|
# Shortcut interface for constructing a font object. Filenames of the form
|
283
|
-
# *.ttf will call
|
284
|
-
# will be passed through to
|
304
|
+
# *.ttf will call Fonts::TTF.new, *.dfont Fonts::DFont.new, *.ttc goes to
|
305
|
+
# Fonts::TTC.new, and anything else will be passed through to
|
306
|
+
# Fonts::AFM.new()
|
285
307
|
def self.load(document, src, options = {})
|
286
308
|
case font_format(src, options)
|
287
|
-
when 'ttf'
|
309
|
+
when 'ttf' then TTF.new(document, src, options)
|
310
|
+
when 'otf' then Fonts::OTF.new(document, src, options)
|
288
311
|
when 'dfont' then DFont.new(document, src, options)
|
312
|
+
when 'ttc' then TTC.new(document, src, options)
|
289
313
|
else AFM.new(document, src, options)
|
290
314
|
end
|
291
315
|
end
|
@@ -294,18 +318,20 @@ module Prawn
|
|
294
318
|
return options.fetch(:format, 'ttf') if src.respond_to? :read
|
295
319
|
|
296
320
|
case src.to_s
|
297
|
-
when /\.ttf$/i
|
298
|
-
when /\.
|
299
|
-
|
321
|
+
when /\.ttf$/i then 'ttf'
|
322
|
+
when /\.otf$/i then 'otf'
|
323
|
+
when /\.dfont$/i then 'dfont'
|
324
|
+
when /\.ttc$/i then 'ttc'
|
325
|
+
else 'afm'
|
300
326
|
end
|
301
327
|
end
|
302
328
|
|
303
329
|
def initialize(document, name, options = {}) #:nodoc:
|
304
|
-
@document
|
305
|
-
@name
|
306
|
-
@options
|
330
|
+
@document = document
|
331
|
+
@name = name
|
332
|
+
@options = options
|
307
333
|
|
308
|
-
@family
|
334
|
+
@family = options[:family]
|
309
335
|
|
310
336
|
@identifier = generate_unique_id
|
311
337
|
|
@@ -334,15 +360,19 @@ module Prawn
|
|
334
360
|
# font. The string is expected to be UTF-8 going in. It will be re-encoded
|
335
361
|
# and the new string will be returned. For an in-place (destructive)
|
336
362
|
# version, see normalize_encoding!.
|
337
|
-
def normalize_encoding(
|
338
|
-
|
363
|
+
def normalize_encoding(_string)
|
364
|
+
raise NotImplementedError,
|
365
|
+
'subclasses of Prawn::Font must implement #normalize_encoding'
|
339
366
|
end
|
340
367
|
|
341
368
|
# Destructive version of normalize_encoding; normalizes the encoding of a
|
342
369
|
# string in place.
|
343
370
|
#
|
371
|
+
# @deprecated
|
344
372
|
def normalize_encoding!(str)
|
345
|
-
|
373
|
+
warn 'Font#normalize_encoding! is deprecated. ' \
|
374
|
+
'Please use non-mutating version Font#normalize_encoding instead.'
|
375
|
+
str.dup.replace(normalize_encoding(str))
|
346
376
|
end
|
347
377
|
|
348
378
|
# Gets height of current font in PDF points at the given font size
|
@@ -364,11 +394,13 @@ module Prawn
|
|
364
394
|
#
|
365
395
|
def add_to_current_page(subset)
|
366
396
|
@references[subset] ||= register(subset)
|
367
|
-
@document.state.page.fonts.merge!(
|
397
|
+
@document.state.page.fonts.merge!(
|
398
|
+
identifier_for(subset) => @references[subset]
|
399
|
+
)
|
368
400
|
end
|
369
401
|
|
370
402
|
def identifier_for(subset) #:nodoc:
|
371
|
-
"#{@identifier}.#{subset}"
|
403
|
+
"#{@identifier}.#{subset}".to_sym
|
372
404
|
end
|
373
405
|
|
374
406
|
def inspect #:nodoc:
|
@@ -381,14 +413,14 @@ module Prawn
|
|
381
413
|
# Prawn::Table::Text#styled_with_of_single_character)
|
382
414
|
#
|
383
415
|
def hash #:nodoc:
|
384
|
-
[
|
416
|
+
[self.class, name, family, size].hash
|
385
417
|
end
|
386
418
|
|
387
419
|
# Compliments the #hash implementation above
|
388
420
|
#
|
389
421
|
def eql?(other) #:nodoc:
|
390
|
-
self.class == other.class &&
|
391
|
-
|
422
|
+
self.class == other.class && name == other.name &&
|
423
|
+
family == other.family && size == other.size
|
392
424
|
end
|
393
425
|
|
394
426
|
private
|
@@ -401,17 +433,20 @@ module Prawn
|
|
401
433
|
loop do
|
402
434
|
key = :"F#{font_count}"
|
403
435
|
break if key_is_unique?(key)
|
436
|
+
|
404
437
|
font_count += 1
|
405
438
|
end
|
406
439
|
key
|
407
440
|
end
|
408
441
|
|
409
442
|
def key_is_unique?(test_key)
|
410
|
-
|
443
|
+
@document.state.page.fonts.keys.none? do |key|
|
411
444
|
key.to_s.start_with?("#{test_key}.")
|
412
445
|
end
|
413
446
|
end
|
414
447
|
|
448
|
+
protected
|
449
|
+
|
415
450
|
def size
|
416
451
|
@document.font_size
|
417
452
|
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
3
|
# font_metric_cache.rb : The Prawn font class
|
4
4
|
#
|
5
5
|
# Copyright Dec 2012, Kenneth Kalmer. All Rights Reserved.
|
@@ -22,21 +22,28 @@ module Prawn
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def width_of(string, options)
|
25
|
-
f =
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
25
|
+
f =
|
26
|
+
if options[:style]
|
27
|
+
# override style with :style => :bold
|
28
|
+
@document.find_font(@document.font.family, style: options[:style])
|
29
|
+
else
|
30
|
+
@document.font
|
31
|
+
end
|
32
|
+
|
33
|
+
encoded_string = f.normalize_encoding(string)
|
34
|
+
|
35
|
+
key = CacheEntry.new(f, options, encoded_string)
|
36
|
+
|
37
|
+
@cache[key] ||= f.compute_width_of(encoded_string, options)
|
31
38
|
|
32
|
-
|
39
|
+
length = @cache[key]
|
33
40
|
|
34
|
-
|
35
|
-
|
41
|
+
character_count = @document.font.character_count(encoded_string)
|
42
|
+
if character_count.positive?
|
43
|
+
length += @document.character_spacing * (character_count - 1)
|
36
44
|
end
|
37
45
|
|
38
|
-
length
|
39
|
-
(@document.character_spacing * @document.font.character_count(string))
|
46
|
+
length
|
40
47
|
end
|
41
48
|
end
|
42
49
|
end
|
@@ -1,15 +1,15 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
#
|
3
|
+
# Implements AFM font support for Prawn
|
4
4
|
#
|
5
5
|
# Copyright May 2008, Gregory Brown / James Healy. All Rights Reserved.
|
6
6
|
#
|
7
7
|
# This is free software. Please see the LICENSE and COPYING files for details.
|
8
8
|
|
9
|
-
require_relative
|
9
|
+
require_relative '../encoding'
|
10
10
|
|
11
11
|
module Prawn
|
12
|
-
|
12
|
+
module Fonts
|
13
13
|
# @private
|
14
14
|
|
15
15
|
class AFM < Font
|
@@ -19,54 +19,62 @@ module Prawn
|
|
19
19
|
|
20
20
|
self.hide_m17n_warning = false
|
21
21
|
|
22
|
-
BUILT_INS = %w[
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
BUILT_INS = %w[
|
23
|
+
Courier Helvetica Times-Roman Symbol ZapfDingbats
|
24
|
+
Courier-Bold Courier-Oblique Courier-BoldOblique
|
25
|
+
Times-Bold Times-Italic Times-BoldItalic
|
26
|
+
Helvetica-Bold Helvetica-Oblique Helvetica-BoldOblique
|
27
|
+
].freeze
|
26
28
|
|
27
29
|
def unicode?
|
28
30
|
false
|
29
31
|
end
|
30
32
|
|
31
33
|
def self.metrics_path
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
34
|
+
@metrics_path ||=
|
35
|
+
if ENV['METRICS']
|
36
|
+
ENV['METRICS'].split(':')
|
37
|
+
else
|
38
|
+
[
|
39
|
+
'.', '/usr/lib/afm',
|
40
|
+
'/usr/local/lib/afm',
|
41
|
+
'/usr/openwin/lib/fonts/afm',
|
42
|
+
"#{Prawn::DATADIR}/fonts"
|
43
|
+
]
|
44
|
+
end
|
42
45
|
end
|
43
46
|
|
44
47
|
attr_reader :attributes #:nodoc:
|
45
48
|
|
49
|
+
# parse each ATM font file once only
|
50
|
+
def self.font_data
|
51
|
+
@font_data ||= SynchronizedCache.new
|
52
|
+
end
|
53
|
+
|
46
54
|
def initialize(document, name, options = {}) #:nodoc:
|
55
|
+
name ||= options[:family]
|
47
56
|
unless BUILT_INS.include?(name)
|
48
|
-
|
57
|
+
raise Prawn::Errors::UnknownFont,
|
58
|
+
"#{name} (#{options[:style] || 'normal'}) is not a known font."
|
49
59
|
end
|
50
60
|
|
51
61
|
super
|
52
62
|
|
53
|
-
@@font_data ||= SynchronizedCache.new # parse each ATM font file once only
|
54
|
-
|
55
63
|
file_name = @name.dup
|
56
|
-
file_name <<
|
64
|
+
file_name << '.afm' unless /\.afm$/.match?(file_name)
|
57
65
|
file_name = file_name[0] == '/' ? file_name : find_font(file_name)
|
58
66
|
|
59
|
-
font_data =
|
60
|
-
@glyph_widths
|
61
|
-
@glyph_table
|
62
|
-
@bounding_boxes
|
63
|
-
@kern_pairs
|
67
|
+
font_data = self.class.font_data[file_name] ||= parse_afm(file_name)
|
68
|
+
@glyph_widths = font_data[:glyph_widths]
|
69
|
+
@glyph_table = font_data[:glyph_table]
|
70
|
+
@bounding_boxes = font_data[:bounding_boxes]
|
71
|
+
@kern_pairs = font_data[:kern_pairs]
|
64
72
|
@kern_pair_table = font_data[:kern_pair_table]
|
65
|
-
@attributes
|
73
|
+
@attributes = font_data[:attributes]
|
66
74
|
|
67
|
-
@ascender
|
68
|
-
@descender = @attributes[
|
69
|
-
@line_gap
|
75
|
+
@ascender = @attributes['ascender'].to_i
|
76
|
+
@descender = @attributes['descender'].to_i
|
77
|
+
@line_gap = Float(bbox[3] - bbox[1]) - (@ascender - @descender)
|
70
78
|
end
|
71
79
|
|
72
80
|
# The font bbox, as an array of integers
|
@@ -81,7 +89,7 @@ module Prawn
|
|
81
89
|
|
82
90
|
if options[:kerning]
|
83
91
|
strings, numbers = kern(string).partition { |e| e.is_a?(String) }
|
84
|
-
total_kerning_offset = numbers.
|
92
|
+
total_kerning_offset = numbers.sum
|
85
93
|
(unscaled_width_of(strings.join) - total_kerning_offset) * scale
|
86
94
|
else
|
87
95
|
unscaled_width_of(string) * scale
|
@@ -90,26 +98,30 @@ module Prawn
|
|
90
98
|
|
91
99
|
# Returns true if the font has kerning data, false otherwise
|
92
100
|
#
|
101
|
+
# rubocop: disable Naming/PredicateName
|
93
102
|
def has_kerning_data?
|
94
103
|
@kern_pairs.any?
|
95
104
|
end
|
105
|
+
# rubocop: enable Naming/PredicateName
|
96
106
|
|
97
107
|
# built-in fonts only work with winansi encoding, so translate the
|
98
108
|
# string. Changes the encoding in-place, so the argument itself
|
99
109
|
# is replaced with a string in WinAnsi encoding.
|
100
110
|
#
|
101
111
|
def normalize_encoding(text)
|
102
|
-
text.encode(
|
112
|
+
text.encode('windows-1252')
|
103
113
|
rescue ::Encoding::InvalidByteSequenceError,
|
104
114
|
::Encoding::UndefinedConversionError
|
105
115
|
|
106
116
|
raise Prawn::Errors::IncompatibleStringEncoding,
|
107
|
-
|
108
|
-
|
117
|
+
"Your document includes text that's not compatible with the " \
|
118
|
+
"Windows-1252 character set.\n" \
|
119
|
+
'If you need full UTF-8 support, use external fonts instead of ' \
|
120
|
+
"PDF's built-in fonts.\n"
|
109
121
|
end
|
110
122
|
|
111
123
|
def to_utf8(text)
|
112
|
-
text.encode(
|
124
|
+
text.encode('UTF-8')
|
113
125
|
end
|
114
126
|
|
115
127
|
# Returns the number of characters in +str+ (a WinAnsi-encoded string).
|
@@ -135,45 +147,52 @@ module Prawn
|
|
135
147
|
end
|
136
148
|
|
137
149
|
def glyph_present?(char)
|
138
|
-
|
150
|
+
!normalize_encoding(char).nil?
|
139
151
|
rescue Prawn::Errors::IncompatibleStringEncoding
|
140
152
|
false
|
141
153
|
end
|
142
154
|
|
143
155
|
private
|
144
156
|
|
145
|
-
def register(
|
157
|
+
def register(_subset)
|
146
158
|
font_dict = {
|
147
|
-
:
|
148
|
-
:
|
149
|
-
:
|
159
|
+
Type: :Font,
|
160
|
+
Subtype: :Type1,
|
161
|
+
BaseFont: name.to_sym
|
150
162
|
}
|
151
163
|
|
152
164
|
# Symbolic AFM fonts (Symbol, ZapfDingbats) have their own encodings
|
153
|
-
font_dict
|
165
|
+
font_dict[:Encoding] = :WinAnsiEncoding unless symbolic?
|
154
166
|
|
155
167
|
@document.ref!(font_dict)
|
156
168
|
end
|
157
169
|
|
158
170
|
def symbolic?
|
159
|
-
attributes[
|
171
|
+
attributes['characterset'] == 'Special'
|
160
172
|
end
|
161
173
|
|
162
174
|
def find_font(file)
|
163
|
-
self.class.metrics_path.find { |f| File.exist? "#{f}/#{file}" } +
|
175
|
+
self.class.metrics_path.find { |f| File.exist? "#{f}/#{file}" } +
|
176
|
+
"/#{file}"
|
164
177
|
rescue NoMethodError
|
165
178
|
raise Prawn::Errors::UnknownFont,
|
166
|
-
|
179
|
+
"Couldn't find the font: #{file} in any of:\n" +
|
180
|
+
self.class.metrics_path.join("\n")
|
167
181
|
end
|
168
182
|
|
169
183
|
def parse_afm(file_name)
|
170
|
-
data
|
184
|
+
data = {
|
185
|
+
glyph_widths: {},
|
186
|
+
bounding_boxes: {},
|
187
|
+
kern_pairs: {},
|
188
|
+
attributes: {}
|
189
|
+
}
|
171
190
|
section = []
|
172
191
|
|
173
192
|
File.foreach(file_name) do |line|
|
174
193
|
case line
|
175
194
|
when /^Start(\w+)/
|
176
|
-
section.push
|
195
|
+
section.push Regexp.last_match(1)
|
177
196
|
next
|
178
197
|
when /^End(\w+)/
|
179
198
|
section.pop
|
@@ -181,17 +200,19 @@ module Prawn
|
|
181
200
|
end
|
182
201
|
|
183
202
|
case section
|
184
|
-
when [
|
185
|
-
next unless
|
203
|
+
when %w[FontMetrics CharMetrics]
|
204
|
+
next unless /^CH?\s/.match?(line)
|
186
205
|
|
187
|
-
name
|
188
|
-
data[:glyph_widths][name]
|
206
|
+
name = line[/\bN\s+(\.?\w+)\s*;/, 1]
|
207
|
+
data[:glyph_widths][name] = line[/\bWX\s+(\d+)\s*;/, 1].to_i
|
189
208
|
data[:bounding_boxes][name] = line[/\bB\s+([^;]+);/, 1].to_s.rstrip
|
190
|
-
when [
|
209
|
+
when %w[FontMetrics KernData KernPairs]
|
191
210
|
next unless line =~ /^KPX\s+(\.?\w+)\s+(\.?\w+)\s+(-?\d+)/
|
192
|
-
|
193
|
-
|
194
|
-
|
211
|
+
|
212
|
+
data[:kern_pairs][[Regexp.last_match(1), Regexp.last_match(2)]] =
|
213
|
+
Regexp.last_match(3).to_i
|
214
|
+
when %w[FontMetrics KernData TrackKern],
|
215
|
+
%w[FontMetrics Composites]
|
195
216
|
next
|
196
217
|
else
|
197
218
|
parse_generic_afm_attribute(line, data)
|
@@ -200,14 +221,20 @@ module Prawn
|
|
200
221
|
|
201
222
|
# process data parsed from AFM file to build tables which
|
202
223
|
# will be used when measuring and kerning text
|
203
|
-
data[:glyph_table] =
|
204
|
-
|
205
|
-
|
224
|
+
data[:glyph_table] =
|
225
|
+
(0..255).map do |i|
|
226
|
+
data[:glyph_widths][Encoding::WinAnsi::CHARACTERS[i]].to_i
|
227
|
+
end
|
206
228
|
|
207
|
-
character_hash = Hash[
|
208
|
-
|
209
|
-
|
210
|
-
|
229
|
+
character_hash = Hash[
|
230
|
+
Encoding::WinAnsi::CHARACTERS.zip(
|
231
|
+
(0..Encoding::WinAnsi::CHARACTERS.size).to_a
|
232
|
+
)
|
233
|
+
]
|
234
|
+
data[:kern_pair_table] =
|
235
|
+
data[:kern_pairs].each_with_object({}) do |p, h|
|
236
|
+
h[p[0].map { |n| character_hash[n] }] = p[1]
|
237
|
+
end
|
211
238
|
|
212
239
|
data.each_value(&:freeze)
|
213
240
|
data.freeze
|
@@ -215,9 +242,15 @@ module Prawn
|
|
215
242
|
|
216
243
|
def parse_generic_afm_attribute(line, hash)
|
217
244
|
line =~ /(^\w+)\s+(.*)/
|
218
|
-
key
|
245
|
+
key = Regexp.last_match(1).to_s.downcase
|
246
|
+
value = Regexp.last_match(2)
|
219
247
|
|
220
|
-
hash[:attributes][key] =
|
248
|
+
hash[:attributes][key] =
|
249
|
+
if hash[:attributes][key]
|
250
|
+
Array(hash[:attributes][key]) << value
|
251
|
+
else
|
252
|
+
value
|
253
|
+
end
|
221
254
|
end
|
222
255
|
|
223
256
|
# converts a string into an array with spacing offsets
|
@@ -230,7 +263,8 @@ module Prawn
|
|
230
263
|
last_byte = nil
|
231
264
|
|
232
265
|
string.each_byte do |byte|
|
233
|
-
|
266
|
+
k = last_byte && @kern_pair_table[[last_byte, byte]]
|
267
|
+
if k
|
234
268
|
kerned << -k << [byte]
|
235
269
|
else
|
236
270
|
kerned.last << byte
|
@@ -238,16 +272,18 @@ module Prawn
|
|
238
272
|
last_byte = byte
|
239
273
|
end
|
240
274
|
|
241
|
-
kerned.map
|
242
|
-
e = (Array
|
243
|
-
e.respond_to?(:force_encoding)
|
244
|
-
|
275
|
+
kerned.map do |e|
|
276
|
+
e = e.is_a?(Array) ? e.pack('C*') : e
|
277
|
+
if e.respond_to?(:force_encoding)
|
278
|
+
e.force_encoding(::Encoding::Windows_1252)
|
279
|
+
else
|
280
|
+
e
|
281
|
+
end
|
282
|
+
end
|
245
283
|
end
|
246
284
|
|
247
|
-
private
|
248
|
-
|
249
285
|
def unscaled_width_of(string)
|
250
|
-
string.bytes.
|
286
|
+
string.bytes.reduce(0) do |s, r|
|
251
287
|
s + @glyph_table[r]
|
252
288
|
end
|
253
289
|
end
|