1<?php 2 3namespace Mpdf\Tag; 4 5use Mpdf\Conversion\DecToAlpha; 6use Mpdf\Conversion\DecToRoman; 7use Mpdf\Utils\Arrays; 8use Mpdf\Utils\UtfString; 9 10abstract class BlockTag extends Tag 11{ 12 13 public function open($attr, &$ahtml, &$ihtml) 14 { 15 $tag = $this->getTagName(); 16 17 // mPDF 6 Lists 18 $this->mpdf->lastoptionaltag = ''; 19 20 // mPDF 6 bidi 21 // Block 22 // If unicode-bidi set on current clock, any embedding levels, isolates, or overrides are closed (not inherited) 23 if (isset($this->mpdf->blk[$this->mpdf->blklvl]['bidicode'])) { 24 $blockpost = $this->mpdf->_setBidiCodes('end', $this->mpdf->blk[$this->mpdf->blklvl]['bidicode']); 25 if ($blockpost) { 26 $this->mpdf->OTLdata = []; 27 if ($this->mpdf->tableLevel) { 28 $this->mpdf->_saveCellTextBuffer($blockpost); 29 } else { 30 $this->mpdf->_saveTextBuffer($blockpost); 31 } 32 } 33 } 34 35 36 $p = $this->cssManager->PreviewBlockCSS($tag, $attr); 37 if (isset($p['DISPLAY']) && strtolower($p['DISPLAY']) === 'none') { 38 $this->mpdf->blklvl++; 39 $this->mpdf->blk[$this->mpdf->blklvl]['hide'] = true; 40 $this->mpdf->blk[$this->mpdf->blklvl]['tag'] = $tag; // mPDF 6 41 return; 42 } 43 if ($tag === 'CAPTION') { 44 // position is written in AdjstHTML 45 $divpos = 'T'; 46 if (isset($attr['POSITION']) && strtolower($attr['POSITION']) === 'bottom') { 47 $divpos = 'B'; 48 } 49 50 $cappos = 'T'; 51 if (isset($attr['ALIGN']) && strtolower($attr['ALIGN']) === 'bottom') { 52 $cappos = 'B'; 53 } elseif (isset($p['CAPTION-SIDE']) && strtolower($p['CAPTION-SIDE']) === 'bottom') { 54 $cappos = 'B'; 55 } 56 if (isset($attr['ALIGN'])) { 57 unset($attr['ALIGN']); 58 } 59 if ($cappos != $divpos) { 60 $this->mpdf->blklvl++; 61 $this->mpdf->blk[$this->mpdf->blklvl]['hide'] = true; 62 $this->mpdf->blk[$this->mpdf->blklvl]['tag'] = $tag; // mPDF 6 63 return; 64 } 65 } 66 67 /* -- FORMS -- */ 68 if ($tag === 'FORM') { 69 $this->form->formMethod = 'POST'; 70 if (isset($attr['METHOD']) && strtolower($attr['METHOD']) === 'get') { 71 $this->form->formMethod = 'GET'; 72 } 73 74 $this->form->formAction = ''; 75 if (isset($attr['ACTION'])) { 76 $this->form->formAction = $attr['ACTION']; 77 } 78 } 79 /* -- END FORMS -- */ 80 81 82 /* -- CSS-POSITION -- */ 83 if ((isset($p['POSITION']) 84 && (strtolower($p['POSITION']) === 'fixed' 85 || strtolower($p['POSITION']) === 'absolute')) 86 && $this->mpdf->blklvl == 0) { 87 if ($this->mpdf->inFixedPosBlock) { 88 throw new \Mpdf\MpdfException('Cannot nest block with position:fixed or position:absolute'); 89 } 90 $this->mpdf->inFixedPosBlock = true; 91 return; 92 } 93 /* -- END CSS-POSITION -- */ 94 // Start Block 95 $this->mpdf->ignorefollowingspaces = true; 96 97 $lastbottommargin = 0; 98 if ($this->mpdf->blockjustfinished && !count($this->mpdf->textbuffer) 99 && $this->mpdf->y != $this->mpdf->tMargin 100 && $this->mpdf->collapseBlockMargins) { 101 $lastbottommargin = $this->mpdf->lastblockbottommargin; 102 } 103 $this->mpdf->lastblockbottommargin = 0; 104 $this->mpdf->blockjustfinished = false; 105 106 107 $this->mpdf->InlineBDF = []; // mPDF 6 108 $this->mpdf->InlineBDFctr = 0; // mPDF 6 109 $this->mpdf->InlineProperties = []; 110 $this->mpdf->divbegin = true; 111 112 $this->mpdf->linebreakjustfinished = false; 113 114 /* -- TABLES -- */ 115 if ($this->mpdf->tableLevel) { 116 // If already something on the line 117 if ($this->mpdf->cell[$this->mpdf->row][$this->mpdf->col]['s'] > 0 && !$this->mpdf->nestedtablejustfinished) { 118 $this->mpdf->_saveCellTextBuffer("\n"); 119 if (!isset($this->mpdf->cell[$this->mpdf->row][$this->mpdf->col]['maxs'])) { 120 $this->mpdf->cell[$this->mpdf->row][$this->mpdf->col]['maxs'] = $this->mpdf->cell[$this->mpdf->row][$this->mpdf->col]['s']; 121 } elseif ($this->mpdf->cell[$this->mpdf->row][$this->mpdf->col]['maxs'] < $this->mpdf->cell[$this->mpdf->row][$this->mpdf->col]['s']) { 122 $this->mpdf->cell[$this->mpdf->row][$this->mpdf->col]['maxs'] = $this->mpdf->cell[$this->mpdf->row][$this->mpdf->col]['s']; 123 } 124 $this->mpdf->cell[$this->mpdf->row][$this->mpdf->col]['s'] = 0; // reset 125 } 126 // Cannot set block properties inside table - use Bold to indicate h1-h6 127 if ($tag === 'CENTER' && $this->mpdf->tdbegin) { 128 $this->mpdf->cell[$this->mpdf->row][$this->mpdf->col]['a'] = $this->getAlign('center'); 129 } 130 131 $this->mpdf->InlineProperties['BLOCKINTABLE'] = $this->mpdf->saveInlineProperties(); 132 $properties = $this->cssManager->MergeCSS('', $tag, $attr); 133 if (!empty($properties)) { 134 $this->mpdf->setCSS($properties, 'INLINE'); 135 } 136 137 // mPDF 6 Lists 138 if ($tag === 'UL' || $tag === 'OL') { 139 $this->mpdf->listlvl++; 140 if (isset($attr['START'])) { 141 $this->mpdf->listcounter[$this->mpdf->listlvl] = (int) $attr['START'] - 1; 142 } else { 143 $this->mpdf->listcounter[$this->mpdf->listlvl] = 0; 144 } 145 $this->mpdf->listitem = []; 146 if ($tag === 'OL') { 147 $this->mpdf->listtype[$this->mpdf->listlvl] = 'decimal'; 148 } elseif ($tag === 'UL') { 149 if ($this->mpdf->listlvl % 3 == 1) { 150 $this->mpdf->listtype[$this->mpdf->listlvl] = 'disc'; 151 } elseif ($this->mpdf->listlvl % 3 == 2) { 152 $this->mpdf->listtype[$this->mpdf->listlvl] = 'circle'; 153 } else { 154 $this->mpdf->listtype[$this->mpdf->listlvl] = 'square'; 155 } 156 } 157 } 158 159 // mPDF 6 Lists - in Tables 160 if ($tag === 'LI') { 161 162 if ($this->mpdf->listlvl == 0) { //in case of malformed HTML code. Example:(...)</p><li>Content</li><p>Paragraph1</p>(...) 163 $this->mpdf->listlvl++; // first depth level 164 $this->mpdf->listcounter[$this->mpdf->listlvl] = 0; 165 } 166 167 $this->mpdf->listcounter[$this->mpdf->listlvl]++; 168 $this->mpdf->listitem = []; 169 //if in table - output here as a tabletextbuffer 170 //position:inside OR position:outside (always output in table as position:inside) 171 172 $decToAlpha = new DecToAlpha(); 173 $decToRoman = new DecToRoman(); 174 175 switch ($this->mpdf->listtype[$this->mpdf->listlvl]) { 176 case 'upper-alpha': 177 case 'upper-latin': 178 case 'A': 179 $blt = $decToAlpha->convert($this->mpdf->listcounter[$this->mpdf->listlvl]) . $this->mpdf->list_number_suffix; 180 break; 181 case 'lower-alpha': 182 case 'lower-latin': 183 case 'a': 184 $blt = $decToAlpha->convert($this->mpdf->listcounter[$this->mpdf->listlvl], false) . $this->mpdf->list_number_suffix; 185 break; 186 case 'upper-roman': 187 case 'I': 188 $blt = $decToRoman->convert($this->mpdf->listcounter[$this->mpdf->listlvl]) . $this->mpdf->list_number_suffix; 189 break; 190 case 'lower-roman': 191 case 'i': 192 $blt = $decToRoman->convert($this->mpdf->listcounter[$this->mpdf->listlvl]) . $this->mpdf->list_number_suffix; 193 break; 194 case 'decimal': 195 case '1': 196 $blt = $this->mpdf->listcounter[$this->mpdf->listlvl] . $this->mpdf->list_number_suffix; 197 break; 198 default: 199 $blt = '-'; 200 if ($this->mpdf->listlvl % 3 == 1 && $this->mpdf->_charDefined($this->mpdf->CurrentFont['cw'], 8226)) { 201 $blt = "\xe2\x80\xa2"; 202 } // • 203 elseif ($this->mpdf->listlvl % 3 == 2 && $this->mpdf->_charDefined($this->mpdf->CurrentFont['cw'], 9900)) { 204 $blt = "\xe2\x9a\xac"; 205 } // ⚬ 206 elseif ($this->mpdf->listlvl % 3 == 0 && $this->mpdf->_charDefined($this->mpdf->CurrentFont['cw'], 9642)) { 207 $blt = "\xe2\x96\xaa"; 208 } // ▪ 209 break; 210 } 211 212 // change to spaces 213 if ($this->mpdf->usingCoreFont) { 214 $ls = str_repeat(chr(160) . chr(160), ($this->mpdf->listlvl - 1) * 2) . $blt . ' '; 215 } else { 216 $ls = str_repeat("\xc2\xa0\xc2\xa0", ($this->mpdf->listlvl - 1) * 2) . $blt . ' '; 217 } 218 $this->mpdf->_saveCellTextBuffer($ls); 219 $this->mpdf->cell[$this->mpdf->row][$this->mpdf->col]['s'] += $this->mpdf->GetStringWidth($ls); 220 } 221 222 return; 223 } 224 /* -- END TABLES -- */ 225 226 if ($this->mpdf->lastblocklevelchange == 1) { 227 $blockstate = 1; 228 } // Top margins/padding only 229 elseif ($this->mpdf->lastblocklevelchange < 1) { 230 $blockstate = 0; 231 } // NO margins/padding 232 233 $this->mpdf->printbuffer($this->mpdf->textbuffer, $blockstate); 234 $this->mpdf->textbuffer = []; 235 236 $save_blklvl = $this->mpdf->blklvl; 237 $save_blk = $this->mpdf->blk; 238 239 $this->mpdf->Reset(); 240 241 $pagesel = ''; 242 /* -- CSS-PAGE -- */ 243 if (isset($p['PAGE'])) { 244 $pagesel = $p['PAGE']; 245 } // mPDF 6 (uses $p - preview of properties so blklvl can be incremented after page-break) 246 /* -- END CSS-PAGE -- */ 247 248 // If page-box has changed AND/OR PAGE-BREAK-BEFORE 249 // mPDF 6 (uses $p - preview of properties so blklvl can be imcremented after page-break) 250 if (!$this->mpdf->tableLevel && (($pagesel && (!isset($this->mpdf->page_box['current']) 251 || $pagesel != $this->mpdf->page_box['current'])) 252 || (isset($p['PAGE-BREAK-BEFORE']) 253 && $p['PAGE-BREAK-BEFORE']))) { 254 // mPDF 6 pagebreaktype 255 $startpage = $this->mpdf->page; 256 $pagebreaktype = $this->mpdf->defaultPagebreakType; 257 $this->mpdf->lastblocklevelchange = -1; 258 if ($this->mpdf->ColActive) { 259 $pagebreaktype = 'cloneall'; 260 } 261 if ($pagesel && (!isset($this->mpdf->page_box['current']) || $pagesel != $this->mpdf->page_box['current'])) { 262 $pagebreaktype = 'cloneall'; 263 } 264 $this->mpdf->_preForcedPagebreak($pagebreaktype); 265 266 if (isset($p['PAGE-BREAK-BEFORE'])) { 267 if (strtoupper($p['PAGE-BREAK-BEFORE']) === 'RIGHT') { 268 $this->mpdf->AddPage( 269 $this->mpdf->CurOrientation, 270 'NEXT-ODD', 271 '', 272 '', 273 '', 274 '', 275 '', 276 '', 277 '', 278 '', 279 '', 280 '', 281 '', 282 '', 283 '', 284 0, 285 0, 286 0, 287 0, 288 $pagesel 289 ); 290 } elseif (strtoupper($p['PAGE-BREAK-BEFORE']) === 'LEFT') { 291 $this->mpdf->AddPage( 292 $this->mpdf->CurOrientation, 293 'NEXT-EVEN', 294 '', 295 '', 296 '', 297 '', 298 '', 299 '', 300 '', 301 '', 302 '', 303 '', 304 '', 305 '', 306 '', 307 0, 308 0, 309 0, 310 0, 311 $pagesel 312 ); 313 } elseif (strtoupper($p['PAGE-BREAK-BEFORE']) === 'ALWAYS') { 314 $this->mpdf->AddPage($this->mpdf->CurOrientation, '', '', '', '', '', '', '', '', '', '', '', '', '', '', 0, 0, 0, 0, $pagesel); 315 } elseif ($this->mpdf->page_box['current'] != $pagesel) { 316 $this->mpdf->AddPage($this->mpdf->CurOrientation, '', '', '', '', '', '', '', '', '', '', '', '', '', '', 0, 0, 0, 0, $pagesel); 317 } // *CSS-PAGE* 318 } /* -- CSS-PAGE -- */ 319 // Must Add new page if changed page properties 320 elseif (!isset($this->mpdf->page_box['current']) || $pagesel != $this->mpdf->page_box['current']) { 321 $this->mpdf->AddPage($this->mpdf->CurOrientation, '', '', '', '', '', '', '', '', '', '', '', '', '', '', 0, 0, 0, 0, $pagesel); 322 } 323 /* -- END CSS-PAGE -- */ 324 325 // mPDF 6 pagebreaktype 326 $this->mpdf->_postForcedPagebreak($pagebreaktype, $startpage, $save_blk, $save_blklvl); 327 } 328 329 // mPDF 6 pagebreaktype - moved after pagebreak 330 $this->mpdf->blklvl++; 331 $currblk = & $this->mpdf->blk[$this->mpdf->blklvl]; 332 $this->mpdf->initialiseBlock($currblk); 333 $prevblk = & $this->mpdf->blk[$this->mpdf->blklvl - 1]; 334 $currblk['tag'] = $tag; 335 $currblk['attr'] = $attr; 336 337 $properties = $this->cssManager->MergeCSS('BLOCK', $tag, $attr); // mPDF 6 - moved to after page-break-before 338 // mPDF 6 page-break-inside:avoid 339 if (isset($properties['PAGE-BREAK-INSIDE']) && strtoupper($properties['PAGE-BREAK-INSIDE']) === 'AVOID' 340 && !$this->mpdf->ColActive && !$this->mpdf->keep_block_together && !isset($attr['PAGEBREAKAVOIDCHECKED'])) { 341 // avoid re-iterating using PAGEBREAKAVOIDCHECKED; set in CloseTag 342 $currblk['keep_block_together'] = 1; 343 $currblk['array_i'] = $ihtml; // mPDF 6 344 $this->mpdf->kt_y00 = $this->mpdf->y; 345 $this->mpdf->kt_p00 = $this->mpdf->page; 346 $this->mpdf->keep_block_together = 1; 347 } 348 if ($lastbottommargin && !empty($properties['MARGIN-TOP']) && empty($properties['FLOAT'])) { 349 $currblk['lastbottommargin'] = $lastbottommargin; 350 } 351 352 if (isset($properties['Z-INDEX']) && $this->mpdf->current_layer == 0) { 353 $v = (int) $properties['Z-INDEX']; 354 if ($v > 0) { 355 $currblk['z-index'] = $v; 356 $this->mpdf->BeginLayer($v); 357 } 358 } 359 360 361 // mPDF 6 Lists 362 // List-type set by attribute 363 if ($tag === 'OL' || $tag === 'UL' || $tag === 'LI') { 364 if (!empty($attr['TYPE'])) { 365 $listtype = $attr['TYPE']; 366 switch ($listtype) { 367 case 'A': 368 $listtype = 'upper-latin'; 369 break; 370 case 'a': 371 $listtype = 'lower-latin'; 372 break; 373 case 'I': 374 $listtype = 'upper-roman'; 375 break; 376 case 'i': 377 $listtype = 'lower-roman'; 378 break; 379 case '1': 380 $listtype = 'decimal'; 381 break; 382 } 383 $currblk['list_style_type'] = $listtype; 384 } 385 } 386 387 $this->mpdf->setCSS($properties, 'BLOCK', $tag); //name(id/class/style) found in the CSS array! 388 $currblk['InlineProperties'] = $this->mpdf->saveInlineProperties(); 389 390 if (isset($properties['VISIBILITY'])) { 391 $v = strtolower($properties['VISIBILITY']); 392 if (($v === 'hidden' || $v === 'printonly' || $v === 'screenonly') && $this->mpdf->visibility === 'visible' && !$this->mpdf->tableLevel) { 393 $currblk['visibility'] = $v; 394 $this->mpdf->SetVisibility($v); 395 } 396 } 397 398 // mPDF 6 399 if (!empty($attr['ALIGN'])) { 400 $currblk['block-align'] = $this->getAlign($attr['ALIGN']); 401 } 402 403 404 if (isset($properties['HEIGHT'])) { 405 $currblk['css_set_height'] = $this->sizeConverter->convert( 406 $properties['HEIGHT'], 407 $this->mpdf->h - $this->mpdf->tMargin - $this->mpdf->bMargin, 408 $this->mpdf->FontSize, 409 false 410 ); 411 if (($currblk['css_set_height'] + $this->mpdf->y) > $this->mpdf->PageBreakTrigger 412 && $this->mpdf->y > $this->mpdf->tMargin + 5 413 && $currblk['css_set_height'] < ($this->mpdf->h - ($this->mpdf->tMargin + $this->mpdf->bMargin))) { 414 $this->mpdf->AddPage($this->mpdf->CurOrientation); 415 } 416 } else { 417 $currblk['css_set_height'] = false; 418 } 419 420 421 // Added mPDF 3.0 Float DIV 422 if (isset($prevblk['blockContext'])) { 423 $currblk['blockContext'] = $prevblk['blockContext']; 424 } // *CSS-FLOAT* 425 426 if (isset($properties['CLEAR'])) { 427 $this->mpdf->ClearFloats(strtoupper($properties['CLEAR']), $this->mpdf->blklvl - 1); 428 } // *CSS-FLOAT* 429 430 $currblk['padding_left'] = is_numeric($currblk['padding_left']) ? $currblk['padding_left'] : 0; 431 $currblk['padding_right'] = is_numeric($currblk['padding_right']) ? $currblk['padding_right'] : 0; 432 433 $container_w = $prevblk['inner_width']; 434 $bdr = $currblk['border_right']['w']; 435 $bdl = $currblk['border_left']['w']; 436 $pdr = $currblk['padding_right']; 437 $pdl = $currblk['padding_left']; 438 439 $setwidth = 0; 440 if (isset($currblk['css_set_width'])) { 441 $setwidth = $currblk['css_set_width']; 442 } 443 444 /* -- CSS-FLOAT -- */ 445 if (isset($properties['FLOAT']) && strtoupper($properties['FLOAT']) === 'RIGHT' && !$this->mpdf->ColActive) { 446 447 // Cancel Keep-Block-together 448 $currblk['keep_block_together'] = false; 449 $this->mpdf->kt_y00 = 0; 450 $this->mpdf->keep_block_together = 0; 451 452 $this->mpdf->blockContext++; 453 $currblk['blockContext'] = $this->mpdf->blockContext; 454 455 list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->mpdf->GetFloatDivInfo($this->mpdf->blklvl - 1); 456 457 // DIV is too narrow for text to fit! 458 $maxw = $container_w - $l_width - $r_width; 459 $doubleCharWidth = (2 * $this->mpdf->GetCharWidth('W', false)); 460 if (($setwidth + $currblk['margin_right'] + $bdl + $pdl + $bdr + $pdr) > $maxw 461 || ($maxw - ($currblk['margin_right'] + $bdl + $pdl + $bdr + $pdr)) < (2 * $this->mpdf->GetCharWidth('W', false))) { 462 // Too narrow to fit - try to move down past L or R float 463 if ($l_max < $r_max && ($setwidth + $currblk['margin_right'] + $bdl + $pdl + $bdr + $pdr) <= ($container_w - $r_width) 464 && (($container_w - $r_width) - ($currblk['margin_right'] + $bdl + $pdl + $bdr + $pdr)) > $doubleCharWidth) { 465 $this->mpdf->ClearFloats('LEFT', $this->mpdf->blklvl - 1); 466 } elseif ($r_max < $l_max && ($setwidth + $currblk['margin_right'] + $bdl + $pdl + $bdr + $pdr) <= ($container_w - $l_width) 467 && (($container_w - $l_width) - ($currblk['margin_right'] + $bdl + $pdl + $bdr + $pdr)) > $doubleCharWidth) { 468 $this->mpdf->ClearFloats('RIGHT', $this->mpdf->blklvl - 1); 469 } else { 470 $this->mpdf->ClearFloats('BOTH', $this->mpdf->blklvl - 1); 471 } 472 list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->mpdf->GetFloatDivInfo($this->mpdf->blklvl - 1); 473 } 474 475 if ($r_exists) { 476 $currblk['margin_right'] += $r_width; 477 } 478 479 $currblk['float'] = 'R'; 480 $currblk['float_start_y'] = $this->mpdf->y; 481 482 if (isset($currblk['css_set_width'])) { 483 $currblk['margin_left'] = $container_w - ($setwidth + $bdl + $pdl + $bdr + $pdr + $currblk['margin_right']); 484 $currblk['float_width'] = ($setwidth + $bdl + $pdl + $bdr + $pdr + $currblk['margin_right']); 485 } else { 486 // *** If no width set - would need to buffer and keep track of max width, then Right-align if not full width 487 // and do borders and backgrounds - For now - just set to maximum width left 488 489 if ($l_exists) { 490 $currblk['margin_left'] += $l_width; 491 } 492 $currblk['css_set_width'] = $container_w - ($currblk['margin_left'] + $currblk['margin_right'] + $bdl + $pdl + $bdr + $pdr); 493 494 $currblk['float_width'] = ($currblk['css_set_width'] + $bdl + $pdl + $bdr + $pdr + $currblk['margin_right']); 495 } 496 497 } elseif (isset($properties['FLOAT']) && strtoupper($properties['FLOAT']) === 'LEFT' && !$this->mpdf->ColActive) { 498 // Cancel Keep-Block-together 499 $currblk['keep_block_together'] = false; 500 $this->mpdf->kt_y00 = 0; 501 $this->mpdf->keep_block_together = 0; 502 503 $this->mpdf->blockContext++; 504 $currblk['blockContext'] = $this->mpdf->blockContext; 505 506 list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->mpdf->GetFloatDivInfo($this->mpdf->blklvl - 1); 507 508 // DIV is too narrow for text to fit! 509 $maxw = $container_w - $l_width - $r_width; 510 $doubleCharWidth = (2 * $this->mpdf->GetCharWidth('W', false)); 511 if (($setwidth + $currblk['margin_left'] + $bdl + $pdl + $bdr + $pdr) > $maxw 512 || ($maxw - ($currblk['margin_left'] + $bdl + $pdl + $bdr + $pdr)) < (2 * $this->mpdf->GetCharWidth('W', false))) { 513 // Too narrow to fit - try to move down past L or R float 514 if ($l_max < $r_max && ($setwidth + $currblk['margin_right'] + $bdl + $pdl + $bdr + $pdr) <= ($container_w - $r_width) 515 && (($container_w - $r_width) - ($currblk['margin_right'] + $bdl + $pdl + $bdr + $pdr)) > $doubleCharWidth) { 516 $this->mpdf->ClearFloats('LEFT', $this->mpdf->blklvl - 1); 517 } elseif ($r_max < $l_max && ($setwidth + $currblk['margin_right'] + $bdl + $pdl + $bdr + $pdr) <= ($container_w - $l_width) 518 && (($container_w - $l_width) - ($currblk['margin_right'] + $bdl + $pdl + $bdr + $pdr)) > $doubleCharWidth) { 519 $this->mpdf->ClearFloats('RIGHT', $this->mpdf->blklvl - 1); 520 } else { 521 $this->mpdf->ClearFloats('BOTH', $this->mpdf->blklvl - 1); 522 } 523 list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->mpdf->GetFloatDivInfo($this->mpdf->blklvl - 1); 524 } 525 526 if ($l_exists) { 527 $currblk['margin_left'] += $l_width; 528 } 529 530 $currblk['float'] = 'L'; 531 $currblk['float_start_y'] = $this->mpdf->y; 532 if ($setwidth) { 533 $currblk['margin_right'] = $container_w - ($setwidth + $bdl + $pdl + $bdr + $pdr + $currblk['margin_left']); 534 $currblk['float_width'] = ($setwidth + $bdl + $pdl + $bdr + $pdr + $currblk['margin_left']); 535 } else { 536 // *** If no width set - would need to buffer and keep track of max width, then Right-align if not full width 537 // and do borders and backgrounds - For now - just set to maximum width left 538 539 if ($r_exists) { 540 $currblk['margin_right'] += $r_width; 541 } 542 $currblk['css_set_width'] = $container_w - ($currblk['margin_left'] + $currblk['margin_right'] + $bdl + $pdl + $bdr + $pdr); 543 544 $currblk['float_width'] = ($currblk['css_set_width'] + $bdl + $pdl + $bdr + $pdr + $currblk['margin_left']); 545 } 546 } else { 547 // Don't allow overlap - if floats present - adjust padding to avoid overlap with Floats 548 list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->mpdf->GetFloatDivInfo($this->mpdf->blklvl - 1); 549 $maxw = $container_w - $l_width - $r_width; 550 551 $pdl = is_numeric($pdl) ? $pdl : 0; 552 $pdr = is_numeric($pdr) ? $pdr : 0; 553 554 $doubleCharWidth = (2 * $this->mpdf->GetCharWidth('W', false)); 555 if (($setwidth + $currblk['margin_left'] + $currblk['margin_right'] + $bdl + $pdl + $bdr + $pdr) > $maxw 556 || ($maxw - ($currblk['margin_right'] + $currblk['margin_left'] + $bdl + $pdl + $bdr + $pdr)) < $doubleCharWidth) { 557 // Too narrow to fit - try to move down past L or R float 558 if ($l_max < $r_max && ($setwidth + $currblk['margin_left'] + $currblk['margin_right'] + $bdl + $pdl + $bdr + $pdr) <= ($container_w - $r_width) 559 && (($container_w - $r_width) - ($currblk['margin_right'] + $currblk['margin_left'] + $bdl + $pdl + $bdr + $pdr)) > $doubleCharWidth) { 560 $this->mpdf->ClearFloats('LEFT', $this->mpdf->blklvl - 1); 561 } elseif ($r_max < $l_max && ($setwidth + $currblk['margin_left'] + $currblk['margin_right'] + $bdl + $pdl + $bdr + $pdr) <= ($container_w - $l_width) 562 && (($container_w - $l_width) - ($currblk['margin_right'] + $currblk['margin_left'] + $bdl + $pdl + $bdr + $pdr)) > $doubleCharWidth) { 563 $this->mpdf->ClearFloats('RIGHT', $this->mpdf->blklvl - 1); 564 } else { 565 $this->mpdf->ClearFloats('BOTH', $this->mpdf->blklvl - 1); 566 } 567 list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->mpdf->GetFloatDivInfo($this->mpdf->blklvl - 1); 568 } 569 if ($r_exists) { 570 $currblk['padding_right'] = max($r_width - $currblk['margin_right'] - $bdr, $pdr); 571 } 572 if ($l_exists) { 573 $currblk['padding_left'] = max($l_width - $currblk['margin_left'] - $bdl, $pdl); 574 } 575 } 576 /* -- END CSS-FLOAT -- */ 577 578 579 /* -- BORDER-RADIUS -- */ 580 // Automatically increase padding if required for border-radius 581 if ($this->mpdf->autoPadding && !$this->mpdf->ColActive) { 582 $currblk['border_radius_TL_H'] = Arrays::get($currblk, 'border_radius_TL_H', 0); 583 $currblk['border_radius_TL_V'] = Arrays::get($currblk, 'border_radius_TL_V', 0); 584 $currblk['border_radius_TR_H'] = Arrays::get($currblk, 'border_radius_TR_H', 0); 585 $currblk['border_radius_TR_V'] = Arrays::get($currblk, 'border_radius_TR_V', 0); 586 $currblk['border_radius_BL_H'] = Arrays::get($currblk, 'border_radius_BL_H', 0); 587 $currblk['border_radius_BL_V'] = Arrays::get($currblk, 'border_radius_BL_V', 0); 588 $currblk['border_radius_BR_H'] = Arrays::get($currblk, 'border_radius_BR_H', 0); 589 $currblk['border_radius_BR_V'] = Arrays::get($currblk, 'border_radius_BR_V', 0); 590 591 if ($currblk['border_radius_TL_H'] > $currblk['padding_left'] && $currblk['border_radius_TL_V'] > $currblk['padding_top']) { 592 if ($currblk['border_radius_TL_H'] > $currblk['border_radius_TL_V']) { 593 $this->mpdf->_borderPadding( 594 $currblk['border_radius_TL_H'], 595 $currblk['border_radius_TL_V'], 596 $currblk['padding_left'], 597 $currblk['padding_top'] 598 ); 599 } else { 600 $this->mpdf->_borderPadding( 601 $currblk['border_radius_TL_V'], 602 $currblk['border_radius_TL_H'], 603 $currblk['padding_top'], 604 $currblk['padding_left'] 605 ); 606 } 607 } 608 if ($currblk['border_radius_TR_H'] > $currblk['padding_right'] && $currblk['border_radius_TR_V'] > $currblk['padding_top']) { 609 if ($currblk['border_radius_TR_H'] > $currblk['border_radius_TR_V']) { 610 $this->mpdf->_borderPadding( 611 $currblk['border_radius_TR_H'], 612 $currblk['border_radius_TR_V'], 613 $currblk['padding_right'], 614 $currblk['padding_top'] 615 ); 616 } else { 617 $this->mpdf->_borderPadding( 618 $currblk['border_radius_TR_V'], 619 $currblk['border_radius_TR_H'], 620 $currblk['padding_top'], 621 $currblk['padding_right'] 622 ); 623 } 624 } 625 if ($currblk['border_radius_BL_H'] > $currblk['padding_left'] && $currblk['border_radius_BL_V'] > $currblk['padding_bottom']) { 626 if ($currblk['border_radius_BL_H'] > $currblk['border_radius_BL_V']) { 627 $this->mpdf->_borderPadding( 628 $currblk['border_radius_BL_H'], 629 $currblk['border_radius_BL_V'], 630 $currblk['padding_left'], 631 $currblk['padding_bottom'] 632 ); 633 } else { 634 $this->mpdf->_borderPadding( 635 $currblk['border_radius_BL_V'], 636 $currblk['border_radius_BL_H'], 637 $currblk['padding_bottom'], 638 $currblk['padding_left'] 639 ); 640 } 641 } 642 if ($currblk['border_radius_BR_H'] > $currblk['padding_right'] && $currblk['border_radius_BR_V'] > $currblk['padding_bottom']) { 643 if ($currblk['border_radius_BR_H'] > $currblk['border_radius_BR_V']) { 644 $this->mpdf->_borderPadding( 645 $currblk['border_radius_BR_H'], 646 $currblk['border_radius_BR_V'], 647 $currblk['padding_right'], 648 $currblk['padding_bottom'] 649 ); 650 } else { 651 $this->mpdf->_borderPadding( 652 $currblk['border_radius_BR_V'], 653 $currblk['border_radius_BR_H'], 654 $currblk['padding_bottom'], 655 $currblk['padding_right'] 656 ); 657 } 658 } 659 } 660 /* -- END BORDER-RADIUS -- */ 661 662 // Hanging indent - if negative indent: ensure padding is >= indent 663 if (!isset($currblk['text_indent'])) { 664 $currblk['text_indent'] = null; 665 } 666 if (!isset($currblk['inner_width'])) { 667 $currblk['inner_width'] = null; 668 } 669 $cbti = $this->sizeConverter->convert( 670 $currblk['text_indent'], 671 $this->mpdf->blk[$this->mpdf->blklvl]['inner_width'], 672 $this->mpdf->FontSize, 673 false 674 ); 675 if ($cbti < 0) { 676 $hangind = -$cbti; 677 if (isset($currblk['direction']) && $currblk['direction'] === 'rtl') { // *OTL* 678 $currblk['padding_right'] = max($currblk['padding_right'], $hangind); // *OTL* 679 } // *OTL* 680 else { // *OTL* 681 $currblk['padding_left'] = max($currblk['padding_left'], $hangind); 682 } // *OTL* 683 } 684 685 if (isset($currblk['css_set_width'])) { 686 if (isset($properties['MARGIN-LEFT'], $properties['MARGIN-RIGHT']) 687 && strtolower($properties['MARGIN-LEFT']) === 'auto' && strtolower($properties['MARGIN-RIGHT']) === 'auto') { 688 // Try to reduce margins to accomodate - if still too wide, set margin-right/left=0 (reduces width) 689 $anyextra = $prevblk['inner_width'] - ($currblk['css_set_width'] + $currblk['border_left']['w'] 690 + $currblk['padding_left'] + $currblk['border_right']['w'] + $currblk['padding_right']); 691 if ($anyextra > 0) { 692 $currblk['margin_left'] = $currblk['margin_right'] = $anyextra / 2; 693 } else { 694 $currblk['margin_left'] = $currblk['margin_right'] = 0; 695 } 696 } elseif (isset($properties['MARGIN-LEFT']) && strtolower($properties['MARGIN-LEFT']) === 'auto') { 697 // Try to reduce margin-left to accomodate - if still too wide, set margin-left=0 (reduces width) 698 $currblk['margin_left'] = $prevblk['inner_width'] - ($currblk['css_set_width'] 699 + $currblk['border_left']['w'] + $currblk['padding_left'] + $currblk['border_right']['w'] 700 + $currblk['padding_right'] + $currblk['margin_right']); 701 if ($currblk['margin_left'] < 0) { 702 $currblk['margin_left'] = 0; 703 } 704 } elseif (isset($properties['MARGIN-RIGHT']) && strtolower($properties['MARGIN-RIGHT']) === 'auto') { 705 // Try to reduce margin-right to accomodate - if still too wide, set margin-right=0 (reduces width) 706 $currblk['margin_right'] = $prevblk['inner_width'] - ($currblk['css_set_width'] 707 + $currblk['border_left']['w'] + $currblk['padding_left'] 708 + $currblk['border_right']['w'] + $currblk['padding_right'] + $currblk['margin_left']); 709 if ($currblk['margin_right'] < 0) { 710 $currblk['margin_right'] = 0; 711 } 712 } else { 713 if ($currblk['direction'] === 'rtl') { // *OTL* 714 // Try to reduce margin-left to accomodate - if still too wide, set margin-left=0 (reduces width) 715 $currblk['margin_left'] = $prevblk['inner_width'] - ($currblk['css_set_width'] 716 + $currblk['border_left']['w'] + $currblk['padding_left'] + $currblk['border_right']['w'] 717 + $currblk['padding_right'] + $currblk['margin_right']); // *OTL* 718 if ($currblk['margin_left'] < 0) { // *OTL* 719 $currblk['margin_left'] = 0; // *OTL* 720 } // *OTL* 721 } // *OTL* 722 else { // *OTL* 723 // Try to reduce margin-right to accomodate - if still too wide, set margin-right=0 (reduces width) 724 $currblk['margin_right'] = $prevblk['inner_width'] - ($currblk['css_set_width'] 725 + $currblk['border_left']['w'] + $currblk['padding_left'] + $currblk['border_right']['w'] 726 + $currblk['padding_right'] + $currblk['margin_left']); 727 if ($currblk['margin_right'] < 0) { 728 $currblk['margin_right'] = 0; 729 } 730 } // *OTL* 731 } 732 } 733 734 $currblk['outer_left_margin'] = $prevblk['outer_left_margin'] + $currblk['margin_left'] 735 + $prevblk['border_left']['w'] + $prevblk['padding_left']; 736 737 $currblk['outer_right_margin'] = $prevblk['outer_right_margin'] + $currblk['margin_right'] 738 + $prevblk['border_right']['w'] + $prevblk['padding_right']; 739 740 $currblk['width'] = $this->mpdf->pgwidth - ($currblk['outer_right_margin'] + $currblk['outer_left_margin']); 741 742 $currblk['inner_width'] = $currblk['width'] 743 - ($currblk['border_left']['w'] + $currblk['padding_left'] + $currblk['border_right']['w'] + $currblk['padding_right']); 744 745 // Check DIV is not now too narrow to fit text 746 $mw = 2 * $this->mpdf->GetCharWidth('W', false); 747 if ($currblk['inner_width'] < $mw) { 748 $currblk['padding_left'] = 0; 749 $currblk['padding_right'] = 0; 750 $currblk['border_left']['w'] = 0.2; 751 $currblk['border_right']['w'] = 0.2; 752 $currblk['margin_left'] = 0; 753 $currblk['margin_right'] = 0; 754 $currblk['outer_left_margin'] = $prevblk['outer_left_margin'] + $currblk['margin_left'] 755 + $prevblk['border_left']['w'] + $prevblk['padding_left']; 756 $currblk['outer_right_margin'] = $prevblk['outer_right_margin'] + $currblk['margin_right'] 757 + $prevblk['border_right']['w'] + $prevblk['padding_right']; 758 $currblk['width'] = $this->mpdf->pgwidth - ($currblk['outer_right_margin'] + $currblk['outer_left_margin']); 759 $currblk['inner_width'] = $this->mpdf->pgwidth - ($currblk['outer_right_margin'] 760 + $currblk['outer_left_margin'] + $currblk['border_left']['w'] + $currblk['padding_left'] 761 + $currblk['border_right']['w'] + $currblk['padding_right']); 762 // if ($currblk['inner_width'] < $mw) { throw new \Mpdf\MpdfException("DIV is too narrow for text to fit!"); } 763 } 764 765 $this->mpdf->x = $this->mpdf->lMargin + $currblk['outer_left_margin']; 766 767 /* -- BACKGROUNDS -- */ 768 if (!empty($properties['BACKGROUND-IMAGE']) && !$this->mpdf->kwt && !$this->mpdf->ColActive && !$this->mpdf->keep_block_together) { 769 $ret = $this->mpdf->SetBackground($properties, $currblk['inner_width']); 770 if ($ret) { 771 $currblk['background-image'] = $ret; 772 } 773 } 774 /* -- END BACKGROUNDS -- */ 775 776 /* -- TABLES -- */ 777 if ($this->mpdf->use_kwt && isset($attr['KEEP-WITH-TABLE']) && !$this->mpdf->ColActive && !$this->mpdf->keep_block_together) { 778 $this->mpdf->kwt = true; 779 $this->mpdf->kwt_y0 = $this->mpdf->y; 780 //$this->mpdf->kwt_x0 = $this->mpdf->x; 781 $this->mpdf->kwt_x0 = $this->mpdf->lMargin; // mPDF 6 782 $this->mpdf->kwt_height = 0; 783 $this->mpdf->kwt_buffer = []; 784 $this->mpdf->kwt_Links = []; 785 $this->mpdf->kwt_Annots = []; 786 $this->mpdf->kwt_moved = false; 787 $this->mpdf->kwt_saved = false; 788 $this->mpdf->kwt_Reference = []; 789 $this->mpdf->kwt_BMoutlines = []; 790 $this->mpdf->kwt_toc = []; 791 } else { 792 /* -- END TABLES -- */ 793 $this->mpdf->kwt = false; 794 } // *TABLES* 795 796 // Save x,y coords in case we need to print borders... 797 $currblk['y0'] = $this->mpdf->y; 798 $currblk['initial_y0'] = $this->mpdf->y; // mPDF 6 799 $currblk['x0'] = $this->mpdf->x; 800 $currblk['initial_x0'] = $this->mpdf->x; // mPDF 6 801 $currblk['initial_startpage'] = $this->mpdf->page; 802 $currblk['startpage'] = $this->mpdf->page; // mPDF 6 803 $this->mpdf->oldy = $this->mpdf->y; 804 805 $this->mpdf->lastblocklevelchange = 1; 806 807 // mPDF 6 Lists 808 if ($tag === 'OL' || $tag === 'UL') { 809 $this->mpdf->listlvl++; 810 if (!empty($attr['START'])) { 811 $this->mpdf->listcounter[$this->mpdf->listlvl] = (int) $attr['START'] - 1; 812 } else { 813 $this->mpdf->listcounter[$this->mpdf->listlvl] = 0; 814 } 815 $this->mpdf->listitem = []; 816 817 // List-type 818 if (empty($currblk['list_style_type'])) { 819 if ($tag === 'OL') { 820 $currblk['list_style_type'] = 'decimal'; 821 } elseif ($tag === 'UL') { 822 if ($this->mpdf->listlvl % 3 == 1) { 823 $currblk['list_style_type'] = 'disc'; 824 } elseif ($this->mpdf->listlvl % 3 == 2) { 825 $currblk['list_style_type'] = 'circle'; 826 } else { 827 $currblk['list_style_type'] = 'square'; 828 } 829 } 830 } 831 832 // List-image 833 if (empty($currblk['list_style_image'])) { 834 $currblk['list_style_image'] = 'none'; 835 } 836 837 // List-position 838 if (empty($currblk['list_style_position'])) { 839 $currblk['list_style_position'] = 'outside'; 840 } 841 842 // Default indentation using padding 843 if (strtolower($this->mpdf->list_auto_mode) === 'mpdf' && isset($currblk['list_style_position']) 844 && $currblk['list_style_position'] === 'outside' && isset($currblk['list_style_image']) 845 && $currblk['list_style_image'] === 'none' && (!isset($currblk['list_style_type']) 846 || !preg_match('/U\+([a-fA-F0-9]+)/i', $currblk['list_style_type']))) { 847 $autopadding = $this->mpdf->_getListMarkerWidth($currblk, $ahtml, $ihtml); 848 if ($this->mpdf->listlvl > 1 || $this->mpdf->list_indent_first_level) { 849 $autopadding += $this->sizeConverter->convert( 850 $this->mpdf->list_indent_default, 851 $currblk['inner_width'], 852 $this->mpdf->FontSize, 853 false 854 ); 855 } 856 // autopadding value is applied to left or right according 857 // to dir of block. Once a CSS value is set for padding it overrides this default value. 858 if (isset($properties['PADDING-RIGHT']) && $properties['PADDING-RIGHT'] === 'auto' 859 && isset($currblk['direction']) && $currblk['direction'] === 'rtl') { 860 $currblk['padding_right'] = $autopadding; 861 } elseif (isset($properties['PADDING-LEFT']) && $properties['PADDING-LEFT'] === 'auto') { 862 $currblk['padding_left'] = $autopadding; 863 } 864 } else { 865 // Initial default value is set by $this->mpdf->list_indent_default in config.php; this value is applied to left or right according 866 // to dir of block. Once a CSS value is set for padding it overrides this default value. 867 if (isset($properties['PADDING-RIGHT']) && $properties['PADDING-RIGHT'] === 'auto' 868 && isset($currblk['direction']) && $currblk['direction'] === 'rtl') { 869 $currblk['padding_right'] = $this->sizeConverter->convert( 870 $this->mpdf->list_indent_default, 871 $currblk['inner_width'], 872 $this->mpdf->FontSize, 873 false 874 ); 875 } elseif (isset($properties['PADDING-LEFT']) && $properties['PADDING-LEFT'] === 'auto') { 876 $currblk['padding_left'] = $this->sizeConverter->convert( 877 $this->mpdf->list_indent_default, 878 $currblk['inner_width'], 879 $this->mpdf->FontSize, 880 false 881 ); 882 } 883 } 884 } 885 886 // mPDF 6 Lists 887 if ($tag === 'LI') { 888 if ($this->mpdf->listlvl == 0) { // in case of malformed HTML code. Example:(...)</p><li>Content</li><p>Paragraph1</p>(...) 889 $this->mpdf->listlvl++; // first depth level 890 $this->mpdf->listcounter[$this->mpdf->listlvl] = 0; 891 } 892 893 if (!isset($attr['PAGEBREAKAVOIDCHECKED']) || !$attr['PAGEBREAKAVOIDCHECKED']) { 894 $this->mpdf->listcounter[$this->mpdf->listlvl]++; 895 } 896 897 $this->mpdf->listitem = []; 898 899 // Listitem-type 900 $this->mpdf->_setListMarker($currblk['list_style_type'], $currblk['list_style_image'], $currblk['list_style_position']); 901 } 902 903 // mPDF 6 Bidirectional formatting for block elements 904 $bdf = false; 905 $bdf2 = ''; 906 $popd = ''; 907 908 // Get current direction 909 $currdir = 'ltr'; 910 if (isset($currblk['direction'])) { 911 $currdir = $currblk['direction']; 912 } 913 if (isset($attr['DIR']) && $attr['DIR'] != '') { 914 $currdir = strtolower($attr['DIR']); 915 } 916 if (isset($properties['DIRECTION'])) { 917 $currdir = strtolower($properties['DIRECTION']); 918 } 919 920 // mPDF 6 bidi 921 // cf. http://www.w3.org/TR/css3-writing-modes/#unicode-bidi 922 if (isset($properties ['UNICODE-BIDI']) 923 && (strtolower($properties ['UNICODE-BIDI']) === 'bidi-override' || strtolower($properties ['UNICODE-BIDI']) === 'isolate-override')) { 924 if ($currdir === 'rtl') { 925 $bdf = 0x202E; 926 $popd = 'RLOPDF'; 927 } // U+202E RLO 928 else { 929 $bdf = 0x202D; 930 $popd = 'LROPDF'; 931 } // U+202D LRO 932 } elseif (isset($properties ['UNICODE-BIDI']) && strtolower($properties ['UNICODE-BIDI']) === 'plaintext') { 933 $bdf = 0x2068; 934 $popd = 'FSIPDI'; // U+2068 FSI 935 } 936 if ($bdf) { 937 if ($bdf2) { 938 $bdf2 = UtfString::code2utf($bdf); 939 } 940 $this->mpdf->OTLdata = []; 941 if ($this->mpdf->tableLevel) { 942 $this->mpdf->_saveCellTextBuffer(UtfString::code2utf($bdf) . $bdf2); 943 } else { 944 $this->mpdf->_saveTextBuffer(UtfString::code2utf($bdf) . $bdf2); 945 } 946 $this->mpdf->biDirectional = true; 947 $currblk['bidicode'] = $popd; 948 } 949 } 950 951 public function close(&$ahtml, &$ihtml) 952 { 953 $tag = $this->getTagName(); 954 955 // mPDF 6 bidi 956 // Block 957 // If unicode-bidi set, any embedding levels, isolates, or overrides started by this box are closed 958 if (isset($this->mpdf->blk[$this->mpdf->blklvl]['bidicode'])) { 959 $blockpost = $this->mpdf->_setBidiCodes('end', $this->mpdf->blk[$this->mpdf->blklvl]['bidicode']); 960 if ($blockpost) { 961 $this->mpdf->OTLdata = []; 962 if ($this->mpdf->tableLevel) { 963 $this->mpdf->_saveCellTextBuffer($blockpost); 964 } else { 965 $this->mpdf->_saveTextBuffer($blockpost); 966 } 967 } 968 } 969 970 $this->mpdf->ignorefollowingspaces = true; //Eliminate exceeding left-side spaces 971 $this->mpdf->blockjustfinished = true; 972 973 $this->mpdf->lastblockbottommargin = $this->mpdf->blk[$this->mpdf->blklvl]['margin_bottom']; 974 // mPDF 6 Lists 975 if ($tag === 'UL' || $tag === 'OL') { 976 if ($this->mpdf->listlvl > 0 && $this->mpdf->tableLevel) { 977 if (isset($this->mpdf->listtype[$this->mpdf->listlvl])) { 978 unset($this->mpdf->listtype[$this->mpdf->listlvl]); 979 } 980 } 981 $this->mpdf->listlvl--; 982 $this->mpdf->listitem = []; 983 } 984 if ($tag === 'LI') { 985 $this->mpdf->listitem = []; 986 } 987 988 if (preg_match('/^H\d/', $tag) && !$this->mpdf->tableLevel && !$this->mpdf->writingToC) { 989 if (isset($this->mpdf->h2toc[$tag]) || isset($this->mpdf->h2bookmarks[$tag])) { 990 $content = ''; 991 if (count($this->mpdf->textbuffer) == 1) { 992 $content = $this->mpdf->textbuffer[0][0]; 993 } else { 994 for ($i = 0; $i < count($this->mpdf->textbuffer); $i++) { 995 if (0 !== strpos($this->mpdf->textbuffer[$i][0], "\xbb\xa4\xac")) { //inline object 996 $content .= $this->mpdf->textbuffer[$i][0]; 997 } 998 } 999 } 1000 /* -- TOC -- */ 1001 if (isset($this->mpdf->h2toc[$tag])) { 1002 $objattr = []; 1003 $objattr['type'] = 'toc'; 1004 $objattr['toclevel'] = $this->mpdf->h2toc[$tag]; 1005 $objattr['CONTENT'] = htmlspecialchars($content); 1006 $e = "\xbb\xa4\xactype=toc,objattr=" . serialize($objattr) . "\xbb\xa4\xac"; 1007 array_unshift($this->mpdf->textbuffer, [$e]); 1008 } 1009 /* -- END TOC -- */ 1010 /* -- BOOKMARKS -- */ 1011 if (isset($this->mpdf->h2bookmarks[$tag])) { 1012 $objattr = []; 1013 $objattr['type'] = 'bookmark'; 1014 $objattr['bklevel'] = $this->mpdf->h2bookmarks[$tag]; 1015 $objattr['CONTENT'] = $content; 1016 $e = "\xbb\xa4\xactype=toc,objattr=" . serialize($objattr) . "\xbb\xa4\xac"; 1017 array_unshift($this->mpdf->textbuffer, [$e]); 1018 } 1019 /* -- END BOOKMARKS -- */ 1020 } 1021 } 1022 1023 /* -- TABLES -- */ 1024 if ($this->mpdf->tableLevel) { 1025 if ($this->mpdf->linebreakjustfinished) { 1026 $this->mpdf->blockjustfinished = false; 1027 } 1028 if (isset($this->mpdf->InlineProperties['BLOCKINTABLE'])) { 1029 if ($this->mpdf->InlineProperties['BLOCKINTABLE']) { 1030 $this->mpdf->restoreInlineProperties($this->mpdf->InlineProperties['BLOCKINTABLE']); 1031 } 1032 unset($this->mpdf->InlineProperties['BLOCKINTABLE']); 1033 } 1034 if ($tag === 'PRE') { 1035 $this->mpdf->ispre = false; 1036 } 1037 return; 1038 } 1039 /* -- END TABLES -- */ 1040 $this->mpdf->lastoptionaltag = ''; 1041 $this->mpdf->divbegin = false; 1042 1043 $this->mpdf->linebreakjustfinished = false; 1044 1045 $this->mpdf->x = $this->mpdf->lMargin + $this->mpdf->blk[$this->mpdf->blklvl]['outer_left_margin']; 1046 1047 /* -- CSS-FLOAT -- */ 1048 // If float contained in a float, need to extend bottom to allow for it 1049 $currpos = $this->mpdf->page * 1000 + $this->mpdf->y; 1050 if (isset($this->mpdf->blk[$this->mpdf->blklvl]['float_endpos']) && $this->mpdf->blk[$this->mpdf->blklvl]['float_endpos'] > $currpos) { 1051 $old_page = $this->mpdf->page; 1052 $new_page = (int) ($this->mpdf->blk[$this->mpdf->blklvl]['float_endpos'] / 1000); 1053 if ($old_page != $new_page) { 1054 $s = $this->mpdf->PrintPageBackgrounds(); 1055 // Writes after the marker so not overwritten later by page background etc. 1056 $this->mpdf->pages[$this->mpdf->page] = preg_replace( 1057 '/(___BACKGROUND___PATTERNS' . $this->mpdf->uniqstr . ')/', 1058 '\\1' . "\n" . $s . "\n", 1059 $this->mpdf->pages[$this->mpdf->page] 1060 ); 1061 $this->mpdf->pageBackgrounds = []; 1062 $this->mpdf->page = $new_page; 1063 $this->mpdf->ResetMargins(); 1064 $this->mpdf->Reset(); 1065 $this->mpdf->pageoutput[$this->mpdf->page] = []; 1066 } 1067 // mod changes operands to integers before processing 1068 $this->mpdf->y = (round($this->mpdf->blk[$this->mpdf->blklvl]['float_endpos'] * 1000) % 1000000) / 1000; 1069 } 1070 /* -- END CSS-FLOAT -- */ 1071 1072 1073 //Print content 1074 $blockstate = 0; 1075 if ($this->mpdf->lastblocklevelchange == 1) { 1076 $blockstate = 3; 1077 } // Top & bottom margins/padding 1078 elseif ($this->mpdf->lastblocklevelchange == -1) { 1079 $blockstate = 2; 1080 } // Bottom margins/padding only 1081 1082 // called from after e.g. </table> </div> </div> ... Outputs block margin/border and padding 1083 if (count($this->mpdf->textbuffer) && $this->mpdf->textbuffer[count($this->mpdf->textbuffer) - 1]) { 1084 if (0 !== strpos($this->mpdf->textbuffer[count($this->mpdf->textbuffer) - 1][0], "\xbb\xa4\xac")) { // not special content 1085 // Right trim last content and adjust OTLdata 1086 if (preg_match('/[ ]+$/', $this->mpdf->textbuffer[count($this->mpdf->textbuffer) - 1][0], $m)) { 1087 $strip = strlen($m[0]); 1088 $this->mpdf->textbuffer[count($this->mpdf->textbuffer) - 1][0] = substr( 1089 $this->mpdf->textbuffer[count($this->mpdf->textbuffer) - 1][0], 1090 0, 1091 strlen($this->mpdf->textbuffer[count($this->mpdf->textbuffer) - 1][0]) - $strip 1092 ); 1093 /* -- OTL -- */ 1094 if (!empty($this->mpdf->CurrentFont['useOTL'])) { 1095 $this->otl->trimOTLdata($this->mpdf->textbuffer[count($this->mpdf->textbuffer) - 1][18], false); // mPDF 6 ZZZ99K 1096 } 1097 /* -- END OTL -- */ 1098 } 1099 } 1100 } 1101 1102 if (count($this->mpdf->textbuffer) == 0 && $this->mpdf->lastblocklevelchange != 0) { 1103 /*$this->mpdf->newFlowingBlock( 1104 $this->mpdf->blk[$this->mpdf->blklvl]['width'], 1105 $this->mpdf->lineheight, 1106 '', 1107 false, 1108 2, 1109 true, 1110 (isset($this->mpdf->blk[$this->mpdf->blklvl]['direction']) ? $this->mpdf->blk[$this->mpdf->blklvl]['direction'] : 'ltr') 1111 );*/ 1112 1113 $this->mpdf->newFlowingBlock( 1114 $this->mpdf->blk[$this->mpdf->blklvl]['width'], 1115 $this->mpdf->lineheight, 1116 '', 1117 false, 1118 $blockstate, 1119 true, 1120 (isset($this->mpdf->blk[$this->mpdf->blklvl]['direction']) ? $this->mpdf->blk[$this->mpdf->blklvl]['direction'] : 'ltr') 1121 ); 1122 1123 $this->mpdf->finishFlowingBlock(true); // true = END of flowing block 1124 $this->mpdf->PaintDivBB('', $blockstate); 1125 } else { 1126 $this->mpdf->printbuffer($this->mpdf->textbuffer, $blockstate); 1127 } 1128 1129 1130 $this->mpdf->textbuffer = []; 1131 1132 if ($this->mpdf->kwt) { 1133 $this->mpdf->kwt_height = $this->mpdf->y - $this->mpdf->kwt_y0; 1134 } 1135 1136 /* -- CSS-IMAGE-FLOAT -- */ 1137 $this->mpdf->printfloatbuffer(); 1138 /* -- END CSS-IMAGE-FLOAT -- */ 1139 1140 if ($tag === 'PRE') { 1141 $this->mpdf->ispre = false; 1142 } 1143 1144 /* -- CSS-FLOAT -- */ 1145 if ($this->mpdf->blk[$this->mpdf->blklvl]['float'] === 'R') { 1146 // If width not set, here would need to adjust and output buffer 1147 $s = $this->mpdf->PrintPageBackgrounds(); 1148 // Writes after the marker so not overwritten later by page background etc. 1149 $this->mpdf->pages[$this->mpdf->page] = preg_replace('/(___BACKGROUND___PATTERNS' . $this->mpdf->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->mpdf->pages[$this->mpdf->page]); 1150 $this->mpdf->pageBackgrounds = []; 1151 $this->mpdf->Reset(); 1152 $this->mpdf->pageoutput[$this->mpdf->page] = []; 1153 1154 for ($i = ($this->mpdf->blklvl - 1); $i >= 0; $i--) { 1155 if (isset($this->mpdf->blk[$i]['float_endpos'])) { 1156 $this->mpdf->blk[$i]['float_endpos'] = max($this->mpdf->blk[$i]['float_endpos'], $this->mpdf->page * 1000 + $this->mpdf->y); 1157 } else { 1158 $this->mpdf->blk[$i]['float_endpos'] = $this->mpdf->page * 1000 + $this->mpdf->y; 1159 } 1160 } 1161 1162 $this->mpdf->floatDivs[] = [ 1163 'side' => 'R', 1164 'startpage' => $this->mpdf->blk[$this->mpdf->blklvl]['startpage'], 1165 'y0' => $this->mpdf->blk[$this->mpdf->blklvl]['float_start_y'], 1166 'startpos' => $this->mpdf->blk[$this->mpdf->blklvl]['startpage'] * 1000 + $this->mpdf->blk[$this->mpdf->blklvl]['float_start_y'], 1167 'endpage' => $this->mpdf->page, 1168 'y1' => $this->mpdf->y, 1169 'endpos' => $this->mpdf->page * 1000 + $this->mpdf->y, 1170 'w' => $this->mpdf->blk[$this->mpdf->blklvl]['float_width'], 1171 'blklvl' => $this->mpdf->blklvl, 1172 'blockContext' => $this->mpdf->blk[$this->mpdf->blklvl - 1]['blockContext'] 1173 ]; 1174 1175 $this->mpdf->y = $this->mpdf->blk[$this->mpdf->blklvl]['float_start_y']; 1176 $this->mpdf->page = $this->mpdf->blk[$this->mpdf->blklvl]['startpage']; 1177 $this->mpdf->ResetMargins(); 1178 $this->mpdf->pageoutput[$this->mpdf->page] = []; 1179 } 1180 if ($this->mpdf->blk[$this->mpdf->blklvl]['float'] === 'L') { 1181 // If width not set, here would need to adjust and output buffer 1182 $s = $this->mpdf->PrintPageBackgrounds(); 1183 // Writes after the marker so not overwritten later by page background etc. 1184 $this->mpdf->pages[$this->mpdf->page] = preg_replace('/(___BACKGROUND___PATTERNS' . $this->mpdf->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->mpdf->pages[$this->mpdf->page]); 1185 $this->mpdf->pageBackgrounds = []; 1186 $this->mpdf->Reset(); 1187 $this->mpdf->pageoutput[$this->mpdf->page] = []; 1188 1189 for ($i = ($this->mpdf->blklvl - 1); $i >= 0; $i--) { 1190 if (isset($this->mpdf->blk[$i]['float_endpos'])) { 1191 $this->mpdf->blk[$i]['float_endpos'] = max($this->mpdf->blk[$i]['float_endpos'], $this->mpdf->page * 1000 + $this->mpdf->y); 1192 } else { 1193 $this->mpdf->blk[$i]['float_endpos'] = $this->mpdf->page * 1000 + $this->mpdf->y; 1194 } 1195 } 1196 1197 $this->mpdf->floatDivs[] = [ 1198 'side' => 'L', 1199 'startpage' => $this->mpdf->blk[$this->mpdf->blklvl]['startpage'], 1200 'y0' => $this->mpdf->blk[$this->mpdf->blklvl]['float_start_y'], 1201 'startpos' => $this->mpdf->blk[$this->mpdf->blklvl]['startpage'] * 1000 + $this->mpdf->blk[$this->mpdf->blklvl]['float_start_y'], 1202 'endpage' => $this->mpdf->page, 1203 'y1' => $this->mpdf->y, 1204 'endpos' => $this->mpdf->page * 1000 + $this->mpdf->y, 1205 'w' => $this->mpdf->blk[$this->mpdf->blklvl]['float_width'], 1206 'blklvl' => $this->mpdf->blklvl, 1207 'blockContext' => $this->mpdf->blk[$this->mpdf->blklvl - 1]['blockContext'] 1208 ]; 1209 1210 $this->mpdf->y = $this->mpdf->blk[$this->mpdf->blklvl]['float_start_y']; 1211 $this->mpdf->page = $this->mpdf->blk[$this->mpdf->blklvl]['startpage']; 1212 $this->mpdf->ResetMargins(); 1213 $this->mpdf->pageoutput[$this->mpdf->page] = []; 1214 } 1215 /* -- END CSS-FLOAT -- */ 1216 1217 if (isset($this->mpdf->blk[$this->mpdf->blklvl]['visibility']) && $this->mpdf->blk[$this->mpdf->blklvl]['visibility'] !== 'visible') { 1218 $this->mpdf->SetVisibility('visible'); 1219 } 1220 1221 $page_break_after = ''; 1222 if (isset($this->mpdf->blk[$this->mpdf->blklvl]['page_break_after'])) { 1223 $page_break_after = $this->mpdf->blk[$this->mpdf->blklvl]['page_break_after']; 1224 } 1225 1226 // Reset values 1227 $this->mpdf->Reset(); 1228 1229 if (isset($this->mpdf->blk[$this->mpdf->blklvl]['z-index']) && $this->mpdf->blk[$this->mpdf->blklvl]['z-index'] > 0) { 1230 $this->mpdf->EndLayer(); 1231 } 1232 1233 // mPDF 6 page-break-inside:avoid 1234 if ($this->mpdf->blk[$this->mpdf->blklvl]['keep_block_together']) { 1235 $movepage = false; 1236 // If page-break-inside:avoid section has broken to new page but fits on one side - then move: 1237 if (($this->mpdf->page - $this->mpdf->kt_p00) == 1 && $this->mpdf->y < $this->mpdf->kt_y00) { 1238 $movepage = true; 1239 } 1240 if (($this->mpdf->page - $this->mpdf->kt_p00) > 0) { 1241 for ($i = $this->mpdf->page; $i > $this->mpdf->kt_p00; $i--) { 1242 unset($this->mpdf->pages[$i]); 1243 if (isset($this->mpdf->blk[$this->mpdf->blklvl]['bb_painted'][$i])) { 1244 unset($this->mpdf->blk[$this->mpdf->blklvl]['bb_painted'][$i]); 1245 } 1246 if (isset($this->mpdf->blk[$this->mpdf->blklvl]['marginCorrected'][$i])) { 1247 unset($this->mpdf->blk[$this->mpdf->blklvl]['marginCorrected'][$i]); 1248 } 1249 if (isset($this->mpdf->pageoutput[$i])) { 1250 unset($this->mpdf->pageoutput[$i]); 1251 } 1252 } 1253 $this->mpdf->page = $this->mpdf->kt_p00; 1254 } 1255 $this->mpdf->keep_block_together = 0; 1256 $this->mpdf->pageoutput[$this->mpdf->page] = []; 1257 1258 $this->mpdf->y = $this->mpdf->kt_y00; 1259 1260 $ihtml = $this->mpdf->blk[$this->mpdf->blklvl]['array_i'] - 1; 1261 1262 $ahtml[$ihtml + 1] .= ' pagebreakavoidchecked="true";'; // avoid re-iterating; read in OpenTag() 1263 1264 unset($this->mpdf->blk[$this->mpdf->blklvl]); 1265 $this->mpdf->blklvl--; 1266 1267 for ($blklvl = 1; $blklvl <= $this->mpdf->blklvl; $blklvl++) { 1268 $this->mpdf->blk[$blklvl]['y0'] = $this->mpdf->blk[$blklvl]['initial_y0']; 1269 $this->mpdf->blk[$blklvl]['x0'] = $this->mpdf->blk[$blklvl]['initial_x0']; 1270 $this->mpdf->blk[$blklvl]['startpage'] = $this->mpdf->blk[$blklvl]['initial_startpage']; 1271 } 1272 1273 if (isset($this->mpdf->blk[$this->mpdf->blklvl]['x0'])) { 1274 $this->mpdf->x = $this->mpdf->blk[$this->mpdf->blklvl]['x0']; 1275 } else { 1276 $this->mpdf->x = $this->mpdf->lMargin; 1277 } 1278 1279 $this->mpdf->lastblocklevelchange = 0; 1280 $this->mpdf->ResetMargins(); 1281 if ($movepage) { 1282 $this->mpdf->AddPage(); 1283 } 1284 return; 1285 } 1286 1287 if ($this->mpdf->blklvl > 0) { // ==0 SHOULDN'T HAPPEN - NOT XHTML 1288 if ($this->mpdf->blk[$this->mpdf->blklvl]['tag'] == $tag) { 1289 unset($this->mpdf->blk[$this->mpdf->blklvl]); 1290 $this->mpdf->blklvl--; 1291 } 1292 //else { echo $tag; exit; } // debug - forces error if incorrectly nested html tags 1293 } 1294 1295 $this->mpdf->lastblocklevelchange = -1; 1296 // Reset Inline-type properties 1297 if (isset($this->mpdf->blk[$this->mpdf->blklvl]['InlineProperties'])) { 1298 $this->mpdf->restoreInlineProperties($this->mpdf->blk[$this->mpdf->blklvl]['InlineProperties']); 1299 } 1300 1301 $this->mpdf->x = $this->mpdf->lMargin + $this->mpdf->blk[$this->mpdf->blklvl]['outer_left_margin']; 1302 1303 if (!$this->mpdf->tableLevel && $page_break_after) { 1304 $save_blklvl = $this->mpdf->blklvl; 1305 $save_blk = $this->mpdf->blk; 1306 $save_silp = $this->mpdf->saveInlineProperties(); 1307 $save_ilp = $this->mpdf->InlineProperties; 1308 $save_bflp = $this->mpdf->InlineBDF; 1309 $save_bflpc = $this->mpdf->InlineBDFctr; // mPDF 6 1310 // mPDF 6 pagebreaktype 1311 $startpage = $this->mpdf->page; 1312 $pagebreaktype = $this->mpdf->defaultPagebreakType; 1313 if ($this->mpdf->ColActive) { 1314 $pagebreaktype = 'cloneall'; 1315 } 1316 1317 // mPDF 6 pagebreaktype 1318 $this->mpdf->_preForcedPagebreak($pagebreaktype); 1319 1320 if ($page_break_after === 'RIGHT') { 1321 $this->mpdf->AddPage($this->mpdf->CurOrientation, 'NEXT-ODD'); 1322 } elseif ($page_break_after === 'LEFT') { 1323 $this->mpdf->AddPage($this->mpdf->CurOrientation, 'NEXT-EVEN'); 1324 } else { 1325 $this->mpdf->AddPage($this->mpdf->CurOrientation); 1326 } 1327 1328 // mPDF 6 pagebreaktype 1329 $this->mpdf->_postForcedPagebreak($pagebreaktype, $startpage, $save_blk, $save_blklvl); 1330 1331 $this->mpdf->InlineProperties = $save_ilp; 1332 $this->mpdf->InlineBDF = $save_bflp; 1333 $this->mpdf->InlineBDFctr = $save_bflpc; // mPDF 6 1334 $this->mpdf->restoreInlineProperties($save_silp); 1335 } 1336 // mPDF 6 bidi 1337 // Block 1338 // If unicode-bidi set, any embedding levels, isolates, or overrides reopened in the continuing block 1339 if (isset($this->mpdf->blk[$this->mpdf->blklvl]['bidicode'])) { 1340 $blockpre = $this->mpdf->_setBidiCodes('start', $this->mpdf->blk[$this->mpdf->blklvl]['bidicode']); 1341 if ($blockpre) { 1342 $this->mpdf->OTLdata = []; 1343 if ($this->mpdf->tableLevel) { 1344 $this->mpdf->_saveCellTextBuffer($blockpre); 1345 } else { 1346 $this->mpdf->_saveTextBuffer($blockpre); 1347 } 1348 } 1349 } 1350 } 1351 1352} 1353