/** * Process opening tags. * @param $dom (array) html dom array * @param $key (int) current element id * @param $cell (boolean) if true add the default left (or right if RTL) padding to each new line (default false). * @return $dom array * @protected */ protected function openHTMLTagHandler($dom, $key, $cell) { $tag = $dom[$key]; $parent = $dom[$dom[$key]['parent']]; $firsttag = $key == 1; // check for text direction attribute if (isset($tag['dir'])) { $this->setTempRTL($tag['dir']); } else { $this->tmprtl = false; } if ($tag['block']) { $hbz = 0; // distance from y to line bottom $hb = 0; // vertical space between block tags // calculate vertical space for block tags if (isset($this->tagvspaces[$tag['value']][0]['h']) and $this->tagvspaces[$tag['value']][0]['h'] >= 0) { $cur_h = $this->tagvspaces[$tag['value']][0]['h']; } elseif (isset($tag['fontsize'])) { $cur_h = $this->getCellHeight($tag['fontsize'] / $this->k); } else { $cur_h = $this->getCellHeight($this->FontSize); } if (isset($this->tagvspaces[$tag['value']][0]['n'])) { $on = $this->tagvspaces[$tag['value']][0]['n']; } elseif (preg_match('/[h][0-9]/', $tag['value']) > 0) { $on = 0.6; } else { $on = 1; } if (!isset($this->tagvspaces[$tag['value']]) and in_array($tag['value'], array('div', 'dt', 'dd', 'li', 'br', 'hr'))) { $hb = 0; } else { $hb = $on * $cur_h; } if ($this->htmlvspace <= 0 and $on > 0) { if (isset($parent['fontsize'])) { $hbz = $parent['fontsize'] / $this->k * $this->cell_height_ratio; } else { $hbz = $this->getCellHeight($this->FontSize); } } if (isset($dom[$key - 1]) and $dom[$key - 1]['value'] == 'table') { // fix vertical space after table $hbz = 0; } // closing vertical space $hbc = 0; if (isset($this->tagvspaces[$tag['value']][1]['h']) and $this->tagvspaces[$tag['value']][1]['h'] >= 0) { $pre_h = $this->tagvspaces[$tag['value']][1]['h']; } elseif (isset($parent['fontsize'])) { $pre_h = $this->getCellHeight($parent['fontsize'] / $this->k); } else { $pre_h = $this->getCellHeight($this->FontSize); } if (isset($this->tagvspaces[$tag['value']][1]['n'])) { $cn = $this->tagvspaces[$tag['value']][1]['n']; } elseif (preg_match('/[h][0-9]/', $tag['value']) > 0) { $cn = 0.6; } else { $cn = 1; } if (isset($this->tagvspaces[$tag['value']][1])) { $hbc = $cn * $pre_h; } } // Opening tag switch ($tag['value']) { case 'table': $cp = 0; $cs = 0; $dom[$key]['rowspans'] = array(); if (!isset($dom[$key]['attribute']['nested']) or $dom[$key]['attribute']['nested'] != 'true') { $this->htmlvspace = 0; // set table header if (!TCPDF_STATIC::empty_string($dom[$key]['thead'])) { // set table header $this->thead = $dom[$key]['thead']; if (!isset($this->theadMargins) or empty($this->theadMargins)) { $this->theadMargins = array(); $this->theadMargins['cell_padding'] = $this->cell_padding; $this->theadMargins['lmargin'] = $this->lMargin; $this->theadMargins['rmargin'] = $this->rMargin; $this->theadMargins['page'] = $this->page; $this->theadMargins['cell'] = $cell; $this->theadMargins['gvars'] = $this->getGraphicVars(); } } } // store current margins and page $dom[$key]['old_cell_padding'] = $this->cell_padding; if (isset($tag['attribute']['cellpadding'])) { $pad = $this->getHTMLUnitToUnits($tag['attribute']['cellpadding'], 1, 'px'); $this->SetCellPadding($pad); } elseif (isset($tag['padding'])) { $this->cell_padding = $tag['padding']; } if (isset($tag['attribute']['cellspacing'])) { $cs = $this->getHTMLUnitToUnits($tag['attribute']['cellspacing'], 1, 'px'); } elseif (isset($tag['border-spacing'])) { $cs = $tag['border-spacing']['V']; } $prev_y = $this->y; if ($this->checkPageBreak(2 * $cp + 2 * $cs + $this->lasth, '', false) or $this->y < $prev_y) { $this->inthead = true; // add a page (or trig AcceptPageBreak() for multicolumn mode) $this->checkPageBreak($this->PageBreakTrigger + 1); } break; case 'tr': // array of columns positions $dom[$key]['cellpos'] = array(); break; case 'hr': if (isset($tag['height']) and $tag['height'] != '') { $hrHeight = $this->getHTMLUnitToUnits($tag['height'], 1, 'px'); } else { $hrHeight = $this->GetLineWidth(); } $this->addHTMLVertSpace($hbz, max($hb, $hrHeight / 2), $cell, $firsttag); $x = $this->GetX(); $y = $this->GetY(); $wtmp = $this->w - $this->lMargin - $this->rMargin; if ($cell) { $wtmp -= $this->cell_padding['L'] + $this->cell_padding['R']; } if (isset($tag['width']) and $tag['width'] != '') { $hrWidth = $this->getHTMLUnitToUnits($tag['width'], $wtmp, 'px'); } else { $hrWidth = $wtmp; } $prevlinewidth = $this->GetLineWidth(); $this->SetLineWidth($hrHeight); $this->Line($x, $y, $x + $hrWidth, $y); $this->SetLineWidth($prevlinewidth); $this->addHTMLVertSpace(max($hbc, $hrHeight / 2), 0, $cell, !isset($dom[$key + 1])); break; case 'a': if (array_key_exists('href', $tag['attribute'])) { $this->HREF['url'] = $tag['attribute']['href']; } break; case 'img': if (!empty($tag['attribute']['src'])) { if ($tag['attribute']['src'][0] === '@') { // data stream $tag['attribute']['src'] = '@' . base64_decode(substr($tag['attribute']['src'], 1)); $type = ''; } else { // get image type $type = TCPDF_IMAGES::getImageFileType($tag['attribute']['src']); } if (!isset($tag['width'])) { $tag['width'] = 0; } if (!isset($tag['height'])) { $tag['height'] = 0; } //if (!isset($tag['attribute']['align'])) { // the only alignment supported is "bottom" // further development is required for other modes. $tag['attribute']['align'] = 'bottom'; //} switch ($tag['attribute']['align']) { case 'top': $align = 'T'; break; case 'middle': $align = 'M'; break; case 'bottom': $align = 'B'; break; default: $align = 'B'; break; } $prevy = $this->y; $xpos = $this->x; $imglink = ''; if (isset($this->HREF['url']) and !TCPDF_STATIC::empty_string($this->HREF['url'])) { $imglink = $this->HREF['url']; if ($imglink[0] == '#') { // convert url to internal link $lnkdata = explode(',', $imglink); if (isset($lnkdata[0])) { $page = intval(substr($lnkdata[0], 1)); if (empty($page) or $page <= 0) { $page = $this->page; } if (isset($lnkdata[1]) and strlen($lnkdata[1]) > 0) { $lnky = floatval($lnkdata[1]); } else { $lnky = 0; } $imglink = $this->AddLink(); $this->SetLink($imglink, $lnky, $page); } } } $border = 0; if (isset($tag['border']) and !empty($tag['border'])) { // currently only support 1 (frame) or a combination of 'LTRB' $border = $tag['border']; } $iw = ''; if (isset($tag['width'])) { $iw = $this->getHTMLUnitToUnits($tag['width'], $tag['fontsize'] / $this->k, 'px', false); } $ih = ''; if (isset($tag['height'])) { $ih = $this->getHTMLUnitToUnits($tag['height'], $tag['fontsize'] / $this->k, 'px', false); } if ($type == 'eps' or $type == 'ai') { $this->ImageEps($tag['attribute']['src'], $xpos, $this->y, $iw, $ih, $imglink, true, $align, '', $border, true); } elseif ($type == 'svg') { $this->ImageSVG($tag['attribute']['src'], $xpos, $this->y, $iw, $ih, $imglink, $align, '', $border, true); } else { $this->Image($tag['attribute']['src'], $xpos, $this->y, $iw, $ih, '', $imglink, $align, false, 300, '', false, false, $border, false, false, true); } switch ($align) { case 'T': $this->y = $prevy; break; case 'M': $this->y = ($this->img_rb_y + $prevy - $this->getCellHeight($tag['fontsize'] / $this->k)) / 2; break; case 'B': $this->y = $this->img_rb_y - ($this->getCellHeight($tag['fontsize'] / $this->k) - $this->getFontDescent($tag['fontname'], $tag['fontstyle'], $tag['fontsize']) * $this->cell_height_ratio); break; } } break; case 'dl': ++$this->listnum; if ($this->listnum == 1) { $this->addHTMLVertSpace($hbz, $hb, $cell, $firsttag); } else { $this->addHTMLVertSpace(0, 0, $cell, $firsttag); } break; case 'dt': $this->addHTMLVertSpace($hbz, $hb, $cell, $firsttag); break; case 'dd': if ($this->rtl) { $this->rMargin += $this->listindent; } else { $this->lMargin += $this->listindent; } ++$this->listindentlevel; $this->addHTMLVertSpace($hbz, $hb, $cell, $firsttag); break; case 'ul': case 'ol': ++$this->listnum; if ($tag['value'] == 'ol') { $this->listordered[$this->listnum] = true; } else { $this->listordered[$this->listnum] = false; } if (isset($tag['attribute']['start'])) { $this->listcount[$this->listnum] = intval($tag['attribute']['start']) - 1; } else { $this->listcount[$this->listnum] = 0; } if ($this->rtl) { $this->rMargin += $this->listindent; $this->x -= $this->listindent; } else { $this->lMargin += $this->listindent; $this->x += $this->listindent; } ++$this->listindentlevel; if ($this->listnum == 1) { if ($key > 1) { $this->addHTMLVertSpace($hbz, $hb, $cell, $firsttag); } } else { $this->addHTMLVertSpace(0, 0, $cell, $firsttag); } break; case 'li': if ($key > 2) { $this->addHTMLVertSpace($hbz, $hb, $cell, $firsttag); } if ($this->listordered[$this->listnum]) { // ordered item if (isset($parent['attribute']['type']) and !TCPDF_STATIC::empty_string($parent['attribute']['type'])) { $this->lispacer = $parent['attribute']['type']; } elseif (isset($parent['listtype']) and !TCPDF_STATIC::empty_string($parent['listtype'])) { $this->lispacer = $parent['listtype']; } elseif (isset($this->lisymbol) and !TCPDF_STATIC::empty_string($this->lisymbol)) { $this->lispacer = $this->lisymbol; } else { $this->lispacer = '#'; } ++$this->listcount[$this->listnum]; if (isset($tag['attribute']['value'])) { $this->listcount[$this->listnum] = intval($tag['attribute']['value']); } } else { // unordered item if (isset($parent['attribute']['type']) and !TCPDF_STATIC::empty_string($parent['attribute']['type'])) { $this->lispacer = $parent['attribute']['type']; } elseif (isset($parent['listtype']) and !TCPDF_STATIC::empty_string($parent['listtype'])) { $this->lispacer = $parent['listtype']; } elseif (isset($this->lisymbol) and !TCPDF_STATIC::empty_string($this->lisymbol)) { $this->lispacer = $this->lisymbol; } else { $this->lispacer = '!'; } } break; case 'blockquote': if ($this->rtl) { $this->rMargin += $this->listindent; } else { $this->lMargin += $this->listindent; } ++$this->listindentlevel; $this->addHTMLVertSpace($hbz, $hb, $cell, $firsttag); break; case 'br': $this->addHTMLVertSpace($hbz, $hb, $cell, $firsttag); break; case 'div': $this->addHTMLVertSpace($hbz, $hb, $cell, $firsttag); break; case 'p': $this->addHTMLVertSpace($hbz, $hb, $cell, $firsttag); break; case 'pre': $this->addHTMLVertSpace($hbz, $hb, $cell, $firsttag); $this->premode = true; break; case 'sup': $this->SetXY($this->GetX(), $this->GetY() - 0.7 * $this->FontSizePt / $this->k); break; case 'sub': $this->SetXY($this->GetX(), $this->GetY() + 0.3 * $this->FontSizePt / $this->k); break; case 'h1': case 'h2': case 'h3': case 'h4': case 'h5': case 'h6': $this->addHTMLVertSpace($hbz, $hb, $cell, $firsttag); break; // Form fields (since 4.8.000 - 2009-09-07) // Form fields (since 4.8.000 - 2009-09-07) case 'form': if (isset($tag['attribute']['action'])) { $this->form_action = $tag['attribute']['action']; } else { $this->Error('Please explicitly set action attribute path!'); } if (isset($tag['attribute']['enctype'])) { $this->form_enctype = $tag['attribute']['enctype']; } else { $this->form_enctype = 'application/x-www-form-urlencoded'; } if (isset($tag['attribute']['method'])) { $this->form_mode = $tag['attribute']['method']; } else { $this->form_mode = 'post'; } break; case 'input': if (isset($tag['attribute']['name']) and !TCPDF_STATIC::empty_string($tag['attribute']['name'])) { $name = $tag['attribute']['name']; } else { break; } $prop = array(); $opt = array(); if (isset($tag['attribute']['readonly']) and !TCPDF_STATIC::empty_string($tag['attribute']['readonly'])) { $prop['readonly'] = true; } if (isset($tag['attribute']['value']) and !TCPDF_STATIC::empty_string($tag['attribute']['value'])) { $value = $tag['attribute']['value']; } if (isset($tag['attribute']['maxlength']) and !TCPDF_STATIC::empty_string($tag['attribute']['maxlength'])) { $opt['maxlen'] = intval($tag['attribute']['maxlength']); } $h = $this->getCellHeight($this->FontSize); if (isset($tag['attribute']['size']) and !TCPDF_STATIC::empty_string($tag['attribute']['size'])) { $w = intval($tag['attribute']['size']) * $this->GetStringWidth(chr(32)) * 2; } else { $w = $h; } if (isset($tag['attribute']['checked']) and ($tag['attribute']['checked'] == 'checked' or $tag['attribute']['checked'] == 'true')) { $checked = true; } else { $checked = false; } if (isset($tag['align'])) { switch ($tag['align']) { case 'C': $opt['q'] = 1; break; case 'R': $opt['q'] = 2; break; case 'L': default: break; } } switch ($tag['attribute']['type']) { case 'text': if (isset($value)) { $opt['v'] = $value; } $this->TextField($name, $w, $h, $prop, $opt, '', '', false); break; case 'password': if (isset($value)) { $opt['v'] = $value; } $prop['password'] = '******'; $this->TextField($name, $w, $h, $prop, $opt, '', '', false); break; case 'checkbox': if (!isset($value)) { break; } $this->CheckBox($name, $w, $checked, $prop, $opt, $value, '', '', false); break; case 'radio': if (!isset($value)) { break; } $this->RadioButton($name, $w, $prop, $opt, $value, $checked, '', '', false); break; case 'submit': if (!isset($value)) { $value = 'submit'; } $w = $this->GetStringWidth($value) * 1.5; $h *= 1.6; $prop = array('lineWidth' => 1, 'borderStyle' => 'beveled', 'fillColor' => array(196, 196, 196), 'strokeColor' => array(255, 255, 255)); $action = array(); $action['S'] = 'SubmitForm'; $action['F'] = $this->form_action; if ($this->form_enctype != 'FDF') { $action['Flags'] = array('ExportFormat'); } if ($this->form_mode == 'get') { $action['Flags'] = array('GetMethod'); } $this->Button($name, $w, $h, $value, $action, $prop, $opt, '', '', false); break; case 'reset': if (!isset($value)) { $value = 'reset'; } $w = $this->GetStringWidth($value) * 1.5; $h *= 1.6; $prop = array('lineWidth' => 1, 'borderStyle' => 'beveled', 'fillColor' => array(196, 196, 196), 'strokeColor' => array(255, 255, 255)); $this->Button($name, $w, $h, $value, array('S' => 'ResetForm'), $prop, $opt, '', '', false); break; case 'file': $prop['fileSelect'] = 'true'; $this->TextField($name, $w, $h, $prop, $opt, '', '', false); if (!isset($value)) { $value = '*'; } $w = $this->GetStringWidth($value) * 2; $h *= 1.2; $prop = array('lineWidth' => 1, 'borderStyle' => 'beveled', 'fillColor' => array(196, 196, 196), 'strokeColor' => array(255, 255, 255)); $jsaction = 'var f=this.getField(\'' . $name . '\'); f.browseForFileToSubmit();'; $this->Button('FB_' . $name, $w, $h, $value, $jsaction, $prop, $opt, '', '', false); break; case 'hidden': if (isset($value)) { $opt['v'] = $value; } $opt['f'] = array('invisible', 'hidden'); $this->TextField($name, 0, 0, $prop, $opt, '', '', false); break; case 'image': // THIS TYPE MUST BE FIXED if (isset($tag['attribute']['src']) and !TCPDF_STATIC::empty_string($tag['attribute']['src'])) { $img = $tag['attribute']['src']; } else { break; } $value = 'img'; //$opt['mk'] = array('i'=>$img, 'tp'=>1, 'if'=>array('sw'=>'A', 's'=>'A', 'fb'=>false)); if (isset($tag['attribute']['onclick']) and !empty($tag['attribute']['onclick'])) { $jsaction = $tag['attribute']['onclick']; } else { $jsaction = ''; } $this->Button($name, $w, $h, $value, $jsaction, $prop, $opt, '', '', false); break; case 'button': if (!isset($value)) { $value = ' '; } $w = $this->GetStringWidth($value) * 1.5; $h *= 1.6; $prop = array('lineWidth' => 1, 'borderStyle' => 'beveled', 'fillColor' => array(196, 196, 196), 'strokeColor' => array(255, 255, 255)); if (isset($tag['attribute']['onclick']) and !empty($tag['attribute']['onclick'])) { $jsaction = $tag['attribute']['onclick']; } else { $jsaction = ''; } $this->Button($name, $w, $h, $value, $jsaction, $prop, $opt, '', '', false); break; } break; case 'textarea': $prop = array(); $opt = array(); if (isset($tag['attribute']['readonly']) and !TCPDF_STATIC::empty_string($tag['attribute']['readonly'])) { $prop['readonly'] = true; } if (isset($tag['attribute']['name']) and !TCPDF_STATIC::empty_string($tag['attribute']['name'])) { $name = $tag['attribute']['name']; } else { break; } if (isset($tag['attribute']['value']) and !TCPDF_STATIC::empty_string($tag['attribute']['value'])) { $opt['v'] = $tag['attribute']['value']; } if (isset($tag['attribute']['cols']) and !TCPDF_STATIC::empty_string($tag['attribute']['cols'])) { $w = intval($tag['attribute']['cols']) * $this->GetStringWidth(chr(32)) * 2; } else { $w = 40; } if (isset($tag['attribute']['rows']) and !TCPDF_STATIC::empty_string($tag['attribute']['rows'])) { $h = intval($tag['attribute']['rows']) * $this->getCellHeight($this->FontSize); } else { $h = 10; } $prop['multiline'] = 'true'; $this->TextField($name, $w, $h, $prop, $opt, '', '', false); break; case 'select': $h = $this->getCellHeight($this->FontSize); if (isset($tag['attribute']['size']) and !TCPDF_STATIC::empty_string($tag['attribute']['size'])) { $h *= $tag['attribute']['size'] + 1; } $prop = array(); $opt = array(); if (isset($tag['attribute']['name']) and !TCPDF_STATIC::empty_string($tag['attribute']['name'])) { $name = $tag['attribute']['name']; } else { break; } $w = 0; if (isset($tag['attribute']['opt']) and !TCPDF_STATIC::empty_string($tag['attribute']['opt'])) { $options = explode('#!NwL!#', $tag['attribute']['opt']); $values = array(); foreach ($options as $val) { if (strpos($val, '#!TaB!#') !== false) { $opts = explode('#!TaB!#', $val); $values[] = $opts; $w = max($w, $this->GetStringWidth($opts[1])); } else { $values[] = $val; $w = max($w, $this->GetStringWidth($val)); } } } else { break; } $w *= 2; if (isset($tag['attribute']['multiple']) and $tag['attribute']['multiple'] = 'multiple') { $prop['multipleSelection'] = 'true'; $this->ListBox($name, $w, $h, $values, $prop, $opt, '', '', false); } else { $this->ComboBox($name, $w, $h, $values, $prop, $opt, '', '', false); } break; case 'tcpdf': if (defined('K_TCPDF_CALLS_IN_HTML') and K_TCPDF_CALLS_IN_HTML === true) { // Special tag used to call TCPDF methods if (isset($tag['attribute']['method'])) { $tcpdf_method = $tag['attribute']['method']; if (method_exists($this, $tcpdf_method)) { if (isset($tag['attribute']['params']) and !empty($tag['attribute']['params'])) { $params = TCPDF_STATIC::unserializeTCPDFtagParameters($tag['attribute']['params']); call_user_func_array(array($this, $tcpdf_method), $params); } else { $this->{$tcpdf_method}(); } $this->newline = true; } } } break; default: break; } // define tags that support borders and background colors $bordertags = array('blockquote', 'br', 'dd', 'dl', 'div', 'dt', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'li', 'ol', 'p', 'pre', 'ul', 'tcpdf', 'table'); if (in_array($tag['value'], $bordertags)) { // set border $dom[$key]['borderposition'] = $this->getBorderStartPosition(); } if ($dom[$key]['self'] and isset($dom[$key]['attribute']['pagebreakafter'])) { $pba = $dom[$key]['attribute']['pagebreakafter']; // check for pagebreak if ($pba == 'true' or $pba == 'left' or $pba == 'right') { // add a page (or trig AcceptPageBreak() for multicolumn mode) $this->checkPageBreak($this->PageBreakTrigger + 1); } if ($pba == 'left' and (!$this->rtl and $this->page % 2 == 0 or $this->rtl and $this->page % 2 != 0) or $pba == 'right' and (!$this->rtl and $this->page % 2 != 0 or $this->rtl and $this->page % 2 == 0)) { // add a page (or trig AcceptPageBreak() for multicolumn mode) $this->checkPageBreak($this->PageBreakTrigger + 1); } } return $dom; }