/** * Analyse the CSS properties from the HTML parsing * * @param string $tagName * @param array $param * @param array $legacy * * @return boolean */ public function analyse($tagName, &$param, $legacy = null) { // prepare the informations $tagName = strtolower($tagName); $id = isset($param['id']) ? strtolower(trim($param['id'])) : null; if (!$id) { $id = null; } $name = isset($param['name']) ? strtolower(trim($param['name'])) : null; if (!$name) { $name = null; } // get the class names to use $class = array(); $tmp = isset($param['class']) ? strtolower(trim($param['class'])) : ''; $tmp = explode(' ', $tmp); foreach ($tmp as $k => $v) { $v = trim($v); if ($v) { $class[] = $v; } } // prepare the values, and the list of css tags to identify $this->value['id_tag'] = $tagName; $this->value['id_name'] = $name; $this->value['id_id'] = $id; $this->value['id_class'] = $class; $this->value['id_lst'] = array(); $this->value['id_lst'][] = '*'; $this->value['id_lst'][] = $tagName; if (count($class)) { foreach ($class as $v) { $this->value['id_lst'][] = '*.' . $v; $this->value['id_lst'][] = '.' . $v; $this->value['id_lst'][] = $tagName . '.' . $v; } } if ($id) { $this->value['id_lst'][] = '*#' . $id; $this->value['id_lst'][] = '#' . $id; $this->value['id_lst'][] = $tagName . '#' . $id; } // get the css styles from class $styles = $this->getFromCSS(); // merge with the css styles from tag $styles = array_merge($styles, $param['style']); if (isset($param['allwidth']) && !isset($styles['width'])) { $styles['width'] = '100%'; } // reset some styles, depending on the tag name $this->resetStyle($tagName); // add the legacy values if ($legacy) { foreach ($legacy as $legacyName => $legacyValue) { if (is_array($legacyValue)) { foreach ($legacyValue as $legacy2Name => $legacy2Value) { $this->value[$legacyName][$legacy2Name] = $legacy2Value; } } else { $this->value[$legacyName] = $legacyValue; } } } // some flags $correctWidth = false; $noWidth = true; // read all the css styles foreach ($styles as $nom => $val) { switch ($nom) { case 'font-family': $val = explode(',', $val); $val = trim($val[0]); if ($val && $val != 'inherit') { $this->value['font-family'] = $val; } break; case 'font-weight': $this->value['font-bold'] = $val == 'bold'; break; case 'font-style': $this->value['font-italic'] = $val == 'italic'; break; case 'text-decoration': $val = explode(' ', $val); $this->value['font-underline'] = in_array('underline', $val); $this->value['font-overline'] = in_array('overline', $val); $this->value['font-linethrough'] = in_array('line-through', $val); break; case 'text-indent': $this->value['text-indent'] = $this->cssConverter->convertToMM($val); break; case 'text-transform': if (!in_array($val, array('none', 'capitalize', 'uppercase', 'lowercase'))) { $val = 'none'; } $this->value['text-transform'] = $val; break; case 'font-size': $val = $this->cssConverter->convertToMM($val, $this->value['font-size']); if ($val) { $this->value['font-size'] = $val; } break; case 'color': $res = null; $this->value['color'] = $this->cssConverter->convertToColor($val, $res); if ($tagName == 'hr') { $this->value['border']['l']['color'] = $this->value['color']; $this->value['border']['t']['color'] = $this->value['color']; $this->value['border']['r']['color'] = $this->value['color']; $this->value['border']['b']['color'] = $this->value['color']; } break; case 'text-align': $val = strtolower($val); if (!in_array($val, array('left', 'right', 'center', 'justify', 'li_right'))) { $val = 'left'; } $this->value['text-align'] = $val; break; case 'vertical-align': $this->value['vertical-align'] = $val; break; case 'width': $this->value['width'] = $this->cssConverter->convertToMM($val, $this->getLastWidth()); if ($this->value['width'] && substr($val, -1) == '%') { $correctWidth = true; } $noWidth = false; break; case 'height': $this->value['height'] = $this->cssConverter->convertToMM($val, $this->getLastHeight()); break; case 'line-height': if (preg_match('/^[0-9\\.]+$/isU', $val)) { $val = floor($val * 100) . '%'; } $this->value['line-height'] = $val; break; case 'rotate': if (!in_array($val, array(0, -90, 90, 180, 270, -180, -270))) { $val = null; } if ($val < 0) { $val += 360; } $this->value['rotate'] = $val; break; case 'overflow': if (!in_array($val, array('visible', 'hidden'))) { $val = 'visible'; } $this->value['overflow'] = $val; break; case 'padding': $val = explode(' ', $val); foreach ($val as $k => $v) { $v = trim($v); if ($v != '') { $val[$k] = $v; } else { unset($val[$k]); } } $val = array_values($val); $this->duplicateBorder($val); $this->value['padding']['t'] = $this->cssConverter->convertToMM($val[0], 0); $this->value['padding']['r'] = $this->cssConverter->convertToMM($val[1], 0); $this->value['padding']['b'] = $this->cssConverter->convertToMM($val[2], 0); $this->value['padding']['l'] = $this->cssConverter->convertToMM($val[3], 0); break; case 'padding-top': $this->value['padding']['t'] = $this->cssConverter->convertToMM($val, 0); break; case 'padding-right': $this->value['padding']['r'] = $this->cssConverter->convertToMM($val, 0); break; case 'padding-bottom': $this->value['padding']['b'] = $this->cssConverter->convertToMM($val, 0); break; case 'padding-left': $this->value['padding']['l'] = $this->cssConverter->convertToMM($val, 0); break; case 'margin': if ($val == 'auto') { $this->value['margin-auto'] = true; break; } $val = explode(' ', $val); foreach ($val as $k => $v) { $v = trim($v); if ($v != '') { $val[$k] = $v; } else { unset($val[$k]); } } $val = array_values($val); $this->duplicateBorder($val); $this->value['margin']['t'] = $this->cssConverter->convertToMM($val[0], 0); $this->value['margin']['r'] = $this->cssConverter->convertToMM($val[1], 0); $this->value['margin']['b'] = $this->cssConverter->convertToMM($val[2], 0); $this->value['margin']['l'] = $this->cssConverter->convertToMM($val[3], 0); break; case 'margin-top': $this->value['margin']['t'] = $this->cssConverter->convertToMM($val, 0); break; case 'margin-right': $this->value['margin']['r'] = $this->cssConverter->convertToMM($val, 0); break; case 'margin-bottom': $this->value['margin']['b'] = $this->cssConverter->convertToMM($val, 0); break; case 'margin-left': $this->value['margin']['l'] = $this->cssConverter->convertToMM($val, 0); break; case 'border': $val = $this->readBorder($val); $this->value['border']['t'] = $val; $this->value['border']['r'] = $val; $this->value['border']['b'] = $val; $this->value['border']['l'] = $val; break; case 'border-style': $val = explode(' ', $val); foreach ($val as $valK => $valV) { if (!in_array($valV, array('solid', 'dotted', 'dashed'))) { $val[$valK] = null; } } $this->duplicateBorder($val); if ($val[0]) { $this->value['border']['t']['type'] = $val[0]; } if ($val[1]) { $this->value['border']['r']['type'] = $val[1]; } if ($val[2]) { $this->value['border']['b']['type'] = $val[2]; } if ($val[3]) { $this->value['border']['l']['type'] = $val[3]; } break; case 'border-top-style': if (in_array($val, array('solid', 'dotted', 'dashed'))) { $this->value['border']['t']['type'] = $val; } break; case 'border-right-style': if (in_array($val, array('solid', 'dotted', 'dashed'))) { $this->value['border']['r']['type'] = $val; } break; case 'border-bottom-style': if (in_array($val, array('solid', 'dotted', 'dashed'))) { $this->value['border']['b']['type'] = $val; } break; case 'border-left-style': if (in_array($val, array('solid', 'dotted', 'dashed'))) { $this->value['border']['l']['type'] = $val; } break; case 'border-color': $res = false; $val = preg_replace('/,[\\s]+/', ',', $val); $val = explode(' ', $val); foreach ($val as $valK => $valV) { $val[$valK] = $this->cssConverter->convertToColor($valV, $res); if (!$res) { $val[$valK] = null; } } $this->duplicateBorder($val); if (is_array($val[0])) { $this->value['border']['t']['color'] = $val[0]; } if (is_array($val[1])) { $this->value['border']['r']['color'] = $val[1]; } if (is_array($val[2])) { $this->value['border']['b']['color'] = $val[2]; } if (is_array($val[3])) { $this->value['border']['l']['color'] = $val[3]; } break; case 'border-top-color': $res = false; $val = $this->cssConverter->convertToColor($val, $res); if ($res) { $this->value['border']['t']['color'] = $val; } break; case 'border-right-color': $res = false; $val = $this->cssConverter->convertToColor($val, $res); if ($res) { $this->value['border']['r']['color'] = $val; } break; case 'border-bottom-color': $res = false; $val = $this->cssConverter->convertToColor($val, $res); if ($res) { $this->value['border']['b']['color'] = $val; } break; case 'border-left-color': $res = false; $val = $this->cssConverter->convertToColor($val, $res); if ($res) { $this->value['border']['l']['color'] = $val; } break; case 'border-width': $val = explode(' ', $val); foreach ($val as $valK => $valV) { $val[$valK] = $this->cssConverter->convertToMM($valV, 0); } $this->duplicateBorder($val); if ($val[0]) { $this->value['border']['t']['width'] = $val[0]; } if ($val[1]) { $this->value['border']['r']['width'] = $val[1]; } if ($val[2]) { $this->value['border']['b']['width'] = $val[2]; } if ($val[3]) { $this->value['border']['l']['width'] = $val[3]; } break; case 'border-top-width': $val = $this->cssConverter->convertToMM($val, 0); if ($val) { $this->value['border']['t']['width'] = $val; } break; case 'border-right-width': $val = $this->cssConverter->convertToMM($val, 0); if ($val) { $this->value['border']['r']['width'] = $val; } break; case 'border-bottom-width': $val = $this->cssConverter->convertToMM($val, 0); if ($val) { $this->value['border']['b']['width'] = $val; } break; case 'border-left-width': $val = $this->cssConverter->convertToMM($val, 0); if ($val) { $this->value['border']['l']['width'] = $val; } break; case 'border-collapse': if ($tagName == 'table') { $this->value['border']['collapse'] = $val == 'collapse'; } break; case 'border-radius': $val = explode('/', $val); if (count($val) > 2) { break; } $valH = $this->cssConverter->convertToRadius(trim($val[0])); if (count($valH) < 1 || count($valH) > 4) { break; } if (!isset($valH[1])) { $valH[1] = $valH[0]; } if (!isset($valH[2])) { $valH = array($valH[0], $valH[0], $valH[1], $valH[1]); } if (!isset($valH[3])) { $valH[3] = $valH[1]; } if (isset($val[1])) { $valV = $this->cssConverter->convertToRadius(trim($val[1])); if (count($valV) < 1 || count($valV) > 4) { break; } if (!isset($valV[1])) { $valV[1] = $valV[0]; } if (!isset($valV[2])) { $valV = array($valV[0], $valV[0], $valV[1], $valV[1]); } if (!isset($valV[3])) { $valV[3] = $valV[1]; } } else { $valV = $valH; } $this->value['border']['radius'] = array('tl' => array($valH[0], $valV[0]), 'tr' => array($valH[1], $valV[1]), 'br' => array($valH[2], $valV[2]), 'bl' => array($valH[3], $valV[3])); break; case 'border-top-left-radius': $val = $this->cssConverter->convertToRadius($val); if (count($val) < 1 || count($val) > 2) { break; } $this->value['border']['radius']['tl'] = array($val[0], isset($val[1]) ? $val[1] : $val[0]); break; case 'border-top-right-radius': $val = $this->cssConverter->convertToRadius($val); if (count($val) < 1 || count($val) > 2) { break; } $this->value['border']['radius']['tr'] = array($val[0], isset($val[1]) ? $val[1] : $val[0]); break; case 'border-bottom-right-radius': $val = $this->cssConverter->convertToRadius($val); if (count($val) < 1 || count($val) > 2) { break; } $this->value['border']['radius']['br'] = array($val[0], isset($val[1]) ? $val[1] : $val[0]); break; case 'border-bottom-left-radius': $val = $this->cssConverter->convertToRadius($val); if (count($val) < 1 || count($val) > 2) { break; } $this->value['border']['radius']['bl'] = array($val[0], isset($val[1]) ? $val[1] : $val[0]); break; case 'border-top': $this->value['border']['t'] = $this->readBorder($val); break; case 'border-right': $this->value['border']['r'] = $this->readBorder($val); break; case 'border-bottom': $this->value['border']['b'] = $this->readBorder($val); break; case 'border-left': $this->value['border']['l'] = $this->readBorder($val); break; case 'background-color': $this->value['background']['color'] = $this->cssConverter->convertBackgroundColor($val); break; case 'background-image': $this->value['background']['image'] = $this->cssConverter->convertBackgroundImage($val); break; case 'background-position': $res = null; $this->value['background']['position'] = $this->cssConverter->convertBackgroundPosition($val, $res); break; case 'background-repeat': $this->value['background']['repeat'] = $this->cssConverter->convertBackgroundRepeat($val); break; case 'background': $this->cssConverter->convertBackground($val, $this->value['background']); break; case 'position': if ($val == 'absolute') { $this->value['position'] = 'absolute'; } elseif ($val == 'relative') { $this->value['position'] = 'relative'; } else { $this->value['position'] = null; } break; case 'float': if ($val == 'left') { $this->value['float'] = 'left'; } elseif ($val == 'right') { $this->value['float'] = 'right'; } else { $this->value['float'] = null; } break; case 'display': if ($val == 'inline') { $this->value['display'] = 'inline'; } elseif ($val == 'block') { $this->value['display'] = 'block'; } elseif ($val == 'none') { $this->value['display'] = 'none'; } else { $this->value['display'] = null; } break; case 'top': case 'bottom': case 'left': case 'right': $this->value[$nom] = $val; break; case 'list-style': case 'list-style-type': case 'list-style-image': if ($nom == 'list-style') { $nom = 'list-style-type'; } $this->value[$nom] = $val; break; case 'start': $this->value[$nom] = intval($val); break; default: break; } } $return = true; // only for P tag if ($this->value['margin']['t'] === null) { $this->value['margin']['t'] = $this->value['font-size']; } if ($this->value['margin']['b'] === null) { $this->value['margin']['b'] = $this->value['font-size']; } // force the text align to left, if asked by html2pdf if ($this->onlyLeft) { $this->value['text-align'] = 'left'; } // correction on the width (quick box) if ($noWidth && in_array($tagName, array('div', 'blockquote', 'fieldset')) && $this->value['position'] != 'absolute') { $this->value['width'] = $this->getLastWidth(); $this->value['width'] -= $this->value['margin']['l'] + $this->value['margin']['r']; } else { if ($correctWidth) { if (!in_array($tagName, array('table', 'div', 'blockquote', 'fieldset', 'hr'))) { $this->value['width'] -= $this->value['padding']['l'] + $this->value['padding']['r']; $this->value['width'] -= $this->value['border']['l']['width'] + $this->value['border']['r']['width']; } if (in_array($tagName, array('th', 'td'))) { $this->value['width'] -= $this->cssConverter->convertToMM(isset($param['cellspacing']) ? $param['cellspacing'] : '2px'); $return = false; } if ($this->value['width'] < 0) { $this->value['width'] = 0; } } else { if ($this->value['width']) { if ($this->value['border']['l']['width']) { $this->value['width'] += $this->value['border']['l']['width']; } if ($this->value['border']['r']['width']) { $this->value['width'] += $this->value['border']['r']['width']; } if ($this->value['padding']['l']) { $this->value['width'] += $this->value['padding']['l']; } if ($this->value['padding']['r']) { $this->value['width'] += $this->value['padding']['r']; } } } } if ($this->value['height']) { if ($this->value['border']['b']['width']) { $this->value['height'] += $this->value['border']['b']['width']; } if ($this->value['border']['t']['width']) { $this->value['height'] += $this->value['border']['t']['width']; } if ($this->value['padding']['b']) { $this->value['height'] += $this->value['padding']['b']; } if ($this->value['padding']['t']) { $this->value['height'] += $this->value['padding']['t']; } } if ($this->value['top'] != null) { $this->value['top'] = $this->cssConverter->convertToMM($this->value['top'], $this->getLastHeight(true)); } if ($this->value['bottom'] != null) { $this->value['bottom'] = $this->cssConverter->convertToMM($this->value['bottom'], $this->getLastHeight(true)); } if ($this->value['left'] != null) { $this->value['left'] = $this->cssConverter->convertToMM($this->value['left'], $this->getLastWidth(true)); } if ($this->value['right'] != null) { $this->value['right'] = $this->cssConverter->convertToMM($this->value['right'], $this->getLastWidth(true)); } if ($this->value['top'] && $this->value['bottom'] && $this->value['height']) { $this->value['bottom'] = null; } if ($this->value['left'] && $this->value['right'] && $this->value['width']) { $this->value['right'] = null; } return $return; }