prawnx 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/COPYING +2 -0
- data/GPLv2 +339 -0
- data/GPLv3 +674 -0
- data/LICENSE +65 -0
- data/LICENSE-prawn-svg +21 -0
- data/README.md +107 -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/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/lib/pdf/core.rb +4 -0
- data/lib/prawn/measurement_extensions.rb +4 -0
- data/lib/prawn/svg/attributes/clip_path.rb +46 -0
- data/lib/prawn/svg/attributes/mask.rb +16 -0
- data/lib/prawn/svg/attributes/opacity.rb +30 -0
- data/lib/prawn/svg/attributes/space.rb +10 -0
- data/lib/prawn/svg/attributes/stroke.rb +50 -0
- data/lib/prawn/svg/attributes/transform.rb +10 -0
- data/lib/prawn/svg/attributes.rb +6 -0
- data/lib/prawn/svg/calculators/arc_to_bezier_curve.rb +57 -0
- data/lib/prawn/svg/calculators/aspect_ratio.rb +60 -0
- data/lib/prawn/svg/calculators/document_sizing.rb +103 -0
- data/lib/prawn/svg/calculators/path_length.rb +168 -0
- data/lib/prawn/svg/calculators/pixels.rb +57 -0
- data/lib/prawn/svg/color.rb +240 -0
- data/lib/prawn/svg/css/font_face_parser.rb +72 -0
- data/lib/prawn/svg/css/font_family_parser.rb +39 -0
- data/lib/prawn/svg/css/font_parser.rb +46 -0
- data/lib/prawn/svg/css/selector_parser.rb +178 -0
- data/lib/prawn/svg/css/stylesheets.rb +233 -0
- data/lib/prawn/svg/css/values_parser.rb +68 -0
- data/lib/prawn/svg/document.rb +170 -0
- data/lib/prawn/svg/elements/anchor.rb +10 -0
- data/lib/prawn/svg/elements/base.rb +312 -0
- data/lib/prawn/svg/elements/bbox_scaling.rb +78 -0
- data/lib/prawn/svg/elements/call_duplicator.rb +37 -0
- data/lib/prawn/svg/elements/circle.rb +25 -0
- data/lib/prawn/svg/elements/clip_path.rb +26 -0
- data/lib/prawn/svg/elements/container.rb +10 -0
- data/lib/prawn/svg/elements/direct_render_base.rb +27 -0
- data/lib/prawn/svg/elements/ellipse.rb +22 -0
- data/lib/prawn/svg/elements/gradient.rb +184 -0
- data/lib/prawn/svg/elements/ignored.rb +5 -0
- data/lib/prawn/svg/elements/image.rb +177 -0
- data/lib/prawn/svg/elements/line.rb +27 -0
- data/lib/prawn/svg/elements/marker.rb +72 -0
- data/lib/prawn/svg/elements/mask.rb +65 -0
- data/lib/prawn/svg/elements/path.rb +294 -0
- data/lib/prawn/svg/elements/pattern.rb +150 -0
- data/lib/prawn/svg/elements/polygon.rb +25 -0
- data/lib/prawn/svg/elements/polyline.rb +23 -0
- data/lib/prawn/svg/elements/rect.rb +64 -0
- data/lib/prawn/svg/elements/root.rb +22 -0
- data/lib/prawn/svg/elements/switch.rb +92 -0
- data/lib/prawn/svg/elements/text.rb +99 -0
- data/lib/prawn/svg/elements/text_component.rb +346 -0
- data/lib/prawn/svg/elements/text_node.rb +308 -0
- data/lib/prawn/svg/elements/text_path.rb +153 -0
- data/lib/prawn/svg/elements/use.rb +142 -0
- data/lib/prawn/svg/elements/viewport.rb +29 -0
- data/lib/prawn/svg/elements.rb +46 -0
- data/lib/prawn/svg/extension.rb +25 -0
- data/lib/prawn/svg/font.rb +20 -0
- data/lib/prawn/svg/font_metrics.rb +144 -0
- data/lib/prawn/svg/font_registry.rb +315 -0
- data/lib/prawn/svg/funciri.rb +14 -0
- data/lib/prawn/svg/gradient_renderer.rb +332 -0
- data/lib/prawn/svg/gradients.rb +53 -0
- data/lib/prawn/svg/interface.rb +72 -0
- data/lib/prawn/svg/length.rb +43 -0
- data/lib/prawn/svg/link_renderer.rb +40 -0
- data/lib/prawn/svg/loaders/data.rb +17 -0
- data/lib/prawn/svg/loaders/file.rb +111 -0
- data/lib/prawn/svg/loaders/web.rb +24 -0
- data/lib/prawn/svg/paint.rb +67 -0
- data/lib/prawn/svg/pathable.rb +153 -0
- data/lib/prawn/svg/pattern_renderer.rb +112 -0
- data/lib/prawn/svg/pdfmatrix.rb +37 -0
- data/lib/prawn/svg/percentage.rb +24 -0
- data/lib/prawn/svg/properties.rb +329 -0
- data/lib/prawn/svg/renderer.rb +249 -0
- data/lib/prawn/svg/state.rb +24 -0
- data/lib/prawn/svg/transform_parser.rb +78 -0
- data/lib/prawn/svg/ttc.rb +35 -0
- data/lib/prawn/svg/ttf.rb +95 -0
- data/lib/prawn/svg/url_loader.rb +46 -0
- data/lib/prawn/svg/version.rb +5 -0
- data/lib/prawn/table.rb +4 -0
- data/lib/prawn-svg.rb +53 -0
- data/lib/prawn.rb +10 -0
- data/lib/prawnx/annotations.rb +21 -0
- data/lib/prawnx/document/bounding_box.rb +193 -0
- data/lib/prawnx/document/column_box.rb +91 -0
- data/lib/prawnx/document/internals.rb +144 -0
- data/lib/prawnx/document/span.rb +25 -0
- data/lib/prawnx/document.rb +253 -0
- data/lib/prawnx/encoding.rb +29 -0
- data/lib/prawnx/errors.rb +37 -0
- data/lib/prawnx/font.rb +214 -0
- data/lib/prawnx/fonts/afm.rb +171 -0
- data/lib/prawnx/fonts/otf.rb +50 -0
- data/lib/prawnx/fonts/ttf.rb +410 -0
- data/lib/prawnx/graphic_state.rb +41 -0
- data/lib/prawnx/graphics/color.rb +148 -0
- data/lib/prawnx/graphics/patterns.rb +100 -0
- data/lib/prawnx/graphics/style.rb +171 -0
- data/lib/prawnx/graphics.rb +208 -0
- data/lib/prawnx/grid.rb +216 -0
- data/lib/prawnx/images/image.rb +244 -0
- data/lib/prawnx/images/png_decoder.rb +65 -0
- data/lib/prawnx/images.rb +115 -0
- data/lib/prawnx/measurement_extensions.rb +40 -0
- data/lib/prawnx/measurements.rb +62 -0
- data/lib/prawnx/outline.rb +146 -0
- data/lib/prawnx/page.rb +125 -0
- data/lib/prawnx/page_geometry.rb +27 -0
- data/lib/prawnx/pdf/outline_node.rb +53 -0
- data/lib/prawnx/pdf/reference.rb +31 -0
- data/lib/prawnx/pdf/writer.rb +105 -0
- data/lib/prawnx/pdf.rb +66 -0
- data/lib/prawnx/pdf_a/srgb_profile.rb +61 -0
- data/lib/prawnx/pdf_a.rb +130 -0
- data/lib/prawnx/pdf_core.rb +25 -0
- data/lib/prawnx/repeater.rb +79 -0
- data/lib/prawnx/security.rb +108 -0
- data/lib/prawnx/stamp.rb +74 -0
- data/lib/prawnx/table/cell/kinds.rb +246 -0
- data/lib/prawnx/table/cell.rb +331 -0
- data/lib/prawnx/table/cells.rb +208 -0
- data/lib/prawnx/table.rb +296 -0
- data/lib/prawnx/text/box.rb +16 -0
- data/lib/prawnx/text/formatted/arranger.rb +217 -0
- data/lib/prawnx/text/formatted/box.rb +312 -0
- data/lib/prawnx/text/formatted/fragment.rb +205 -0
- data/lib/prawnx/text/formatted/line_wrap.rb +204 -0
- data/lib/prawnx/text/formatted/parser.rb +149 -0
- data/lib/prawnx/text/formatted/wrap.rb +103 -0
- data/lib/prawnx/text.rb +281 -0
- data/lib/prawnx/transformation_stack.rb +43 -0
- data/lib/prawnx/true_type/cff_subset.rb +157 -0
- data/lib/prawnx/true_type/file.rb +371 -0
- data/lib/prawnx/true_type/open_type_layout.rb +189 -0
- data/lib/prawnx/true_type/simple_subsets.rb +94 -0
- data/lib/prawnx/true_type/subset.rb +187 -0
- data/lib/prawnx/version.rb +7 -0
- data/lib/prawnx/view.rb +28 -0
- data/lib/prawnx.rb +102 -0
- metadata +251 -0
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
class Prawn::SVG::Elements::Base
|
|
2
|
+
extend Forwardable
|
|
3
|
+
|
|
4
|
+
include Prawn::SVG::Elements::CallDuplicator
|
|
5
|
+
include Prawn::SVG::Elements::BboxScaling
|
|
6
|
+
|
|
7
|
+
include Prawn::SVG::Calculators::Pixels
|
|
8
|
+
|
|
9
|
+
include Prawn::SVG::Attributes::Transform
|
|
10
|
+
include Prawn::SVG::Attributes::Opacity
|
|
11
|
+
include Prawn::SVG::Attributes::ClipPath
|
|
12
|
+
include Prawn::SVG::Attributes::Mask
|
|
13
|
+
include Prawn::SVG::Attributes::Stroke
|
|
14
|
+
include Prawn::SVG::Attributes::Space
|
|
15
|
+
|
|
16
|
+
include Prawn::SVG::TransformParser
|
|
17
|
+
|
|
18
|
+
PAINT_TYPES = %w[fill stroke].freeze
|
|
19
|
+
COMMA_WSP_REGEXP = Prawn::SVG::Elements::COMMA_WSP_REGEXP
|
|
20
|
+
SVG_NAMESPACE = 'http://www.w3.org/2000/svg'.freeze
|
|
21
|
+
|
|
22
|
+
SkipElementQuietly = Class.new(StandardError)
|
|
23
|
+
SkipElementError = Class.new(StandardError)
|
|
24
|
+
MissingAttributesError = Class.new(SkipElementError)
|
|
25
|
+
|
|
26
|
+
attr_reader :document, :source, :parent_calls, :base_calls, :state, :attributes, :properties
|
|
27
|
+
attr_accessor :calls
|
|
28
|
+
|
|
29
|
+
def_delegators :@document, :warnings
|
|
30
|
+
def_delegator :@state, :computed_properties
|
|
31
|
+
|
|
32
|
+
def initialize(document, source, parent_calls, state)
|
|
33
|
+
@document = document
|
|
34
|
+
@source = source
|
|
35
|
+
@parent_calls = parent_calls
|
|
36
|
+
@state = state
|
|
37
|
+
@base_calls = @calls = []
|
|
38
|
+
@attributes = {}
|
|
39
|
+
@properties = Prawn::SVG::Properties.new
|
|
40
|
+
|
|
41
|
+
if source && add_to_elements_by_id? && !state.inside_use
|
|
42
|
+
id = source.attributes['id']
|
|
43
|
+
id = id.strip if id
|
|
44
|
+
|
|
45
|
+
document.elements_by_id[id] = self if id && id != ''
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def process
|
|
50
|
+
extract_attributes_and_properties
|
|
51
|
+
parse_and_apply
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def parse_and_apply
|
|
55
|
+
parse_standard_attributes
|
|
56
|
+
parse
|
|
57
|
+
|
|
58
|
+
apply_calls_from_standard_attributes
|
|
59
|
+
apply
|
|
60
|
+
|
|
61
|
+
if state.anchor_href && bounding_box
|
|
62
|
+
add_call('svg:add_link', state.anchor_href, bounding_box)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
process_child_elements if container?
|
|
66
|
+
|
|
67
|
+
append_calls_to_parent unless computed_properties.display == 'none'
|
|
68
|
+
rescue SkipElementQuietly
|
|
69
|
+
rescue SkipElementError => e
|
|
70
|
+
@document.warnings << e.message
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def name
|
|
74
|
+
@name ||= source ? source.name : '???'
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
protected
|
|
78
|
+
|
|
79
|
+
def parse; end
|
|
80
|
+
|
|
81
|
+
def apply; end
|
|
82
|
+
|
|
83
|
+
def bounding_box; end
|
|
84
|
+
|
|
85
|
+
def container?
|
|
86
|
+
false
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def drawable?
|
|
90
|
+
!container?
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def parse_standard_attributes
|
|
94
|
+
parse_xml_space_attribute
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def add_call(name, *arguments, **kwarguments)
|
|
98
|
+
@calls << [name.to_s, arguments, kwarguments, []]
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def add_call_and_enter(name, *arguments, **kwarguments)
|
|
102
|
+
@calls << [name.to_s, arguments, kwarguments, []]
|
|
103
|
+
@calls = @calls.last.last
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def push_call_position
|
|
107
|
+
@call_positions ||= []
|
|
108
|
+
@call_positions << @calls
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def pop_call_position
|
|
112
|
+
@calls = @call_positions.pop
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def append_calls_to_parent
|
|
116
|
+
@parent_calls.concat(@base_calls)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def add_calls_from_element(other)
|
|
120
|
+
@calls.concat duplicate_calls(other.base_calls)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def add_yield_call(&block)
|
|
124
|
+
add_call('svg:yield', block)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def new_call_context_from_base
|
|
128
|
+
old_calls = @calls
|
|
129
|
+
@calls = @base_calls
|
|
130
|
+
yield
|
|
131
|
+
@calls = old_calls
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def process_child_elements
|
|
135
|
+
return unless source
|
|
136
|
+
|
|
137
|
+
svg_child_elements.each do |elem|
|
|
138
|
+
if (element_class = Prawn::SVG::Elements::TAG_CLASS_MAPPING[elem.name.to_sym])
|
|
139
|
+
add_call 'save'
|
|
140
|
+
|
|
141
|
+
child = element_class.new(@document, elem, @calls, state.dup)
|
|
142
|
+
child.process
|
|
143
|
+
|
|
144
|
+
add_call 'restore'
|
|
145
|
+
else
|
|
146
|
+
@document.warnings << "Unknown tag '#{elem.name}'; ignoring"
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def svg_child_elements
|
|
152
|
+
source.elements.select do |elem|
|
|
153
|
+
# To be strict, we shouldn't treat namespace-less elements as SVG, but for
|
|
154
|
+
# backwards compatibility, and because it doesn't hurt, we will.
|
|
155
|
+
[SVG_NAMESPACE, ''].include?(elem.namespace)
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def apply_calls_from_standard_attributes
|
|
160
|
+
parse_transform_attribute_and_call
|
|
161
|
+
parse_opacity_attributes_and_call
|
|
162
|
+
parse_clip_path_attribute_and_call
|
|
163
|
+
parse_mask_attribute_and_call
|
|
164
|
+
apply_colors
|
|
165
|
+
parse_stroke_attributes_and_call
|
|
166
|
+
apply_drawing_call
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def apply_drawing_call
|
|
170
|
+
return if state.disable_drawing || !drawable?
|
|
171
|
+
|
|
172
|
+
fill = !computed_properties.fill.none? # rubocop:disable Style/InverseMethods
|
|
173
|
+
stroke = !computed_properties.stroke.none? # rubocop:disable Style/InverseMethods
|
|
174
|
+
|
|
175
|
+
if fill
|
|
176
|
+
command = stroke ? 'fill_and_stroke' : 'fill'
|
|
177
|
+
|
|
178
|
+
if computed_properties.fill_rule == 'evenodd'
|
|
179
|
+
add_call_and_enter(command, fill_rule: :even_odd)
|
|
180
|
+
else
|
|
181
|
+
add_call_and_enter(command)
|
|
182
|
+
end
|
|
183
|
+
elsif stroke
|
|
184
|
+
add_call_and_enter('stroke')
|
|
185
|
+
else
|
|
186
|
+
add_call_and_enter('end_path')
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def apply_colors
|
|
191
|
+
PAINT_TYPES.each do |type|
|
|
192
|
+
paint = properties.send(type)
|
|
193
|
+
|
|
194
|
+
case paint
|
|
195
|
+
when nil, 'inherit'
|
|
196
|
+
next
|
|
197
|
+
when Prawn::SVG::Paint
|
|
198
|
+
color = paint.resolve(document.gradients, computed_properties.color, document.color_mode)
|
|
199
|
+
|
|
200
|
+
case color
|
|
201
|
+
when Prawn::SVG::Color::RGB, Prawn::SVG::Color::CMYK
|
|
202
|
+
add_call "#{type}_color", color.value
|
|
203
|
+
when Prawn::SVG::Elements::Gradient
|
|
204
|
+
add_call 'svg:render_gradient', type.to_sym, **color.gradient_arguments(self)
|
|
205
|
+
when Prawn::SVG::Elements::Pattern
|
|
206
|
+
args = color.pattern_arguments(self)
|
|
207
|
+
add_call 'svg:render_pattern', type.to_sym, **args if args
|
|
208
|
+
when nil
|
|
209
|
+
nil
|
|
210
|
+
else
|
|
211
|
+
raise "Unknown resolved color type: #{color.inspect}"
|
|
212
|
+
end
|
|
213
|
+
else
|
|
214
|
+
raise "Unknown paint type: #{paint.inspect}"
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def extract_attributes_and_properties
|
|
220
|
+
# Apply user agent stylesheet
|
|
221
|
+
if %w[svg symbol image marker pattern foreignObject].include?(source.name)
|
|
222
|
+
@properties.set('overflow', 'hidden')
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Apply presentation attributes, and set attributes that aren't presentation attributes
|
|
226
|
+
source.attributes.each do |name, value|
|
|
227
|
+
# Properties#set returns nil if it's not a recognised property name
|
|
228
|
+
@properties.set(name, value) or @attributes[name] = value
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# Apply stylesheet styles
|
|
232
|
+
if (styles = document.element_styles[source])
|
|
233
|
+
styles.each do |name, value, important|
|
|
234
|
+
@properties.set(name, value, important: important)
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# Apply inline styles
|
|
239
|
+
@properties.load_hash(parse_css_declarations(source.attributes['style'] || ''))
|
|
240
|
+
|
|
241
|
+
state.computed_properties.compute_properties(@properties)
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
def parse_css_declarations(declarations)
|
|
245
|
+
# copied from css_parser
|
|
246
|
+
declarations
|
|
247
|
+
.gsub(/(^\s*)|(\s*$)/, '')
|
|
248
|
+
.split(/[;$]+/m)
|
|
249
|
+
.each_with_object({}) do |decs, output|
|
|
250
|
+
if (matches = decs.match(/\s*(.[^:]*)\s*:\s*(.[^;]*)\s*(;|\Z)/i))
|
|
251
|
+
property, value, = matches.captures
|
|
252
|
+
output[property.downcase] = value
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def require_attributes(*names)
|
|
258
|
+
missing_attrs = names - attributes.keys
|
|
259
|
+
if missing_attrs.any?
|
|
260
|
+
raise MissingAttributesError, "Must have attributes #{missing_attrs.join(', ')} on tag #{name}; skipping tag"
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def require_positive_value(*args)
|
|
265
|
+
if args.any? { |arg| arg.nil? || arg <= 0 }
|
|
266
|
+
raise SkipElementError, "Invalid attributes on tag #{name}; skipping tag"
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def extract_element_from_url_id_reference(value, expected_type = nil)
|
|
271
|
+
case value
|
|
272
|
+
when Prawn::SVG::FuncIRI
|
|
273
|
+
element = document.elements_by_id[value.url[1..]] if value.url.start_with?('#')
|
|
274
|
+
element if element && (expected_type.nil? || element.name == expected_type)
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def href_attribute
|
|
279
|
+
attributes['xlink:href'] || attributes['href']
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
def overflow_hidden?
|
|
283
|
+
['hidden', 'scroll'].include?(computed_properties.overflow)
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
def transformable?
|
|
287
|
+
true
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
def add_to_elements_by_id?
|
|
291
|
+
true
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
def stroke_width
|
|
295
|
+
if computed_properties.stroke.none?
|
|
296
|
+
0
|
|
297
|
+
else
|
|
298
|
+
pixels(properties.stroke_width) || 1.0
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
def clone_element_source(source)
|
|
303
|
+
new_source = source.dup
|
|
304
|
+
document.element_styles[new_source] = document.element_styles[source]
|
|
305
|
+
new_source
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def set_display_none
|
|
309
|
+
properties.display = 'none'
|
|
310
|
+
computed_properties.display = 'none'
|
|
311
|
+
end
|
|
312
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
module Prawn::SVG::Elements::BboxScaling
|
|
2
|
+
private
|
|
3
|
+
|
|
4
|
+
def build_object_bounding_box_calls(bbox, source_element = source)
|
|
5
|
+
bbox_left = bbox[0]
|
|
6
|
+
bbox_top = bbox[1]
|
|
7
|
+
bbox_right = bbox[2]
|
|
8
|
+
bbox_bottom = bbox[3]
|
|
9
|
+
bbox_w = bbox_right - bbox_left
|
|
10
|
+
bbox_h = bbox_top - bbox_bottom
|
|
11
|
+
|
|
12
|
+
unit_sizing = Prawn::SVG::Calculators::DocumentSizing.new([1, 1])
|
|
13
|
+
unit_sizing.document_width = 1
|
|
14
|
+
unit_sizing.document_height = 1
|
|
15
|
+
unit_sizing.calculate
|
|
16
|
+
|
|
17
|
+
result_calls = document.with_sizing(unit_sizing) do
|
|
18
|
+
new_state = state.dup
|
|
19
|
+
new_state.viewport_sizing = unit_sizing
|
|
20
|
+
new_state.inside_use = true
|
|
21
|
+
|
|
22
|
+
container = Prawn::SVG::Elements::Container.new(document, source_element, [], new_state)
|
|
23
|
+
container.process
|
|
24
|
+
|
|
25
|
+
container.base_calls
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
scale_calls_to_bbox(duplicate_calls(result_calls), bbox_left, bbox_top, bbox_w, bbox_h)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def scale_calls_to_bbox(calls, bbox_left, bbox_top, bbox_w, bbox_h)
|
|
32
|
+
calls.map do |name, args, kwargs, children|
|
|
33
|
+
new_args = case name
|
|
34
|
+
when 'rectangle'
|
|
35
|
+
point, width, height = args
|
|
36
|
+
[scale_point(point, bbox_left, bbox_top, bbox_w, bbox_h), width * bbox_w, height * bbox_h]
|
|
37
|
+
when 'rounded_rectangle'
|
|
38
|
+
point, width, height, radius = args
|
|
39
|
+
[scale_point(point, bbox_left, bbox_top, bbox_w, bbox_h), width * bbox_w, height * bbox_h, radius * bbox_w]
|
|
40
|
+
when 'move_to', 'line_to'
|
|
41
|
+
[scale_point(args[0], bbox_left, bbox_top, bbox_w, bbox_h)]
|
|
42
|
+
when 'circle'
|
|
43
|
+
point, radius = args
|
|
44
|
+
scaled_point = scale_point(point, bbox_left, bbox_top, bbox_w, bbox_h)
|
|
45
|
+
if bbox_w == bbox_h
|
|
46
|
+
[scaled_point, radius * bbox_w]
|
|
47
|
+
else
|
|
48
|
+
new_children = children.any? ? scale_calls_to_bbox(children, bbox_left, bbox_top, bbox_w, bbox_h) : children
|
|
49
|
+
next ['ellipse', [scaled_point, radius * bbox_w, radius * bbox_h], kwargs, new_children]
|
|
50
|
+
end
|
|
51
|
+
when 'ellipse'
|
|
52
|
+
point, rx, ry = args
|
|
53
|
+
[scale_point(point, bbox_left, bbox_top, bbox_w, bbox_h), rx * bbox_w, ry * bbox_h]
|
|
54
|
+
when 'curve_to'
|
|
55
|
+
dest = scale_point(args[0], bbox_left, bbox_top, bbox_w, bbox_h)
|
|
56
|
+
[dest]
|
|
57
|
+
else
|
|
58
|
+
args
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
new_kwargs = if name == 'curve_to' && kwargs[:bounds]
|
|
62
|
+
b = kwargs[:bounds]
|
|
63
|
+
{ bounds: b.map { |p| scale_point(p, bbox_left, bbox_top, bbox_w, bbox_h) } }
|
|
64
|
+
else
|
|
65
|
+
kwargs
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
new_children = children.any? ? scale_calls_to_bbox(children, bbox_left, bbox_top, bbox_w, bbox_h) : children
|
|
69
|
+
[name, new_args, new_kwargs, new_children]
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def scale_point(point, bbox_left, bbox_top, bbox_w, bbox_h)
|
|
74
|
+
x = bbox_left + (point[0] * bbox_w)
|
|
75
|
+
y = bbox_top - ((1.0 - point[1]) * bbox_h)
|
|
76
|
+
[x, y]
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Unfortunately, prawn mutates arguments passed in to it.
|
|
3
|
+
# When we make a copy of one of the call stacks, we need to make a deep
|
|
4
|
+
# duplicate of it so that the first time prawn mutates the arguments, it
|
|
5
|
+
# won't affect the subsequent calls.
|
|
6
|
+
#
|
|
7
|
+
module Prawn::SVG::Elements::CallDuplicator
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def duplicate_calls(calls)
|
|
11
|
+
calls.map { |call| duplicate_call(call) }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def duplicate_call(call)
|
|
15
|
+
[call[0], duplicate_array(call[1]), duplicate_hash(call[2]), duplicate_calls(call[3])]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def duplicate_array(array)
|
|
19
|
+
array.map do |value|
|
|
20
|
+
case value
|
|
21
|
+
when Array then duplicate_array(value)
|
|
22
|
+
when Hash then duplicate_hash(value)
|
|
23
|
+
else value
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def duplicate_hash(hash)
|
|
29
|
+
hash.each.with_object({}) do |(key, value), result|
|
|
30
|
+
result[key] = case value
|
|
31
|
+
when Array then duplicate_array(value)
|
|
32
|
+
when Hash then duplicate_hash(value)
|
|
33
|
+
else value
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
class Prawn::SVG::Elements::Circle < Prawn::SVG::Elements::Base
|
|
2
|
+
USE_NEW_CIRCLE_CALL = Prawn::Document.instance_methods.include?(:circle)
|
|
3
|
+
|
|
4
|
+
def parse
|
|
5
|
+
require_attributes 'r'
|
|
6
|
+
|
|
7
|
+
@x = x(attributes['cx'] || '0')
|
|
8
|
+
@y = y(attributes['cy'] || '0')
|
|
9
|
+
@r = pixels(attributes['r'])
|
|
10
|
+
|
|
11
|
+
require_positive_value @r
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def apply
|
|
15
|
+
if USE_NEW_CIRCLE_CALL
|
|
16
|
+
add_call 'circle', [@x, @y], @r
|
|
17
|
+
else
|
|
18
|
+
add_call 'circle_at', [@x, @y], radius: @r
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def bounding_box
|
|
23
|
+
[@x - @r, @y + @r, @x + @r, @y - @r]
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
class Prawn::SVG::Elements::ClipPath < Prawn::SVG::Elements::Base
|
|
2
|
+
def parse
|
|
3
|
+
state.inside_clip_path = true
|
|
4
|
+
set_display_none
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def container?
|
|
8
|
+
true
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def build_clip_calls(element)
|
|
12
|
+
units = attributes['clipPathUnits'] || 'userSpaceOnUse'
|
|
13
|
+
|
|
14
|
+
if units == 'objectBoundingBox'
|
|
15
|
+
bbox = element.bounding_box
|
|
16
|
+
if bbox.nil?
|
|
17
|
+
document.warnings << 'clipPath with clipPathUnits="objectBoundingBox" requires element to have a bounding box'
|
|
18
|
+
return nil
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
build_object_bounding_box_calls(bbox)
|
|
22
|
+
else
|
|
23
|
+
duplicate_calls(base_calls)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#
|
|
2
|
+
# This element base class is used for elements that render directly to the Prawn canvas.
|
|
3
|
+
#
|
|
4
|
+
# Initially when I wrote prawn-svg, I was expecting to have multiple renderers and thought separating the codebase
|
|
5
|
+
# from the Prawn renderer would be a good idea. However, it turns out that the Prawn renderer was the only one
|
|
6
|
+
# that was targeted, and it ended up being tightly coupled with the Prawn library.
|
|
7
|
+
#
|
|
8
|
+
# This class is probably how I should have written it. Direct render is required to do text rendering properly
|
|
9
|
+
# because we need to know the width of all the things we print. As of the time of this comment it's the only
|
|
10
|
+
# system that uses DirectRenderBase in prawn-svg.
|
|
11
|
+
#
|
|
12
|
+
class Prawn::SVG::Elements::DirectRenderBase < Prawn::SVG::Elements::Base
|
|
13
|
+
# Called by Renderer when it finds the svg:render call added below.
|
|
14
|
+
def render(prawn, renderer); end
|
|
15
|
+
|
|
16
|
+
protected
|
|
17
|
+
|
|
18
|
+
def parse_and_apply
|
|
19
|
+
parse_standard_attributes
|
|
20
|
+
parse
|
|
21
|
+
apply_calls_from_standard_attributes
|
|
22
|
+
@parent_calls << ['svg:render', [self], [], []] unless computed_properties.display == 'none'
|
|
23
|
+
rescue SkipElementQuietly
|
|
24
|
+
rescue SkipElementError => e
|
|
25
|
+
@document.warnings << e.message
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
class Prawn::SVG::Elements::Ellipse < Prawn::SVG::Elements::Base
|
|
2
|
+
USE_NEW_ELLIPSE_CALL = Prawn::Document.instance_methods.include?(:ellipse)
|
|
3
|
+
|
|
4
|
+
def parse
|
|
5
|
+
require_attributes 'rx', 'ry'
|
|
6
|
+
|
|
7
|
+
@x = x(attributes['cx'] || '0')
|
|
8
|
+
@y = y(attributes['cy'] || '0')
|
|
9
|
+
@rx = x_pixels(attributes['rx'])
|
|
10
|
+
@ry = y_pixels(attributes['ry'])
|
|
11
|
+
|
|
12
|
+
require_positive_value @rx, @ry
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def apply
|
|
16
|
+
add_call USE_NEW_ELLIPSE_CALL ? 'ellipse' : 'ellipse_at', [@x, @y], @rx, @ry
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def bounding_box
|
|
20
|
+
[@x - @rx, @y + @ry, @x + @rx, @y - @ry]
|
|
21
|
+
end
|
|
22
|
+
end
|