]>
Commit | Line | Data |
---|---|---|
d4949327 NL |
1 | <?php\r |
2 | \r | |
3 | /**\r | |
4 | * Defines allowed CSS attributes and what their values are.\r | |
5 | * @see HTMLPurifier_HTMLDefinition\r | |
6 | */\r | |
7 | class HTMLPurifier_CSSDefinition extends HTMLPurifier_Definition\r | |
8 | {\r | |
9 | \r | |
10 | public $type = 'CSS';\r | |
11 | \r | |
12 | /**\r | |
13 | * Assoc array of attribute name to definition object.\r | |
14 | * @type HTMLPurifier_AttrDef[]\r | |
15 | */\r | |
16 | public $info = array();\r | |
17 | \r | |
18 | /**\r | |
19 | * Constructs the info array. The meat of this class.\r | |
20 | * @param HTMLPurifier_Config $config\r | |
21 | */\r | |
22 | protected function doSetup($config)\r | |
23 | {\r | |
24 | $this->info['text-align'] = new HTMLPurifier_AttrDef_Enum(\r | |
25 | array('left', 'right', 'center', 'justify'),\r | |
26 | false\r | |
27 | );\r | |
28 | \r | |
29 | $border_style =\r | |
30 | $this->info['border-bottom-style'] =\r | |
31 | $this->info['border-right-style'] =\r | |
32 | $this->info['border-left-style'] =\r | |
33 | $this->info['border-top-style'] = new HTMLPurifier_AttrDef_Enum(\r | |
34 | array(\r | |
35 | 'none',\r | |
36 | 'hidden',\r | |
37 | 'dotted',\r | |
38 | 'dashed',\r | |
39 | 'solid',\r | |
40 | 'double',\r | |
41 | 'groove',\r | |
42 | 'ridge',\r | |
43 | 'inset',\r | |
44 | 'outset'\r | |
45 | ),\r | |
46 | false\r | |
47 | );\r | |
48 | \r | |
49 | $this->info['border-style'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_style);\r | |
50 | \r | |
51 | $this->info['clear'] = new HTMLPurifier_AttrDef_Enum(\r | |
52 | array('none', 'left', 'right', 'both'),\r | |
53 | false\r | |
54 | );\r | |
55 | $this->info['float'] = new HTMLPurifier_AttrDef_Enum(\r | |
56 | array('none', 'left', 'right'),\r | |
57 | false\r | |
58 | );\r | |
59 | $this->info['font-style'] = new HTMLPurifier_AttrDef_Enum(\r | |
60 | array('normal', 'italic', 'oblique'),\r | |
61 | false\r | |
62 | );\r | |
63 | $this->info['font-variant'] = new HTMLPurifier_AttrDef_Enum(\r | |
64 | array('normal', 'small-caps'),\r | |
65 | false\r | |
66 | );\r | |
67 | \r | |
68 | $uri_or_none = new HTMLPurifier_AttrDef_CSS_Composite(\r | |
69 | array(\r | |
70 | new HTMLPurifier_AttrDef_Enum(array('none')),\r | |
71 | new HTMLPurifier_AttrDef_CSS_URI()\r | |
72 | )\r | |
73 | );\r | |
74 | \r | |
75 | $this->info['list-style-position'] = new HTMLPurifier_AttrDef_Enum(\r | |
76 | array('inside', 'outside'),\r | |
77 | false\r | |
78 | );\r | |
79 | $this->info['list-style-type'] = new HTMLPurifier_AttrDef_Enum(\r | |
80 | array(\r | |
81 | 'disc',\r | |
82 | 'circle',\r | |
83 | 'square',\r | |
84 | 'decimal',\r | |
85 | 'lower-roman',\r | |
86 | 'upper-roman',\r | |
87 | 'lower-alpha',\r | |
88 | 'upper-alpha',\r | |
89 | 'none'\r | |
90 | ),\r | |
91 | false\r | |
92 | );\r | |
93 | $this->info['list-style-image'] = $uri_or_none;\r | |
94 | \r | |
95 | $this->info['list-style'] = new HTMLPurifier_AttrDef_CSS_ListStyle($config);\r | |
96 | \r | |
97 | $this->info['text-transform'] = new HTMLPurifier_AttrDef_Enum(\r | |
98 | array('capitalize', 'uppercase', 'lowercase', 'none'),\r | |
99 | false\r | |
100 | );\r | |
101 | $this->info['color'] = new HTMLPurifier_AttrDef_CSS_Color();\r | |
102 | \r | |
103 | $this->info['background-image'] = $uri_or_none;\r | |
104 | $this->info['background-repeat'] = new HTMLPurifier_AttrDef_Enum(\r | |
105 | array('repeat', 'repeat-x', 'repeat-y', 'no-repeat')\r | |
106 | );\r | |
107 | $this->info['background-attachment'] = new HTMLPurifier_AttrDef_Enum(\r | |
108 | array('scroll', 'fixed')\r | |
109 | );\r | |
110 | $this->info['background-position'] = new HTMLPurifier_AttrDef_CSS_BackgroundPosition();\r | |
111 | \r | |
112 | $border_color =\r | |
113 | $this->info['border-top-color'] =\r | |
114 | $this->info['border-bottom-color'] =\r | |
115 | $this->info['border-left-color'] =\r | |
116 | $this->info['border-right-color'] =\r | |
117 | $this->info['background-color'] = new HTMLPurifier_AttrDef_CSS_Composite(\r | |
118 | array(\r | |
119 | new HTMLPurifier_AttrDef_Enum(array('transparent')),\r | |
120 | new HTMLPurifier_AttrDef_CSS_Color()\r | |
121 | )\r | |
122 | );\r | |
123 | \r | |
124 | $this->info['background'] = new HTMLPurifier_AttrDef_CSS_Background($config);\r | |
125 | \r | |
126 | $this->info['border-color'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_color);\r | |
127 | \r | |
128 | $border_width =\r | |
129 | $this->info['border-top-width'] =\r | |
130 | $this->info['border-bottom-width'] =\r | |
131 | $this->info['border-left-width'] =\r | |
132 | $this->info['border-right-width'] = new HTMLPurifier_AttrDef_CSS_Composite(\r | |
133 | array(\r | |
134 | new HTMLPurifier_AttrDef_Enum(array('thin', 'medium', 'thick')),\r | |
135 | new HTMLPurifier_AttrDef_CSS_Length('0') //disallow negative\r | |
136 | )\r | |
137 | );\r | |
138 | \r | |
139 | $this->info['border-width'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_width);\r | |
140 | \r | |
141 | $this->info['letter-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite(\r | |
142 | array(\r | |
143 | new HTMLPurifier_AttrDef_Enum(array('normal')),\r | |
144 | new HTMLPurifier_AttrDef_CSS_Length()\r | |
145 | )\r | |
146 | );\r | |
147 | \r | |
148 | $this->info['word-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite(\r | |
149 | array(\r | |
150 | new HTMLPurifier_AttrDef_Enum(array('normal')),\r | |
151 | new HTMLPurifier_AttrDef_CSS_Length()\r | |
152 | )\r | |
153 | );\r | |
154 | \r | |
155 | $this->info['font-size'] = new HTMLPurifier_AttrDef_CSS_Composite(\r | |
156 | array(\r | |
157 | new HTMLPurifier_AttrDef_Enum(\r | |
158 | array(\r | |
159 | 'xx-small',\r | |
160 | 'x-small',\r | |
161 | 'small',\r | |
162 | 'medium',\r | |
163 | 'large',\r | |
164 | 'x-large',\r | |
165 | 'xx-large',\r | |
166 | 'larger',\r | |
167 | 'smaller'\r | |
168 | )\r | |
169 | ),\r | |
170 | new HTMLPurifier_AttrDef_CSS_Percentage(),\r | |
171 | new HTMLPurifier_AttrDef_CSS_Length()\r | |
172 | )\r | |
173 | );\r | |
174 | \r | |
175 | $this->info['line-height'] = new HTMLPurifier_AttrDef_CSS_Composite(\r | |
176 | array(\r | |
177 | new HTMLPurifier_AttrDef_Enum(array('normal')),\r | |
178 | new HTMLPurifier_AttrDef_CSS_Number(true), // no negatives\r | |
179 | new HTMLPurifier_AttrDef_CSS_Length('0'),\r | |
180 | new HTMLPurifier_AttrDef_CSS_Percentage(true)\r | |
181 | )\r | |
182 | );\r | |
183 | \r | |
184 | $margin =\r | |
185 | $this->info['margin-top'] =\r | |
186 | $this->info['margin-bottom'] =\r | |
187 | $this->info['margin-left'] =\r | |
188 | $this->info['margin-right'] = new HTMLPurifier_AttrDef_CSS_Composite(\r | |
189 | array(\r | |
190 | new HTMLPurifier_AttrDef_CSS_Length(),\r | |
191 | new HTMLPurifier_AttrDef_CSS_Percentage(),\r | |
192 | new HTMLPurifier_AttrDef_Enum(array('auto'))\r | |
193 | )\r | |
194 | );\r | |
195 | \r | |
196 | $this->info['margin'] = new HTMLPurifier_AttrDef_CSS_Multiple($margin);\r | |
197 | \r | |
198 | // non-negative\r | |
199 | $padding =\r | |
200 | $this->info['padding-top'] =\r | |
201 | $this->info['padding-bottom'] =\r | |
202 | $this->info['padding-left'] =\r | |
203 | $this->info['padding-right'] = new HTMLPurifier_AttrDef_CSS_Composite(\r | |
204 | array(\r | |
205 | new HTMLPurifier_AttrDef_CSS_Length('0'),\r | |
206 | new HTMLPurifier_AttrDef_CSS_Percentage(true)\r | |
207 | )\r | |
208 | );\r | |
209 | \r | |
210 | $this->info['padding'] = new HTMLPurifier_AttrDef_CSS_Multiple($padding);\r | |
211 | \r | |
212 | $this->info['text-indent'] = new HTMLPurifier_AttrDef_CSS_Composite(\r | |
213 | array(\r | |
214 | new HTMLPurifier_AttrDef_CSS_Length(),\r | |
215 | new HTMLPurifier_AttrDef_CSS_Percentage()\r | |
216 | )\r | |
217 | );\r | |
218 | \r | |
219 | $trusted_wh = new HTMLPurifier_AttrDef_CSS_Composite(\r | |
220 | array(\r | |
221 | new HTMLPurifier_AttrDef_CSS_Length('0'),\r | |
222 | new HTMLPurifier_AttrDef_CSS_Percentage(true),\r | |
223 | new HTMLPurifier_AttrDef_Enum(array('auto'))\r | |
224 | )\r | |
225 | );\r | |
226 | $max = $config->get('CSS.MaxImgLength');\r | |
227 | \r | |
228 | $this->info['width'] =\r | |
229 | $this->info['height'] =\r | |
230 | $max === null ?\r | |
231 | $trusted_wh :\r | |
232 | new HTMLPurifier_AttrDef_Switch(\r | |
233 | 'img',\r | |
234 | // For img tags:\r | |
235 | new HTMLPurifier_AttrDef_CSS_Composite(\r | |
236 | array(\r | |
237 | new HTMLPurifier_AttrDef_CSS_Length('0', $max),\r | |
238 | new HTMLPurifier_AttrDef_Enum(array('auto'))\r | |
239 | )\r | |
240 | ),\r | |
241 | // For everyone else:\r | |
242 | $trusted_wh\r | |
243 | );\r | |
244 | \r | |
245 | $this->info['text-decoration'] = new HTMLPurifier_AttrDef_CSS_TextDecoration();\r | |
246 | \r | |
247 | $this->info['font-family'] = new HTMLPurifier_AttrDef_CSS_FontFamily();\r | |
248 | \r | |
249 | // this could use specialized code\r | |
250 | $this->info['font-weight'] = new HTMLPurifier_AttrDef_Enum(\r | |
251 | array(\r | |
252 | 'normal',\r | |
253 | 'bold',\r | |
254 | 'bolder',\r | |
255 | 'lighter',\r | |
256 | '100',\r | |
257 | '200',\r | |
258 | '300',\r | |
259 | '400',\r | |
260 | '500',\r | |
261 | '600',\r | |
262 | '700',\r | |
263 | '800',\r | |
264 | '900'\r | |
265 | ),\r | |
266 | false\r | |
267 | );\r | |
268 | \r | |
269 | // MUST be called after other font properties, as it references\r | |
270 | // a CSSDefinition object\r | |
271 | $this->info['font'] = new HTMLPurifier_AttrDef_CSS_Font($config);\r | |
272 | \r | |
273 | // same here\r | |
274 | $this->info['border'] =\r | |
275 | $this->info['border-bottom'] =\r | |
276 | $this->info['border-top'] =\r | |
277 | $this->info['border-left'] =\r | |
278 | $this->info['border-right'] = new HTMLPurifier_AttrDef_CSS_Border($config);\r | |
279 | \r | |
280 | $this->info['border-collapse'] = new HTMLPurifier_AttrDef_Enum(\r | |
281 | array('collapse', 'separate')\r | |
282 | );\r | |
283 | \r | |
284 | $this->info['caption-side'] = new HTMLPurifier_AttrDef_Enum(\r | |
285 | array('top', 'bottom')\r | |
286 | );\r | |
287 | \r | |
288 | $this->info['table-layout'] = new HTMLPurifier_AttrDef_Enum(\r | |
289 | array('auto', 'fixed')\r | |
290 | );\r | |
291 | \r | |
292 | $this->info['vertical-align'] = new HTMLPurifier_AttrDef_CSS_Composite(\r | |
293 | array(\r | |
294 | new HTMLPurifier_AttrDef_Enum(\r | |
295 | array(\r | |
296 | 'baseline',\r | |
297 | 'sub',\r | |
298 | 'super',\r | |
299 | 'top',\r | |
300 | 'text-top',\r | |
301 | 'middle',\r | |
302 | 'bottom',\r | |
303 | 'text-bottom'\r | |
304 | )\r | |
305 | ),\r | |
306 | new HTMLPurifier_AttrDef_CSS_Length(),\r | |
307 | new HTMLPurifier_AttrDef_CSS_Percentage()\r | |
308 | )\r | |
309 | );\r | |
310 | \r | |
311 | $this->info['border-spacing'] = new HTMLPurifier_AttrDef_CSS_Multiple(new HTMLPurifier_AttrDef_CSS_Length(), 2);\r | |
312 | \r | |
313 | // These CSS properties don't work on many browsers, but we live\r | |
314 | // in THE FUTURE!\r | |
315 | $this->info['white-space'] = new HTMLPurifier_AttrDef_Enum(\r | |
316 | array('nowrap', 'normal', 'pre', 'pre-wrap', 'pre-line')\r | |
317 | );\r | |
318 | \r | |
319 | if ($config->get('CSS.Proprietary')) {\r | |
320 | $this->doSetupProprietary($config);\r | |
321 | }\r | |
322 | \r | |
323 | if ($config->get('CSS.AllowTricky')) {\r | |
324 | $this->doSetupTricky($config);\r | |
325 | }\r | |
326 | \r | |
327 | if ($config->get('CSS.Trusted')) {\r | |
328 | $this->doSetupTrusted($config);\r | |
329 | }\r | |
330 | \r | |
331 | $allow_important = $config->get('CSS.AllowImportant');\r | |
332 | // wrap all attr-defs with decorator that handles !important\r | |
333 | foreach ($this->info as $k => $v) {\r | |
334 | $this->info[$k] = new HTMLPurifier_AttrDef_CSS_ImportantDecorator($v, $allow_important);\r | |
335 | }\r | |
336 | \r | |
337 | $this->setupConfigStuff($config);\r | |
338 | }\r | |
339 | \r | |
340 | /**\r | |
341 | * @param HTMLPurifier_Config $config\r | |
342 | */\r | |
343 | protected function doSetupProprietary($config)\r | |
344 | {\r | |
345 | // Internet Explorer only scrollbar colors\r | |
346 | $this->info['scrollbar-arrow-color'] = new HTMLPurifier_AttrDef_CSS_Color();\r | |
347 | $this->info['scrollbar-base-color'] = new HTMLPurifier_AttrDef_CSS_Color();\r | |
348 | $this->info['scrollbar-darkshadow-color'] = new HTMLPurifier_AttrDef_CSS_Color();\r | |
349 | $this->info['scrollbar-face-color'] = new HTMLPurifier_AttrDef_CSS_Color();\r | |
350 | $this->info['scrollbar-highlight-color'] = new HTMLPurifier_AttrDef_CSS_Color();\r | |
351 | $this->info['scrollbar-shadow-color'] = new HTMLPurifier_AttrDef_CSS_Color();\r | |
352 | \r | |
353 | // technically not proprietary, but CSS3, and no one supports it\r | |
354 | $this->info['opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue();\r | |
355 | $this->info['-moz-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue();\r | |
356 | $this->info['-khtml-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue();\r | |
357 | \r | |
358 | // only opacity, for now\r | |
359 | $this->info['filter'] = new HTMLPurifier_AttrDef_CSS_Filter();\r | |
360 | \r | |
361 | // more CSS3\r | |
362 | $this->info['page-break-after'] =\r | |
363 | $this->info['page-break-before'] = new HTMLPurifier_AttrDef_Enum(\r | |
364 | array(\r | |
365 | 'auto',\r | |
366 | 'always',\r | |
367 | 'avoid',\r | |
368 | 'left',\r | |
369 | 'right'\r | |
370 | )\r | |
371 | );\r | |
372 | $this->info['page-break-inside'] = new HTMLPurifier_AttrDef_Enum(array('auto', 'avoid'));\r | |
373 | \r | |
374 | }\r | |
375 | \r | |
376 | /**\r | |
377 | * @param HTMLPurifier_Config $config\r | |
378 | */\r | |
379 | protected function doSetupTricky($config)\r | |
380 | {\r | |
381 | $this->info['display'] = new HTMLPurifier_AttrDef_Enum(\r | |
382 | array(\r | |
383 | 'inline',\r | |
384 | 'block',\r | |
385 | 'list-item',\r | |
386 | 'run-in',\r | |
387 | 'compact',\r | |
388 | 'marker',\r | |
389 | 'table',\r | |
390 | 'inline-block',\r | |
391 | 'inline-table',\r | |
392 | 'table-row-group',\r | |
393 | 'table-header-group',\r | |
394 | 'table-footer-group',\r | |
395 | 'table-row',\r | |
396 | 'table-column-group',\r | |
397 | 'table-column',\r | |
398 | 'table-cell',\r | |
399 | 'table-caption',\r | |
400 | 'none'\r | |
401 | )\r | |
402 | );\r | |
403 | $this->info['visibility'] = new HTMLPurifier_AttrDef_Enum(\r | |
404 | array('visible', 'hidden', 'collapse')\r | |
405 | );\r | |
406 | $this->info['overflow'] = new HTMLPurifier_AttrDef_Enum(array('visible', 'hidden', 'auto', 'scroll'));\r | |
407 | }\r | |
408 | \r | |
409 | /**\r | |
410 | * @param HTMLPurifier_Config $config\r | |
411 | */\r | |
412 | protected function doSetupTrusted($config)\r | |
413 | {\r | |
414 | $this->info['position'] = new HTMLPurifier_AttrDef_Enum(\r | |
415 | array('static', 'relative', 'absolute', 'fixed')\r | |
416 | );\r | |
417 | $this->info['top'] =\r | |
418 | $this->info['left'] =\r | |
419 | $this->info['right'] =\r | |
420 | $this->info['bottom'] = new HTMLPurifier_AttrDef_CSS_Composite(\r | |
421 | array(\r | |
422 | new HTMLPurifier_AttrDef_CSS_Length(),\r | |
423 | new HTMLPurifier_AttrDef_CSS_Percentage(),\r | |
424 | new HTMLPurifier_AttrDef_Enum(array('auto')),\r | |
425 | )\r | |
426 | );\r | |
427 | $this->info['z-index'] = new HTMLPurifier_AttrDef_CSS_Composite(\r | |
428 | array(\r | |
429 | new HTMLPurifier_AttrDef_Integer(),\r | |
430 | new HTMLPurifier_AttrDef_Enum(array('auto')),\r | |
431 | )\r | |
432 | );\r | |
433 | }\r | |
434 | \r | |
435 | /**\r | |
436 | * Performs extra config-based processing. Based off of\r | |
437 | * HTMLPurifier_HTMLDefinition.\r | |
438 | * @param HTMLPurifier_Config $config\r | |
439 | * @todo Refactor duplicate elements into common class (probably using\r | |
440 | * composition, not inheritance).\r | |
441 | */\r | |
442 | protected function setupConfigStuff($config)\r | |
443 | {\r | |
444 | // setup allowed elements\r | |
445 | $support = "(for information on implementing this, see the " .\r | |
446 | "support forums) ";\r | |
447 | $allowed_properties = $config->get('CSS.AllowedProperties');\r | |
448 | if ($allowed_properties !== null) {\r | |
449 | foreach ($this->info as $name => $d) {\r | |
450 | if (!isset($allowed_properties[$name])) {\r | |
451 | unset($this->info[$name]);\r | |
452 | }\r | |
453 | unset($allowed_properties[$name]);\r | |
454 | }\r | |
455 | // emit errors\r | |
456 | foreach ($allowed_properties as $name => $d) {\r | |
457 | // :TODO: Is this htmlspecialchars() call really necessary?\r | |
458 | $name = htmlspecialchars($name);\r | |
459 | trigger_error("Style attribute '$name' is not supported $support", E_USER_WARNING);\r | |
460 | }\r | |
461 | }\r | |
462 | \r | |
463 | $forbidden_properties = $config->get('CSS.ForbiddenProperties');\r | |
464 | if ($forbidden_properties !== null) {\r | |
465 | foreach ($this->info as $name => $d) {\r | |
466 | if (isset($forbidden_properties[$name])) {\r | |
467 | unset($this->info[$name]);\r | |
468 | }\r | |
469 | }\r | |
470 | }\r | |
471 | }\r | |
472 | }\r | |
473 | \r | |
474 | // vim: et sw=4 sts=4\r |