]>
Commit | Line | Data |
---|---|---|
f45a286b AD |
1 | <?php |
2 | ||
3 | /** | |
4 | * Validates shorthand CSS property font. | |
5 | */ | |
6 | class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef | |
7 | { | |
8 | ||
9 | /** | |
10 | * Local copy of component validators. | |
11 | * | |
12 | * @note If we moved specific CSS property definitions to their own | |
13 | * classes instead of having them be assembled at run time by | |
14 | * CSSDefinition, this wouldn't be necessary. We'd instantiate | |
15 | * our own copies. | |
16 | */ | |
17 | protected $info = array(); | |
18 | ||
19 | public function __construct($config) { | |
20 | $def = $config->getCSSDefinition(); | |
21 | $this->info['font-style'] = $def->info['font-style']; | |
22 | $this->info['font-variant'] = $def->info['font-variant']; | |
23 | $this->info['font-weight'] = $def->info['font-weight']; | |
24 | $this->info['font-size'] = $def->info['font-size']; | |
25 | $this->info['line-height'] = $def->info['line-height']; | |
26 | $this->info['font-family'] = $def->info['font-family']; | |
27 | } | |
28 | ||
29 | public function validate($string, $config, $context) { | |
30 | ||
31 | static $system_fonts = array( | |
32 | 'caption' => true, | |
33 | 'icon' => true, | |
34 | 'menu' => true, | |
35 | 'message-box' => true, | |
36 | 'small-caption' => true, | |
37 | 'status-bar' => true | |
38 | ); | |
39 | ||
40 | // regular pre-processing | |
41 | $string = $this->parseCDATA($string); | |
42 | if ($string === '') return false; | |
43 | ||
44 | // check if it's one of the keywords | |
45 | $lowercase_string = strtolower($string); | |
46 | if (isset($system_fonts[$lowercase_string])) { | |
47 | return $lowercase_string; | |
48 | } | |
49 | ||
50 | $bits = explode(' ', $string); // bits to process | |
51 | $stage = 0; // this indicates what we're looking for | |
52 | $caught = array(); // which stage 0 properties have we caught? | |
53 | $stage_1 = array('font-style', 'font-variant', 'font-weight'); | |
54 | $final = ''; // output | |
55 | ||
56 | for ($i = 0, $size = count($bits); $i < $size; $i++) { | |
57 | if ($bits[$i] === '') continue; | |
58 | switch ($stage) { | |
59 | ||
60 | // attempting to catch font-style, font-variant or font-weight | |
61 | case 0: | |
62 | foreach ($stage_1 as $validator_name) { | |
63 | if (isset($caught[$validator_name])) continue; | |
64 | $r = $this->info[$validator_name]->validate( | |
65 | $bits[$i], $config, $context); | |
66 | if ($r !== false) { | |
67 | $final .= $r . ' '; | |
68 | $caught[$validator_name] = true; | |
69 | break; | |
70 | } | |
71 | } | |
72 | // all three caught, continue on | |
73 | if (count($caught) >= 3) $stage = 1; | |
74 | if ($r !== false) break; | |
75 | ||
76 | // attempting to catch font-size and perhaps line-height | |
77 | case 1: | |
78 | $found_slash = false; | |
79 | if (strpos($bits[$i], '/') !== false) { | |
80 | list($font_size, $line_height) = | |
81 | explode('/', $bits[$i]); | |
82 | if ($line_height === '') { | |
83 | // ooh, there's a space after the slash! | |
84 | $line_height = false; | |
85 | $found_slash = true; | |
86 | } | |
87 | } else { | |
88 | $font_size = $bits[$i]; | |
89 | $line_height = false; | |
90 | } | |
91 | $r = $this->info['font-size']->validate( | |
92 | $font_size, $config, $context); | |
93 | if ($r !== false) { | |
94 | $final .= $r; | |
95 | // attempt to catch line-height | |
96 | if ($line_height === false) { | |
97 | // we need to scroll forward | |
98 | for ($j = $i + 1; $j < $size; $j++) { | |
99 | if ($bits[$j] === '') continue; | |
100 | if ($bits[$j] === '/') { | |
101 | if ($found_slash) { | |
102 | return false; | |
103 | } else { | |
104 | $found_slash = true; | |
105 | continue; | |
106 | } | |
107 | } | |
108 | $line_height = $bits[$j]; | |
109 | break; | |
110 | } | |
111 | } else { | |
112 | // slash already found | |
113 | $found_slash = true; | |
114 | $j = $i; | |
115 | } | |
116 | if ($found_slash) { | |
117 | $i = $j; | |
118 | $r = $this->info['line-height']->validate( | |
119 | $line_height, $config, $context); | |
120 | if ($r !== false) { | |
121 | $final .= '/' . $r; | |
122 | } | |
123 | } | |
124 | $final .= ' '; | |
125 | $stage = 2; | |
126 | break; | |
127 | } | |
128 | return false; | |
129 | ||
130 | // attempting to catch font-family | |
131 | case 2: | |
132 | $font_family = | |
133 | implode(' ', array_slice($bits, $i, $size - $i)); | |
134 | $r = $this->info['font-family']->validate( | |
135 | $font_family, $config, $context); | |
136 | if ($r !== false) { | |
137 | $final .= $r . ' '; | |
138 | // processing completed successfully | |
139 | return rtrim($final); | |
140 | } | |
141 | return false; | |
142 | } | |
143 | } | |
144 | return false; | |
145 | } | |
146 | ||
147 | } | |
148 | ||
149 | // vim: et sw=4 sts=4 |