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