prawn-svg 0.27.1 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +11 -2
- data/lib/prawn-svg.rb +3 -1
- data/lib/prawn/svg/{css.rb → css/font_family_parser.rb} +3 -4
- data/lib/prawn/svg/css/selector_parser.rb +174 -0
- data/lib/prawn/svg/css/stylesheets.rb +125 -0
- data/lib/prawn/svg/document.rb +3 -15
- data/lib/prawn/svg/elements.rb +2 -2
- data/lib/prawn/svg/elements/base.rb +20 -23
- data/lib/prawn/svg/elements/clip_path.rb +12 -0
- data/lib/prawn/svg/elements/container.rb +1 -3
- data/lib/prawn/svg/elements/text.rb +1 -1
- data/lib/prawn/svg/elements/text_component.rb +46 -13
- data/lib/prawn/svg/font_registry.rb +4 -3
- data/lib/prawn/svg/interface.rb +3 -1
- data/lib/prawn/svg/properties.rb +1 -0
- data/lib/prawn/svg/state.rb +6 -3
- data/lib/prawn/svg/version.rb +1 -1
- data/prawn-svg.gemspec +2 -2
- data/spec/prawn/svg/{css_spec.rb → css/font_family_parser_spec.rb} +3 -3
- data/spec/prawn/svg/css/selector_parser_spec.rb +33 -0
- data/spec/prawn/svg/css/stylesheets_spec.rb +113 -0
- data/spec/prawn/svg/document_spec.rb +0 -33
- data/spec/prawn/svg/elements/base_spec.rb +56 -0
- data/spec/prawn/svg/elements/text_spec.rb +59 -16
- data/spec/prawn/svg/font_registry_spec.rb +30 -0
- data/spec/prawn/svg/interface_spec.rb +33 -1
- data/spec/sample_output/{directory → .keep} +0 -0
- data/spec/sample_svg/text_stroke.svg +41 -0
- data/spec/sample_svg/warning-radioactive.svg +98 -0
- data/spec/spec_helper.rb +2 -2
- metadata +108 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5f5f1b932d2ff278ac37b5957a18b57d51013345
|
4
|
+
data.tar.gz: 7502fc93ebe947b1955d478292bf71c7b5dd40c0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 770335f6cd4fbff5a30d6d6ff965ff2148e66543342de66a320583f4f24ec040d341054749c619c7a9ef1491e1e0155158ba63ea407b440406791dec60fc57f2
|
7
|
+
data.tar.gz: 8e1d9b9a00984309065c1ffc93b7695aafb97d4fbc91c3b6b76d7cc9ee4fe106365b23672f7a87fe0edc97e2612a7d7d3adfe557d5aaa1af4a0c90fb15652717
|
data/README.md
CHANGED
@@ -81,7 +81,7 @@ prawn-svg supports most but not all of the full SVG 1.1 specification. It curre
|
|
81
81
|
- `<switch>` and `<foreignObject>`, although prawn-svg cannot handle any data that is not SVG so `<foreignObject>`
|
82
82
|
tags are always ignored.
|
83
83
|
|
84
|
-
- properties: `clip-path`, `color`, `display`, `fill-opacity`, `fill`, `opacity`, `overflow`, `stroke`, `stroke-dasharray`, `stroke-linecap`, `stroke-opacity`, `stroke-width`
|
84
|
+
- properties: `clip-path`, `color`, `display`, `fill`, `fill-opacity`, `fill-rule`, `opacity`, `overflow`, `stroke`, `stroke-dasharray`, `stroke-linecap`, `stroke-opacity`, `stroke-width`
|
85
85
|
|
86
86
|
- properties on lines, polylines, polygons and paths: `marker-end`, `marker-mid`, `marker-start`
|
87
87
|
|
@@ -101,12 +101,21 @@ prawn-svg supports most but not all of the full SVG 1.1 specification. It curre
|
|
101
101
|
|
102
102
|
## CSS
|
103
103
|
|
104
|
-
prawn-svg
|
104
|
+
prawn-svg supports CSS, both in `<style>` blocks and `style` attributes.
|
105
|
+
|
106
|
+
In CSS selectors you can use element names, IDs, classes, attributes (existence, `=`, `^=`, `$=`, `*=`, `~=`, `|=`)
|
107
|
+
and all combinators (` `, `>`, `+`, `~`).
|
108
|
+
The pseudo-classes `:first-child`, `:last-child` and `:nth-child(n)` (where n is a number) also work.
|
109
|
+
|
110
|
+
Pseudo-elements and the other pseudo-classes are not supported. Specificity ordering is
|
111
|
+
implemented, but `!important` is not.
|
105
112
|
|
106
113
|
## Not supported
|
107
114
|
|
108
115
|
prawn-svg does not support radial gradients, patterns or filters.
|
109
116
|
|
117
|
+
It does not support text in the clip area, but you can clip shapes and text by any shape.
|
118
|
+
|
110
119
|
## Configuration
|
111
120
|
|
112
121
|
### Fonts
|
data/lib/prawn-svg.rb
CHANGED
@@ -21,7 +21,9 @@ require 'prawn/svg/pathable'
|
|
21
21
|
require 'prawn/svg/elements'
|
22
22
|
require 'prawn/svg/extension'
|
23
23
|
require 'prawn/svg/interface'
|
24
|
-
require 'prawn/svg/css'
|
24
|
+
require 'prawn/svg/css/font_family_parser'
|
25
|
+
require 'prawn/svg/css/selector_parser'
|
26
|
+
require 'prawn/svg/css/stylesheets'
|
25
27
|
require 'prawn/svg/ttf'
|
26
28
|
require 'prawn/svg/font'
|
27
29
|
require 'prawn/svg/document'
|
@@ -1,6 +1,6 @@
|
|
1
|
-
|
2
|
-
class
|
3
|
-
def
|
1
|
+
module Prawn::SVG::CSS
|
2
|
+
class FontFamilyParser
|
3
|
+
def self.parse(string)
|
4
4
|
in_quote = nil
|
5
5
|
in_escape = false
|
6
6
|
current = nil
|
@@ -37,4 +37,3 @@ class Prawn::SVG::CSS
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
end
|
40
|
-
|
@@ -0,0 +1,174 @@
|
|
1
|
+
module Prawn::SVG::CSS
|
2
|
+
class SelectorParser
|
3
|
+
def self.parse(selector)
|
4
|
+
tokens = tokenise_css_selector(selector) or return
|
5
|
+
|
6
|
+
result = [{}]
|
7
|
+
part = nil
|
8
|
+
|
9
|
+
tokens.each do |token|
|
10
|
+
case token
|
11
|
+
when Modifier
|
12
|
+
part = token.type
|
13
|
+
result.last[part] ||= part == :name ? "" : []
|
14
|
+
when Identifier
|
15
|
+
return unless part
|
16
|
+
result.last[part] << token.name
|
17
|
+
when Attribute
|
18
|
+
return unless ["=", "*=", "~=", "^=", "|=", "$=", nil].include?(token.operator)
|
19
|
+
(result.last[:attribute] ||= []) << [token.key, token.operator, token.value]
|
20
|
+
when Combinator
|
21
|
+
result << {combinator: token.type}
|
22
|
+
part = nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
result
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
VALID_CSS_IDENTIFIER_CHAR = /[a-zA-Z0-9_\u00a0-\uffff-]/
|
32
|
+
Identifier = Struct.new(:name)
|
33
|
+
Modifier = Struct.new(:type)
|
34
|
+
Combinator = Struct.new(:type)
|
35
|
+
Attribute = Struct.new(:key, :operator, :value)
|
36
|
+
|
37
|
+
def self.tokenise_css_selector(selector)
|
38
|
+
result = []
|
39
|
+
brackets = false
|
40
|
+
attribute = false
|
41
|
+
quote = false
|
42
|
+
|
43
|
+
selector.strip.chars do |char|
|
44
|
+
if brackets
|
45
|
+
result.last.name << char
|
46
|
+
brackets = false if char == ')'
|
47
|
+
elsif attribute
|
48
|
+
case attribute
|
49
|
+
when :pre_key
|
50
|
+
if VALID_CSS_IDENTIFIER_CHAR.match(char)
|
51
|
+
result.last.key = char
|
52
|
+
attribute = :key
|
53
|
+
elsif char != " " && char != "\t"
|
54
|
+
return
|
55
|
+
end
|
56
|
+
|
57
|
+
when :key
|
58
|
+
if VALID_CSS_IDENTIFIER_CHAR.match(char)
|
59
|
+
result.last.key << char
|
60
|
+
elsif char == "]"
|
61
|
+
attribute = nil
|
62
|
+
elsif "=*~^|$".include?(char)
|
63
|
+
result.last.operator = char
|
64
|
+
attribute = :operator
|
65
|
+
elsif char == " " || char == "\t"
|
66
|
+
attribute = :pre_operator
|
67
|
+
else
|
68
|
+
return
|
69
|
+
end
|
70
|
+
|
71
|
+
when :pre_operator
|
72
|
+
if "=*~^|$".include?(char)
|
73
|
+
result.last.operator = char
|
74
|
+
attribute = :operator
|
75
|
+
elsif char != " " && char != "\t"
|
76
|
+
return
|
77
|
+
end
|
78
|
+
|
79
|
+
when :operator
|
80
|
+
if "=*~^|$".include?(char)
|
81
|
+
result.last.operator << char
|
82
|
+
elsif char == " " || char == "\t"
|
83
|
+
attribute = :pre_value
|
84
|
+
elsif char == '"' || char == "'"
|
85
|
+
result.last.value = ''
|
86
|
+
attribute = char
|
87
|
+
else
|
88
|
+
result.last.value = char
|
89
|
+
attribute = :value
|
90
|
+
end
|
91
|
+
|
92
|
+
when :pre_value
|
93
|
+
if char == '"' || char == "'"
|
94
|
+
result.last.value = ''
|
95
|
+
attribute = char
|
96
|
+
elsif char != " " && char != "\t"
|
97
|
+
result.last.value = char
|
98
|
+
attribute = :value
|
99
|
+
end
|
100
|
+
|
101
|
+
when :value
|
102
|
+
if char == "]"
|
103
|
+
result.last.value = result.last.value.rstrip
|
104
|
+
attribute = nil
|
105
|
+
else
|
106
|
+
result.last.value << char
|
107
|
+
end
|
108
|
+
|
109
|
+
when '"', "'"
|
110
|
+
if char == "\\" && !quote
|
111
|
+
quote = true
|
112
|
+
elsif char == attribute && !quote
|
113
|
+
attribute = :post_string
|
114
|
+
else
|
115
|
+
quote = false
|
116
|
+
result.last.value << char
|
117
|
+
end
|
118
|
+
|
119
|
+
when :post_string
|
120
|
+
if char == "]"
|
121
|
+
attribute = nil
|
122
|
+
elsif char != " " && char != "\t"
|
123
|
+
return
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
elsif VALID_CSS_IDENTIFIER_CHAR.match(char)
|
128
|
+
case result.last
|
129
|
+
when Identifier
|
130
|
+
result.last.name << char
|
131
|
+
else
|
132
|
+
result << Modifier.new(:name) if !result.last.is_a?(Modifier)
|
133
|
+
result << Identifier.new(char)
|
134
|
+
end
|
135
|
+
else
|
136
|
+
case char
|
137
|
+
when "."
|
138
|
+
result << Modifier.new(:class)
|
139
|
+
when "#"
|
140
|
+
result << Modifier.new(:id)
|
141
|
+
when ":"
|
142
|
+
result << Modifier.new(:pseudo_class)
|
143
|
+
when " ", "\t"
|
144
|
+
result << Combinator.new(:descendant) unless result.last.is_a?(Combinator)
|
145
|
+
when ">"
|
146
|
+
result.pop if result.last == Combinator.new(:descendant)
|
147
|
+
result << Combinator.new(:child)
|
148
|
+
when "+"
|
149
|
+
result.pop if result.last == Combinator.new(:descendant)
|
150
|
+
result << Combinator.new(:adjacent)
|
151
|
+
when "~"
|
152
|
+
result.pop if result.last == Combinator.new(:descendant)
|
153
|
+
result << Combinator.new(:siblings)
|
154
|
+
when "*"
|
155
|
+
return unless result.empty? || result.last.is_a?(Combinator)
|
156
|
+
result << Modifier.new(:name)
|
157
|
+
result << Identifier.new("*")
|
158
|
+
when "(" # e.g. :nth-child(3n+4)
|
159
|
+
return unless result.last.is_a?(Identifier) && result[-2] && result[-2].is_a?(Modifier) && result[-2].type == :pseudo_class
|
160
|
+
result.last.name << "("
|
161
|
+
brackets = true
|
162
|
+
when "["
|
163
|
+
result << Attribute.new
|
164
|
+
attribute = :pre_key
|
165
|
+
else
|
166
|
+
return # unsupported Combinator
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
result unless brackets || attribute
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
module Prawn::SVG::CSS
|
2
|
+
class Stylesheets
|
3
|
+
attr_reader :css_parser, :root, :media
|
4
|
+
|
5
|
+
def initialize(css_parser, root, media = :all)
|
6
|
+
@css_parser = css_parser
|
7
|
+
@root = root
|
8
|
+
@media = media
|
9
|
+
end
|
10
|
+
|
11
|
+
def load
|
12
|
+
load_style_elements
|
13
|
+
xpath_styles = gather_xpath_styles
|
14
|
+
associate_xpath_styles_with_elements(xpath_styles)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def load_style_elements
|
20
|
+
REXML::XPath.match(root, '//style').each do |source|
|
21
|
+
data = source.texts.map(&:value).join
|
22
|
+
css_parser.add_block!(data)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def gather_xpath_styles
|
27
|
+
xpath_styles = []
|
28
|
+
order = 0
|
29
|
+
|
30
|
+
css_parser.each_rule_set(media) do |rule_set, _|
|
31
|
+
declarations = []
|
32
|
+
rule_set.each_declaration { |*data| declarations << data }
|
33
|
+
|
34
|
+
rule_set.selectors.each do |selector_text|
|
35
|
+
selector = Prawn::SVG::CSS::SelectorParser.parse(selector_text)
|
36
|
+
xpath = css_selector_to_xpath(selector)
|
37
|
+
specificity = calculate_specificity(selector)
|
38
|
+
specificity << order
|
39
|
+
order += 1
|
40
|
+
|
41
|
+
xpath_styles << [xpath, declarations, specificity]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
xpath_styles.sort_by(&:last)
|
46
|
+
end
|
47
|
+
|
48
|
+
def associate_xpath_styles_with_elements(xpath_styles)
|
49
|
+
element_styles = {}
|
50
|
+
|
51
|
+
xpath_styles.each do |xpath, declarations, _|
|
52
|
+
REXML::XPath.match(root, xpath).each do |element|
|
53
|
+
(element_styles[element] ||= []).concat declarations
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
element_styles
|
58
|
+
end
|
59
|
+
|
60
|
+
def xpath_quote(value)
|
61
|
+
%{"#{value.gsub('\\', '\\\\').gsub('"', '\\"')}"} if value
|
62
|
+
end
|
63
|
+
|
64
|
+
def css_selector_to_xpath(selector)
|
65
|
+
selector.map do |element|
|
66
|
+
pseudo_classes = Set.new(element[:pseudo_class])
|
67
|
+
|
68
|
+
result = case element[:combinator]
|
69
|
+
when :child
|
70
|
+
'/'
|
71
|
+
when :adjacent
|
72
|
+
pseudo_classes << 'first-child'
|
73
|
+
'/following-sibling::'
|
74
|
+
when :siblings
|
75
|
+
'/following-sibling::'
|
76
|
+
else
|
77
|
+
'//'
|
78
|
+
end
|
79
|
+
|
80
|
+
result << element[:name] if element[:name]
|
81
|
+
result << ((element[:class] || []).map { |name| "[contains(concat(' ',@class,' '), ' #{name} ')]" }.join)
|
82
|
+
result << ((element[:id] || []).map { |name| "[@id='#{name}']" }.join)
|
83
|
+
|
84
|
+
(element[:attribute] || []).each do |key, operator, value|
|
85
|
+
case operator
|
86
|
+
when nil
|
87
|
+
result << "[@#{key}]"
|
88
|
+
when "="
|
89
|
+
result << "[@#{key}=#{xpath_quote value}]"
|
90
|
+
when "^="
|
91
|
+
result << "[starts-with(@#{key}, #{xpath_quote value})]"
|
92
|
+
when "$="
|
93
|
+
result << "[substring(@#{key}, string-length(@#{key}) - #{value.length - 1}) = #{xpath_quote value})]"
|
94
|
+
when "*="
|
95
|
+
result << "[contains(@#{key}, #{xpath_quote value})]"
|
96
|
+
when "~="
|
97
|
+
result << "[contains(concat(' ',@#{key},' '), #{xpath_quote " #{value} "})]"
|
98
|
+
when "|="
|
99
|
+
result << "[contains(concat('-',@#{key},'-'), #{xpath_quote "-#{value}-"})]"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
pseudo_classes.each do |pc|
|
104
|
+
case pc
|
105
|
+
when "first-child" then result << "[1]"
|
106
|
+
when "last-child" then result << "[last()]"
|
107
|
+
when /^nth-child\((\d+)\)$/ then result << "[#{$1}]"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
result
|
112
|
+
end.join
|
113
|
+
end
|
114
|
+
|
115
|
+
def calculate_specificity(selector)
|
116
|
+
selector.reduce([0, 0, 0]) do |(a, b, c), element|
|
117
|
+
[
|
118
|
+
a + (element[:id] || []).length,
|
119
|
+
b + (element[:class] || []).length + (element[:attribute] || []).length + (element[:pseudo_class] || []).length,
|
120
|
+
c + (element[:name] && element[:name] != "*" ? 1 : 0)
|
121
|
+
]
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
data/lib/prawn/svg/document.rb
CHANGED
@@ -12,7 +12,8 @@ class Prawn::SVG::Document
|
|
12
12
|
:fallback_font_name,
|
13
13
|
:font_registry,
|
14
14
|
:url_loader,
|
15
|
-
:
|
15
|
+
:elements_by_id, :gradients,
|
16
|
+
:element_styles
|
16
17
|
|
17
18
|
def initialize(data, bounds, options, font_registry: nil, css_parser: CssParser::Parser.new)
|
18
19
|
@root = REXML::Document.new(data).root
|
@@ -31,7 +32,6 @@ class Prawn::SVG::Document
|
|
31
32
|
@gradients = {}
|
32
33
|
@fallback_font_name = options.fetch(:fallback_font_name, DEFAULT_FALLBACK_FONT_NAME)
|
33
34
|
@font_registry = font_registry
|
34
|
-
@css_parser = css_parser
|
35
35
|
|
36
36
|
@url_loader = Prawn::SVG::UrlLoader.new(
|
37
37
|
enable_cache: options[:cache_images],
|
@@ -42,7 +42,7 @@ class Prawn::SVG::Document
|
|
42
42
|
@sizing = Prawn::SVG::Calculators::DocumentSizing.new(bounds, @root.attributes)
|
43
43
|
calculate_sizing(requested_width: options[:width], requested_height: options[:height])
|
44
44
|
|
45
|
-
|
45
|
+
@element_styles = Prawn::SVG::CSS::Stylesheets.new(css_parser, root).load
|
46
46
|
|
47
47
|
yield self if block_given?
|
48
48
|
end
|
@@ -52,16 +52,4 @@ class Prawn::SVG::Document
|
|
52
52
|
sizing.requested_height = requested_height
|
53
53
|
sizing.calculate
|
54
54
|
end
|
55
|
-
|
56
|
-
private
|
57
|
-
|
58
|
-
# <style> elements specified anywhere in the document apply to the entire
|
59
|
-
# document. Because of this, we load all <style> elements before parsing
|
60
|
-
# the rest of the document.
|
61
|
-
def parse_style_elements
|
62
|
-
REXML::XPath.match(root, '//style').each do |source|
|
63
|
-
data = source.texts.map(&:value).join
|
64
|
-
css_parser.add_block!(data)
|
65
|
-
end
|
66
|
-
end
|
67
55
|
end
|
data/lib/prawn/svg/elements.rb
CHANGED
@@ -4,7 +4,7 @@ end
|
|
4
4
|
|
5
5
|
require 'prawn/svg/elements/call_duplicator'
|
6
6
|
|
7
|
-
%w(base depth_first_base root container viewport text text_component line polyline polygon circle ellipse rect path use image gradient marker ignored).each do |filename|
|
7
|
+
%w(base depth_first_base root container clip_path viewport text text_component line polyline polygon circle ellipse rect path use image gradient marker ignored).each do |filename|
|
8
8
|
require "prawn/svg/elements/#{filename}"
|
9
9
|
end
|
10
10
|
|
@@ -13,7 +13,7 @@ module Prawn::SVG::Elements
|
|
13
13
|
g: Prawn::SVG::Elements::Container,
|
14
14
|
symbol: Prawn::SVG::Elements::Container,
|
15
15
|
defs: Prawn::SVG::Elements::Container,
|
16
|
-
clipPath: Prawn::SVG::Elements::
|
16
|
+
clipPath: Prawn::SVG::Elements::ClipPath,
|
17
17
|
switch: Prawn::SVG::Elements::Container,
|
18
18
|
svg: Prawn::SVG::Elements::Viewport,
|
19
19
|
text: Prawn::SVG::Elements::Text,
|
@@ -157,14 +157,23 @@ class Prawn::SVG::Elements::Base
|
|
157
157
|
end
|
158
158
|
|
159
159
|
def apply_drawing_call
|
160
|
-
if
|
161
|
-
draw_types = PAINT_TYPES.select { |property| computed_properties.send(property) != 'none' }
|
160
|
+
return if state.disable_drawing || !drawable?
|
162
161
|
|
163
|
-
|
164
|
-
|
162
|
+
fill = computed_properties.fill != 'none'
|
163
|
+
stroke = computed_properties.stroke != 'none'
|
164
|
+
|
165
|
+
if fill
|
166
|
+
command = stroke ? 'fill_and_stroke' : 'fill'
|
167
|
+
|
168
|
+
if computed_properties.fill_rule == 'evenodd'
|
169
|
+
add_call_and_enter(command, {fill_rule: :even_odd})
|
165
170
|
else
|
166
|
-
add_call_and_enter(
|
171
|
+
add_call_and_enter(command)
|
167
172
|
end
|
173
|
+
elsif stroke
|
174
|
+
add_call_and_enter('stroke')
|
175
|
+
else
|
176
|
+
add_call_and_enter('end_path')
|
168
177
|
end
|
169
178
|
end
|
170
179
|
|
@@ -207,32 +216,20 @@ class Prawn::SVG::Elements::Base
|
|
207
216
|
end
|
208
217
|
|
209
218
|
def extract_attributes_and_properties
|
210
|
-
if
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
if classes = source.attributes["class"]
|
215
|
-
class_styles = classes.split(' ').collect do |class_name|
|
216
|
-
@document.css_parser.find_by_selector(".#{class_name}")
|
217
|
-
end
|
219
|
+
if styles = document.element_styles[source]
|
220
|
+
# TODO : implement !important, at the moment it's just ignored
|
221
|
+
styles.each do |name, value, _important|
|
222
|
+
@properties.set(name, value)
|
218
223
|
end
|
219
|
-
|
220
|
-
element_style = source.attributes['style']
|
221
|
-
|
222
|
-
style = [tag_style, class_styles, id_style, element_style].flatten.collect do |s|
|
223
|
-
s.nil? || s.strip == "" ? "" : "#{s}#{";" unless s.match(/;\s*\z/)}"
|
224
|
-
end.join
|
225
|
-
else
|
226
|
-
style = source.attributes['style'] || ""
|
227
224
|
end
|
228
225
|
|
226
|
+
@properties.load_hash(parse_css_declarations(source.attributes['style'] || ''))
|
227
|
+
|
229
228
|
source.attributes.each do |name, value|
|
230
229
|
# Properties#set returns nil if it's not a recognised property name
|
231
230
|
@properties.set(name, value) or @attributes[name] = value
|
232
231
|
end
|
233
232
|
|
234
|
-
@properties.load_hash(parse_css_declarations(style))
|
235
|
-
|
236
233
|
state.computed_properties.compute_properties(@properties)
|
237
234
|
end
|
238
235
|
|