alphasights-prawn 0.10.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.
- data/COPYING +340 -0
- data/HACKING +50 -0
- data/LICENSE +56 -0
- data/README +141 -0
- data/Rakefile +52 -0
- data/data/encodings/win_ansi.txt +29 -0
- data/data/fonts/Action Man.dfont +0 -0
- data/data/fonts/Activa.ttf +0 -0
- data/data/fonts/Chalkboard.ttf +0 -0
- data/data/fonts/Courier-Bold.afm +342 -0
- data/data/fonts/Courier-BoldOblique.afm +342 -0
- data/data/fonts/Courier-Oblique.afm +342 -0
- data/data/fonts/Courier.afm +342 -0
- data/data/fonts/DejaVuSans.ttf +0 -0
- data/data/fonts/Dustismo_Roman.ttf +0 -0
- data/data/fonts/Helvetica-Bold.afm +2827 -0
- data/data/fonts/Helvetica-BoldOblique.afm +2827 -0
- data/data/fonts/Helvetica-Oblique.afm +3051 -0
- data/data/fonts/Helvetica.afm +3051 -0
- data/data/fonts/MustRead.html +19 -0
- data/data/fonts/Symbol.afm +213 -0
- data/data/fonts/Times-Bold.afm +2588 -0
- data/data/fonts/Times-BoldItalic.afm +2384 -0
- data/data/fonts/Times-Italic.afm +2667 -0
- data/data/fonts/Times-Roman.afm +2419 -0
- data/data/fonts/ZapfDingbats.afm +225 -0
- data/data/fonts/comicsans.ttf +0 -0
- data/data/fonts/gkai00mp.ttf +0 -0
- data/data/images/16bit.alpha +0 -0
- data/data/images/16bit.dat +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/barcode_issue.png +0 -0
- data/data/images/dice.alpha +0 -0
- data/data/images/dice.dat +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/letterhead.jpg +0 -0
- data/data/images/page_white_text.alpha +0 -0
- data/data/images/page_white_text.dat +0 -0
- data/data/images/page_white_text.png +0 -0
- data/data/images/pigs.jpg +0 -0
- data/data/images/rails.dat +0 -0
- data/data/images/rails.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 +1 -0
- 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/hexagon.pdf +61 -0
- data/data/pdfs/indirect_reference.pdf +86 -0
- data/data/pdfs/nested_pages.pdf +118 -0
- data/data/pdfs/resources_as_indirect_object.pdf +83 -0
- data/data/pdfs/two_hexagons.pdf +90 -0
- data/data/pdfs/version_1_6.pdf +61 -0
- data/data/shift_jis_text.txt +1 -0
- data/examples/bounding_box/bounding_boxes.rb +43 -0
- data/examples/bounding_box/indentation.rb +34 -0
- data/examples/bounding_box/russian_boxes.rb +36 -0
- data/examples/bounding_box/stretched_nesting.rb +67 -0
- data/examples/builder/simple.rb +28 -0
- data/examples/example_helper.rb +4 -0
- data/examples/general/background.rb +23 -0
- data/examples/general/canvas.rb +15 -0
- data/examples/general/context_sensitive_headers.rb +37 -0
- data/examples/general/float.rb +11 -0
- data/examples/general/margin.rb +36 -0
- data/examples/general/measurement_units.rb +51 -0
- data/examples/general/metadata-info.rb +16 -0
- data/examples/general/multi_page_layout.rb +18 -0
- data/examples/general/outlines.rb +50 -0
- data/examples/general/page_geometry.rb +31 -0
- data/examples/general/page_numbering.rb +15 -0
- data/examples/general/repeaters.rb +47 -0
- data/examples/general/stamp.rb +41 -0
- data/examples/general/templates.rb +13 -0
- data/examples/graphics/basic_images.rb +23 -0
- data/examples/graphics/chunkable.rb +38 -0
- data/examples/graphics/cmyk.rb +12 -0
- data/examples/graphics/curves.rb +11 -0
- data/examples/graphics/hexagon.rb +13 -0
- data/examples/graphics/image_fit.rb +15 -0
- data/examples/graphics/image_flow.rb +37 -0
- data/examples/graphics/image_position.rb +17 -0
- data/examples/graphics/line.rb +32 -0
- data/examples/graphics/png_types.rb +22 -0
- data/examples/graphics/polygons.rb +16 -0
- data/examples/graphics/remote_images.rb +12 -0
- data/examples/graphics/rounded_polygons.rb +19 -0
- data/examples/graphics/rounded_rectangle.rb +20 -0
- data/examples/graphics/ruport_style_helpers.rb +19 -0
- data/examples/graphics/stroke_bounds.rb +20 -0
- data/examples/graphics/stroke_cap_and_join.rb +45 -0
- data/examples/graphics/stroke_dash.rb +42 -0
- data/examples/graphics/transformations.rb +52 -0
- data/examples/graphics/transparency.rb +26 -0
- data/examples/m17n/chinese_text_wrapping.rb +17 -0
- data/examples/m17n/euro.rb +15 -0
- data/examples/m17n/sjis.rb +28 -0
- data/examples/m17n/utf8.rb +13 -0
- data/examples/m17n/win_ansi_charset.rb +54 -0
- data/examples/security/hello_foo.rb +8 -0
- data/examples/table/bill.rb +53 -0
- data/examples/table/cell.rb +12 -0
- data/examples/table/checkerboard.rb +22 -0
- data/examples/table/header.rb +14 -0
- data/examples/table/inline_format_table.rb +12 -0
- data/examples/table/multi_page_table.rb +9 -0
- data/examples/table/simple_table.rb +24 -0
- data/examples/table/subtable.rb +12 -0
- data/examples/table/widths.rb +20 -0
- data/examples/text/alignment.rb +18 -0
- data/examples/text/character_spacing.rb +12 -0
- data/examples/text/dfont.rb +48 -0
- data/examples/text/family_based_styling.rb +24 -0
- data/examples/text/font_calculations.rb +91 -0
- data/examples/text/font_size.rb +33 -0
- data/examples/text/hyphenation.rb +45 -0
- data/examples/text/indent_paragraphs.rb +22 -0
- data/examples/text/inline_format.rb +103 -0
- data/examples/text/kerning.rb +30 -0
- data/examples/text/rotated.rb +98 -0
- data/examples/text/shaped_text_box.rb +31 -0
- data/examples/text/simple_text.rb +17 -0
- data/examples/text/simple_text_ttf.rb +17 -0
- data/examples/text/text_box.rb +88 -0
- data/examples/text/text_box_returning_excess.rb +51 -0
- data/examples/text/text_flow.rb +67 -0
- data/lib/prawn.rb +27 -0
- data/lib/prawn/canvas.rb +119 -0
- data/lib/prawn/chunkable.rb +37 -0
- data/lib/prawn/compatibility.rb +51 -0
- data/lib/prawn/core.rb +85 -0
- data/lib/prawn/core/annotations.rb +61 -0
- data/lib/prawn/core/byte_string.rb +9 -0
- data/lib/prawn/core/chunk.rb +36 -0
- data/lib/prawn/core/destinations.rb +90 -0
- data/lib/prawn/core/document_state.rb +78 -0
- data/lib/prawn/core/literal_string.rb +16 -0
- data/lib/prawn/core/name_tree.rb +165 -0
- data/lib/prawn/core/object_store.rb +236 -0
- data/lib/prawn/core/page.rb +179 -0
- data/lib/prawn/core/pdf_object.rb +108 -0
- data/lib/prawn/core/reference.rb +112 -0
- data/lib/prawn/core/text.rb +140 -0
- data/lib/prawn/core/text/formatted/arranger.rb +266 -0
- data/lib/prawn/core/text/formatted/line_wrap.rb +127 -0
- data/lib/prawn/core/text/formatted/wrap.rb +112 -0
- data/lib/prawn/core/text/line_wrap.rb +209 -0
- data/lib/prawn/core/text/wrap.rb +80 -0
- data/lib/prawn/document.rb +573 -0
- data/lib/prawn/document/bounding_box.rb +425 -0
- data/lib/prawn/document/graphics_state.rb +48 -0
- data/lib/prawn/document/internals.rb +170 -0
- data/lib/prawn/document/page_geometry.rb +136 -0
- data/lib/prawn/document/snapshot.rb +87 -0
- data/lib/prawn/document_builder.rb +51 -0
- data/lib/prawn/document_builder/command.rb +38 -0
- data/lib/prawn/document_builder/constructs.rb +2 -0
- data/lib/prawn/document_builder/constructs/flowing_text_construct.rb +18 -0
- data/lib/prawn/document_builder/constructs/path_construct.rb +9 -0
- data/lib/prawn/document_builder/layout.rb +25 -0
- data/lib/prawn/document_builder/modifications.rb +2 -0
- data/lib/prawn/document_builder/modifications/layout_modification.rb +9 -0
- data/lib/prawn/document_builder/modifications/path_modification.rb +9 -0
- data/lib/prawn/encoding.rb +121 -0
- data/lib/prawn/errors.rb +94 -0
- data/lib/prawn/font.rb +341 -0
- data/lib/prawn/font/afm.rb +225 -0
- data/lib/prawn/font/dfont.rb +42 -0
- data/lib/prawn/font/ttf.rb +350 -0
- data/lib/prawn/graphics.rb +325 -0
- data/lib/prawn/graphics/cap_style.rb +38 -0
- data/lib/prawn/graphics/color.rb +205 -0
- data/lib/prawn/graphics/dash.rb +71 -0
- data/lib/prawn/graphics/join_style.rb +38 -0
- data/lib/prawn/graphics/transformation.rb +156 -0
- data/lib/prawn/graphics/transparency.rb +99 -0
- data/lib/prawn/images.rb +348 -0
- data/lib/prawn/images/jpg.rb +46 -0
- data/lib/prawn/images/png.rb +226 -0
- data/lib/prawn/measurement_extensions.rb +46 -0
- data/lib/prawn/measurements.rb +71 -0
- data/lib/prawn/outline.rb +278 -0
- data/lib/prawn/repeater.rb +129 -0
- data/lib/prawn/security.rb +262 -0
- data/lib/prawn/security/arcfour.rb +51 -0
- data/lib/prawn/stamp.rb +126 -0
- data/lib/prawn/table.rb +421 -0
- data/lib/prawn/table/accessors.rb +180 -0
- data/lib/prawn/table/cell.rb +350 -0
- data/lib/prawn/table/cell/in_table.rb +27 -0
- data/lib/prawn/table/cell/subtable.rb +65 -0
- data/lib/prawn/table/cell/text.rb +125 -0
- data/lib/prawn/text.rb +449 -0
- data/lib/prawn/text/box.rb +392 -0
- data/lib/prawn/text/formatted.rb +4 -0
- data/lib/prawn/text/formatted/box.rb +228 -0
- data/lib/prawn/text/formatted/fragment.rb +181 -0
- data/lib/prawn/text/formatted/parser.rb +213 -0
- data/spec/annotations_spec.rb +90 -0
- data/spec/bounding_box_spec.rb +190 -0
- data/spec/cell_spec.rb +348 -0
- data/spec/destinations_spec.rb +15 -0
- data/spec/document_spec.rb +473 -0
- data/spec/font_spec.rb +324 -0
- data/spec/formatted_text_arranger_spec.rb +426 -0
- data/spec/formatted_text_box_spec.rb +756 -0
- data/spec/formatted_text_fragment_spec.rb +211 -0
- data/spec/graphics_spec.rb +446 -0
- data/spec/images_spec.rb +96 -0
- data/spec/inline_formatted_text_parser_spec.rb +502 -0
- data/spec/jpg_spec.rb +25 -0
- data/spec/line_wrap_spec.rb +341 -0
- data/spec/measurement_units_spec.rb +23 -0
- data/spec/name_tree_spec.rb +112 -0
- data/spec/object_store_spec.rb +160 -0
- data/spec/outline_spec.rb +269 -0
- data/spec/pdf_object_spec.rb +170 -0
- data/spec/png_spec.rb +237 -0
- data/spec/reference_spec.rb +82 -0
- data/spec/repeater_spec.rb +96 -0
- data/spec/security_spec.rb +120 -0
- data/spec/snapshot_spec.rb +138 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/stamp_spec.rb +108 -0
- data/spec/stroke_styles_spec.rb +163 -0
- data/spec/table_spec.rb +598 -0
- data/spec/template_spec.rb +158 -0
- data/spec/text_at_spec.rb +119 -0
- data/spec/text_box_spec.rb +742 -0
- data/spec/text_spacing_spec.rb +75 -0
- data/spec/text_spec.rb +333 -0
- data/spec/text_with_inline_formatting_spec.rb +193 -0
- data/spec/transparency_spec.rb +89 -0
- metadata +331 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
# text/formatted/rectangle.rb : Implements text boxes with formatted text
|
|
4
|
+
#
|
|
5
|
+
# Copyright February 2010, Daniel Nelson. All Rights Reserved.
|
|
6
|
+
#
|
|
7
|
+
# This is free software. Please see the LICENSE and COPYING files for details.
|
|
8
|
+
#
|
|
9
|
+
|
|
10
|
+
module Prawn
|
|
11
|
+
module Text
|
|
12
|
+
module Formatted
|
|
13
|
+
|
|
14
|
+
# Draws the requested formatted text into a box. When the text overflows
|
|
15
|
+
# the rectangle shrink to fit or truncate the text. Text boxes are
|
|
16
|
+
# independent of the document y position.
|
|
17
|
+
#
|
|
18
|
+
# == Formatted Text Array
|
|
19
|
+
#
|
|
20
|
+
# Formatted text is comprised of an array of hashes, where each hash
|
|
21
|
+
# defines text and format information. As of the time of writing, the
|
|
22
|
+
# following hash options are supported:
|
|
23
|
+
#
|
|
24
|
+
# <tt>:text</tt>::
|
|
25
|
+
# the text to format according to the other hash options
|
|
26
|
+
# <tt>:styles</tt>::
|
|
27
|
+
# an array of styles to apply to this text. Available styles include
|
|
28
|
+
# :bold, :italic, :underline, :strikethrough, :subscript, and
|
|
29
|
+
# :superscript
|
|
30
|
+
# <tt>:size</tt>::
|
|
31
|
+
# a number denoting the font size to apply to this text
|
|
32
|
+
# <tt>:character_spacing</tt>::
|
|
33
|
+
# a number denoting how much to increase or decrease the default
|
|
34
|
+
# spacing between characters
|
|
35
|
+
# <tt>:font</tt>::
|
|
36
|
+
# the name of a font. The name must be an AFM font with the desired
|
|
37
|
+
# faces or must be a font that is already registered using
|
|
38
|
+
# Prawn::Document#font_families
|
|
39
|
+
# <tt>:color</tt>::
|
|
40
|
+
# anything compatible with Prawn::Graphics::Color#fill_color and
|
|
41
|
+
# Prawn::Graphics::Color#stroke_color
|
|
42
|
+
# <tt>:link</tt>::
|
|
43
|
+
# a URL to which to create a link. A clickable link will be created
|
|
44
|
+
# to that URL. Note that you must explicitly underline and color using
|
|
45
|
+
# the appropriate tags if you which to draw attention to the link
|
|
46
|
+
# <tt>:anchor</tt>::
|
|
47
|
+
# a destination that has already been or will be registered using
|
|
48
|
+
# Prawn::Core::Destinations#add_dest. A clickable link will be
|
|
49
|
+
# created to that destination. Note that you must explicitly underline
|
|
50
|
+
# and color using the appropriate tags if you which to draw attention
|
|
51
|
+
# to the link
|
|
52
|
+
# <tt>:callback</tt>::
|
|
53
|
+
# an object (or array of such objects) with two methods:
|
|
54
|
+
# #render_behind and #render_in_front, which are called immediately
|
|
55
|
+
# prior to and immediately after rendring the text fragment and which
|
|
56
|
+
# are passed the fragment as an argument
|
|
57
|
+
#
|
|
58
|
+
# == Example
|
|
59
|
+
#
|
|
60
|
+
# formatted_text_box([{ :text => "hello" },
|
|
61
|
+
# { :text => "world",
|
|
62
|
+
# :size => 24,
|
|
63
|
+
# :styles => [:bold, :italic] }])
|
|
64
|
+
#
|
|
65
|
+
# == Options
|
|
66
|
+
#
|
|
67
|
+
# Accepts the same options as Text::Box with the below exceptions
|
|
68
|
+
#
|
|
69
|
+
# <tt>:overflow</tt>::
|
|
70
|
+
# does not accept :ellipses
|
|
71
|
+
#
|
|
72
|
+
# == Returns
|
|
73
|
+
#
|
|
74
|
+
# Returns a formatted text array representing any text that did not print
|
|
75
|
+
# under the current settings.
|
|
76
|
+
#
|
|
77
|
+
# == Exceptions
|
|
78
|
+
#
|
|
79
|
+
# Raises "Bad font family" if no font family is defined for the current font
|
|
80
|
+
#
|
|
81
|
+
# Raises <tt>Prawn::Errrors::CannotFit</tt> if not wide enough to print
|
|
82
|
+
# any text
|
|
83
|
+
#
|
|
84
|
+
# Raises <tt>NotImplementedError</tt> if <tt>:ellipses</tt> <tt>overflow</tt>
|
|
85
|
+
# option included
|
|
86
|
+
#
|
|
87
|
+
def formatted_text_box(array, options)
|
|
88
|
+
Text::Formatted::Box.new(array, options.merge(:document => self)).render
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Generally, one would use the Prawn::Text::Formatted#formatted_text_box
|
|
92
|
+
# convenience method. However, using Text::Formatted::Box.new in
|
|
93
|
+
# conjunction with #render(:dry_run => true) enables one to do look-ahead
|
|
94
|
+
# calculations prior to placing text on the page, or to determine how much
|
|
95
|
+
# vertical space was consumed by the printed text
|
|
96
|
+
#
|
|
97
|
+
class Box < Prawn::Text::Box
|
|
98
|
+
include Prawn::Core::Text::Formatted::Wrap
|
|
99
|
+
|
|
100
|
+
def initialize(array, options={})
|
|
101
|
+
super(array, options)
|
|
102
|
+
if @overflow == :ellipses
|
|
103
|
+
raise NotImplementedError, "ellipses overflow unavailable with" +
|
|
104
|
+
"formatted box"
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# The height actually used during the previous <tt>render</tt>
|
|
109
|
+
#
|
|
110
|
+
def height
|
|
111
|
+
return 0 if @baseline_y.nil? || @descender.nil?
|
|
112
|
+
@baseline_y.abs + @line_height - @ascender
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# <tt>fragment</tt> is a Prawn::Text::Formatted::Fragment object
|
|
116
|
+
#
|
|
117
|
+
def draw_fragment(fragment, accumulated_width=0, line_width=0, word_spacing=0) #:nodoc:
|
|
118
|
+
case(@align)
|
|
119
|
+
when :left, :justify
|
|
120
|
+
x = @at[0]
|
|
121
|
+
when :center
|
|
122
|
+
x = @at[0] + @width * 0.5 - line_width * 0.5
|
|
123
|
+
when :right
|
|
124
|
+
x = @at[0] + @width - line_width
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
x += accumulated_width
|
|
128
|
+
|
|
129
|
+
y = @at[1] + @baseline_y
|
|
130
|
+
|
|
131
|
+
y += fragment.y_offset
|
|
132
|
+
|
|
133
|
+
fragment.left = x
|
|
134
|
+
fragment.baseline = y
|
|
135
|
+
|
|
136
|
+
draw_fragment_underlays(fragment)
|
|
137
|
+
|
|
138
|
+
if @inked
|
|
139
|
+
if @align == :justify
|
|
140
|
+
@document.word_spacing(word_spacing) {
|
|
141
|
+
@document.draw_text!(fragment.text, :at => [x, y],
|
|
142
|
+
:kerning => @kerning)
|
|
143
|
+
}
|
|
144
|
+
else
|
|
145
|
+
@document.draw_text!(fragment.text, :at => [x, y],
|
|
146
|
+
:kerning => @kerning)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
draw_fragment_overlays(fragment)
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
private
|
|
154
|
+
|
|
155
|
+
def original_text
|
|
156
|
+
@original_array.collect { |hash| hash.dup }
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def original_text=(array)
|
|
160
|
+
@original_array = array
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def normalize_encoding
|
|
164
|
+
array = original_text
|
|
165
|
+
array.each do |hash|
|
|
166
|
+
hash[:text] = @document.font.normalize_encoding(hash[:text])
|
|
167
|
+
end
|
|
168
|
+
array
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def move_baseline_down
|
|
172
|
+
if @baseline_y == 0
|
|
173
|
+
@baseline_y = -@ascender
|
|
174
|
+
else
|
|
175
|
+
@baseline_y -= (@line_height + @leading)
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def draw_fragment_underlays(fragment)
|
|
180
|
+
fragment.callback_objects.each do |obj|
|
|
181
|
+
obj.render_behind(fragment) if obj.respond_to?(:render_behind)
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def draw_fragment_overlays(fragment)
|
|
186
|
+
draw_fragment_overlay_styles(fragment)
|
|
187
|
+
draw_fragment_overlay_link(fragment)
|
|
188
|
+
draw_fragment_overlay_anchor(fragment)
|
|
189
|
+
fragment.callback_objects.each do |obj|
|
|
190
|
+
obj.render_in_front(fragment) if obj.respond_to?(:render_in_front)
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def draw_fragment_overlay_link(fragment)
|
|
195
|
+
return unless fragment.link
|
|
196
|
+
box = fragment.absolute_bounding_box
|
|
197
|
+
@document.link_annotation(box,
|
|
198
|
+
:Border => [0, 0, 0],
|
|
199
|
+
:A => { :Type => :Action,
|
|
200
|
+
:S => :URI,
|
|
201
|
+
:URI => Prawn::Core::LiteralString.new(fragment.link) })
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def draw_fragment_overlay_anchor(fragment)
|
|
205
|
+
return unless fragment.anchor
|
|
206
|
+
box = fragment.absolute_bounding_box
|
|
207
|
+
@document.link_annotation(box,
|
|
208
|
+
:Border => [0, 0, 0],
|
|
209
|
+
:Dest => fragment.anchor)
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def draw_fragment_overlay_styles(fragment)
|
|
213
|
+
underline = fragment.styles.include?(:underline)
|
|
214
|
+
if underline
|
|
215
|
+
@document.stroke_line(fragment.underline_points)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
strikethrough = fragment.styles.include?(:strikethrough)
|
|
219
|
+
if strikethrough
|
|
220
|
+
@document.stroke_line(fragment.strikethrough_points)
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
end
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
# text/formatted/fragment.rb : Implements information about a formatted fragment
|
|
4
|
+
#
|
|
5
|
+
# Copyright March 2010, Daniel Nelson. All Rights Reserved.
|
|
6
|
+
#
|
|
7
|
+
# This is free software. Please see the LICENSE and COPYING files for details.
|
|
8
|
+
|
|
9
|
+
module Prawn
|
|
10
|
+
module Text
|
|
11
|
+
module Formatted
|
|
12
|
+
|
|
13
|
+
# Prawn::Text::Formatted::Fragment is a state store for a formatted text
|
|
14
|
+
# fragment. It does not render anything.
|
|
15
|
+
#
|
|
16
|
+
class Fragment
|
|
17
|
+
|
|
18
|
+
attr_reader :text, :format_state
|
|
19
|
+
attr_writer :width
|
|
20
|
+
attr_accessor :line_height, :descender, :ascender
|
|
21
|
+
attr_accessor :word_spacing, :left, :baseline
|
|
22
|
+
|
|
23
|
+
def initialize(text, format_state, document)
|
|
24
|
+
@text = text
|
|
25
|
+
@format_state = format_state
|
|
26
|
+
@document = document
|
|
27
|
+
@word_spacing = 0
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def width
|
|
31
|
+
if @word_spacing == 0 then @width
|
|
32
|
+
else @width + @word_spacing * @text.count(" ")
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def height
|
|
37
|
+
top - bottom
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def subscript?
|
|
41
|
+
styles.include?(:subscript)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def superscript?
|
|
45
|
+
styles.include?(:superscript)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def y_offset
|
|
49
|
+
if subscript? then -descender
|
|
50
|
+
elsif superscript? then 0.85 * ascender
|
|
51
|
+
else 0
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def bounding_box
|
|
56
|
+
[left, bottom, right, top]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def absolute_bounding_box
|
|
60
|
+
box = bounding_box
|
|
61
|
+
box[0] += @document.bounds.absolute_left
|
|
62
|
+
box[2] += @document.bounds.absolute_left
|
|
63
|
+
box[1] += @document.bounds.absolute_bottom
|
|
64
|
+
box[3] += @document.bounds.absolute_bottom
|
|
65
|
+
box
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def underline_points
|
|
69
|
+
y = baseline - 1.25
|
|
70
|
+
[[left, y], [right, y]]
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def strikethrough_points
|
|
74
|
+
y = baseline + ascender * 0.3
|
|
75
|
+
[[left, y], [right, y]]
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def styles
|
|
79
|
+
@format_state[:styles] || []
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def link
|
|
83
|
+
@format_state[:link]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def anchor
|
|
87
|
+
@format_state[:anchor]
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def color
|
|
91
|
+
@format_state[:color]
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def font
|
|
95
|
+
@format_state[:font]
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def size
|
|
99
|
+
@format_state[:size]
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def character_spacing
|
|
103
|
+
@format_state[:character_spacing] ||
|
|
104
|
+
@document.character_spacing
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def callback_objects
|
|
108
|
+
callback = @format_state[:callback]
|
|
109
|
+
if callback.nil?
|
|
110
|
+
[]
|
|
111
|
+
elsif callback.is_a?(Array)
|
|
112
|
+
callback
|
|
113
|
+
else
|
|
114
|
+
[callback]
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def right
|
|
119
|
+
left + width
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def top
|
|
123
|
+
baseline + ascender
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def bottom
|
|
127
|
+
baseline - descender
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def top_left
|
|
131
|
+
[left, top]
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def top_right
|
|
135
|
+
[right, top]
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def bottom_right
|
|
139
|
+
[right, bottom]
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def bottom_left
|
|
143
|
+
[left, bottom]
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def absolute_left
|
|
147
|
+
absolute_bounding_box[0]
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def absolute_right
|
|
151
|
+
absolute_bounding_box[2]
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def absolute_top
|
|
155
|
+
absolute_bounding_box[3]
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def absolute_bottom
|
|
159
|
+
absolute_bounding_box[1]
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def absolute_top_left
|
|
163
|
+
[absolute_left, absolute_top]
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def absolute_top_right
|
|
167
|
+
[absolute_right, absolute_top]
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def absolute_bottom_left
|
|
171
|
+
[absolute_left, absolute_bottom]
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def absolute_bottom_right
|
|
175
|
+
[absolute_right, absolute_bottom]
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
# text/formatted/parser.rb : Implements a bi-directional parser between a subset
|
|
4
|
+
# of html and formatted text arrays
|
|
5
|
+
#
|
|
6
|
+
# Copyright February 2010, Daniel Nelson. All Rights Reserved.
|
|
7
|
+
#
|
|
8
|
+
# This is free software. Please see the LICENSE and COPYING files for details.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
module Prawn
|
|
12
|
+
module Text
|
|
13
|
+
module Formatted
|
|
14
|
+
|
|
15
|
+
class Parser
|
|
16
|
+
|
|
17
|
+
def self.to_array(string)
|
|
18
|
+
regex_string = "\n|" +
|
|
19
|
+
"<b>|</b>|" +
|
|
20
|
+
"<i>|</i>|" +
|
|
21
|
+
"<u>|</u>|" +
|
|
22
|
+
"<strikethrough>|</strikethrough>|" +
|
|
23
|
+
"<sub>|</sub>|" +
|
|
24
|
+
"<sup>|</sup>|" +
|
|
25
|
+
"<link[^>]*>|</link>|" +
|
|
26
|
+
"<color[^>]*>|</color>|" +
|
|
27
|
+
"<font[^>]*>|</font>|" +
|
|
28
|
+
"<strong>|</strong>|" +
|
|
29
|
+
"<em>|</em>|" +
|
|
30
|
+
"<a[^>]*>|</a>|" +
|
|
31
|
+
"[^<\n]+"
|
|
32
|
+
regex = Regexp.new(regex_string, Regexp::MULTILINE)
|
|
33
|
+
tokens = string.scan(regex)
|
|
34
|
+
self.array_from_tokens(tokens)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.to_string(array)
|
|
38
|
+
prefixes = { :bold => "<b>",
|
|
39
|
+
:italic => "<i>",
|
|
40
|
+
:underline => "<u>",
|
|
41
|
+
:strikethrough => "<strikethrough>",
|
|
42
|
+
:subscript => "<sub>",
|
|
43
|
+
:superscript => "<sup>" }
|
|
44
|
+
suffixes = { :bold => "</b>",
|
|
45
|
+
:italic => "</i>",
|
|
46
|
+
:underline => "</u>",
|
|
47
|
+
:strikethrough => "</strikethrough>",
|
|
48
|
+
:subscript => "</sub>",
|
|
49
|
+
:superscript => "</sup>" }
|
|
50
|
+
array.collect do |hash|
|
|
51
|
+
prefix = ""
|
|
52
|
+
suffix = ""
|
|
53
|
+
if hash[:styles]
|
|
54
|
+
hash[:styles].each do |style|
|
|
55
|
+
prefix = prefix + prefixes[style]
|
|
56
|
+
suffix = suffixes[style] + suffix
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
font = hash[:font] ? " name='#{hash[:font]}'" : nil
|
|
61
|
+
size = hash[:size] ? " size='#{hash[:size]}'" : nil
|
|
62
|
+
if hash[:character_spacing]
|
|
63
|
+
character_spacing = " character_spacing='#{hash[:character_spacing]}'"
|
|
64
|
+
else
|
|
65
|
+
character_spacing = nil
|
|
66
|
+
end
|
|
67
|
+
if font || size || character_spacing
|
|
68
|
+
prefix = prefix + "<font#{font}#{size}#{character_spacing}>"
|
|
69
|
+
suffix = "</font>"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
link = hash[:link] ? " href='#{hash[:link]}'" : nil
|
|
73
|
+
anchor = hash[:anchor] ? " anchor='#{hash[:anchor]}'" : nil
|
|
74
|
+
if link || anchor
|
|
75
|
+
prefix = prefix + "<link#{link}#{anchor}>"
|
|
76
|
+
suffix = "</link>"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
if hash[:color]
|
|
80
|
+
if hash[:color].kind_of?(Array)
|
|
81
|
+
prefix = prefix + "<color c='#{hash[:color][0]}'" +
|
|
82
|
+
" m='#{hash[:color][1]}'" +
|
|
83
|
+
" y='#{hash[:color][2]}'" +
|
|
84
|
+
" k='#{hash[:color][3]}'>"
|
|
85
|
+
else
|
|
86
|
+
prefix = prefix + "<color rgb='#{hash[:color]}'>"
|
|
87
|
+
end
|
|
88
|
+
suffix = "</color>"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
string = hash[:text].gsub("&", "&").gsub(">", ">").gsub("<", "<")
|
|
92
|
+
prefix + string + suffix
|
|
93
|
+
end.join("")
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def self.array_paragraphs(array) #:nodoc:
|
|
97
|
+
paragraphs = []
|
|
98
|
+
paragraph = []
|
|
99
|
+
previous_string = "\n"
|
|
100
|
+
scan_pattern = /[^\n]+|\n/
|
|
101
|
+
array.each do |hash|
|
|
102
|
+
hash[:text].scan(scan_pattern).each do |string|
|
|
103
|
+
if string == "\n"
|
|
104
|
+
paragraph << hash.dup.merge(:text => "\n") if previous_string == "\n"
|
|
105
|
+
paragraphs << paragraph unless paragraph.empty?
|
|
106
|
+
paragraph = []
|
|
107
|
+
else
|
|
108
|
+
paragraph << hash.dup.merge(:text => string)
|
|
109
|
+
end
|
|
110
|
+
previous_string = string
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
paragraphs << paragraph unless paragraph.empty?
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
private
|
|
117
|
+
|
|
118
|
+
def self.array_from_tokens(tokens)
|
|
119
|
+
array = []
|
|
120
|
+
styles = []
|
|
121
|
+
colors = []
|
|
122
|
+
link = nil
|
|
123
|
+
anchor = nil
|
|
124
|
+
fonts = []
|
|
125
|
+
sizes = []
|
|
126
|
+
character_spacings = []
|
|
127
|
+
|
|
128
|
+
while token = tokens.shift
|
|
129
|
+
case token
|
|
130
|
+
when "<b>", "<strong>"
|
|
131
|
+
styles << :bold
|
|
132
|
+
when "<i>", "<em>"
|
|
133
|
+
styles << :italic
|
|
134
|
+
when "<u>"
|
|
135
|
+
styles << :underline
|
|
136
|
+
when "<strikethrough>"
|
|
137
|
+
styles << :strikethrough
|
|
138
|
+
when "<sub>"
|
|
139
|
+
styles << :subscript
|
|
140
|
+
when "<sup>"
|
|
141
|
+
styles << :superscript
|
|
142
|
+
when "</b>", "</strong>"
|
|
143
|
+
styles.delete(:bold)
|
|
144
|
+
when "</i>", "</em>"
|
|
145
|
+
styles.delete(:italic)
|
|
146
|
+
when "</u>"
|
|
147
|
+
styles.delete(:underline)
|
|
148
|
+
when "</strikethrough>"
|
|
149
|
+
styles.delete(:strikethrough)
|
|
150
|
+
when "</sub>"
|
|
151
|
+
styles.delete(:subscript)
|
|
152
|
+
when "</sup>"
|
|
153
|
+
styles.delete(:superscript)
|
|
154
|
+
when "</link>", "</a>"
|
|
155
|
+
link = nil
|
|
156
|
+
anchor = nil
|
|
157
|
+
when "</color>"
|
|
158
|
+
colors.pop
|
|
159
|
+
when "</font>"
|
|
160
|
+
fonts.pop
|
|
161
|
+
sizes.pop
|
|
162
|
+
character_spacings.pop
|
|
163
|
+
else
|
|
164
|
+
if token =~ /^<link[^>]*>$/ or token =~ /^<a[^>]*>$/
|
|
165
|
+
matches = /href="([^"]*)"/.match(token) || /href='([^']*)'/.match(token)
|
|
166
|
+
link = matches[1] unless matches.nil?
|
|
167
|
+
|
|
168
|
+
matches = /anchor="([^"]*)"/.match(token) || /anchor='([^']*)'/.match(token)
|
|
169
|
+
anchor = matches[1] unless matches.nil?
|
|
170
|
+
elsif token =~ /^<color[^>]*>$/
|
|
171
|
+
matches = /rgb="#?([^"]*)"/.match(token) || /rgb='#?([^']*)'/.match(token)
|
|
172
|
+
colors << matches[1] if matches
|
|
173
|
+
|
|
174
|
+
matches = /c="#?([^"]*)" +m="#?([^"]*)" +y="#?([^"]*)" +k="#?([^"]*)"/.match(token) ||
|
|
175
|
+
/c='#?([^']*)' +m='#?([^']*)' +y='#?([^']*)' +k='#?([^']*)'/.match(token)
|
|
176
|
+
colors << [matches[1].to_i, matches[2].to_i, matches[3].to_i, matches[4].to_i] if matches
|
|
177
|
+
|
|
178
|
+
# intend to support rgb="#ffffff" or rgb='#ffffff',
|
|
179
|
+
# r="255" g="255" b="255" or r='255' g='255' b='255',
|
|
180
|
+
# and c="100" m="100" y="100" k="100" or
|
|
181
|
+
# c='100' m='100' y='100' k='100'
|
|
182
|
+
# color = { :rgb => "#ffffff" }
|
|
183
|
+
# color = { :r => 255, :g => 255, :b => 255 }
|
|
184
|
+
# color = { :c => 100, :m => 100, :y => 100, :k => 100 }
|
|
185
|
+
elsif token =~ /^<font[^>]*>$/
|
|
186
|
+
matches = /name="([^"]*)"/.match(token) || /name='([^']*)'/.match(token)
|
|
187
|
+
fonts << matches[1] unless matches.nil?
|
|
188
|
+
|
|
189
|
+
matches = /size="([^"]*)"/.match(token) || /size='([^']*)'/.match(token)
|
|
190
|
+
sizes << matches[1].to_f unless matches.nil?
|
|
191
|
+
|
|
192
|
+
matches = /character_spacing="([^"]*)"/.match(token) || /character_spacing='([^']*)'/.match(token)
|
|
193
|
+
character_spacings << matches[1].to_f unless matches.nil?
|
|
194
|
+
else
|
|
195
|
+
string = token.gsub("<", "<").gsub(">", ">").gsub("&", "&")
|
|
196
|
+
array << { :text => string,
|
|
197
|
+
:styles => styles.dup,
|
|
198
|
+
:color => colors.last,
|
|
199
|
+
:link => link,
|
|
200
|
+
:anchor => anchor,
|
|
201
|
+
:font => fonts.last,
|
|
202
|
+
:size => sizes.last,
|
|
203
|
+
:character_spacing => character_spacings.last }
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
array
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
end
|