-
Notifications
You must be signed in to change notification settings - Fork 7
/
style.go
134 lines (111 loc) · 2.83 KB
/
style.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package htmlPDF
import (
"fmt"
"sort"
)
type StyleNode struct {
node *Node
specified_values map[string]Value
children map[int]StyleNode
}
type MatchedRule struct {
spec Specificity
rule *Rule
}
//If rule match elem, return a MatchedRule
func matchRule(elem *ElementData, rule *Rule) MatchedRule {
for _, selector := range rule.selectors {
if matchesSelector(elem, selector) {
//Fine the first (highest-specificity) matching selector
mr := MatchedRule{
selector.specificity(),
rule,
}
return mr
}
}
return MatchedRule{}
}
func matchesSelector(elem *ElementData, selector SimpleSelector) bool {
//Check type selector
if selector.tag_name != "" && selector.tag_name != elem.tag_name {
return false
}
//Check id
if selector.id != "" && selector.id != elem.id() {
return false
}
// Check class selectors
if !elem.classContains(selector.class) {
return false
}
return true
}
//Find all CSS rules that match the given element
func matchingRules(elem *ElementData, stylesheet *Stylesheet) map[int]MatchedRule {
matched := map[int]MatchedRule{}
for i, rule := range stylesheet.rules {
mr := matchRule(elem, rule)
if mr.rule != nil {
matched[i] = mr
}
}
return matched
}
type SortBySpec map[int]MatchedRule
func (a SortBySpec) Len() int { return len(a) }
func (a SortBySpec) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a SortBySpec) Less(i, j int) bool { return a[i].spec.a < a[j].spec.a }
func specifiedValues(elem *ElementData, stylesheet *Stylesheet) map[string]Value {
values := map[string]Value{}
rules := matchingRules(elem, stylesheet)
//add sort rules
sort.Sort(SortBySpec(rules))
for _, matchedRule := range rules {
for _, declaration := range matchedRule.rule.declaration {
values[declaration.name] = declaration.value
}
}
return values
}
func styleTree(root *Node, stylesheet *Stylesheet) StyleNode {
children := map[int]StyleNode{}
for i, child := range root.children {
children[i] = styleTree(child, stylesheet)
}
specifiedValue := map[string]Value{}
if root.node_type.element.tag_name != "" {
specifiedValue = specifiedValues(&root.node_type.element, stylesheet)
}
return StyleNode{
node: root,
specified_values: specifiedValue,
children: children,
}
}
func (s StyleNode) print(l int) {
tab(l)
fmt.Printf("node %v\n", s.node)
tab(l)
fmt.Printf("specified_values len %d\n", len(s.specified_values))
tab(l)
fmt.Printf("childrens: \n")
l++
for i := 0; i < len(s.children); i++ {
s.children[i].print(l + 1)
}
}
//Return true if ElementData contain one or more class
func (e ElementData) classContains(class map[int]string) bool {
if len(class) == 0 {
return true
}
for _, class := range class {
for _, eclass := range e.classes() {
if class == eclass {
return true
}
}
}
return false
}