|
|
';
}
echo ' |
|
tag if ($ln > 0) { //Go to next line $this->y += $h; if ($ln == 1) { //Move to next line if ($currentx != 0) { $this->x = $currentx; } else { $this->x = $this->lMargin; } } } else $this->x+=$w; } function applyGPOSpdf($txt, $aix, $x, $y, $OTLdata, $textvar = 0) { // Generate PDF string //============================== if ((isset($this->CurrentFont['sip']) && $this->CurrentFont['sip']) || (isset($this->CurrentFont['smp']) && $this->CurrentFont['smp'])) { $sipset = true; } else { $sipset = false; } if ($textvar & FC_SMALLCAPS) { $smcaps = true; } // IF SmallCaps using transformation, NOT OTL else { $smcaps = false; } if ($sipset) { $fontid = $last_fontid = $original_fontid = $this->CurrentFont['subsetfontids'][0]; } else { $fontid = $last_fontid = $original_fontid = $this->CurrentFont['i']; } $SmallCapsON = false; // state: uppercase/not $lastSmallCapsON = false; // state: uppercase/not $last_fontsize = $fontsize = $this->FontSizePt; $last_fontstretch = $fontstretch = 100; $groupBreak = false; $unicode = $this->UTF8StringToArray($txt); $GPOSinfo = (isset($OTLdata['GPOSinfo']) ? $OTLdata['GPOSinfo'] : array()); $charspacing = ($this->charspacing * 1000 / $this->FontSizePt); $wordspacing = ($this->ws * 1000 / $this->FontSizePt); $XshiftBefore = 0; $XshiftAfter = 0; $lastYPlacement = 0; if ($sipset) { // mPDF 6 DELETED ******** // $txt= preg_replace('/'.preg_quote($this->aliasNbPg,'/').'/', chr(7), $txt); // ? Need to adjust OTL info // $txt= preg_replace('/'.preg_quote($this->aliasNbPgGp,'/').'/', chr(8), $txt); // ? Need to adjust OTL info $tj = '<'; } else { $tj = '('; } for ($i = 0; $i < count($unicode); $i++) { $c = $unicode[$i]; $tx = ''; $XshiftBefore = $XshiftAfter; $XshiftAfter = 0; $YPlacement = 0; $groupBreak = false; $kashida = 0; if (!empty($OTLdata)) { // YPlacement from GPOS if (isset($GPOSinfo[$i]['YPlacement']) && $GPOSinfo[$i]['YPlacement']) { $YPlacement = $GPOSinfo[$i]['YPlacement'] * $this->FontSizePt / $this->CurrentFont['unitsPerEm']; $groupBreak = true; } // XPlacement from GPOS if (isset($GPOSinfo[$i]['XPlacement']) && $GPOSinfo[$i]['XPlacement']) { if (!isset($GPOSinfo[$i]['wDir']) || $GPOSinfo[$i]['wDir'] != 'RTL') { if (isset($GPOSinfo[$i]['BaseWidth'])) { $GPOSinfo[$i]['XPlacement'] -= $GPOSinfo[$i]['BaseWidth']; } } // Convert to PDF Text space (thousandths of a unit ); $XshiftBefore += $GPOSinfo[$i]['XPlacement'] * 1000 / $this->CurrentFont['unitsPerEm']; $XshiftAfter += -$GPOSinfo[$i]['XPlacement'] * 1000 / $this->CurrentFont['unitsPerEm']; } // Kashida from GPOS // Kashida is set as an absolute length value, but to adjust text needs to be converted to // font-related size if (isset($GPOSinfo[$i]['kashida_space']) && $GPOSinfo[$i]['kashida_space']) { $kashida = $GPOSinfo[$i]['kashida_space']; } if ($c == 32) { // word spacing $XshiftAfter += $wordspacing; } if (substr($OTLdata['group'], ($i + 1), 1) != 'M') { // Don't add inter-character spacing before Marks $XshiftAfter += $charspacing; } // ...applyGPOSpdf... // XAdvance from GPOS - Convert to PDF Text space (thousandths of a unit ); if (((isset($GPOSinfo[$i]['wDir']) && $GPOSinfo[$i]['wDir'] != 'RTL') || !isset($GPOSinfo[$i]['wDir'])) && isset($GPOSinfo[$i]['XAdvanceL']) && $GPOSinfo[$i]['XAdvanceL']) { $XshiftAfter += $GPOSinfo[$i]['XAdvanceL'] * 1000 / $this->CurrentFont['unitsPerEm']; } elseif (isset($GPOSinfo[$i]['wDir']) && $GPOSinfo[$i]['wDir'] == 'RTL' && isset($GPOSinfo[$i]['XAdvanceR']) && $GPOSinfo[$i]['XAdvanceR']) { $XshiftAfter += $GPOSinfo[$i]['XAdvanceR'] * 1000 / $this->CurrentFont['unitsPerEm']; } } // Character & Word spacing - if NOT OTL else { $XshiftAfter += $charspacing; if ($c == 32) { $XshiftAfter += $wordspacing; } } // IF Kerning done using pairs rather than OTL if ($textvar & FC_KERNING) { if ($i > 0 && isset($this->CurrentFont['kerninfo'][$unicode[($i - 1)]][$unicode[$i]])) { $XshiftBefore += $this->CurrentFont['kerninfo'][$unicode[($i - 1)]][$unicode[$i]]; } } if ($YPlacement != $lastYPlacement) { $groupBreak = true; } if ($XshiftBefore) { // +ve value in PDF moves to the left // If Fontstretch is ongoing, need to adjust X adjustments because these will be stretched out. $XshiftBefore *= 100 / $last_fontstretch; if ($sipset) { $tj .= sprintf('>%d<', (-$XshiftBefore)); } else { $tj .= sprintf(')%d(', (-$XshiftBefore)); } } // Small-Caps if ($smcaps) { if (isset($this->upperCase[$c])) { $c = $this->upperCase[$c]; //$this->CurrentFont['subset'][$this->upperCase[$c]] = $this->upperCase[$c]; // add the CAP to subset $SmallCapsON = true; // For $sipset if (!$lastSmallCapsON) { // Turn ON SmallCaps $groupBreak = true; $fontstretch = $this->smCapsStretch; $fontsize = $this->FontSizePt * $this->smCapsScale; } } else { $SmallCapsON = false; if ($lastSmallCapsON) { // Turn OFF SmallCaps $groupBreak = true; $fontstretch = 100; $fontsize = $this->FontSizePt; } } } // Prepare Text and Select Font ID if ($sipset) { // mPDF 6 DELETED ******** //if ($c == 7 || $c == 8) { // if ($original_fontid != $last_fontid) { // $groupBreak = true; // $fontid = $original_fontid; // } // if ($c == 7) { $tj .= $this->aliasNbPgHex; } // else { $tj .= $this->aliasNbPgGpHex; } // continue; //} for ($j = 0; $j < 99; $j++) { $init = array_search($c, $this->CurrentFont['subsets'][$j]); if ($init !== false) { if ($this->CurrentFont['subsetfontids'][$j] != $last_fontid) { $groupBreak = true; $fontid = $this->CurrentFont['subsetfontids'][$j]; } $tx = sprintf("%02s", strtoupper(dechex($init))); break; } elseif (count($this->CurrentFont['subsets'][$j]) < 255) { $n = count($this->CurrentFont['subsets'][$j]); $this->CurrentFont['subsets'][$j][$n] = $c; if ($this->CurrentFont['subsetfontids'][$j] != $last_fontid) { $groupBreak = true; $fontid = $this->CurrentFont['subsetfontids'][$j]; } $tx = sprintf("%02s", strtoupper(dechex($n))); break; } elseif (!isset($this->CurrentFont['subsets'][($j + 1)])) { $this->CurrentFont['subsets'][($j + 1)] = array(0 => 0); $this->CurrentFont['subsetfontids'][($j + 1)] = count($this->fonts) + $this->extraFontSubsets + 1; $this->extraFontSubsets++; } } } else { $tx = code2utf($c); if ($this->usingCoreFont) { $tx = utf8_decode($tx); } else { $tx = $this->UTF8ToUTF16BE($tx, false); } $tx = $this->_escape($tx); } // If any settings require a new Text Group if ($groupBreak || $fontstretch != $last_fontstretch) { if ($sipset) { $tj .= '>] TJ '; } else { $tj .= ')] TJ '; } if ($fontid != $last_fontid || $fontsize != $last_fontsize) { $tj .= sprintf(' /F%d %.3F Tf ', $fontid, $fontsize); } if ($fontstretch != $last_fontstretch) { $tj .= sprintf('%d Tz ', $fontstretch); } if ($YPlacement != $lastYPlacement) { $tj .= sprintf('%.3F Ts ', $YPlacement); } if ($sipset) { $tj .= '[<'; } else { $tj .= '[('; } } // Output the code for the txt character $tj .= $tx; $lastSmallCapsON = $SmallCapsON; $last_fontid = $fontid; $last_fontsize = $fontsize; $last_fontstretch = $fontstretch; // Kashida if ($kashida) { $c = 0x0640; // add the Tatweel U+0640 if (isset($this->CurrentFont['subset'])) { $this->CurrentFont['subset'][$c] = $c; } $kashida *= 1000 / $this->FontSizePt; $tatw = $this->_getCharWidth($this->CurrentFont['cw'], 0x0640); // Get YPlacement from next Base character $nextbase = $i + 1; while ($OTLdata['group']{$nextbase} != 'C') { $nextbase++; } if (isset($GPOSinfo[$nextbase]) && isset($GPOSinfo[$nextbase]['YPlacement']) && $GPOSinfo[$nextbase]['YPlacement']) { $YPlacement = $GPOSinfo[$nextbase]['YPlacement'] * $this->FontSizePt / $this->CurrentFont['unitsPerEm']; } // Prepare Text and Select Font ID if ($sipset) { for ($j = 0; $j < 99; $j++) { $init = array_search($c, $this->CurrentFont['subsets'][$j]); if ($init !== false) { if ($this->CurrentFont['subsetfontids'][$j] != $last_fontid) { $fontid = $this->CurrentFont['subsetfontids'][$j]; } $tx = sprintf("%02s", strtoupper(dechex($init))); break; } elseif (count($this->CurrentFont['subsets'][$j]) < 255) { $n = count($this->CurrentFont['subsets'][$j]); $this->CurrentFont['subsets'][$j][$n] = $c; if ($this->CurrentFont['subsetfontids'][$j] != $last_fontid) { $fontid = $this->CurrentFont['subsetfontids'][$j]; } $tx = sprintf("%02s", strtoupper(dechex($n))); break; } elseif (!isset($this->CurrentFont['subsets'][($j + 1)])) { $this->CurrentFont['subsets'][($j + 1)] = array(0 => 0); $this->CurrentFont['subsetfontids'][($j + 1)] = count($this->fonts) + $this->extraFontSubsets + 1; $this->extraFontSubsets++; } } } else { $tx = code2utf($c); $tx = $this->UTF8ToUTF16BE($tx, false); $tx = $this->_escape($tx); } if ($kashida > $tatw) { // Insert multiple tatweel characters, repositioning the last one to give correct total length $fontstretch = 100; $nt = intval($kashida / $tatw); $nudgeback = (($nt + 1) * $tatw) - $kashida; $optx = str_repeat($tx, $nt); if ($sipset) { $optx .= sprintf('>%d<', ($nudgeback)); } else { $optx .= sprintf(')%d(', ($nudgeback)); } $optx .= $tx; // #last } else { // Insert single tatweel character and use fontstretch to get correct length $fontstretch = ($kashida / $tatw) * 100; $optx = $tx; } if ($sipset) { $tj .= '>] TJ '; } else { $tj .= ')] TJ '; } if ($fontid != $last_fontid || $fontsize != $last_fontsize) { $tj .= sprintf(' /F%d %.3F Tf ', $fontid, $fontsize); } if ($fontstretch != $last_fontstretch) { $tj .= sprintf('%d Tz ', $fontstretch); } $tj .= sprintf('%.3F Ts ', $YPlacement); if ($sipset) { $tj .= '[<'; } else { $tj .= '[('; } // Output the code for the txt character(s) $tj .= $optx; $last_fontid = $fontid; $last_fontstretch = $fontstretch; $fontstretch = 100; } $lastYPlacement = $YPlacement; } // Finish up if ($sipset) { $tj .= '>'; if ($XshiftAfter) { $tj .= sprintf('%d', (-$XshiftAfter)); } if ($last_fontid != $original_fontid) { $tj .= '] TJ '; $tj .= sprintf(' /F%d %.3F Tf ', $original_fontid, $fontsize); $tj .= '['; } $tj = preg_replace('/([^\\\])<>/', '\\1 ', $tj); } else { $tj .= ')'; if ($XshiftAfter) { $tj .= sprintf('%d', (-$XshiftAfter)); } if ($last_fontid != $original_fontid) { $tj .= '] TJ '; $tj .= sprintf(' /F%d %.3F Tf ', $original_fontid, $fontsize); $tj .= '['; } $tj = preg_replace('/([^\\\])\(\)/', '\\1 ', $tj); } $s = sprintf(' BT ' . $aix . ' 0 Tc 0 Tw [%s] TJ ET ', $x, $y, $tj); //echo $s."\n\n"; // exit; return $s; } function _kern($txt, $mode, $aix, $x, $y) { if ($mode == 'MBTw') { // Multibyte requiring word spacing $space = ' '; //Convert string to UTF-16BE without BOM $space = $this->UTF8ToUTF16BE($space, false); $space = $this->_escape($space); $s = sprintf(' BT ' . $aix, $x * _MPDFK, ($this->h - $y) * _MPDFK); $t = explode(' ', $txt); for ($i = 0; $i < count($t); $i++) { $tx = $t[$i]; $tj = '('; $unicode = $this->UTF8StringToArray($tx); for ($ti = 0; $ti < count($unicode); $ti++) { if ($ti > 0 && isset($this->CurrentFont['kerninfo'][$unicode[($ti - 1)]][$unicode[$ti]])) { $kern = -$this->CurrentFont['kerninfo'][$unicode[($ti - 1)]][$unicode[$ti]]; $tj .= sprintf(')%d(', $kern); } $tc = code2utf($unicode[$ti]); $tc = $this->UTF8ToUTF16BE($tc, false); $tj .= $this->_escape($tc); } $tj .= ')'; $s.=sprintf(' %.3F Tc [%s] TJ', $this->charspacing, $tj); if (($i + 1) < count($t)) { $s.=sprintf(' %.3F Tc (%s) Tj', $this->ws + $this->charspacing, $space); } } $s.=' ET '; } elseif (!$this->usingCoreFont) { $s = ''; $tj = '('; $unicode = $this->UTF8StringToArray($txt); for ($i = 0; $i < count($unicode); $i++) { if ($i > 0 && isset($this->CurrentFont['kerninfo'][$unicode[($i - 1)]][$unicode[$i]])) { $kern = -$this->CurrentFont['kerninfo'][$unicode[($i - 1)]][$unicode[$i]]; $tj .= sprintf(')%d(', $kern); } $tx = code2utf($unicode[$i]); $tx = $this->UTF8ToUTF16BE($tx, false); $tj .= $this->_escape($tx); } $tj .= ')'; $s.=sprintf(' BT ' . $aix . ' [%s] TJ ET ', $x * _MPDFK, ($this->h - $y) * _MPDFK, $tj); } else { // CORE Font $s = ''; $tj = '('; $l = strlen($txt); for ($i = 0; $i < $l; $i++) { if ($i > 0 && isset($this->CurrentFont['kerninfo'][$txt[($i - 1)]][$txt[$i]])) { $kern = -$this->CurrentFont['kerninfo'][$txt[($i - 1)]][$txt[$i]]; $tj .= sprintf(')%d(', $kern); } $tj .= $this->_escape($txt[$i]); } $tj .= ')'; $s.=sprintf(' BT ' . $aix . ' [%s] TJ ET ', $x * _MPDFK, ($this->h - $y) * _MPDFK, $tj); } return $s; } function MultiCell($w, $h, $txt, $border = 0, $align = '', $fill = 0, $link = '', $directionality = 'ltr', $encoded = false, $OTLdata = false, $maxrows = false) { // maxrows is called from mpdfform->TEXTAREA // Parameter (pre-)encoded - When called internally from form::textarea - mb_encoding already done and OTL - but not reverse RTL if (!$encoded) { $txt = $this->purify_utf8_text($txt); if ($this->text_input_as_HTML) { $txt = $this->all_entities_to_utf8($txt); } if ($this->usingCoreFont) { $txt = mb_convert_encoding($txt, $this->mb_enc, 'UTF-8'); } if (preg_match("/([" . $this->pregRTLchars . "])/u", $txt)) { $this->biDirectional = true; } // *OTL* /* -- OTL -- */ $OTLdata = array(); // Use OTL OpenType Table Layout - GSUB & GPOS if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) { $txt = $this->otl->applyOTL($txt, $this->CurrentFont['useOTL']); $OTLdata = $this->otl->OTLdata; } if ($directionality == 'rtl' || $this->biDirectional) { if (!isset($OTLdata)) { $unicode = $this->UTF8StringToArray($txt, false); $is_strong = false; $this->getBasicOTLdata($OTLdata, $unicode, $is_strong); } } /* -- END OTL -- */ } if (!$align) { $align = $this->defaultAlign; } //Output text with automatic or explicit line breaks $cw = &$this->CurrentFont['cw']; if ($w == 0) $w = $this->w - $this->rMargin - $this->x; $wmax = ($w - ($this->cMarginL + $this->cMarginR)); if ($this->usingCoreFont) { $s = str_replace("\r", '', $txt); $nb = strlen($s); while ($nb > 0 and $s[$nb - 1] == "\n") $nb--; } else { $s = str_replace("\r", '', $txt); $nb = mb_strlen($s, $this->mb_enc); while ($nb > 0 and mb_substr($s, $nb - 1, 1, $this->mb_enc) == "\n") $nb--; } $b = 0; if ($border) { if ($border == 1) { $border = 'LTRB'; $b = 'LRT'; $b2 = 'LR'; } else { $b2 = ''; if (is_int(strpos($border, 'L'))) $b2.='L'; if (is_int(strpos($border, 'R'))) $b2.='R'; $b = is_int(strpos($border, 'T')) ? $b2 . 'T' : $b2; } } $sep = -1; $i = 0; $j = 0; $l = 0; $ns = 0; $nl = 1; $rows = 0; $start_y = $this->y; if (!$this->usingCoreFont) { $inclCursive = false; if (preg_match("/([" . $this->pregCURSchars . "])/u", $s)) { $inclCursive = true; } while ($i < $nb) { //Get next character $c = mb_substr($s, $i, 1, $this->mb_enc); if ($c == "\n") { //Explicit line break // WORD SPACING $this->ResetSpacing(); $tmp = rtrim(mb_substr($s, $j, $i - $j, $this->mb_enc)); $tmpOTLdata = false; /* -- OTL -- */ if (isset($OTLdata)) { $tmpOTLdata = $this->otl->sliceOTLdata($OTLdata, $j, $i - $j); $this->otl->trimOTLdata($tmpOTLdata, false, true); $this->magic_reverse_dir($tmp, $directionality, $tmpOTLdata); } /* -- END OTL -- */ $this->Cell($w, $h, $tmp, $b, 2, $align, $fill, $link, 0, 0, 0, 'M', 0, false, $tmpOTLdata); if ($maxrows != false && isset($this->mpdfform) && ($this->y - $start_y) / $h > $maxrows) { return false; } $i++; $sep = -1; $j = $i; $l = 0; $ns = 0; $nl++; if ($border and $nl == 2) $b = $b2; continue; } if ($c == " ") { $sep = $i; $ls = $l; $ns++; } $l += $this->GetCharWidthNonCore($c); if ($l > $wmax) { //Automatic line break if ($sep == -1) { // Only one word if ($i == $j) $i++; // WORD SPACING $this->ResetSpacing(); $tmp = rtrim(mb_substr($s, $j, $i - $j, $this->mb_enc)); $tmpOTLdata = false; /* -- OTL -- */ if (isset($OTLdata)) { $tmpOTLdata = $this->otl->sliceOTLdata($OTLdata, $j, $i - $j); $this->otl->trimOTLdata($tmpOTLdata, false, true); $this->magic_reverse_dir($tmp, $directionality, $tmpOTLdata); } /* -- END OTL -- */ $this->Cell($w, $h, $tmp, $b, 2, $align, $fill, $link, 0, 0, 0, 'M', 0, false, $tmpOTLdata); } else { $tmp = rtrim(mb_substr($s, $j, $sep - $j, $this->mb_enc)); $tmpOTLdata = false; /* -- OTL -- */ if (isset($OTLdata)) { $tmpOTLdata = $this->otl->sliceOTLdata($OTLdata, $j, $sep - $j); $this->otl->trimOTLdata($tmpOTLdata, false, true); } /* -- END OTL -- */ if ($align == 'J') { ////////////////////////////////////////// // JUSTIFY J using Unicode fonts (Word spacing doesn't work) // WORD SPACING UNICODE // Change NON_BREAKING SPACE to spaces so they are 'spaced' properly $tmp = str_replace(chr(194) . chr(160), chr(32), $tmp); $len_ligne = $this->GetStringWidth($tmp, false, $tmpOTLdata); $nb_carac = mb_strlen($tmp, $this->mb_enc); $nb_spaces = mb_substr_count($tmp, ' ', $this->mb_enc); // Take off number of Marks // Use GPOS OTL if (isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'])) { if (isset($tmpOTLdata['group']) && $tmpOTLdata['group']) { $nb_carac -= substr_count($tmpOTLdata['group'], 'M'); } } list($charspacing, $ws, $kashida) = $this->GetJspacing($nb_carac, $nb_spaces, ((($wmax) - $len_ligne) * _MPDFK), $inclCursive, $tmpOTLdata); $this->SetSpacing($charspacing, $ws); ////////////////////////////////////////// } if (isset($OTLdata)) { $this->magic_reverse_dir($tmp, $directionality, $tmpOTLdata); } $this->Cell($w, $h, $tmp, $b, 2, $align, $fill, $link, 0, 0, 0, 'M', 0, false, $tmpOTLdata); $i = $sep + 1; } if ($maxrows != false && isset($this->mpdfform) && ($this->y - $start_y) / $h > $maxrows) { return false; } $sep = -1; $j = $i; $l = 0; $ns = 0; $nl++; if ($border and $nl == 2) $b = $b2; } else $i++; } //Last chunk // WORD SPACING $this->ResetSpacing(); } else { while ($i < $nb) { //Get next character $c = $s[$i]; if ($c == "\n") { //Explicit line break // WORD SPACING $this->ResetSpacing(); $this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill, $link); if ($maxrows != false && isset($this->mpdfform) && ($this->y - $start_y) / $h > $maxrows) { return false; } $i++; $sep = -1; $j = $i; $l = 0; $ns = 0; $nl++; if ($border and $nl == 2) $b = $b2; continue; } if ($c == " ") { $sep = $i; $ls = $l; $ns++; } $l += $this->GetCharWidthCore($c); if ($l > $wmax) { //Automatic line break if ($sep == -1) { if ($i == $j) $i++; // WORD SPACING $this->ResetSpacing(); $this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill, $link); } else { if ($align == 'J') { $tmp = rtrim(substr($s, $j, $sep - $j)); ////////////////////////////////////////// // JUSTIFY J using Unicode fonts (Word spacing doesn't work) // WORD SPACING NON_UNICODE/CJK // Change NON_BREAKING SPACE to spaces so they are 'spaced' properly $tmp = str_replace(chr(160), chr(32), $tmp); $len_ligne = $this->GetStringWidth($tmp); $nb_carac = strlen($tmp); $nb_spaces = substr_count($tmp, ' '); $tmpOTLdata = array(); list($charspacing, $ws, $kashida) = $this->GetJspacing($nb_carac, $nb_spaces, ((($wmax) - $len_ligne) * _MPDFK), false, $tmpOTLdata); $this->SetSpacing($charspacing, $ws); ////////////////////////////////////////// } $this->Cell($w, $h, substr($s, $j, $sep - $j), $b, 2, $align, $fill, $link); $i = $sep + 1; } if ($maxrows != false && isset($this->mpdfform) && ($this->y - $start_y) / $h > $maxrows) { return false; } $sep = -1; $j = $i; $l = 0; $ns = 0; $nl++; if ($border and $nl == 2) $b = $b2; } else $i++; } //Last chunk // WORD SPACING $this->ResetSpacing(); } //Last chunk if ($border and is_int(strpos($border, 'B'))) $b.='B'; if (!$this->usingCoreFont) { $tmp = rtrim(mb_substr($s, $j, $i - $j, $this->mb_enc)); $tmpOTLdata = false; /* -- OTL -- */ if (isset($OTLdata)) { $tmpOTLdata = $this->otl->sliceOTLdata($OTLdata, $j, $i - $j); $this->otl->trimOTLdata($tmpOTLdata, false, true); $this->magic_reverse_dir($tmp, $directionality, $tmpOTLdata); } /* -- END OTL -- */ $this->Cell($w, $h, $tmp, $b, 2, $align, $fill, $link, 0, 0, 0, 'M', 0, false, $tmpOTLdata); } else { $this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill, $link); } $this->x = $this->lMargin; } /* -- DIRECTW -- */ function Write($h, $txt, $currentx = 0, $link = '', $directionality = 'ltr', $align = '') { if (!class_exists('directw', false)) { include(_MPDF_PATH . 'classes/directw.php'); } if (empty($this->directw)) { $this->directw = new directw($this); } $this->directw->Write($h, $txt, $currentx, $link, $directionality, $align); } /* -- END DIRECTW -- */ /* -- HTML-CSS -- */ function saveInlineProperties() { $saved = array(); $saved['family'] = $this->FontFamily; $saved['style'] = $this->FontStyle; $saved['sizePt'] = $this->FontSizePt; $saved['size'] = $this->FontSize; $saved['HREF'] = $this->HREF; $saved['textvar'] = $this->textvar; // mPDF 5.7.1 $saved['OTLtags'] = $this->OTLtags; // mPDF 5.7.1 $saved['textshadow'] = $this->textshadow; $saved['linewidth'] = $this->LineWidth; $saved['drawcolor'] = $this->DrawColor; $saved['textparam'] = $this->textparam; $saved['lSpacingCSS'] = $this->lSpacingCSS; $saved['wSpacingCSS'] = $this->wSpacingCSS; $saved['I'] = $this->I; $saved['B'] = $this->B; $saved['colorarray'] = $this->colorarray; $saved['bgcolorarray'] = $this->spanbgcolorarray; $saved['border'] = $this->spanborddet; $saved['color'] = $this->TextColor; $saved['bgcolor'] = $this->FillColor; $saved['lang'] = $this->currentLang; $saved['fontLanguageOverride'] = $this->fontLanguageOverride; // mPDF 5.7.1 $saved['display_off'] = $this->inlineDisplayOff; return $saved; } function restoreInlineProperties(&$saved) { $FontFamily = $saved['family']; $this->FontStyle = $saved['style']; $this->FontSizePt = $saved['sizePt']; $this->FontSize = $saved['size']; $this->currentLang = $saved['lang']; $this->fontLanguageOverride = $saved['fontLanguageOverride']; // mPDF 5.7.1 $this->ColorFlag = ($this->FillColor != $this->TextColor); //Restore ColorFlag as well $this->HREF = $saved['HREF']; $this->textvar = $saved['textvar']; // mPDF 5.7.1 $this->OTLtags = $saved['OTLtags']; // mPDF 5.7.1 $this->textshadow = $saved['textshadow']; $this->LineWidth = $saved['linewidth']; $this->DrawColor = $saved['drawcolor']; $this->textparam = $saved['textparam']; $this->inlineDisplayOff = $saved['display_off']; $this->lSpacingCSS = $saved['lSpacingCSS']; if (($this->lSpacingCSS || $this->lSpacingCSS === '0') && strtoupper($this->lSpacingCSS) != 'NORMAL') { $this->fixedlSpacing = $this->ConvertSize($this->lSpacingCSS, $this->FontSize); } else { $this->fixedlSpacing = false; } $this->wSpacingCSS = $saved['wSpacingCSS']; if ($this->wSpacingCSS && strtoupper($this->wSpacingCSS) != 'NORMAL') { $this->minwSpacing = $this->ConvertSize($this->wSpacingCSS, $this->FontSize); } else { $this->minwSpacing = 0; } $this->SetFont($FontFamily, $saved['style'], $saved['sizePt'], false); $this->currentfontstyle = $saved['style']; $this->currentfontsize = $saved['sizePt']; $this->SetStylesArray(array('B' => $saved['B'], 'I' => $saved['I'])); // mPDF 5.7.1 $this->TextColor = $saved['color']; $this->FillColor = $saved['bgcolor']; $this->colorarray = $saved['colorarray']; $cor = $saved['colorarray']; if ($cor) $this->SetTColor($cor); $this->spanbgcolorarray = $saved['bgcolorarray']; $cor = $saved['bgcolorarray']; if ($cor) $this->SetFColor($cor); $this->spanborddet = $saved['border']; } // Used when ColActive for tables - updated to return first block with background fill OR borders function GetFirstBlockFill() { // Returns the first blocklevel that uses a bgcolor fill $startfill = 0; for ($i = 1; $i <= $this->blklvl; $i++) { if ($this->blk[$i]['bgcolor'] || $this->blk[$i]['border_left']['w'] || $this->blk[$i]['border_right']['w'] || $this->blk[$i]['border_top']['w'] || $this->blk[$i]['border_bottom']['w']) { $startfill = $i; break; } } return $startfill; } //-------------------------FLOWING BLOCK------------------------------------// //The following functions were originally written by Damon Kohler // //--------------------------------------------------------------------------// function saveFont() { $saved = array(); $saved['family'] = $this->FontFamily; $saved['style'] = $this->FontStyle; $saved['sizePt'] = $this->FontSizePt; $saved['size'] = $this->FontSize; $saved['curr'] = &$this->CurrentFont; $saved['lang'] = $this->currentLang; // mPDF 6 $saved['color'] = $this->TextColor; $saved['spanbgcolor'] = $this->spanbgcolor; $saved['spanbgcolorarray'] = $this->spanbgcolorarray; $saved['bord'] = $this->spanborder; $saved['border'] = $this->spanborddet; $saved['HREF'] = $this->HREF; $saved['textvar'] = $this->textvar; // mPDF 5.7.1 $saved['textshadow'] = $this->textshadow; $saved['linewidth'] = $this->LineWidth; $saved['drawcolor'] = $this->DrawColor; $saved['textparam'] = $this->textparam; $saved['ReqFontStyle'] = $this->ReqFontStyle; $saved['fixedlSpacing'] = $this->fixedlSpacing; $saved['minwSpacing'] = $this->minwSpacing; return $saved; } function restoreFont(&$saved, $write = true) { if (!isset($saved) || empty($saved)) return; $this->FontFamily = $saved['family']; $this->FontStyle = $saved['style']; $this->FontSizePt = $saved['sizePt']; $this->FontSize = $saved['size']; $this->CurrentFont = &$saved['curr']; $this->currentLang = $saved['lang']; // mPDF 6 $this->TextColor = $saved['color']; $this->spanbgcolor = $saved['spanbgcolor']; $this->spanbgcolorarray = $saved['spanbgcolorarray']; $this->spanborder = $saved['bord']; $this->spanborddet = $saved['border']; $this->ColorFlag = ($this->FillColor != $this->TextColor); //Restore ColorFlag as well $this->HREF = $saved['HREF']; $this->fixedlSpacing = $saved['fixedlSpacing']; $this->minwSpacing = $saved['minwSpacing']; $this->textvar = $saved['textvar']; // mPDF 5.7.1 $this->textshadow = $saved['textshadow']; $this->LineWidth = $saved['linewidth']; $this->DrawColor = $saved['drawcolor']; $this->textparam = $saved['textparam']; if ($write) { $this->SetFont($saved['family'], $saved['style'], $saved['sizePt'], true, true); // force output $fontout = (sprintf('BT /F%d %.3F Tf ET', $this->CurrentFont['i'], $this->FontSizePt)); if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['Font']) && $this->pageoutput[$this->page]['Font'] != $fontout) || !isset($this->pageoutput[$this->page]['Font']))) { $this->_out($fontout); } $this->pageoutput[$this->page]['Font'] = $fontout; } else $this->SetFont($saved['family'], $saved['style'], $saved['sizePt'], false); $this->ReqFontStyle = $saved['ReqFontStyle']; } function newFlowingBlock($w, $h, $a = '', $is_table = false, $blockstate = 0, $newblock = true, $blockdir = 'ltr', $table_draft = false) { if (!$a) { if ($blockdir == 'rtl') { $a = 'R'; } else { $a = 'L'; } } $this->flowingBlockAttr['width'] = ($w * _MPDFK); // line height in user units $this->flowingBlockAttr['is_table'] = $is_table; $this->flowingBlockAttr['table_draft'] = $table_draft; $this->flowingBlockAttr['height'] = $h; $this->flowingBlockAttr['lineCount'] = 0; $this->flowingBlockAttr['align'] = $a; $this->flowingBlockAttr['font'] = array(); $this->flowingBlockAttr['content'] = array(); $this->flowingBlockAttr['contentB'] = array(); $this->flowingBlockAttr['contentWidth'] = 0; $this->flowingBlockAttr['blockstate'] = $blockstate; $this->flowingBlockAttr['newblock'] = $newblock; $this->flowingBlockAttr['valign'] = 'M'; $this->flowingBlockAttr['blockdir'] = $blockdir; $this->flowingBlockAttr['cOTLdata'] = array(); // mPDF 5.7.1 $this->flowingBlockAttr['lastBidiText'] = ''; // mPDF 5.7.1 if (!empty($this->otl)) { $this->otl->lastBidiStrongType = ''; } // *OTL* } function finishFlowingBlock($endofblock = false, $next = '') { $currentx = $this->x; //prints out the last chunk $is_table = $this->flowingBlockAttr['is_table']; $table_draft = $this->flowingBlockAttr['table_draft']; $maxWidth = & $this->flowingBlockAttr['width']; $stackHeight = & $this->flowingBlockAttr['height']; $align = & $this->flowingBlockAttr['align']; $content = & $this->flowingBlockAttr['content']; $contentB = & $this->flowingBlockAttr['contentB']; $font = & $this->flowingBlockAttr['font']; $contentWidth = & $this->flowingBlockAttr['contentWidth']; $lineCount = & $this->flowingBlockAttr['lineCount']; $valign = & $this->flowingBlockAttr['valign']; $blockstate = $this->flowingBlockAttr['blockstate']; $cOTLdata = & $this->flowingBlockAttr['cOTLdata']; // mPDF 5.7.1 $newblock = $this->flowingBlockAttr['newblock']; $blockdir = $this->flowingBlockAttr['blockdir']; // *********** BLOCK BACKGROUND COLOR *****************// if ($this->blk[$this->blklvl]['bgcolor'] && !$is_table) { $fill = 0; } else { $this->SetFColor($this->ConvertColor(255)); $fill = 0; } $hanger = ''; // Always right trim! // Right trim last content and adjust width if needed to justify (later) if (isset($content[count($content) - 1]) && preg_match('/[ ]+$/', $content[count($content) - 1], $m)) { $strip = strlen($m[0]); $content[count($content) - 1] = substr($content[count($content) - 1], 0, (strlen($content[count($content) - 1]) - $strip)); /* -- OTL -- */ if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) { $this->otl->trimOTLdata($cOTLdata[count($cOTLdata) - 1], false, true); } /* -- END OTL -- */ } // the amount of space taken up so far in user units $usedWidth = 0; // COLS $oldcolumn = $this->CurrCol; if ($this->ColActive && !$is_table) { $this->breakpoints[$this->CurrCol][] = $this->y; } // *COLUMNS* // Print out each chunk /* -- TABLES -- */ if ($is_table) { $ipaddingL = 0; $ipaddingR = 0; $paddingL = 0; $paddingR = 0; } else { /* -- END TABLES -- */ $ipaddingL = $this->blk[$this->blklvl]['padding_left']; $ipaddingR = $this->blk[$this->blklvl]['padding_right']; $paddingL = ($ipaddingL * _MPDFK); $paddingR = ($ipaddingR * _MPDFK); $this->cMarginL = $this->blk[$this->blklvl]['border_left']['w']; $this->cMarginR = $this->blk[$this->blklvl]['border_right']['w']; // Added mPDF 3.0 Float DIV $fpaddingR = 0; $fpaddingL = 0; /* -- CSS-FLOAT -- */ if (count($this->floatDivs)) { list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($this->blklvl); if ($r_exists) { $fpaddingR = $r_width; } if ($l_exists) { $fpaddingL = $l_width; } } /* -- END CSS-FLOAT -- */ $usey = $this->y + 0.002; if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 0)) { $usey += $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w']; } /* -- CSS-IMAGE-FLOAT -- */ // If float exists at this level if (isset($this->floatmargins['R']) && $usey <= $this->floatmargins['R']['y1'] && $usey >= $this->floatmargins['R']['y0'] && !$this->floatmargins['R']['skipline']) { $fpaddingR += $this->floatmargins['R']['w']; } if (isset($this->floatmargins['L']) && $usey <= $this->floatmargins['L']['y1'] && $usey >= $this->floatmargins['L']['y0'] && !$this->floatmargins['L']['skipline']) { $fpaddingL += $this->floatmargins['L']['w']; } /* -- END CSS-IMAGE-FLOAT -- */ } // *TABLES* $lineBox = array(); $this->_setInlineBlockHeights($lineBox, $stackHeight, $content, $font, $is_table); if ($is_table && count($content) == 0) { $stackHeight = 0; } if ($table_draft) { $this->y += $stackHeight; $this->objectbuffer = array(); return 0; } // While we're at it, check if contains cursive text // Change NBSP to SPACE. // Re-calculate contentWidth $contentWidth = 0; foreach ($content as $k => $chunk) { $this->restoreFont($font[$k], false); if (!isset($this->objectbuffer[$k]) || (isset($this->objectbuffer[$k]) && !$this->objectbuffer[$k])) { // Soft Hyphens chr(173) if (!$this->usingCoreFont) { /* -- OTL -- */ // mPDF 5.7.1 if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) { $this->otl->removeChar($chunk, $cOTLdata[$k], "\xc2\xad"); $this->otl->replaceSpace($chunk, $cOTLdata[$k]); $content[$k] = $chunk; } /* -- END OTL -- */ else { // *OTL* $content[$k] = $chunk = str_replace("\xc2\xad", '', $chunk); $content[$k] = $chunk = str_replace(chr(194) . chr(160), chr(32), $chunk); } // *OTL* } elseif ($this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats') { $content[$k] = $chunk = str_replace(chr(173), '', $chunk); $content[$k] = $chunk = str_replace(chr(160), chr(32), $chunk); } $contentWidth += $this->GetStringWidth($chunk, true, (isset($cOTLdata[$k]) ? $cOTLdata[$k] : false), $this->textvar) * _MPDFK; } elseif (isset($this->objectbuffer[$k]) && $this->objectbuffer[$k]) { // LIST MARKERS // mPDF 6 Lists if ($this->objectbuffer[$k]['type'] == 'image' && isset($this->objectbuffer[$k]['listmarker']) && $this->objectbuffer[$k]['listmarker'] && $this->objectbuffer[$k]['listmarkerposition'] == 'outside') { // do nothing } else { $contentWidth += $this->objectbuffer[$k]['OUTER-WIDTH'] * _MPDFK; } } } if (isset($font[count($font) - 1])) { $lastfontreqstyle = (isset($font[count($font) - 1]['ReqFontStyle']) ? $font[count($font) - 1]['ReqFontStyle'] : ''); $lastfontstyle = (isset($font[count($font) - 1]['style']) ? $font[count($font) - 1]['style'] : ''); } else { $lastfontreqstyle = null; $lastfontstyle = null; } if ($blockdir == 'ltr' && strpos($lastfontreqstyle, "I") !== false && strpos($lastfontstyle, "I") === false) { // Artificial italic $lastitalic = $this->FontSize * 0.15 * _MPDFK; } else { $lastitalic = 0; } // Get PAGEBREAK TO TEST for height including the bottom border/padding $check_h = max($this->divheight, $stackHeight); // This fixes a proven bug... if ($endofblock && $newblock && $blockstate == 0 && !$content) { $check_h = 0; } // but ? needs to fix potentially more widespread... // if (!$content) { $check_h = 0; } if ($this->blklvl > 0 && !$is_table) { if ($endofblock && $blockstate > 1) { if ($this->blk[$this->blklvl]['page_break_after_avoid']) { $check_h += $stackHeight; } $check_h += ($this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w']); } if (($newblock && ($blockstate == 1 || $blockstate == 3) && $lineCount == 0) || ($endofblock && $blockstate == 3 && $lineCount == 0)) { $check_h += ($this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['border_top']['w']); } } // Force PAGE break if column height cannot take check-height if ($this->ColActive && $check_h > ($this->PageBreakTrigger - $this->y0)) { $this->SetCol($this->NbCol - 1); } // Avoid just border/background-color moved on to next page if ($endofblock && $blockstate > 1 && !$content) { $buff = $this->margBuffer; } else { $buff = 0; } // PAGEBREAK if (!$is_table && ($this->y + $check_h) > ($this->PageBreakTrigger + $buff) and ! $this->InFooter and $this->AcceptPageBreak()) { $bak_x = $this->x; //Current X position // WORD SPACING $ws = $this->ws; //Word Spacing $charspacing = $this->charspacing; //Character Spacing $this->ResetSpacing(); $this->AddPage($this->CurOrientation); $this->x = $bak_x; // Added to correct for OddEven Margins $currentx += $this->MarginCorrection; $this->x += $this->MarginCorrection; // WORD SPACING $this->SetSpacing($charspacing, $ws); } /* -- COLUMNS -- */ // COLS // COLUMN CHANGE if ($this->CurrCol != $oldcolumn) { $currentx += $this->ChangeColumn * ($this->ColWidth + $this->ColGap); $this->x += $this->ChangeColumn * ($this->ColWidth + $this->ColGap); $oldcolumn = $this->CurrCol; } if ($this->ColActive && !$is_table) { $this->breakpoints[$this->CurrCol][] = $this->y; } /* -- END COLUMNS -- */ // TOP MARGIN if ($newblock && ($blockstate == 1 || $blockstate == 3) && ($this->blk[$this->blklvl]['margin_top']) && $lineCount == 0 && !$is_table) { $this->DivLn($this->blk[$this->blklvl]['margin_top'], $this->blklvl - 1, true, $this->blk[$this->blklvl]['margin_collapse']); if ($this->ColActive) { $this->breakpoints[$this->CurrCol][] = $this->y; } // *COLUMNS* } if ($newblock && ($blockstate == 1 || $blockstate == 3) && $lineCount == 0 && !$is_table) { $this->blk[$this->blklvl]['y0'] = $this->y; $this->blk[$this->blklvl]['startpage'] = $this->page; if ($this->blk[$this->blklvl]['float']) { $this->blk[$this->blklvl]['float_start_y'] = $this->y; } if ($this->ColActive) { $this->breakpoints[$this->CurrCol][] = $this->y; } // *COLUMNS* } // Paragraph INDENT $WidthCorrection = 0; if (($newblock) && ($blockstate == 1 || $blockstate == 3) && isset($this->blk[$this->blklvl]['text_indent']) && ($lineCount == 0) && (!$is_table) && ($align != 'C')) { $ti = $this->ConvertSize($this->blk[$this->blklvl]['text_indent'], $this->blk[$this->blklvl]['inner_width'], $this->blk[$this->blklvl]['InlineProperties']['size'], false); // mPDF 5.7.4 $WidthCorrection = ($ti * _MPDFK); } // PADDING and BORDER spacing/fill if (($newblock) && ($blockstate == 1 || $blockstate == 3) && (($this->blk[$this->blklvl]['padding_top']) || ($this->blk[$this->blklvl]['border_top'])) && ($lineCount == 0) && (!$is_table)) { // $state = 0 normal; 1 top; 2 bottom; 3 top and bottom $this->DivLn($this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'], -3, true, false, 1); if ($this->ColActive) { $this->breakpoints[$this->CurrCol][] = $this->y; } // *COLUMNS* $this->x = $currentx; } // Added mPDF 3.0 Float DIV $fpaddingR = 0; $fpaddingL = 0; /* -- CSS-FLOAT -- */ if (count($this->floatDivs)) { list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($this->blklvl); if ($r_exists) { $fpaddingR = $r_width; } if ($l_exists) { $fpaddingL = $l_width; } } /* -- END CSS-FLOAT -- */ $usey = $this->y + 0.002; if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 0)) { $usey += $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w']; } /* -- CSS-IMAGE-FLOAT -- */ // If float exists at this level if (isset($this->floatmargins['R']) && $usey <= $this->floatmargins['R']['y1'] && $usey >= $this->floatmargins['R']['y0'] && !$this->floatmargins['R']['skipline']) { $fpaddingR += $this->floatmargins['R']['w']; } if (isset($this->floatmargins['L']) && $usey <= $this->floatmargins['L']['y1'] && $usey >= $this->floatmargins['L']['y0'] && !$this->floatmargins['L']['skipline']) { $fpaddingL += $this->floatmargins['L']['w']; } /* -- END CSS-IMAGE-FLOAT -- */ if ($content) { // In FinishFlowing Block no lines are justified as it is always last line // but if CJKorphan has allowed content width to go over max width, use J charspacing to compress line // JUSTIFICATION J - NOT! $nb_carac = 0; $nb_spaces = 0; $jcharspacing = 0; $jkashida = 0; $jws = 0; $inclCursive = false; $dottab = false; foreach ($content as $k => $chunk) { if (!isset($this->objectbuffer[$k]) || (isset($this->objectbuffer[$k]) && !$this->objectbuffer[$k])) { $nb_carac += mb_strlen($chunk, $this->mb_enc); $nb_spaces += mb_substr_count($chunk, ' ', $this->mb_enc); // mPDF 6 // Use GPOS OTL $this->restoreFont($font[$k], false); if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) { if (isset($cOTLdata[$k]['group']) && $cOTLdata[$k]['group']) { $nb_marks = substr_count($cOTLdata[$k]['group'], 'M'); $nb_carac -= $nb_marks; } if (preg_match("/([" . $this->pregCURSchars . "])/u", $chunk)) { $inclCursive = true; } } } else { $nb_carac ++; // mPDF 6 allow spacing for inline object if ($this->objectbuffer[$k]['type'] == 'dottab') { $dottab = $this->objectbuffer[$k]['outdent']; } } } // DIRECTIONALITY RTL $chunkorder = range(0, count($content) - 1); // mPDF 6 /* -- OTL -- */ // mPDF 6 if ($blockdir == 'rtl' || $this->biDirectional) { $this->otl->_bidiReorder($chunkorder, $content, $cOTLdata, $blockdir); // From this point on, $content and $cOTLdata may contain more elements (and re-ordered) compared to // $this->objectbuffer and $font ($chunkorder contains the mapping) } /* -- END OTL -- */ // Remove any XAdvance from OTL data at end of line // And correct for XPlacement on last character // BIDI is applied foreach ($chunkorder AS $aord => $k) { if (count($cOTLdata)) { $this->restoreFont($font[$k], false); // ...FinishFlowingBlock... if ($aord == count($chunkorder) - 1 && isset($cOTLdata[$aord]['group'])) { // Last chunk on line $nGPOS = strlen($cOTLdata[$aord]['group']) - 1; // Last character if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL']) || isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'])) { if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'])) { $w = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] * 1000 / $this->CurrentFont['unitsPerEm']; } else { $w = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] * 1000 / $this->CurrentFont['unitsPerEm']; } $w *= ($this->FontSize / 1000); $contentWidth -= $w * _MPDFK; $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] = 0; $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] = 0; } // If last character has an XPlacement set, adjust width calculation, and add to XAdvance to account for it if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'])) { $w = -$cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'] * 1000 / $this->CurrentFont['unitsPerEm']; $w *= ($this->FontSize / 1000); $contentWidth -= $w * _MPDFK; $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement']; $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement']; } } } } // if it's justified, we need to find the char/word spacing (or if orphans have allowed length of line to go over the maxwidth) // If "orphans" in fact is just a final space - ignore this $lastchar = mb_substr($content[(count($chunkorder) - 1)], mb_strlen($content[(count($chunkorder) - 1)], $this->mb_enc) - 1, 1, $this->mb_enc); if (preg_match("/[" . $this->CJKoverflow . "]/u", $lastchar)) { $CJKoverflow = true; } else { $CJKoverflow = false; } if ((((($contentWidth + $lastitalic) > $maxWidth) && ($content[(count($chunkorder) - 1)] != ' ') ) || (!$endofblock && $align == 'J' && ($next == 'image' || $next == 'select' || $next == 'input' || $next == 'textarea' || ($next == 'br' && $this->justifyB4br)))) && !($CJKoverflow && $this->allowCJKoverflow)) { // WORD SPACING list($jcharspacing, $jws, $jkashida) = $this->GetJspacing($nb_carac, $nb_spaces, ($maxWidth - $lastitalic - $contentWidth - $WidthCorrection - (($this->cMarginL + $this->cMarginR) * _MPDFK) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * _MPDFK) )), $inclCursive, $cOTLdata); } /* -- CJK-FONTS -- */ elseif ($this->checkCJK && $align == 'J' && $CJKoverflow && $this->allowCJKoverflow && $this->CJKforceend) { // force-end overhang $hanger = mb_substr($content[(count($chunkorder) - 1)], mb_strlen($content[(count($chunkorder) - 1)], $this->mb_enc) - 1, 1, $this->mb_enc); if (preg_match("/[" . $this->CJKoverflow . "]/u", $hanger)) { $content[(count($chunkorder) - 1)] = mb_substr($content[(count($chunkorder) - 1)], 0, mb_strlen($content[(count($chunkorder) - 1)], $this->mb_enc) - 1, $this->mb_enc); $this->restoreFont($font[$chunkorder[count($chunkorder) - 1]], false); $contentWidth -= $this->GetStringWidth($hanger) * _MPDFK; $nb_carac -= 1; list($jcharspacing, $jws, $jkashida) = $this->GetJspacing($nb_carac, $nb_spaces, ($maxWidth - $lastitalic - $contentWidth - $WidthCorrection - (($this->cMarginL + $this->cMarginR) * _MPDFK) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * _MPDFK) )), $inclCursive, $cOTLdata); } } /* -- END CJK-FONTS -- */ // Check if will fit at word/char spacing of previous line - if so continue it // but only allow a maximum of $this->jSmaxWordLast and $this->jSmaxCharLast elseif ($contentWidth < ($maxWidth - $lastitalic - $WidthCorrection - (($this->cMarginL + $this->cMarginR) * _MPDFK) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * _MPDFK))) && !$this->fixedlSpacing) { if ($this->ws > $this->jSmaxWordLast) { $jws = $this->jSmaxWordLast; } if ($this->charspacing > $this->jSmaxCharLast) { $jcharspacing = $this->jSmaxCharLast; } $check = $maxWidth - $lastitalic - $WidthCorrection - $contentWidth - (($this->cMarginL + $this->cMarginR) * _MPDFK) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * _MPDFK) ) - ( $jcharspacing * $nb_carac) - ( $jws * $nb_spaces); if ($check <= 0) { $jcharspacing = 0; $jws = 0; } } $empty = $maxWidth - $lastitalic - $WidthCorrection - $contentWidth - (($this->cMarginL + $this->cMarginR) * _MPDFK) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * _MPDFK) ); $empty -= ($jcharspacing * ($nb_carac - 1)); // mPDF 6 nb_carac MINUS 1 $empty -= ($jws * $nb_spaces); $empty -= ($jkashida); $empty /= _MPDFK; if (!$is_table) { $this->maxPosR = max($this->maxPosR, ($this->w - $this->rMargin - $this->blk[$this->blklvl]['outer_right_margin'] - $empty)); $this->maxPosL = min($this->maxPosL, ($this->lMargin + $this->blk[$this->blklvl]['outer_left_margin'] + $empty)); } $arraysize = count($chunkorder); $margins = ($this->cMarginL + $this->cMarginR) + ($ipaddingL + $ipaddingR + $fpaddingR + $fpaddingR ); if (!$is_table) { $this->DivLn($stackHeight, $this->blklvl, false); } // false -> don't advance y $this->x = $currentx + $this->cMarginL + $ipaddingL + $fpaddingL; if ($dottab !== false && $blockdir == 'rtl') { $this->x -= $dottab; } elseif ($align == 'R') { $this->x += $empty; } elseif ($align == 'J' && $blockdir == 'rtl') { $this->x += $empty; } elseif ($align == 'C') { $this->x += ($empty / 2); } // Paragraph INDENT $WidthCorrection = 0; if (($newblock) && ($blockstate == 1 || $blockstate == 3) && isset($this->blk[$this->blklvl]['text_indent']) && ($lineCount == 0) && (!$is_table) && ($align != 'C')) { $ti = $this->ConvertSize($this->blk[$this->blklvl]['text_indent'], $this->blk[$this->blklvl]['inner_width'], $this->blk[$this->blklvl]['InlineProperties']['size'], false); // mPDF 5.7.4 if ($blockdir != 'rtl') { $this->x += $ti; } // mPDF 6 } foreach ($chunkorder AS $aord => $k) { // mPDF 5.7 $chunk = $content[$aord]; if (isset($this->objectbuffer[$k]) && $this->objectbuffer[$k]) { $xadj = $this->x - $this->objectbuffer[$k]['OUTER-X']; $this->objectbuffer[$k]['OUTER-X'] += $xadj; $this->objectbuffer[$k]['BORDER-X'] += $xadj; $this->objectbuffer[$k]['INNER-X'] += $xadj; if ($this->objectbuffer[$k]['type'] == 'listmarker') { $this->objectbuffer[$k]['lineBox'] = $lineBox[-1]; // Block element details for glyph-origin } $yadj = $this->y - $this->objectbuffer[$k]['OUTER-Y']; if ($this->objectbuffer[$k]['type'] == 'dottab') { // mPDF 6 DOTTAB $this->objectbuffer[$k]['lineBox'] = $lineBox[$k]; // element details for glyph-origin } if ($this->objectbuffer[$k]['type'] != 'dottab') { // mPDF 6 DOTTAB $yadj += $lineBox[$k]['top']; } $this->objectbuffer[$k]['OUTER-Y'] += $yadj; $this->objectbuffer[$k]['BORDER-Y'] += $yadj; $this->objectbuffer[$k]['INNER-Y'] += $yadj; } $this->restoreFont($font[$k]); // mPDF 5.7 if ($is_table && substr($align, 0, 1) == 'D' && $aord == 0) { $dp = $this->decimal_align[substr($align, 0, 2)]; $s = preg_split('/' . preg_quote($dp, '/') . '/', $content[0], 2); // ? needs to be /u if not core $s0 = $this->GetStringWidth($s[0], false); $this->x += ($this->decimal_offset - $s0); } $this->SetSpacing(($this->fixedlSpacing * _MPDFK) + $jcharspacing, ($this->fixedlSpacing + $this->minwSpacing) * _MPDFK + $jws); $this->fixedlSpacing = false; $this->minwSpacing = 0; $save_vis = $this->visibility; if (isset($this->textparam['visibility']) && $this->textparam['visibility'] && $this->textparam['visibility'] != $this->visibility) { $this->SetVisibility($this->textparam['visibility']); } // *********** SPAN BACKGROUND COLOR ***************** // if (isset($this->spanbgcolor) && $this->spanbgcolor) { $cor = $this->spanbgcolorarray; $this->SetFColor($cor); $save_fill = $fill; $spanfill = 1; $fill = 1; } if (!empty($this->spanborddet)) { if (strpos($contentB[$k], 'L') !== false && isset($this->spanborddet['L'])) $this->x += $this->spanborddet['L']['w']; if (strpos($contentB[$k], 'L') === false) $this->spanborddet['L']['s'] = $this->spanborddet['L']['w'] = 0; if (strpos($contentB[$k], 'R') === false) $this->spanborddet['R']['s'] = $this->spanborddet['R']['w'] = 0; } // WORD SPACING // mPDF 5.7.1 $stringWidth = $this->GetStringWidth($chunk, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar); $nch = mb_strlen($chunk, $this->mb_enc); // Use GPOS OTL if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) { if (isset($cOTLdata[$aord]['group']) && $cOTLdata[$aord]['group']) { $nch -= substr_count($cOTLdata[$aord]['group'], 'M'); } } $stringWidth += ( $this->charspacing * $nch / _MPDFK ); $stringWidth += ( $this->ws * mb_substr_count($chunk, ' ', $this->mb_enc) / _MPDFK ); if (isset($this->objectbuffer[$k])) { if ($this->objectbuffer[$k]['type'] == 'dottab') { $this->objectbuffer[$k]['OUTER-WIDTH'] +=$empty; $this->objectbuffer[$k]['OUTER-WIDTH'] +=$this->objectbuffer[$k]['outdent']; } // LIST MARKERS // mPDF 6 Lists if ($this->objectbuffer[$k]['type'] == 'image' && isset($this->objectbuffer[$k]['listmarker']) && $this->objectbuffer[$k]['listmarker'] && $this->objectbuffer[$k]['listmarkerposition'] == 'outside') { // do nothing } else { $stringWidth = $this->objectbuffer[$k]['OUTER-WIDTH']; } } if ($stringWidth == 0) { $stringWidth = 0.000001; } if ($aord == $arraysize - 1) { // mPDF 5.7 // mPDF 5.7.1 if ($this->checkCJK && $CJKoverflow && $align == 'J' && $this->allowCJKoverflow && $hanger && $this->CJKforceend) { // force-end overhang $this->Cell($stringWidth, $stackHeight, $chunk, '', 0, '', $fill, $this->HREF, $currentx, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false)); // mPDF 5.7.1 $this->Cell($this->GetStringWidth($hanger), $stackHeight, $hanger, '', 1, '', $fill, $this->HREF, $currentx, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false)); // mPDF 5.7.1 } else { $this->Cell($stringWidth, $stackHeight, $chunk, '', 1, '', $fill, $this->HREF, $currentx, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false)); // mPDF 5.7.1 } } else $this->Cell($stringWidth, $stackHeight, $chunk, '', 0, '', $fill, $this->HREF, 0, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false)); //first or middle part // mPDF 5.7.1 if (!empty($this->spanborddet)) { if (strpos($contentB[$k], 'R') !== false && $aord != $arraysize - 1) $this->x += $this->spanborddet['R']['w']; } // *********** SPAN BACKGROUND COLOR OFF - RESET BLOCK BGCOLOR ***************** // if (isset($spanfill) && $spanfill) { $fill = $save_fill; $spanfill = 0; if ($fill) { $this->SetFColor($bcor); } } if (isset($this->textparam['visibility']) && $this->textparam['visibility'] && $this->visibility != $save_vis) { $this->SetVisibility($save_vis); } } $this->printobjectbuffer($is_table, $blockdir); $this->objectbuffer = array(); $this->ResetSpacing(); } // END IF CONTENT /* -- CSS-IMAGE-FLOAT -- */ // Update values if set to skipline if ($this->floatmargins) { $this->_advanceFloatMargins(); } if ($endofblock && $blockstate > 1) { // If float exists at this level if (isset($this->floatmargins['R']['y1'])) { $fry1 = $this->floatmargins['R']['y1']; } else { $fry1 = 0; } if (isset($this->floatmargins['L']['y1'])) { $fly1 = $this->floatmargins['L']['y1']; } else { $fly1 = 0; } if ($this->y < $fry1 || $this->y < $fly1) { $drop = max($fry1, $fly1) - $this->y; $this->DivLn($drop); $this->x = $currentx; } } /* -- END CSS-IMAGE-FLOAT -- */ // PADDING and BORDER spacing/fill if ($endofblock && ($blockstate > 1) && ($this->blk[$this->blklvl]['padding_bottom'] || $this->blk[$this->blklvl]['border_bottom'] || $this->blk[$this->blklvl]['css_set_height']) && (!$is_table)) { // If CSS height set, extend bottom - if on same page as block started, and CSS HEIGHT > actual height, // and does not force pagebreak $extra = 0; if (isset($this->blk[$this->blklvl]['css_set_height']) && $this->blk[$this->blklvl]['css_set_height'] && $this->blk[$this->blklvl]['startpage'] == $this->page) { // predicted height $h1 = ($this->y - $this->blk[$this->blklvl]['y0']) + $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w']; if ($h1 < ($this->blk[$this->blklvl]['css_set_height'] + $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['padding_top'])) { $extra = ($this->blk[$this->blklvl]['css_set_height'] + $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['padding_top']) - $h1; } if ($this->y + $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w'] + $extra > $this->PageBreakTrigger) { $extra = $this->PageBreakTrigger - ($this->y + $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w']); } } // $state = 0 normal; 1 top; 2 bottom; 3 top and bottom $this->DivLn($this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w'] + $extra, -3, true, false, 2); $this->x = $currentx; if ($this->ColActive) { $this->breakpoints[$this->CurrCol][] = $this->y; } // *COLUMNS* } // SET Bottom y1 of block (used for painting borders) if (($endofblock) && ($blockstate > 1) && (!$is_table)) { $this->blk[$this->blklvl]['y1'] = $this->y; } // BOTTOM MARGIN if (($endofblock) && ($blockstate > 1) && ($this->blk[$this->blklvl]['margin_bottom']) && (!$is_table)) { if ($this->y + $this->blk[$this->blklvl]['margin_bottom'] < $this->PageBreakTrigger and ! $this->InFooter) { $this->DivLn($this->blk[$this->blklvl]['margin_bottom'], $this->blklvl - 1, true, $this->blk[$this->blklvl]['margin_collapse']); if ($this->ColActive) { $this->breakpoints[$this->CurrCol][] = $this->y; } // *COLUMNS* } } // Reset lineheight $stackHeight = $this->divheight; } function printobjectbuffer($is_table = false, $blockdir = false) { if (!$blockdir) { $blockdir = $this->directionality; } if ($is_table && $this->shrin_k > 1) { $k = $this->shrin_k; } else { $k = 1; } $save_y = $this->y; $save_x = $this->x; $save_currentfontfamily = $this->FontFamily; $save_currentfontsize = $this->FontSizePt; $save_currentfontstyle = $this->FontStyle; if ($blockdir == 'rtl') { $rtlalign = 'R'; } else { $rtlalign = 'L'; } foreach ($this->objectbuffer AS $ib => $objattr) { if ($objattr['type'] == 'bookmark' || $objattr['type'] == 'indexentry' || $objattr['type'] == 'toc') { $x = $objattr['OUTER-X']; $y = $objattr['OUTER-Y']; $this->y = $y - $this->FontSize / 2; $this->x = $x; if ($objattr['type'] == 'bookmark') { $this->Bookmark($objattr['CONTENT'], $objattr['bklevel'], $y - $this->FontSize); } // *BOOKMARKS* if ($objattr['type'] == 'indexentry') { $this->IndexEntry($objattr['CONTENT']); } // *INDEX* if ($objattr['type'] == 'toc') { $this->TOC_Entry($objattr['CONTENT'], $objattr['toclevel'], (isset($objattr['toc_id']) ? $objattr['toc_id'] : '')); } // *TOC* } /* -- ANNOTATIONS -- */ elseif ($objattr['type'] == 'annot') { if ($objattr['POS-X']) { $x = $objattr['POS-X']; } elseif ($this->annotMargin <> 0) { $x = -$objattr['OUTER-X']; } else { $x = $objattr['OUTER-X']; } if ($objattr['POS-Y']) { $y = $objattr['POS-Y']; } else { $y = $objattr['OUTER-Y'] - $this->FontSize / 2; } // Create a dummy entry in the _out/columnBuffer with position sensitive data, // linking $y-1 in the Columnbuffer with entry in $this->columnAnnots // and when columns are split in length will not break annotation from current line $this->y = $y - 1; $this->x = $x - 1; $this->Line($x - 1, $y - 1, $x - 1, $y - 1); $this->Annotation($objattr['CONTENT'], $x, $y, $objattr['ICON'], $objattr['AUTHOR'], $objattr['SUBJECT'], $objattr['OPACITY'], $objattr['COLOR'], (isset($objattr['POPUP']) ? $objattr['POPUP'] : ''), (isset($objattr['FILE']) ? $objattr['FILE'] : '')); } /* -- END ANNOTATIONS -- */ else { $y = $objattr['OUTER-Y']; $x = $objattr['OUTER-X']; $w = $objattr['OUTER-WIDTH']; $h = $objattr['OUTER-HEIGHT']; if (isset($objattr['text'])) { $texto = $objattr['text']; } $this->y = $y; $this->x = $x; if (isset($objattr['fontfamily'])) { $this->SetFont($objattr['fontfamily'], '', $objattr['fontsize']); } } // HR if ($objattr['type'] == 'hr') { $this->SetDColor($objattr['color']); switch ($objattr['align']) { case 'C': $empty = $objattr['OUTER-WIDTH'] - $objattr['INNER-WIDTH']; $empty /= 2; $x += $empty; break; case 'R': $empty = $objattr['OUTER-WIDTH'] - $objattr['INNER-WIDTH']; $x += $empty; break; } $oldlinewidth = $this->LineWidth; $this->SetLineWidth($objattr['linewidth'] / $k); $this->y += ($objattr['linewidth'] / 2) + $objattr['margin_top'] / $k; $this->Line($x, $this->y, $x + $objattr['INNER-WIDTH'], $this->y); $this->SetLineWidth($oldlinewidth); $this->SetDColor($this->ConvertColor(0)); } // IMAGE if ($objattr['type'] == 'image') { // mPDF 5.7.3 TRANSFORMS if (isset($objattr['transform'])) { $this->_out("\n" . '% BTR'); // Begin Transform } if (isset($objattr['z-index']) && $objattr['z-index'] > 0 && $this->current_layer == 0) { $this->BeginLayer($objattr['z-index']); } if (isset($objattr['visibility']) && $objattr['visibility'] != 'visible' && $objattr['visibility']) { $this->SetVisibility($objattr['visibility']); } if (isset($objattr['opacity'])) { $this->SetAlpha($objattr['opacity']); } $obiw = $objattr['INNER-WIDTH']; $obih = $objattr['INNER-HEIGHT']; $sx = $objattr['INNER-WIDTH'] * _MPDFK / $objattr['orig_w']; $sy = abs($objattr['INNER-HEIGHT']) * _MPDFK / abs($objattr['orig_h']); $sx = ($objattr['INNER-WIDTH'] * _MPDFK / $objattr['orig_w']); $sy = ($objattr['INNER-HEIGHT'] * _MPDFK / $objattr['orig_h']); $rotate = 0; if (isset($objattr['ROTATE'])) { $rotate = $objattr['ROTATE']; } if ($rotate == 90) { // Clockwise $obiw = $objattr['INNER-HEIGHT']; $obih = $objattr['INNER-WIDTH']; $tr = $this->transformTranslate(0, -$objattr['INNER-WIDTH'], true); $tr .= ' ' . $this->transformRotate(90, $objattr['INNER-X'], ($objattr['INNER-Y'] + $objattr['INNER-WIDTH']), true); $sx = $obiw * _MPDFK / $objattr['orig_h']; $sy = $obih * _MPDFK / $objattr['orig_w']; } elseif ($rotate == -90 || $rotate == 270) { // AntiClockwise $obiw = $objattr['INNER-HEIGHT']; $obih = $objattr['INNER-WIDTH']; $tr = $this->transformTranslate($objattr['INNER-WIDTH'], ($objattr['INNER-HEIGHT'] - $objattr['INNER-WIDTH']), true); $tr .= ' ' . $this->transformRotate(-90, $objattr['INNER-X'], ($objattr['INNER-Y'] + $objattr['INNER-WIDTH']), true); $sx = $obiw * _MPDFK / $objattr['orig_h']; $sy = $obih * _MPDFK / $objattr['orig_w']; } elseif ($rotate == 180) { // Mirror $tr = $this->transformTranslate($objattr['INNER-WIDTH'], -$objattr['INNER-HEIGHT'], true); $tr .= ' ' . $this->transformRotate(180, $objattr['INNER-X'], ($objattr['INNER-Y'] + $objattr['INNER-HEIGHT']), true); } else { $tr = ''; } $tr = trim($tr); if ($tr) { $tr .= ' '; } $gradmask = ''; // mPDF 5.7.3 TRANSFORMS $tr2 = ''; if (isset($objattr['transform'])) { $maxsize_x = $w; $maxsize_y = $h; $cx = $x + $w / 2; $cy = $y + $h / 2; preg_match_all('/(translatex|translatey|translate|scalex|scaley|scale|rotate|skewX|skewY|skew)\((.*?)\)/is', $objattr['transform'], $m); if (count($m[0])) { for ($i = 0; $i < count($m[0]); $i++) { $c = strtolower($m[1][$i]); $v = trim($m[2][$i]); $vv = preg_split('/[ ,]+/', $v); if ($c == 'translate' && count($vv)) { $translate_x = $this->ConvertSize($vv[0], $maxsize_x, false, false); if (count($vv) == 2) { $translate_y = $this->ConvertSize($vv[1], $maxsize_y, false, false); } else { $translate_y = 0; } $tr2 .= $this->transformTranslate($translate_x, $translate_y, true) . ' '; } elseif ($c == 'translatex' && count($vv)) { $translate_x = $this->ConvertSize($vv[0], $maxsize_x, false, false); $tr2 .= $this->transformTranslate($translate_x, 0, true) . ' '; } elseif ($c == 'translatey' && count($vv)) { $translate_y = $this->ConvertSize($vv[1], $maxsize_y, false, false); $tr2 .= $this->transformTranslate(0, $translate_y, true) . ' '; } elseif ($c == 'scale' && count($vv)) { $scale_x = $vv[0] * 100; if (count($vv) == 2) { $scale_y = $vv[1] * 100; } else { $scale_y = $scale_x; } $tr2 .= $this->transformScale($scale_x, $scale_y, $cx, $cy, true) . ' '; } elseif ($c == 'scalex' && count($vv)) { $scale_x = $vv[0] * 100; $tr2 .= $this->transformScale($scale_x, 0, $cx, $cy, true) . ' '; } elseif ($c == 'scaley' && count($vv)) { $scale_y = $vv[1] * 100; $tr2 .= $this->transformScale(0, $scale_y, $cx, $cy, true) . ' '; } elseif ($c == 'skew' && count($vv)) { $angle_x = $this->ConvertAngle($vv[0], false); if (count($vv) == 2) { $angle_y = $this->ConvertAngle($vv[1], false); } else { $angle_y = 0; } $tr2 .= $this->transformSkew($angle_x, $angle_y, $cx, $cy, true) . ' '; } elseif ($c == 'skewx' && count($vv)) { $angle = $this->ConvertAngle($vv[0], false); $tr2 .= $this->transformSkew($angle, 0, $cx, $cy, true) . ' '; } elseif ($c == 'skewy' && count($vv)) { $angle = $this->ConvertAngle($vv[0], false); $tr2 .= $this->transformSkew(0, $angle, $cx, $cy, true) . ' '; } elseif ($c == 'rotate' && count($vv)) { $angle = $this->ConvertAngle($vv[0]); $tr2 .= $this->transformRotate($angle, $cx, $cy, true) . ' '; } } } } // LIST MARKERS (Images) // mPDF 6 Lists if (isset($objattr['listmarker']) && $objattr['listmarker'] && $objattr['listmarkerposition'] == 'outside') { $mw = $objattr['OUTER-WIDTH']; // NB If change marker-offset, also need to alter in function _getListMarkerWidth $adjx = $this->ConvertSize($this->list_marker_offset, $this->FontSize); if ($objattr['dir'] == 'rtl') { $objattr['INNER-X'] += $adjx; } else { $objattr['INNER-X'] -= $adjx; $objattr['INNER-X'] -= $mw; } } // mPDF 5.7.3 TRANSFORMS / BACKGROUND COLOR // Transform also affects image background if ($tr2) { $this->_out('q ' . $tr2 . ' '); } if (isset($objattr['bgcolor']) && $objattr['bgcolor']) { $bgcol = $objattr['bgcolor']; $this->SetFColor($bgcol); $this->Rect($x, $y, $w, $h, 'F'); $this->SetFColor($this->ConvertColor(255)); } if ($tr2) { $this->_out('Q'); } /* -- BACKGROUNDS -- */ if (isset($objattr['GRADIENT-MASK'])) { $g = $this->grad->parseMozGradient($objattr['GRADIENT-MASK']); if ($g) { $dummy = $this->grad->Gradient($objattr['INNER-X'], $objattr['INNER-Y'], $obiw, $obih, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend'], true, true); $gradmask = '/TGS' . count($this->gradients) . ' gs '; } } /* -- END BACKGROUNDS -- */ /* -- IMAGES-WMF -- */ if (isset($objattr['itype']) && $objattr['itype'] == 'wmf') { $outstring = sprintf('q ' . $tr . $tr2 . '%.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, -$sy, $objattr['INNER-X'] * _MPDFK - $sx * $objattr['wmf_x'], (($this->h - $objattr['INNER-Y']) * _MPDFK) + $sy * $objattr['wmf_y'], $objattr['ID']); // mPDF 5.7.3 TRANSFORMS } else /* -- END IMAGES-WMF -- */ if (isset($objattr['itype']) && $objattr['itype'] == 'svg') { $outstring = sprintf('q ' . $tr . $tr2 . '%.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, -$sy, $objattr['INNER-X'] * _MPDFK - $sx * $objattr['wmf_x'], (($this->h - $objattr['INNER-Y']) * _MPDFK) + $sy * $objattr['wmf_y'], $objattr['ID']); // mPDF 5.7.3 TRANSFORMS } else { $outstring = sprintf("q " . $tr . $tr2 . "%.3F 0 0 %.3F %.3F %.3F cm " . $gradmask . "/I%d Do Q", $obiw * _MPDFK, $obih * _MPDFK, $objattr['INNER-X'] * _MPDFK, ($this->h - ($objattr['INNER-Y'] + $obih )) * _MPDFK, $objattr['ID']); // mPDF 5.7.3 TRANSFORMS } $this->_out($outstring); // LINK if (isset($objattr['link'])) $this->Link($objattr['INNER-X'], $objattr['INNER-Y'], $objattr['INNER-WIDTH'], $objattr['INNER-HEIGHT'], $objattr['link']); if (isset($objattr['opacity'])) { $this->SetAlpha(1); } // mPDF 5.7.3 TRANSFORMS // Transform also affects image borders if ($tr2) { $this->_out('q ' . $tr2 . ' '); } if ((isset($objattr['border_top']) && $objattr['border_top'] > 0) || (isset($objattr['border_left']) && $objattr['border_left'] > 0) || (isset($objattr['border_right']) && $objattr['border_right'] > 0) || (isset($objattr['border_bottom']) && $objattr['border_bottom'] > 0)) { $this->PaintImgBorder($objattr, $is_table); } if ($tr2) { $this->_out('Q'); } if (isset($objattr['visibility']) && $objattr['visibility'] != 'visible' && $objattr['visibility']) { $this->SetVisibility('visible'); } if (isset($objattr['z-index']) && $objattr['z-index'] > 0 && $this->current_layer == 0) { $this->EndLayer(); } // mPDF 5.7.3 TRANSFORMS if (isset($objattr['transform'])) { $this->_out("\n" . '% ETR'); // End Transform } } /* -- BARCODES -- */ // BARCODE if ($objattr['type'] == 'barcode') { $bgcol = $this->ConvertColor(255); if (isset($objattr['bgcolor']) && $objattr['bgcolor']) { $bgcol = $objattr['bgcolor']; } $col = $this->ConvertColor(0); if (isset($objattr['color']) && $objattr['color']) { $col = $objattr['color']; } $this->SetFColor($bgcol); $this->Rect($objattr['BORDER-X'], $objattr['BORDER-Y'], $objattr['BORDER-WIDTH'], $objattr['BORDER-HEIGHT'], 'F'); $this->SetFColor($this->ConvertColor(255)); if (isset($objattr['BORDER-WIDTH'])) { $this->PaintImgBorder($objattr, $is_table); } if ($objattr['btype'] == 'EAN13' || $objattr['btype'] == 'ISBN' || $objattr['btype'] == 'ISSN' || $objattr['btype'] == 'UPCA' || $objattr['btype'] == 'UPCE' || $objattr['btype'] == 'EAN8') { $this->WriteBarcode($objattr['code'], $objattr['showtext'], $objattr['INNER-X'], $objattr['INNER-Y'], $objattr['bsize'], 0, 0, 0, 0, 0, $objattr['bheight'], $bgcol, $col, $objattr['btype'], $objattr['bsupp'], (isset($objattr['bsupp_code']) ? $objattr['bsupp_code'] : ''), $k); } // QR-code elseif ($objattr['btype'] == 'QR') { if (!class_exists('QRcode', false)) { include(_MPDF_PATH . 'qrcode/qrcode.class.php'); } $this->qrcode = new QRcode($objattr['code'], $objattr['errorlevel']); $this->qrcode->displayFPDF($this, $objattr['INNER-X'], $objattr['INNER-Y'], $objattr['bsize'] * 25, array(255, 255, 255), array(0, 0, 0)); } else { $this->WriteBarcode2($objattr['code'], $objattr['INNER-X'], $objattr['INNER-Y'], $objattr['bsize'], $objattr['bheight'], $bgcol, $col, $objattr['btype'], $objattr['pr_ratio'], $k); } } /* -- END BARCODES -- */ // TEXT CIRCLE if ($objattr['type'] == 'textcircle') { $bgcol = ''; if (isset($objattr['bgcolor']) && $objattr['bgcolor']) { $bgcol = $objattr['bgcolor']; } $col = $this->ConvertColor(0); if (isset($objattr['color']) && $objattr['color']) { $col = $objattr['color']; } $this->SetTColor($col); $this->SetFColor($bgcol); if ($bgcol) $this->Rect($objattr['BORDER-X'], $objattr['BORDER-Y'], $objattr['BORDER-WIDTH'], $objattr['BORDER-HEIGHT'], 'F'); $this->SetFColor($this->ConvertColor(255)); if (isset($objattr['BORDER-WIDTH'])) { $this->PaintImgBorder($objattr, $is_table); } if (!class_exists('directw', false)) { include(_MPDF_PATH . 'classes/directw.php'); } if (empty($this->directw)) { $this->directw = new directw($this); } if (isset($objattr['top-text'])) { $this->directw->CircularText($objattr['INNER-X'] + $objattr['INNER-WIDTH'] / 2, $objattr['INNER-Y'] + $objattr['INNER-HEIGHT'] / 2, $objattr['r'] / $k, $objattr['top-text'], 'top', $objattr['fontfamily'], $objattr['fontsize'] / $k, $objattr['fontstyle'], $objattr['space-width'], $objattr['char-width'], (isset($objattr['divider']) ? $objattr['divider'] : '')); } if (isset($objattr['bottom-text'])) { $this->directw->CircularText($objattr['INNER-X'] + $objattr['INNER-WIDTH'] / 2, $objattr['INNER-Y'] + $objattr['INNER-HEIGHT'] / 2, $objattr['r'] / $k, $objattr['bottom-text'], 'bottom', $objattr['fontfamily'], $objattr['fontsize'] / $k, $objattr['fontstyle'], $objattr['space-width'], $objattr['char-width'], (isset($objattr['divider']) ? $objattr['divider'] : '')); } } $this->ResetSpacing(); // LIST MARKERS (Text or bullets) // mPDF 6 Lists if ($objattr['type'] == 'listmarker') { if (isset($objattr['fontfamily'])) { $this->SetFont($objattr['fontfamily'], $objattr['fontstyle'], $objattr['fontsizept']); } $col = $this->ConvertColor(0); if (isset($objattr['colorarray']) && ($objattr['colorarray'])) { $col = $objattr['colorarray']; } if (isset($objattr['bullet']) && $objattr['bullet']) { // Used for position "outside" only $type = $objattr['bullet']; $size = $objattr['size']; if ($objattr['listmarkerposition'] == 'inside') { $adjx = $size / 2; if ($objattr['dir'] == 'rtl') { $adjx += $objattr['offset']; } $this->x += $adjx; } else { $adjx = $objattr['offset']; $adjx += $size / 2; if ($objattr['dir'] == 'rtl') { $this->x += $adjx; } else { $this->x -= $adjx; } } $yadj = $objattr['lineBox']['glyphYorigin']; if (isset($this->CurrentFont['desc']['XHeight']) && $this->CurrentFont['desc']['XHeight']) { $xh = $this->CurrentFont['desc']['XHeight']; } else { $xh = 500; } $yadj -= ($this->FontSize * $xh / 1000) * 0.625; // Vertical height of bullet (centre) from baseline= XHeight * 0.625 $this->y += $yadj; $this->_printListBullet($this->x, $this->y, $size, $type, $col); } else { $this->SetTColor($col); $w = $this->GetStringWidth($texto); // NB If change marker-offset, also need to alter in function _getListMarkerWidth $adjx = $this->ConvertSize($this->list_marker_offset, $this->FontSize); if ($objattr['dir'] == 'rtl') { $align = 'L'; $this->x += $adjx; } else { // Use these lines to set as marker-offset, right-aligned - default $align = 'R'; $this->x -= $adjx; $this->x -= $w; } $this->Cell($w, $this->FontSize, $texto, 0, 0, $align, 0, '', 0, 0, 0, 'T', 0, false, false, 0, $objattr['lineBox']); $this->SetTColor($this->ConvertColor(0)); } } // DOT-TAB if ($objattr['type'] == 'dottab') { if (isset($objattr['fontfamily'])) { $this->SetFont($objattr['fontfamily'], '', $objattr['fontsize']); } $sp = $this->GetStringWidth(' '); $nb = floor(($w - 2 * $sp) / $this->GetStringWidth('.')); if ($nb > 0) { $dots = ' ' . str_repeat('.', $nb) . ' '; } else { $dots = ' '; } $col = $this->ConvertColor(0); if (isset($objattr['colorarray']) && ($objattr['colorarray'])) { $col = $objattr['colorarray']; } $this->SetTColor($col); $save_dh = $this->divheight; $save_sbd = $this->spanborddet; $save_textvar = $this->textvar; // mPDF 5.7.1 $this->spanborddet = ''; $this->divheight = 0; $this->textvar = 0x00; // mPDF 5.7.1 $this->Cell($w, $h, $dots, 0, 0, 'C', 0, '', 0, 0, 0, 'T', 0, false, false, 0, $objattr['lineBox']); // mPDF 6 DOTTAB $this->spanborddet = $save_sbd; $this->textvar = $save_textvar; // mPDF 5.7.1 $this->divheight = $save_dh; $this->SetTColor($this->ConvertColor(0)); } /* -- FORMS -- */ // TEXT/PASSWORD INPUT if ($objattr['type'] == 'input' && ($objattr['subtype'] == 'TEXT' || $objattr['subtype'] == 'PASSWORD')) { $this->mpdfform->print_ob_text($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir); } // TEXTAREA if ($objattr['type'] == 'textarea') { $this->mpdfform->print_ob_textarea($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir); } // SELECT if ($objattr['type'] == 'select') { $this->mpdfform->print_ob_select($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir); } // INPUT/BUTTON as IMAGE if ($objattr['type'] == 'input' && $objattr['subtype'] == 'IMAGE') { $this->mpdfform->print_ob_imageinput($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir); } // BUTTON if ($objattr['type'] == 'input' && ($objattr['subtype'] == 'SUBMIT' || $objattr['subtype'] == 'RESET' || $objattr['subtype'] == 'BUTTON')) { $this->mpdfform->print_ob_button($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir); } // CHECKBOX if ($objattr['type'] == 'input' && ($objattr['subtype'] == 'CHECKBOX')) { $this->mpdfform->print_ob_checkbox($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir, $x, $y); } // RADIO if ($objattr['type'] == 'input' && ($objattr['subtype'] == 'RADIO')) { $this->mpdfform->print_ob_radio($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir, $x, $y); } /* -- END FORMS -- */ } $this->SetFont($save_currentfontfamily, $save_currentfontstyle, $save_currentfontsize); $this->y = $save_y; $this->x = $save_x; unset($content); } function _printListBullet($x, $y, $size, $type, $color) { // x and y are the centre of the bullet; size is the width and/or height in mm $fcol = $this->SetTColor($color, true); $lcol = strtoupper($fcol); // change 0 0 0 rg to 0 0 0 RG $this->_out(sprintf('q %s %s', $lcol, $fcol)); $this->_out('0 j 0 J [] 0 d'); if ($type == 'square') { $size *= 0.85; // Smaller to appear the same size as circle/disc $this->_out(sprintf('%.3F %.3F %.3F %.3F re f', ($x - $size / 2) * _MPDFK, ($this->h - $y + $size / 2) * _MPDFK, ($size) * _MPDFK, (-$size) * _MPDFK)); } elseif ($type == 'disc') { $this->Circle($x, $y, $size / 2, 'F'); // Fill } elseif ($type == 'circle') { $lw = $size / 12; // Line width $this->_out(sprintf('%.3F w ', $lw * _MPDFK)); $this->Circle($x, $y, $size / 2 - $lw / 2, 'S'); // Stroke } $this->_out('Q'); } // mPDF 6 // Get previous character and move pointers function _moveToPrevChar(&$contentctr, &$charctr, $content) { $lastchar = false; $charctr--; while ($charctr < 0) { // go back to previous $content[] $contentctr--; if ($contentctr < 0) { return false; } if ($this->usingCoreFont) { $charctr = strlen($content[$contentctr]) - 1; } else { $charctr = mb_strlen($content[$contentctr], $this->mb_enc) - 1; } } if ($this->usingCoreFont) { $lastchar = $content[$contentctr][$charctr]; } else { $lastchar = mb_substr($content[$contentctr], $charctr, 1, $this->mb_enc); } return $lastchar; } // Get previous character function _getPrevChar($contentctr, $charctr, $content) { $lastchar = false; $charctr--; while ($charctr < 0) { // go back to previous $content[] $contentctr--; if ($contentctr < 0) { return false; } if ($this->usingCoreFont) { $charctr = strlen($content[$contentctr]) - 1; } else { $charctr = mb_strlen($content[$contentctr], $this->mb_enc) - 1; } } if ($this->usingCoreFont) { $lastchar = $content[$contentctr][$charctr]; } else { $lastchar = mb_substr($content[$contentctr], $charctr, 1, $this->mb_enc); } return $lastchar; } function WriteFlowingBlock($s, $sOTLdata) { // mPDF 5.7.1 $currentx = $this->x; $is_table = $this->flowingBlockAttr['is_table']; $table_draft = $this->flowingBlockAttr['table_draft']; // width of all the content so far in points $contentWidth = & $this->flowingBlockAttr['contentWidth']; // cell width in points $maxWidth = & $this->flowingBlockAttr['width']; $lineCount = & $this->flowingBlockAttr['lineCount']; // line height in user units $stackHeight = & $this->flowingBlockAttr['height']; $align = & $this->flowingBlockAttr['align']; $content = & $this->flowingBlockAttr['content']; $contentB = & $this->flowingBlockAttr['contentB']; $font = & $this->flowingBlockAttr['font']; $valign = & $this->flowingBlockAttr['valign']; $blockstate = $this->flowingBlockAttr['blockstate']; $cOTLdata = & $this->flowingBlockAttr['cOTLdata']; // mPDF 5.7.1 $newblock = $this->flowingBlockAttr['newblock']; $blockdir = $this->flowingBlockAttr['blockdir']; // *********** BLOCK BACKGROUND COLOR ***************** // if ($this->blk[$this->blklvl]['bgcolor'] && !$is_table) { $fill = 0; } else { $this->SetFColor($this->ConvertColor(255)); $fill = 0; } $font[] = $this->saveFont(); $content[] = ''; $contentB[] = ''; $cOTLdata[] = $sOTLdata; // mPDF 5.7.1 $currContent = & $content[count($content) - 1]; $CJKoverflow = false; $Oikomi = false; // mPDF 6 $hanger = ''; // COLS $oldcolumn = $this->CurrCol; if ($this->ColActive && !$is_table) { $this->breakpoints[$this->CurrCol][] = $this->y; } // *COLUMNS* /* -- TABLES -- */ if ($is_table) { $ipaddingL = 0; $ipaddingR = 0; $paddingL = 0; $paddingR = 0; $cpaddingadjustL = 0; $cpaddingadjustR = 0; // Added mPDF 3.0 $fpaddingR = 0; $fpaddingL = 0; } else { /* -- END TABLES -- */ $ipaddingL = $this->blk[$this->blklvl]['padding_left']; $ipaddingR = $this->blk[$this->blklvl]['padding_right']; $paddingL = ($ipaddingL * _MPDFK); $paddingR = ($ipaddingR * _MPDFK); $this->cMarginL = $this->blk[$this->blklvl]['border_left']['w']; $cpaddingadjustL = -$this->cMarginL; $this->cMarginR = $this->blk[$this->blklvl]['border_right']['w']; $cpaddingadjustR = -$this->cMarginR; // Added mPDF 3.0 Float DIV $fpaddingR = 0; $fpaddingL = 0; /* -- CSS-FLOAT -- */ if (count($this->floatDivs)) { list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($this->blklvl); if ($r_exists) { $fpaddingR = $r_width; } if ($l_exists) { $fpaddingL = $l_width; } } /* -- END CSS-FLOAT -- */ $usey = $this->y + 0.002; if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 0)) { $usey += $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w']; } /* -- CSS-IMAGE-FLOAT -- */ // If float exists at this level if (isset($this->floatmargins['R']) && $usey <= $this->floatmargins['R']['y1'] && $usey >= $this->floatmargins['R']['y0'] && !$this->floatmargins['R']['skipline']) { $fpaddingR += $this->floatmargins['R']['w']; } if (isset($this->floatmargins['L']) && $usey <= $this->floatmargins['L']['y1'] && $usey >= $this->floatmargins['L']['y0'] && !$this->floatmargins['L']['skipline']) { $fpaddingL += $this->floatmargins['L']['w']; } /* -- END CSS-IMAGE-FLOAT -- */ } // *TABLES* //OBJECTS - IMAGES & FORM Elements (NB has already skipped line/page if required - in printbuffer) if (substr($s, 0, 3) == "\xbb\xa4\xac") { //identifier has been identified! $objattr = $this->_getObjAttr($s); $h_corr = 0; if ($is_table) { // *TABLES* $maximumW = ($maxWidth / _MPDFK) - ($this->cellPaddingL + $this->cMarginL + $this->cellPaddingR + $this->cMarginR); // *TABLES* } // *TABLES* else { // *TABLES* if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 0) && (!$is_table)) { $h_corr = $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w']; } $maximumW = ($maxWidth / _MPDFK) - ($this->blk[$this->blklvl]['padding_left'] + $this->blk[$this->blklvl]['border_left']['w'] + $this->blk[$this->blklvl]['padding_right'] + $this->blk[$this->blklvl]['border_right']['w'] + $fpaddingL + $fpaddingR ); } // *TABLES* $objattr = $this->inlineObject($objattr['type'], $this->lMargin + $fpaddingL + ($contentWidth / _MPDFK), ($this->y + $h_corr), $objattr, $this->lMargin, ($contentWidth / _MPDFK), $maximumW, $stackHeight, true, $is_table); // SET LINEHEIGHT for this line ================ RESET AT END $stackHeight = MAX($stackHeight, $objattr['OUTER-HEIGHT']); $this->objectbuffer[count($content) - 1] = $objattr; // if (isset($objattr['vertical-align'])) { $valign = $objattr['vertical-align']; } // else { $valign = ''; } // LIST MARKERS // mPDF 6 Lists if ($objattr['type'] == 'image' && isset($objattr['listmarker']) && $objattr['listmarker'] && $objattr['listmarkerposition'] == 'outside') { // do nothing } else { $contentWidth += ($objattr['OUTER-WIDTH'] * _MPDFK); } return; } $lbw = $rbw = 0; // Border widths if (!empty($this->spanborddet)) { if (isset($this->spanborddet['L'])) $lbw = $this->spanborddet['L']['w']; if (isset($this->spanborddet['R'])) $rbw = $this->spanborddet['R']['w']; } if ($this->usingCoreFont) { $clen = strlen($s); } else { $clen = mb_strlen($s, $this->mb_enc); } // for every character in the string for ($i = 0; $i < $clen; $i++) { // extract the current character // get the width of the character in points if ($this->usingCoreFont) { $c = $s[$i]; // Soft Hyphens chr(173) $cw = ($this->GetCharWidthCore($c) * _MPDFK); if (($this->textvar & FC_KERNING) && $i > 0) { // mPDF 5.7.1 if (isset($this->CurrentFont['kerninfo'][$s[($i - 1)]][$c])) { $cw += ($this->CurrentFont['kerninfo'][$s[($i - 1)]][$c] * $this->FontSizePt / 1000 ); } } } else { $c = mb_substr($s, $i, 1, $this->mb_enc); $cw = ($this->GetCharWidthNonCore($c, false) * _MPDFK); // mPDF 5.7.1 // Use OTL GPOS if (isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF)) { // ...WriteFlowingBlock... // Only add XAdvanceL (not sure at present whether RTL or LTR writing direction) // At this point, XAdvanceL and XAdvanceR will balance if (isset($sOTLdata['GPOSinfo'][$i]['XAdvanceL'])) { $cw += $sOTLdata['GPOSinfo'][$i]['XAdvanceL'] * (1000 / $this->CurrentFont['unitsPerEm']) * ($this->FontSize / 1000) * _MPDFK; } } if (($this->textvar & FC_KERNING) && $i > 0) { // mPDF 5.7.1 $lastc = mb_substr($s, ($i - 1), 1, $this->mb_enc); $ulastc = $this->UTF8StringToArray($lastc, false); $uc = $this->UTF8StringToArray($c, false); if (isset($this->CurrentFont['kerninfo'][$ulastc[0]][$uc[0]])) { $cw += ($this->CurrentFont['kerninfo'][$ulastc[0]][$uc[0]] * $this->FontSizePt / 1000 ); } } } if ($i == 0) { $cw += $lbw * _MPDFK; $contentB[(count($contentB) - 1)] .= 'L'; } if ($i == ($clen - 1)) { $cw += $rbw * _MPDFK; $contentB[(count($contentB) - 1)] .= 'R'; } if ($c == ' ') { $currContent .= $c; $contentWidth += $cw; continue; } // Paragraph INDENT $WidthCorrection = 0; if (($newblock) && ($blockstate == 1 || $blockstate == 3) && isset($this->blk[$this->blklvl]['text_indent']) && ($lineCount == 0) && (!$is_table) && ($align != 'C')) { $ti = $this->ConvertSize($this->blk[$this->blklvl]['text_indent'], $this->blk[$this->blklvl]['inner_width'], $this->blk[$this->blklvl]['InlineProperties']['size'], false); // mPDF 5.7.4 $WidthCorrection = ($ti * _MPDFK); } // OUTDENT foreach ($this->objectbuffer AS $k => $objattr) { // mPDF 6 DOTTAB if ($objattr['type'] == 'dottab') { $WidthCorrection -= ($objattr['outdent'] * _MPDFK); break; } } // Added mPDF 3.0 Float DIV $fpaddingR = 0; $fpaddingL = 0; /* -- CSS-FLOAT -- */ if (count($this->floatDivs)) { list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($this->blklvl); if ($r_exists) { $fpaddingR = $r_width; } if ($l_exists) { $fpaddingL = $l_width; } } /* -- END CSS-FLOAT -- */ $usey = $this->y + 0.002; if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 0)) { $usey += $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w']; } /* -- CSS-IMAGE-FLOAT -- */ // If float exists at this level if (isset($this->floatmargins['R']) && $usey <= $this->floatmargins['R']['y1'] && $usey >= $this->floatmargins['R']['y0'] && !$this->floatmargins['R']['skipline']) { $fpaddingR += $this->floatmargins['R']['w']; } if (isset($this->floatmargins['L']) && $usey <= $this->floatmargins['L']['y1'] && $usey >= $this->floatmargins['L']['y0'] && !$this->floatmargins['L']['skipline']) { $fpaddingL += $this->floatmargins['L']['w']; } /* -- END CSS-IMAGE-FLOAT -- */ // try adding another char if (( $contentWidth + $cw > $maxWidth - $WidthCorrection - (($this->cMarginL + $this->cMarginR) * _MPDFK) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * _MPDFK) ) + 0.001)) {// 0.001 is to correct for deviations converting mm=>pts // it won't fit, output what we already have $lineCount++; // contains any content that didn't make it into this print $savedContent = ''; $savedContentB = ''; $savedOTLdata = array(); // mPDF 5.7.1 $savedFont = array(); $savedObj = array(); $savedPreOTLdata = array(); // mPDF 5.7.1 $savedPreContent = array(); $savedPreContentB = array(); $savedPreFont = array(); // mPDF 6 // New line-breaking algorithm ///////////////////// // LINE BREAKING ///////////////////// $breakfound = false; $contentctr = count($content) - 1; if ($this->usingCoreFont) { $charctr = strlen($currContent); } else { $charctr = mb_strlen($currContent, $this->mb_enc); } $checkchar = $c; $prevchar = $this->_getPrevChar($contentctr, $charctr, $content); /* -- CJK-FONTS -- */ ///////////////////// // 1) CJK Overflowing a) punctuation or b) Oikomi ///////////////////// // Next character ($c) is suitable to add as overhanging or squeezed punctuation, or Oikomi if ($CJKoverflow || $Oikomi) { // If flag already set $CJKoverflow = false; $Oikomi = false; $breakfound = true; } if (!$this->usingCoreFont && !$breakfound && $this->checkCJK) { // Get next/following character (in this chunk) $followingchar = ''; if ($i < ($clen - 1)) { if ($this->usingCoreFont) { $followingchar = $s[$i + 1]; } else { $followingchar = mb_substr($s, $i + 1, 1, $this->mb_enc); } } ///////////////////// // 1a) Overflow punctuation ///////////////////// if (preg_match("/[" . $this->pregCJKchars . "]/u", $prevchar) && preg_match("/[" . $this->CJKoverflow . "]/u", $checkchar) && $this->allowCJKorphans) { // add character onto this line $currContent .= $c; $contentWidth += $cw; $CJKoverflow = true; // Set flag continue; } ///////////////////// // 1b) Try squeezing another character(s) onto this line = Oikomi, if character cannot end line // or next character cannot start line (and not splitting CJK numerals) ///////////////////// // NB otherwise it move lastchar(s) to next line to keep $c company = Oidashi, which is done below in standard way elseif (preg_match("/[" . $this->pregCJKchars . "]/u", $checkchar) && $this->allowCJKorphans && (preg_match("/[" . $this->CJKleading . "]/u", $followingchar) || preg_match("/[" . $this->CJKfollowing . "]/u", $checkchar)) && !preg_match("/[" . $this->CJKleading . "]/u", $checkchar) && !preg_match("/[" . $this->CJKfollowing . "]/u", $followingchar) && !(preg_match("/[0-9\x{ff10}-\x{ff19}]/u", $followingchar) && preg_match("/[0-9\x{ff10}-\x{ff19}]/u", $checkchar))) { // add character onto this line $currContent .= $c; $contentWidth += $cw; $Oikomi = true; // Set flag continue; } } /* -- END CJK-FONTS -- */ /* -- HYPHENATION -- */ ///////////////////// // AUTOMATIC HYPHENATION // 2) Automatic hyphen in current word (does not cross tags) ///////////////////// if (isset($this->textparam['hyphens']) && $this->textparam['hyphens'] == 1) { $currWord = ''; // Look back and ahead to get current word for ($ac = $charctr - 1; $ac >= 0; $ac--) { if ($this->usingCoreFont) { $addc = substr($currContent, $ac, 1); } else { $addc = mb_substr($currContent, $ac, 1, $this->mb_enc); } if ($addc == ' ') { break; } $currWord = $addc . $currWord; } $start = $ac + 1; for ($ac = $i; $ac < ($clen - 1); $ac++) { if ($this->usingCoreFont) { $addc = substr($s, $ac, 1); } else { $addc = mb_substr($s, $ac, 1, $this->mb_enc); } if ($addc == ' ') { break; } $currWord .= $addc; } $ptr = $this->hyphenateWord($currWord, $charctr - $start); if ($ptr > -1) { $breakfound = array($contentctr, $start + $ptr, $contentctr, $start + $ptr, 'hyphen'); } } /* -- END HYPHENATION -- */ // Search backwards to find first line-break opportunity while ($breakfound == false && $prevchar !== false) { $cutcontentctr = $contentctr; $cutcharctr = $charctr; $prevchar = $this->_moveToPrevChar($contentctr, $charctr, $content); ///////////////////// // 3) Break at SPACE ///////////////////// if ($prevchar == ' ') { $breakfound = array($contentctr, $charctr, $cutcontentctr, $cutcharctr, 'discard'); } ///////////////////// // 4) Break at U+200B in current word (Khmer, Lao & Thai Invisible word boundary, and Tibetan) ///////////////////// elseif ($prevchar == "\xe2\x80\x8b") { // U+200B Zero-width Word Break $breakfound = array($contentctr, $charctr, $cutcontentctr, $cutcharctr, 'discard'); } ///////////////////// // 5) Break at Hard HYPHEN '-' or U+2010 ///////////////////// elseif (isset($this->textparam['hyphens']) && $this->textparam['hyphens'] != 2 && ($prevchar == '-' || $prevchar == "\xe2\x80\x90")) { // Don't break a URL // Look back to get first part of current word $checkw = ''; for ($ac = $charctr - 1; $ac >= 0; $ac--) { if ($this->usingCoreFont) { $addc = substr($currContent, $ac, 1); } else { $addc = mb_substr($currContent, $ac, 1, $this->mb_enc); } if ($addc == ' ') { break; } $checkw = $addc . $checkw; } // Don't break if HyphenMinus AND (a URL or before a numeral or before a >) if ((!preg_match('/(http:|ftp:|https:|www\.)/', $checkw) && $checkchar != '>' && !preg_match('/[0-9]/', $checkchar)) || $prevchar == "\xe2\x80\x90") { $breakfound = array($cutcontentctr, $cutcharctr, $cutcontentctr, $cutcharctr, 'cut'); } } ///////////////////// // 6) Break at Soft HYPHEN (replace with hard hyphen) ///////////////////// elseif (isset($this->textparam['hyphens']) && $this->textparam['hyphens'] != 2 && !$this->usingCoreFont && $prevchar == "\xc2\xad") { $breakfound = array($cutcontentctr, $cutcharctr, $cutcontentctr, $cutcharctr, 'cut'); $content[$contentctr] = mb_substr($content[$contentctr], 0, $charctr, $this->mb_enc) . '-' . mb_substr($content[$contentctr], $charctr + 1, mb_strlen($content[$contentctr]), $this->mb_enc); if (!empty($cOTLdata[$contentctr])) { $cOTLdata[$contentctr]['char_data'][$charctr] = array('bidi_class' => 9, 'uni' => 45); $cOTLdata[$contentctr]['group'][$charctr] = 'C'; } } elseif (isset($this->textparam['hyphens']) && $this->textparam['hyphens'] != 2 && $this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats' && $prevchar == chr(173)) { $breakfound = array($cutcontentctr, $cutcharctr, $cutcontentctr, $cutcharctr, 'cut'); $content[$contentctr] = substr($content[$contentctr], 0, $charctr) . '-' . substr($content[$contentctr], $charctr + 1); } /* -- CJK-FONTS -- */ ///////////////////// // 7) Break at CJK characters (unless forbidden characters to end or start line) // CJK Avoiding line break in the middle of numerals ///////////////////// elseif (!$this->usingCoreFont && $this->checkCJK && preg_match("/[" . $this->pregCJKchars . "]/u", $checkchar) && !preg_match("/[" . $this->CJKfollowing . "]/u", $checkchar) && !preg_match("/[" . $this->CJKleading . "]/u", $prevchar) && !(preg_match("/[0-9\x{ff10}-\x{ff19}]/u", $prevchar) && preg_match("/[0-9\x{ff10}-\x{ff19}]/u", $checkchar))) { $breakfound = array($cutcontentctr, $cutcharctr, $cutcontentctr, $cutcharctr, 'cut'); } /* -- END CJK-FONTS -- */ ///////////////////// // 8) Break at OBJECT (Break before all objects here - selected objects are moved forward to next line below e.g. dottab) ///////////////////// if (isset($this->objectbuffer[$contentctr])) { $breakfound = array($cutcontentctr, $cutcharctr, $cutcontentctr, $cutcharctr, 'cut'); } $checkchar = $prevchar; } // If a line-break opportunity found: if (is_array($breakfound)) { $contentctr = $breakfound[0]; $charctr = $breakfound[1]; $cutcontentctr = $breakfound[2]; $cutcharctr = $breakfound[3]; $type = $breakfound[4]; // Cache chunks which are already processed, but now need to be passed on to the new line for ($ix = count($content) - 1; $ix > $cutcontentctr; $ix--) { // save and crop off any subsequent chunks /* -- OTL -- */ if (!empty($sOTLdata)) { $tmpOTL = array_pop($cOTLdata); $savedPreOTLdata[] = $tmpOTL; } /* -- END OTL -- */ $savedPreContent[] = array_pop($content); $savedPreContentB[] = array_pop($contentB); $savedPreFont[] = array_pop($font); } // Next cache the part which will start the next line if ($this->usingCoreFont) { $savedPreContent[] = substr($content[$cutcontentctr], $cutcharctr); } else { $savedPreContent[] = mb_substr($content[$cutcontentctr], $cutcharctr, mb_strlen($content[$cutcontentctr]), $this->mb_enc); } $savedPreContentB[] = preg_replace('/L/', '', $contentB[$cutcontentctr]); $savedPreFont[] = $font[$cutcontentctr]; /* -- OTL -- */ if (!empty($sOTLdata)) { $savedPreOTLdata[] = $this->otl->splitOTLdata($cOTLdata[$cutcontentctr], $cutcharctr, $cutcharctr); } /* -- END OTL -- */ // Finally adjust the Current content which ends this line if ($cutcharctr == 0 && $type == 'discard') { array_pop($content); array_pop($contentB); array_pop($font); array_pop($cOTLdata); } $currContent = & $content[count($content) - 1]; if ($this->usingCoreFont) { $currContent = substr($currContent, 0, $charctr); } else { $currContent = mb_substr($currContent, 0, $charctr, $this->mb_enc); } if (!empty($sOTLdata)) { $savedPreOTLdata[] = $this->otl->splitOTLdata($cOTLdata[(count($cOTLdata) - 1)], mb_strlen($currContent, $this->mb_enc)); } if (strpos($contentB[(count($contentB) - 1)], 'R') !== false) { // ??? $contentB[count($content) - 1] = preg_replace('/R/', '', $contentB[count($content) - 1]); // ??? } if ($type == 'hyphen') { $currContent .= '-'; if (!empty($cOTLdata[(count($cOTLdata) - 1)])) { $cOTLdata[(count($cOTLdata) - 1)]['char_data'][] = array('bidi_class' => 9, 'uni' => 45); $cOTLdata[(count($cOTLdata) - 1)]['group'] .= 'C'; } } $savedContent = ''; $savedContentB = ''; $savedFont = array(); $savedOTLdata = array(); } // If no line-break opportunity found - split at current position // or - Next character ($c) is suitable to add as overhanging or squeezed punctuation, or Oikomi, as set above by: // 1) CJK Overflowing a) punctuation or b) Oikomi // in which case $breakfound==1 and NOT array if (!is_array($breakfound)) { $savedFont = $this->saveFont(); if (!empty($sOTLdata)) { $savedOTLdata = $this->otl->splitOTLdata($cOTLdata[(count($cOTLdata) - 1)], mb_strlen($currContent, $this->mb_enc)); } } if ($content[count($content) - 1] == '' && !isset($this->objectbuffer[count($content) - 1])) { array_pop($content); array_pop($contentB); array_pop($font); array_pop($cOTLdata); $currContent = & $content[count($content) - 1]; } // Right Trim current content - including CJK space, and for OTLdata // incl. CJK - strip CJK space at end of line = \xe3\x80\x80 = CJK space $currContent = rtrim($currContent); if ($this->checkCJK) { $currContent = preg_replace("/\xe3\x80\x80$/", '', $currContent); } // *CJK-FONTS* /* -- OTL -- */ if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) { $this->otl->trimOTLdata($cOTLdata[count($cOTLdata) - 1], false, true); // NB also does U+3000 } /* -- END OTL -- */ // Selected OBJECTS are moved forward to next line, unless they come before a space or U+200B (type='discard') if (isset($this->objectbuffer[(count($content) - 1)]) && (!isset($type) || $type != 'discard')) { $objtype = $this->objectbuffer[(count($content) - 1)]['type']; if ($objtype == 'dottab' || $objtype == 'bookmark' || $objtype == 'indexentry' || $objtype == 'toc' || $objtype == 'annot') { $savedObj = array_pop($this->objectbuffer); } } // Decimal alignment (cancel if wraps to > 1 line) if ($is_table && substr($align, 0, 1) == 'D') { $align = substr($align, 2, 1); } $lineBox = array(); $this->_setInlineBlockHeights($lineBox, $stackHeight, $content, $font, $is_table); // update $contentWidth since it has changed with cropping $contentWidth = 0; $inclCursive = false; foreach ($content as $k => $chunk) { if (isset($this->objectbuffer[$k]) && $this->objectbuffer[$k]) { // LIST MARKERS if ($this->objectbuffer[$k]['type'] == 'image' && isset($this->objectbuffer[$k]['listmarker']) && $this->objectbuffer[$k]['listmarker']) { if ($this->objectbuffer[$k]['listmarkerposition'] != 'outside') { $contentWidth += $this->objectbuffer[$k]['OUTER-WIDTH'] * _MPDFK; } } else { $contentWidth += $this->objectbuffer[$k]['OUTER-WIDTH'] * _MPDFK; } } elseif (!isset($this->objectbuffer[$k]) || (isset($this->objectbuffer[$k]) && !$this->objectbuffer[$k])) { $this->restoreFont($font[$k], false); if ($this->checkCJK && $k == count($content) - 1 && $CJKoverflow && $align == 'J' && $this->allowCJKoverflow && $this->CJKforceend) { // force-end overhang $hanger = mb_substr($chunk, mb_strlen($chunk, $this->mb_enc) - 1, 1, $this->mb_enc); // Probably ought to do something with char_data and GPOS in cOTLdata... $content[$k] = $chunk = mb_substr($chunk, 0, mb_strlen($chunk, $this->mb_enc) - 1, $this->mb_enc); } // Soft Hyphens chr(173) + Replace NBSP with SPACE + Set inclcursive if includes CURSIVE TEXT if (!$this->usingCoreFont) { /* -- OTL -- */ if ((isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) || !empty($sOTLdata)) { $this->otl->removeChar($chunk, $cOTLdata[$k], "\xc2\xad"); $this->otl->replaceSpace($chunk, $cOTLdata[$k]); // NBSP -> space if (preg_match("/([" . $this->pregCURSchars . "])/u", $chunk)) { $inclCursive = true; } $content[$k] = $chunk; } /* -- END OTL -- */ else { // *OTL* $content[$k] = $chunk = str_replace("\xc2\xad", '', $chunk); $content[$k] = $chunk = str_replace(chr(194) . chr(160), chr(32), $chunk); } // *OTL* } elseif ($this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats') { $content[$k] = $chunk = str_replace(chr(173), '', $chunk); $content[$k] = $chunk = str_replace(chr(160), chr(32), $chunk); } $contentWidth += $this->GetStringWidth($chunk, true, (isset($cOTLdata[$k]) ? $cOTLdata[$k] : false), $this->textvar) * _MPDFK; // mPDF 5.7.1 if (!empty($this->spanborddet)) { if (isset($this->spanborddet['L']['w']) && strpos($contentB[$k], 'L') !== false) $contentWidth += $this->spanborddet['L']['w'] * _MPDFK; if (isset($this->spanborddet['R']['w']) && strpos($contentB[$k], 'R') !== false) $contentWidth += $this->spanborddet['R']['w'] * _MPDFK; } } } $lastfontreqstyle = (isset($font[count($font) - 1]['ReqFontStyle']) ? $font[count($font) - 1]['ReqFontStyle'] : ''); $lastfontstyle = (isset($font[count($font) - 1]['style']) ? $font[count($font) - 1]['style'] : ''); if ($blockdir == 'ltr' && strpos($lastfontreqstyle, "I") !== false && strpos($lastfontstyle, "I") === false) { // Artificial italic $lastitalic = $this->FontSize * 0.15 * _MPDFK; } else { $lastitalic = 0; } // NOW FORMAT THE LINE TO OUTPUT if (!$table_draft) { // DIRECTIONALITY RTL $chunkorder = range(0, count($content) - 1); // mPDF 5.7 /* -- OTL -- */ // mPDF 6 if ($blockdir == 'rtl' || $this->biDirectional) { $this->otl->_bidiReorder($chunkorder, $content, $cOTLdata, $blockdir); // From this point on, $content and $cOTLdata may contain more elements (and re-ordered) compared to // $this->objectbuffer and $font ($chunkorder contains the mapping) } /* -- END OTL -- */ // Remove any XAdvance from OTL data at end of line foreach ($chunkorder AS $aord => $k) { if (count($cOTLdata)) { $this->restoreFont($font[$k], false); // ...WriteFlowingBlock... if ($aord == count($chunkorder) - 1 && isset($cOTLdata[$aord]['group'])) { // Last chunk on line $nGPOS = strlen($cOTLdata[$aord]['group']) - 1; // Last character if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL']) || isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'])) { if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'])) { $w = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] * 1000 / $this->CurrentFont['unitsPerEm']; } else { $w = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] * 1000 / $this->CurrentFont['unitsPerEm']; } $w *= ($this->FontSize / 1000); $contentWidth -= $w * _MPDFK; $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] = 0; $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] = 0; } // If last character has an XPlacement set, adjust width calculation, and add to XAdvance to account for it if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'])) { $w = -$cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'] * 1000 / $this->CurrentFont['unitsPerEm']; $w *= ($this->FontSize / 1000); $contentWidth -= $w * _MPDFK; $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement']; $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement']; } } } } // JUSTIFICATION J $jcharspacing = 0; $jws = 0; $nb_carac = 0; $nb_spaces = 0; $jkashida = 0; // if it's justified, we need to find the char/word spacing (or if hanger $this->CJKforceend) if (($align == 'J' && !$CJKoverflow) || (($contentWidth + $lastitalic > $maxWidth - $WidthCorrection - (($this->cMarginL + $this->cMarginR) * _MPDFK) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * _MPDFK) ) + 0.001) && (!$CJKoverflow || ($CJKoverflow && !$this->allowCJKoverflow))) || $CJKoverflow && $align == 'J' && $this->allowCJKoverflow && $hanger && $this->CJKforceend) { // 0.001 is to correct for deviations converting mm=>pts // JUSTIFY J (Use character spacing) // WORD SPACING foreach ($chunkorder AS $aord => $k) { // mPDF 5.7 $chunk = $content[$aord]; if (!isset($this->objectbuffer[$k]) || (isset($this->objectbuffer[$k]) && !$this->objectbuffer[$k])) { $nb_carac += mb_strlen($chunk, $this->mb_enc); $nb_spaces += mb_substr_count($chunk, ' ', $this->mb_enc); // Use GPOS OTL if (isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF)) { if (isset($cOTLdata[$aord]['group']) && $cOTLdata[$aord]['group']) { $nb_carac -= substr_count($cOTLdata[$aord]['group'], 'M'); } } } else { $nb_carac ++; } // mPDF 6 allow spacing for inline object } // GetJSpacing adds kashida spacing to GPOSinfo if appropriate for Font list($jcharspacing, $jws, $jkashida) = $this->GetJspacing($nb_carac, $nb_spaces, ($maxWidth - $lastitalic - $contentWidth - $WidthCorrection - (($this->cMarginL + $this->cMarginR) * _MPDFK) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * _MPDFK) )), $inclCursive, $cOTLdata); } // WORD SPACING $empty = $maxWidth - $lastitalic - $WidthCorrection - $contentWidth - (($this->cMarginL + $this->cMarginR) * _MPDFK) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * _MPDFK) ); $empty -= ($jcharspacing * ($nb_carac - 1)); // mPDF 6 nb_carac MINUS 1 $empty -= ($jws * $nb_spaces); $empty -= ($jkashida); $empty /= _MPDFK; $b = ''; //do not use borders // Get PAGEBREAK TO TEST for height including the top border/padding $check_h = max($this->divheight, $stackHeight); if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($this->blklvl > 0) && ($lineCount == 1) && (!$is_table)) { $check_h += ($this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['border_top']['w']); } if ($this->ColActive && $check_h > ($this->PageBreakTrigger - $this->y0)) { $this->SetCol($this->NbCol - 1); } // PAGEBREAK // 'If' below used in order to fix "first-line of other page with justify on" bug if (!$is_table && ($this->y + $check_h) > $this->PageBreakTrigger and ! $this->InFooter and $this->AcceptPageBreak()) { $bak_x = $this->x; //Current X position // WORD SPACING $ws = $this->ws; //Word Spacing $charspacing = $this->charspacing; //Character Spacing $this->ResetSpacing(); $this->AddPage($this->CurOrientation); $this->x = $bak_x; // Added to correct for OddEven Margins $currentx += $this->MarginCorrection; $this->x += $this->MarginCorrection; // WORD SPACING $this->SetSpacing($charspacing, $ws); } if ($this->kwt && !$is_table) { // mPDF 5.7+ $this->printkwtbuffer(); $this->kwt = false; } /* -- COLUMNS -- */ // COLS // COLUMN CHANGE if ($this->CurrCol != $oldcolumn) { $currentx += $this->ChangeColumn * ($this->ColWidth + $this->ColGap); $this->x += $this->ChangeColumn * ($this->ColWidth + $this->ColGap); $oldcolumn = $this->CurrCol; } if ($this->ColActive && !$is_table) { $this->breakpoints[$this->CurrCol][] = $this->y; } // *COLUMNS* /* -- END COLUMNS -- */ // TOP MARGIN if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($this->blk[$this->blklvl]['margin_top']) && ($lineCount == 1) && (!$is_table)) { $this->DivLn($this->blk[$this->blklvl]['margin_top'], $this->blklvl - 1, true, $this->blk[$this->blklvl]['margin_collapse']); if ($this->ColActive) { $this->breakpoints[$this->CurrCol][] = $this->y; } // *COLUMNS* } // Update y0 for top of block (used to paint border) if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 1) && (!$is_table)) { $this->blk[$this->blklvl]['y0'] = $this->y; $this->blk[$this->blklvl]['startpage'] = $this->page; if ($this->blk[$this->blklvl]['float']) { $this->blk[$this->blklvl]['float_start_y'] = $this->y; } } // TOP PADDING and BORDER spacing/fill if (($newblock) && ($blockstate == 1 || $blockstate == 3) && (($this->blk[$this->blklvl]['padding_top']) || ($this->blk[$this->blklvl]['border_top'])) && ($lineCount == 1) && (!$is_table)) { // $state = 0 normal; 1 top; 2 bottom; 3 top and bottom $this->DivLn($this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'], -3, true, false, 1); if ($this->ColActive) { $this->breakpoints[$this->CurrCol][] = $this->y; } // *COLUMNS* } $arraysize = count($chunkorder); $margins = ($this->cMarginL + $this->cMarginR) + ($ipaddingL + $ipaddingR + $fpaddingR + $fpaddingR ); // PAINT BACKGROUND FOR THIS LINE if (!$is_table) { $this->DivLn($stackHeight, $this->blklvl, false); } // false -> don't advance y $this->x = $currentx + $this->cMarginL + $ipaddingL + $fpaddingL; if ($align == 'R') { $this->x += $empty; } elseif ($align == 'C') { $this->x += ($empty / 2); } // Paragraph INDENT if (isset($this->blk[$this->blklvl]['text_indent']) && ($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 1) && (!$is_table) && ($blockdir != 'rtl') && ($align != 'C')) { $ti = $this->ConvertSize($this->blk[$this->blklvl]['text_indent'], $this->blk[$this->blklvl]['inner_width'], $this->blk[$this->blklvl]['InlineProperties']['size'], false); // mPDF 5.7.4 $this->x += $ti; } // BIDI magic_reverse moved upwards from here foreach ($chunkorder AS $aord => $k) { // mPDF 5.7 $chunk = $content[$aord]; if (isset($this->objectbuffer[$k]) && $this->objectbuffer[$k]) { $xadj = $this->x - $this->objectbuffer[$k]['OUTER-X']; $this->objectbuffer[$k]['OUTER-X'] += $xadj; $this->objectbuffer[$k]['BORDER-X'] += $xadj; $this->objectbuffer[$k]['INNER-X'] += $xadj; if ($this->objectbuffer[$k]['type'] == 'listmarker') { $this->objectbuffer[$k]['lineBox'] = $lineBox[-1]; // Block element details for glyph-origin } $yadj = $this->y - $this->objectbuffer[$k]['OUTER-Y']; if ($this->objectbuffer[$k]['type'] == 'dottab') { // mPDF 6 DOTTAB $this->objectbuffer[$k]['lineBox'] = $lineBox[$k]; // element details for glyph-origin } if ($this->objectbuffer[$k]['type'] != 'dottab') { // mPDF 6 DOTTAB $yadj += $lineBox[$k]['top']; } $this->objectbuffer[$k]['OUTER-Y'] += $yadj; $this->objectbuffer[$k]['BORDER-Y'] += $yadj; $this->objectbuffer[$k]['INNER-Y'] += $yadj; } $this->restoreFont($font[$k]); // mPDF 5.7 $this->SetSpacing(($this->fixedlSpacing * _MPDFK) + $jcharspacing, ($this->fixedlSpacing + $this->minwSpacing) * _MPDFK + $jws); // Now unset these values so they don't influence GetStringwidth below or in fn. Cell $this->fixedlSpacing = false; $this->minwSpacing = 0; $save_vis = $this->visibility; if (isset($this->textparam['visibility']) && $this->textparam['visibility'] && $this->textparam['visibility'] != $this->visibility) { $this->SetVisibility($this->textparam['visibility']); } // *********** SPAN BACKGROUND COLOR ***************** // if ($this->spanbgcolor) { $cor = $this->spanbgcolorarray; $this->SetFColor($cor); $save_fill = $fill; $spanfill = 1; $fill = 1; } if (!empty($this->spanborddet)) { if (strpos($contentB[$k], 'L') !== false) $this->x += (isset($this->spanborddet['L']['w']) ? $this->spanborddet['L']['w'] : 0); if (strpos($contentB[$k], 'L') === false) $this->spanborddet['L']['s'] = $this->spanborddet['L']['w'] = 0; if (strpos($contentB[$k], 'R') === false) $this->spanborddet['R']['s'] = $this->spanborddet['R']['w'] = 0; } // WORD SPACING // StringWidth this time includes any kashida spacing $stringWidth = $this->GetStringWidth($chunk, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, true); $nch = mb_strlen($chunk, $this->mb_enc); // Use GPOS OTL if (isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF)) { if (isset($cOTLdata[$aord]['group']) && $cOTLdata[$aord]['group']) { $nch -= substr_count($cOTLdata[$aord]['group'], 'M'); } } $stringWidth += ( $this->charspacing * $nch / _MPDFK ); $stringWidth += ( $this->ws * mb_substr_count($chunk, ' ', $this->mb_enc) / _MPDFK ); if (isset($this->objectbuffer[$k])) { // LIST MARKERS // mPDF 6 Lists if ($this->objectbuffer[$k]['type'] == 'image' && isset($this->objectbuffer[$k]['listmarker']) && $this->objectbuffer[$k]['listmarker'] && $this->objectbuffer[$k]['listmarkerposition'] == 'outside') { $stringWidth = 0; } else { $stringWidth = $this->objectbuffer[$k]['OUTER-WIDTH']; } } if ($stringWidth == 0) { $stringWidth = 0.000001; } if ($aord == $arraysize - 1) { $stringWidth -= ( $this->charspacing / _MPDFK ); if ($this->checkCJK && $CJKoverflow && $align == 'J' && $this->allowCJKoverflow && $hanger && $this->CJKforceend) { // force-end overhang $this->Cell($stringWidth, $stackHeight, $chunk, '', 0, '', $fill, $this->HREF, $currentx, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false)); $this->Cell($this->GetStringWidth($hanger), $stackHeight, $hanger, '', 1, '', $fill, $this->HREF, $currentx, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false)); } else { $this->Cell($stringWidth, $stackHeight, $chunk, '', 1, '', $fill, $this->HREF, $currentx, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false)); //mono-style line or last part (skips line) } } else $this->Cell($stringWidth, $stackHeight, $chunk, '', 0, '', $fill, $this->HREF, 0, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false)); //first or middle part if (!empty($this->spanborddet)) { if (strpos($contentB[$k], 'R') !== false && $aord != $arraysize - 1) $this->x += $this->spanborddet['R']['w']; } // *********** SPAN BACKGROUND COLOR OFF - RESET BLOCK BGCOLOR ***************** // if (isset($spanfill) && $spanfill) { $fill = $save_fill; $spanfill = 0; if ($fill) { $this->SetFColor($bcor); } } if (isset($this->textparam['visibility']) && $this->textparam['visibility'] && $this->visibility != $save_vis) { $this->SetVisibility($save_vis); } } } elseif ($table_draft) { $this->y += $stackHeight; } if (!$is_table) { $this->maxPosR = max($this->maxPosR, ($this->w - $this->rMargin - $this->blk[$this->blklvl]['outer_right_margin'])); $this->maxPosL = min($this->maxPosL, ($this->lMargin + $this->blk[$this->blklvl]['outer_left_margin'])); } // move on to the next line, reset variables, tack on saved content and current char if (!$table_draft) $this->printobjectbuffer($is_table, $blockdir); $this->objectbuffer = array(); /* -- CSS-IMAGE-FLOAT -- */ // Update values if set to skipline if ($this->floatmargins) { $this->_advanceFloatMargins(); } /* -- END CSS-IMAGE-FLOAT -- */ // Reset lineheight $stackHeight = $this->divheight; $valign = 'M'; $font = array(); $content = array(); $contentB = array(); $cOTLdata = array(); // mPDF 5.7.1 $contentWidth = 0; if (!empty($savedObj)) { $this->objectbuffer[] = $savedObj; $font[] = $savedFont; $content[] = ''; $contentB[] = ''; $cOTLdata[] = array(); // mPDF 5.7.1 $contentWidth += $savedObj['OUTER-WIDTH'] * _MPDFK; } if (count($savedPreContent) > 0) { for ($ix = count($savedPreContent) - 1; $ix >= 0; $ix--) { $font[] = $savedPreFont[$ix]; $content[] = $savedPreContent[$ix]; $contentB[] = $savedPreContentB[$ix]; if (!empty($sOTLdata)) { $cOTLdata[] = $savedPreOTLdata[$ix]; } $this->restoreFont($savedPreFont[$ix]); $lbw = $rbw = 0; // Border widths if (!empty($this->spanborddet)) { $lbw = (isset($this->spanborddet['L']['w']) ? $this->spanborddet['L']['w'] : 0); $rbw = (isset($this->spanborddet['R']['w']) ? $this->spanborddet['R']['w'] : 0); } if ($ix > 0) { $contentWidth += $this->GetStringWidth($savedPreContent[$ix], true, (isset($savedPreOTLdata[$ix]) ? $savedPreOTLdata[$ix] : false), $this->textvar) * _MPDFK; // mPDF 5.7.1 if (strpos($savedPreContentB[$ix], 'L') !== false) $contentWidth += $lbw; if (strpos($savedPreContentB[$ix], 'R') !== false) $contentWidth += $rbw; } } $savedPreContent = array(); $savedPreContentB = array(); $savedPreOTLdata = array(); // mPDF 5.7.1 $savedPreFont = array(); $content[(count($content) - 1)] .= $c; } else { $font[] = $savedFont; $content[] = $savedContent . $c; $contentB[] = $savedContentB; $cOTLdata[] = $savedOTLdata; // mPDF 5.7.1 } $currContent = & $content[(count($content) - 1)]; $this->restoreFont($font[(count($font) - 1)]); // mPDF 6.0 /* -- CJK-FONTS -- */ // CJK - strip CJK space at start of line // = \xe3\x80\x80 = CJK space if ($this->checkCJK && $currContent == "\xe3\x80\x80") { $currContent = ''; if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) { $this->otl->trimOTLdata($cOTLdata[count($cOTLdata) - 1], true, false); // left trim U+3000 } } /* -- END CJK-FONTS -- */ $lbw = $rbw = 0; // Border widths if (!empty($this->spanborddet)) { $lbw = (isset($this->spanborddet['L']['w']) ? $this->spanborddet['L']['w'] : 0); $rbw = (isset($this->spanborddet['R']['w']) ? $this->spanborddet['R']['w'] : 0); } $contentWidth += $this->GetStringWidth($currContent, false, (isset($cOTLdata[(count($cOTLdata) - 1)]) ? $cOTLdata[(count($cOTLdata) - 1)] : false), $this->textvar) * _MPDFK; // mPDF 5.7.1 if (strpos($savedContentB, 'L') !== false) $contentWidth += $lbw; $CJKoverflow = false; $hanger = ''; } // another character will fit, so add it on else { $contentWidth += $cw; $currContent .= $c; } } unset($content); unset($contentB); } //----------------------END OF FLOWING BLOCK------------------------------------// /* -- CSS-IMAGE-FLOAT -- */ // Update values if set to skipline function _advanceFloatMargins() { // Update floatmargins - L if (isset($this->floatmargins['L']) && $this->floatmargins['L']['skipline'] && $this->floatmargins['L']['y0'] != $this->y) { $yadj = $this->y - $this->floatmargins['L']['y0']; $this->floatmargins['L']['y0'] = $this->y; $this->floatmargins['L']['y1'] += $yadj; // Update objattr in floatbuffer if ($this->floatbuffer[$this->floatmargins['L']['id']]['border_left']['w']) { $this->floatbuffer[$this->floatmargins['L']['id']]['BORDER-Y'] += $yadj; } $this->floatbuffer[$this->floatmargins['L']['id']]['INNER-Y'] += $yadj; $this->floatbuffer[$this->floatmargins['L']['id']]['OUTER-Y'] += $yadj; // Unset values $this->floatbuffer[$this->floatmargins['L']['id']]['skipline'] = false; $this->floatmargins['L']['skipline'] = false; $this->floatmargins['L']['id'] = ''; } // Update floatmargins - R if (isset($this->floatmargins['R']) && $this->floatmargins['R']['skipline'] && $this->floatmargins['R']['y0'] != $this->y) { $yadj = $this->y - $this->floatmargins['R']['y0']; $this->floatmargins['R']['y0'] = $this->y; $this->floatmargins['R']['y1'] += $yadj; // Update objattr in floatbuffer if ($this->floatbuffer[$this->floatmargins['R']['id']]['border_left']['w']) { $this->floatbuffer[$this->floatmargins['R']['id']]['BORDER-Y'] += $yadj; } $this->floatbuffer[$this->floatmargins['R']['id']]['INNER-Y'] += $yadj; $this->floatbuffer[$this->floatmargins['R']['id']]['OUTER-Y'] += $yadj; // Unset values $this->floatbuffer[$this->floatmargins['R']['id']]['skipline'] = false; $this->floatmargins['R']['skipline'] = false; $this->floatmargins['R']['id'] = ''; } } /* -- END CSS-IMAGE-FLOAT -- */ /* -- END HTML-CSS -- */ function _SetTextRendering($mode) { if (!(($mode == 0) || ($mode == 1) || ($mode == 2))) throw new MpdfException("Text rendering mode should be 0, 1 or 2 (value : $mode)"); $tr = ($mode . ' Tr'); if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['TextRendering']) && $this->pageoutput[$this->page]['TextRendering'] != $tr) || !isset($this->pageoutput[$this->page]['TextRendering']))) { $this->_out($tr); } $this->pageoutput[$this->page]['TextRendering'] = $tr; } function SetTextOutline($params = array()) { if (isset($params['outline-s']) && $params['outline-s']) { $this->SetLineWidth($params['outline-WIDTH']); $this->SetDColor($params['outline-COLOR']); $tr = ('2 Tr'); if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['TextRendering']) && $this->pageoutput[$this->page]['TextRendering'] != $tr) || !isset($this->pageoutput[$this->page]['TextRendering']))) { $this->_out($tr); } $this->pageoutput[$this->page]['TextRendering'] = $tr; } else { //Now resets all values $this->SetLineWidth(0.2); $this->SetDColor($this->ConvertColor(0)); $this->_SetTextRendering(0); $tr = ('0 Tr'); if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['TextRendering']) && $this->pageoutput[$this->page]['TextRendering'] != $tr) || !isset($this->pageoutput[$this->page]['TextRendering']))) { $this->_out($tr); } $this->pageoutput[$this->page]['TextRendering'] = $tr; } } function Image($file, $x, $y, $w = 0, $h = 0, $type = '', $link = '', $paint = true, $constrain = true, $watermark = false, $shownoimg = true, $allowvector = true) { $orig_srcpath = $file; $this->GetFullPath($file); $info = $this->_getImage($file, true, $allowvector, $orig_srcpath); if (!$info && $paint) { $info = $this->_getImage($this->noImageFile); if ($info) { $file = $this->noImageFile; $w = ($info['w'] * (25.4 / $this->dpi)); // 14 x 16px $h = ($info['h'] * (25.4 / $this->dpi)); // 14 x 16px } } if (!$info) return false; //Automatic width and height calculation if needed if ($w == 0 and $h == 0) { /* -- IMAGES-WMF -- */ if ($info['type'] == 'wmf') { // WMF units are twips (1/20pt) // divide by 20 to get points // divide by k to get user units $w = abs($info['w']) / (20 * _MPDFK); $h = abs($info['h']) / (20 * _MPDFK); } else /* -- END IMAGES-WMF -- */ if ($info['type'] == 'svg') { // returned SVG units are pts // divide by k to get user units (mm) $w = abs($info['w']) / _MPDFK; $h = abs($info['h']) / _MPDFK; } else { //Put image at default image dpi $w = ($info['w'] / _MPDFK) * (72 / $this->img_dpi); $h = ($info['h'] / _MPDFK) * (72 / $this->img_dpi); } } if ($w == 0) $w = abs($h * $info['w'] / $info['h']); if ($h == 0) $h = abs($w * $info['h'] / $info['w']); /* -- WATERMARK -- */ if ($watermark) { $maxw = $this->w; $maxh = $this->h; // Size = D PF or array if (is_array($this->watermark_size)) { $w = $this->watermark_size[0]; $h = $this->watermark_size[1]; } elseif (!is_string($this->watermark_size)) { $maxw -= $this->watermark_size * 2; $maxh -= $this->watermark_size * 2; $w = $maxw; $h = abs($w * $info['h'] / $info['w']); if ($h > $maxh) { $h = $maxh; $w = abs($h * $info['w'] / $info['h']); } } elseif ($this->watermark_size == 'F') { if ($this->ColActive) { $maxw = $this->w - ($this->DeflMargin + $this->DefrMargin); } else { $maxw = $this->pgwidth; } $maxh = $this->h - ($this->tMargin + $this->bMargin); $w = $maxw; $h = abs($w * $info['h'] / $info['w']); if ($h > $maxh) { $h = $maxh; $w = abs($h * $info['w'] / $info['h']); } } elseif ($this->watermark_size == 'P') { // Default P $w = $maxw; $h = abs($w * $info['h'] / $info['w']); if ($h > $maxh) { $h = $maxh; $w = abs($h * $info['w'] / $info['h']); } } // Automatically resize to maximum dimensions of page if too large if ($w > $maxw) { $w = $maxw; $h = abs($w * $info['h'] / $info['w']); } if ($h > $maxh) { $h = $maxh; $w = abs($h * $info['w'] / $info['h']); } // Position if (is_array($this->watermark_pos)) { $x = $this->watermark_pos[0]; $y = $this->watermark_pos[1]; } elseif ($this->watermark_pos == 'F') { // centred on printable area if ($this->ColActive) { // *COLUMNS* if (($this->mirrorMargins) && (($this->page) % 2 == 0)) { $xadj = $this->DeflMargin - $this->DefrMargin; } // *COLUMNS* else { $xadj = 0; } // *COLUMNS* $x = ($this->DeflMargin - $xadj + ($this->w - ($this->DeflMargin + $this->DefrMargin)) / 2) - ($w / 2); // *COLUMNS* } // *COLUMNS* else { // *COLUMNS* $x = ($this->lMargin + ($this->pgwidth) / 2) - ($w / 2); } // *COLUMNS* $y = ($this->tMargin + ($this->h - ($this->tMargin + $this->bMargin)) / 2) - ($h / 2); } else { // default P - centred on whole page $x = ($this->w / 2) - ($w / 2); $y = ($this->h / 2) - ($h / 2); } /* -- IMAGES-WMF -- */ if ($info['type'] == 'wmf') { $sx = $w * _MPDFK / $info['w']; $sy = -$h * _MPDFK / $info['h']; $outstring = sprintf('q %.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, $sy, $x * _MPDFK - $sx * $info['x'], (($this->h - $y) * _MPDFK) - $sy * $info['y'], $info['i']); } else /* -- END IMAGES-WMF -- */ if ($info['type'] == 'svg') { $sx = $w * _MPDFK / $info['w']; $sy = -$h * _MPDFK / $info['h']; $outstring = sprintf('q %.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, $sy, $x * _MPDFK - $sx * $info['x'], (($this->h - $y) * _MPDFK) - $sy * $info['y'], $info['i']); } else { $outstring = sprintf("q %.3F 0 0 %.3F %.3F %.3F cm /I%d Do Q", $w * _MPDFK, $h * _MPDFK, $x * _MPDFK, ($this->h - ($y + $h)) * _MPDFK, $info['i']); } if ($this->watermarkImgBehind) { $outstring = $this->watermarkImgAlpha . "\n" . $outstring . "\n" . $this->SetAlpha(1, 'Normal', true) . "\n"; $this->pages[$this->page] = preg_replace('/(___BACKGROUND___PATTERNS' . $this->uniqstr . ')/', "\n" . $outstring . "\n" . '\\1', $this->pages[$this->page]); } else { $this->_out($outstring); } return 0; } // end of IF watermark /* -- END WATERMARK -- */ if ($constrain) { // Automatically resize to maximum dimensions of page if too large if (isset($this->blk[$this->blklvl]['inner_width']) && $this->blk[$this->blklvl]['inner_width']) { $maxw = $this->blk[$this->blklvl]['inner_width']; } else { $maxw = $this->pgwidth; } if ($w > $maxw) { $w = $maxw; $h = abs($w * $info['h'] / $info['w']); } if ($h > $this->h - ($this->tMargin + $this->bMargin + 1)) { // see below - +10 to avoid drawing too close to border of page $h = $this->h - ($this->tMargin + $this->bMargin + 1); if ($this->fullImageHeight) { $h = $this->fullImageHeight; } $w = abs($h * $info['w'] / $info['h']); } //Avoid drawing out of the paper(exceeding width limits). //if ( ($x + $w) > $this->fw ) { if (($x + $w) > $this->w) { $x = $this->lMargin; $y += 5; } $changedpage = false; $oldcolumn = $this->CurrCol; //Avoid drawing out of the page. if ($y + $h > $this->PageBreakTrigger and ! $this->InFooter and $this->AcceptPageBreak()) { $this->AddPage($this->CurOrientation); // Added to correct for OddEven Margins $x = $x + $this->MarginCorrection; $y = $this->tMargin; // mPDF 5.7.3 $changedpage = true; } /* -- COLUMNS -- */ // COLS // COLUMN CHANGE if ($this->CurrCol != $oldcolumn) { $y = $this->y0; $x += $this->ChangeColumn * ($this->ColWidth + $this->ColGap); $this->x += $this->ChangeColumn * ($this->ColWidth + $this->ColGap); } /* -- END COLUMNS -- */ } // end of IF constrain /* -- IMAGES-WMF -- */ if ($info['type'] == 'wmf') { $sx = $w * _MPDFK / $info['w']; $sy = -$h * _MPDFK / $info['h']; $outstring = sprintf('q %.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, $sy, $x * _MPDFK - $sx * $info['x'], (($this->h - $y) * _MPDFK) - $sy * $info['y'], $info['i']); } else /* -- END IMAGES-WMF -- */ if ($info['type'] == 'svg') { $sx = $w * _MPDFK / $info['w']; $sy = -$h * _MPDFK / $info['h']; $outstring = sprintf('q %.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, $sy, $x * _MPDFK - $sx * $info['x'], (($this->h - $y) * _MPDFK) - $sy * $info['y'], $info['i']); } else { $outstring = sprintf("q %.3F 0 0 %.3F %.3F %.3F cm /I%d Do Q", $w * _MPDFK, $h * _MPDFK, $x * _MPDFK, ($this->h - ($y + $h)) * _MPDFK, $info['i']); } if ($paint) { $this->_out($outstring); if ($link) $this->Link($x, $y, $w, $h, $link); // Avoid writing text on top of the image. // THIS WAS OUTSIDE THE if ($paint) bit!!!!!!!!!!!!!!!! $this->y = $y + $h; } //Return width-height array $sizesarray['WIDTH'] = $w; $sizesarray['HEIGHT'] = $h; $sizesarray['X'] = $x; //Position before painting image $sizesarray['Y'] = $y; //Position before painting image $sizesarray['OUTPUT'] = $outstring; $sizesarray['IMAGE_ID'] = $info['i']; $sizesarray['itype'] = $info['type']; $sizesarray['set-dpi'] = (isset($info['set-dpi']) ? $info['set-dpi'] : 0); return $sizesarray; } //============================================================= //============================================================= //============================================================= //============================================================= //============================================================= /* -- HTML-CSS -- */ function _getObjAttr($t) { $c = explode("\xbb\xa4\xac", $t, 2); $c = explode(",", $c[1], 2); foreach ($c as $v) { $v = explode("=", $v, 2); $sp[$v[0]] = $v[1]; } return (unserialize($sp['objattr'])); } function inlineObject($type, $x, $y, $objattr, $Lmargin, $widthUsed, $maxWidth, $lineHeight, $paint = false, $is_table = false) { if ($is_table) { $k = $this->shrin_k; } else { $k = 1; } // NB $x is only used when paint=true // Lmargin not used $w = 0; if (isset($objattr['width'])) { $w = $objattr['width'] / $k; } $h = 0; if (isset($objattr['height'])) { $h = abs($objattr['height'] / $k); } $widthLeft = $maxWidth - $widthUsed; $maxHeight = $this->h - ($this->tMargin + $this->bMargin + 10); if ($this->fullImageHeight) { $maxHeight = $this->fullImageHeight; } // For Images if (isset($objattr['border_left'])) { $extraWidth = ($objattr['border_left']['w'] + $objattr['border_right']['w'] + $objattr['margin_left'] + $objattr['margin_right']) / $k; $extraHeight = ($objattr['border_top']['w'] + $objattr['border_bottom']['w'] + $objattr['margin_top'] + $objattr['margin_bottom']) / $k; if ($type == 'image' || $type == 'barcode' || $type == 'textcircle') { $extraWidth += ($objattr['padding_left'] + $objattr['padding_right']) / $k; $extraHeight += ($objattr['padding_top'] + $objattr['padding_bottom']) / $k; } } if (!isset($objattr['vertical-align'])) { if ($objattr['type'] == 'select') { $objattr['vertical-align'] = 'M'; } else { $objattr['vertical-align'] = 'BS'; } } // mPDF 6 if ($type == 'image' || (isset($objattr['subtype']) && $objattr['subtype'] == 'IMAGE')) { if (isset($objattr['itype']) && ($objattr['itype'] == 'wmf' || $objattr['itype'] == 'svg')) { $file = $objattr['file']; $info = $this->formobjects[$file]; } elseif (isset($objattr['file'])) { $file = $objattr['file']; $info = $this->images[$file]; } } if ($type == 'annot' || $type == 'bookmark' || $type == 'indexentry' || $type == 'toc') { $w = 0.00001; $h = 0.00001; } // TEST whether need to skipline if (!$paint) { if ($type == 'hr') { // always force new line if (($y + $h + $lineHeight > $this->PageBreakTrigger) && !$this->InFooter && !$is_table) { return array(-2, $w, $h); } // New page + new line else { return array(1, $w, $h); } // new line } else { // LIST MARKERS // mPDF 6 Lists $displayheight = $h; $displaywidth = $w; if ($objattr['type'] == 'image' && isset($objattr['listmarker']) && $objattr['listmarker']) { $displayheight = 0; if ($objattr['listmarkerposition'] == 'outside') { $displaywidth = 0; } } if ($widthUsed > 0 && $displaywidth > $widthLeft && (!$is_table || $type != 'image')) { // New line needed // mPDF 6 Lists if (($y + $displayheight + $lineHeight > $this->PageBreakTrigger) && !$this->InFooter) { return array(-2, $w, $h); } // New page + new line return array(1, $w, $h); // new line } elseif ($widthUsed > 0 && $displaywidth > $widthLeft && $is_table) { // New line needed in TABLE return array(1, $w, $h); // new line } // Will fit on line but NEW PAGE REQUIRED elseif (($y + $displayheight > $this->PageBreakTrigger) && !$this->InFooter && !$is_table) { return array(-1, $w, $h); } // mPDF 6 Lists else { return array(0, $w, $h); } } } if ($type == 'annot' || $type == 'bookmark' || $type == 'indexentry' || $type == 'toc') { $w = 0.00001; $h = 0.00001; $objattr['BORDER-WIDTH'] = 0; $objattr['BORDER-HEIGHT'] = 0; $objattr['BORDER-X'] = $x; $objattr['BORDER-Y'] = $y; $objattr['INNER-WIDTH'] = 0; $objattr['INNER-HEIGHT'] = 0; $objattr['INNER-X'] = $x; $objattr['INNER-Y'] = $y; } if ($type == 'image') { // Automatically resize to width remaining if ($w > ($widthLeft + 0.0001) && !$is_table) { // mPDF 5.7.4 0.0001 to allow for rounding errors when w==maxWidth $w = $widthLeft; $h = abs($w * $info['h'] / $info['w']); } $img_w = $w - $extraWidth; $img_h = $h - $extraHeight; $objattr['BORDER-WIDTH'] = $img_w + $objattr['padding_left'] / $k + $objattr['padding_right'] / $k + (($objattr['border_left']['w'] / $k + $objattr['border_right']['w'] / $k) / 2); $objattr['BORDER-HEIGHT'] = $img_h + $objattr['padding_top'] / $k + $objattr['padding_bottom'] / $k + (($objattr['border_top']['w'] / $k + $objattr['border_bottom']['w'] / $k) / 2); $objattr['BORDER-X'] = $x + $objattr['margin_left'] / $k + (($objattr['border_left']['w'] / $k) / 2); $objattr['BORDER-Y'] = $y + $objattr['margin_top'] / $k + (($objattr['border_top']['w'] / $k) / 2); $objattr['INNER-WIDTH'] = $img_w; $objattr['INNER-HEIGHT'] = $img_h; $objattr['INNER-X'] = $x + $objattr['padding_left'] / $k + $objattr['margin_left'] / $k + ($objattr['border_left']['w'] / $k); $objattr['INNER-Y'] = $y + $objattr['padding_top'] / $k + $objattr['margin_top'] / $k + ($objattr['border_top']['w'] / $k); $objattr['ID'] = $info['i']; } if ($type == 'input' && $objattr['subtype'] == 'IMAGE') { $img_w = $w - $extraWidth; $img_h = $h - $extraHeight; $objattr['BORDER-WIDTH'] = $img_w + (($objattr['border_left']['w'] / $k + $objattr['border_right']['w'] / $k) / 2); $objattr['BORDER-HEIGHT'] = $img_h + (($objattr['border_top']['w'] / $k + $objattr['border_bottom']['w'] / $k) / 2); $objattr['BORDER-X'] = $x + $objattr['margin_left'] / $k + (($objattr['border_left']['w'] / $k) / 2); $objattr['BORDER-Y'] = $y + $objattr['margin_top'] / $k + (($objattr['border_top']['w'] / $k) / 2); $objattr['INNER-WIDTH'] = $img_w; $objattr['INNER-HEIGHT'] = $img_h; $objattr['INNER-X'] = $x + $objattr['margin_left'] / $k + ($objattr['border_left']['w'] / $k); $objattr['INNER-Y'] = $y + $objattr['margin_top'] / $k + ($objattr['border_top']['w'] / $k); $objattr['ID'] = $info['i']; } if ($type == 'barcode' || $type == 'textcircle') { $b_w = $w - $extraWidth; $b_h = $h - $extraHeight; $objattr['BORDER-WIDTH'] = $b_w + $objattr['padding_left'] / $k + $objattr['padding_right'] / $k + (($objattr['border_left']['w'] / $k + $objattr['border_right']['w'] / $k) / 2); $objattr['BORDER-HEIGHT'] = $b_h + $objattr['padding_top'] / $k + $objattr['padding_bottom'] / $k + (($objattr['border_top']['w'] / $k + $objattr['border_bottom']['w'] / $k) / 2); $objattr['BORDER-X'] = $x + $objattr['margin_left'] / $k + (($objattr['border_left']['w'] / $k) / 2); $objattr['BORDER-Y'] = $y + $objattr['margin_top'] / $k + (($objattr['border_top']['w'] / $k) / 2); $objattr['INNER-X'] = $x + $objattr['padding_left'] / $k + $objattr['margin_left'] / $k + ($objattr['border_left']['w'] / $k); $objattr['INNER-Y'] = $y + $objattr['padding_top'] / $k + $objattr['margin_top'] / $k + ($objattr['border_top']['w'] / $k); $objattr['INNER-WIDTH'] = $b_w; $objattr['INNER-HEIGHT'] = $b_h; } if ($type == 'textarea') { // Automatically resize to width remaining if ($w > $widthLeft && !$is_table) { $w = $widthLeft; } // This used to resize height to maximum remaining on page ? why. Causes problems when in table and causing a new column // if (($y + $h > $this->PageBreakTrigger) && !$this->InFooter) { // $h=$this->h - $y - $this->bMargin; // } } if ($type == 'hr') { if ($is_table) { $objattr['INNER-WIDTH'] = $maxWidth * $objattr['W-PERCENT'] / 100; $objattr['width'] = $objattr['INNER-WIDTH']; $w = $maxWidth; } else { if ($w > $maxWidth) { $w = $maxWidth; } $objattr['INNER-WIDTH'] = $w; $w = $maxWidth; } } if (($type == 'select') || ($type == 'input' && ($objattr['subtype'] == 'TEXT' || $objattr['subtype'] == 'PASSWORD'))) { // Automatically resize to width remaining if ($w > $widthLeft && !$is_table) { $w = $widthLeft; } } if ($type == 'textarea' || $type == 'select' || $type == 'input') { if (isset($objattr['fontsize'])) $objattr['fontsize'] /= $k; if (isset($objattr['linewidth'])) $objattr['linewidth'] /= $k; } if (!isset($objattr['BORDER-Y'])) { $objattr['BORDER-Y'] = 0; } if (!isset($objattr['BORDER-X'])) { $objattr['BORDER-X'] = 0; } if (!isset($objattr['INNER-Y'])) { $objattr['INNER-Y'] = 0; } if (!isset($objattr['INNER-X'])) { $objattr['INNER-X'] = 0; } //Return width-height array $objattr['OUTER-WIDTH'] = $w; $objattr['OUTER-HEIGHT'] = $h; $objattr['OUTER-X'] = $x; $objattr['OUTER-Y'] = $y; return $objattr; } /* -- END HTML-CSS -- */ //============================================================= //============================================================= //============================================================= //============================================================= //============================================================= function SetLineJoin($mode = 0) { $s = sprintf('%d j', $mode); if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['LineJoin']) && $this->pageoutput[$this->page]['LineJoin'] != $s) || !isset($this->pageoutput[$this->page]['LineJoin']))) { $this->_out($s); } $this->pageoutput[$this->page]['LineJoin'] = $s; } function SetLineCap($mode = 2) { $s = sprintf('%d J', $mode); if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['LineCap']) && $this->pageoutput[$this->page]['LineCap'] != $s) || !isset($this->pageoutput[$this->page]['LineCap']))) { $this->_out($s); } $this->pageoutput[$this->page]['LineCap'] = $s; } function SetDash($black = false, $white = false) { if ($black and $white) $s = sprintf('[%.3F %.3F] 0 d', $black * _MPDFK, $white * _MPDFK); else $s = '[] 0 d'; if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['Dash']) && $this->pageoutput[$this->page]['Dash'] != $s) || !isset($this->pageoutput[$this->page]['Dash']))) { $this->_out($s); } $this->pageoutput[$this->page]['Dash'] = $s; } function SetDisplayPreferences($preferences) { // String containing any or none of /HideMenubar/HideToolbar/HideWindowUI/DisplayDocTitle/CenterWindow/FitWindow $this->DisplayPreferences .= $preferences; } function Ln($h = '', $collapsible = 0) { // Added collapsible to allow collapsible top-margin on new page //Line feed; default value is last cell height $this->x = $this->lMargin + $this->blk[$this->blklvl]['outer_left_margin']; if ($collapsible && ($this->y == $this->tMargin) && (!$this->ColActive)) { $h = 0; } if (is_string($h)) $this->y+=$this->lasth; else $this->y+=$h; } /* -- HTML-CSS -- */ function DivLn($h, $level = -3, $move_y = true, $collapsible = false, $state = 0) { // $state = 0 normal; 1 top; 2 bottom; 3 top and bottom // Used in Columns and keep-with-table i.e. "kwt" // writes background block by block so it can be repositioned // and also used in writingFlowingBlock at top and bottom of blocks to move y (not to draw/paint anything) // adds lines (y) where DIV bgcolors are filled in // this->x is returned as it was // allows .00001 as nominal height used for bookmarks/annotations etc. if ($collapsible && (sprintf("%0.4f", $this->y) == sprintf("%0.4f", $this->tMargin)) && (!$this->ColActive)) { return; } // mPDF 6 Columns // if ($collapsible && (sprintf("%0.4f", $this->y)==sprintf("%0.4f", $this->y0)) && ($this->ColActive) && $this->CurrCol == 0) { return; } // *COLUMNS* if ($collapsible && (sprintf("%0.4f", $this->y) == sprintf("%0.4f", $this->y0)) && ($this->ColActive)) { return; } // *COLUMNS* // Still use this method if columns or keep-with-table, as it allows repositioning later // otherwise, now uses PaintDivBB() if (!$this->ColActive && !$this->kwt) { if ($move_y && !$this->ColActive) { $this->y += $h; } return; } if ($level == -3) { $level = $this->blklvl; } $firstblockfill = $this->GetFirstBlockFill(); if ($firstblockfill && $this->blklvl > 0 && $this->blklvl >= $firstblockfill) { $last_x = 0; $last_w = 0; $last_fc = $this->FillColor; $bak_x = $this->x; $bak_h = $this->divheight; $this->divheight = 0; // Temporarily turn off divheight - as Cell() uses it to check for PageBreak for ($blvl = $firstblockfill; $blvl <= $level; $blvl++) { $this->x = $this->lMargin + $this->blk[$blvl]['outer_left_margin']; // mPDF 6 if ($this->blk[$blvl]['bgcolor']) { $this->SetFColor($this->blk[$blvl]['bgcolorarray']); } if ($last_x != ($this->lMargin + $this->blk[$blvl]['outer_left_margin']) || ($last_w != $this->blk[$blvl]['width']) || $last_fc != $this->FillColor || (isset($this->blk[$blvl]['border_top']['s']) && $this->blk[$blvl]['border_top']['s']) || (isset($this->blk[$blvl]['border_bottom']['s']) && $this->blk[$blvl]['border_bottom']['s']) || (isset($this->blk[$blvl]['border_left']['s']) && $this->blk[$blvl]['border_left']['s']) || (isset($this->blk[$blvl]['border_right']['s']) && $this->blk[$blvl]['border_right']['s'])) { $x = $this->x; $this->Cell(($this->blk[$blvl]['width']), $h, '', '', 0, '', 1); $this->x = $x; if (!$this->keep_block_together && !$this->writingHTMLheader && !$this->writingHTMLfooter) { // $state = 0 normal; 1 top; 2 bottom; 3 top and bottom if ($blvl == $this->blklvl) { $this->PaintDivLnBorder($state, $blvl, $h); } else { $this->PaintDivLnBorder(0, $blvl, $h); } } } $last_x = $this->lMargin + $this->blk[$blvl]['outer_left_margin']; $last_w = $this->blk[$blvl]['width']; $last_fc = $this->FillColor; } // Reset current block fill if (isset($this->blk[$this->blklvl]['bgcolorarray'])) { $bcor = $this->blk[$this->blklvl]['bgcolorarray']; $this->SetFColor($bcor); } $this->x = $bak_x; $this->divheight = $bak_h; } if ($move_y) { $this->y += $h; } } /* -- END HTML-CSS -- */ function SetX($x) { //Set x position if ($x >= 0) $this->x = $x; else $this->x = $this->w + $x; } function SetY($y) { //Set y position and reset x $this->x = $this->lMargin; if ($y >= 0) $this->y = $y; else $this->y = $this->h + $y; } function SetXY($x, $y) { //Set x and y positions $this->SetY($y); $this->SetX($x); } function Output($name = '', $dest = '') { //Output PDF to some destination if ($this->showStats) { echo '
Error message detected - PDF file generation aborted.
"; echo $e['message'] . ''; echo 'File: ' . $e['file'] . '
'; echo 'Line: ' . $e['line'] . '
'; exit; } } if (($this->PDFA || $this->PDFX) && $this->encrypted) { throw new MpdfException("PDFA1-b or PDFX/1-a does not permit encryption of documents."); } if (count($this->PDFAXwarnings) && (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto))) { if ($this->PDFA) { echo '
- ';
$this->PDFAXwarnings = array_unique($this->PDFAXwarnings);
foreach ($this->PDFAXwarnings AS $w) {
echo '
- ' . $w . ' '; } echo '