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