composer package updates
[openemr.git] / vendor / dompdf / dompdf / src / Css / AttributeTranslator.php
blobc45d7413adeb6f0456f02dc91ced70b004832951
1 <?php
2 /**
3 * @package dompdf
4 * @link http://dompdf.github.com/
5 * @author Benj Carson <benjcarson@digitaljunkies.ca>
6 * @author Fabien Ménager <fabien.menager@gmail.com>
7 * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
8 */
9 namespace Dompdf\Css;
11 use Dompdf\Frame;
13 /**
14 * Translates HTML 4.0 attributes into CSS rules
16 * @package dompdf
18 class AttributeTranslator
20 static $_style_attr = "_html_style_attribute";
22 // Munged data originally from
23 // http://www.w3.org/TR/REC-html40/index/attributes.html
24 // http://www.cs.tut.fi/~jkorpela/html2css.html
25 static private $__ATTRIBUTE_LOOKUP = array(
26 //'caption' => array ( 'align' => '', ),
27 'img' => array(
28 'align' => array(
29 'bottom' => 'vertical-align: baseline;',
30 'middle' => 'vertical-align: middle;',
31 'top' => 'vertical-align: top;',
32 'left' => 'float: left;',
33 'right' => 'float: right;'
35 'border' => 'border: %0.2Fpx solid;',
36 'height' => 'height: %spx;',
37 'hspace' => 'padding-left: %1$0.2Fpx; padding-right: %1$0.2Fpx;',
38 'vspace' => 'padding-top: %1$0.2Fpx; padding-bottom: %1$0.2Fpx;',
39 'width' => 'width: %spx;',
41 'table' => array(
42 'align' => array(
43 'left' => 'margin-left: 0; margin-right: auto;',
44 'center' => 'margin-left: auto; margin-right: auto;',
45 'right' => 'margin-left: auto; margin-right: 0;'
47 'bgcolor' => 'background-color: %s;',
48 'border' => '!set_table_border',
49 'cellpadding' => '!set_table_cellpadding', //'border-spacing: %0.2F; border-collapse: separate;',
50 'cellspacing' => '!set_table_cellspacing',
51 'frame' => array(
52 'void' => 'border-style: none;',
53 'above' => 'border-top-style: solid;',
54 'below' => 'border-bottom-style: solid;',
55 'hsides' => 'border-left-style: solid; border-right-style: solid;',
56 'vsides' => 'border-top-style: solid; border-bottom-style: solid;',
57 'lhs' => 'border-left-style: solid;',
58 'rhs' => 'border-right-style: solid;',
59 'box' => 'border-style: solid;',
60 'border' => 'border-style: solid;'
62 'rules' => '!set_table_rules',
63 'width' => 'width: %s;',
65 'hr' => array(
66 'align' => '!set_hr_align', // Need to grab width to set 'left' & 'right' correctly
67 'noshade' => 'border-style: solid;',
68 'size' => '!set_hr_size', //'border-width: %0.2F px;',
69 'width' => 'width: %s;',
71 'div' => array(
72 'align' => 'text-align: %s;',
74 'h1' => array(
75 'align' => 'text-align: %s;',
77 'h2' => array(
78 'align' => 'text-align: %s;',
80 'h3' => array(
81 'align' => 'text-align: %s;',
83 'h4' => array(
84 'align' => 'text-align: %s;',
86 'h5' => array(
87 'align' => 'text-align: %s;',
89 'h6' => array(
90 'align' => 'text-align: %s;',
92 //TODO: translate more form element attributes
93 'input' => array(
94 'size' => '!set_input_width'
96 'p' => array(
97 'align' => 'text-align: %s;',
99 // 'col' => array(
100 // 'align' => '',
101 // 'valign' => '',
102 // ),
103 // 'colgroup' => array(
104 // 'align' => '',
105 // 'valign' => '',
106 // ),
107 'tbody' => array(
108 'align' => '!set_table_row_align',
109 'valign' => '!set_table_row_valign',
111 'td' => array(
112 'align' => 'text-align: %s;',
113 'bgcolor' => '!set_background_color',
114 'height' => 'height: %s;',
115 'nowrap' => 'white-space: nowrap;',
116 'valign' => 'vertical-align: %s;',
117 'width' => 'width: %s;',
119 'tfoot' => array(
120 'align' => '!set_table_row_align',
121 'valign' => '!set_table_row_valign',
123 'th' => array(
124 'align' => 'text-align: %s;',
125 'bgcolor' => '!set_background_color',
126 'height' => 'height: %s;',
127 'nowrap' => 'white-space: nowrap;',
128 'valign' => 'vertical-align: %s;',
129 'width' => 'width: %s;',
131 'thead' => array(
132 'align' => '!set_table_row_align',
133 'valign' => '!set_table_row_valign',
135 'tr' => array(
136 'align' => '!set_table_row_align',
137 'bgcolor' => '!set_table_row_bgcolor',
138 'valign' => '!set_table_row_valign',
140 'body' => array(
141 'background' => 'background-image: url(%s);',
142 'bgcolor' => '!set_background_color',
143 'link' => '!set_body_link',
144 'text' => '!set_color',
146 'br' => array(
147 'clear' => 'clear: %s;',
149 'basefont' => array(
150 'color' => '!set_color',
151 'face' => 'font-family: %s;',
152 'size' => '!set_basefont_size',
154 'font' => array(
155 'color' => '!set_color',
156 'face' => 'font-family: %s;',
157 'size' => '!set_font_size',
159 'dir' => array(
160 'compact' => 'margin: 0.5em 0;',
162 'dl' => array(
163 'compact' => 'margin: 0.5em 0;',
165 'menu' => array(
166 'compact' => 'margin: 0.5em 0;',
168 'ol' => array(
169 'compact' => 'margin: 0.5em 0;',
170 'start' => 'counter-reset: -dompdf-default-counter %d;',
171 'type' => 'list-style-type: %s;',
173 'ul' => array(
174 'compact' => 'margin: 0.5em 0;',
175 'type' => 'list-style-type: %s;',
177 'li' => array(
178 'type' => 'list-style-type: %s;',
179 'value' => 'counter-reset: -dompdf-default-counter %d;',
181 'pre' => array(
182 'width' => 'width: %s;',
186 static protected $_last_basefont_size = 3;
187 static protected $_font_size_lookup = array(
188 // For basefont support
189 -3 => "4pt",
190 -2 => "5pt",
191 -1 => "6pt",
192 0 => "7pt",
194 1 => "8pt",
195 2 => "10pt",
196 3 => "12pt",
197 4 => "14pt",
198 5 => "18pt",
199 6 => "24pt",
200 7 => "34pt",
202 // For basefont support
203 8 => "48pt",
204 9 => "44pt",
205 10 => "52pt",
206 11 => "60pt",
210 * @param Frame $frame
212 static function translate_attributes(Frame $frame)
214 $node = $frame->get_node();
215 $tag = $node->nodeName;
217 if (!isset(self::$__ATTRIBUTE_LOOKUP[$tag])) {
218 return;
221 $valid_attrs = self::$__ATTRIBUTE_LOOKUP[$tag];
222 $attrs = $node->attributes;
223 $style = rtrim($node->getAttribute(self::$_style_attr), "; ");
224 if ($style != "") {
225 $style .= ";";
228 foreach ($attrs as $attr => $attr_node) {
229 if (!isset($valid_attrs[$attr])) {
230 continue;
233 $value = $attr_node->value;
235 $target = $valid_attrs[$attr];
237 // Look up $value in $target, if $target is an array:
238 if (is_array($target)) {
239 if (isset($target[$value])) {
240 $style .= " " . self::_resolve_target($node, $target[$value], $value);
242 } else {
243 // otherwise use target directly
244 $style .= " " . self::_resolve_target($node, $target, $value);
248 if (!is_null($style)) {
249 $style = ltrim($style);
250 $node->setAttribute(self::$_style_attr, $style);
256 * @param \DOMNode $node
257 * @param string $target
258 * @param string $value
260 * @return string
262 static protected function _resolve_target(\DOMNode $node, $target, $value)
264 if ($target[0] === "!") {
265 // Function call
266 $func = "_" . mb_substr($target, 1);
268 return self::$func($node, $value);
271 return $value ? sprintf($target, $value) : "";
275 * @param \DOMElement $node
276 * @param string $new_style
278 static function append_style(\DOMElement $node, $new_style)
280 $style = rtrim($node->getAttribute(self::$_style_attr), ";");
281 $style .= $new_style;
282 $style = ltrim($style, ";");
283 $node->setAttribute(self::$_style_attr, $style);
287 * @param \DOMNode $node
289 * @return \DOMNodeList|\DOMElement[]
291 static protected function get_cell_list(\DOMNode $node)
293 $xpath = new \DOMXpath($node->ownerDocument);
295 switch ($node->nodeName) {
296 default:
297 case "table":
298 $query = "tr/td | thead/tr/td | tbody/tr/td | tfoot/tr/td | tr/th | thead/tr/th | tbody/tr/th | tfoot/tr/th";
299 break;
301 case "tbody":
302 case "tfoot":
303 case "thead":
304 $query = "tr/td | tr/th";
305 break;
307 case "tr":
308 $query = "td | th";
309 break;
312 return $xpath->query($query, $node);
316 * @param string $value
318 * @return string
320 static protected function _get_valid_color($value)
322 if (preg_match('/^#?([0-9A-F]{6})$/i', $value, $matches)) {
323 $value = "#$matches[1]";
326 return $value;
330 * @param \DOMElement $node
331 * @param string $value
333 * @return string
335 static protected function _set_color(\DOMElement $node, $value)
337 $value = self::_get_valid_color($value);
339 return "color: $value;";
343 * @param \DOMElement $node
344 * @param string $value
346 * @return string
348 static protected function _set_background_color(\DOMElement $node, $value)
350 $value = self::_get_valid_color($value);
352 return "background-color: $value;";
356 * @param \DOMElement $node
357 * @param string $value
359 * @return null
361 static protected function _set_table_cellpadding(\DOMElement $node, $value)
363 $cell_list = self::get_cell_list($node);
365 foreach ($cell_list as $cell) {
366 self::append_style($cell, "; padding: {$value}px;");
369 return null;
373 * @param \DOMElement $node
374 * @param string $value
376 * @return string
378 static protected function _set_table_border(\DOMElement $node, $value)
380 $cell_list = self::get_cell_list($node);
382 foreach ($cell_list as $cell) {
383 $style = rtrim($cell->getAttribute(self::$_style_attr));
384 $style .= "; border-width: " . ($value > 0 ? 1 : 0) . "pt; border-style: inset;";
385 $style = ltrim($style, ";");
386 $cell->setAttribute(self::$_style_attr, $style);
389 $style = rtrim($node->getAttribute(self::$_style_attr), ";");
390 $style .= "; border-width: $value" . "px; ";
392 return ltrim($style, "; ");
396 * @param \DOMElement $node
397 * @param string $value
399 * @return string
401 static protected function _set_table_cellspacing(\DOMElement $node, $value)
403 $style = rtrim($node->getAttribute(self::$_style_attr), ";");
405 if ($value == 0) {
406 $style .= "; border-collapse: collapse;";
407 } else {
408 $style .= "; border-spacing: {$value}px; border-collapse: separate;";
411 return ltrim($style, ";");
415 * @param \DOMElement $node
416 * @param string $value
418 * @return null|string
420 static protected function _set_table_rules(\DOMElement $node, $value)
422 $new_style = "; border-collapse: collapse;";
424 switch ($value) {
425 case "none":
426 $new_style .= "border-style: none;";
427 break;
429 case "groups":
430 // FIXME: unsupported
431 return null;
433 case "rows":
434 $new_style .= "border-style: solid none solid none; border-width: 1px; ";
435 break;
437 case "cols":
438 $new_style .= "border-style: none solid none solid; border-width: 1px; ";
439 break;
441 case "all":
442 $new_style .= "border-style: solid; border-width: 1px; ";
443 break;
445 default:
446 // Invalid value
447 return null;
450 $cell_list = self::get_cell_list($node);
452 foreach ($cell_list as $cell) {
453 $style = $cell->getAttribute(self::$_style_attr);
454 $style .= $new_style;
455 $cell->setAttribute(self::$_style_attr, $style);
458 $style = rtrim($node->getAttribute(self::$_style_attr), ";");
459 $style .= "; border-collapse: collapse; ";
461 return ltrim($style, "; ");
465 * @param \DOMElement $node
466 * @param string $value
468 * @return string
470 static protected function _set_hr_size(\DOMElement $node, $value)
472 $style = rtrim($node->getAttribute(self::$_style_attr), ";");
473 $style .= "; border-width: " . max(0, $value - 2) . "; ";
475 return ltrim($style, "; ");
479 * @param \DOMElement $node
480 * @param string $value
482 * @return null|string
484 static protected function _set_hr_align(\DOMElement $node, $value)
486 $style = rtrim($node->getAttribute(self::$_style_attr), ";");
487 $width = $node->getAttribute("width");
489 if ($width == "") {
490 $width = "100%";
493 $remainder = 100 - (double)rtrim($width, "% ");
495 switch ($value) {
496 case "left":
497 $style .= "; margin-right: $remainder %;";
498 break;
500 case "right":
501 $style .= "; margin-left: $remainder %;";
502 break;
504 case "center":
505 $style .= "; margin-left: auto; margin-right: auto;";
506 break;
508 default:
509 return null;
512 return ltrim($style, "; ");
516 * @param \DOMElement $node
517 * @param string $value
519 * @return null|string
521 static protected function _set_input_width(\DOMElement $node, $value)
523 if (empty($value)) { return null; }
525 if ($node->hasAttribute("type") && in_array(strtolower($node->getAttribute("type")), array("text","password"))) {
526 return sprintf("width: %Fem", (((int)$value * .65)+2));
527 } else {
528 return sprintf("width: %upx;", (int)$value);
533 * @param \DOMElement $node
534 * @param string $value
536 * @return null
538 static protected function _set_table_row_align(\DOMElement $node, $value)
540 $cell_list = self::get_cell_list($node);
542 foreach ($cell_list as $cell) {
543 self::append_style($cell, "; text-align: $value;");
546 return null;
550 * @param \DOMElement $node
551 * @param string $value
553 * @return null
555 static protected function _set_table_row_valign(\DOMElement $node, $value)
557 $cell_list = self::get_cell_list($node);
559 foreach ($cell_list as $cell) {
560 self::append_style($cell, "; vertical-align: $value;");
563 return null;
567 * @param \DOMElement $node
568 * @param string $value
570 * @return null
572 static protected function _set_table_row_bgcolor(\DOMElement $node, $value)
574 $cell_list = self::get_cell_list($node);
575 $value = self::_get_valid_color($value);
577 foreach ($cell_list as $cell) {
578 self::append_style($cell, "; background-color: $value;");
581 return null;
585 * @param \DOMElement $node
586 * @param string $value
588 * @return null
590 static protected function _set_body_link(\DOMElement $node, $value)
592 $a_list = $node->getElementsByTagName("a");
593 $value = self::_get_valid_color($value);
595 foreach ($a_list as $a) {
596 self::append_style($a, "; color: $value;");
599 return null;
603 * @param \DOMElement $node
604 * @param string $value
606 * @return null
608 static protected function _set_basefont_size(\DOMElement $node, $value)
610 // FIXME: ? we don't actually set the font size of anything here, just
611 // the base size for later modification by <font> tags.
612 self::$_last_basefont_size = $value;
614 return null;
618 * @param \DOMElement $node
619 * @param string $value
621 * @return string
623 static protected function _set_font_size(\DOMElement $node, $value)
625 $style = $node->getAttribute(self::$_style_attr);
627 if ($value[0] === "-" || $value[0] === "+") {
628 $value = self::$_last_basefont_size + (int)$value;
631 if (isset(self::$_font_size_lookup[$value])) {
632 $style .= "; font-size: " . self::$_font_size_lookup[$value] . ";";
633 } else {
634 $style .= "; font-size: $value;";
637 return ltrim($style, "; ");