prawn-svg 0.34.2 → 0.35.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/lint.yml +19 -0
- data/.github/workflows/test.yml +14 -27
- data/.gitignore +0 -1
- data/.rubocop.yml +86 -0
- data/.rubocop_todo.yml +51 -0
- data/Gemfile +4 -3
- data/Gemfile.lock +81 -0
- data/README.md +1 -1
- data/Rakefile +1 -1
- data/lib/prawn/svg/attributes/clip_path.rb +3 -3
- data/lib/prawn/svg/attributes/opacity.rb +3 -3
- data/lib/prawn/svg/attributes/stroke.rb +9 -9
- data/lib/prawn/svg/attributes/transform.rb +2 -2
- data/lib/prawn/svg/attributes.rb +1 -1
- data/lib/prawn/svg/calculators/arc_to_bezier_curve.rb +17 -15
- data/lib/prawn/svg/calculators/aspect_ratio.rb +16 -14
- data/lib/prawn/svg/calculators/document_sizing.rb +9 -10
- data/lib/prawn/svg/calculators/pixels.rb +8 -5
- data/lib/prawn/svg/color.rb +209 -212
- data/lib/prawn/svg/css/font_family_parser.rb +2 -2
- data/lib/prawn/svg/css/selector_parser.rb +39 -35
- data/lib/prawn/svg/css/stylesheets.rb +24 -24
- data/lib/prawn/svg/css/values_parser.rb +68 -0
- data/lib/prawn/svg/document.rb +6 -5
- data/lib/prawn/svg/elements/base.rb +29 -34
- data/lib/prawn/svg/elements/circle.rb +4 -4
- data/lib/prawn/svg/elements/clip_path.rb +0 -1
- data/lib/prawn/svg/elements/depth_first_base.rb +6 -6
- data/lib/prawn/svg/elements/ellipse.rb +3 -4
- data/lib/prawn/svg/elements/gradient.rb +49 -51
- data/lib/prawn/svg/elements/image.rb +5 -5
- data/lib/prawn/svg/elements/marker.rb +5 -5
- data/lib/prawn/svg/elements/path.rb +46 -47
- data/lib/prawn/svg/elements/polygon.rb +1 -1
- data/lib/prawn/svg/elements/polyline.rb +2 -2
- data/lib/prawn/svg/elements/rect.rb +3 -3
- data/lib/prawn/svg/elements/text.rb +1 -1
- data/lib/prawn/svg/elements/text_component.rb +22 -22
- data/lib/prawn/svg/elements/use.rb +3 -7
- data/lib/prawn/svg/elements/viewport.rb +1 -3
- data/lib/prawn/svg/elements.rb +30 -29
- data/lib/prawn/svg/extension.rb +2 -1
- data/lib/prawn/svg/font.rb +7 -7
- data/lib/prawn/svg/font_registry.rb +13 -13
- data/lib/prawn/svg/gradients.rb +3 -2
- data/lib/prawn/svg/interface.rb +4 -3
- data/lib/prawn/svg/loaders/data.rb +2 -2
- data/lib/prawn/svg/loaders/file.rb +12 -14
- data/lib/prawn/svg/loaders/web.rb +4 -8
- data/lib/prawn/svg/pathable.rb +41 -37
- data/lib/prawn/svg/properties.rb +34 -33
- data/lib/prawn/svg/renderer.rb +7 -7
- data/lib/prawn/svg/state.rb +1 -1
- data/lib/prawn/svg/transform_parser.rb +5 -5
- data/lib/prawn/svg/ttf.rb +21 -17
- data/lib/prawn/svg/url_loader.rb +1 -1
- data/lib/prawn/svg/version.rb +1 -1
- data/lib/prawn-svg.rb +1 -0
- data/prawn-svg.gemspec +5 -7
- data/spec/integration_spec.rb +77 -70
- data/spec/prawn/svg/attributes/opacity_spec.rb +11 -15
- data/spec/prawn/svg/attributes/transform_spec.rb +6 -6
- data/spec/prawn/svg/calculators/aspect_ratio_spec.rb +50 -50
- data/spec/prawn/svg/calculators/document_sizing_spec.rb +35 -35
- data/spec/prawn/svg/calculators/pixels_spec.rb +31 -30
- data/spec/prawn/svg/color_spec.rb +31 -31
- data/spec/prawn/svg/css/font_family_parser_spec.rb +12 -12
- data/spec/prawn/svg/css/selector_parser_spec.rb +21 -21
- data/spec/prawn/svg/css/stylesheets_spec.rb +51 -45
- data/spec/prawn/svg/css/values_parser_spec.rb +16 -0
- data/spec/prawn/svg/document_spec.rb +15 -14
- data/spec/prawn/svg/elements/base_spec.rb +39 -34
- data/spec/prawn/svg/elements/gradient_spec.rb +39 -39
- data/spec/prawn/svg/elements/line_spec.rb +22 -22
- data/spec/prawn/svg/elements/marker_spec.rb +36 -40
- data/spec/prawn/svg/elements/path_spec.rb +134 -110
- data/spec/prawn/svg/elements/polygon_spec.rb +18 -18
- data/spec/prawn/svg/elements/polyline_spec.rb +16 -16
- data/spec/prawn/svg/elements/text_spec.rb +149 -127
- data/spec/prawn/svg/font_registry_spec.rb +34 -34
- data/spec/prawn/svg/font_spec.rb +4 -4
- data/spec/prawn/svg/interface_spec.rb +47 -39
- data/spec/prawn/svg/loaders/data_spec.rb +21 -21
- data/spec/prawn/svg/loaders/file_spec.rb +43 -40
- data/spec/prawn/svg/loaders/web_spec.rb +15 -15
- data/spec/prawn/svg/pathable_spec.rb +21 -21
- data/spec/prawn/svg/properties_spec.rb +51 -51
- data/spec/prawn/svg/transform_parser_spec.rb +12 -12
- data/spec/prawn/svg/ttf_spec.rb +5 -5
- data/spec/prawn/svg/url_loader_spec.rb +25 -23
- data/spec/spec_helper.rb +4 -4
- metadata +21 -146
@@ -9,7 +9,7 @@ class Prawn::SVG::Elements::Use < Prawn::SVG::Elements::Base
|
|
9
9
|
raise SkipElementError, 'use tag has an href that is not a reference to an id; this is not supported'
|
10
10
|
end
|
11
11
|
|
12
|
-
id = href[1
|
12
|
+
id = href[1..]
|
13
13
|
referenced_element = @document.elements_by_id[id]
|
14
14
|
|
15
15
|
if referenced_element
|
@@ -28,9 +28,7 @@ class Prawn::SVG::Elements::Use < Prawn::SVG::Elements::Base
|
|
28
28
|
|
29
29
|
raise SkipElementError, "no tag with ID '#{id}' was found, referenced by use tag" if referenced_element_class.nil?
|
30
30
|
|
31
|
-
if referenced_element_source.name == 'symbol'
|
32
|
-
@referenced_element_class = Prawn::SVG::Elements::Viewport
|
33
|
-
end
|
31
|
+
@referenced_element_class = Prawn::SVG::Elements::Viewport if referenced_element_source.name == 'symbol'
|
34
32
|
|
35
33
|
state.inside_use = true
|
36
34
|
|
@@ -45,9 +43,7 @@ class Prawn::SVG::Elements::Use < Prawn::SVG::Elements::Base
|
|
45
43
|
end
|
46
44
|
|
47
45
|
def apply
|
48
|
-
if @x || @y
|
49
|
-
add_call_and_enter 'translate', x_pixels(@x || 0), -y_pixels(@y || 0)
|
50
|
-
end
|
46
|
+
add_call_and_enter 'translate', x_pixels(@x || 0), -y_pixels(@y || 0) if @x || @y
|
51
47
|
end
|
52
48
|
|
53
49
|
def process_child_elements
|
@@ -12,9 +12,7 @@ class Prawn::SVG::Elements::Viewport < Prawn::SVG::Elements::Base
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def apply
|
15
|
-
if @x != 0 || @y != 0
|
16
|
-
add_call 'transformation_matrix', 1, 0, 0, 1, @x, -@y
|
17
|
-
end
|
15
|
+
add_call 'transformation_matrix', 1, 0, 0, 1, @x, -@y if @x != 0 || @y != 0
|
18
16
|
|
19
17
|
if overflow_hidden?
|
20
18
|
add_call 'rectangle', [0, y(0)], @sizing.output_width, @sizing.output_height
|
data/lib/prawn/svg/elements.rb
CHANGED
@@ -1,42 +1,43 @@
|
|
1
1
|
module Prawn::SVG::Elements
|
2
|
-
COMMA_WSP_REGEXP = /(?:\s+,?\s*|,\s*)
|
2
|
+
COMMA_WSP_REGEXP = /(?:\s+,?\s*|,\s*)/.freeze
|
3
3
|
end
|
4
4
|
|
5
5
|
require 'prawn/svg/elements/call_duplicator'
|
6
6
|
|
7
|
-
%w
|
7
|
+
%w[base depth_first_base root container clip_path viewport text text_component line polyline polygon circle ellipse
|
8
|
+
rect path use image gradient marker ignored].each do |filename|
|
8
9
|
require "prawn/svg/elements/#{filename}"
|
9
10
|
end
|
10
11
|
|
11
12
|
module Prawn::SVG::Elements
|
12
13
|
TAG_CLASS_MAPPING = {
|
13
|
-
g:
|
14
|
-
symbol:
|
15
|
-
defs:
|
16
|
-
a:
|
17
|
-
clipPath:
|
18
|
-
switch:
|
19
|
-
svg:
|
20
|
-
text:
|
21
|
-
line:
|
22
|
-
polyline:
|
23
|
-
polygon:
|
24
|
-
circle:
|
25
|
-
ellipse:
|
26
|
-
rect:
|
27
|
-
path:
|
28
|
-
use:
|
29
|
-
image:
|
14
|
+
g: Prawn::SVG::Elements::Container,
|
15
|
+
symbol: Prawn::SVG::Elements::Container,
|
16
|
+
defs: Prawn::SVG::Elements::Container,
|
17
|
+
a: Prawn::SVG::Elements::Container,
|
18
|
+
clipPath: Prawn::SVG::Elements::ClipPath,
|
19
|
+
switch: Prawn::SVG::Elements::Container,
|
20
|
+
svg: Prawn::SVG::Elements::Viewport,
|
21
|
+
text: Prawn::SVG::Elements::Text,
|
22
|
+
line: Prawn::SVG::Elements::Line,
|
23
|
+
polyline: Prawn::SVG::Elements::Polyline,
|
24
|
+
polygon: Prawn::SVG::Elements::Polygon,
|
25
|
+
circle: Prawn::SVG::Elements::Circle,
|
26
|
+
ellipse: Prawn::SVG::Elements::Ellipse,
|
27
|
+
rect: Prawn::SVG::Elements::Rect,
|
28
|
+
path: Prawn::SVG::Elements::Path,
|
29
|
+
use: Prawn::SVG::Elements::Use,
|
30
|
+
image: Prawn::SVG::Elements::Image,
|
30
31
|
linearGradient: Prawn::SVG::Elements::Gradient,
|
31
32
|
radialGradient: Prawn::SVG::Elements::Gradient,
|
32
|
-
marker:
|
33
|
-
style:
|
34
|
-
title:
|
35
|
-
desc:
|
36
|
-
metadata:
|
37
|
-
foreignObject:
|
38
|
-
|
39
|
-
filter:
|
40
|
-
mask:
|
41
|
-
}
|
33
|
+
marker: Prawn::SVG::Elements::Marker,
|
34
|
+
style: Prawn::SVG::Elements::Ignored, # because it is pre-parsed by Document
|
35
|
+
title: Prawn::SVG::Elements::Ignored,
|
36
|
+
desc: Prawn::SVG::Elements::Ignored,
|
37
|
+
metadata: Prawn::SVG::Elements::Ignored,
|
38
|
+
foreignObject: Prawn::SVG::Elements::Ignored,
|
39
|
+
'font-face': Prawn::SVG::Elements::Ignored,
|
40
|
+
filter: Prawn::SVG::Elements::Ignored, # unsupported
|
41
|
+
mask: Prawn::SVG::Elements::Ignored # unsupported
|
42
|
+
}.freeze
|
42
43
|
end
|
data/lib/prawn/svg/extension.rb
CHANGED
@@ -17,7 +17,8 @@ module Prawn
|
|
17
17
|
def svg(data, options = {}, &block)
|
18
18
|
svg = Prawn::SVG::Interface.new(data, self, options, &block)
|
19
19
|
svg.draw
|
20
|
-
{:
|
20
|
+
{ warnings: svg.document.warnings, width: svg.document.sizing.output_width,
|
21
|
+
height: svg.document.sizing.output_height }
|
21
22
|
end
|
22
23
|
end
|
23
24
|
end
|
data/lib/prawn/svg/font.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
class Prawn::SVG::Font
|
2
2
|
GENERIC_CSS_FONT_MAPPING = {
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
}
|
3
|
+
'serif' => 'Times-Roman',
|
4
|
+
'sans-serif' => 'Helvetica',
|
5
|
+
'cursive' => 'Times-Roman',
|
6
|
+
'fantasy' => 'Times-Roman',
|
7
|
+
'monospace' => 'Courier'
|
8
|
+
}.freeze
|
9
9
|
|
10
10
|
attr_reader :name, :weight, :style
|
11
11
|
|
@@ -38,7 +38,7 @@ class Prawn::SVG::Font
|
|
38
38
|
|
39
39
|
# Construct a subfamily name, ensuring that the subfamily is a valid one for the font.
|
40
40
|
def subfamily
|
41
|
-
if subfamilies = @font_registry.installed_fonts[name]
|
41
|
+
if (subfamilies = @font_registry.installed_fonts[name])
|
42
42
|
if subfamilies.key?(subfamily_name)
|
43
43
|
subfamily_name
|
44
44
|
elsif subfamilies.key?(:normal)
|
@@ -1,11 +1,11 @@
|
|
1
1
|
class Prawn::SVG::FontRegistry
|
2
2
|
DEFAULT_FONT_PATHS = [
|
3
|
-
|
4
|
-
|
5
|
-
"#{
|
6
|
-
|
7
|
-
|
8
|
-
]
|
3
|
+
'/Library/Fonts',
|
4
|
+
'/System/Library/Fonts',
|
5
|
+
"#{Dir.home}/Library/Fonts",
|
6
|
+
'/usr/share/fonts/truetype',
|
7
|
+
'/mnt/c/Windows/Fonts' # Bash on Ubuntu on Windows
|
8
|
+
].freeze
|
9
9
|
|
10
10
|
@font_path = DEFAULT_FONT_PATHS.select { |path| Dir.exist?(path) }
|
11
11
|
|
@@ -37,8 +37,8 @@ class Prawn::SVG::FontRegistry
|
|
37
37
|
def merge_external_fonts
|
38
38
|
if @font_case_mapping.nil?
|
39
39
|
self.class.load_external_fonts unless self.class.external_font_families
|
40
|
-
@font_families.merge!(self.class.external_font_families) do |
|
41
|
-
|
40
|
+
@font_families.merge!(self.class.external_font_families) do |_key, v1, _v2|
|
41
|
+
v1
|
42
42
|
end
|
43
43
|
@font_case_mapping = @font_families.keys.each.with_object({}) do |key, result|
|
44
44
|
result[key.downcase] = key
|
@@ -54,11 +54,11 @@ class Prawn::SVG::FontRegistry
|
|
54
54
|
|
55
55
|
external_font_paths.each do |filename|
|
56
56
|
ttf = Prawn::SVG::TTF.new(filename)
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
57
|
+
next unless ttf.family
|
58
|
+
|
59
|
+
subfamily = (ttf.subfamily || 'normal').gsub(/\s+/, '_').downcase.to_sym
|
60
|
+
subfamily = :normal if subfamily == :regular
|
61
|
+
(external_font_families[ttf.family] ||= {})[subfamily] ||= filename
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
data/lib/prawn/svg/gradients.rb
CHANGED
@@ -9,9 +9,9 @@ module Prawn::SVG
|
|
9
9
|
id &&= id.strip
|
10
10
|
return unless id && id != ''
|
11
11
|
|
12
|
-
if element = @gradients_by_id[id]
|
12
|
+
if (element = @gradients_by_id[id])
|
13
13
|
element
|
14
|
-
elsif raw_element = find_raw_gradient_element_by_id(id)
|
14
|
+
elsif (raw_element = find_raw_gradient_element_by_id(id))
|
15
15
|
create_gradient_element(raw_element)
|
16
16
|
end
|
17
17
|
end
|
@@ -37,6 +37,7 @@ module Prawn::SVG
|
|
37
37
|
|
38
38
|
def gradient_element?(raw_element)
|
39
39
|
return false if raw_element.nil? || raw_element.name.nil?
|
40
|
+
|
40
41
|
Elements::TAG_CLASS_MAPPING[raw_element.name.to_sym] == Elements::Gradient
|
41
42
|
end
|
42
43
|
|
data/lib/prawn/svg/interface.rb
CHANGED
@@ -8,12 +8,12 @@ module Prawn
|
|
8
8
|
VALID_OPTIONS = %i[
|
9
9
|
at position vposition width height cache_images enable_web_requests
|
10
10
|
enable_file_requests_with_root fallback_font_name color_mode
|
11
|
-
]
|
11
|
+
].freeze
|
12
12
|
|
13
13
|
INHERITABLE_OPTIONS = %i[
|
14
14
|
enable_web_requests enable_file_requests_with_root
|
15
15
|
cache_images fallback_font_name color_mode
|
16
|
-
]
|
16
|
+
].freeze
|
17
17
|
|
18
18
|
attr_reader :data, :prawn, :document, :options
|
19
19
|
|
@@ -60,7 +60,8 @@ module Prawn
|
|
60
60
|
@renderer.position
|
61
61
|
end
|
62
62
|
|
63
|
-
|
63
|
+
# backwards support for when the font_path used to be stored on this class
|
64
|
+
def self.font_path
|
64
65
|
Prawn::SVG::FontRegistry.font_path
|
65
66
|
end
|
66
67
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Prawn::SVG::Loaders
|
2
2
|
class Data
|
3
|
-
REGEXP = %r{\Adata:image/(png|jpeg|svg\+xml);base64(;[a-z0-9]+)*,}i
|
3
|
+
REGEXP = %r{\Adata:image/(png|jpeg|svg\+xml);base64(;[a-z0-9]+)*,}i.freeze
|
4
4
|
|
5
5
|
def from_url(url)
|
6
6
|
return if url[0..4].downcase != 'data:'
|
@@ -8,7 +8,7 @@ module Prawn::SVG::Loaders
|
|
8
8
|
matches = url.match(REGEXP)
|
9
9
|
if matches.nil?
|
10
10
|
raise Prawn::SVG::UrlLoader::Error,
|
11
|
-
|
11
|
+
'prawn-svg only supports base64-encoded image/png, image/jpeg, and image/svg+xml data URLs'
|
12
12
|
end
|
13
13
|
|
14
14
|
matches.post_match.unpack1('m')
|
@@ -24,7 +24,7 @@ require 'addressable/uri'
|
|
24
24
|
# FILES READ AS BINARY
|
25
25
|
# ====================
|
26
26
|
# At the moment, prawn-svg uses this class only to load graphical files, which are binary.
|
27
|
-
# This class therefore uses
|
27
|
+
# This class therefore uses File.binread to read file data. If it is ever used in the future
|
28
28
|
# to load text files, it will have to be taught about what kind of file it's expecting to
|
29
29
|
# read, and adjust the file read function accordingly.
|
30
30
|
#
|
@@ -34,7 +34,8 @@ module Prawn::SVG::Loaders
|
|
34
34
|
|
35
35
|
def initialize(root_path)
|
36
36
|
if root_path.empty?
|
37
|
-
raise ArgumentError,
|
37
|
+
raise ArgumentError,
|
38
|
+
"An empty string is not a valid root path. Use '.' if you want the current working directory."
|
38
39
|
end
|
39
40
|
|
40
41
|
@root_path = ::File.expand_path(root_path)
|
@@ -62,14 +63,12 @@ module Prawn::SVG::Loaders
|
|
62
63
|
path = build_absolute_and_expand_path(path)
|
63
64
|
assert_valid_path!(path)
|
64
65
|
assert_file_exists!(path)
|
65
|
-
|
66
|
+
::File.binread(path)
|
66
67
|
end
|
67
68
|
|
68
69
|
def build_uri(url)
|
69
|
-
|
70
|
-
|
71
|
-
rescue URI::InvalidURIError
|
72
|
-
end
|
70
|
+
URI(url)
|
71
|
+
rescue URI::InvalidURIError
|
73
72
|
end
|
74
73
|
|
75
74
|
def assert_valid_path!(path)
|
@@ -77,7 +76,7 @@ module Prawn::SVG::Loaders
|
|
77
76
|
# making it dependent on whether the file system is case sensitive or not.
|
78
77
|
# Leaving it like this until it's a problem for someone.
|
79
78
|
|
80
|
-
|
79
|
+
unless path.start_with?("#{root_path}#{::File::SEPARATOR}")
|
81
80
|
raise Prawn::SVG::UrlLoader::Error, "file path is not inside the root path of #{root_path}"
|
82
81
|
end
|
83
82
|
end
|
@@ -88,19 +87,18 @@ module Prawn::SVG::Loaders
|
|
88
87
|
|
89
88
|
def assert_valid_file_uri!(uri)
|
90
89
|
unless uri.host.nil? || uri.host.empty?
|
91
|
-
raise Prawn::SVG::UrlLoader::Error,
|
90
|
+
raise Prawn::SVG::UrlLoader::Error,
|
91
|
+
"prawn-svg does not suport file: URLs with a host. Your URL probably doesn't start with three slashes, and it should."
|
92
92
|
end
|
93
93
|
end
|
94
94
|
|
95
95
|
def assert_file_exists!(path)
|
96
|
-
|
97
|
-
raise Prawn::SVG::UrlLoader::Error, "File #{path} does not exist"
|
98
|
-
end
|
96
|
+
raise Prawn::SVG::UrlLoader::Error, "File #{path} does not exist" unless ::File.exist?(path)
|
99
97
|
end
|
100
98
|
|
101
99
|
def fix_windows_path(path)
|
102
|
-
if
|
103
|
-
path[1
|
100
|
+
if path.match(%r{\A/[a-z]:/}i)
|
101
|
+
path[1..]
|
104
102
|
else
|
105
103
|
path
|
106
104
|
end
|
@@ -5,23 +5,19 @@ module Prawn::SVG::Loaders
|
|
5
5
|
def from_url(url)
|
6
6
|
uri = build_uri(url)
|
7
7
|
|
8
|
-
if uri && %w
|
9
|
-
perform_request(uri)
|
10
|
-
end
|
8
|
+
perform_request(uri) if uri && %w[http https].include?(uri.scheme)
|
11
9
|
end
|
12
10
|
|
13
11
|
private
|
14
12
|
|
15
13
|
def build_uri(url)
|
16
|
-
|
17
|
-
|
18
|
-
rescue URI::InvalidURIError
|
19
|
-
end
|
14
|
+
URI(url)
|
15
|
+
rescue URI::InvalidURIError
|
20
16
|
end
|
21
17
|
|
22
18
|
def perform_request(uri)
|
23
19
|
Net::HTTP.get(uri)
|
24
|
-
rescue => e
|
20
|
+
rescue StandardError => e
|
25
21
|
raise Prawn::SVG::UrlLoader::Error, e.message
|
26
22
|
end
|
27
23
|
end
|
data/lib/prawn/svg/pathable.rb
CHANGED
@@ -24,25 +24,26 @@ module Prawn::SVG::Pathable
|
|
24
24
|
when Line
|
25
25
|
add_call 'line_to', translate(command.destination)
|
26
26
|
when Curve
|
27
|
-
add_call 'curve_to', translate(command.destination),
|
27
|
+
add_call 'curve_to', translate(command.destination),
|
28
|
+
bounds: [translate(command.point1), translate(command.point2)]
|
28
29
|
else
|
29
|
-
raise NotImplementedError,
|
30
|
+
raise NotImplementedError, 'Unknown path command type'
|
30
31
|
end
|
31
32
|
end
|
32
33
|
end
|
33
34
|
|
34
35
|
def apply_markers
|
35
|
-
if marker = extract_element_from_url_id_reference(properties.marker_start,
|
36
|
+
if (marker = extract_element_from_url_id_reference(properties.marker_start, 'marker'))
|
36
37
|
marker.apply_marker(self, point: commands.first.destination, angle: angles.first)
|
37
38
|
end
|
38
39
|
|
39
|
-
if marker = extract_element_from_url_id_reference(properties.marker_mid,
|
40
|
-
(1..commands.length-2).each do |index|
|
40
|
+
if (marker = extract_element_from_url_id_reference(properties.marker_mid, 'marker'))
|
41
|
+
(1..commands.length - 2).each do |index|
|
41
42
|
marker.apply_marker(self, point: commands[index].destination, angle: angles[index])
|
42
43
|
end
|
43
44
|
end
|
44
45
|
|
45
|
-
if marker = extract_element_from_url_id_reference(properties.marker_end,
|
46
|
+
if (marker = extract_element_from_url_id_reference(properties.marker_end, 'marker'))
|
46
47
|
marker.apply_marker(self, point: commands.last.destination, angle: angles.last)
|
47
48
|
end
|
48
49
|
end
|
@@ -53,23 +54,26 @@ module Prawn::SVG::Pathable
|
|
53
54
|
last_point = nil
|
54
55
|
|
55
56
|
destination_angles = commands.map do |command|
|
56
|
-
angles =
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
57
|
+
angles =
|
58
|
+
case command
|
59
|
+
when Move
|
60
|
+
[nil, nil]
|
61
|
+
when Close, Line
|
62
|
+
angle = Math.atan2(command.destination[1] - last_point[1],
|
63
|
+
command.destination[0] - last_point[0]) * 180.0 / Math::PI
|
64
|
+
[angle, angle]
|
65
|
+
when Curve
|
66
|
+
point = select_non_equal_point(last_point, command.point1, command.point2, command.destination)
|
67
|
+
start = Math.atan2(point[1] - last_point[1], point[0] - last_point[0]) * 180.0 / Math::PI
|
68
|
+
|
69
|
+
point = select_non_equal_point(command.destination, command.point2, command.point1, last_point)
|
70
|
+
stop = Math.atan2(command.destination[1] - point[1],
|
71
|
+
command.destination[0] - point[0]) * 180.0 / Math::PI
|
72
|
+
|
73
|
+
[start, stop]
|
74
|
+
else
|
75
|
+
raise NotImplementedError, 'Unknown path command type'
|
76
|
+
end
|
73
77
|
|
74
78
|
last_point = command.destination
|
75
79
|
angles
|
@@ -99,10 +103,10 @@ module Prawn::SVG::Pathable
|
|
99
103
|
bisect = (first + second) / 2.0
|
100
104
|
|
101
105
|
angles << if (first - second).abs > 180
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
+
bisect >= 0 ? bisect - 180 : bisect + 180
|
107
|
+
else
|
108
|
+
bisect
|
109
|
+
end
|
106
110
|
else
|
107
111
|
angles << destination_angles.last.last
|
108
112
|
end
|
@@ -111,19 +115,19 @@ module Prawn::SVG::Pathable
|
|
111
115
|
end
|
112
116
|
|
113
117
|
def parse_points(points_string)
|
114
|
-
values = points_string
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
if values.length
|
122
|
-
document.warnings <<
|
118
|
+
values = points_string
|
119
|
+
.to_s
|
120
|
+
.strip
|
121
|
+
.gsub(/(\d)-(\d)/, '\1 -\2')
|
122
|
+
.split(Prawn::SVG::Elements::COMMA_WSP_REGEXP)
|
123
|
+
.map(&:to_f)
|
124
|
+
|
125
|
+
if values.length.odd?
|
126
|
+
document.warnings << 'points attribute has an odd number of points; ignoring the last one'
|
123
127
|
values.pop
|
124
128
|
end
|
125
129
|
|
126
|
-
raise Prawn::SVG::Elements::Base::SkipElementQuietly if values.
|
130
|
+
raise Prawn::SVG::Elements::Base::SkipElementQuietly if values.empty?
|
127
131
|
|
128
132
|
values.each_slice(2).to_a
|
129
133
|
end
|
data/lib/prawn/svg/properties.rb
CHANGED
@@ -10,40 +10,41 @@ class Prawn::SVG::Properties
|
|
10
10
|
'large' => EM / 4 * 5,
|
11
11
|
'x-large' => EM / 4 * 6,
|
12
12
|
'xx-large' => EM / 4 * 7
|
13
|
-
}
|
13
|
+
}.freeze
|
14
14
|
|
15
15
|
PROPERTIES = {
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
'text-
|
42
|
-
|
16
|
+
'clip-path' => Config.new('none', false, %w[inherit none]),
|
17
|
+
'color' => Config.new('', true),
|
18
|
+
'display' => Config.new('inline', false, %w[inherit inline none], true),
|
19
|
+
'fill' => Config.new('black', true, %w[inherit none currentColor]),
|
20
|
+
'fill-opacity' => Config.new('1', true),
|
21
|
+
'fill-rule' => Config.new('nonzero', true, %w[inherit nonzero evenodd]),
|
22
|
+
'font-family' => Config.new('sans-serif', true),
|
23
|
+
'font-size' => Config.new('medium', true,
|
24
|
+
%w[inherit xx-small x-small small medium large x-large xx-large larger smaller]),
|
25
|
+
'font-style' => Config.new('normal', true, %w[inherit normal italic oblique], true),
|
26
|
+
'font-variant' => Config.new('normal', true, %w[inherit normal small-caps], true),
|
27
|
+
'font-weight' => Config.new('normal', true, %w[inherit normal bold 100 200 300 400 500 600 700 800 900], true), # bolder/lighter not supported
|
28
|
+
'letter-spacing' => Config.new('normal', true, %w[inherit normal]),
|
29
|
+
'marker-end' => Config.new('none', true, %w[inherit none]),
|
30
|
+
'marker-mid' => Config.new('none', true, %w[inherit none]),
|
31
|
+
'marker-start' => Config.new('none', true, %w[inherit none]),
|
32
|
+
'opacity' => Config.new('1', false),
|
33
|
+
'overflow' => Config.new('visible', false, %w[inherit visible hidden scroll auto], true),
|
34
|
+
'stop-color' => Config.new('black', false, %w[inherit none currentColor]),
|
35
|
+
'stroke' => Config.new('none', true, %w[inherit none currentColor]),
|
36
|
+
'stroke-dasharray' => Config.new('none', true, %w[inherit none]),
|
37
|
+
'stroke-linecap' => Config.new('butt', true, %w[inherit butt round square], true),
|
38
|
+
'stroke-linejoin' => Config.new('miter', true, %w[inherit miter round bevel], true),
|
39
|
+
'stroke-opacity' => Config.new('1', true),
|
40
|
+
'stroke-width' => Config.new('1', true),
|
41
|
+
'text-anchor' => Config.new('start', true, %w[inherit start middle end], true),
|
42
|
+
'text-decoration' => Config.new('none', true, %w[inherit none underline], true),
|
43
|
+
'dominant-baseline' => Config.new('auto', true, %w[inherit auto middle], true)
|
43
44
|
}.freeze
|
44
45
|
|
45
46
|
PROPERTIES.each do |name, value|
|
46
|
-
value.attr = name.gsub(
|
47
|
+
value.attr = name.gsub('-', '_')
|
47
48
|
value.ivar = "@#{value.attr}"
|
48
49
|
end
|
49
50
|
|
@@ -51,7 +52,7 @@ class Prawn::SVG::Properties
|
|
51
52
|
NAMES = PROPERTIES.keys
|
52
53
|
ATTR_NAMES = PROPERTIES.keys.map { |name| name.gsub('-', '_') }
|
53
54
|
|
54
|
-
attr_accessor
|
55
|
+
attr_accessor(*ATTR_NAMES)
|
55
56
|
|
56
57
|
def load_default_stylesheet
|
57
58
|
PROPERTY_CONFIGS.each do |config|
|
@@ -62,7 +63,7 @@ class Prawn::SVG::Properties
|
|
62
63
|
end
|
63
64
|
|
64
65
|
def set(name, value)
|
65
|
-
if config = PROPERTIES[name.to_s.downcase]
|
66
|
+
if (config = PROPERTIES[name.to_s.downcase])
|
66
67
|
value = value.strip
|
67
68
|
keyword = value.downcase
|
68
69
|
keywords = config.keywords || ['inherit']
|
@@ -92,7 +93,7 @@ class Prawn::SVG::Properties
|
|
92
93
|
value = other.send(config.attr)
|
93
94
|
|
94
95
|
if value && value != 'inherit'
|
95
|
-
value = compute_font_size_property(value).to_s if config.attr ==
|
96
|
+
value = compute_font_size_property(value).to_s if config.attr == 'font_size'
|
96
97
|
instance_variable_set(config.ivar, value)
|
97
98
|
|
98
99
|
elsif value.nil? && !config.inheritable?
|
@@ -109,7 +110,7 @@ class Prawn::SVG::Properties
|
|
109
110
|
private
|
110
111
|
|
111
112
|
def compute_font_size_property(value)
|
112
|
-
if value[-1] ==
|
113
|
+
if value[-1] == '%'
|
113
114
|
numerical_font_size * (value.to_f / 100.0)
|
114
115
|
elsif value == 'larger'
|
115
116
|
numerical_font_size + 4
|
data/lib/prawn/svg/renderer.rb
CHANGED
@@ -74,7 +74,7 @@ module Prawn
|
|
74
74
|
when :top
|
75
75
|
sizing.bounds[1]
|
76
76
|
when :center, :centre
|
77
|
-
sizing.bounds[1] - (sizing.bounds[1] - sizing.output_height) / 2.0
|
77
|
+
sizing.bounds[1] - ((sizing.bounds[1] - sizing.output_height) / 2.0)
|
78
78
|
when :bottom
|
79
79
|
sizing.output_height
|
80
80
|
when Numeric
|
@@ -135,20 +135,20 @@ module Prawn
|
|
135
135
|
@cursor = [at[0], at[1]]
|
136
136
|
end
|
137
137
|
|
138
|
-
if offset = options.delete(:offset)
|
138
|
+
if (offset = options.delete(:offset))
|
139
139
|
at[0] += offset[0]
|
140
140
|
at[1] -= offset[1]
|
141
141
|
end
|
142
142
|
|
143
143
|
width = prawn.width_of(text, options.merge(kerning: true))
|
144
144
|
|
145
|
-
if stretch_to_width = options.delete(:stretch_to_width)
|
145
|
+
if (stretch_to_width = options.delete(:stretch_to_width))
|
146
146
|
factor = stretch_to_width.to_f * 100 / width.to_f
|
147
147
|
prawn.add_content "#{factor} Tz"
|
148
148
|
width = stretch_to_width.to_f
|
149
149
|
end
|
150
150
|
|
151
|
-
if pad_to_width = options.delete(:pad_to_width)
|
151
|
+
if (pad_to_width = options.delete(:pad_to_width))
|
152
152
|
padding_required = pad_to_width.to_f - width.to_f
|
153
153
|
padding_per_character = padding_required / text.length.to_f
|
154
154
|
prawn.add_content "#{padding_per_character} Tc"
|
@@ -158,7 +158,7 @@ module Prawn
|
|
158
158
|
case options.delete(:text_anchor)
|
159
159
|
when 'middle'
|
160
160
|
at[0] -= width / 2
|
161
|
-
@cursor = [at[0] + width / 2, at[1]]
|
161
|
+
@cursor = [at[0] + (width / 2), at[1]]
|
162
162
|
when 'end'
|
163
163
|
at[0] -= width
|
164
164
|
@cursor = at.dup
|
@@ -178,8 +178,8 @@ module Prawn
|
|
178
178
|
when 'transformation_matrix'
|
179
179
|
left = prawn.bounds.absolute_left
|
180
180
|
top = prawn.bounds.absolute_top
|
181
|
-
arguments[4] += left - (left * arguments[0] + top * arguments[2])
|
182
|
-
arguments[5] += top - (left * arguments[1] + top * arguments[3])
|
181
|
+
arguments[4] += left - ((left * arguments[0]) + (top * arguments[2]))
|
182
|
+
arguments[5] += top - ((left * arguments[1]) + (top * arguments[3]))
|
183
183
|
|
184
184
|
when 'clip'
|
185
185
|
prawn.add_content 'W n' # clip to path
|