1 <?php
2 
3 namespace Mpdf;
4 
5 use Mpdf\Config\ConfigVariables;
6 use Mpdf\Config\FontVariables;
7 use Mpdf\Conversion;
8 use Mpdf\Css\Border;
9 use Mpdf\Css\TextVars;
10 use Mpdf\Log\Context as LogContext;
11 use Mpdf\Fonts\MetricsGenerator;
12 use Mpdf\Output\Destination;
13 use Mpdf\QrCode;
14 use Mpdf\Utils\Arrays;
15 use Mpdf\Utils\NumericString;
16 use Mpdf\Utils\UtfString;
17 use Psr\Log\LoggerInterface;
18 use Psr\Log\NullLogger;
19 
20 /**
21  * mPDF, PHP library generating PDF files from UTF-8 encoded HTML
22  *
23  * based on FPDF by Olivier Plathey
24  *      and HTML2FPDF by Renato Coelho
25  *
26  * @license GPL-2.0
27  */
28 class Mpdf implements \Psr\Log\LoggerAwareInterface
29 {
30 
31 	use Strict;
32 	use FpdiTrait;
33 
34 	const VERSION = '8.0.17';
35 
36 	const SCALE = 72 / 25.4;
37 
38 	var $useFixedNormalLineHeight; // mPDF 6
39 	var $useFixedTextBaseline; // mPDF 6
40 	var $adjustFontDescLineheight; // mPDF 6
41 	var $interpolateImages; // mPDF 6
42 	var $defaultPagebreakType; // mPDF 6 pagebreaktype
43 	var $indexUseSubentries; // mPDF 6
44 
45 	var $autoScriptToLang; // mPDF 6
46 	var $baseScript; // mPDF 6
47 	var $autoVietnamese; // mPDF 6
48 	var $autoArabic; // mPDF 6
49 
50 	var $CJKforceend;
51 	var $h2bookmarks;
52 	var $h2toc;
53 	var $decimal_align;
54 	var $margBuffer;
55 	var $splitTableBorderWidth;
56 
57 	var $bookmarkStyles;
58 	var $useActiveForms;
59 
60 	var $repackageTTF;
61 	var $allowCJKorphans;
62 	var $allowCJKoverflow;
63 
64 	var $useKerning;
65 	var $restrictColorSpace;
66 	var $bleedMargin;
67 	var $crossMarkMargin;
68 	var $cropMarkMargin;
69 	var $cropMarkLength;
70 	var $nonPrintMargin;
71 
72 	var $PDFX;
73 	var $PDFXauto;
74 
75 	var $PDFA;
76 	var $PDFAversion = '1-B';
77 	var $PDFAauto;
78 	var $ICCProfile;
79 
80 	var $printers_info;
81 	var $iterationCounter;
82 	var $smCapsScale;
83 	var $smCapsStretch;
84 
85 	var $backupSubsFont;
86 	var $backupSIPFont;
87 	var $fonttrans;
88 	var $debugfonts;
89 	var $useAdobeCJK;
90 	var $percentSubset;
91 	var $maxTTFFilesize;
92 	var $BMPonly;
93 
94 	var $tableMinSizePriority;
95 
96 	var $dpi;
97 	var $watermarkImgAlphaBlend;
98 	var $watermarkImgBehind;
99 	var $justifyB4br;
100 	var $packTableData;
101 	var $pgsIns;
102 	var $simpleTables;
103 	var $enableImports;
104 
105 	var $debug;
106 
107 	var $setAutoTopMargin;
108 	var $setAutoBottomMargin;
109 	var $autoMarginPadding;
110 	var $collapseBlockMargins;
111 	var $falseBoldWeight;
112 	var $normalLineheight;
113 	var $incrementFPR1;
114 	var $incrementFPR2;
115 	var $incrementFPR3;
116 	var $incrementFPR4;
117 
118 	var $SHYlang;
119 	var $SHYleftmin;
120 	var $SHYrightmin;
121 	var $SHYcharmin;
122 	var $SHYcharmax;
123 	var $SHYlanguages;
124 
125 	// PageNumber Conditional Text
126 	var $pagenumPrefix;
127 	var $pagenumSuffix;
128 
129 	var $nbpgPrefix;
130 	var $nbpgSuffix;
131 	var $showImageErrors;
132 	var $allow_output_buffering;
133 	var $autoPadding;
134 	var $tabSpaces;
135 	var $autoLangToFont;
136 	var $watermarkTextAlpha;
137 	var $watermarkImageAlpha;
138 	var $watermark_size;
139 	var $watermark_pos;
140 	var $annotSize;
141 	var $annotMargin;
142 	var $annotOpacity;
143 	var $title2annots;
144 	var $keepColumns;
145 	var $keep_table_proportions;
146 	var $ignore_table_widths;
147 	var $ignore_table_percents;
148 	var $list_number_suffix;
149 
150 	var $list_auto_mode; // mPDF 6
151 	var $list_indent_first_level; // mPDF 6
152 	var $list_indent_default; // mPDF 6
153 	var $list_indent_default_mpdf;
154 	var $list_marker_offset; // mPDF 6
155 	var $list_symbol_size;
156 
157 	var $useSubstitutions;
158 	var $CSSselectMedia;
159 
160 	var $forcePortraitHeaders;
161 	var $forcePortraitMargins;
162 	var $displayDefaultOrientation;
163 	var $ignore_invalid_utf8;
164 	var $allowedCSStags;
165 	var $onlyCoreFonts;
166 	var $allow_charset_conversion;
167 
168 	var $jSWord;
169 	var $jSmaxChar;
170 	var $jSmaxCharLast;
171 	var $jSmaxWordLast;
172 
173 	var $max_colH_correction;
174 
175 	var $table_error_report;
176 	var $table_error_report_param;
177 	var $biDirectional;
178 	var $text_input_as_HTML;
179 	var $anchor2Bookmark;
180 	var $shrink_tables_to_fit;
181 
182 	var $allow_html_optional_endtags;
183 
184 	var $img_dpi;
185 	var $whitelistStreamWrappers;
186 
187 	var $defaultheaderfontsize;
188 	var $defaultheaderfontstyle;
189 	var $defaultheaderline;
190 	var $defaultfooterfontsize;
191 	var $defaultfooterfontstyle;
192 	var $defaultfooterline;
193 	var $header_line_spacing;
194 	var $footer_line_spacing;
195 
196 	var $pregCJKchars;
197 	var $pregRTLchars;
198 	var $pregCURSchars; // mPDF 6
199 
200 	var $mirrorMargins;
201 	var $watermarkText;
202 	var $watermarkAngle;
203 	var $watermarkImage;
204 	var $showWatermarkText;
205 	var $showWatermarkImage;
206 
207 	var $svgAutoFont;
208 	var $svgClasses;
209 
210 	var $fontsizes;
211 
212 	var $defaultPageNumStyle; // mPDF 6
213 
214 	//////////////////////
215 	// INTERNAL VARIABLES
216 	//////////////////////
217 	var $extrapagebreak; // mPDF 6 pagebreaktype
218 
219 	var $uniqstr; // mPDF 5.7.2
220 	var $hasOC;
221 
222 	var $textvar; // mPDF 5.7.1
223 	var $fontLanguageOverride; // mPDF 5.7.1
224 	var $OTLtags; // mPDF 5.7.1
225 	var $OTLdata;  // mPDF 5.7.1
226 
227 	var $useDictionaryLBR;
228 	var $useTibetanLBR;
229 
230 	var $writingToC;
231 	var $layers;
232 	var $layerDetails;
233 	var $current_layer;
234 	var $open_layer_pane;
235 	var $decimal_offset;
236 	var $inMeter;
237 
238 	var $CJKleading;
239 	var $CJKfollowing;
240 	var $CJKoverflow;
241 
242 	var $textshadow;
243 
244 	var $colsums;
245 	var $spanborder;
246 	var $spanborddet;
247 
248 	var $visibility;
249 
250 	var $kerning;
251 	var $fixedlSpacing;
252 	var $minwSpacing;
253 	var $lSpacingCSS;
254 	var $wSpacingCSS;
255 
256 	var $spotColorIDs;
257 	var $SVGcolors;
258 	var $spotColors;
259 	var $defTextColor;
260 	var $defDrawColor;
261 	var $defFillColor;
262 
263 	var $tableBackgrounds;
264 	var $inlineDisplayOff;
265 	var $kt_y00;
266 	var $kt_p00;
267 	var $upperCase;
268 	var $checkSIP;
269 	var $checkSMP;
270 	var $checkCJK;
271 
272 	var $watermarkImgAlpha;
273 	var $PDFAXwarnings;
274 
275 	var $MetadataRoot;
276 	var $OutputIntentRoot;
277 	var $InfoRoot;
278 	var $associatedFilesRoot;
279 
280 	var $pdf_version;
281 
282 	private $fontDir;
283 
284 	var $tempDir;
285 
286 	var $cacheCleanupInterval;
287 
288 	var $allowAnnotationFiles;
289 
290 	var $fontdata;
291 
292 	var $noImageFile;
293 	var $lastblockbottommargin;
294 	var $baselineC;
295 
296 	// mPDF 5.7.3  inline text-decoration parameters
297 	var $baselineSup;
298 	var $baselineSub;
299 	var $baselineS;
300 	var $baselineO;
301 
302 	var $subPos;
303 	var $subArrMB;
304 	var $ReqFontStyle;
305 	var $tableClipPath;
306 
307 	var $fullImageHeight;
308 
309 	var $inFixedPosBlock;  // Internal flag for position:fixed block
310 	var $fixedPosBlock;  // Buffer string for position:fixed block
311 	var $fixedPosBlockDepth;
312 	var $fixedPosBlockBBox;
313 	var $fixedPosBlockSave;
314 	var $maxPosL;
315 	var $maxPosR;
316 	var $loaded;
317 
318 	var $extraFontSubsets;
319 
320 	var $docTemplateStart;  // Internal flag for page (page no. -1) that docTemplate starts on
321 
322 	var $time0;
323 
324 	var $hyphenationDictionaryFile;
325 
326 	var $spanbgcolorarray;
327 	var $default_font;
328 	var $headerbuffer;
329 	var $lastblocklevelchange;
330 	var $nestedtablejustfinished;
331 	var $linebreakjustfinished;
332 	var $cell_border_dominance_L;
333 	var $cell_border_dominance_R;
334 	var $cell_border_dominance_T;
335 	var $cell_border_dominance_B;
336 	var $table_keep_together;
337 	var $plainCell_properties;
338 	var $shrin_k1;
339 	var $outerfilled;
340 
341 	var $blockContext;
342 	var $floatDivs;
343 
344 	var $patterns;
345 	var $pageBackgrounds;
346 
347 	var $bodyBackgroundGradient;
348 	var $bodyBackgroundImage;
349 	var $bodyBackgroundColor;
350 
351 	var $writingHTMLheader; // internal flag - used both for writing HTMLHeaders/Footers and FixedPos block
352 	var $writingHTMLfooter;
353 
354 	var $angle;
355 
356 	var $gradients;
357 
358 	var $kwt_Reference;
359 	var $kwt_BMoutlines;
360 	var $kwt_toc;
361 
362 	var $tbrot_BMoutlines;
363 	var $tbrot_toc;
364 
365 	var $col_BMoutlines;
366 	var $col_toc;
367 
368 	var $floatbuffer;
369 	var $floatmargins;
370 
371 	var $bullet;
372 	var $bulletarray;
373 
374 	var $currentLang;
375 	var $default_lang;
376 
377 	var $default_available_fonts;
378 
379 	var $pageTemplate;
380 	var $docTemplate;
381 	var $docTemplateContinue;
382 	var $docTemplateContinue2pages;
383 
384 	var $arabGlyphs;
385 	var $arabHex;
386 	var $persianGlyphs;
387 	var $persianHex;
388 	var $arabVowels;
389 	var $arabPrevLink;
390 	var $arabNextLink;
391 
392 	var $formobjects; // array of Form Objects for WMF
393 	var $InlineProperties;
394 	var $InlineAnnots;
395 	var $InlineBDF; // mPDF 6 Bidirectional formatting
396 	var $InlineBDFctr; // mPDF 6
397 
398 	var $ktAnnots;
399 	var $tbrot_Annots;
400 	var $kwt_Annots;
401 	var $columnAnnots;
402 	var $columnForms;
403 	var $tbrotForms;
404 
405 	var $PageAnnots;
406 
407 	var $pageDim; // Keep track of page wxh for orientation changes - set in _beginpage, used in _putannots
408 
409 	var $breakpoints;
410 
411 	var $tableLevel;
412 	var $tbctr;
413 	var $innermostTableLevel;
414 	var $saveTableCounter;
415 	var $cellBorderBuffer;
416 
417 	var $saveHTMLFooter_height;
418 	var $saveHTMLFooterE_height;
419 
420 	var $firstPageBoxHeader;
421 	var $firstPageBoxHeaderEven;
422 	var $firstPageBoxFooter;
423 	var $firstPageBoxFooterEven;
424 
425 	var $page_box;
426 
427 	var $show_marks; // crop or cross marks
428 	var $basepathIsLocal;
429 
430 	var $use_kwt;
431 	var $kwt;
432 	var $kwt_height;
433 	var $kwt_y0;
434 	var $kwt_x0;
435 	var $kwt_buffer;
436 	var $kwt_Links;
437 	var $kwt_moved;
438 	var $kwt_saved;
439 
440 	var $PageNumSubstitutions;
441 
442 	var $table_borders_separate;
443 	var $base_table_properties;
444 	var $borderstyles;
445 
446 	var $blockjustfinished;
447 
448 	var $orig_bMargin;
449 	var $orig_tMargin;
450 	var $orig_lMargin;
451 	var $orig_rMargin;
452 	var $orig_hMargin;
453 	var $orig_fMargin;
454 
455 	var $pageHTMLheaders;
456 	var $pageHTMLfooters;
457 
458 	var $saveHTMLHeader;
459 	var $saveHTMLFooter;
460 
461 	var $HTMLheaderPageLinks;
462 	var $HTMLheaderPageAnnots;
463 	var $HTMLheaderPageForms;
464 
465 	// See Config\FontVariables for these next 5 values
466 	var $available_unifonts;
467 	var $sans_fonts;
468 	var $serif_fonts;
469 	var $mono_fonts;
470 	var $defaultSubsFont;
471 
472 	// List of ALL available CJK fonts (incl. styles) (Adobe add-ons)  hw removed
473 	var $available_CJK_fonts;
474 
475 	var $HTMLHeader;
476 	var $HTMLFooter;
477 	var $HTMLHeaderE;
478 	var $HTMLFooterE;
479 	var $bufferoutput;
480 
481 	// CJK fonts
482 	var $Big5_widths;
483 	var $GB_widths;
484 	var $SJIS_widths;
485 	var $UHC_widths;
486 
487 	// SetProtection
488 	var $encrypted;
489 
490 	var $enc_obj_id; // encryption object id
491 
492 	// Bookmark
493 	var $BMoutlines;
494 	var $OutlineRoot;
495 
496 	// INDEX
497 	var $ColActive;
498 	var $Reference;
499 	var $CurrCol;
500 	var $NbCol;
501 	var $y0;   // Top ordinate of columns
502 
503 	var $ColL;
504 	var $ColWidth;
505 	var $ColGap;
506 
507 	// COLUMNS
508 	var $ColR;
509 	var $ChangeColumn;
510 	var $columnbuffer;
511 	var $ColDetails;
512 	var $columnLinks;
513 	var $colvAlign;
514 
515 	// Substitutions
516 	var $substitute;  // Array of substitution strings e.g. <ttz>112</ttz>
517 	var $entsearch;  // Array of HTML entities (>ASCII 127) to substitute
518 	var $entsubstitute; // Array of substitution decimal unicode for the Hi entities
519 
520 	// Default values if no style sheet offered	(cf. http://www.w3.org/TR/CSS21/sample.html)
521 	var $defaultCSS;
522 	var $defaultCssFile;
523 
524 	var $lastoptionaltag; // Save current block item which HTML specifies optionsl endtag
525 	var $pageoutput;
526 	var $charset_in;
527 	var $blk;
528 	var $blklvl;
529 	var $ColumnAdjust;
530 
531 	var $ws; // Word spacing
532 
533 	var $HREF;
534 	var $pgwidth;
535 	var $fontlist;
536 	var $oldx;
537 	var $oldy;
538 	var $B;
539 	var $I;
540 
541 	var $tdbegin;
542 	var $table;
543 	var $cell;
544 	var $col;
545 	var $row;
546 
547 	var $divbegin;
548 	var $divwidth;
549 	var $divheight;
550 	var $spanbgcolor;
551 
552 	// mPDF 6 Used for table cell (block-type) properties
553 	var $cellTextAlign;
554 	var $cellLineHeight;
555 	var $cellLineStackingStrategy;
556 	var $cellLineStackingShift;
557 
558 	// mPDF 6  Lists
559 	var $listcounter;
560 	var $listlvl;
561 	var $listtype;
562 	var $listitem;
563 
564 	var $pjustfinished;
565 	var $ignorefollowingspaces;
566 	var $SMALL;
567 	var $BIG;
568 	var $dash_on;
569 	var $dotted_on;
570 
571 	var $textbuffer;
572 	var $currentfontstyle;
573 	var $currentfontfamily;
574 	var $currentfontsize;
575 	var $colorarray;
576 	var $bgcolorarray;
577 	var $internallink;
578 	var $enabledtags;
579 
580 	var $lineheight;
581 	var $default_lineheight_correction;
582 	var $basepath;
583 	var $textparam;
584 
585 	var $specialcontent;
586 	var $selectoption;
587 	var $objectbuffer;
588 
589 	// Table Rotation
590 	var $table_rotate;
591 	var $tbrot_maxw;
592 	var $tbrot_maxh;
593 	var $tablebuffer;
594 	var $tbrot_align;
595 	var $tbrot_Links;
596 
597 	var $keep_block_together; // Keep a Block from page-break-inside: avoid
598 
599 	var $tbrot_y0;
600 	var $tbrot_x0;
601 	var $tbrot_w;
602 	var $tbrot_h;
603 
604 	var $mb_enc;
605 	var $originalMbEnc;
606 	var $originalMbRegexEnc;
607 
608 	var $directionality;
609 
610 	var $extgstates; // Used for alpha channel - Transparency (Watermark)
611 	var $mgl;
612 	var $mgt;
613 	var $mgr;
614 	var $mgb;
615 
616 	var $tts;
617 	var $ttz;
618 	var $tta;
619 
620 	// Best to alter the below variables using default stylesheet above
621 	var $page_break_after_avoid;
622 	var $margin_bottom_collapse;
623 	var $default_font_size; // in pts
624 	var $original_default_font_size; // used to save default sizes when using table default
625 	var $original_default_font;
626 	var $watermark_font;
627 	var $defaultAlign;
628 
629 	// TABLE
630 	var $defaultTableAlign;
631 	var $tablethead;
632 	var $thead_font_weight;
633 	var $thead_font_style;
634 	var $thead_font_smCaps;
635 	var $thead_valign_default;
636 	var $thead_textalign_default;
637 	var $tabletfoot;
638 	var $tfoot_font_weight;
639 	var $tfoot_font_style;
640 	var $tfoot_font_smCaps;
641 	var $tfoot_valign_default;
642 	var $tfoot_textalign_default;
643 
644 	var $trow_text_rotate;
645 
646 	var $cellPaddingL;
647 	var $cellPaddingR;
648 	var $cellPaddingT;
649 	var $cellPaddingB;
650 	var $table_border_attr_set;
651 	var $table_border_css_set;
652 
653 	var $shrin_k; // factor with which to shrink tables - used internally - do not change
654 	var $shrink_this_table_to_fit; // 0 or false to disable; value (if set) gives maximum factor to reduce fontsize
655 	var $MarginCorrection; // corrects for OddEven Margins
656 	var $margin_footer;
657 	var $margin_header;
658 
659 	var $tabletheadjustfinished;
660 	var $usingCoreFont;
661 	var $charspacing;
662 
663 	var $js;
664 
665 	/**
666 	 * Set timeout for cURL
667 	 *
668 	 * @var int
669 	 */
670 	var $curlTimeout;
671 
672 	/**
673 	 * Set execution timeout for cURL
674 	 *
675 	 * @var int
676 	 */
677 	var $curlExecutionTimeout;
678 
679 	/**
680 	 * Set to true to follow redirects with cURL.
681 	 *
682 	 * @var bool
683 	 */
684 	var $curlFollowLocation;
685 
686 	/**
687 	 * Set your own CA certificate store for SSL Certificate verification when using cURL
688 	 *
689 	 * Useful setting to use on hosts with outdated CA certificates.
690 	 *
691 	 * Download the latest CA certificate from https://curl.haxx.se/docs/caextract.html
692 	 *
693 	 * @var string The absolute path to the pem file
694 	 */
695 	var $curlCaCertificate;
696 
697 	/**
698 	 * Set to true to allow unsafe SSL HTTPS requests.
699 	 *
700 	 * Can be useful when using CDN with HTTPS and if you don't want to configure settings with SSL certificates.
701 	 *
702 	 * @var bool
703 	 */
704 	var $curlAllowUnsafeSslRequests;
705 
706 	/**
707 	 * Set the proxy for cURL.
708 	 *
709 	 * @see https://curl.haxx.se/libcurl/c/CURLOPT_PROXY.html
710 	 *
711 	 * @var string
712 	 */
713 	var $curlProxy;
714 
715 	/**
716 	 * Set the proxy auth for cURL.
717 	 *
718 	 * @see https://curl.haxx.se/libcurl/c/CURLOPT_PROXYUSERPWD.html
719 	 *
720 	 * @var string
721 	 */
722 	var $curlProxyAuth;
723 
724 	/**
725 	 * Set the User-Agent header in the HTTP requests sent by cURL.
726 	 *
727 	 * @see https://curl.haxx.se/libcurl/c/CURLOPT_USERAGENT.html
728 	 *
729 	 * @var string User Agent header
730 	 */
731 	var $curlUserAgent;
732 
733 	// Private properties FROM FPDF
734 	var $DisplayPreferences;
735 	var $flowingBlockAttr;
736 
737 	var $page; // current page number
738 
739 	var $n; // current object number
740 	var $n_js; // current object number
741 
742 	var $n_ocg_hidden;
743 	var $n_ocg_print;
744 	var $n_ocg_view;
745 
746 	var $offsets; // array of object offsets
747 	var $buffer; // buffer holding in-memory PDF
748 	var $pages; // array containing pages
749 	var $state; // current document state
750 	var $compress; // compression flag
751 
752 	var $DefOrientation; // default orientation
753 	var $CurOrientation; // current orientation
754 	var $OrientationChanges; // array indicating orientation changes
755 
756 	var $fwPt;
757 	var $fhPt; // dimensions of page format in points
758 	var $fw;
759 	var $fh; // dimensions of page format in user unit
760 	var $wPt;
761 	var $hPt; // current dimensions of page in points
762 
763 	var $w;
764 	var $h; // current dimensions of page in user unit
765 
766 	var $lMargin; // left margin
767 	var $tMargin; // top margin
768 	var $rMargin; // right margin
769 	var $bMargin; // page break margin
770 	var $cMarginL; // cell margin Left
771 	var $cMarginR; // cell margin Right
772 	var $cMarginT; // cell margin Left
773 	var $cMarginB; // cell margin Right
774 
775 	var $DeflMargin; // Default left margin
776 	var $DefrMargin; // Default right margin
777 
778 	var $x;
779 	var $y; // current position in user unit for cell positioning
780 
781 	var $lasth; // height of last cell printed
782 	var $LineWidth; // line width in user unit
783 
784 	var $CoreFonts; // array of standard font names
785 	var $fonts; // array of used fonts
786 	var $FontFiles; // array of font files
787 
788 	var $images; // array of used images
789 	var $imageVars = []; // array of image vars
790 
791 	var $PageLinks; // array of links in pages
792 	var $links; // array of internal links
793 	var $FontFamily; // current font family
794 	var $FontStyle; // current font style
795 	var $CurrentFont; // current font info
796 	var $FontSizePt; // current font size in points
797 	var $FontSize; // current font size in user unit
798 	var $DrawColor; // commands for drawing color
799 	var $FillColor; // commands for filling color
800 	var $TextColor; // commands for text color
801 	var $ColorFlag; // indicates whether fill and text colors are different
802 	var $autoPageBreak; // automatic page breaking
803 	var $PageBreakTrigger; // threshold used to trigger page breaks
804 	var $InFooter; // flag set when processing footer
805 
806 	var $InHTMLFooter;
807 	var $processingFooter; // flag set when processing footer - added for columns
808 	var $processingHeader; // flag set when processing header - added for columns
809 	var $ZoomMode; // zoom display mode
810 	var $LayoutMode; // layout display mode
811 	var $title; // title
812 	var $subject; // subject
813 	var $author; // author
814 	var $keywords; // keywords
815 	var $creator; // creator
816 
817 	var $customProperties; // array of custom document properties
818 
819 	var $associatedFiles; // associated files (see SetAssociatedFiles below)
820 	var $additionalXmpRdf; // additional rdf added in xmp
821 
822 	var $aliasNbPg; // alias for total number of pages
823 	var $aliasNbPgGp; // alias for total number of pages in page group
824 
825 	var $ispre;
826 	var $outerblocktags;
827 	var $innerblocktags;
828 
829 	public $exposeVersion;
830 
831 	private $preambleWritten = false;
832 
833 	/**
834 	 * @var string
835 	 */
836 	private $fontDescriptor;
837 
838 	/**
839 	 * @var \Mpdf\Otl
840 	 */
841 	private $otl;
842 
843 	/**
844 	 * @var \Mpdf\CssManager
845 	 */
846 	private $cssManager;
847 
848 	/**
849 	 * @var \Mpdf\Gradient
850 	 */
851 	private $gradient;
852 
853 	/**
854 	 * @var \Mpdf\Image\Bmp
855 	 */
856 	private $bmp;
857 
858 	/**
859 	 * @var \Mpdf\Image\Wmf
860 	 */
861 	private $wmf;
862 
863 	/**
864 	 * @var \Mpdf\TableOfContents
865 	 */
866 	private $tableOfContents;
867 
868 	/**
869 	 * @var \Mpdf\Form
870 	 */
871 	private $form;
872 
873 	/**
874 	 * @var \Mpdf\DirectWrite
875 	 */
876 	private $directWrite;
877 
878 	/**
879 	 * @var \Mpdf\Cache
880 	 */
881 	private $cache;
882 
883 	/**
884 	 * @var \Mpdf\Fonts\FontCache
885 	 */
886 	private $fontCache;
887 
888 	/**
889 	 * @var \Mpdf\Fonts\FontFileFinder
890 	 */
891 	private $fontFileFinder;
892 
893 	/**
894 	 * @var \Mpdf\Tag
895 	 */
896 	private $tag;
897 
898 	/**
899 	 * @var \Mpdf\Barcode
900 	 * @todo solve Tag dependency and make private
901 	 */
902 	public $barcode;
903 
904 	/**
905 	 * @var \Mpdf\QrCode\QrCode
906 	 */
907 	private $qrcode;
908 
909 	/**
910 	 * @var \Mpdf\SizeConverter
911 	 */
912 	private $sizeConverter;
913 
914 	/**
915 	 * @var \Mpdf\Color\ColorConverter
916 	 */
917 	private $colorConverter;
918 
919 	/**
920 	 * @var \Mpdf\Color\ColorModeConverter
921 	 */
922 	private $colorModeConverter;
923 
924 	/**
925 	 * @var \Mpdf\Color\ColorSpaceRestrictor
926 	 */
927 	private $colorSpaceRestrictor;
928 
929 	/**
930 	 * @var \Mpdf\Hyphenator
931 	 */
932 	private $hyphenator;
933 
934 	/**
935 	 * @var \Mpdf\Pdf\Protection
936 	 */
937 	private $protection;
938 
939 	/**
940 	 * @var \Mpdf\RemoteContentFetcher
941 	 */
942 	private $remoteContentFetcher;
943 
944 	/**
945 	 * @var \Mpdf\Image\ImageProcessor
946 	 */
947 	private $imageProcessor;
948 
949 	/**
950 	 * @var \Mpdf\Language\LanguageToFontInterface
951 	 */
952 	private $languageToFont;
953 
954 	/**
955 	 * @var \Mpdf\Language\ScriptToLanguageInterface
956 	 */
957 	private $scriptToLanguage;
958 
959 	/**
960 	 * @var \Psr\Log\LoggerInterface
961 	 */
962 	private $logger;
963 
964 	/**
965 	 * @var \Mpdf\Writer\BaseWriter
966 	 */
967 	private $writer;
968 
969 	/**
970 	 * @var \Mpdf\Writer\FontWriter
971 	 */
972 	private $fontWriter;
973 
974 	/**
975 	 * @var \Mpdf\Writer\MetadataWriter
976 	 */
977 	private $metadataWriter;
978 
979 	/**
980 	 * @var \Mpdf\Writer\ImageWriter
981 	 */
982 	private $imageWriter;
983 
984 	/**
985 	 * @var \Mpdf\Writer\FormWriter
986 	 */
987 	private $formWriter;
988 
989 	/**
990 	 * @var \Mpdf\Writer\PageWriter
991 	 */
992 	private $pageWriter;
993 
994 	/**
995 	 * @var \Mpdf\Writer\BookmarkWriter
996 	 */
997 	private $bookmarkWriter;
998 
999 	/**
1000 	 * @var \Mpdf\Writer\OptionalContentWriter
1001 	 */
1002 	private $optionalContentWriter;
1003 
1004 	/**
1005 	 * @var \Mpdf\Writer\ColorWriter
1006 	 */
1007 	private $colorWriter;
1008 
1009 	/**
1010 	 * @var \Mpdf\Writer\BackgroundWriter
1011 	 */
1012 	private $backgroundWriter;
1013 
1014 	/**
1015 	 * @var \Mpdf\Writer\JavaScriptWriter
1016 	 */
1017 	private $javaScriptWriter;
1018 
1019 	/**
1020 	 * @var \Mpdf\Writer\ResourceWriter
1021 	 */
1022 	private $resourceWriter;
1023 
1024 	/**
1025 	 * @var string[]
1026 	 */
1027 	private $services;
1028 
1029 	/**
1030 	 * @param mixed[] $config
1031 	 */
1032 	public function __construct(array $config = [])
1033 	{
1034 		$this->_dochecks();
1035 
1036 		list(
1037 			$mode,
1038 			$format,
1039 			$default_font_size,
1040 			$default_font,
1041 			$mgl,
1042 			$mgr,
1043 			$mgt,
1044 			$mgb,
1045 			$mgh,
1046 			$mgf,
1047 			$orientation
1048 		) = $this->initConstructorParams($config);
1049 
1050 		$this->logger = new NullLogger();
1051 
1052 		$originalConfig = $config;
1053 		$config = $this->initConfig($originalConfig);
1054 
1055 		$serviceFactory = new ServiceFactory();
1056 		$services = $serviceFactory->getServices(
1057 			$this,
1058 			$this->logger,
1059 			$config,
1060 			$this->restrictColorSpace,
1061 			$this->languageToFont,
1062 			$this->scriptToLanguage,
1063 			$this->fontDescriptor,
1064 			$this->bmp,
1065 			$this->directWrite,
1066 			$this->wmf
1067 		);
1068 
1069 		$this->services = [];
1070 
1071 		foreach ($services as $key => $service) {
1072 			$this->{$key} = $service;
1073 			$this->services[] = $key;
1074 		}
1075 
1076 		$this->time0 = microtime(true);
1077 
1078 		$this->writingToC = false;
1079 
1080 		$this->layers = [];
1081 		$this->current_layer = 0;
1082 		$this->open_layer_pane = false;
1083 
1084 		$this->visibility = 'visible';
1085 
1086 		$this->tableBackgrounds = [];
1087 		$this->uniqstr = '20110230'; // mPDF 5.7.2
1088 		$this->kt_y00 = 0;
1089 		$this->kt_p00 = 0;
1090 		$this->BMPonly = [];
1091 		$this->page = 0;
1092 		$this->n = 2;
1093 		$this->buffer = '';
1094 		$this->objectbuffer = [];
1095 		$this->pages = [];
1096 		$this->OrientationChanges = [];
1097 		$this->state = 0;
1098 		$this->fonts = [];
1099 		$this->FontFiles = [];
1100 		$this->images = [];
1101 		$this->links = [];
1102 		$this->InFooter = false;
1103 		$this->processingFooter = false;
1104 		$this->processingHeader = false;
1105 		$this->lasth = 0;
1106 		$this->FontFamily = '';
1107 		$this->FontStyle = '';
1108 		$this->FontSizePt = 9;
1109 
1110 		// Small Caps
1111 		$this->inMeter = false;
1112 		$this->decimal_offset = 0;
1113 
1114 		$this->PDFAXwarnings = [];
1115 
1116 		$this->defTextColor = $this->TextColor = $this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings), true);
1117 		$this->defDrawColor = $this->DrawColor = $this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings), true);
1118 		$this->defFillColor = $this->FillColor = $this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings), true);
1119 
1120 		$this->upperCase = require __DIR__ . '/../data/upperCase.php';
1121 
1122 		$this->extrapagebreak = true; // mPDF 6 pagebreaktype
1123 
1124 		$this->ColorFlag = false;
1125 		$this->extgstates = [];
1126 
1127 		$this->mb_enc = 'windows-1252';
1128 		$this->originalMbEnc = mb_internal_encoding();
1129 		$this->originalMbRegexEnc = mb_regex_encoding();
1130 
1131 		$this->directionality = 'ltr';
1132 		$this->defaultAlign = 'L';
1133 		$this->defaultTableAlign = 'L';
1134 
1135 		$this->fixedPosBlockSave = [];
1136 		$this->extraFontSubsets = 0;
1137 
1138 		$this->blockContext = 1;
1139 		$this->floatDivs = [];
1140 		$this->DisplayPreferences = '';
1141 
1142 		// Tiling patterns used for backgrounds
1143 		$this->patterns = [];
1144 		$this->pageBackgrounds = [];
1145 		$this->gradients = [];
1146 
1147 		// internal flag - used both for writing HTMLHeaders/Footers and FixedPos block
1148 		$this->writingHTMLheader = false;
1149 		// internal flag - used both for writing HTMLHeaders/Footers and FixedPos block
1150 		$this->writingHTMLfooter = false;
1151 
1152 		$this->kwt_Reference = [];
1153 		$this->kwt_BMoutlines = [];
1154 		$this->kwt_toc = [];
1155 
1156 		$this->tbrot_BMoutlines = [];
1157 		$this->tbrot_toc = [];
1158 
1159 		$this->col_BMoutlines = [];
1160 		$this->col_toc = [];
1161 
1162 		$this->pgsIns = [];
1163 		$this->PDFAXwarnings = [];
1164 		$this->inlineDisplayOff = false;
1165 		$this->lSpacingCSS = '';
1166 		$this->wSpacingCSS = '';
1167 		$this->fixedlSpacing = false;
1168 		$this->minwSpacing = 0;
1169 
1170 		// Baseline for text
1171 		$this->baselineC = 0.35;
1172 
1173 		// mPDF 5.7.3  inline text-decoration parameters
1174 		// Sets default change in baseline for <sup> text as factor of preceeding fontsize
1175 		// 0.35 has been recommended; 0.5 matches applications like MS Word
1176 		$this->baselineSup = 0.5;
1177 
1178 		// Sets default change in baseline for <sub> text as factor of preceeding fontsize
1179 		$this->baselineSub = -0.2;
1180 		// Sets default height for <strike> text as factor of fontsize
1181 		$this->baselineS = 0.3;
1182 		// Sets default height for overline text as factor of fontsize
1183 		$this->baselineO = 1.1;
1184 
1185 		$this->noImageFile = __DIR__ . '/../data/no_image.jpg';
1186 		$this->subPos = 0;
1187 
1188 		$this->fullImageHeight = false;
1189 		$this->floatbuffer = [];
1190 		$this->floatmargins = [];
1191 		$this->formobjects = []; // array of Form Objects for WMF
1192 		$this->InlineProperties = [];
1193 		$this->InlineAnnots = [];
1194 		$this->InlineBDF = []; // mPDF 6
1195 		$this->InlineBDFctr = 0; // mPDF 6
1196 		$this->tbrot_Annots = [];
1197 		$this->kwt_Annots = [];
1198 		$this->columnAnnots = [];
1199 		$this->PageLinks = [];
1200 		$this->OrientationChanges = [];
1201 		$this->pageDim = [];
1202 		$this->saveHTMLHeader = [];
1203 		$this->saveHTMLFooter = [];
1204 		$this->PageAnnots = [];
1205 		$this->PageNumSubstitutions = [];
1206 		$this->breakpoints = []; // used in columnbuffer
1207 		$this->tableLevel = 0;
1208 		$this->tbctr = []; // counter for nested tables at each level
1209 		$this->page_box = [];
1210 		$this->show_marks = ''; // crop or cross marks
1211 		$this->kwt = false;
1212 		$this->kwt_height = 0;
1213 		$this->kwt_y0 = 0;
1214 		$this->kwt_x0 = 0;
1215 		$this->kwt_buffer = [];
1216 		$this->kwt_Links = [];
1217 		$this->kwt_moved = false;
1218 		$this->kwt_saved = false;
1219 		$this->PageNumSubstitutions = [];
1220 		$this->base_table_properties = [];
1221 		$this->borderstyles = ['inset', 'groove', 'outset', 'ridge', 'dotted', 'dashed', 'solid', 'double'];
1222 		$this->tbrot_align = 'C';
1223 
1224 		$this->pageHTMLheaders = [];
1225 		$this->pageHTMLfooters = [];
1226 		$this->HTMLheaderPageLinks = [];
1227 		$this->HTMLheaderPageAnnots = [];
1228 
1229 		$this->HTMLheaderPageForms = [];
1230 		$this->columnForms = [];
1231 		$this->tbrotForms = [];
1232 
1233 		$this->pageoutput = [];
1234 
1235 		$this->bufferoutput = false;
1236 
1237 		$this->encrypted = false;
1238 
1239 		$this->BMoutlines = [];
1240 		$this->ColActive = 0;          // Flag indicating that columns are on (the index is being processed)
1241 		$this->Reference = [];    // Array containing the references
1242 		$this->CurrCol = 0;               // Current column number
1243 		$this->ColL = [0];   // Array of Left pos of columns - absolute - needs Margin correction for Odd-Even
1244 		$this->ColR = [0];   // Array of Right pos of columns - absolute pos - needs Margin correction for Odd-Even
1245 		$this->ChangeColumn = 0;
1246 		$this->columnbuffer = [];
1247 		$this->ColDetails = [];  // Keeps track of some column details
1248 		$this->columnLinks = [];  // Cross references PageLinks
1249 		$this->substitute = [];  // Array of substitution strings e.g. <ttz>112</ttz>
1250 		$this->entsearch = [];  // Array of HTML entities (>ASCII 127) to substitute
1251 		$this->entsubstitute = []; // Array of substitution decimal unicode for the Hi entities
1252 		$this->lastoptionaltag = '';
1253 		$this->charset_in = '';
1254 		$this->blk = [];
1255 		$this->blklvl = 0;
1256 		$this->tts = false;
1257 		$this->ttz = false;
1258 		$this->tta = false;
1259 		$this->ispre = false;
1260 
1261 		$this->checkSIP = false;
1262 		$this->checkSMP = false;
1263 		$this->checkCJK = false;
1264 
1265 		$this->page_break_after_avoid = false;
1266 		$this->margin_bottom_collapse = false;
1267 		$this->tablethead = 0;
1268 		$this->tabletfoot = 0;
1269 		$this->table_border_attr_set = 0;
1270 		$this->table_border_css_set = 0;
1271 		$this->shrin_k = 1.0;
1272 		$this->shrink_this_table_to_fit = 0;
1273 		$this->MarginCorrection = 0;
1274 
1275 		$this->tabletheadjustfinished = false;
1276 		$this->usingCoreFont = false;
1277 		$this->charspacing = 0;
1278 
1279 		$this->autoPageBreak = true;
1280 
1281 		$this->_setPageSize($format, $orientation);
1282 		$this->DefOrientation = $orientation;
1283 
1284 		$this->margin_header = $mgh;
1285 		$this->margin_footer = $mgf;
1286 
1287 		$bmargin = $mgb;
1288 
1289 		$this->DeflMargin = $mgl;
1290 		$this->DefrMargin = $mgr;
1291 
1292 		$this->orig_tMargin = $mgt;
1293 		$this->orig_bMargin = $bmargin;
1294 		$this->orig_lMargin = $this->DeflMargin;
1295 		$this->orig_rMargin = $this->DefrMargin;
1296 		$this->orig_hMargin = $this->margin_header;
1297 		$this->orig_fMargin = $this->margin_footer;
1298 
1299 		if ($this->setAutoTopMargin == 'pad') {
1300 			$mgt += $this->margin_header;
1301 		}
1302 		if ($this->setAutoBottomMargin == 'pad') {
1303 			$mgb += $this->margin_footer;
1304 		}
1305 
1306 		// sets l r t margin
1307 		$this->SetMargins($this->DeflMargin, $this->DefrMargin, $mgt);
1308 
1309 		// Automatic page break
1310 		// sets $this->bMargin & PageBreakTrigger
1311 		$this->SetAutoPageBreak($this->autoPageBreak, $bmargin);
1312 
1313 		$this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
1314 
1315 		// Interior cell margin (1 mm) ? not used
1316 		$this->cMarginL = 1;
1317 		$this->cMarginR = 1;
1318 
1319 		// Line width (0.2 mm)
1320 		$this->LineWidth = .567 / Mpdf::SCALE;
1321 
1322 		// Enable all tags as default
1323 		$this->DisableTags();
1324 		// Full width display mode
1325 		$this->SetDisplayMode(100); // fullwidth? 'fullpage'
1326 
1327 		// Compression
1328 		$this->SetCompression(true);
1329 		// Set default display preferences
1330 		$this->SetDisplayPreferences('');
1331 
1332 		$this->initFontConfig($originalConfig);
1333 
1334 		// Available fonts
1335 		$this->available_unifonts = [];
1336 		foreach ($this->fontdata as $f => $fs) {
1337 			if (isset($fs['R']) && $fs['R']) {
1338 				$this->available_unifonts[] = $f;
1339 			}
1340 			if (isset($fs['B']) && $fs['B']) {
1341 				$this->available_unifonts[] = $f . 'B';
1342 			}
1343 			if (isset($fs['I']) && $fs['I']) {
1344 				$this->available_unifonts[] = $f . 'I';
1345 			}
1346 			if (isset($fs['BI']) && $fs['BI']) {
1347 				$this->available_unifonts[] = $f . 'BI';
1348 			}
1349 		}
1350 
1351 		$this->default_available_fonts = $this->available_unifonts;
1352 
1353 		$optcore = false;
1354 		$onlyCoreFonts = false;
1355 		if (preg_match('/([\-+])aCJK/i', $mode, $m)) {
1356 			$mode = preg_replace('/([\-+])aCJK/i', '', $mode); // mPDF 6
1357 			if ($m[1] == '+') {
1358 				$this->useAdobeCJK = true;
1359 			} else {
1360 				$this->useAdobeCJK = false;
1361 			}
1362 		}
1363 
1364 		if (strlen($mode) == 1) {
1365 			if ($mode == 's') {
1366 				$this->percentSubset = 100;
1367 				$mode = '';
1368 			} elseif ($mode == 'c') {
1369 				$onlyCoreFonts = true;
1370 				$mode = '';
1371 			}
1372 		} elseif (substr($mode, -2) == '-s') {
1373 			$this->percentSubset = 100;
1374 			$mode = substr($mode, 0, strlen($mode) - 2);
1375 		} elseif (substr($mode, -2) == '-c') {
1376 			$onlyCoreFonts = true;
1377 			$mode = substr($mode, 0, strlen($mode) - 2);
1378 		} elseif (substr($mode, -2) == '-x') {
1379 			$optcore = true;
1380 			$mode = substr($mode, 0, strlen($mode) - 2);
1381 		}
1382 
1383 		// Autodetect if mode is a language_country string (en-GB or en_GB or en)
1384 		if ($mode && $mode != 'UTF-8') { // mPDF 6
1385 			list ($coreSuitable, $mpdf_pdf_unifont) = $this->languageToFont->getLanguageOptions($mode, $this->useAdobeCJK);
1386 			if ($coreSuitable && $optcore) {
1387 				$onlyCoreFonts = true;
1388 			}
1389 			if ($mpdf_pdf_unifont) {  // mPDF 6
1390 				$default_font = $mpdf_pdf_unifont;
1391 			}
1392 			$this->currentLang = $mode;
1393 			$this->default_lang = $mode;
1394 		}
1395 
1396 		$this->onlyCoreFonts = $onlyCoreFonts;
1397 
1398 		if ($this->onlyCoreFonts) {
1399 			$this->setMBencoding('windows-1252'); // sets $this->mb_enc
1400 		} else {
1401 			$this->setMBencoding('UTF-8'); // sets $this->mb_enc
1402 		}
1403 		@mb_regex_encoding('UTF-8'); // required only for mb_ereg... and mb_split functions
1404 
1405 		// Adobe CJK fonts
1406 		$this->available_CJK_fonts = [
1407 			'gb',
1408 			'big5',
1409 			'sjis',
1410 			'uhc',
1411 			'gbB',
1412 			'big5B',
1413 			'sjisB',
1414 			'uhcB',
1415 			'gbI',
1416 			'big5I',
1417 			'sjisI',
1418 			'uhcI',
1419 			'gbBI',
1420 			'big5BI',
1421 			'sjisBI',
1422 			'uhcBI',
1423 		];
1424 
1425 		// Standard fonts
1426 		$this->CoreFonts = [
1427 			'ccourier' => 'Courier',
1428 			'ccourierB' => 'Courier-Bold',
1429 			'ccourierI' => 'Courier-Oblique',
1430 			'ccourierBI' => 'Courier-BoldOblique',
1431 			'chelvetica' => 'Helvetica',
1432 			'chelveticaB' => 'Helvetica-Bold',
1433 			'chelveticaI' => 'Helvetica-Oblique',
1434 			'chelveticaBI' => 'Helvetica-BoldOblique',
1435 			'ctimes' => 'Times-Roman',
1436 			'ctimesB' => 'Times-Bold',
1437 			'ctimesI' => 'Times-Italic',
1438 			'ctimesBI' => 'Times-BoldItalic',
1439 			'csymbol' => 'Symbol',
1440 			'czapfdingbats' => 'ZapfDingbats'
1441 		];
1442 
1443 		$this->fontlist = [
1444 			"ctimes",
1445 			"ccourier",
1446 			"chelvetica",
1447 			"csymbol",
1448 			"czapfdingbats"
1449 		];
1450 
1451 		// Substitutions
1452 		$this->setHiEntitySubstitutions();
1453 
1454 		if ($this->onlyCoreFonts) {
1455 			$this->useSubstitutions = true;
1456 			$this->SetSubstitutions();
1457 		} else {
1458 			$this->useSubstitutions = $config['useSubstitutions'];
1459 		}
1460 
1461 		if (file_exists($this->defaultCssFile)) {
1462 			$css = file_get_contents($this->defaultCssFile);
1463 			$this->cssManager->ReadCSS('<style> ' . $css . ' </style>');
1464 		} else {
1465 			throw new \Mpdf\MpdfException(sprintf('Unable to read default CSS file "%s"', $this->defaultCssFile));
1466 		}
1467 
1468 		if ($default_font == '') {
1469 			if ($this->onlyCoreFonts) {
1470 				if (in_array(strtolower($this->defaultCSS['BODY']['FONT-FAMILY']), $this->mono_fonts)) {
1471 					$default_font = 'ccourier';
1472 				} elseif (in_array(strtolower($this->defaultCSS['BODY']['FONT-FAMILY']), $this->sans_fonts)) {
1473 					$default_font = 'chelvetica';
1474 				} else {
1475 					$default_font = 'ctimes';
1476 				}
1477 			} else {
1478 				$default_font = $this->defaultCSS['BODY']['FONT-FAMILY'];
1479 			}
1480 		}
1481 		if (!$default_font_size) {
1482 			$mmsize = $this->sizeConverter->convert($this->defaultCSS['BODY']['FONT-SIZE']);
1483 			$default_font_size = $mmsize * (Mpdf::SCALE);
1484 		}
1485 
1486 		if ($default_font) {
1487 			$this->SetDefaultFont($default_font);
1488 		}
1489 		if ($default_font_size) {
1490 			$this->SetDefaultFontSize($default_font_size);
1491 		}
1492 
1493 		$this->SetLineHeight(); // lineheight is in mm
1494 
1495 		$this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
1496 		$this->HREF = '';
1497 		$this->oldy = -1;
1498 		$this->B = 0;
1499 		$this->I = 0;
1500 
1501 		// mPDF 6  Lists
1502 		$this->listlvl = 0;
1503 		$this->listtype = [];
1504 		$this->listitem = [];
1505 		$this->listcounter = [];
1506 
1507 		$this->tdbegin = false;
1508 		$this->table = [];
1509 		$this->cell = [];
1510 		$this->col = -1;
1511 		$this->row = -1;
1512 		$this->cellBorderBuffer = [];
1513 
1514 		$this->divbegin = false;
1515 		// mPDF 6
1516 		$this->cellTextAlign = '';
1517 		$this->cellLineHeight = '';
1518 		$this->cellLineStackingStrategy = '';
1519 		$this->cellLineStackingShift = '';
1520 
1521 		$this->divwidth = 0;
1522 		$this->divheight = 0;
1523 		$this->spanbgcolor = false;
1524 		$this->spanborder = false;
1525 		$this->spanborddet = [];
1526 
1527 		$this->blockjustfinished = false;
1528 		$this->ignorefollowingspaces = true; // in order to eliminate exceeding left-side spaces
1529 		$this->dash_on = false;
1530 		$this->dotted_on = false;
1531 		$this->textshadow = '';
1532 
1533 		$this->currentfontfamily = '';
1534 		$this->currentfontsize = '';
1535 		$this->currentfontstyle = '';
1536 		$this->colorarray = ''; // mPDF 6
1537 		$this->spanbgcolorarray = ''; // mPDF 6
1538 		$this->textbuffer = [];
1539 		$this->internallink = [];
1540 		$this->basepath = "";
1541 
1542 		$this->SetBasePath('');
1543 
1544 		$this->textparam = [];
1545 
1546 		$this->specialcontent = '';
1547 		$this->selectoption = [];
1548 	}
1549 
1550 	public function cleanup()
1551 	{
1552 		mb_internal_encoding($this->originalMbEnc);
1553 		@mb_regex_encoding($this->originalMbRegexEnc);
1554 
1555 		// this will free up the readers, based on code from Setasign's FpdiTrait::cleanUp()
1556 		foreach ($this->createdReaders as $id) {
1557 			$this->readers[$id]->getParser()->getStreamReader()->cleanUp();
1558 			unset($this->readers[$id]);
1559 		}
1560 
1561 		$this->createdReaders = [];
1562 	}
1563 
1564 	/**
1565 	 * @param \Psr\Log\LoggerInterface
1566 	 *
1567 	 * @return \Mpdf\Mpdf
1568 	 */
1569 	public function setLogger(LoggerInterface $logger)
1570 	{
1571 		$this->logger = $logger;
1572 
1573 		foreach ($this->services as $name) {
1574 			if ($this->$name && $this->$name instanceof \Psr\Log\LoggerAwareInterface) {
1575 				$this->$name->setLogger($logger);
1576 			}
1577 		}
1578 
1579 		return $this;
1580 	}
1581 
1582 	private function initConfig(array $config)
1583 	{
1584 		$configObject = new ConfigVariables();
1585 		$defaults = $configObject->getDefaults();
1586 		$config = array_intersect_key($config + $defaults, $defaults);
1587 
1588 		foreach ($config as $var => $val) {
1589 			$this->{$var} = $val;
1590 		}
1591 
1592 		return $config;
1593 	}
1594 
1595 	private function initConstructorParams(array $config)
1596 	{
1597 		$constructor = [
1598 			'mode' => '',
1599 			'format' => 'A4',
1600 			'default_font_size' => 0,
1601 			'default_font' => '',
1602 			'margin_left' => 15,
1603 			'margin_right' => 15,
1604 			'margin_top' => 16,
1605 			'margin_bottom' => 16,
1606 			'margin_header' => 9,
1607 			'margin_footer' => 9,
1608 			'orientation' => 'P',
1609 		];
1610 
1611 		foreach ($constructor as $key => $val) {
1612 			if (isset($config[$key])) {
1613 				$constructor[$key] = $config[$key];
1614 			}
1615 		}
1616 
1617 		return array_values($constructor);
1618 	}
1619 
1620 	private function initFontConfig(array $config)
1621 	{
1622 		$configObject = new FontVariables();
1623 		$defaults = $configObject->getDefaults();
1624 		$config = array_intersect_key($config + $defaults, $defaults);
1625 		foreach ($config as $var => $val) {
1626 			$this->{$var} = $val;
1627 		}
1628 
1629 		return $config;
1630 	}
1631 
1632 	function _setPageSize($format, &$orientation)
1633 	{
1634 		if (is_string($format)) {
1635 
1636 			if (empty($format)) {
1637 				$format = 'A4';
1638 			}
1639 
1640 			// e.g. A4-L = A4 landscape, A4-P = A4 portrait
1641 			if (preg_match('/([0-9a-zA-Z]*)-([P,L])/i', $format, $m)) {
1642 				$format = $m[1];
1643 				$orientation = $m[2];
1644 			} elseif (empty($orientation)) {
1645 				$orientation = 'P';
1646 			}
1647 
1648 			$format = PageFormat::getSizeFromName($format);
1649 
1650 			$this->fwPt = $format[0];
1651 			$this->fhPt = $format[1];
1652 
1653 		} else {
1654 
1655 			if (!$format[0] || !$format[1]) {
1656 				throw new \Mpdf\MpdfException('Invalid page format: ' . $format[0] . ' ' . $format[1]);
1657 			}
1658 
1659 			$this->fwPt = $format[0] * Mpdf::SCALE;
1660 			$this->fhPt = $format[1] * Mpdf::SCALE;
1661 		}
1662 
1663 		$this->fw = $this->fwPt / Mpdf::SCALE;
1664 		$this->fh = $this->fhPt / Mpdf::SCALE;
1665 
1666 		// Page orientation
1667 		$orientation = strtolower($orientation);
1668 		if ($orientation === 'p' || $orientation == 'portrait') {
1669 			$orientation = 'P';
1670 			$this->wPt = $this->fwPt;
1671 			$this->hPt = $this->fhPt;
1672 		} elseif ($orientation === 'l' || $orientation == 'landscape') {
1673 			$orientation = 'L';
1674 			$this->wPt = $this->fhPt;
1675 			$this->hPt = $this->fwPt;
1676 		} else {
1677 			throw new \Mpdf\MpdfException('Incorrect orientation: ' . $orientation);
1678 		}
1679 
1680 		$this->CurOrientation = $orientation;
1681 
1682 		$this->w = $this->wPt / Mpdf::SCALE;
1683 		$this->h = $this->hPt / Mpdf::SCALE;
1684 	}
1685 
1686 	function RestrictUnicodeFonts($res)
1687 	{
1688 		// $res = array of (Unicode) fonts to restrict to: e.g. norasi|norasiB - language specific
1689 		if (count($res)) { // Leave full list of available fonts if passed blank array
1690 			$this->available_unifonts = $res;
1691 		} else {
1692 			$this->available_unifonts = $this->default_available_fonts;
1693 		}
1694 		if (count($this->available_unifonts) == 0) {
1695 			$this->available_unifonts[] = $this->default_available_fonts[0];
1696 		}
1697 		$this->available_unifonts = array_values($this->available_unifonts);
1698 	}
1699 
1700 	function setMBencoding($enc)
1701 	{
1702 		if ($this->mb_enc != $enc) {
1703 			$this->mb_enc = $enc;
1704 			mb_internal_encoding($this->mb_enc);
1705 		}
1706 	}
1707 
1708 	function SetMargins($left, $right, $top)
1709 	{
1710 		// Set left, top and right margins
1711 		$this->lMargin = $left;
1712 		$this->rMargin = $right;
1713 		$this->tMargin = $top;
1714 	}
1715 
1716 	function ResetMargins()
1717 	{
1718 		// ReSet left, top margins
1719 		if (($this->forcePortraitHeaders || $this->forcePortraitMargins) && $this->DefOrientation == 'P' && $this->CurOrientation == 'L') {
1720 			if (($this->mirrorMargins) && (($this->page) % 2 == 0)) { // EVEN
1721 				$this->tMargin = $this->orig_rMargin;
1722 				$this->bMargin = $this->orig_lMargin;
1723 			} else { // ODD	// OR NOT MIRRORING MARGINS/FOOTERS
1724 				$this->tMargin = $this->orig_lMargin;
1725 				$this->bMargin = $this->orig_rMargin;
1726 			}
1727 			$this->lMargin = $this->DeflMargin;
1728 			$this->rMargin = $this->DefrMargin;
1729 			$this->MarginCorrection = 0;
1730 			$this->PageBreakTrigger = $this->h - $this->bMargin;
1731 		} elseif (($this->mirrorMargins) && (($this->page) % 2 == 0)) { // EVEN
1732 			$this->lMargin = $this->DefrMargin;
1733 			$this->rMargin = $this->DeflMargin;
1734 			$this->MarginCorrection = $this->DefrMargin - $this->DeflMargin;
1735 		} else { // ODD	// OR NOT MIRRORING MARGINS/FOOTERS
1736 			$this->lMargin = $this->DeflMargin;
1737 			$this->rMargin = $this->DefrMargin;
1738 			if ($this->mirrorMargins) {
1739 				$this->MarginCorrection = $this->DeflMargin - $this->DefrMargin;
1740 			}
1741 		}
1742 		$this->x = $this->lMargin;
1743 	}
1744 
1745 	function SetLeftMargin($margin)
1746 	{
1747 		// Set left margin
1748 		$this->lMargin = $margin;
1749 		if ($this->page > 0 and $this->x < $margin) {
1750 			$this->x = $margin;
1751 		}
1752 	}
1753 
1754 	function SetTopMargin($margin)
1755 	{
1756 		// Set top margin
1757 		$this->tMargin = $margin;
1758 	}
1759 
1760 	function SetRightMargin($margin)
1761 	{
1762 		// Set right margin
1763 		$this->rMargin = $margin;
1764 	}
1765 
1766 	function SetAutoPageBreak($auto, $margin = 0)
1767 	{
1768 		// Set auto page break mode and triggering margin
1769 		$this->autoPageBreak = $auto;
1770 		$this->bMargin = $margin;
1771 		$this->PageBreakTrigger = $this->h - $margin;
1772 	}
1773 
1774 	function SetDisplayMode($zoom, $layout = 'continuous')
1775 	{
1776 		$allowedZoomModes = ['fullpage', 'fullwidth', 'real', 'default', 'none'];
1777 
1778 		if (in_array($zoom, $allowedZoomModes, true) || is_numeric($zoom)) {
1779 			$this->ZoomMode = $zoom;
1780 		} else {
1781 			throw new \Mpdf\MpdfException('Incorrect zoom display mode: ' . $zoom);
1782 		}
1783 
1784 		$allowedLayoutModes = ['single', 'continuous', 'two', 'twoleft', 'tworight', 'default'];
1785 
1786 		if (in_array($layout, $allowedLayoutModes, true)) {
1787 			$this->LayoutMode = $layout;
1788 		} else {
1789 			throw new \Mpdf\MpdfException('Incorrect layout display mode: ' . $layout);
1790 		}
1791 	}
1792 
1793 	function SetCompression($compress)
1794 	{
1795 		// Set page compression
1796 		if (function_exists('gzcompress')) {
1797 			$this->compress = $compress;
1798 		} else {
1799 			$this->compress = false;
1800 		}
1801 	}
1802 
1803 	function SetTitle($title)
1804 	{
1805 		// Title of document // Arrives as UTF-8
1806 		$this->title = $title;
1807 	}
1808 
1809 	function SetSubject($subject)
1810 	{
1811 		// Subject of document
1812 		$this->subject = $subject;
1813 	}
1814 
1815 	function SetAuthor($author)
1816 	{
1817 		// Author of document
1818 		$this->author = $author;
1819 	}
1820 
1821 	function SetKeywords($keywords)
1822 	{
1823 		// Keywords of document
1824 		$this->keywords = $keywords;
1825 	}
1826 
1827 	function SetCreator($creator)
1828 	{
1829 		// Creator of document
1830 		$this->creator = $creator;
1831 	}
1832 
1833 	function AddCustomProperty($key, $value)
1834 	{
1835 		$this->customProperties[$key] = $value;
1836 	}
1837 
1838 	/**
1839 	 * Set one or multiple associated file ("/AF" as required by PDF/A-3)
1840 	 *
1841 	 * param $files is an array of hash containing:
1842 	 *   path: file path on FS
1843 	 *   content: file content
1844 	 *   name: file name (not necessarily the same as the file on FS)
1845 	 *   mime (optional): file mime type (will show up as /Subtype in the PDF)
1846 	 *   description (optional): file description
1847 	 *   AFRelationship (optional): PDF/A-3 AFRelationship (e.g. "Alternative")
1848 	 *
1849 	 * e.g. to associate 1 file:
1850 	 *     [[
1851 	 *         'path' => 'tmp/1234.xml',
1852 	 *         'content' => 'file content',
1853 	 *         'name' => 'public_name.xml',
1854 	 *         'mime' => 'text/xml',
1855 	 *         'description' => 'foo',
1856 	 *         'AFRelationship' => 'Alternative',
1857 	 *     ]]
1858 	 *
1859 	 * @param mixed[] $files Array of arrays of associated files. See above
1860 	 */
1861 	function SetAssociatedFiles(array $files)
1862 	{
1863 		$this->associatedFiles = $files;
1864 	}
1865 
1866 	function SetAdditionalXmpRdf($s)
1867 	{
1868 		$this->additionalXmpRdf = $s;
1869 	}
1870 
1871 	function SetAnchor2Bookmark($x)
1872 	{
1873 		$this->anchor2Bookmark = $x;
1874 	}
1875 
1876 	public function AliasNbPages($alias = '{nb}')
1877 	{
1878 		// Define an alias for total number of pages
1879 		$this->aliasNbPg = $alias;
1880 	}
1881 
1882 	public function AliasNbPageGroups($alias = '{nbpg}')
1883 	{
1884 		// Define an alias for total number of pages in a group
1885 		$this->aliasNbPgGp = $alias;
1886 	}
1887 
1888 	function SetAlpha($alpha, $bm = 'Normal', $return = false, $mode = 'B')
1889 	{
1890 		// alpha: real value from 0 (transparent) to 1 (opaque)
1891 		// bm:    blend mode, one of the following:
1892 		//          Normal, Multiply, Screen, Overlay, Darken, Lighten, ColorDodge, ColorBurn,
1893 		//          HardLight, SoftLight, Difference, Exclusion, Hue, Saturation, Color, Luminosity
1894 		// set alpha for stroking (CA) and non-stroking (ca) operations
1895 		// mode determines F (fill) S (stroke) B (both)
1896 		if (($this->PDFA || $this->PDFX) && $alpha != 1) {
1897 			if (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto)) {
1898 				$this->PDFAXwarnings[] = "Image opacity must be 100% (Opacity changed to 100%)";
1899 			}
1900 			$alpha = 1;
1901 		}
1902 		$a = ['BM' => '/' . $bm];
1903 		if ($mode == 'F' || $mode == 'B') {
1904 			$a['ca'] = $alpha; // mPDF 5.7.2
1905 		}
1906 		if ($mode == 'S' || $mode == 'B') {
1907 			$a['CA'] = $alpha; // mPDF 5.7.2
1908 		}
1909 		$gs = $this->AddExtGState($a);
1910 		if ($return) {
1911 			return sprintf('/GS%d gs', $gs);
1912 		} else {
1913 			$this->writer->write(sprintf('/GS%d gs', $gs));
1914 		}
1915 	}
1916 
1917 	function AddExtGState($parms)
1918 	{
1919 		$n = count($this->extgstates);
1920 		// check if graphics state already exists
1921 		for ($i = 1; $i <= $n; $i++) {
1922 			if (count($this->extgstates[$i]['parms']) == count($parms)) {
1923 				$same = true;
1924 				foreach ($this->extgstates[$i]['parms'] as $k => $v) {
1925 					if (!isset($parms[$k]) || $parms[$k] != $v) {
1926 						$same = false;
1927 						break;
1928 					}
1929 				}
1930 				if ($same) {
1931 					return $i;
1932 				}
1933 			}
1934 		}
1935 		$n++;
1936 		$this->extgstates[$n]['parms'] = $parms;
1937 		return $n;
1938 	}
1939 
1940 	function SetVisibility($v)
1941 	{
1942 		if (($this->PDFA || $this->PDFX) && $this->visibility != 'visible') {
1943 			$this->PDFAXwarnings[] = "Cannot set visibility to anything other than full when using PDFA or PDFX";
1944 			return '';
1945 		} elseif (!$this->PDFA && !$this->PDFX) {
1946 			$this->pdf_version = '1.5';
1947 		}
1948 		if ($this->visibility != 'visible') {
1949 			$this->writer->write('EMC');
1950 			$this->hasOC = intval($this->hasOC);
1951 		}
1952 		if ($v == 'printonly') {
1953 			$this->writer->write('/OC /OC1 BDC');
1954 			$this->hasOC = ($this->hasOC | 1);
1955 		} elseif ($v == 'screenonly') {
1956 			$this->writer->write('/OC /OC2 BDC');
1957 			$this->hasOC = ($this->hasOC | 2);
1958 		} elseif ($v == 'hidden') {
1959 			$this->writer->write('/OC /OC3 BDC');
1960 			$this->hasOC = ($this->hasOC | 4);
1961 		} elseif ($v != 'visible') {
1962 			throw new \Mpdf\MpdfException('Incorrect visibility: ' . $v);
1963 		}
1964 		$this->visibility = $v;
1965 	}
1966 
1967 	function Open()
1968 	{
1969 		// Begin document
1970 		if ($this->state == 0) {
1971 			$this->state = 1;
1972 			if (false === $this->preambleWritten) {
1973 				$this->writer->write('%PDF-' . $this->pdf_version);
1974 				$this->writer->write('%' . chr(226) . chr(227) . chr(207) . chr(211)); // 4 chars > 128 to show binary file
1975 				$this->preambleWritten = true;
1976 			}
1977 		}
1978 	}
1979 
1980 	function Close()
1981 	{
1982 		// @log Closing last page
1983 
1984 		// Terminate document
1985 		if ($this->state == 3) {
1986 			return;
1987 		}
1988 
1989 		if ($this->page == 0) {
1990 			$this->AddPage($this->CurOrientation);
1991 		}
1992 
1993 		if (count($this->cellBorderBuffer)) {
1994 			$this->printcellbuffer();
1995 		}
1996 
1997 		// *TABLES*
1998 		if ($this->tablebuffer) {
1999 			$this->printtablebuffer();
2000 		}
2001 
2002 		/* -- COLUMNS -- */
2003 
2004 		if ($this->ColActive) {
2005 			$this->SetColumns(0);
2006 			$this->ColActive = 0;
2007 			if (count($this->columnbuffer)) {
2008 				$this->printcolumnbuffer();
2009 			}
2010 		}
2011 
2012 		/* -- END COLUMNS -- */
2013 
2014 		// BODY Backgrounds
2015 		$s = '';
2016 
2017 		$s .= $this->PrintBodyBackgrounds();
2018 		$s .= $this->PrintPageBackgrounds();
2019 
2020 		$this->pages[$this->page] = preg_replace(
2021 			'/(___BACKGROUND___PATTERNS' . $this->uniqstr . ')/',
2022 			"\n" . $s . "\n" . '\\1',
2023 			$this->pages[$this->page]
2024 		);
2025 
2026 		$this->pageBackgrounds = [];
2027 
2028 		if ($this->visibility != 'visible') {
2029 			$this->SetVisibility('visible');
2030 		}
2031 
2032 		$this->EndLayer();
2033 
2034 		if (!$this->tableOfContents->TOCmark) { // Page footer
2035 			$this->InFooter = true;
2036 			$this->Footer();
2037 			$this->InFooter = false;
2038 		}
2039 
2040 		if ($this->tableOfContents->TOCmark || count($this->tableOfContents->m_TOC)) {
2041 			$this->tableOfContents->insertTOC();
2042 		}
2043 
2044 		// Close page
2045 		$this->_endpage();
2046 
2047 		// Close document
2048 		$this->_enddoc();
2049 	}
2050 
2051 	/* -- BACKGROUNDS -- */
2052 
2053 	function _resizeBackgroundImage($imw, $imh, $cw, $ch, $resize, $repx, $repy, $pba = [], $size = [])
2054 	{
2055 		// pba is background positioning area (from CSS background-origin) may not always be set [x,y,w,h]
2056 		// size is from CSS3 background-size - takes precendence over old resize
2057 		// $w - absolute length or % or auto or cover | contain
2058 		// $h - absolute length or % or auto or cover | contain
2059 		if (isset($pba['w'])) {
2060 			$cw = $pba['w'];
2061 		}
2062 		if (isset($pba['h'])) {
2063 			$ch = $pba['h'];
2064 		}
2065 
2066 		$cw = $cw * Mpdf::SCALE;
2067 		$ch = $ch * Mpdf::SCALE;
2068 		if (empty($size) && !$resize) {
2069 			return [$imw, $imh, $repx, $repy];
2070 		}
2071 
2072 		if (isset($size['w']) && $size['w']) {
2073 			if ($size['w'] == 'contain') {
2074 				// Scale the image, while preserving its intrinsic aspect ratio (if any),
2075 				// to the largest size such that both its width and its height can fit inside the background positioning area.
2076 				// Same as resize==3
2077 				$h = $imh * $cw / $imw;
2078 				$w = $cw;
2079 				if ($h > $ch) {
2080 					$w = $w * $ch / $h;
2081 					$h = $ch;
2082 				}
2083 			} elseif ($size['w'] == 'cover') {
2084 				// Scale the image, while preserving its intrinsic aspect ratio (if any),
2085 				// to the smallest size such that both its width and its height can completely cover the background positioning area.
2086 				$h = $imh * $cw / $imw;
2087 				$w = $cw;
2088 				if ($h < $ch) {
2089 					$w = $w * $h / $ch;
2090 					$h = $ch;
2091 				}
2092 			} else {
2093 				if (stristr($size['w'], '%')) {
2094 					$size['w'] = (float) $size['w'];
2095 					$size['w'] /= 100;
2096 					$size['w'] = ($cw * $size['w']);
2097 				}
2098 				if (stristr($size['h'], '%')) {
2099 					$size['h'] = (float) $size['h'];
2100 					$size['h'] /= 100;
2101 					$size['h'] = ($ch * $size['h']);
2102 				}
2103 				if ($size['w'] == 'auto' && $size['h'] == 'auto') {
2104 					$w = $imw;
2105 					$h = $imh;
2106 				} elseif ($size['w'] == 'auto' && $size['h'] != 'auto') {
2107 					$w = $imw * $size['h'] / $imh;
2108 					$h = $size['h'];
2109 				} elseif ($size['w'] != 'auto' && $size['h'] == 'auto') {
2110 					$h = $imh * $size['w'] / $imw;
2111 					$w = $size['w'];
2112 				} else {
2113 					$w = $size['w'];
2114 					$h = $size['h'];
2115 				}
2116 			}
2117 			return [$w, $h, $repx, $repy];
2118 		} elseif ($resize == 1 && $imw > $cw) {
2119 			$h = $imh * $cw / $imw;
2120 			return [$cw, $h, $repx, $repy];
2121 		} elseif ($resize == 2 && $imh > $ch) {
2122 			$w = $imw * $ch / $imh;
2123 			return [$w, $ch, $repx, $repy];
2124 		} elseif ($resize == 3) {
2125 			$w = $imw;
2126 			$h = $imh;
2127 			if ($w > $cw) {
2128 				$h = $h * $cw / $w;
2129 				$w = $cw;
2130 			}
2131 			if ($h > $ch) {
2132 				$w = $w * $ch / $h;
2133 				$h = $ch;
2134 			}
2135 			return [$w, $h, $repx, $repy];
2136 		} elseif ($resize == 4) {
2137 			$h = $imh * $cw / $imw;
2138 			return [$cw, $h, $repx, $repy];
2139 		} elseif ($resize == 5) {
2140 			$w = $imw * $ch / $imh;
2141 			return [$w, $ch, $repx, $repy];
2142 		} elseif ($resize == 6) {
2143 			return [$cw, $ch, $repx, $repy];
2144 		}
2145 		return [$imw, $imh, $repx, $repy];
2146 	}
2147 
2148 	function SetBackground(&$properties, &$maxwidth)
2149 	{
2150 		if (isset($properties['BACKGROUND-ORIGIN']) && ($properties['BACKGROUND-ORIGIN'] == 'border-box' || $properties['BACKGROUND-ORIGIN'] == 'content-box')) {
2151 			$origin = $properties['BACKGROUND-ORIGIN'];
2152 		} else {
2153 			$origin = 'padding-box';
2154 		}
2155 
2156 		if (isset($properties['BACKGROUND-SIZE'])) {
2157 			if (stristr($properties['BACKGROUND-SIZE'], 'contain')) {
2158 				$bsw = $bsh = 'contain';
2159 			} elseif (stristr($properties['BACKGROUND-SIZE'], 'cover')) {
2160 				$bsw = $bsh = 'cover';
2161 			} else {
2162 				$bsw = $bsh = 'auto';
2163 				$sz = preg_split('/\s+/', trim($properties['BACKGROUND-SIZE']));
2164 				if (count($sz) == 2) {
2165 					$bsw = $sz[0];
2166 					$bsh = $sz[1];
2167 				} else {
2168 					$bsw = $sz[0];
2169 				}
2170 				if (!stristr($bsw, '%') && !stristr($bsw, 'auto')) {
2171 					$bsw = $this->sizeConverter->convert($bsw, $maxwidth, $this->FontSize);
2172 				}
2173 				if (!stristr($bsh, '%') && !stristr($bsh, 'auto')) {
2174 					$bsh = $this->sizeConverter->convert($bsh, $maxwidth, $this->FontSize);
2175 				}
2176 			}
2177 			$size = ['w' => $bsw, 'h' => $bsh];
2178 		} else {
2179 			$size = false;
2180 		} // mPDF 6
2181 		if (preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $properties['BACKGROUND-IMAGE'])) {
2182 			return ['gradient' => $properties['BACKGROUND-IMAGE'], 'origin' => $origin, 'size' => $size];
2183 		} else {
2184 			$file = $properties['BACKGROUND-IMAGE'];
2185 			$sizesarray = $this->Image($file, 0, 0, 0, 0, '', '', false, false, false, false, true);
2186 			if (isset($sizesarray['IMAGE_ID'])) {
2187 				$image_id = $sizesarray['IMAGE_ID'];
2188 				$orig_w = $sizesarray['WIDTH'] * Mpdf::SCALE;  // in user units i.e. mm
2189 				$orig_h = $sizesarray['HEIGHT'] * Mpdf::SCALE;  // (using $this->img_dpi)
2190 				if (isset($properties['BACKGROUND-IMAGE-RESOLUTION'])) {
2191 					if (preg_match('/from-image/i', $properties['BACKGROUND-IMAGE-RESOLUTION']) && isset($sizesarray['set-dpi']) && $sizesarray['set-dpi'] > 0) {
2192 						$orig_w *= $this->img_dpi / $sizesarray['set-dpi'];
2193 						$orig_h *= $this->img_dpi / $sizesarray['set-dpi'];
2194 					} elseif (preg_match('/(\d+)dpi/i', $properties['BACKGROUND-IMAGE-RESOLUTION'], $m)) {
2195 						$dpi = $m[1];
2196 						if ($dpi > 0) {
2197 							$orig_w *= $this->img_dpi / $dpi;
2198 							$orig_h *= $this->img_dpi / $dpi;
2199 						}
2200 					}
2201 				}
2202 				$x_repeat = true;
2203 				$y_repeat = true;
2204 				if (isset($properties['BACKGROUND-REPEAT'])) {
2205 					if ($properties['BACKGROUND-REPEAT'] == 'no-repeat' || $properties['BACKGROUND-REPEAT'] == 'repeat-x') {
2206 						$y_repeat = false;
2207 					}
2208 					if ($properties['BACKGROUND-REPEAT'] == 'no-repeat' || $properties['BACKGROUND-REPEAT'] == 'repeat-y') {
2209 						$x_repeat = false;
2210 					}
2211 				}
2212 				$x_pos = 0;
2213 				$y_pos = 0;
2214 				if (isset($properties['BACKGROUND-POSITION'])) {
2215 					$ppos = preg_split('/\s+/', $properties['BACKGROUND-POSITION']);
2216 					$x_pos = $ppos[0];
2217 					$y_pos = $ppos[1];
2218 					if (!stristr($x_pos, '%')) {
2219 						$x_pos = $this->sizeConverter->convert($x_pos, $maxwidth, $this->FontSize);
2220 					}
2221 					if (!stristr($y_pos, '%')) {
2222 						$y_pos = $this->sizeConverter->convert($y_pos, $maxwidth, $this->FontSize);
2223 					}
2224 				}
2225 				if (isset($properties['BACKGROUND-IMAGE-RESIZE'])) {
2226 					$resize = $properties['BACKGROUND-IMAGE-RESIZE'];
2227 				} else {
2228 					$resize = 0;
2229 				}
2230 				if (isset($properties['BACKGROUND-IMAGE-OPACITY'])) {
2231 					$opacity = $properties['BACKGROUND-IMAGE-OPACITY'];
2232 				} else {
2233 					$opacity = 1;
2234 				}
2235 				return ['image_id' => $image_id, 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $x_pos, 'y_pos' => $y_pos, 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat, 'resize' => $resize, 'opacity' => $opacity, 'itype' => $sizesarray['itype'], 'origin' => $origin, 'size' => $size];
2236 			}
2237 		}
2238 		return false;
2239 	}
2240 
2241 	/* -- END BACKGROUNDS -- */
2242 
2243 	function PrintBodyBackgrounds()
2244 	{
2245 		$s = '';
2246 		$clx = 0;
2247 		$cly = 0;
2248 		$clw = $this->w;
2249 		$clh = $this->h;
2250 		// If using bleed and trim margins in paged media
2251 		if ($this->pageDim[$this->page]['outer_width_LR'] || $this->pageDim[$this->page]['outer_width_TB']) {
2252 			$clx = $this->pageDim[$this->page]['outer_width_LR'] - $this->pageDim[$this->page]['bleedMargin'];
2253 			$cly = $this->pageDim[$this->page]['outer_width_TB'] - $this->pageDim[$this->page]['bleedMargin'];
2254 			$clw = $this->w - 2 * $clx;
2255 			$clh = $this->h - 2 * $cly;
2256 		}
2257 
2258 		if ($this->bodyBackgroundColor) {
2259 			$s .= 'q ' . $this->SetFColor($this->bodyBackgroundColor, true) . "\n";
2260 			if ($this->bodyBackgroundColor[0] == 5) { // RGBa
2261 				$s .= $this->SetAlpha(ord($this->bodyBackgroundColor[4]) / 100, 'Normal', true, 'F') . "\n";
2262 			} elseif ($this->bodyBackgroundColor[0] == 6) { // CMYKa
2263 				$s .= $this->SetAlpha(ord($this->bodyBackgroundColor[5]) / 100, 'Normal', true, 'F') . "\n";
2264 			}
2265 			$s .= sprintf('%.3F %.3F %.3F %.3F re f Q', ($clx * Mpdf::SCALE), ($cly * Mpdf::SCALE), $clw * Mpdf::SCALE, $clh * Mpdf::SCALE) . "\n";
2266 		}
2267 
2268 		/* -- BACKGROUNDS -- */
2269 		if ($this->bodyBackgroundGradient) {
2270 			$g = $this->gradient->parseBackgroundGradient($this->bodyBackgroundGradient);
2271 			if ($g) {
2272 				$s .= $this->gradient->Gradient($clx, $cly, $clw, $clh, (isset($g['gradtype']) ? $g['gradtype'] : null), $g['stops'], $g['colorspace'], $g['coords'], $g['extend'], true);
2273 			}
2274 		}
2275 		if ($this->bodyBackgroundImage) {
2276 			if (isset($this->bodyBackgroundImage['gradient']) && $this->bodyBackgroundImage['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $this->bodyBackgroundImage['gradient'])) {
2277 				$g = $this->gradient->parseMozGradient($this->bodyBackgroundImage['gradient']);
2278 				if ($g) {
2279 					$s .= $this->gradient->Gradient($clx, $cly, $clw, $clh, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend'], true);
2280 				}
2281 			} elseif ($this->bodyBackgroundImage['image_id']) { // Background pattern
2282 				$n = count($this->patterns) + 1;
2283 				// If using resize, uses TrimBox (not including the bleed)
2284 				list($orig_w, $orig_h, $x_repeat, $y_repeat) = $this->_resizeBackgroundImage($this->bodyBackgroundImage['orig_w'], $this->bodyBackgroundImage['orig_h'], $clw, $clh, $this->bodyBackgroundImage['resize'], $this->bodyBackgroundImage['x_repeat'], $this->bodyBackgroundImage['y_repeat']);
2285 
2286 				$this->patterns[$n] = ['x' => $clx, 'y' => $cly, 'w' => $clw, 'h' => $clh, 'pgh' => $this->h, 'image_id' => $this->bodyBackgroundImage['image_id'], 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $this->bodyBackgroundImage['x_pos'], 'y_pos' => $this->bodyBackgroundImage['y_pos'], 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat, 'itype' => $this->bodyBackgroundImage['itype']];
2287 				if (($this->bodyBackgroundImage['opacity'] > 0 || $this->bodyBackgroundImage['opacity'] === '0') && $this->bodyBackgroundImage['opacity'] < 1) {
2288 					$opac = $this->SetAlpha($this->bodyBackgroundImage['opacity'], 'Normal', true);
2289 				} else {
2290 					$opac = '';
2291 				}
2292 				$s .= sprintf('q /Pattern cs /P%d scn %s %.3F %.3F %.3F %.3F re f Q', $n, $opac, ($clx * Mpdf::SCALE), ($cly * Mpdf::SCALE), $clw * Mpdf::SCALE, $clh * Mpdf::SCALE) . "\n";
2293 			}
2294 		}
2295 		/* -- END BACKGROUNDS -- */
2296 		return $s;
2297 	}
2298 
2299 	function _setClippingPath($clx, $cly, $clw, $clh)
2300 	{
2301 		$s = ' q 0 w '; // Line width=0
2302 		$s .= sprintf('%.3F %.3F m ', ($clx) * Mpdf::SCALE, ($this->h - ($cly)) * Mpdf::SCALE); // start point TL before the arc
2303 		$s .= sprintf('%.3F %.3F l ', ($clx) * Mpdf::SCALE, ($this->h - ($cly + $clh)) * Mpdf::SCALE); // line to BL
2304 		$s .= sprintf('%.3F %.3F l ', ($clx + $clw) * Mpdf::SCALE, ($this->h - ($cly + $clh)) * Mpdf::SCALE); // line to BR
2305 		$s .= sprintf('%.3F %.3F l ', ($clx + $clw) * Mpdf::SCALE, ($this->h - ($cly)) * Mpdf::SCALE); // line to TR
2306 		$s .= sprintf('%.3F %.3F l ', ($clx) * Mpdf::SCALE, ($this->h - ($cly)) * Mpdf::SCALE); // line to TL
2307 		$s .= ' W n '; // Ends path no-op & Sets the clipping path
2308 		return $s;
2309 	}
2310 
2311 	function PrintPageBackgrounds($adjustmenty = 0)
2312 	{
2313 		$s = '';
2314 
2315 		ksort($this->pageBackgrounds);
2316 
2317 		foreach ($this->pageBackgrounds as $bl => $pbs) {
2318 
2319 			foreach ($pbs as $pb) {
2320 
2321 				if ((!isset($pb['image_id']) && !isset($pb['gradient'])) || isset($pb['shadowonly'])) { // Background colour or boxshadow
2322 
2323 					if ($pb['z-index'] > 0) {
2324 						$this->current_layer = $pb['z-index'];
2325 						$s .= "\n" . '/OCBZ-index /ZI' . $pb['z-index'] . ' BDC' . "\n";
2326 					}
2327 
2328 					if ($pb['visibility'] != 'visible') {
2329 						if ($pb['visibility'] == 'printonly') {
2330 							$s .= '/OC /OC1 BDC' . "\n";
2331 						} elseif ($pb['visibility'] == 'screenonly') {
2332 							$s .= '/OC /OC2 BDC' . "\n";
2333 						} elseif ($pb['visibility'] == 'hidden') {
2334 							$s .= '/OC /OC3 BDC' . "\n";
2335 						}
2336 					}
2337 
2338 					// Box shadow
2339 					if (isset($pb['shadow']) && $pb['shadow']) {
2340 						$s .= $pb['shadow'] . "\n";
2341 					}
2342 
2343 					if (isset($pb['clippath']) && $pb['clippath']) {
2344 						$s .= $pb['clippath'] . "\n";
2345 					}
2346 
2347 					$s .= 'q ' . $this->SetFColor($pb['col'], true) . "\n";
2348 
2349 					if ($pb['col'] && $pb['col'][0] === '5') { // RGBa
2350 						$s .= $this->SetAlpha(ord($pb['col'][4]) / 100, 'Normal', true, 'F') . "\n";
2351 					} elseif ($pb['col'] && $pb['col'][0] === '6') { // CMYKa
2352 						$s .= $this->SetAlpha(ord($pb['col'][5]) / 100, 'Normal', true, 'F') . "\n";
2353 					}
2354 
2355 					$s .= sprintf('%.3F %.3F %.3F %.3F re f Q', $pb['x'] * Mpdf::SCALE, ($this->h - $pb['y']) * Mpdf::SCALE, $pb['w'] * Mpdf::SCALE, -$pb['h'] * Mpdf::SCALE) . "\n";
2356 
2357 					if (isset($pb['clippath']) && $pb['clippath']) {
2358 						$s .= 'Q' . "\n";
2359 					}
2360 
2361 					if ($pb['visibility'] != 'visible') {
2362 						$s .= 'EMC' . "\n";
2363 					}
2364 
2365 					if ($pb['z-index'] > 0) {
2366 						$s .= "\n" . 'EMCBZ-index' . "\n";
2367 						$this->current_layer = 0;
2368 					}
2369 				}
2370 			}
2371 
2372 			/* -- BACKGROUNDS -- */
2373 			foreach ($pbs as $pb) {
2374 
2375 				if ((isset($pb['gradient']) && $pb['gradient']) || (isset($pb['image_id']) && $pb['image_id'])) {
2376 
2377 					if ($pb['z-index'] > 0) {
2378 						$this->current_layer = $pb['z-index'];
2379 						$s .= "\n" . '/OCGZ-index /ZI' . $pb['z-index'] . ' BDC' . "\n";
2380 					}
2381 
2382 					if ($pb['visibility'] != 'visible') {
2383 						if ($pb['visibility'] == 'printonly') {
2384 							$s .= '/OC /OC1 BDC' . "\n";
2385 						} elseif ($pb['visibility'] == 'screenonly') {
2386 							$s .= '/OC /OC2 BDC' . "\n";
2387 						} elseif ($pb['visibility'] == 'hidden') {
2388 							$s .= '/OC /OC3 BDC' . "\n";
2389 						}
2390 					}
2391 
2392 				}
2393 
2394 				if (isset($pb['gradient']) && $pb['gradient']) {
2395 
2396 					if (isset($pb['clippath']) && $pb['clippath']) {
2397 						$s .= $pb['clippath'] . "\n";
2398 					}
2399 
2400 					$s .= $this->gradient->Gradient($pb['x'], $pb['y'], $pb['w'], $pb['h'], $pb['gradtype'], $pb['stops'], $pb['colorspace'], $pb['coords'], $pb['extend'], true);
2401 
2402 					if (isset($pb['clippath']) && $pb['clippath']) {
2403 						$s .= 'Q' . "\n";
2404 					}
2405 
2406 				} elseif (isset($pb['image_id']) && $pb['image_id']) { // Background Image
2407 
2408 					$pb['y'] -= $adjustmenty;
2409 					$pb['h'] += $adjustmenty;
2410 					$n = count($this->patterns) + 1;
2411 
2412 					list($orig_w, $orig_h, $x_repeat, $y_repeat) = $this->_resizeBackgroundImage($pb['orig_w'], $pb['orig_h'], $pb['w'], $pb['h'], $pb['resize'], $pb['x_repeat'], $pb['y_repeat'], $pb['bpa'], $pb['size']);
2413 
2414 					$this->patterns[$n] = ['x' => $pb['x'], 'y' => $pb['y'], 'w' => $pb['w'], 'h' => $pb['h'], 'pgh' => $this->h, 'image_id' => $pb['image_id'], 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $pb['x_pos'], 'y_pos' => $pb['y_pos'], 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat, 'itype' => $pb['itype'], 'bpa' => $pb['bpa']];
2415 
2416 					$x = $pb['x'] * Mpdf::SCALE;
2417 					$y = ($this->h - $pb['y']) * Mpdf::SCALE;
2418 					$w = $pb['w'] * Mpdf::SCALE;
2419 					$h = -$pb['h'] * Mpdf::SCALE;
2420 
2421 					if (isset($pb['clippath']) && $pb['clippath']) {
2422 						$s .= $pb['clippath'] . "\n";
2423 					}
2424 
2425 					if ($this->writingHTMLfooter || $this->writingHTMLheader) { // Write each (tiles) image rather than use as a pattern
2426 
2427 						$iw = $pb['orig_w'] / Mpdf::SCALE;
2428 						$ih = $pb['orig_h'] / Mpdf::SCALE;
2429 
2430 						$w = $pb['w'];
2431 						$h = $pb['h'];
2432 						$x0 = $pb['x'];
2433 						$y0 = $pb['y'];
2434 
2435 						if (isset($pb['bpa']) && $pb['bpa']) {
2436 							$w = $pb['bpa']['w'];
2437 							$h = $pb['bpa']['h'];
2438 							$x0 = $pb['bpa']['x'];
2439 							$y0 = $pb['bpa']['y'];
2440 						}
2441 
2442 						if (isset($pb['size']['w']) && $pb['size']['w']) {
2443 							$size = $pb['size'];
2444 
2445 							if ($size['w'] == 'contain') {
2446 								// Scale the image, while preserving its intrinsic aspect ratio (if any), to the largest
2447 								// size such that both its width and its height can fit inside the background positioning area.
2448 								// Same as resize==3
2449 								$ih = $ih * $pb['bpa']['w'] / $iw;
2450 								$iw = $pb['bpa']['w'];
2451 								if ($ih > $pb['bpa']['h']) {
2452 									$iw = $iw * $pb['bpa']['h'] / $ih;
2453 									$ih = $pb['bpa']['h'];
2454 								}
2455 							} elseif ($size['w'] == 'cover') {
2456 								// Scale the image, while preserving its intrinsic aspect ratio (if any), to the smallest
2457 								// size such that both its width and its height can completely cover the background positioning area.
2458 								$ih = $ih * $pb['bpa']['w'] / $iw;
2459 								$iw = $pb['bpa']['w'];
2460 								if ($ih < $pb['bpa']['h']) {
2461 									$iw = $iw * $ih / $pb['bpa']['h'];
2462 									$ih = $pb['bpa']['h'];
2463 								}
2464 							} else {
2465 
2466 								if (NumericString::containsPercentChar($size['w'])) {
2467 									$size['w'] = NumericString::removePercentChar($size['w']);
2468 									$size['w'] /= 100;
2469 									$size['w'] = ($pb['bpa']['w'] * $size['w']);
2470 								}
2471 
2472 								if (NumericString::containsPercentChar($size['h'])) {
2473 									$size['h'] = NumericString::removePercentChar($size['h']);
2474 									$size['h'] /= 100;
2475 									$size['h'] = ($pb['bpa']['h'] * $size['h']);
2476 								}
2477 
2478 								if ($size['w'] == 'auto' && $size['h'] == 'auto') {
2479 									$iw = $iw;
2480 									$ih = $ih;
2481 								} elseif ($size['w'] == 'auto' && $size['h'] != 'auto') {
2482 									$iw = $iw * $size['h'] / $ih;
2483 									$ih = $size['h'];
2484 								} elseif ($size['w'] != 'auto' && $size['h'] == 'auto') {
2485 									$ih = $ih * $size['w'] / $iw;
2486 									$iw = $size['w'];
2487 								} else {
2488 									$iw = $size['w'];
2489 									$ih = $size['h'];
2490 								}
2491 							}
2492 						}
2493 
2494 						// Number to repeat
2495 						if ($pb['x_repeat']) {
2496 							$nx = ceil($pb['w'] / $iw) + 1;
2497 						} else {
2498 							$nx = 1;
2499 						}
2500 
2501 						if ($pb['y_repeat']) {
2502 							$ny = ceil($pb['h'] / $ih) + 1;
2503 						} else {
2504 							$ny = 1;
2505 						}
2506 
2507 						$x_pos = $pb['x_pos'];
2508 						if (stristr($x_pos, '%')) {
2509 							$x_pos = (float) $x_pos;
2510 							$x_pos /= 100;
2511 							$x_pos = ($pb['bpa']['w'] * $x_pos) - ($iw * $x_pos);
2512 						}
2513 
2514 						$y_pos = $pb['y_pos'];
2515 
2516 						if (stristr($y_pos, '%')) {
2517 							$y_pos = (float) $y_pos;
2518 							$y_pos /= 100;
2519 							$y_pos = ($pb['bpa']['h'] * $y_pos) - ($ih * $y_pos);
2520 						}
2521 
2522 						if ($nx > 1) {
2523 							while ($x_pos > ($pb['x'] - $pb['bpa']['x'])) {
2524 								$x_pos -= $iw;
2525 							}
2526 						}
2527 
2528 						if ($ny > 1) {
2529 							while ($y_pos > ($pb['y'] - $pb['bpa']['y'])) {
2530 								$y_pos -= $ih;
2531 							}
2532 						}
2533 
2534 						for ($xi = 0; $xi < $nx; $xi++) {
2535 							for ($yi = 0; $yi < $ny; $yi++) {
2536 								$x = $x0 + $x_pos + ($iw * $xi);
2537 								$y = $y0 + $y_pos + ($ih * $yi);
2538 								if ($pb['opacity'] > 0 && $pb['opacity'] < 1) {
2539 									$opac = $this->SetAlpha($pb['opacity'], 'Normal', true);
2540 								} else {
2541 									$opac = '';
2542 								}
2543 								$s .= sprintf("q %s %.3F 0 0 %.3F %.3F %.3F cm /I%d Do Q", $opac, $iw * Mpdf::SCALE, $ih * Mpdf::SCALE, $x * Mpdf::SCALE, ($this->h - ($y + $ih)) * Mpdf::SCALE, $pb['image_id']) . "\n";
2544 							}
2545 						}
2546 
2547 					} else {
2548 						if (($pb['opacity'] > 0 || $pb['opacity'] === '0') && $pb['opacity'] < 1) {
2549 							$opac = $this->SetAlpha($pb['opacity'], 'Normal', true);
2550 						} else {
2551 							$opac = '';
2552 						}
2553 						$s .= sprintf('q /Pattern cs /P%d scn %s %.3F %.3F %.3F %.3F re f Q', $n, $opac, $x, $y, $w, $h) . "\n";
2554 					}
2555 
2556 					if (isset($pb['clippath']) && $pb['clippath']) {
2557 						$s .= 'Q' . "\n";
2558 					}
2559 				}
2560 
2561 				if ((isset($pb['gradient']) && $pb['gradient']) || (isset($pb['image_id']) && $pb['image_id'])) {
2562 					if ($pb['visibility'] != 'visible') {
2563 						$s .= 'EMC' . "\n";
2564 					}
2565 
2566 					if ($pb['z-index'] > 0) {
2567 						$s .= "\n" . 'EMCGZ-index' . "\n";
2568 						$this->current_layer = 0;
2569 					}
2570 				}
2571 			}
2572 			/* -- END BACKGROUNDS -- */
2573 		}
2574 
2575 		return $s;
2576 	}
2577 
2578 	function PrintTableBackgrounds($adjustmenty = 0)
2579 	{
2580 		$s = '';
2581 		/* -- BACKGROUNDS -- */
2582 		ksort($this->tableBackgrounds);
2583 		foreach ($this->tableBackgrounds as $bl => $pbs) {
2584 			foreach ($pbs as $pb) {
2585 				if ((!isset($pb['gradient']) || !$pb['gradient']) && (!isset($pb['image_id']) || !$pb['image_id'])) {
2586 					$s .= 'q ' . $this->SetFColor($pb['col'], true) . "\n";
2587 					if ($pb['col'][0] == 5) { // RGBa
2588 						$s .= $this->SetAlpha(ord($pb['col'][4]) / 100, 'Normal', true, 'F') . "\n";
2589 					} elseif ($pb['col'][0] == 6) { // CMYKa
2590 						$s .= $this->SetAlpha(ord($pb['col'][5]) / 100, 'Normal', true, 'F') . "\n";
2591 					}
2592 					$s .= sprintf('%.3F %.3F %.3F %.3F re %s Q', $pb['x'] * Mpdf::SCALE, ($this->h - $pb['y']) * Mpdf::SCALE, $pb['w'] * Mpdf::SCALE, -$pb['h'] * Mpdf::SCALE, 'f') . "\n";
2593 				}
2594 				if (isset($pb['gradient']) && $pb['gradient']) {
2595 					if (isset($pb['clippath']) && $pb['clippath']) {
2596 						$s .= $pb['clippath'] . "\n";
2597 					}
2598 					$s .= $this->gradient->Gradient($pb['x'], $pb['y'], $pb['w'], $pb['h'], $pb['gradtype'], $pb['stops'], $pb['colorspace'], $pb['coords'], $pb['extend'], true);
2599 					if (isset($pb['clippath']) && $pb['clippath']) {
2600 						$s .= 'Q' . "\n";
2601 					}
2602 				}
2603 				if (isset($pb['image_id']) && $pb['image_id']) { // Background pattern
2604 					$pb['y'] -= $adjustmenty;
2605 					$pb['h'] += $adjustmenty;
2606 					$n = count($this->patterns) + 1;
2607 					list($orig_w, $orig_h, $x_repeat, $y_repeat) = $this->_resizeBackgroundImage($pb['orig_w'], $pb['orig_h'], $pb['w'], $pb['h'], $pb['resize'], $pb['x_repeat'], $pb['y_repeat']);
2608 					$this->patterns[$n] = ['x' => $pb['x'], 'y' => $pb['y'], 'w' => $pb['w'], 'h' => $pb['h'], 'pgh' => $this->h, 'image_id' => $pb['image_id'], 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $pb['x_pos'], 'y_pos' => $pb['y_pos'], 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat, 'itype' => $pb['itype']];
2609 					$x = $pb['x'] * Mpdf::SCALE;
2610 					$y = ($this->h - $pb['y']) * Mpdf::SCALE;
2611 					$w = $pb['w'] * Mpdf::SCALE;
2612 					$h = -$pb['h'] * Mpdf::SCALE;
2613 
2614 					// mPDF 5.7.3
2615 					if (($this->writingHTMLfooter || $this->writingHTMLheader) && (!isset($pb['clippath']) || $pb['clippath'] == '')) {
2616 						// Set clipping path
2617 						$pb['clippath'] = sprintf(' q 0 w %.3F %.3F m %.3F %.3F l %.3F %.3F l %.3F %.3F l %.3F %.3F l W n ', $x, $y, $x, $y + $h, $x + $w, $y + $h, $x + $w, $y, $x, $y);
2618 					}
2619 
2620 					if (isset($pb['clippath']) && $pb['clippath']) {
2621 						$s .= $pb['clippath'] . "\n";
2622 					}
2623 
2624 					// mPDF 5.7.3
2625 					if ($this->writingHTMLfooter || $this->writingHTMLheader) { // Write each (tiles) image rather than use as a pattern
2626 						$iw = $pb['orig_w'] / Mpdf::SCALE;
2627 						$ih = $pb['orig_h'] / Mpdf::SCALE;
2628 
2629 						$w = $pb['w'];
2630 						$h = $pb['h'];
2631 						$x0 = $pb['x'];
2632 						$y0 = $pb['y'];
2633 
2634 						if (isset($pb['bpa']) && $pb['bpa']) {
2635 							$w = $pb['bpa']['w'];
2636 							$h = $pb['bpa']['h'];
2637 							$x0 = $pb['bpa']['x'];
2638 							$y0 = $pb['bpa']['y'];
2639 						} // At present 'bpa' (background page area) is not set for tablebackgrounds - only pagebackgrounds
2640 						// For now, just set it as:
2641 						else {
2642 							$pb['bpa'] = ['x' => $x0, 'y' => $y0, 'w' => $w, 'h' => $h];
2643 						}
2644 
2645 						if (isset($pb['size']['w']) && $pb['size']['w']) {
2646 							$size = $pb['size'];
2647 
2648 							if ($size['w'] == 'contain') {
2649 								// Scale the image, while preserving its intrinsic aspect ratio (if any), to the largest size such that both its width and its height can fit inside the background positioning area.
2650 								// Same as resize==3
2651 								$ih = $ih * $pb['bpa']['w'] / $iw;
2652 								$iw = $pb['bpa']['w'];
2653 								if ($ih > $pb['bpa']['h']) {
2654 									$iw = $iw * $pb['bpa']['h'] / $ih;
2655 									$ih = $pb['bpa']['h'];
2656 								}
2657 							} elseif ($size['w'] == 'cover') {
2658 								// Scale the image, while preserving its intrinsic aspect ratio (if any), to the smallest size such that both its width and its height can completely cover the background positioning area.
2659 								$ih = $ih * $pb['bpa']['w'] / $iw;
2660 								$iw = $pb['bpa']['w'];
2661 								if ($ih < $pb['bpa']['h']) {
2662 									$iw = $iw * $ih / $pb['bpa']['h'];
2663 									$ih = $pb['bpa']['h'];
2664 								}
2665 							} else {
2666 								if (NumericString::containsPercentChar($size['w'])) {
2667 									$size['w'] = NumericString::removePercentChar($size['w']);
2668 									$size['w'] /= 100;
2669 									$size['w'] = ($pb['bpa']['w'] * $size['w']);
2670 								}
2671 								if (NumericString::containsPercentChar($size['h'])) {
2672 									$size['h'] = NumericString::removePercentChar($size['h']);
2673 									$size['h'] /= 100;
2674 									$size['h'] = ($pb['bpa']['h'] * $size['h']);
2675 								}
2676 								if ($size['w'] == 'auto' && $size['h'] == 'auto') {
2677 									$iw = $iw;
2678 									$ih = $ih;
2679 								} elseif ($size['w'] == 'auto' && $size['h'] != 'auto') {
2680 									$iw = $iw * $size['h'] / $ih;
2681 									$ih = $size['h'];
2682 								} elseif ($size['w'] != 'auto' && $size['h'] == 'auto') {
2683 									$ih = $ih * $size['w'] / $iw;
2684 									$iw = $size['w'];
2685 								} else {
2686 									$iw = $size['w'];
2687 									$ih = $size['h'];
2688 								}
2689 							}
2690 						}
2691 
2692 						// Number to repeat
2693 						if (isset($pb['x_repeat']) && $pb['x_repeat']) {
2694 							$nx = ceil($pb['w'] / $iw) + 1;
2695 						} else {
2696 							$nx = 1;
2697 						}
2698 						if (isset($pb['y_repeat']) && $pb['y_repeat']) {
2699 							$ny = ceil($pb['h'] / $ih) + 1;
2700 						} else {
2701 							$ny = 1;
2702 						}
2703 
2704 						$x_pos = $pb['x_pos'];
2705 						if (NumericString::containsPercentChar($x_pos)) {
2706 							$x_pos = NumericString::removePercentChar($x_pos);
2707 							$x_pos /= 100;
2708 							$x_pos = ($pb['bpa']['w'] * $x_pos) - ($iw * $x_pos);
2709 						}
2710 						$y_pos = $pb['y_pos'];
2711 						if (NumericString::containsPercentChar($y_pos)) {
2712 							$y_pos = NumericString::removePercentChar($y_pos);
2713 							$y_pos /= 100;
2714 							$y_pos = ($pb['bpa']['h'] * $y_pos) - ($ih * $y_pos);
2715 						}
2716 						if ($nx > 1) {
2717 							while ($x_pos > ($pb['x'] - $pb['bpa']['x'])) {
2718 								$x_pos -= $iw;
2719 							}
2720 						}
2721 						if ($ny > 1) {
2722 							while ($y_pos > ($pb['y'] - $pb['bpa']['y'])) {
2723 								$y_pos -= $ih;
2724 							}
2725 						}
2726 						for ($xi = 0; $xi < $nx; $xi++) {
2727 							for ($yi = 0; $yi < $ny; $yi++) {
2728 								$x = $x0 + $x_pos + ($iw * $xi);
2729 								$y = $y0 + $y_pos + ($ih * $yi);
2730 								if ($pb['opacity'] > 0 && $pb['opacity'] < 1) {
2731 									$opac = $this->SetAlpha($pb['opacity'], 'Normal', true);
2732 								} else {
2733 									$opac = '';
2734 								}
2735 								$s .= sprintf("q %s %.3F 0 0 %.3F %.3F %.3F cm /I%d Do Q", $opac, $iw * Mpdf::SCALE, $ih * Mpdf::SCALE, $x * Mpdf::SCALE, ($this->h - ($y + $ih)) * Mpdf::SCALE, $pb['image_id']) . "\n";
2736 							}
2737 						}
2738 					} else {
2739 						if (($pb['opacity'] > 0 || $pb['opacity'] === '0') && $pb['opacity'] < 1) {
2740 							$opac = $this->SetAlpha($pb['opacity'], 'Normal', true);
2741 						} else {
2742 							$opac = '';
2743 						}
2744 						$s .= sprintf('q /Pattern cs /P%d scn %s %.3F %.3F %.3F %.3F re f Q', $n, $opac, $x, $y, $w, $h) . "\n";
2745 					}
2746 
2747 					if (isset($pb['clippath']) && $pb['clippath']) {
2748 						$s .= 'Q' . "\n";
2749 					}
2750 				}
2751 			}
2752 		}
2753 		/* -- END BACKGROUNDS -- */
2754 		return $s;
2755 	}
2756 
2757 	function BeginLayer($id)
2758 	{
2759 		if ($this->current_layer > 0) {
2760 			$this->EndLayer();
2761 		}
2762 		if ($id < 1) {
2763 			return false;
2764 		}
2765 		if (!isset($this->layers[$id])) {
2766 			$this->layers[$id] = ['name' => 'Layer ' . ($id)];
2767 			if (($this->PDFA || $this->PDFX)) {
2768 				$this->PDFAXwarnings[] = "Cannot use layers when using PDFA or PDFX";
2769 				return '';
2770 			} elseif (!$this->PDFA && !$this->PDFX) {
2771 				$this->pdf_version = '1.5';
2772 			}
2773 		}
2774 		$this->current_layer = $id;
2775 		$this->writer->write('/OCZ-index /ZI' . $id . ' BDC');
2776 
2777 		$this->pageoutput[$this->page] = [];
2778 	}
2779 
2780 	function EndLayer()
2781 	{
2782 		if ($this->current_layer > 0) {
2783 			$this->writer->write('EMCZ-index');
2784 			$this->current_layer = 0;
2785 		}
2786 	}
2787 
2788 	function AddPageByArray($a)
2789 	{
2790 		if (!is_array($a)) {
2791 			$a = [];
2792 		}
2793 
2794 		$orientation = (isset($a['orientation']) ? $a['orientation'] : '');
2795 		$condition = (isset($a['condition']) ? $a['condition'] : (isset($a['type']) ? $a['type'] : ''));
2796 		$resetpagenum = (isset($a['resetpagenum']) ? $a['resetpagenum'] : '');
2797 		$pagenumstyle = (isset($a['pagenumstyle']) ? $a['pagenumstyle'] : '');
2798 		$suppress = (isset($a['suppress']) ? $a['suppress'] : '');
2799 		$mgl = (isset($a['mgl']) ? $a['mgl'] : (isset($a['margin-left']) ? $a['margin-left'] : ''));
2800 		$mgr = (isset($a['mgr']) ? $a['mgr'] : (isset($a['margin-right']) ? $a['margin-right'] : ''));
2801 		$mgt = (isset($a['mgt']) ? $a['mgt'] : (isset($a['margin-top']) ? $a['margin-top'] : ''));
2802 		$mgb = (isset($a['mgb']) ? $a['mgb'] : (isset($a['margin-bottom']) ? $a['margin-bottom'] : ''));
2803 		$mgh = (isset($a['mgh']) ? $a['mgh'] : (isset($a['margin-header']) ? $a['margin-header'] : ''));
2804 		$mgf = (isset($a['mgf']) ? $a['mgf'] : (isset($a['margin-footer']) ? $a['margin-footer'] : ''));
2805 		$ohname = (isset($a['ohname']) ? $a['ohname'] : (isset($a['odd-header-name']) ? $a['odd-header-name'] : ''));
2806 		$ehname = (isset($a['ehname']) ? $a['ehname'] : (isset($a['even-header-name']) ? $a['even-header-name'] : ''));
2807 		$ofname = (isset($a['ofname']) ? $a['ofname'] : (isset($a['odd-footer-name']) ? $a['odd-footer-name'] : ''));
2808 		$efname = (isset($a['efname']) ? $a['efname'] : (isset($a['even-footer-name']) ? $a['even-footer-name'] : ''));
2809 		$ohvalue = (isset($a['ohvalue']) ? $a['ohvalue'] : (isset($a['odd-header-value']) ? $a['odd-header-value'] : 0));
2810 		$ehvalue = (isset($a['ehvalue']) ? $a['ehvalue'] : (isset($a['even-header-value']) ? $a['even-header-value'] : 0));
2811 		$ofvalue = (isset($a['ofvalue']) ? $a['ofvalue'] : (isset($a['odd-footer-value']) ? $a['odd-footer-value'] : 0));
2812 		$efvalue = (isset($a['efvalue']) ? $a['efvalue'] : (isset($a['even-footer-value']) ? $a['even-footer-value'] : 0));
2813 		$pagesel = (isset($a['pagesel']) ? $a['pagesel'] : (isset($a['pageselector']) ? $a['pageselector'] : ''));
2814 		$newformat = (isset($a['newformat']) ? $a['newformat'] : (isset($a['sheet-size']) ? $a['sheet-size'] : ''));
2815 
2816 		$this->AddPage($orientation, $condition, $resetpagenum, $pagenumstyle, $suppress, $mgl, $mgr, $mgt, $mgb, $mgh, $mgf, $ohname, $ehname, $ofname, $efname, $ohvalue, $ehvalue, $ofvalue, $efvalue, $pagesel, $newformat);
2817 	}
2818 
2819 	// mPDF 6 pagebreaktype
2820 	function _preForcedPagebreak($pagebreaktype)
2821 	{
2822 		if ($pagebreaktype == 'cloneall') {
2823 			// Close any open block tags
2824 			$arr = [];
2825 			$ai = 0;
2826 			for ($b = $this->blklvl; $b > 0; $b--) {
2827 				$this->tag->CloseTag($this->blk[$b]['tag'], $arr, $ai);
2828 			}
2829 			if ($this->blklvl == 0 && !empty($this->textbuffer)) { // Output previously buffered content
2830 				$this->printbuffer($this->textbuffer, 1);
2831 				$this->textbuffer = [];
2832 			}
2833 		} elseif ($pagebreaktype == 'clonebycss') {
2834 			// Close open block tags whilst box-decoration-break==clone
2835 			$arr = [];
2836 			$ai = 0;
2837 			for ($b = $this->blklvl; $b > 0; $b--) {
2838 				if (isset($this->blk[$b]['box_decoration_break']) && $this->blk[$b]['box_decoration_break'] == 'clone') {
2839 					$this->tag->CloseTag($this->blk[$b]['tag'], $arr, $ai);
2840 				} else {
2841 					if ($b == $this->blklvl && !empty($this->textbuffer)) { // Output previously buffered content
2842 						$this->printbuffer($this->textbuffer, 1);
2843 						$this->textbuffer = [];
2844 					}
2845 					break;
2846 				}
2847 			}
2848 		} elseif (!empty($this->textbuffer)) { // Output previously buffered content
2849 			$this->printbuffer($this->textbuffer, 1);
2850 			$this->textbuffer = [];
2851 		}
2852 	}
2853 
2854 	// mPDF 6 pagebreaktype
2855 	function _postForcedPagebreak($pagebreaktype, $startpage, $save_blk, $save_blklvl)
2856 	{
2857 		if ($pagebreaktype == 'cloneall') {
2858 			$this->blk = [];
2859 			$this->blk[0] = $save_blk[0];
2860 			// Re-open block tags
2861 			$this->blklvl = 0;
2862 			$arr = [];
2863 			$i = 0;
2864 			for ($b = 1; $b <= $save_blklvl; $b++) {
2865 				$this->tag->OpenTag($save_blk[$b]['tag'], $save_blk[$b]['attr'], $arr, $i);
2866 			}
2867 		} elseif ($pagebreaktype == 'clonebycss') {
2868 			$this->blk = [];
2869 			$this->blk[0] = $save_blk[0];
2870 			// Don't re-open tags for lowest level elements - so need to do some adjustments
2871 			for ($b = 1; $b <= $this->blklvl; $b++) {
2872 				$this->blk[$b] = $save_blk[$b];
2873 				$this->blk[$b]['startpage'] = 0;
2874 				$this->blk[$b]['y0'] = $this->y; // ?? $this->tMargin
2875 				if (($this->page - $startpage) % 2) {
2876 					if (isset($this->blk[$b]['x0'])) {
2877 						$this->blk[$b]['x0'] += $this->MarginCorrection;
2878 					} else {
2879 						$this->blk[$b]['x0'] = $this->MarginCorrection;
2880 					}
2881 				}
2882 				// for Float DIV
2883 				$this->blk[$b]['marginCorrected'][$this->page] = true;
2884 			}
2885 
2886 			// Re-open block tags for any that have box_decoration_break==clone
2887 			$arr = [];
2888 			$i = 0;
2889 			for ($b = $this->blklvl + 1; $b <= $save_blklvl; $b++) {
2890 				if ($b < $this->blklvl) {
2891 					$this->lastblocklevelchange = -1;
2892 				}
2893 				$this->tag->OpenTag($save_blk[$b]['tag'], $save_blk[$b]['attr'], $arr, $i);
2894 			}
2895 			if ($this->blk[$this->blklvl]['box_decoration_break'] != 'clone') {
2896 				$this->lastblocklevelchange = -1;
2897 			}
2898 		} else {
2899 			$this->lastblocklevelchange = -1;
2900 		}
2901 	}
2902 
2903 	function AddPage(
2904 		$orientation = '',
2905 		$condition = '',
2906 		$resetpagenum = '',
2907 		$pagenumstyle = '',
2908 		$suppress = '',
2909 		$mgl = '',
2910 		$mgr = '',
2911 		$mgt = '',
2912 		$mgb = '',
2913 		$mgh = '',
2914 		$mgf = '',
2915 		$ohname = '',
2916 		$ehname = '',
2917 		$ofname = '',
2918 		$efname = '',
2919 		$ohvalue = 0,
2920 		$ehvalue = 0,
2921 		$ofvalue = 0,
2922 		$efvalue = 0,
2923 		$pagesel = '',
2924 		$newformat = ''
2925 	) {
2926 		/* -- CSS-FLOAT -- */
2927 		// Float DIV
2928 		// Cannot do with columns on, or if any change in page orientation/margins etc.
2929 		// If next page already exists - i.e background /headers and footers already written
2930 		if ($this->state > 0 && $this->page < count($this->pages)) {
2931 			$bak_cml = $this->cMarginL;
2932 			$bak_cmr = $this->cMarginR;
2933 			$bak_dw = $this->divwidth;
2934 			// Paint Div Border if necessary
2935 			if ($this->blklvl > 0) {
2936 				$save_tr = $this->table_rotate; // *TABLES*
2937 				$this->table_rotate = 0; // *TABLES*
2938 				if (isset($this->blk[$this->blklvl]['y0']) && $this->y == $this->blk[$this->blklvl]['y0']) {
2939 					$this->blk[$this->blklvl]['startpage'] ++;
2940 				}
2941 				if ((isset($this->blk[$this->blklvl]['y0']) && $this->y > $this->blk[$this->blklvl]['y0']) || $this->flowingBlockAttr['is_table']) {
2942 					$toplvl = $this->blklvl;
2943 				} else {
2944 					$toplvl = $this->blklvl - 1;
2945 				}
2946 				$sy = $this->y;
2947 				for ($bl = 1; $bl <= $toplvl; $bl++) {
2948 					$this->PaintDivBB('pagebottom', 0, $bl);
2949 				}
2950 				$this->y = $sy;
2951 				$this->table_rotate = $save_tr; // *TABLES*
2952 			}
2953 			$s = $this->PrintPageBackgrounds();
2954 
2955 			// Writes after the marker so not overwritten later by page background etc.
2956 			$this->pages[$this->page] = preg_replace(
2957 				'/(___BACKGROUND___PATTERNS' . $this->uniqstr . ')/',
2958 				'\\1' . "\n" . $s . "\n",
2959 				$this->pages[$this->page]
2960 			);
2961 
2962 			$this->pageBackgrounds = [];
2963 			$family = $this->FontFamily;
2964 			$style = $this->FontStyle;
2965 			$size = $this->FontSizePt;
2966 			$lw = $this->LineWidth;
2967 			$dc = $this->DrawColor;
2968 			$fc = $this->FillColor;
2969 			$tc = $this->TextColor;
2970 			$cf = $this->ColorFlag;
2971 
2972 			$this->printfloatbuffer();
2973 
2974 			// Move to next page
2975 			$this->page++;
2976 
2977 			$this->ResetMargins();
2978 			$this->SetAutoPageBreak($this->autoPageBreak, $this->bMargin);
2979 			$this->x = $this->lMargin;
2980 			$this->y = $this->tMargin;
2981 			$this->FontFamily = '';
2982 			$this->writer->write('2 J');
2983 			$this->LineWidth = $lw;
2984 			$this->writer->write(sprintf('%.3F w', $lw * Mpdf::SCALE));
2985 
2986 			if ($family) {
2987 				$this->SetFont($family, $style, $size, true, true);
2988 			}
2989 
2990 			$this->DrawColor = $dc;
2991 
2992 			if ($dc != $this->defDrawColor) {
2993 				$this->writer->write($dc);
2994 			}
2995 
2996 			$this->FillColor = $fc;
2997 
2998 			if ($fc != $this->defFillColor) {
2999 				$this->writer->write($fc);
3000 			}
3001 
3002 			$this->TextColor = $tc;
3003 			$this->ColorFlag = $cf;
3004 
3005 			for ($bl = 1; $bl <= $this->blklvl; $bl++) {
3006 				$this->blk[$bl]['y0'] = $this->y;
3007 				// Don't correct more than once for background DIV containing a Float
3008 				if (!isset($this->blk[$bl]['marginCorrected'][$this->page])) {
3009 					if (isset($this->blk[$bl]['x0'])) {
3010 						$this->blk[$bl]['x0'] += $this->MarginCorrection;
3011 					} else {
3012 						$this->blk[$bl]['x0'] = $this->MarginCorrection;
3013 					}
3014 				}
3015 				$this->blk[$bl]['marginCorrected'][$this->page] = true;
3016 			}
3017 
3018 			$this->cMarginL = $bak_cml;
3019 			$this->cMarginR = $bak_cmr;
3020 			$this->divwidth = $bak_dw;
3021 
3022 			return '';
3023 		}
3024 		/* -- END CSS-FLOAT -- */
3025 
3026 		// Start a new page
3027 		if ($this->state == 0) {
3028 			$this->Open();
3029 		}
3030 
3031 		$bak_cml = $this->cMarginL;
3032 		$bak_cmr = $this->cMarginR;
3033 		$bak_dw = $this->divwidth;
3034 
3035 		$bak_lh = $this->lineheight;
3036 
3037 		$orientation = substr(strtoupper($orientation), 0, 1);
3038 		$condition = strtoupper($condition);
3039 
3040 
3041 		if ($condition == 'E') { // only adds new page if needed to create an Even page
3042 			if (!$this->mirrorMargins || ($this->page) % 2 == 0) {
3043 				return false;
3044 			}
3045 		} elseif ($condition == 'O') { // only adds new page if needed to create an Odd page
3046 			if (!$this->mirrorMargins || ($this->page) % 2 == 1) {
3047 				return false;
3048 			}
3049 		} elseif ($condition == 'NEXT-EVEN') { // always adds at least one new page to create an Even page
3050 			if (!$this->mirrorMargins) {
3051 				$condition = '';
3052 			} else {
3053 				if ($pagesel) {
3054 					$pbch = $pagesel;
3055 					$pagesel = '';
3056 				} // *CSS-PAGE*
3057 				else {
3058 					$pbch = false;
3059 				} // *CSS-PAGE*
3060 				$this->AddPage($this->CurOrientation, 'O');
3061 				$this->extrapagebreak = true; // mPDF 6 pagebreaktype
3062 				if ($pbch) {
3063 					$pagesel = $pbch;
3064 				} // *CSS-PAGE*
3065 				$condition = '';
3066 			}
3067 		} elseif ($condition == 'NEXT-ODD') { // always adds at least one new page to create an Odd page
3068 			if (!$this->mirrorMargins) {
3069 				$condition = '';
3070 			} else {
3071 				if ($pagesel) {
3072 					$pbch = $pagesel;
3073 					$pagesel = '';
3074 				} // *CSS-PAGE*
3075 				else {
3076 					$pbch = false;
3077 				} // *CSS-PAGE*
3078 				$this->AddPage($this->CurOrientation, 'E');
3079 				$this->extrapagebreak = true; // mPDF 6 pagebreaktype
3080 				if ($pbch) {
3081 					$pagesel = $pbch;
3082 				} // *CSS-PAGE*
3083 				$condition = '';
3084 			}
3085 		}
3086 
3087 		if ($resetpagenum || $pagenumstyle || $suppress) {
3088 			$this->PageNumSubstitutions[] = ['from' => ($this->page + 1), 'reset' => $resetpagenum, 'type' => $pagenumstyle, 'suppress' => $suppress];
3089 		}
3090 
3091 		$save_tr = $this->table_rotate; // *TABLES*
3092 		$this->table_rotate = 0; // *TABLES*
3093 		$save_kwt = $this->kwt;
3094 		$this->kwt = 0;
3095 		$save_layer = $this->current_layer;
3096 		$save_vis = $this->visibility;
3097 
3098 		if ($this->visibility != 'visible') {
3099 			$this->SetVisibility('visible');
3100 		}
3101 
3102 		$this->EndLayer();
3103 
3104 		// Paint Div Border if necessary
3105 		// PAINTS BACKGROUND COLOUR OR BORDERS for DIV - DISABLED FOR COLUMNS (cf. AcceptPageBreak) AT PRESENT in ->PaintDivBB
3106 		if (!$this->ColActive && $this->blklvl > 0) {
3107 			if (isset($this->blk[$this->blklvl]['y0']) && $this->y == $this->blk[$this->blklvl]['y0'] && !$this->extrapagebreak) { // mPDF 6 pagebreaktype
3108 				if (isset($this->blk[$this->blklvl]['startpage'])) {
3109 					$this->blk[$this->blklvl]['startpage'] ++;
3110 				} else {
3111 					$this->blk[$this->blklvl]['startpage'] = 1;
3112 				}
3113 			}
3114 			if ((isset($this->blk[$this->blklvl]['y0']) && $this->y > $this->blk[$this->blklvl]['y0']) || $this->flowingBlockAttr['is_table'] || $this->extrapagebreak) {
3115 				$toplvl = $this->blklvl;
3116 			} // mPDF 6 pagebreaktype
3117 			else {
3118 				$toplvl = $this->blklvl - 1;
3119 			}
3120 			$sy = $this->y;
3121 			for ($bl = 1; $bl <= $toplvl; $bl++) {
3122 				if (isset($this->blk[$bl]['z-index']) && $this->blk[$bl]['z-index'] > 0) {
3123 					$this->BeginLayer($this->blk[$bl]['z-index']);
3124 				}
3125 				if (isset($this->blk[$bl]['visibility']) && $this->blk[$bl]['visibility'] && $this->blk[$bl]['visibility'] != 'visible') {
3126 					$this->SetVisibility($this->blk[$bl]['visibility']);
3127 				}
3128 				$this->PaintDivBB('pagebottom', 0, $bl);
3129 			}
3130 			$this->y = $sy;
3131 			// RESET block y0 and x0 - see below
3132 		}
3133 		$this->extrapagebreak = false; // mPDF 6 pagebreaktype
3134 
3135 		if ($this->visibility != 'visible') {
3136 			$this->SetVisibility('visible');
3137 		}
3138 
3139 		$this->EndLayer();
3140 
3141 		// BODY Backgrounds
3142 		if ($this->page > 0) {
3143 			$s = '';
3144 			$s .= $this->PrintBodyBackgrounds();
3145 
3146 			$s .= $this->PrintPageBackgrounds();
3147 			$this->pages[$this->page] = preg_replace('/(___BACKGROUND___PATTERNS' . $this->uniqstr . ')/', "\n" . $s . "\n" . '\\1', $this->pages[$this->page]);
3148 			$this->pageBackgrounds = [];
3149 		}
3150 
3151 		$save_kt = $this->keep_block_together;
3152 		$this->keep_block_together = 0;
3153 
3154 		$save_cols = false;
3155 
3156 		/* -- COLUMNS -- */
3157 		if ($this->ColActive) {
3158 			$save_cols = true;
3159 			$save_nbcol = $this->NbCol; // other values of gap and vAlign will not change by setting Columns off
3160 			$this->SetColumns(0);
3161 		}
3162 		/* -- END COLUMNS -- */
3163 
3164 		$family = $this->FontFamily;
3165 		$style = $this->FontStyle;
3166 		$size = $this->FontSizePt;
3167 		$this->ColumnAdjust = true; // enables column height adjustment for the page
3168 		$lw = $this->LineWidth;
3169 		$dc = $this->DrawColor;
3170 		$fc = $this->FillColor;
3171 		$tc = $this->TextColor;
3172 		$cf = $this->ColorFlag;
3173 		if ($this->page > 0) {
3174 			// Page footer
3175 			$this->InFooter = true;
3176 
3177 			$this->Reset();
3178 			$this->pageoutput[$this->page] = [];
3179 
3180 			$this->Footer();
3181 			// Close page
3182 			$this->_endpage();
3183 		}
3184 
3185 		// Start new page
3186 		$pageBeforeNewPage = $this->page;
3187 		$this->_beginpage($orientation, $mgl, $mgr, $mgt, $mgb, $mgh, $mgf, $ohname, $ehname, $ofname, $efname, $ohvalue, $ehvalue, $ofvalue, $efvalue, $pagesel, $newformat);
3188 		$isNewPage = $pageBeforeNewPage !== $this->page;
3189 
3190 		if ($this->docTemplate) {
3191 			$currentReaderId = $this->currentReaderId;
3192 
3193 			$pagecount = $this->setSourceFile($this->docTemplate);
3194 			if (($this->page - $this->docTemplateStart) > $pagecount) {
3195 				if ($this->docTemplateContinue) {
3196 					if ($this->docTemplateContinue2pages && $pagecount >= 2 && (0 === $this->page % 2)) {
3197 						$tplIdx = $this->importPage(($pagecount - 1));
3198 						$this->useTemplate($tplIdx);
3199 					} else {
3200 						$tplIdx = $this->importPage($pagecount);
3201 						$this->useTemplate($tplIdx);
3202 					}
3203 				}
3204 			} else {
3205 				$tplIdx = $this->importPage(($this->page - $this->docTemplateStart));
3206 				$this->useTemplate($tplIdx);
3207 			}
3208 
3209 			$this->currentReaderId = $currentReaderId;
3210 		}
3211 
3212 		if ($this->pageTemplate) {
3213 			$this->useTemplate($this->pageTemplate);
3214 		}
3215 
3216 		// Only add the headers if it's a new page
3217 		if ($isNewPage) {
3218 			// Tiling Patterns
3219 			$this->writer->write('___PAGE___START' . $this->uniqstr);
3220 			$this->writer->write('___BACKGROUND___PATTERNS' . $this->uniqstr);
3221 			$this->writer->write('___HEADER___MARKER' . $this->uniqstr);
3222 		}
3223 
3224 		$this->pageBackgrounds = [];
3225 
3226 		// Set line cap style to square
3227 		$this->SetLineCap(2);
3228 		// Set line width
3229 		$this->LineWidth = $lw;
3230 		$this->writer->write(sprintf('%.3F w', $lw * Mpdf::SCALE));
3231 		// Set font
3232 		if ($family) {
3233 			$this->SetFont($family, $style, $size, true, true); // forces write
3234 		}
3235 
3236 		// Set colors
3237 		$this->DrawColor = $dc;
3238 		if ($dc != $this->defDrawColor) {
3239 			$this->writer->write($dc);
3240 		}
3241 		$this->FillColor = $fc;
3242 		if ($fc != $this->defFillColor) {
3243 			$this->writer->write($fc);
3244 		}
3245 		$this->TextColor = $tc;
3246 		$this->ColorFlag = $cf;
3247 
3248 		// Page header
3249 		$this->Header();
3250 
3251 		// Restore line width
3252 		if ($this->LineWidth != $lw) {
3253 			$this->LineWidth = $lw;
3254 			$this->writer->write(sprintf('%.3F w', $lw * Mpdf::SCALE));
3255 		}
3256 		// Restore font
3257 		if ($family) {
3258 			$this->SetFont($family, $style, $size, true, true); // forces write
3259 		}
3260 
3261 		// Restore colors
3262 		if ($this->DrawColor != $dc) {
3263 			$this->DrawColor = $dc;
3264 			$this->writer->write($dc);
3265 		}
3266 		if ($this->FillColor != $fc) {
3267 			$this->FillColor = $fc;
3268 			$this->writer->write($fc);
3269 		}
3270 		$this->TextColor = $tc;
3271 		$this->ColorFlag = $cf;
3272 		$this->InFooter = false;
3273 
3274 		if ($save_layer > 0) {
3275 			$this->BeginLayer($save_layer);
3276 		}
3277 
3278 		if ($save_vis != 'visible') {
3279 			$this->SetVisibility($save_vis);
3280 		}
3281 
3282 		/* -- COLUMNS -- */
3283 		if ($save_cols) {
3284 			// Restore columns
3285 			$this->SetColumns($save_nbcol, $this->colvAlign, $this->ColGap);
3286 		}
3287 		if ($this->ColActive) {
3288 			$this->SetCol(0);
3289 		}
3290 		/* -- END COLUMNS -- */
3291 
3292 
3293 		// RESET BLOCK BORDER TOP
3294 		if (!$this->ColActive) {
3295 			for ($bl = 1; $bl <= $this->blklvl; $bl++) {
3296 				$this->blk[$bl]['y0'] = $this->y;
3297 				if (isset($this->blk[$bl]['x0'])) {
3298 					$this->blk[$bl]['x0'] += $this->MarginCorrection;
3299 				} else {
3300 					$this->blk[$bl]['x0'] = $this->MarginCorrection;
3301 				}
3302 				// Added mPDF 3.0 Float DIV
3303 				$this->blk[$bl]['marginCorrected'][$this->page] = true;
3304 			}
3305 		}
3306 
3307 
3308 		$this->table_rotate = $save_tr; // *TABLES*
3309 		$this->kwt = $save_kwt;
3310 
3311 		$this->keep_block_together = $save_kt;
3312 
3313 		$this->cMarginL = $bak_cml;
3314 		$this->cMarginR = $bak_cmr;
3315 		$this->divwidth = $bak_dw;
3316 
3317 		$this->lineheight = $bak_lh;
3318 	}
3319 
3320 	/**
3321 	 * Get current page number
3322 	 *
3323 	 * @return int
3324 	 */
3325 	function PageNo()
3326 	{
3327 		return $this->page;
3328 	}
3329 
3330 	function AddSpotColorsFromFile($file)
3331 	{
3332 		$colors = @file($file);
3333 		if (!$colors) {
3334 			throw new \Mpdf\MpdfException("Cannot load spot colors file - " . $file);
3335 		}
3336 		foreach ($colors as $sc) {
3337 			list($name, $c, $m, $y, $k) = preg_split("/\t/", $sc);
3338 			$c = intval($c);
3339 			$m = intval($m);
3340 			$y = intval($y);
3341 			$k = intval($k);
3342 			$this->AddSpotColor($name, $c, $m, $y, $k);
3343 		}
3344 	}
3345 
3346 	function AddSpotColor($name, $c, $m, $y, $k)
3347 	{
3348 		$name = strtoupper(trim($name));
3349 		if (!isset($this->spotColors[$name])) {
3350 			$i = count($this->spotColors) + 1;
3351 			$this->spotColors[$name] = ['i' => $i, 'c' => $c, 'm' => $m, 'y' => $y, 'k' => $k];
3352 			$this->spotColorIDs[$i] = $name;
3353 		}
3354 	}
3355 
3356 	function SetColor($col, $type = '')
3357 	{
3358 		$out = '';
3359 		if (!$col) {
3360 			return '';
3361 		} // mPDF 6
3362 		if ($col[0] == 3 || $col[0] == 5) { // RGB / RGBa
3363 			$out = sprintf('%.3F %.3F %.3F rg', ord($col[1]) / 255, ord($col[2]) / 255, ord($col[3]) / 255);
3364 		} elseif ($col[0] == 1) { // GRAYSCALE
3365 			$out = sprintf('%.3F g', ord($col[1]) / 255);
3366 		} elseif ($col[0] == 2) { // SPOT COLOR
3367 			$out = sprintf('/CS%d cs %.3F scn', ord($col[1]), ord($col[2]) / 100);
3368 		} elseif ($col[0] == 4 || $col[0] == 6) { // CMYK / CMYKa
3369 			$out = sprintf('%.3F %.3F %.3F %.3F k', ord($col[1]) / 100, ord($col[2]) / 100, ord($col[3]) / 100, ord($col[4]) / 100);
3370 		}
3371 		if ($type == 'Draw') {
3372 			$out = strtoupper($out);
3373 		} // e.g. rg => RG
3374 		elseif ($type == 'CodeOnly') {
3375 			$out = preg_replace('/\s(rg|g|k)/', '', $out);
3376 		}
3377 		return $out;
3378 	}
3379 
3380 	function SetDColor($col, $return = false)
3381 	{
3382 		$out = $this->SetColor($col, 'Draw');
3383 		if ($return) {
3384 			return $out;
3385 		}
3386 		if ($out == '') {
3387 			return '';
3388 		}
3389 		$this->DrawColor = $out;
3390 		if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['DrawColor']) && $this->pageoutput[$this->page]['DrawColor'] != $this->DrawColor) || !isset($this->pageoutput[$this->page]['DrawColor']))) {
3391 			$this->writer->write($this->DrawColor);
3392 		}
3393 		$this->pageoutput[$this->page]['DrawColor'] = $this->DrawColor;
3394 	}
3395 
3396 	function SetFColor($col, $return = false)
3397 	{
3398 		$out = $this->SetColor($col, 'Fill');
3399 		if ($return) {
3400 			return $out;
3401 		}
3402 		if ($out == '') {
3403 			return '';
3404 		}
3405 		$this->FillColor = $out;
3406 		$this->ColorFlag = ($out != $this->TextColor);
3407 		if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['FillColor']) && $this->pageoutput[$this->page]['FillColor'] != $this->FillColor) || !isset($this->pageoutput[$this->page]['FillColor']))) {
3408 			$this->writer->write($this->FillColor);
3409 		}
3410 		$this->pageoutput[$this->page]['FillColor'] = $this->FillColor;
3411 	}
3412 
3413 	function SetTColor($col, $return = false)
3414 	{
3415 		$out = $this->SetColor($col, 'Text');
3416 		if ($return) {
3417 			return $out;
3418 		}
3419 		if ($out == '') {
3420 			return '';
3421 		}
3422 		$this->TextColor = $out;
3423 		$this->ColorFlag = ($this->FillColor != $out);
3424 	}
3425 
3426 	function SetDrawColor($r, $g = -1, $b = -1, $col4 = -1, $return = false)
3427 	{
3428 		// Set color for all stroking operations
3429 		$col = [];
3430 		if (($r == 0 and $g == 0 and $b == 0 && $col4 == -1) or $g == -1) {
3431 			$col = $this->colorConverter->convert($r, $this->PDFAXwarnings);
3432 		} elseif ($col4 == -1) {
3433 			$col = $this->colorConverter->convert('rgb(' . $r . ',' . $g . ',' . $b . ')', $this->PDFAXwarnings);
3434 		} else {
3435 			$col = $this->colorConverter->convert('cmyk(' . $r . ',' . $g . ',' . $b . ',' . $col4 . ')', $this->PDFAXwarnings);
3436 		}
3437 		$out = $this->SetDColor($col, $return);
3438 		return $out;
3439 	}
3440 
3441 	function SetFillColor($r, $g = -1, $b = -1, $col4 = -1, $return = false)
3442 	{
3443 		// Set color for all filling operations
3444 		$col = [];
3445 		if (($r == 0 and $g == 0 and $b == 0 && $col4 == -1) or $g == -1) {
3446 			$col = $this->colorConverter->convert($r, $this->PDFAXwarnings);
3447 		} elseif ($col4 == -1) {
3448 			$col = $this->colorConverter->convert('rgb(' . $r . ',' . $g . ',' . $b . ')', $this->PDFAXwarnings);
3449 		} else {
3450 			$col = $this->colorConverter->convert('cmyk(' . $r . ',' . $g . ',' . $b . ',' . $col4 . ')', $this->PDFAXwarnings);
3451 		}
3452 		$out = $this->SetFColor($col, $return);
3453 		return $out;
3454 	}
3455 
3456 	function SetTextColor($r, $g = -1, $b = -1, $col4 = -1, $return = false)
3457 	{
3458 		// Set color for text
3459 		$col = [];
3460 		if (($r == 0 and $g == 0 and $b == 0 && $col4 == -1) or $g == -1) {
3461 			$col = $this->colorConverter->convert($r, $this->PDFAXwarnings);
3462 		} elseif ($col4 == -1) {
3463 			$col = $this->colorConverter->convert('rgb(' . $r . ',' . $g . ',' . $b . ')', $this->PDFAXwarnings);
3464 		} else {
3465 			$col = $this->colorConverter->convert('cmyk(' . $r . ',' . $g . ',' . $b . ',' . $col4 . ')', $this->PDFAXwarnings);
3466 		}
3467 		$out = $this->SetTColor($col, $return);
3468 		return $out;
3469 	}
3470 
3471 	function _getCharWidth(&$cw, $u, $isdef = true)
3472 	{
3473 		$w = 0;
3474 
3475 		if ($u == 0) {
3476 			$w = false;
3477 		} elseif (isset($cw[$u * 2 + 1])) {
3478 			$w = (ord($cw[$u * 2]) << 8) + ord($cw[$u * 2 + 1]);
3479 		}
3480 
3481 		if ($w == 65535) {
3482 			return 0;
3483 		} elseif ($w) {
3484 			return $w;
3485 		} elseif ($isdef) {
3486 			return false;
3487 		} else {
3488 			return 0;
3489 		}
3490 	}
3491 
3492 	function _charDefined(&$cw, $u)
3493 	{
3494 		$w = 0;
3495 		if ($u == 0) {
3496 			return false;
3497 		}
3498 		if (isset($cw[$u * 2 + 1])) {
3499 			$w = (ord($cw[$u * 2]) << 8) + ord($cw[$u * 2 + 1]);
3500 		}
3501 
3502 		return (bool) $w;
3503 	}
3504 
3505 	function GetCharWidthCore($c)
3506 	{
3507 		// Get width of a single character in the current Core font
3508 		$c = (string) $c;
3509 		$w = 0;
3510 		// Soft Hyphens chr(173)
3511 		if ($c == chr(173) && $this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats') {
3512 			return 0;
3513 		} elseif (($this->textvar & TextVars::FC_SMALLCAPS) && isset($this->upperCase[ord($c)])) {  // mPDF 5.7.1
3514 			$charw = $this->CurrentFont['cw'][chr($this->upperCase[ord($c)])];
3515 			if ($charw !== false) {
3516 				$charw = $charw * $this->smCapsScale * $this->smCapsStretch / 100;
3517 				$w+=$charw;
3518 			}
3519 		} elseif (isset($this->CurrentFont['cw'][$c])) {
3520 			$w += $this->CurrentFont['cw'][$c];
3521 		} elseif (isset($this->CurrentFont['cw'][ord($c)])) {
3522 			$w += $this->CurrentFont['cw'][ord($c)];
3523 		}
3524 		$w *= ($this->FontSize / 1000);
3525 		if ($this->minwSpacing || $this->fixedlSpacing) {
3526 			if ($c == ' ') {
3527 				$nb_spaces = 1;
3528 			} else {
3529 				$nb_spaces = 0;
3530 			}
3531 			$w += $this->fixedlSpacing + ($nb_spaces * $this->minwSpacing);
3532 		}
3533 		return ($w);
3534 	}
3535 
3536 	function GetCharWidthNonCore($c, $addSubset = true)
3537 	{
3538 		// Get width of a single character in the current Non-Core font
3539 		$c = (string) $c;
3540 		$w = 0;
3541 		$unicode = $this->UTF8StringToArray($c, $addSubset);
3542 		$char = $unicode[0];
3543 		/* -- CJK-FONTS -- */
3544 		if ($this->CurrentFont['type'] == 'Type0') { // CJK Adobe fonts
3545 			if ($char == 173) {
3546 				return 0;
3547 			} // Soft Hyphens
3548 			elseif (isset($this->CurrentFont['cw'][$char])) {
3549 				$w+=$this->CurrentFont['cw'][$char];
3550 			} elseif (isset($this->CurrentFont['MissingWidth'])) {
3551 				$w += $this->CurrentFont['MissingWidth'];
3552 			} else {
3553 				$w += 500;
3554 			}
3555 		} else {
3556 			/* -- END CJK-FONTS -- */
3557 			if ($char == 173) {
3558 				return 0;
3559 			} // Soft Hyphens
3560 			elseif (($this->textvar & TextVars::FC_SMALLCAPS) && isset($this->upperCase[$char])) { // mPDF 5.7.1
3561 				$charw = $this->_getCharWidth($this->CurrentFont['cw'], $this->upperCase[$char]);
3562 				if ($charw !== false) {
3563 					$charw = $charw * $this->smCapsScale * $this->smCapsStretch / 100;
3564 					$w+=$charw;
3565 				} elseif (isset($this->CurrentFont['desc']['MissingWidth'])) {
3566 					$w += $this->CurrentFont['desc']['MissingWidth'];
3567 				} elseif (isset($this->CurrentFont['MissingWidth'])) {
3568 					$w += $this->CurrentFont['MissingWidth'];
3569 				} else {
3570 					$w += 500;
3571 				}
3572 			} else {
3573 				$charw = $this->_getCharWidth($this->CurrentFont['cw'], $char);
3574 				if ($charw !== false) {
3575 					$w+=$charw;
3576 				} elseif (isset($this->CurrentFont['desc']['MissingWidth'])) {
3577 					$w += $this->CurrentFont['desc']['MissingWidth'];
3578 				} elseif (isset($this->CurrentFont['MissingWidth'])) {
3579 					$w += $this->CurrentFont['MissingWidth'];
3580 				} else {
3581 					$w += 500;
3582 				}
3583 			}
3584 		} // *CJK-FONTS*
3585 		$w *= ($this->FontSize / 1000);
3586 		if ($this->minwSpacing || $this->fixedlSpacing) {
3587 			if ($c == ' ') {
3588 				$nb_spaces = 1;
3589 			} else {
3590 				$nb_spaces = 0;
3591 			}
3592 			$w += $this->fixedlSpacing + ($nb_spaces * $this->minwSpacing);
3593 		}
3594 		return ($w);
3595 	}
3596 
3597 	function GetCharWidth($c, $addSubset = true)
3598 	{
3599 		if (!$this->usingCoreFont) {
3600 			return $this->GetCharWidthNonCore($c, $addSubset);
3601 		} else {
3602 			return $this->GetCharWidthCore($c);
3603 		}
3604 	}
3605 
3606 	function GetStringWidth($s, $addSubset = true, $OTLdata = false, $textvar = 0, $includeKashida = false)
3607 	{
3608 	// mPDF 5.7.1
3609 		// Get width of a string in the current font
3610 		$s = (string) $s;
3611 		$cw = &$this->CurrentFont['cw'];
3612 		$w = 0;
3613 		$kerning = 0;
3614 		$lastchar = 0;
3615 		$nb_carac = 0;
3616 		$nb_spaces = 0;
3617 		$kashida = 0;
3618 		// mPDF ITERATION
3619 		if ($this->iterationCounter) {
3620 			$s = preg_replace('/{iteration ([a-zA-Z0-9_]+)}/', '\\1', $s);
3621 		}
3622 		if (!$this->usingCoreFont) {
3623 			$discards = substr_count($s, "\xc2\xad"); // mPDF 6 soft hyphens [U+00AD]
3624 			$unicode = $this->UTF8StringToArray($s, $addSubset);
3625 			if ($this->minwSpacing || $this->fixedlSpacing) {
3626 				$nb_spaces = mb_substr_count($s, ' ', $this->mb_enc);
3627 				$nb_carac = count($unicode) - $discards; // mPDF 6
3628 				// mPDF 5.7.1
3629 				// Use GPOS OTL
3630 				if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
3631 					if (isset($OTLdata['group']) && $OTLdata['group']) {
3632 						$nb_carac -= substr_count($OTLdata['group'], 'M');
3633 					}
3634 				}
3635 			}
3636 			/* -- CJK-FONTS -- */
3637 			if ($this->CurrentFont['type'] == 'Type0') { // CJK Adobe fonts
3638 				foreach ($unicode as $char) {
3639 					if ($char == 0x00AD) {
3640 						continue;
3641 					} // mPDF 6 soft hyphens [U+00AD]
3642 					if (isset($cw[$char])) {
3643 						$w+=$cw[$char];
3644 					} elseif (isset($this->CurrentFont['MissingWidth'])) {
3645 						$w += $this->CurrentFont['MissingWidth'];
3646 					} else {
3647 						$w += 500;
3648 					}
3649 				}
3650 			} else {
3651 				/* -- END CJK-FONTS -- */
3652 				foreach ($unicode as $i => $char) {
3653 					if ($char == 0x00AD) {
3654 						continue;
3655 					} // mPDF 6 soft hyphens [U+00AD]
3656 					if (($textvar & TextVars::FC_SMALLCAPS) && isset($this->upperCase[$char])) {
3657 						$charw = $this->_getCharWidth($cw, $this->upperCase[$char]);
3658 						if ($charw !== false) {
3659 							$charw = $charw * $this->smCapsScale * $this->smCapsStretch / 100;
3660 							$w+=$charw;
3661 						} elseif (isset($this->CurrentFont['desc']['MissingWidth'])) {
3662 							$w += $this->CurrentFont['desc']['MissingWidth'];
3663 						} elseif (isset($this->CurrentFont['MissingWidth'])) {
3664 							$w += $this->CurrentFont['MissingWidth'];
3665 						} else {
3666 							$w += 500;
3667 						}
3668 					} else {
3669 						$charw = $this->_getCharWidth($cw, $char);
3670 						if ($charw !== false) {
3671 							$w+=$charw;
3672 						} elseif (isset($this->CurrentFont['desc']['MissingWidth'])) {
3673 							$w += $this->CurrentFont['desc']['MissingWidth'];
3674 						} elseif (isset($this->CurrentFont['MissingWidth'])) {
3675 							$w += $this->CurrentFont['MissingWidth'];
3676 						} else {
3677 							$w += 500;
3678 						}
3679 						// mPDF 5.7.1
3680 						// Use GPOS OTL
3681 						// ...GetStringWidth...
3682 						if (isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF) && !empty($OTLdata)) {
3683 							if (isset($OTLdata['GPOSinfo'][$i]['wDir']) && $OTLdata['GPOSinfo'][$i]['wDir'] == 'RTL') {
3684 								if (isset($OTLdata['GPOSinfo'][$i]['XAdvanceR']) && $OTLdata['GPOSinfo'][$i]['XAdvanceR']) {
3685 									$w += $OTLdata['GPOSinfo'][$i]['XAdvanceR'] * 1000 / $this->CurrentFont['unitsPerEm'];
3686 								}
3687 							} else {
3688 								if (isset($OTLdata['GPOSinfo'][$i]['XAdvanceL']) && $OTLdata['GPOSinfo'][$i]['XAdvanceL']) {
3689 									$w += $OTLdata['GPOSinfo'][$i]['XAdvanceL'] * 1000 / $this->CurrentFont['unitsPerEm'];
3690 								}
3691 							}
3692 							// Kashida from GPOS
3693 							// Kashida is set as an absolute length value (already set as a proportion based on useKashida %)
3694 							if ($includeKashida && isset($OTLdata['GPOSinfo'][$i]['kashida_space']) && $OTLdata['GPOSinfo'][$i]['kashida_space']) {
3695 								$kashida += $OTLdata['GPOSinfo'][$i]['kashida_space'];
3696 							}
3697 						}
3698 						if (($textvar & TextVars::FC_KERNING) && $lastchar) {
3699 							if (isset($this->CurrentFont['kerninfo'][$lastchar][$char])) {
3700 								$kerning += $this->CurrentFont['kerninfo'][$lastchar][$char];
3701 							}
3702 						}
3703 						$lastchar = $char;
3704 					}
3705 				}
3706 			} // *CJK-FONTS*
3707 		} else {
3708 			if ($this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats') {
3709 				$s = str_replace(chr(173), '', $s);
3710 			}
3711 			$nb_carac = $l = strlen($s);
3712 			if ($this->minwSpacing || $this->fixedlSpacing) {
3713 				$nb_spaces = substr_count($s, ' ');
3714 			}
3715 			for ($i = 0; $i < $l; $i++) {
3716 				if (($textvar & TextVars::FC_SMALLCAPS) && isset($this->upperCase[ord($s[$i])])) {  // mPDF 5.7.1
3717 					$charw = $cw[chr($this->upperCase[ord($s[$i])])];
3718 					if ($charw !== false) {
3719 						$charw = $charw * $this->smCapsScale * $this->smCapsStretch / 100;
3720 						$w+=$charw;
3721 					}
3722 				} elseif (isset($cw[$s[$i]])) {
3723 					$w += $cw[$s[$i]];
3724 				} elseif (isset($cw[ord($s[$i])])) {
3725 					$w += $cw[ord($s[$i])];
3726 				}
3727 				if (($textvar & TextVars::FC_KERNING) && $i > 0) { // mPDF 5.7.1
3728 					if (isset($this->CurrentFont['kerninfo'][$s[($i - 1)]][$s[$i]])) {
3729 						$kerning += $this->CurrentFont['kerninfo'][$s[($i - 1)]][$s[$i]];
3730 					}
3731 				}
3732 			}
3733 		}
3734 		unset($cw);
3735 		if ($textvar & TextVars::FC_KERNING) {
3736 			$w += $kerning;
3737 		} // mPDF 5.7.1
3738 		$w *= ($this->FontSize / 1000);
3739 		$w += (($nb_carac + $nb_spaces) * $this->fixedlSpacing) + ($nb_spaces * $this->minwSpacing);
3740 		$w += $kashida / Mpdf::SCALE;
3741 
3742 		return ($w);
3743 	}
3744 
3745 	function SetLineWidth($width)
3746 	{
3747 		// Set line width
3748 		$this->LineWidth = $width;
3749 		$lwout = (sprintf('%.3F w', $width * Mpdf::SCALE));
3750 		if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['LineWidth']) && $this->pageoutput[$this->page]['LineWidth'] != $lwout) || !isset($this->pageoutput[$this->page]['LineWidth']))) {
3751 			$this->writer->write($lwout);
3752 		}
3753 		$this->pageoutput[$this->page]['LineWidth'] = $lwout;
3754 	}
3755 
3756 	function Line($x1, $y1, $x2, $y2)
3757 	{
3758 		// Draw a line
3759 		$this->writer->write(sprintf('%.3F %.3F m %.3F %.3F l S', $x1 * Mpdf::SCALE, ($this->h - $y1) * Mpdf::SCALE, $x2 * Mpdf::SCALE, ($this->h - $y2) * Mpdf::SCALE));
3760 	}
3761 
3762 	function Arrow($x1, $y1, $x2, $y2, $headsize = 3, $fill = 'B', $angle = 25)
3763 	{
3764 		// F == fill // S == stroke // B == stroke and fill
3765 		// angle = splay of arrowhead - 1 - 89 degrees
3766 		if ($fill == 'F') {
3767 			$fill = 'f';
3768 		} elseif ($fill == 'FD' or $fill == 'DF' or $fill == 'B') {
3769 			$fill = 'B';
3770 		} else {
3771 			$fill = 'S';
3772 		}
3773 		$a = atan2(($y2 - $y1), ($x2 - $x1));
3774 		$b = $a + deg2rad($angle);
3775 		$c = $a - deg2rad($angle);
3776 		$x3 = $x2 - ($headsize * cos($b));
3777 		$y3 = $this->h - ($y2 - ($headsize * sin($b)));
3778 		$x4 = $x2 - ($headsize * cos($c));
3779 		$y4 = $this->h - ($y2 - ($headsize * sin($c)));
3780 
3781 		$x5 = $x3 - ($x3 - $x4) / 2; // mid point of base of arrowhead - to join arrow line to
3782 		$y5 = $y3 - ($y3 - $y4) / 2;
3783 
3784 		$s = '';
3785 		$s .= sprintf('%.3F %.3F m %.3F %.3F l S', $x1 * Mpdf::SCALE, ($this->h - $y1) * Mpdf::SCALE, $x5 * Mpdf::SCALE, $y5 * Mpdf::SCALE);
3786 		$this->writer->write($s);
3787 
3788 		$s = '';
3789 		$s .= sprintf('%.3F %.3F m %.3F %.3F l %.3F %.3F l %.3F %.3F l %.3F %.3F l ', $x5 * Mpdf::SCALE, $y5 * Mpdf::SCALE, $x3 * Mpdf::SCALE, $y3 * Mpdf::SCALE, $x2 * Mpdf::SCALE, ($this->h - $y2) * Mpdf::SCALE, $x4 * Mpdf::SCALE, $y4 * Mpdf::SCALE, $x5 * Mpdf::SCALE, $y5 * Mpdf::SCALE);
3790 		$s .= $fill;
3791 		$this->writer->write($s);
3792 	}
3793 
3794 	function Rect($x, $y, $w, $h, $style = '')
3795 	{
3796 		// Draw a rectangle
3797 		if ($style == 'F') {
3798 			$op = 'f';
3799 		} elseif ($style == 'FD' or $style == 'DF') {
3800 			$op = 'B';
3801 		} else {
3802 			$op = 'S';
3803 		}
3804 		$this->writer->write(sprintf('%.3F %.3F %.3F %.3F re %s', $x * Mpdf::SCALE, ($this->h - $y) * Mpdf::SCALE, $w * Mpdf::SCALE, -$h * Mpdf::SCALE, $op));
3805 	}
3806 
3807 	function AddFontDirectory($directory)
3808 	{
3809 		$this->fontDir[] = $directory;
3810 		$this->fontFileFinder->setDirectories($this->fontDir);
3811 	}
3812 
3813 	function AddFont($family, $style = '')
3814 	{
3815 		if (empty($family)) {
3816 			return;
3817 		}
3818 
3819 		$family = strtolower($family);
3820 		$style = strtoupper($style);
3821 		$style = str_replace('U', '', $style);
3822 
3823 		if ($style == 'IB') {
3824 			$style = 'BI';
3825 		}
3826 
3827 		$fontkey = $family . $style;
3828 
3829 		// check if the font has been already added
3830 		if (isset($this->fonts[$fontkey])) {
3831 			return;
3832 		}
3833 
3834 		/* -- CJK-FONTS -- */
3835 		if (in_array($family, $this->available_CJK_fonts)) {
3836 			if (empty($this->Big5_widths)) {
3837 				require __DIR__ . '/../data/CJKdata.php';
3838 			}
3839 			$this->AddCJKFont($family); // don't need to add style
3840 			return;
3841 		}
3842 		/* -- END CJK-FONTS -- */
3843 
3844 		if ($this->usingCoreFont) {
3845 			throw new \Mpdf\MpdfException("mPDF Error - problem with Font management");
3846 		}
3847 
3848 		$stylekey = $style;
3849 		if (!$style) {
3850 			$stylekey = 'R';
3851 		}
3852 
3853 		if (!isset($this->fontdata[$family][$stylekey]) || !$this->fontdata[$family][$stylekey]) {
3854 			throw new \Mpdf\MpdfException(sprintf('Font "%s%s%s" is not supported', $family, $style ? ' - ' : '', $style));
3855 		}
3856 
3857 		/* Setup defaults */
3858 		$font = [
3859 			'name' => '',
3860 			'type' => '',
3861 			'desc' => '',
3862 			'panose' => '',
3863 			'unitsPerEm' => '',
3864 			'up' => '',
3865 			'ut' => '',
3866 			'strs' => '',
3867 			'strp' => '',
3868 			'sip' => false,
3869 			'smp' => false,
3870 			'useOTL' => 0,
3871 			'fontmetrics' => '',
3872 			'haskerninfo' => false,
3873 			'haskernGPOS' => false,
3874 			'hassmallcapsGSUB' => false,
3875 			'BMPselected' => false,
3876 			'GSUBScriptLang' => [],
3877 			'GSUBFeatures' => [],
3878 			'GSUBLookups' => [],
3879 			'GPOSScriptLang' => [],
3880 			'GPOSFeatures' => [],
3881 			'GPOSLookups' => [],
3882 			'rtlPUAstr' => '',
3883 		];
3884 
3885 		$fontCacheFilename = $fontkey . '.mtx.json';
3886 		if ($this->fontCache->jsonHas($fontCacheFilename)) {
3887 			$font = $this->fontCache->jsonLoad($fontCacheFilename);
3888 		}
3889 
3890 		$ttffile = $this->fontFileFinder->findFontFile($this->fontdata[$family][$stylekey]);
3891 		$ttfstat = stat($ttffile);
3892 
3893 		$TTCfontID = isset($this->fontdata[$family]['TTCfontID'][$stylekey]) ? isset($this->fontdata[$family]['TTCfontID'][$stylekey]) : 0;
3894 		$fontUseOTL = isset($this->fontdata[$family]['useOTL']) ? $this->fontdata[$family]['useOTL'] : false;
3895 		$BMPonly = in_array($family, $this->BMPonly) ? true : false;
3896 
3897 		$regenerate = false;
3898 		if ($BMPonly && !$font['BMPselected']) {
3899 			$regenerate = true;
3900 		} elseif (!$BMPonly && $font['BMPselected']) {
3901 			$regenerate = true;
3902 		}
3903 
3904 		if ($fontUseOTL && $font['useOTL'] != $fontUseOTL) {
3905 			$regenerate = true;
3906 			$font['useOTL'] = $fontUseOTL;
3907 		} elseif (!$fontUseOTL && $font['useOTL']) {
3908 			$regenerate = true;
3909 			$font['useOTL'] = 0;
3910 		}
3911 
3912 		if ($this->fontDescriptor != $font['fontmetrics']) {
3913 			$regenerate = true;
3914 		} // mPDF 6
3915 
3916 		if (empty($font['name']) || $font['originalsize'] != $ttfstat['size'] || $regenerate) {
3917 			$generator = new MetricsGenerator($this->fontCache, $this->fontDescriptor);
3918 
3919 			$generator->generateMetrics(
3920 				$ttffile,
3921 				$ttfstat,
3922 				$fontkey,
3923 				$TTCfontID,
3924 				$this->debugfonts,
3925 				$BMPonly,
3926 				$font['useOTL'],
3927 				$fontUseOTL
3928 			);
3929 
3930 			$font = $this->fontCache->jsonLoad($fontCacheFilename);
3931 			$cw = $this->fontCache->load($fontkey . '.cw.dat');
3932 			$glyphIDtoUni = $this->fontCache->load($fontkey . '.gid.dat');
3933 		} else {
3934 			if ($this->fontCache->has($fontkey . '.cw.dat')) {
3935 				$cw = $this->fontCache->load($fontkey . '.cw.dat');
3936 			}
3937 
3938 			if ($this->fontCache->has($fontkey . '.gid.dat')) {
3939 				$glyphIDtoUni = $this->fontCache->load($fontkey . '.gid.dat');
3940 			}
3941 		}
3942 
3943 		if (isset($this->fontdata[$family]['sip-ext']) && $this->fontdata[$family]['sip-ext']) {
3944 			$sipext = $this->fontdata[$family]['sip-ext'];
3945 		} else {
3946 			$sipext = '';
3947 		}
3948 
3949 		// Override with values from config_font.php
3950 		if (isset($this->fontdata[$family]['Ascent']) && $this->fontdata[$family]['Ascent']) {
3951 			$desc['Ascent'] = $this->fontdata[$family]['Ascent'];
3952 		}
3953 		if (isset($this->fontdata[$family]['Descent']) && $this->fontdata[$family]['Descent']) {
3954 			$desc['Descent'] = $this->fontdata[$family]['Descent'];
3955 		}
3956 		if (isset($this->fontdata[$family]['Leading']) && $this->fontdata[$family]['Leading']) {
3957 			$desc['Leading'] = $this->fontdata[$family]['Leading'];
3958 		}
3959 
3960 		$i = count($this->fonts) + $this->extraFontSubsets + 1;
3961 
3962 		$this->fonts[$fontkey] = [
3963 			'i' => $i,
3964 			'name' => $font['name'],
3965 			'type' => $font['type'],
3966 			'desc' => $font['desc'],
3967 			'panose' => $font['panose'],
3968 			'unitsPerEm' => $font['unitsPerEm'],
3969 			'up' => $font['up'],
3970 			'ut' => $font['ut'],
3971 			'strs' => $font['strs'],
3972 			'strp' => $font['strp'],
3973 			'cw' => $cw,
3974 			'ttffile' => $ttffile,
3975 			'fontkey' => $fontkey,
3976 			'used' => false,
3977 			'sip' => $font['sip'],
3978 			'sipext' => $sipext,
3979 			'smp' => $font['smp'],
3980 			'TTCfontID' => $TTCfontID,
3981 			'useOTL' => $fontUseOTL,
3982 			'useKashida' => (isset($this->fontdata[$family]['useKashida']) ? $this->fontdata[$family]['useKashida'] : false),
3983 			'GSUBScriptLang' => $font['GSUBScriptLang'],
3984 			'GSUBFeatures' => $font['GSUBFeatures'],
3985 			'GSUBLookups' => $font['GSUBLookups'],
3986 			'GPOSScriptLang' => $font['GPOSScriptLang'],
3987 			'GPOSFeatures' => $font['GPOSFeatures'],
3988 			'GPOSLookups' => $font['GPOSLookups'],
3989 			'rtlPUAstr' => $font['rtlPUAstr'],
3990 			'glyphIDtoUni' => $glyphIDtoUni,
3991 			'haskerninfo' => $font['haskerninfo'],
3992 			'haskernGPOS' => $font['haskernGPOS'],
3993 			'hassmallcapsGSUB' => $font['hassmallcapsGSUB'],
3994 		];
3995 
3996 
3997 		if (!$font['sip'] && !$font['smp']) {
3998 			$subsetRange = range(32, 127);
3999 			$this->fonts[$fontkey]['subset'] = array_combine($subsetRange, $subsetRange);
4000 		} else {
4001 			$this->fonts[$fontkey]['subsets'] = [0 => range(0, 127)];
4002 			$this->fonts[$fontkey]['subsetfontids'] = [$i];
4003 		}
4004 
4005 		if ($font['haskerninfo']) {
4006 			$this->fonts[$fontkey]['kerninfo'] = $font['kerninfo'];
4007 		}
4008 
4009 		$this->FontFiles[$fontkey] = [
4010 			'length1' => $font['originalsize'],
4011 			'type' => 'TTF',
4012 			'ttffile' => $ttffile,
4013 			'sip' => $font['sip'],
4014 			'smp' => $font['smp'],
4015 		];
4016 
4017 		unset($cw);
4018 	}
4019 
4020 	function SetFont($family, $style = '', $size = 0, $write = true, $forcewrite = false)
4021 	{
4022 		$family = strtolower($family);
4023 
4024 		if (!$this->onlyCoreFonts) {
4025 			if ($family == 'sans' || $family == 'sans-serif') {
4026 				$family = $this->sans_fonts[0];
4027 			}
4028 			if ($family == 'serif') {
4029 				$family = $this->serif_fonts[0];
4030 			}
4031 			if ($family == 'mono' || $family == 'monospace') {
4032 				$family = $this->mono_fonts[0];
4033 			}
4034 		}
4035 
4036 		if (isset($this->fonttrans[$family]) && $this->fonttrans[$family]) {
4037 			$family = $this->fonttrans[$family];
4038 		}
4039 
4040 		if ($family == '') {
4041 			if ($this->FontFamily) {
4042 				$family = $this->FontFamily;
4043 			} elseif ($this->default_font) {
4044 				$family = $this->default_font;
4045 			} else {
4046 				throw new \Mpdf\MpdfException("No font or default font set!");
4047 			}
4048 		}
4049 
4050 		$this->ReqFontStyle = $style; // required or requested style - used later for artificial bold/italic
4051 
4052 		if (($family == 'csymbol') || ($family == 'czapfdingbats') || ($family == 'ctimes') || ($family == 'ccourier') || ($family == 'chelvetica')) {
4053 			if ($this->PDFA || $this->PDFX) {
4054 				if ($family == 'csymbol' || $family == 'czapfdingbats') {
4055 					throw new \Mpdf\MpdfException("Symbol and Zapfdingbats cannot be embedded in mPDF (required for PDFA1-b or PDFX/1-a).");
4056 				}
4057 				if ($family == 'ctimes' || $family == 'ccourier' || $family == 'chelvetica') {
4058 					if (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto)) {
4059 						$this->PDFAXwarnings[] = "Core Adobe font " . ucfirst($family) . " cannot be embedded in mPDF, which is required for PDFA1-b or PDFX/1-a. (Embedded font will be substituted.)";
4060 					}
4061 					if ($family == 'chelvetica') {
4062 						$family = 'sans';
4063 					}
4064 					if ($family == 'ctimes') {
4065 						$family = 'serif';
4066 					}
4067 					if ($family == 'ccourier') {
4068 						$family = 'mono';
4069 					}
4070 				}
4071 				$this->usingCoreFont = false;
4072 			} else {
4073 				$this->usingCoreFont = true;
4074 			}
4075 			if ($family == 'csymbol' || $family == 'czapfdingbats') {
4076 				$style = '';
4077 			}
4078 		} else {
4079 			$this->usingCoreFont = false;
4080 		}
4081 
4082 		// mPDF 5.7.1
4083 		if ($style) {
4084 			$style = strtoupper($style);
4085 			if ($style == 'IB') {
4086 				$style = 'BI';
4087 			}
4088 		}
4089 
4090 		if (!$size) {
4091 			$size = $this->FontSizePt;
4092 		}
4093 
4094 		$fontkey = $family . $style;
4095 
4096 		$stylekey = $style;
4097 
4098 		if (!$stylekey) {
4099 			$stylekey = "R";
4100 		}
4101 
4102 		if (!$this->onlyCoreFonts && !$this->usingCoreFont) {
4103 			if (!isset($this->fonts[$fontkey]) || count($this->default_available_fonts) != count($this->available_unifonts)) { // not already added
4104 
4105 				/* -- CJK-FONTS -- */
4106 				if (in_array($fontkey, $this->available_CJK_fonts)) {
4107 					if (!isset($this->fonts[$fontkey])) { // already added
4108 						if (empty($this->Big5_widths)) {
4109 							require __DIR__ . '/../data/CJKdata.php';
4110 						}
4111 						$this->AddCJKFont($family); // don't need to add style
4112 					}
4113 				} else { // Test to see if requested font/style is available - or substitute /* -- END CJK-FONTS -- */
4114 					if (!in_array($fontkey, $this->available_unifonts)) {
4115 						// If font[nostyle] exists - set it
4116 						if (in_array($family, $this->available_unifonts)) {
4117 							$style = '';
4118 						} // elseif only one font available - set it (assumes if only one font available it will not have a style)
4119 						elseif (count($this->available_unifonts) == 1) {
4120 							$family = $this->available_unifonts[0];
4121 							$style = '';
4122 						} else {
4123 							$found = 0;
4124 							// else substitute font of similar type
4125 							if (in_array($family, $this->sans_fonts)) {
4126 								$i = array_intersect($this->sans_fonts, $this->available_unifonts);
4127 								if (count($i)) {
4128 									$i = array_values($i);
4129 									// with requested style if possible
4130 									if (!in_array(($i[0] . $style), $this->available_unifonts)) {
4131 										$style = '';
4132 									}
4133 									$family = $i[0];
4134 									$found = 1;
4135 								}
4136 							} elseif (in_array($family, $this->serif_fonts)) {
4137 								$i = array_intersect($this->serif_fonts, $this->available_unifonts);
4138 								if (count($i)) {
4139 									$i = array_values($i);
4140 									// with requested style if possible
4141 									if (!in_array(($i[0] . $style), $this->available_unifonts)) {
4142 										$style = '';
4143 									}
4144 									$family = $i[0];
4145 									$found = 1;
4146 								}
4147 							} elseif (in_array($family, $this->mono_fonts)) {
4148 								$i = array_intersect($this->mono_fonts, $this->available_unifonts);
4149 								if (count($i)) {
4150 									$i = array_values($i);
4151 									// with requested style if possible
4152 									if (!in_array(($i[0] . $style), $this->available_unifonts)) {
4153 										$style = '';
4154 									}
4155 									$family = $i[0];
4156 									$found = 1;
4157 								}
4158 							}
4159 
4160 							if (!$found) {
4161 								// set first available font
4162 								$fs = $this->available_unifonts[0];
4163 								preg_match('/^([a-z_0-9\-]+)([BI]{0,2})$/', $fs, $fas); // Allow "-"
4164 								// with requested style if possible
4165 								$ws = $fas[1] . $style;
4166 								if (in_array($ws, $this->available_unifonts)) {
4167 									$family = $fas[1]; // leave $style as is
4168 								} elseif (in_array($fas[1], $this->available_unifonts)) {
4169 									// or without style
4170 									$family = $fas[1];
4171 									$style = '';
4172 								} else {
4173 									// or with the style specified
4174 									$family = $fas[1];
4175 									$style = $fas[2];
4176 								}
4177 							}
4178 						}
4179 						$fontkey = $family . $style;
4180 					}
4181 				}
4182 			}
4183 
4184 			// try to add font (if not already added)
4185 			$this->AddFont($family, $style);
4186 
4187 			// Test if font is already selected
4188 			if ($this->FontFamily == $family && $this->FontFamily == $this->currentfontfamily && $this->FontStyle == $style && $this->FontStyle == $this->currentfontstyle && $this->FontSizePt == $size && $this->FontSizePt == $this->currentfontsize && !$forcewrite) {
4189 				return $family;
4190 			}
4191 
4192 			$fontkey = $family . $style;
4193 
4194 			// Select it
4195 			$this->FontFamily = $family;
4196 			$this->FontStyle = $style;
4197 			$this->FontSizePt = $size;
4198 			$this->FontSize = $size / Mpdf::SCALE;
4199 			$this->CurrentFont = &$this->fonts[$fontkey];
4200 			if ($write) {
4201 				$fontout = (sprintf('BT /F%d %.3F Tf ET', $this->CurrentFont['i'], $this->FontSizePt));
4202 				if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['Font']) && $this->pageoutput[$this->page]['Font'] != $fontout) || !isset($this->pageoutput[$this->page]['Font']))) {
4203 					$this->writer->write($fontout);
4204 				}
4205 				$this->pageoutput[$this->page]['Font'] = $fontout;
4206 			}
4207 
4208 			// Added - currentfont (lowercase) used in HTML2PDF
4209 			$this->currentfontfamily = $family;
4210 			$this->currentfontsize = $size;
4211 			$this->currentfontstyle = $style;
4212 			$this->setMBencoding('UTF-8');
4213 		} else {  // if using core fonts
4214 			if ($this->PDFA || $this->PDFX) {
4215 				throw new \Mpdf\MpdfException('Core Adobe fonts cannot be embedded in mPDF (required for PDFA1-b or PDFX/1-a) - cannot use option to use core fonts.');
4216 			}
4217 			$this->setMBencoding('windows-1252');
4218 
4219 			// Test if font is already selected
4220 			if (($this->FontFamily == $family) and ( $this->FontStyle == $style) and ( $this->FontSizePt == $size) && !$forcewrite) {
4221 				return $family;
4222 			}
4223 
4224 			if (!isset($this->CoreFonts[$fontkey])) {
4225 				if (in_array($family, $this->serif_fonts)) {
4226 					$family = 'ctimes';
4227 				} elseif (in_array($family, $this->mono_fonts)) {
4228 					$family = 'ccourier';
4229 				} else {
4230 					$family = 'chelvetica';
4231 				}
4232 				$this->usingCoreFont = true;
4233 				$fontkey = $family . $style;
4234 			}
4235 
4236 			if (!isset($this->fonts[$fontkey])) {
4237 				// STANDARD CORE FONTS
4238 				if (isset($this->CoreFonts[$fontkey])) {
4239 					// Load metric file
4240 					$file = $family;
4241 					if ($family == 'ctimes' || $family == 'chelvetica' || $family == 'ccourier') {
4242 						$file .= strtolower($style);
4243 					}
4244 					require __DIR__ . '/../data/font/' . $file . '.php';
4245 					if (!isset($cw)) {
4246 						throw new \Mpdf\MpdfException(sprintf('Could not include font metric file "%s"', $file));
4247 					}
4248 					$i = count($this->fonts) + $this->extraFontSubsets + 1;
4249 					$this->fonts[$fontkey] = ['i' => $i, 'type' => 'core', 'name' => $this->CoreFonts[$fontkey], 'desc' => $desc, 'up' => $up, 'ut' => $ut, 'cw' => $cw];
4250 					if ($this->useKerning && isset($kerninfo)) {
4251 						$this->fonts[$fontkey]['kerninfo'] = $kerninfo;
4252 					}
4253 				} else {
4254 					throw new \Mpdf\MpdfException(sprintf('Font %s not defined', $fontkey));
4255 				}
4256 			}
4257 
4258 			// Test if font is already selected
4259 			if (($this->FontFamily == $family) and ( $this->FontStyle == $style) and ( $this->FontSizePt == $size) && !$forcewrite) {
4260 				return $family;
4261 			}
4262 			// Select it
4263 			$this->FontFamily = $family;
4264 			$this->FontStyle = $style;
4265 			$this->FontSizePt = $size;
4266 			$this->FontSize = $size / Mpdf::SCALE;
4267 			$this->CurrentFont = &$this->fonts[$fontkey];
4268 			if ($write) {
4269 				$fontout = (sprintf('BT /F%d %.3F Tf ET', $this->CurrentFont['i'], $this->FontSizePt));
4270 				if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['Font']) && $this->pageoutput[$this->page]['Font'] != $fontout) || !isset($this->pageoutput[$this->page]['Font']))) {
4271 					$this->writer->write($fontout);
4272 				}
4273 				$this->pageoutput[$this->page]['Font'] = $fontout;
4274 			}
4275 			// Added - currentfont (lowercase) used in HTML2PDF
4276 			$this->currentfontfamily = $family;
4277 			$this->currentfontsize = $size;
4278 			$this->currentfontstyle = $style;
4279 		}
4280 
4281 		return $family;
4282 	}
4283 
4284 	function SetFontSize($size, $write = true)
4285 	{
4286 		// Set font size in points
4287 		if ($this->FontSizePt == $size) {
4288 			return;
4289 		}
4290 		$this->FontSizePt = $size;
4291 		$this->FontSize = $size / Mpdf::SCALE;
4292 		$this->currentfontsize = $size;
4293 		if ($write) {
4294 			$fontout = (sprintf('BT /F%d %.3F Tf ET', $this->CurrentFont['i'], $this->FontSizePt));
4295 			// Edited mPDF 3.0
4296 			if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['Font']) && $this->pageoutput[$this->page]['Font'] != $fontout) || !isset($this->pageoutput[$this->page]['Font']))) {
4297 				$this->writer->write($fontout);
4298 			}
4299 			$this->pageoutput[$this->page]['Font'] = $fontout;
4300 		}
4301 	}
4302 
4303 	function AddLink()
4304 	{
4305 		// Create a new internal link
4306 		$n = count($this->links) + 1;
4307 		$this->links[$n] = [0, 0];
4308 		return $n;
4309 	}
4310 
4311 	function SetLink($link, $y = 0, $page = -1)
4312 	{
4313 		// Set destination of internal link
4314 		if ($y == -1) {
4315 			$y = $this->y;
4316 		}
4317 		if ($page == -1) {
4318 			$page = $this->page;
4319 		}
4320 		$this->links[$link] = [$page, $y];
4321 	}
4322 
4323 	function Link($x, $y, $w, $h, $link)
4324 	{
4325 		$l = [$x * Mpdf::SCALE, $this->hPt - $y * Mpdf::SCALE, $w * Mpdf::SCALE, $h * Mpdf::SCALE, $link];
4326 		if ($this->keep_block_together) { // don't write yet
4327 			return;
4328 		} elseif ($this->table_rotate) { // *TABLES*
4329 			$this->tbrot_Links[$this->page][] = $l; // *TABLES*
4330 			return; // *TABLES*
4331 		} // *TABLES*
4332 		elseif ($this->kwt) {
4333 			$this->kwt_Links[$this->page][] = $l;
4334 			return;
4335 		}
4336 
4337 		if ($this->writingHTMLheader || $this->writingHTMLfooter) {
4338 			$this->HTMLheaderPageLinks[] = $l;
4339 			return;
4340 		}
4341 		// Put a link on the page
4342 		$this->PageLinks[$this->page][] = $l;
4343 		// Save cross-reference to Column buffer
4344 		$ref = count($this->PageLinks[$this->page]) - 1; // *COLUMNS*
4345 		$this->columnLinks[$this->CurrCol][(int) $this->x][(int) $this->y] = $ref; // *COLUMNS*
4346 	}
4347 
4348 	function Text($x, $y, $txt, $OTLdata = [], $textvar = 0, $aixextra = '', $coordsys = '', $return = false)
4349 	{
4350 		// Output (or return) a string
4351 		// Called (internally) by Watermark() & _tableWrite() [rotated cells] & TableHeaderFooter() & WriteText()
4352 		// Called also from classes/svg.php
4353 		// Expects Font to be set
4354 		// Expects input to be mb_encoded if necessary and RTL reversed & OTL processed
4355 		// ARTIFICIAL BOLD AND ITALIC
4356 		$s = 'q ';
4357 		if ($this->falseBoldWeight && strpos($this->ReqFontStyle, "B") !== false && strpos($this->FontStyle, "B") === false) {
4358 			$s .= '2 Tr 1 J 1 j ';
4359 			$s .= sprintf('%.3F w ', ($this->FontSize / 130) * Mpdf::SCALE * $this->falseBoldWeight);
4360 			$tc = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
4361 			if ($this->FillColor != $tc) {
4362 				$s .= $tc . ' ';
4363 			}  // stroke (outline) = same colour as text(fill)
4364 		}
4365 		if (strpos($this->ReqFontStyle, "I") !== false && strpos($this->FontStyle, "I") === false) {
4366 			$aix = '1 0 0.261799 1 %.3F %.3F Tm';
4367 		} else {
4368 			$aix = '%.3F %.3F Td';
4369 		}
4370 
4371 		$aix = $aixextra . $aix;
4372 
4373 		if ($this->ColorFlag) {
4374 			$s .= $this->TextColor . ' ';
4375 		}
4376 
4377 		$this->CurrentFont['used'] = true;
4378 
4379 		if ($this->usingCoreFont) {
4380 			$txt2 = str_replace(chr(160), chr(32), $txt);
4381 		} else {
4382 			$txt2 = str_replace(chr(194) . chr(160), chr(32), $txt);
4383 		}
4384 
4385 		$px = $x;
4386 		$py = $y;
4387 		if ($coordsys != 'SVG') {
4388 			$px = $x * Mpdf::SCALE;
4389 			$py = ($this->h - $y) * Mpdf::SCALE;
4390 		}
4391 
4392 
4393 		/** ************** SIMILAR TO Cell() ************************ */
4394 
4395 		// IF corefonts AND NOT SmCaps AND NOT Kerning
4396 		// Just output text
4397 		if ($this->usingCoreFont && !($textvar & TextVars::FC_SMALLCAPS) && !($textvar & TextVars::FC_KERNING)) {
4398 			$txt2 = $this->writer->escape($txt2);
4399 			$s .= sprintf('BT ' . $aix . ' (%s) Tj ET', $px, $py, $txt2);
4400 		} // IF NOT corefonts [AND NO wordspacing] AND NOT SIP/SMP AND NOT SmCaps AND NOT Kerning AND NOT OTL
4401 		// Just output text
4402 		elseif (!$this->usingCoreFont && !($textvar & TextVars::FC_SMALLCAPS) && !($textvar & TextVars::FC_KERNING) && !(isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF) && !empty($OTLdata['GPOSinfo']))) {
4403 			// IF SIP/SMP
4404 			if ($this->CurrentFont['sip'] || $this->CurrentFont['smp']) {
4405 				$txt2 = $this->UTF8toSubset($txt2);
4406 				$s .=sprintf('BT ' . $aix . ' %s Tj ET', $px, $py, $txt2);
4407 			} // NOT SIP/SMP
4408 			else {
4409 				$txt2 = $this->writer->utf8ToUtf16BigEndian($txt2, false);
4410 				$txt2 = $this->writer->escape($txt2);
4411 				$s .=sprintf('BT ' . $aix . ' (%s) Tj ET', $px, $py, $txt2);
4412 			}
4413 		} // IF NOT corefonts [AND IS wordspacing] AND NOT SIP AND NOT SmCaps AND NOT Kerning AND NOT OTL
4414 		// Not required here (cf. Cell() )
4415 		// ELSE (IF SmCaps || Kerning || OTL) [corefonts or not corefonts; SIP or SMP or BMP]
4416 		else {
4417 			$s .= $this->applyGPOSpdf($txt2, $aix, $px, $py, $OTLdata, $textvar);
4418 		}
4419 		/*         * ************** END ************************ */
4420 
4421 		$s .= ' ';
4422 
4423 		if (($textvar & TextVars::FD_UNDERLINE) && $txt != '') { // mPDF 5.7.1
4424 			$c = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
4425 			if ($this->FillColor != $c) {
4426 				$s.= ' ' . $c . ' ';
4427 			}
4428 			if (isset($this->CurrentFont['up']) && $this->CurrentFont['up']) {
4429 				$up = $this->CurrentFont['up'];
4430 			} else {
4431 				$up = -100;
4432 			}
4433 			$adjusty = (-$up / 1000 * $this->FontSize);
4434 			if (isset($this->CurrentFont['ut']) && $this->CurrentFont['ut']) {
4435 				$ut = $this->CurrentFont['ut'] / 1000 * $this->FontSize;
4436 			} else {
4437 				$ut = 60 / 1000 * $this->FontSize;
4438 			}
4439 			$olw = $this->LineWidth;
4440 			$s .= ' ' . (sprintf(' %.3F w', $ut * Mpdf::SCALE));
4441 			$s .= ' ' . $this->_dounderline($x, $y + $adjusty, $txt, $OTLdata, $textvar);
4442 			$s .= ' ' . (sprintf(' %.3F w', $olw * Mpdf::SCALE));
4443 			if ($this->FillColor != $c) {
4444 				$s.= ' ' . $this->FillColor . ' ';
4445 			}
4446 		}
4447 		// STRIKETHROUGH
4448 		if (($textvar & TextVars::FD_LINETHROUGH) && $txt != '') { // mPDF 5.7.1
4449 			$c = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
4450 			if ($this->FillColor != $c) {
4451 				$s.= ' ' . $c . ' ';
4452 			}
4453 			// Superscript and Subscript Y coordinate adjustment (now for striked-through texts)
4454 			if (isset($this->CurrentFont['desc']['CapHeight']) && $this->CurrentFont['desc']['CapHeight']) {
4455 				$ch = $this->CurrentFont['desc']['CapHeight'];
4456 			} else {
4457 				$ch = 700;
4458 			}
4459 			$adjusty = (-$ch / 1000 * $this->FontSize) * 0.35;
4460 			if (isset($this->CurrentFont['ut']) && $this->CurrentFont['ut']) {
4461 				$ut = $this->CurrentFont['ut'] / 1000 * $this->FontSize;
4462 			} else {
4463 				$ut = 60 / 1000 * $this->FontSize;
4464 			}
4465 			$olw = $this->LineWidth;
4466 			$s .= ' ' . (sprintf(' %.3F w', $ut * Mpdf::SCALE));
4467 			$s .= ' ' . $this->_dounderline($x, $y + $adjusty, $txt, $OTLdata, $textvar);
4468 			$s .= ' ' . (sprintf(' %.3F w', $olw * Mpdf::SCALE));
4469 			if ($this->FillColor != $c) {
4470 				$s.= ' ' . $this->FillColor . ' ';
4471 			}
4472 		}
4473 		$s .= 'Q';
4474 
4475 		if ($return) {
4476 			return $s . " \n";
4477 		}
4478 		$this->writer->write($s);
4479 	}
4480 
4481 	/* -- DIRECTW -- */
4482 
4483 	function WriteText($x, $y, $txt)
4484 	{
4485 		// Output a string using Text() but does encoding and text reversing of RTL
4486 		$txt = $this->purify_utf8_text($txt);
4487 		if ($this->text_input_as_HTML) {
4488 			$txt = $this->all_entities_to_utf8($txt);
4489 		}
4490 		if ($this->usingCoreFont) {
4491 			$txt = mb_convert_encoding($txt, $this->mb_enc, 'UTF-8');
4492 		}
4493 
4494 		// DIRECTIONALITY
4495 		if (preg_match("/([" . $this->pregRTLchars . "])/u", $txt)) {
4496 			$this->biDirectional = true;
4497 		} // *OTL*
4498 
4499 		$textvar = 0;
4500 		$save_OTLtags = $this->OTLtags;
4501 		$this->OTLtags = [];
4502 		if ($this->useKerning) {
4503 			if ($this->CurrentFont['haskernGPOS']) {
4504 				$this->OTLtags['Plus'] .= ' kern';
4505 			} else {
4506 				$textvar = ($textvar | TextVars::FC_KERNING);
4507 			}
4508 		}
4509 
4510 		/* -- OTL -- */
4511 		// Use OTL OpenType Table Layout - GSUB & GPOS
4512 		if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
4513 			$txt = $this->otl->applyOTL($txt, $this->CurrentFont['useOTL']);
4514 			$OTLdata = $this->otl->OTLdata;
4515 		}
4516 		/* -- END OTL -- */
4517 		$this->OTLtags = $save_OTLtags;
4518 
4519 		$this->magic_reverse_dir($txt, $this->directionality, $OTLdata);
4520 
4521 		$this->Text($x, $y, $txt, $OTLdata, $textvar);
4522 	}
4523 
4524 	function WriteCell($w, $h = 0, $txt = '', $border = 0, $ln = 0, $align = '', $fill = 0, $link = '', $currentx = 0)
4525 	{
4526 		// Output a cell using Cell() but does encoding and text reversing of RTL
4527 		$txt = $this->purify_utf8_text($txt);
4528 		if ($this->text_input_as_HTML) {
4529 			$txt = $this->all_entities_to_utf8($txt);
4530 		}
4531 		if ($this->usingCoreFont) {
4532 			$txt = mb_convert_encoding($txt, $this->mb_enc, 'UTF-8');
4533 		}
4534 		// DIRECTIONALITY
4535 		if (preg_match("/([" . $this->pregRTLchars . "])/u", $txt)) {
4536 			$this->biDirectional = true;
4537 		} // *OTL*
4538 
4539 		$textvar = 0;
4540 		$save_OTLtags = $this->OTLtags;
4541 		$this->OTLtags = [];
4542 		if ($this->useKerning) {
4543 			if ($this->CurrentFont['haskernGPOS']) {
4544 				$this->OTLtags['Plus'] .= ' kern';
4545 			} else {
4546 				$textvar = ($textvar | TextVars::FC_KERNING);
4547 			}
4548 		}
4549 
4550 		/* -- OTL -- */
4551 		// Use OTL OpenType Table Layout - GSUB & GPOS
4552 		if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
4553 			$txt = $this->otl->applyOTL($txt, $this->CurrentFont['useOTL']);
4554 			$OTLdata = $this->otl->OTLdata;
4555 		}
4556 		/* -- END OTL -- */
4557 		$this->OTLtags = $save_OTLtags;
4558 
4559 		$this->magic_reverse_dir($txt, $this->directionality, $OTLdata);
4560 
4561 		$this->Cell($w, $h, $txt, $border, $ln, $align, $fill, $link, $currentx, 0, 0, 'M', 0, false, $OTLdata, $textvar);
4562 	}
4563 
4564 	/* -- END DIRECTW -- */
4565 
4566 	function ResetSpacing()
4567 	{
4568 		if ($this->ws != 0) {
4569 			$this->writer->write('BT 0 Tw ET');
4570 		}
4571 		$this->ws = 0;
4572 		if ($this->charspacing != 0) {
4573 			$this->writer->write('BT 0 Tc ET');
4574 		}
4575 		$this->charspacing = 0;
4576 	}
4577 
4578 	function SetSpacing($cs, $ws)
4579 	{
4580 		if (intval($cs * 1000) == 0) {
4581 			$cs = 0;
4582 		}
4583 		if ($cs) {
4584 			$this->writer->write(sprintf('BT %.3F Tc ET', $cs));
4585 		} elseif ($this->charspacing != 0) {
4586 			$this->writer->write('BT 0 Tc ET');
4587 		}
4588 		$this->charspacing = $cs;
4589 		if (intval($ws * 1000) == 0) {
4590 			$ws = 0;
4591 		}
4592 		if ($ws) {
4593 			$this->writer->write(sprintf('BT %.3F Tw ET', $ws));
4594 		} elseif ($this->ws != 0) {
4595 			$this->writer->write('BT 0 Tw ET');
4596 		}
4597 		$this->ws = $ws;
4598 	}
4599 
4600 	// WORD SPACING
4601 	function GetJspacing($nc, $ns, $w, $inclCursive, &$cOTLdata)
4602 	{
4603 		$kashida_present = false;
4604 		$kashida_space = 0;
4605 		if ($w > 0 && $inclCursive && isset($this->CurrentFont['useKashida']) && $this->CurrentFont['useKashida'] && !empty($cOTLdata)) {
4606 			for ($c = 0; $c < count($cOTLdata); $c++) {
4607 				for ($i = 0; $i < strlen($cOTLdata[$c]['group']); $i++) {
4608 					if (isset($cOTLdata[$c]['GPOSinfo'][$i]['kashida']) && $cOTLdata[$c]['GPOSinfo'][$i]['kashida'] > 0) {
4609 						$kashida_present = true;
4610 						break 2;
4611 					}
4612 				}
4613 			}
4614 		}
4615 
4616 		if ($kashida_present) {
4617 			$k_ctr = 0;  // Number of kashida points
4618 			$k_total = 0;  // Total of kashida values (priority)
4619 			// Reset word
4620 			$max_kashida_in_word = 0;
4621 			$last_kashida_in_word = -1;
4622 
4623 			for ($c = 0; $c < count($cOTLdata); $c++) {
4624 				for ($i = 0; $i < strlen($cOTLdata[$c]['group']); $i++) {
4625 					if ($cOTLdata[$c]['group'][$i] == 'S') {
4626 						// Save from last word
4627 						if ($max_kashida_in_word) {
4628 							$k_ctr++;
4629 							$k_total = $max_kashida_in_word;
4630 						}
4631 						// Reset word
4632 						$max_kashida_in_word = 0;
4633 						$last_kashida_in_word = -1;
4634 					}
4635 
4636 					if (isset($cOTLdata[$c]['GPOSinfo'][$i]['kashida']) && $cOTLdata[$c]['GPOSinfo'][$i]['kashida'] > 0) {
4637 						if ($max_kashida_in_word) {
4638 							if ($cOTLdata[$c]['GPOSinfo'][$i]['kashida'] > $max_kashida_in_word) {
4639 								$max_kashida_in_word = $cOTLdata[$c]['GPOSinfo'][$i]['kashida'];
4640 								$cOTLdata[$c]['GPOSinfo'][$last_kashida_in_word]['kashida'] = 0;
4641 								$last_kashida_in_word = $i;
4642 							} else {
4643 								$cOTLdata[$c]['GPOSinfo'][$i]['kashida'] = 0;
4644 							}
4645 						} else {
4646 							$max_kashida_in_word = $cOTLdata[$c]['GPOSinfo'][$i]['kashida'];
4647 							$last_kashida_in_word = $i;
4648 						}
4649 					}
4650 				}
4651 			}
4652 			// Save from last word
4653 			if ($max_kashida_in_word) {
4654 				$k_ctr++;
4655 				$k_total = $max_kashida_in_word;
4656 			}
4657 
4658 			// Number of kashida points = $k_ctr
4659 			// $useKashida is a % value from CurrentFont/config_fonts.php
4660 			// % ratio divided between word-spacing and kashida-spacing
4661 			$kashida_space_ratio = intval($this->CurrentFont['useKashida']) / 100;
4662 
4663 
4664 			$kashida_space = $w * $kashida_space_ratio;
4665 
4666 			$tatw = $this->_getCharWidth($this->CurrentFont['cw'], 0x0640);
4667 			// Only use kashida if each allocated kashida width is > 0.01 x width of a tatweel
4668 			// Otherwise fontstretch is too small and errors
4669 			// If not just leave to adjust word-spacing
4670 			if ($tatw && (($kashida_space / $k_ctr) / $tatw) > 0.01) {
4671 				for ($c = 0; $c < count($cOTLdata); $c++) {
4672 					for ($i = 0; $i < strlen($cOTLdata[$c]['group']); $i++) {
4673 						if (isset($cOTLdata[$c]['GPOSinfo'][$i]['kashida']) && $cOTLdata[$c]['GPOSinfo'][$i]['kashida'] > 0) {
4674 							// At this point kashida is a number representing priority (higher number - higher priority)
4675 							// We are now going to set it as an actual length
4676 							// This shares it equally amongst words:
4677 							$cOTLdata[$c]['GPOSinfo'][$i]['kashida_space'] = (1 / $k_ctr) * $kashida_space;
4678 						}
4679 					}
4680 				}
4681 				$w -= $kashida_space;
4682 			}
4683 		}
4684 
4685 		$ws = 0;
4686 		$charspacing = 0;
4687 		$ww = $this->jSWord;
4688 		$ncx = $nc - 1;
4689 		if ($nc == 0) {
4690 			return [0, 0, 0];
4691 		} // Only word spacing allowed / possible
4692 		elseif ($this->fixedlSpacing !== false || $inclCursive) {
4693 			if ($ns) {
4694 				$ws = $w / $ns;
4695 			}
4696 		} elseif ($nc == 1) {
4697 			$charspacing = $w;
4698 		} elseif (!$ns) {
4699 			$charspacing = $w / ($ncx );
4700 			if (($this->jSmaxChar > 0) && ($charspacing > $this->jSmaxChar)) {
4701 				$charspacing = $this->jSmaxChar;
4702 			}
4703 		} elseif ($ns == ($ncx )) {
4704 			$charspacing = $w / $ns;
4705 		} else {
4706 			if ($this->usingCoreFont) {
4707 				$cs = ($w * (1 - $this->jSWord)) / ($ncx );
4708 				if (($this->jSmaxChar > 0) && ($cs > $this->jSmaxChar)) {
4709 					$cs = $this->jSmaxChar;
4710 					$ww = 1 - (($cs * ($ncx )) / $w);
4711 				}
4712 				$charspacing = $cs;
4713 				$ws = ($w * ($ww) ) / $ns;
4714 			} else {
4715 				$cs = ($w * (1 - $this->jSWord)) / ($ncx - $ns);
4716 				if (($this->jSmaxChar > 0) && ($cs > $this->jSmaxChar)) {
4717 					$cs = $this->jSmaxChar;
4718 					$ww = 1 - (($cs * ($ncx - $ns)) / $w);
4719 				}
4720 				$charspacing = $cs;
4721 				$ws = (($w * ($ww) ) / $ns) - $charspacing;
4722 			}
4723 		}
4724 		return [$charspacing, $ws, $kashida_space];
4725 	}
4726 
4727 	/**
4728 	 * Output a cell
4729 	 *
4730 	 * Expects input to be mb_encoded if necessary and RTL reversed
4731 	 *
4732 	 * @since mPDF 5.7.1
4733 	 */
4734 	function Cell($w, $h = 0, $txt = '', $border = 0, $ln = 0, $align = '', $fill = 0, $link = '', $currentx = 0, $lcpaddingL = 0, $lcpaddingR = 0, $valign = 'M', $spanfill = 0, $exactWidth = false, $OTLdata = false, $textvar = 0, $lineBox = false)
4735 	{
4736 		// NON_BREAKING SPACE
4737 		if ($this->usingCoreFont) {
4738 			$txt = str_replace(chr(160), chr(32), $txt);
4739 		} else {
4740 			$txt = str_replace(chr(194) . chr(160), chr(32), $txt);
4741 		}
4742 
4743 		$oldcolumn = $this->CurrCol;
4744 
4745 		// Automatic page break
4746 		// Allows PAGE-BREAK-AFTER = avoid to work
4747 		if (isset($this->blk[$this->blklvl])) {
4748 			$bottom = $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['margin_bottom'];
4749 		} else {
4750 			$bottom = 0;
4751 		}
4752 
4753 		if (!$this->tableLevel
4754 			&& (
4755 				($this->y + $this->divheight > $this->PageBreakTrigger)
4756 				|| ($this->y + $h > $this->PageBreakTrigger)
4757 				|| (
4758 					$this->y + ($h * 2) + $bottom > $this->PageBreakTrigger
4759 						&& (isset($this->blk[$this->blklvl]['page_break_after_avoid']) && $this->blk[$this->blklvl]['page_break_after_avoid'])
4760 				)
4761 			)
4762 			&& !$this->InFooter
4763 			&& $this->AcceptPageBreak()
4764 		) { // mPDF 5.7.2
4765 
4766 			$x = $this->x; // Current X position
4767 
4768 			// WORD SPACING
4769 			$ws = $this->ws; // Word Spacing
4770 			$charspacing = $this->charspacing; // Character Spacing
4771 			$this->ResetSpacing();
4772 
4773 			$this->AddPage($this->CurOrientation);
4774 
4775 			// Added to correct for OddEven Margins
4776 			$x += $this->MarginCorrection;
4777 			if ($currentx) {
4778 				$currentx += $this->MarginCorrection;
4779 			}
4780 			$this->x = $x;
4781 			// WORD SPACING
4782 			$this->SetSpacing($charspacing, $ws);
4783 		}
4784 
4785 		// Test: to put line through centre of cell: $this->Line($this->x,$this->y+($h/2),$this->x+50,$this->y+($h/2));
4786 		// Test: to put border around cell as it is specified: $border='LRTB';
4787 
4788 		/* -- COLUMNS -- */
4789 		// COLS
4790 		// COLUMN CHANGE
4791 		if ($this->CurrCol != $oldcolumn) {
4792 			if ($currentx) {
4793 				$currentx += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
4794 			}
4795 			$this->x += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
4796 		}
4797 
4798 		// COLUMNS Update/overwrite the lowest bottom of printing y value for a column
4799 		if ($this->ColActive) {
4800 			if ($h) {
4801 				$this->ColDetails[$this->CurrCol]['bottom_margin'] = $this->y + $h;
4802 			} else {
4803 				$this->ColDetails[$this->CurrCol]['bottom_margin'] = $this->y + $this->divheight;
4804 			}
4805 		}
4806 		/* -- END COLUMNS -- */
4807 
4808 
4809 		if ($w == 0) {
4810 			$w = $this->w - $this->rMargin - $this->x;
4811 		}
4812 
4813 		$s = '';
4814 		if ($fill == 1 && $this->FillColor) {
4815 			if ((isset($this->pageoutput[$this->page]['FillColor']) && $this->pageoutput[$this->page]['FillColor'] != $this->FillColor) || !isset($this->pageoutput[$this->page]['FillColor'])) {
4816 				$s .= $this->FillColor . ' ';
4817 			}
4818 			$this->pageoutput[$this->page]['FillColor'] = $this->FillColor;
4819 		}
4820 
4821 		if ($lineBox && isset($lineBox['boxtop']) && $txt) { // i.e. always from WriteFlowingBlock/finishFlowingBlock (but not objects -
4822 			// which only have $lineBox['top'] set)
4823 			$boxtop = $this->y + $lineBox['boxtop'];
4824 			$boxbottom = $this->y + $lineBox['boxbottom'];
4825 			$glyphYorigin = $lineBox['glyphYorigin'];
4826 			$baseline_shift = $lineBox['baseline-shift'];
4827 			$bord_boxtop = $bg_boxtop = $boxtop = $boxtop - $baseline_shift;
4828 			$bord_boxbottom = $bg_boxbottom = $boxbottom = $boxbottom - $baseline_shift;
4829 			$bord_boxheight = $bg_boxheight = $boxheight = $boxbottom - $boxtop;
4830 
4831 			// If inline element BACKGROUND has bounding box set by parent element:
4832 			if (isset($lineBox['background-boxtop'])) {
4833 				$bg_boxtop = $this->y + $lineBox['background-boxtop'] - $lineBox['background-baseline-shift'];
4834 				$bg_boxbottom = $this->y + $lineBox['background-boxbottom'] - $lineBox['background-baseline-shift'];
4835 				$bg_boxheight = $bg_boxbottom - $bg_boxtop;
4836 			}
4837 			// If inline element BORDER has bounding box set by parent element:
4838 			if (isset($lineBox['border-boxtop'])) {
4839 				$bord_boxtop = $this->y + $lineBox['border-boxtop'] - $lineBox['border-baseline-shift'];
4840 				$bord_boxbottom = $this->y + $lineBox['border-boxbottom'] - $lineBox['border-baseline-shift'];
4841 				$bord_boxheight = $bord_boxbottom - $bord_boxtop;
4842 			}
4843 
4844 		} else {
4845 
4846 			$boxtop = $this->y;
4847 			$boxheight = $h;
4848 			$boxbottom = $this->y + $h;
4849 			$baseline_shift = 0;
4850 
4851 			if ($txt != '') {
4852 
4853 				// FONT SIZE - this determines the baseline caculation
4854 				$bfs = $this->FontSize;
4855 				// Calculate baseline Superscript and Subscript Y coordinate adjustment
4856 				$bfx = $this->baselineC;
4857 				$baseline = $bfx * $bfs;
4858 
4859 				if ($textvar & TextVars::FA_SUPERSCRIPT) {
4860 					$baseline_shift = $this->textparam['text-baseline'];
4861 				} elseif ($textvar & TextVars::FA_SUBSCRIPT) {
4862 					$baseline_shift = $this->textparam['text-baseline'];
4863 				} elseif ($this->bullet) {
4864 					$baseline += ($bfx - 0.7) * $this->FontSize;
4865 				}
4866 
4867 				// Vertical align (for Images)
4868 				if ($valign == 'T') {
4869 					$va = (0.5 * $bfs * $this->normalLineheight);
4870 				} elseif ($valign == 'B') {
4871 					$va = $h - (0.5 * $bfs * $this->normalLineheight);
4872 				} else {
4873 					$va = 0.5 * $h;
4874 				} // Middle
4875 
4876 				// ONLY SET THESE IF WANT TO CONFINE BORDER +/- FILL TO FIT FONTSIZE - NOT FULL CELL AS IS ORIGINAL FUNCTION
4877 				// spanfill or spanborder are set in FlowingBlock functions
4878 				if ($spanfill || !empty($this->spanborddet) || $link != '') {
4879 					$exth = 0.2; // Add to fontsize to increase height of background / link / border
4880 					$boxtop = $this->y + $baseline + $va - ($this->FontSize * (1 + $exth / 2) * (0.5 + $bfx));
4881 					$boxheight = $this->FontSize * (1 + $exth);
4882 					$boxbottom = $boxtop + $boxheight;
4883 				}
4884 
4885 				$glyphYorigin = $baseline + $va;
4886 			}
4887 
4888 			$boxtop -= $baseline_shift;
4889 			$boxbottom -= $baseline_shift;
4890 			$bord_boxtop = $bg_boxtop = $boxtop;
4891 			$bord_boxbottom = $bg_boxbottom = $boxbottom;
4892 			$bord_boxheight = $bg_boxheight = $boxheight = $boxbottom - $boxtop;
4893 		}
4894 
4895 		$bbw = $tbw = $lbw = $rbw = 0; // Border widths
4896 		if (!empty($this->spanborddet)) {
4897 
4898 			if (!isset($this->spanborddet['B'])) {
4899 				$this->spanborddet['B'] = ['s' => 0, 'style' => '', 'w' => 0];
4900 			}
4901 
4902 			if (!isset($this->spanborddet['T'])) {
4903 				$this->spanborddet['T'] = ['s' => 0, 'style' => '', 'w' => 0];
4904 			}
4905 
4906 			if (!isset($this->spanborddet['L'])) {
4907 				$this->spanborddet['L'] = ['s' => 0, 'style' => '', 'w' => 0];
4908 			}
4909 
4910 			if (!isset($this->spanborddet['R'])) {
4911 				$this->spanborddet['R'] = ['s' => 0, 'style' => '', 'w' => 0];
4912 			}
4913 
4914 			$bbw = $this->spanborddet['B']['w'];
4915 			$tbw = $this->spanborddet['T']['w'];
4916 			$lbw = $this->spanborddet['L']['w'];
4917 			$rbw = $this->spanborddet['R']['w'];
4918 		}
4919 
4920 		if ($fill == 1 || $border == 1 || !empty($this->spanborddet)) {
4921 
4922 			if (!empty($this->spanborddet)) {
4923 
4924 				if ($fill == 1) {
4925 					$s .= sprintf('%.3F %.3F %.3F %.3F re f ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bg_boxtop + $tbw) * Mpdf::SCALE, ($w + $lbw + $rbw) * Mpdf::SCALE, (-$bg_boxheight - $tbw - $bbw) * Mpdf::SCALE);
4926 				}
4927 
4928 				$s.= ' q ';
4929 				$dashon = 3;
4930 				$dashoff = 3.5;
4931 				$dot = 2.5;
4932 
4933 				if ($tbw) {
4934 					$short = 0;
4935 
4936 					if ($this->spanborddet['T']['style'] == 'dashed') {
4937 						$s .= sprintf(' 0 j 0 J [%.3F %.3F] 0 d ', $tbw * $dashon * Mpdf::SCALE, $tbw * $dashoff * Mpdf::SCALE);
4938 					} elseif ($this->spanborddet['T']['style'] == 'dotted') {
4939 						$s .= sprintf(' 1 j 1 J [%.3F %.3F] %.3F d ', 0.001, $tbw * $dot * Mpdf::SCALE, -$tbw / 2 * Mpdf::SCALE);
4940 						$short = $tbw / 2;
4941 					} else {
4942 						$s .= ' 0 j 0 J [] 0 d ';
4943 					}
4944 
4945 					if ($this->spanborddet['T']['style'] != 'dotted') {
4946 						$s .= 'q ';
4947 						$s .= sprintf('%.3F %.3F m ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw) * Mpdf::SCALE);
4948 						$s .= sprintf('%.3F %.3F l ', ($this->x + $w + $rbw) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw) * Mpdf::SCALE);
4949 						$s .= sprintf('%.3F %.3F l ', ($this->x + $w) * Mpdf::SCALE, ($this->h - $bord_boxtop) * Mpdf::SCALE);
4950 						$s .= sprintf('%.3F %.3F l ', ($this->x) * Mpdf::SCALE, ($this->h - $bord_boxtop) * Mpdf::SCALE);
4951 						$s .= ' h W n '; // Ends path no-op & Sets the clipping path
4952 					}
4953 
4954 					$c = $this->SetDColor($this->spanborddet['T']['c'], true);
4955 
4956 					if ($this->spanborddet['T']['style'] == 'double') {
4957 						$s .= sprintf(' %s %.3F w ', $c, $tbw / 3 * Mpdf::SCALE);
4958 						$s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw * 5 / 6) * Mpdf::SCALE, ($this->x + $w + $rbw) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw * 5 / 6) * Mpdf::SCALE);
4959 						$s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw / 6) * Mpdf::SCALE, ($this->x + $w + $rbw) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw / 6) * Mpdf::SCALE);
4960 					} elseif ($this->spanborddet['T']['style'] == 'dotted') {
4961 						$s .= sprintf(' %s %.3F w ', $c, $tbw * Mpdf::SCALE);
4962 						$s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw / 2) * Mpdf::SCALE, ($this->x + $w + $rbw - $short) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw / 2) * Mpdf::SCALE);
4963 					} else {
4964 						$s .= sprintf(' %s %.3F w ', $c, $tbw * Mpdf::SCALE);
4965 						$s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw / 2) * Mpdf::SCALE, ($this->x + $w + $rbw - $short) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw / 2) * Mpdf::SCALE);
4966 					}
4967 
4968 					if ($this->spanborddet['T']['style'] != 'dotted') {
4969 						$s .= ' Q ';
4970 					}
4971 				}
4972 				if ($bbw) {
4973 
4974 					$short = 0;
4975 					if ($this->spanborddet['B']['style'] == 'dashed') {
4976 						$s .= sprintf(' 0 j 0 J [%.3F %.3F] 0 d ', $bbw * $dashon * Mpdf::SCALE, $bbw * $dashoff * Mpdf::SCALE);
4977 					} elseif ($this->spanborddet['B']['style'] == 'dotted') {
4978 						$s .= sprintf(' 1 j 1 J [%.3F %.3F] %.3F d ', 0.001, $bbw * $dot * Mpdf::SCALE, -$bbw / 2 * Mpdf::SCALE);
4979 						$short = $bbw / 2;
4980 					} else {
4981 						$s .= ' 0 j 0 J [] 0 d ';
4982 					}
4983 
4984 					if ($this->spanborddet['B']['style'] != 'dotted') {
4985 						$s .= 'q ';
4986 						$s .= sprintf('%.3F %.3F m ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw) * Mpdf::SCALE);
4987 						$s .= sprintf('%.3F %.3F l ', ($this->x + $w + $rbw) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw) * Mpdf::SCALE);
4988 						$s .= sprintf('%.3F %.3F l ', ($this->x + $w) * Mpdf::SCALE, ($this->h - $bord_boxbottom) * Mpdf::SCALE);
4989 						$s .= sprintf('%.3F %.3F l ', ($this->x) * Mpdf::SCALE, ($this->h - $bord_boxbottom) * Mpdf::SCALE);
4990 						$s .= ' h W n '; // Ends path no-op & Sets the clipping path
4991 					}
4992 
4993 					$c = $this->SetDColor($this->spanborddet['B']['c'], true);
4994 
4995 					if ($this->spanborddet['B']['style'] == 'double') {
4996 						$s .= sprintf(' %s %.3F w ', $c, $bbw / 3 * Mpdf::SCALE);
4997 						$s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw / 6) * Mpdf::SCALE, ($this->x + $w + $rbw - $short) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw / 6) * Mpdf::SCALE);
4998 						$s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw * 5 / 6) * Mpdf::SCALE, ($this->x + $w + $rbw - $short) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw * 5 / 6) * Mpdf::SCALE);
4999 					} elseif ($this->spanborddet['B']['style'] == 'dotted') {
5000 						$s .= sprintf(' %s %.3F w ', $c, $bbw * Mpdf::SCALE);
5001 						$s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw / 2) * Mpdf::SCALE, ($this->x + $w + $rbw - $short) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw / 2) * Mpdf::SCALE);
5002 					} else {
5003 						$s .= sprintf(' %s %.3F w ', $c, $bbw * Mpdf::SCALE);
5004 						$s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw / 2) * Mpdf::SCALE, ($this->x + $w + $rbw - $short) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw / 2) * Mpdf::SCALE);
5005 					}
5006 
5007 					if ($this->spanborddet['B']['style'] != 'dotted') {
5008 						$s .= ' Q ';
5009 					}
5010 				}
5011 
5012 				if ($lbw) {
5013 					$short = 0;
5014 					if ($this->spanborddet['L']['style'] == 'dashed') {
5015 						$s .= sprintf(' 0 j 0 J [%.3F %.3F] 0 d ', $lbw * $dashon * Mpdf::SCALE, $lbw * $dashoff * Mpdf::SCALE);
5016 					} elseif ($this->spanborddet['L']['style'] == 'dotted') {
5017 						$s .= sprintf(' 1 j 1 J [%.3F %.3F] %.3F d ', 0.001, $lbw * $dot * Mpdf::SCALE, -$lbw / 2 * Mpdf::SCALE);
5018 						$short = $lbw / 2;
5019 					} else {
5020 						$s .= ' 0 j 0 J [] 0 d ';
5021 					}
5022 
5023 					if ($this->spanborddet['L']['style'] != 'dotted') {
5024 						$s .= 'q ';
5025 						$s .= sprintf('%.3F %.3F m ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw) * Mpdf::SCALE);
5026 						$s .= sprintf('%.3F %.3F l ', ($this->x) * Mpdf::SCALE, ($this->h - $bord_boxbottom) * Mpdf::SCALE);
5027 						$s .= sprintf('%.3F %.3F l ', ($this->x) * Mpdf::SCALE, ($this->h - $bord_boxtop) * Mpdf::SCALE);
5028 						$s .= sprintf('%.3F %.3F l ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw) * Mpdf::SCALE);
5029 						$s .= ' h W n '; // Ends path no-op & Sets the clipping path
5030 					}
5031 
5032 					$c = $this->SetDColor($this->spanborddet['L']['c'], true);
5033 					if ($this->spanborddet['L']['style'] == 'double') {
5034 						$s .= sprintf(' %s %.3F w ', $c, $lbw / 3 * Mpdf::SCALE);
5035 						$s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw / 6) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw) * Mpdf::SCALE, ($this->x - $lbw / 6) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw + $short) * Mpdf::SCALE);
5036 						$s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw * 5 / 6) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw) * Mpdf::SCALE, ($this->x - $lbw * 5 / 6) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw + $short) * Mpdf::SCALE);
5037 					} elseif ($this->spanborddet['L']['style'] == 'dotted') {
5038 						$s .= sprintf(' %s %.3F w ', $c, $lbw * Mpdf::SCALE);
5039 						$s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw / 2) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw) * Mpdf::SCALE, ($this->x - $lbw / 2) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw + $short) * Mpdf::SCALE);
5040 					} else {
5041 						$s .= sprintf(' %s %.3F w ', $c, $lbw * Mpdf::SCALE);
5042 						$s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw / 2) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw) * Mpdf::SCALE, ($this->x - $lbw / 2) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw + $short) * Mpdf::SCALE);
5043 					}
5044 
5045 					if ($this->spanborddet['L']['style'] != 'dotted') {
5046 						$s .= ' Q ';
5047 					}
5048 				}
5049 
5050 				if ($rbw) {
5051 
5052 					$short = 0;
5053 					if ($this->spanborddet['R']['style'] == 'dashed') {
5054 						$s .= sprintf(' 0 j 0 J [%.3F %.3F] 0 d ', $rbw * $dashon * Mpdf::SCALE, $rbw * $dashoff * Mpdf::SCALE);
5055 					} elseif ($this->spanborddet['R']['style'] == 'dotted') {
5056 						$s .= sprintf(' 1 j 1 J [%.3F %.3F] %.3F d ', 0.001, $rbw * $dot * Mpdf::SCALE, -$rbw / 2 * Mpdf::SCALE);
5057 						$short = $rbw / 2;
5058 					} else {
5059 						$s .= ' 0 j 0 J [] 0 d ';
5060 					}
5061 
5062 					if ($this->spanborddet['R']['style'] != 'dotted') {
5063 						$s .= 'q ';
5064 						$s .= sprintf('%.3F %.3F m ', ($this->x + $w + $rbw) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw) * Mpdf::SCALE);
5065 						$s .= sprintf('%.3F %.3F l ', ($this->x + $w) * Mpdf::SCALE, ($this->h - $bord_boxbottom) * Mpdf::SCALE);
5066 						$s .= sprintf('%.3F %.3F l ', ($this->x + $w) * Mpdf::SCALE, ($this->h - $bord_boxtop) * Mpdf::SCALE);
5067 						$s .= sprintf('%.3F %.3F l ', ($this->x + $w + $rbw) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw) * Mpdf::SCALE);
5068 						$s .= ' h W n '; // Ends path no-op & Sets the clipping path
5069 					}
5070 
5071 					$c = $this->SetDColor($this->spanborddet['R']['c'], true);
5072 					if ($this->spanborddet['R']['style'] == 'double') {
5073 						$s .= sprintf(' %s %.3F w ', $c, $rbw / 3 * Mpdf::SCALE);
5074 						$s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x + $w + $rbw / 6) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw) * Mpdf::SCALE, ($this->x + $w + $rbw / 6) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw + $short) * Mpdf::SCALE);
5075 						$s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x + $w + $rbw * 5 / 6) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw) * Mpdf::SCALE, ($this->x + $w + $rbw * 5 / 6) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw + $short) * Mpdf::SCALE);
5076 					} elseif ($this->spanborddet['R']['style'] == 'dotted') {
5077 						$s .= sprintf(' %s %.3F w ', $c, $rbw * Mpdf::SCALE);
5078 						$s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x + $w + $rbw / 2) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw) * Mpdf::SCALE, ($this->x + $w + $rbw / 2) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw + $short) * Mpdf::SCALE);
5079 					} else {
5080 						$s .= sprintf(' %s %.3F w ', $c, $rbw * Mpdf::SCALE);
5081 						$s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x + $w + $rbw / 2) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw) * Mpdf::SCALE, ($this->x + $w + $rbw / 2) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw + $short) * Mpdf::SCALE);
5082 					}
5083 
5084 					if ($this->spanborddet['R']['style'] != 'dotted') {
5085 						$s .= ' Q ';
5086 					}
5087 				}
5088 
5089 				$s.= ' Q ';
5090 
5091 			} else { // If "border", does not come from WriteFlowingBlock or FinishFlowingBlock
5092 
5093 				if ($fill == 1) {
5094 					$op = ($border == 1) ? 'B' : 'f';
5095 				} else {
5096 					$op = 'S';
5097 				}
5098 
5099 				$s .= sprintf('%.3F %.3F %.3F %.3F re %s ', $this->x * Mpdf::SCALE, ($this->h - $bg_boxtop) * Mpdf::SCALE, $w * Mpdf::SCALE, -$bg_boxheight * Mpdf::SCALE, $op);
5100 			}
5101 		}
5102 
5103 		if (is_string($border)) { // If "border", does not come from WriteFlowingBlock or FinishFlowingBlock
5104 
5105 			$x = $this->x;
5106 			$y = $this->y;
5107 
5108 			if (is_int(strpos($border, 'L'))) {
5109 				$s .= sprintf('%.3F %.3F m %.3F %.3F l S ', $x * Mpdf::SCALE, ($this->h - $bord_boxtop) * Mpdf::SCALE, $x * Mpdf::SCALE, ($this->h - ($bord_boxbottom)) * Mpdf::SCALE);
5110 			}
5111 
5112 			if (is_int(strpos($border, 'T'))) {
5113 				$s .= sprintf('%.3F %.3F m %.3F %.3F l S ', $x * Mpdf::SCALE, ($this->h - $bord_boxtop) * Mpdf::SCALE, ($x + $w) * Mpdf::SCALE, ($this->h - $bord_boxtop) * Mpdf::SCALE);
5114 			}
5115 
5116 			if (is_int(strpos($border, 'R'))) {
5117 				$s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($x + $w) * Mpdf::SCALE, ($this->h - $bord_boxtop) * Mpdf::SCALE, ($x + $w) * Mpdf::SCALE, ($this->h - ($bord_boxbottom)) * Mpdf::SCALE);
5118 			}
5119 
5120 			if (is_int(strpos($border, 'B'))) {
5121 				$s .= sprintf('%.3F %.3F m %.3F %.3F l S ', $x * Mpdf::SCALE, ($this->h - ($bord_boxbottom)) * Mpdf::SCALE, ($x + $w) * Mpdf::SCALE, ($this->h - ($bord_boxbottom)) * Mpdf::SCALE);
5122 			}
5123 		}
5124 
5125 		if ($txt != '') {
5126 
5127 			if ($exactWidth) {
5128 				$stringWidth = $w;
5129 			} else {
5130 				$stringWidth = $this->GetStringWidth($txt, true, $OTLdata, $textvar) + ( $this->charspacing * mb_strlen($txt, $this->mb_enc) / Mpdf::SCALE ) + ( $this->ws * mb_substr_count($txt, ' ', $this->mb_enc) / Mpdf::SCALE );
5131 			}
5132 
5133 			// Set x OFFSET FOR PRINTING
5134 			if ($align == 'R') {
5135 				$dx = $w - $this->cMarginR - $stringWidth - $lcpaddingR;
5136 			} elseif ($align == 'C') {
5137 				$dx = (($w - $stringWidth ) / 2);
5138 			} elseif ($align == 'L' or $align == 'J') {
5139 				$dx = $this->cMarginL + $lcpaddingL;
5140 			} else {
5141 				$dx = 0;
5142 			}
5143 
5144 			if ($this->ColorFlag) {
5145 				$s .='q ' . $this->TextColor . ' ';
5146 			}
5147 
5148 			// OUTLINE
5149 			if (isset($this->textparam['outline-s']) && $this->textparam['outline-s'] && !($textvar & TextVars::FC_SMALLCAPS)) { // mPDF 5.7.1
5150 				$s .=' ' . sprintf('%.3F w', $this->LineWidth * Mpdf::SCALE) . ' ';
5151 				$s .=" $this->DrawColor ";
5152 				$s .=" 2 Tr ";
5153 			} elseif ($this->falseBoldWeight && strpos($this->ReqFontStyle, "B") !== false && strpos($this->FontStyle, "B") === false && !($textvar & TextVars::FC_SMALLCAPS)) { // can't use together with OUTLINE or Small Caps	// mPDF 5.7.1	??? why not with SmallCaps ???
5154 				$s .= ' 2 Tr 1 J 1 j ';
5155 				$s .= ' ' . sprintf('%.3F w', ($this->FontSize / 130) * Mpdf::SCALE * $this->falseBoldWeight) . ' ';
5156 				$tc = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
5157 				if ($this->FillColor != $tc) {
5158 					$s .= ' ' . $tc . ' ';
5159 				}  // stroke (outline) = same colour as text(fill)
5160 			} else {
5161 				$s .=" 0 Tr ";
5162 			}
5163 
5164 			if (strpos($this->ReqFontStyle, "I") !== false && strpos($this->FontStyle, "I") === false) { // Artificial italic
5165 				$aix = '1 0 0.261799 1 %.3F %.3F Tm ';
5166 			} else {
5167 				$aix = '%.3F %.3F Td ';
5168 			}
5169 
5170 			$px = ($this->x + $dx) * Mpdf::SCALE;
5171 			$py = ($this->h - ($this->y + $glyphYorigin - $baseline_shift)) * Mpdf::SCALE;
5172 
5173 			// THE TEXT
5174 			$txt2 = $txt;
5175 			$sub = '';
5176 			$this->CurrentFont['used'] = true;
5177 
5178 			/*             * ************** SIMILAR TO Text() ************************ */
5179 
5180 			// IF corefonts AND NOT SmCaps AND NOT Kerning
5181 			// Just output text; charspacing and wordspacing already set by charspacing (Tc) and ws (Tw)
5182 			if ($this->usingCoreFont && !($textvar & TextVars::FC_SMALLCAPS) && !($textvar & TextVars::FC_KERNING)) {
5183 				$txt2 = $this->writer->escape($txt2);
5184 				$sub .= sprintf('BT ' . $aix . ' (%s) Tj ET', $px, $py, $txt2);
5185 			} // IF NOT corefonts AND NO wordspacing AND NOT SIP/SMP AND NOT SmCaps AND NOT Kerning AND NOT OTL
5186 			// Just output text
5187 			elseif (!$this->usingCoreFont && !$this->ws && !($textvar & TextVars::FC_SMALLCAPS) && !($textvar & TextVars::FC_KERNING) && !(isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF) && !empty($OTLdata['GPOSinfo']))) {
5188 				// IF SIP/SMP
5189 				if ((isset($this->CurrentFont['sip']) && $this->CurrentFont['sip']) || (isset($this->CurrentFont['smp']) && $this->CurrentFont['smp'])) {
5190 					$txt2 = $this->UTF8toSubset($txt2);
5191 					$sub .=sprintf('BT ' . $aix . ' %s Tj ET', $px, $py, $txt2);
5192 				} // NOT SIP/SMP
5193 				else {
5194 					$txt2 = $this->writer->utf8ToUtf16BigEndian($txt2, false);
5195 					$txt2 = $this->writer->escape($txt2);
5196 					$sub .=sprintf('BT ' . $aix . ' (%s) Tj ET', $px, $py, $txt2);
5197 				}
5198 			} // IF NOT corefonts AND IS wordspacing AND NOT SIP AND NOT SmCaps AND NOT Kerning AND NOT OTL
5199 			// Output text word by word with an adjustment to the intercharacter spacing for SPACEs to form word spacing
5200 			// IF multibyte - Tw has no effect - need to do word spacing using an adjustment before each space
5201 			elseif (!$this->usingCoreFont && $this->ws && !((isset($this->CurrentFont['sip']) && $this->CurrentFont['sip']) || (isset($this->CurrentFont['smp']) && $this->CurrentFont['smp'])) && !($textvar & TextVars::FC_SMALLCAPS) && !($textvar & TextVars::FC_KERNING) && !(isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF) && (!empty($OTLdata['GPOSinfo']) || (strpos($OTLdata['group'], 'M') !== false && $this->charspacing)) )) {
5202 				$space = " ";
5203 				$space = $this->writer->utf8ToUtf16BigEndian($space, false);
5204 				$space = $this->writer->escape($space);
5205 				$sub .=sprintf('BT ' . $aix . ' %.3F Tc [', $px, $py, $this->charspacing);
5206 				$t = explode(' ', $txt2);
5207 				$numt = count($t);
5208 				for ($i = 0; $i < $numt; $i++) {
5209 					$tx = $t[$i];
5210 					$tx = $this->writer->utf8ToUtf16BigEndian($tx, false);
5211 					$tx = $this->writer->escape($tx);
5212 					$sub .=sprintf('(%s) ', $tx);
5213 					if (($i + 1) < $numt) {
5214 						$adj = -($this->ws) * 1000 / $this->FontSizePt;
5215 						$sub .=sprintf('%d(%s) ', $adj, $space);
5216 					}
5217 				}
5218 				$sub .='] TJ ';
5219 				$sub .=' ET';
5220 			} // ELSE (IF SmCaps || Kerning || OTL) [corefonts or not corefonts; SIP or SMP or BMP]
5221 			else {
5222 				$sub = $this->applyGPOSpdf($txt, $aix, $px, $py, $OTLdata, $textvar);
5223 			}
5224 
5225 			/** ************** END SIMILAR TO Text() ************************ */
5226 
5227 			if ($this->shrin_k > 1) {
5228 				$shrin_k = $this->shrin_k;
5229 			} else {
5230 				$shrin_k = 1;
5231 			}
5232 
5233 			// UNDERLINE
5234 			if ($textvar & TextVars::FD_UNDERLINE) { // mPDF 5.7.1	// mPDF 6
5235 
5236 				// mPDF 5.7.3  inline text-decoration parameters
5237 
5238 				$c = isset($this->textparam['u-decoration']['color']) ? $this->textparam['u-decoration']['color'] : '';
5239 				if ($this->FillColor != $c) {
5240 					$sub .= ' ' . $c . ' ';
5241 				}
5242 
5243 				// mPDF 5.7.3  inline text-decoration parameters
5244 				$decorationfontkey = isset($this->textparam['u-decoration']['fontkey']) ? $this->textparam['u-decoration']['fontkey'] : '';
5245 				$decorationfontsize = isset($this->textparam['u-decoration']['fontsize']) ? $this->textparam['u-decoration']['fontsize'] / $shrin_k : 0;
5246 
5247 				if (isset($this->fonts[$decorationfontkey]['ut']) && $this->fonts[$decorationfontkey]['ut']) {
5248 					$ut = $this->fonts[$decorationfontkey]['ut'] / 1000 * $decorationfontsize;
5249 				} else {
5250 					$ut = 60 / 1000 * $decorationfontsize;
5251 				}
5252 
5253 				if (isset($this->fonts[$decorationfontkey]['up']) && $this->fonts[$decorationfontkey]['up']) {
5254 					$up = $this->fonts[$decorationfontkey]['up'];
5255 				} else {
5256 					$up = -100;
5257 				}
5258 
5259 				$adjusty = (-$up / 1000 * $decorationfontsize) + $ut / 2;
5260 				$ubaseline = isset($this->textparam['u-decoration']['baseline'])
5261 					? $glyphYorigin - $this->textparam['u-decoration']['baseline'] / $shrin_k
5262 					: $glyphYorigin;
5263 
5264 				$olw = $this->LineWidth;
5265 
5266 				$sub .= ' ' . (sprintf(' %.3F w 0 j 0 J ', $ut * Mpdf::SCALE));
5267 				$sub .= ' ' . $this->_dounderline($this->x + $dx, $this->y + $ubaseline + $adjusty, $txt, $OTLdata, $textvar);
5268 				$sub .= ' ' . (sprintf(' %.3F w 2 j 2 J ', $olw * Mpdf::SCALE));
5269 
5270 				if ($this->FillColor != $c) {
5271 					$sub .= ' ' . $this->FillColor . ' ';
5272 				}
5273 			}
5274 
5275 			// STRIKETHROUGH
5276 			if ($textvar & TextVars::FD_LINETHROUGH) { // mPDF 5.7.1	// mPDF 6
5277 
5278 				// mPDF 5.7.3  inline text-decoration parameters
5279 				$c = $this->textparam['s-decoration']['color'];
5280 
5281 				if ($this->FillColor != $c) {
5282 					$sub .= ' ' . $c . ' ';
5283 				}
5284 
5285 				// mPDF 5.7.3  inline text-decoration parameters
5286 				$decorationfontkey = $this->textparam['s-decoration']['fontkey'];
5287 				$decorationfontsize = $this->textparam['s-decoration']['fontsize'] / $shrin_k;
5288 
5289 				// Use yStrikeoutSize from OS/2 if available
5290 				if (isset($this->fonts[$decorationfontkey]['strs']) && $this->fonts[$decorationfontkey]['strs']) {
5291 					$ut = $this->fonts[$decorationfontkey]['strs'] / 1000 * $decorationfontsize;
5292 				} // else use underlineThickness from post if available
5293 				elseif (isset($this->fonts[$decorationfontkey]['ut']) && $this->fonts[$decorationfontkey]['ut']) {
5294 					$ut = $this->fonts[$decorationfontkey]['ut'] / 1000 * $decorationfontsize;
5295 				} else {
5296 					$ut = 50 / 1000 * $decorationfontsize;
5297 				}
5298 
5299 				// Use yStrikeoutPosition from OS/2 if available
5300 				if (isset($this->fonts[$decorationfontkey]['strp']) && $this->fonts[$decorationfontkey]['strp']) {
5301 					$up = $this->fonts[$decorationfontkey]['strp'];
5302 					$adjusty = (-$up / 1000 * $decorationfontsize);
5303 				} // else use a fraction ($this->baselineS) of CapHeight
5304 				else {
5305 					if (isset($this->fonts[$decorationfontkey]['desc']['CapHeight']) && $this->fonts[$decorationfontkey]['desc']['CapHeight']) {
5306 						$ch = $this->fonts[$decorationfontkey]['desc']['CapHeight'];
5307 					} else {
5308 						$ch = 700;
5309 					}
5310 					$adjusty = (-$ch / 1000 * $decorationfontsize) * $this->baselineS;
5311 				}
5312 
5313 				$sbaseline = $glyphYorigin - $this->textparam['s-decoration']['baseline'] / $shrin_k;
5314 
5315 				$olw = $this->LineWidth;
5316 
5317 				$sub .=' ' . (sprintf(' %.3F w 0 j 0 J ', $ut * Mpdf::SCALE));
5318 				$sub .=' ' . $this->_dounderline($this->x + $dx, $this->y + $sbaseline + $adjusty, $txt, $OTLdata, $textvar);
5319 				$sub .=' ' . (sprintf(' %.3F w 2 j 2 J ', $olw * Mpdf::SCALE));
5320 
5321 				if ($this->FillColor != $c) {
5322 					$sub .= ' ' . $this->FillColor . ' ';
5323 				}
5324 			}
5325 
5326 			// mPDF 5.7.3  inline text-decoration parameters
5327 			// OVERLINE
5328 			if ($textvar & TextVars::FD_OVERLINE) { // mPDF 5.7.1	// mPDF 6
5329 				// mPDF 5.7.3  inline text-decoration parameters
5330 				$c = $this->textparam['o-decoration']['color'];
5331 				if ($this->FillColor != $c) {
5332 					$sub .= ' ' . $c . ' ';
5333 				}
5334 
5335 				// mPDF 5.7.3  inline text-decoration parameters
5336 				$decorationfontkey = (int) (((float) $this->textparam['o-decoration']['fontkey']) / $shrin_k);
5337 				$decorationfontsize = $this->textparam['o-decoration']['fontsize'];
5338 
5339 				if (isset($this->fonts[$decorationfontkey]['ut']) && $this->fonts[$decorationfontkey]['ut']) {
5340 					$ut = $this->fonts[$decorationfontkey]['ut'] / 1000 * $decorationfontsize;
5341 				} else {
5342 					$ut = 60 / 1000 * $decorationfontsize;
5343 				}
5344 				if (isset($this->fonts[$decorationfontkey]['desc']['CapHeight']) && $this->fonts[$decorationfontkey]['desc']['CapHeight']) {
5345 					$ch = $this->fonts[$decorationfontkey]['desc']['CapHeight'];
5346 				} else {
5347 					$ch = 700;
5348 				}
5349 				$adjusty = (-$ch / 1000 * $decorationfontsize) * $this->baselineO;
5350 				$obaseline = $glyphYorigin - $this->textparam['o-decoration']['baseline'] / $shrin_k;
5351 				$olw = $this->LineWidth;
5352 				$sub .=' ' . (sprintf(' %.3F w 0 j 0 J ', $ut * Mpdf::SCALE));
5353 				$sub .=' ' . $this->_dounderline($this->x + $dx, $this->y + $obaseline + $adjusty, $txt, $OTLdata, $textvar);
5354 				$sub .=' ' . (sprintf(' %.3F w 2 j 2 J ', $olw * Mpdf::SCALE));
5355 				if ($this->FillColor != $c) {
5356 					$sub .= ' ' . $this->FillColor . ' ';
5357 				}
5358 			}
5359 
5360 			// TEXT SHADOW
5361 			if ($this->textshadow) {  // First to process is last in CSS comma separated shadows
5362 				foreach ($this->textshadow as $ts) {
5363 					$s .= ' q ';
5364 					$s .= $this->SetTColor($ts['col'], true) . "\n";
5365 					if ($ts['col'][0] == 5 && ord($ts['col'][4]) < 100) { // RGBa
5366 						$s .= $this->SetAlpha(ord($ts['col'][4]) / 100, 'Normal', true, 'F') . "\n";
5367 					} elseif ($ts['col'][0] == 6 && ord($ts['col'][5]) < 100) { // CMYKa
5368 						$s .= $this->SetAlpha(ord($ts['col'][5]) / 100, 'Normal', true, 'F') . "\n";
5369 					} elseif ($ts['col'][0] == 1 && $ts['col'][2] == 1 && ord($ts['col'][3]) < 100) { // Gray
5370 						$s .= $this->SetAlpha(ord($ts['col'][3]) / 100, 'Normal', true, 'F') . "\n";
5371 					}
5372 					$s .= sprintf(' 1 0 0 1 %.4F %.4F cm', $ts['x'] * Mpdf::SCALE, -$ts['y'] * Mpdf::SCALE) . "\n";
5373 					$s .= $sub;
5374 					$s .= ' Q ';
5375 				}
5376 			}
5377 
5378 			$s .= $sub;
5379 
5380 			// COLOR
5381 			if ($this->ColorFlag) {
5382 				$s .=' Q';
5383 			}
5384 
5385 			// LINK
5386 			if ($link != '') {
5387 				$this->Link($this->x, $boxtop, $w, $boxheight, $link);
5388 			}
5389 		}
5390 		if ($s) {
5391 			$this->writer->write($s);
5392 		}
5393 
5394 		// WORD SPACING
5395 		if ($this->ws && !$this->usingCoreFont) {
5396 			$this->writer->write(sprintf('BT %.3F Tc ET', $this->charspacing));
5397 		}
5398 		$this->lasth = $h;
5399 		if (strpos($txt, "\n") !== false) {
5400 			$ln = 1; // cell recognizes \n from <BR> tag
5401 		}
5402 		if ($ln > 0) {
5403 			// Go to next line
5404 			$this->y += $h;
5405 			if ($ln == 1) {
5406 				// Move to next line
5407 				if ($currentx != 0) {
5408 					$this->x = $currentx;
5409 				} else {
5410 					$this->x = $this->lMargin;
5411 				}
5412 			}
5413 		} else {
5414 			$this->x+=$w;
5415 		}
5416 	}
5417 
5418 	function applyGPOSpdf($txt, $aix, $x, $y, $OTLdata, $textvar = 0)
5419 	{
5420 		// Generate PDF string
5421 		// ==============================
5422 		if ((isset($this->CurrentFont['sip']) && $this->CurrentFont['sip']) || (isset($this->CurrentFont['smp']) && $this->CurrentFont['smp'])) {
5423 			$sipset = true;
5424 		} else {
5425 			$sipset = false;
5426 		}
5427 
5428 		if ($textvar & TextVars::FC_SMALLCAPS) {
5429 			$smcaps = true;
5430 		} // IF SmallCaps using transformation, NOT OTL
5431 		else {
5432 			$smcaps = false;
5433 		}
5434 
5435 		if ($sipset) {
5436 			$fontid = $last_fontid = $original_fontid = $this->CurrentFont['subsetfontids'][0];
5437 		} else {
5438 			$fontid = $last_fontid = $original_fontid = $this->CurrentFont['i'];
5439 		}
5440 		$SmallCapsON = false;  // state: uppercase/not
5441 		$lastSmallCapsON = false; // state: uppercase/not
5442 		$last_fontsize = $fontsize = $this->FontSizePt;
5443 		$last_fontstretch = $fontstretch = 100;
5444 		$groupBreak = false;
5445 
5446 		$unicode = $this->UTF8StringToArray($txt);
5447 
5448 		$GPOSinfo = (isset($OTLdata['GPOSinfo']) ? $OTLdata['GPOSinfo'] : []);
5449 		$charspacing = ($this->charspacing * 1000 / $this->FontSizePt);
5450 		$wordspacing = ($this->ws * 1000 / $this->FontSizePt);
5451 
5452 		$XshiftBefore = 0;
5453 		$XshiftAfter = 0;
5454 		$lastYPlacement = 0;
5455 
5456 		if ($sipset) {
5457 			// mPDF 6  DELETED ********
5458 			// 	$txt= preg_replace('/'.preg_quote($this->aliasNbPg,'/').'/', chr(7), $txt);	// ? Need to adjust OTL info
5459 			// 	$txt= preg_replace('/'.preg_quote($this->aliasNbPgGp,'/').'/', chr(8), $txt);	// ? Need to adjust OTL info
5460 			$tj = '<';
5461 		} else {
5462 			$tj = '(';
5463 		}
5464 
5465 		for ($i = 0; $i < count($unicode); $i++) {
5466 			$c = $unicode[$i];
5467 			$tx = '';
5468 			$XshiftBefore = $XshiftAfter;
5469 			$XshiftAfter = 0;
5470 			$YPlacement = 0;
5471 			$groupBreak = false;
5472 			$kashida = 0;
5473 			if (!empty($OTLdata)) {
5474 				// YPlacement from GPOS
5475 				if (isset($GPOSinfo[$i]['YPlacement']) && $GPOSinfo[$i]['YPlacement']) {
5476 					$YPlacement = $GPOSinfo[$i]['YPlacement'] * $this->FontSizePt / $this->CurrentFont['unitsPerEm'];
5477 					$groupBreak = true;
5478 				}
5479 				// XPlacement from GPOS
5480 				if (isset($GPOSinfo[$i]['XPlacement']) && $GPOSinfo[$i]['XPlacement']) {
5481 					if (!isset($GPOSinfo[$i]['wDir']) || $GPOSinfo[$i]['wDir'] != 'RTL') {
5482 						if (isset($GPOSinfo[$i]['BaseWidth'])) {
5483 							$GPOSinfo[$i]['XPlacement'] -= $GPOSinfo[$i]['BaseWidth'];
5484 						}
5485 					}
5486 
5487 					// Convert to PDF Text space (thousandths of a unit );
5488 					$XshiftBefore += $GPOSinfo[$i]['XPlacement'] * 1000 / $this->CurrentFont['unitsPerEm'];
5489 					$XshiftAfter += -$GPOSinfo[$i]['XPlacement'] * 1000 / $this->CurrentFont['unitsPerEm'];
5490 				}
5491 
5492 				// Kashida from GPOS
5493 				// Kashida is set as an absolute length value, but to adjust text needs to be converted to
5494 				// font-related size
5495 				if (isset($GPOSinfo[$i]['kashida_space']) && $GPOSinfo[$i]['kashida_space']) {
5496 					$kashida = $GPOSinfo[$i]['kashida_space'];
5497 				}
5498 
5499 				if ($c == 32) { // word spacing
5500 					$XshiftAfter += $wordspacing;
5501 				}
5502 
5503 				if (substr($OTLdata['group'], ($i + 1), 1) != 'M') { // Don't add inter-character spacing before Marks
5504 					$XshiftAfter += $charspacing;
5505 				}
5506 
5507 				// ...applyGPOSpdf...
5508 				// XAdvance from GPOS - Convert to PDF Text space (thousandths of a unit );
5509 				if (((isset($GPOSinfo[$i]['wDir']) && $GPOSinfo[$i]['wDir'] != 'RTL') || !isset($GPOSinfo[$i]['wDir'])) && isset($GPOSinfo[$i]['XAdvanceL']) && $GPOSinfo[$i]['XAdvanceL']) {
5510 					$XshiftAfter += $GPOSinfo[$i]['XAdvanceL'] * 1000 / $this->CurrentFont['unitsPerEm'];
5511 				} elseif (isset($GPOSinfo[$i]['wDir']) && $GPOSinfo[$i]['wDir'] == 'RTL' && isset($GPOSinfo[$i]['XAdvanceR']) && $GPOSinfo[$i]['XAdvanceR']) {
5512 					$XshiftAfter += $GPOSinfo[$i]['XAdvanceR'] * 1000 / $this->CurrentFont['unitsPerEm'];
5513 				}
5514 			} // Character & Word spacing - if NOT OTL
5515 			else {
5516 				$XshiftAfter += $charspacing;
5517 				if ($c == 32) {
5518 					$XshiftAfter += $wordspacing;
5519 				}
5520 			}
5521 
5522 			// IF Kerning done using pairs rather than OTL
5523 			if ($textvar & TextVars::FC_KERNING) {
5524 				if ($i > 0 && isset($this->CurrentFont['kerninfo'][$unicode[($i - 1)]][$unicode[$i]])) {
5525 					$XshiftBefore += $this->CurrentFont['kerninfo'][$unicode[($i - 1)]][$unicode[$i]];
5526 				}
5527 			}
5528 
5529 			if ($YPlacement != $lastYPlacement) {
5530 				$groupBreak = true;
5531 			}
5532 
5533 			if ($XshiftBefore) {  // +ve value in PDF moves to the left
5534 				// If Fontstretch is ongoing, need to adjust X adjustments because these will be stretched out.
5535 				$XshiftBefore *= 100 / $last_fontstretch;
5536 				if ($sipset) {
5537 					$tj .= sprintf('>%d<', (-$XshiftBefore));
5538 				} else {
5539 					$tj .= sprintf(')%d(', (-$XshiftBefore));
5540 				}
5541 			}
5542 
5543 			// Small-Caps
5544 			if ($smcaps) {
5545 				if (isset($this->upperCase[$c])) {
5546 					$c = $this->upperCase[$c];
5547 					// $this->CurrentFont['subset'][$this->upperCase[$c]] = $this->upperCase[$c];	// add the CAP to subset
5548 					$SmallCapsON = true;
5549 					// For $sipset
5550 					if (!$lastSmallCapsON) {   // Turn ON SmallCaps
5551 						$groupBreak = true;
5552 						$fontstretch = $this->smCapsStretch;
5553 						$fontsize = $this->FontSizePt * $this->smCapsScale;
5554 					}
5555 				} else {
5556 					$SmallCapsON = false;
5557 					if ($lastSmallCapsON) {  // Turn OFF SmallCaps
5558 						$groupBreak = true;
5559 						$fontstretch = 100;
5560 						$fontsize = $this->FontSizePt;
5561 					}
5562 				}
5563 			}
5564 
5565 			// Prepare Text and Select Font ID
5566 			if ($sipset) {
5567 				// mPDF 6  DELETED ********
5568 				// if ($c == 7 || $c == 8) {
5569 				// if ($original_fontid != $last_fontid) {
5570 				// 	$groupBreak = true;
5571 				// 	$fontid = $original_fontid;
5572 				// }
5573 				// if ($c == 7) { $tj .= $this->aliasNbPgHex; }
5574 				// else { $tj .= $this->aliasNbPgGpHex; }
5575 				// continue;
5576 				// }
5577 				for ($j = 0; $j < 99; $j++) {
5578 					$init = array_search($c, $this->CurrentFont['subsets'][$j]);
5579 					if ($init !== false) {
5580 						if ($this->CurrentFont['subsetfontids'][$j] != $last_fontid) {
5581 							$groupBreak = true;
5582 							$fontid = $this->CurrentFont['subsetfontids'][$j];
5583 						}
5584 						$tx = sprintf("%02s", strtoupper(dechex($init)));
5585 						break;
5586 					} elseif (count($this->CurrentFont['subsets'][$j]) < 255) {
5587 						$n = count($this->CurrentFont['subsets'][$j]);
5588 						$this->CurrentFont['subsets'][$j][$n] = $c;
5589 						if ($this->CurrentFont['subsetfontids'][$j] != $last_fontid) {
5590 							$groupBreak = true;
5591 							$fontid = $this->CurrentFont['subsetfontids'][$j];
5592 						}
5593 						$tx = sprintf("%02s", strtoupper(dechex($n)));
5594 						break;
5595 					} elseif (!isset($this->CurrentFont['subsets'][($j + 1)])) {
5596 						$this->CurrentFont['subsets'][($j + 1)] = [0 => 0];
5597 						$this->CurrentFont['subsetfontids'][($j + 1)] = count($this->fonts) + $this->extraFontSubsets + 1;
5598 						$this->extraFontSubsets++;
5599 					}
5600 				}
5601 			} else {
5602 				$tx = UtfString::code2utf($c);
5603 				if ($this->usingCoreFont) {
5604 					$tx = utf8_decode($tx);
5605 				} else {
5606 					$tx = $this->writer->utf8ToUtf16BigEndian($tx, false);
5607 				}
5608 				$tx = $this->writer->escape($tx);
5609 			}
5610 
5611 			// If any settings require a new Text Group
5612 			if ($groupBreak || $fontstretch != $last_fontstretch) {
5613 				if ($sipset) {
5614 					$tj .= '>] TJ ';
5615 				} else {
5616 					$tj .= ')] TJ ';
5617 				}
5618 				if ($fontid != $last_fontid || $fontsize != $last_fontsize) {
5619 					$tj .= sprintf(' /F%d %.3F Tf ', $fontid, $fontsize);
5620 				}
5621 				if ($fontstretch != $last_fontstretch) {
5622 					$tj .= sprintf('%d Tz ', $fontstretch);
5623 				}
5624 				if ($YPlacement != $lastYPlacement) {
5625 					$tj .= sprintf('%.3F Ts ', $YPlacement);
5626 				}
5627 				if ($sipset) {
5628 					$tj .= '[<';
5629 				} else {
5630 					$tj .= '[(';
5631 				}
5632 			}
5633 
5634 			// Output the code for the txt character
5635 			$tj .= $tx;
5636 			$lastSmallCapsON = $SmallCapsON;
5637 			$last_fontid = $fontid;
5638 			$last_fontsize = $fontsize;
5639 			$last_fontstretch = $fontstretch;
5640 
5641 			// Kashida
5642 			if ($kashida) {
5643 				$c = 0x0640; // add the Tatweel U+0640
5644 				if (isset($this->CurrentFont['subset'])) {
5645 					$this->CurrentFont['subset'][$c] = $c;
5646 				}
5647 				$kashida *= 1000 / $this->FontSizePt;
5648 				$tatw = $this->_getCharWidth($this->CurrentFont['cw'], 0x0640);
5649 
5650 				// Get YPlacement from next Base character
5651 				$nextbase = $i + 1;
5652 				while ($OTLdata['group'][$nextbase] != 'C') {
5653 					$nextbase++;
5654 				}
5655 				if (isset($GPOSinfo[$nextbase]) && isset($GPOSinfo[$nextbase]['YPlacement']) && $GPOSinfo[$nextbase]['YPlacement']) {
5656 					$YPlacement = $GPOSinfo[$nextbase]['YPlacement'] * $this->FontSizePt / $this->CurrentFont['unitsPerEm'];
5657 				}
5658 
5659 				// Prepare Text and Select Font ID
5660 				if ($sipset) {
5661 					for ($j = 0; $j < 99; $j++) {
5662 						$init = array_search($c, $this->CurrentFont['subsets'][$j]);
5663 						if ($init !== false) {
5664 							if ($this->CurrentFont['subsetfontids'][$j] != $last_fontid) {
5665 								$fontid = $this->CurrentFont['subsetfontids'][$j];
5666 							}
5667 							$tx = sprintf("%02s", strtoupper(dechex($init)));
5668 							break;
5669 						} elseif (count($this->CurrentFont['subsets'][$j]) < 255) {
5670 							$n = count($this->CurrentFont['subsets'][$j]);
5671 							$this->CurrentFont['subsets'][$j][$n] = $c;
5672 							if ($this->CurrentFont['subsetfontids'][$j] != $last_fontid) {
5673 								$fontid = $this->CurrentFont['subsetfontids'][$j];
5674 							}
5675 							$tx = sprintf("%02s", strtoupper(dechex($n)));
5676 							break;
5677 						} elseif (!isset($this->CurrentFont['subsets'][($j + 1)])) {
5678 							$this->CurrentFont['subsets'][($j + 1)] = [0 => 0];
5679 							$this->CurrentFont['subsetfontids'][($j + 1)] = count($this->fonts) + $this->extraFontSubsets + 1;
5680 							$this->extraFontSubsets++;
5681 						}
5682 					}
5683 				} else {
5684 					$tx = UtfString::code2utf($c);
5685 					$tx = $this->writer->utf8ToUtf16BigEndian($tx, false);
5686 					$tx = $this->writer->escape($tx);
5687 				}
5688 
5689 				if ($kashida > $tatw) {
5690 					// Insert multiple tatweel characters, repositioning the last one to give correct total length
5691 					$fontstretch = 100;
5692 					$nt = intval($kashida / $tatw);
5693 					$nudgeback = (($nt + 1) * $tatw) - $kashida;
5694 					$optx = str_repeat($tx, $nt);
5695 					if ($sipset) {
5696 						$optx .= sprintf('>%d<', ($nudgeback));
5697 					} else {
5698 						$optx .= sprintf(')%d(', ($nudgeback));
5699 					}
5700 					$optx .= $tx; // #last
5701 				} else {
5702 					// Insert single tatweel character and use fontstretch to get correct length
5703 					$fontstretch = ($kashida / $tatw) * 100;
5704 					$optx = $tx;
5705 				}
5706 
5707 				if ($sipset) {
5708 					$tj .= '>] TJ ';
5709 				} else {
5710 					$tj .= ')] TJ ';
5711 				}
5712 				if ($fontid != $last_fontid || $fontsize != $last_fontsize) {
5713 					$tj .= sprintf(' /F%d %.3F Tf ', $fontid, $fontsize);
5714 				}
5715 				if ($fontstretch != $last_fontstretch) {
5716 					$tj .= sprintf('%d Tz ', $fontstretch);
5717 				}
5718 				$tj .= sprintf('%.3F Ts ', $YPlacement);
5719 				if ($sipset) {
5720 					$tj .= '[<';
5721 				} else {
5722 					$tj .= '[(';
5723 				}
5724 
5725 				// Output the code for the txt character(s)
5726 				$tj .= $optx;
5727 				$last_fontid = $fontid;
5728 				$last_fontstretch = $fontstretch;
5729 				$fontstretch = 100;
5730 			}
5731 
5732 			$lastYPlacement = $YPlacement;
5733 		}
5734 
5735 
5736 		// Finish up
5737 		if ($sipset) {
5738 			$tj .= '>';
5739 			if ($XshiftAfter) {
5740 				$tj .= sprintf('%d', (-$XshiftAfter));
5741 			}
5742 			if ($last_fontid != $original_fontid) {
5743 				$tj .= '] TJ ';
5744 				$tj .= sprintf(' /F%d %.3F Tf ', $original_fontid, $fontsize);
5745 				$tj .= '[';
5746 			}
5747 			$tj = preg_replace('/([^\\\])<>/', '\\1 ', $tj);
5748 		} else {
5749 			$tj .= ')';
5750 			if ($XshiftAfter) {
5751 				$tj .= sprintf('%d', (-$XshiftAfter));
5752 			}
5753 			if ($last_fontid != $original_fontid) {
5754 				$tj .= '] TJ ';
5755 				$tj .= sprintf(' /F%d %.3F Tf ', $original_fontid, $fontsize);
5756 				$tj .= '[';
5757 			}
5758 			$tj = preg_replace('/([^\\\])\(\)/', '\\1 ', $tj);
5759 		}
5760 
5761 		$s = sprintf(' BT ' . $aix . ' 0 Tc 0 Tw [%s] TJ ET ', $x, $y, $tj);
5762 
5763 		// echo $s."\n\n"; // exit;
5764 
5765 		return $s;
5766 	}
5767 
5768 	function _kern($txt, $mode, $aix, $x, $y)
5769 	{
5770 		if ($mode == 'MBTw') { // Multibyte requiring word spacing
5771 			$space = ' ';
5772 			// Convert string to UTF-16BE without BOM
5773 			$space = $this->writer->utf8ToUtf16BigEndian($space, false);
5774 			$space = $this->writer->escape($space);
5775 			$s = sprintf(' BT ' . $aix, $x * Mpdf::SCALE, ($this->h - $y) * Mpdf::SCALE);
5776 			$t = explode(' ', $txt);
5777 			for ($i = 0; $i < count($t); $i++) {
5778 				$tx = $t[$i];
5779 
5780 				$tj = '(';
5781 				$unicode = $this->UTF8StringToArray($tx);
5782 				for ($ti = 0; $ti < count($unicode); $ti++) {
5783 					if ($ti > 0 && isset($this->CurrentFont['kerninfo'][$unicode[($ti - 1)]][$unicode[$ti]])) {
5784 						$kern = -$this->CurrentFont['kerninfo'][$unicode[($ti - 1)]][$unicode[$ti]];
5785 						$tj .= sprintf(')%d(', $kern);
5786 					}
5787 					$tc = UtfString::code2utf($unicode[$ti]);
5788 					$tc = $this->writer->utf8ToUtf16BigEndian($tc, false);
5789 					$tj .= $this->writer->escape($tc);
5790 				}
5791 				$tj .= ')';
5792 				$s .= sprintf(' %.3F Tc [%s] TJ', $this->charspacing, $tj);
5793 
5794 
5795 				if (($i + 1) < count($t)) {
5796 					$s .= sprintf(' %.3F Tc (%s) Tj', $this->ws + $this->charspacing, $space);
5797 				}
5798 			}
5799 			$s .= ' ET ';
5800 		} elseif (!$this->usingCoreFont) {
5801 			$s = '';
5802 			$tj = '(';
5803 			$unicode = $this->UTF8StringToArray($txt);
5804 			for ($i = 0; $i < count($unicode); $i++) {
5805 				if ($i > 0 && isset($this->CurrentFont['kerninfo'][$unicode[($i - 1)]][$unicode[$i]])) {
5806 					$kern = -$this->CurrentFont['kerninfo'][$unicode[($i - 1)]][$unicode[$i]];
5807 					$tj .= sprintf(')%d(', $kern);
5808 				}
5809 				$tx = UtfString::code2utf($unicode[$i]);
5810 				$tx = $this->writer->utf8ToUtf16BigEndian($tx, false);
5811 				$tj .= $this->writer->escape($tx);
5812 			}
5813 			$tj .= ')';
5814 			$s .= sprintf(' BT ' . $aix . ' [%s] TJ ET ', $x * Mpdf::SCALE, ($this->h - $y) * Mpdf::SCALE, $tj);
5815 		} else { // CORE Font
5816 			$s = '';
5817 			$tj = '(';
5818 			$l = strlen($txt);
5819 			for ($i = 0; $i < $l; $i++) {
5820 				if ($i > 0 && isset($this->CurrentFont['kerninfo'][$txt[($i - 1)]][$txt[$i]])) {
5821 					$kern = -$this->CurrentFont['kerninfo'][$txt[($i - 1)]][$txt[$i]];
5822 					$tj .= sprintf(')%d(', $kern);
5823 				}
5824 				$tj .= $this->writer->escape($txt[$i]);
5825 			}
5826 			$tj .= ')';
5827 			$s .= sprintf(' BT ' . $aix . ' [%s] TJ ET ', $x * Mpdf::SCALE, ($this->h - $y) * Mpdf::SCALE, $tj);
5828 		}
5829 
5830 		return $s;
5831 	}
5832 
5833 	function MultiCell(
5834 		$w,
5835 		$h,
5836 		$txt,
5837 		$border = 0,
5838 		$align = '',
5839 		$fill = 0,
5840 		$link = '',
5841 		$directionality = 'ltr',
5842 		$encoded = false,
5843 		$OTLdata = false,
5844 		$maxrows = false
5845 	) {
5846 		// maxrows is called from mpdfform->TEXTAREA
5847 		// Parameter (pre-)encoded - When called internally from form::textarea -
5848 		// mb_encoding already done and OTL - but not reverse RTL
5849 		if (!$encoded) {
5850 
5851 			$txt = $this->purify_utf8_text($txt);
5852 
5853 			if ($this->text_input_as_HTML) {
5854 				$txt = $this->all_entities_to_utf8($txt);
5855 			}
5856 
5857 			if ($this->usingCoreFont) {
5858 				$txt = mb_convert_encoding($txt, $this->mb_enc, 'UTF-8');
5859 			}
5860 
5861 			if (preg_match("/([" . $this->pregRTLchars . "])/u", $txt)) {
5862 				$this->biDirectional = true;
5863 			}
5864 
5865 			/* -- OTL -- */
5866 			if (!is_array($OTLdata)) {
5867 				unset($OTLdata);
5868 			}
5869 
5870 			// Use OTL OpenType Table Layout - GSUB & GPOS
5871 			if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
5872 				$txt = $this->otl->applyOTL($txt, $this->CurrentFont['useOTL']);
5873 				$OTLdata = $this->otl->OTLdata;
5874 			}
5875 
5876 			if ($directionality == 'rtl' || $this->biDirectional) {
5877 				if (!isset($OTLdata)) {
5878 					$unicode = $this->UTF8StringToArray($txt, false);
5879 					$is_strong = false;
5880 					$this->getBasicOTLdata($OTLdata, $unicode, $is_strong);
5881 				}
5882 			}
5883 			/* -- END OTL -- */
5884 		}
5885 
5886 		if (!$align) {
5887 			$align = $this->defaultAlign;
5888 		}
5889 
5890 		// Output text with automatic or explicit line breaks
5891 		$cw = &$this->CurrentFont['cw'];
5892 
5893 		if ($w == 0) {
5894 			$w = $this->w - $this->rMargin - $this->x;
5895 		}
5896 
5897 		$wmax = ($w - ($this->cMarginL + $this->cMarginR));
5898 
5899 		if ($this->usingCoreFont) {
5900 			$s = str_replace("\r", '', $txt);
5901 			$nb = strlen($s);
5902 			while ($nb > 0 and $s[$nb - 1] == "\n") {
5903 				$nb--;
5904 			}
5905 		} else {
5906 			$s = str_replace("\r", '', $txt);
5907 			$nb = mb_strlen($s, $this->mb_enc);
5908 			while ($nb > 0 and mb_substr($s, $nb - 1, 1, $this->mb_enc) == "\n") {
5909 				$nb--;
5910 			}
5911 		}
5912 
5913 		$b = 0;
5914 
5915 		if ($border) {
5916 
5917 			if ($border == 1) {
5918 				$border = 'LTRB';
5919 				$b = 'LRT';
5920 				$b2 = 'LR';
5921 			} else {
5922 				$b2 = '';
5923 				if (is_int(strpos($border, 'L'))) {
5924 					$b2 .= 'L';
5925 				}
5926 				if (is_int(strpos($border, 'R'))) {
5927 					$b2 .= 'R';
5928 				}
5929 				$b = is_int(strpos($border, 'T')) ? $b2 . 'T' : $b2;
5930 			}
5931 		}
5932 
5933 		$sep = -1;
5934 		$i = 0;
5935 		$j = 0;
5936 		$l = 0;
5937 		$ns = 0;
5938 		$nl = 1;
5939 
5940 		$rows = 0;
5941 		$start_y = $this->y;
5942 
5943 		if (!$this->usingCoreFont) {
5944 
5945 			$inclCursive = false;
5946 
5947 			if (preg_match("/([" . $this->pregCURSchars . "])/u", $s)) {
5948 				$inclCursive = true;
5949 			}
5950 
5951 			while ($i < $nb) {
5952 
5953 				// Get next character
5954 				$c = mb_substr($s, $i, 1, $this->mb_enc);
5955 
5956 				if ($c === "\n") { // Explicit line break
5957 
5958 					// WORD SPACING
5959 					$this->ResetSpacing();
5960 					$tmp = rtrim(mb_substr($s, $j, $i - $j, $this->mb_enc));
5961 					$tmpOTLdata = false;
5962 
5963 					/* -- OTL -- */
5964 					if (isset($OTLdata)) {
5965 						$tmpOTLdata = $this->otl->sliceOTLdata($OTLdata, $j, $i - $j);
5966 						$this->otl->trimOTLdata($tmpOTLdata, false, true);
5967 						$this->magic_reverse_dir($tmp, $directionality, $tmpOTLdata);
5968 					}
5969 					/* -- END OTL -- */
5970 
5971 					$this->Cell($w, $h, $tmp, $b, 2, $align, $fill, $link, 0, 0, 0, 'M', 0, false, $tmpOTLdata);
5972 
5973 					if ($maxrows != false && isset($this->form) && ($this->y - $start_y) / $h > $maxrows) {
5974 						return false;
5975 					}
5976 
5977 					$i++;
5978 					$sep = -1;
5979 					$j = $i;
5980 					$l = 0;
5981 					$ns = 0;
5982 					$nl++;
5983 
5984 					if ($border and $nl == 2) {
5985 						$b = $b2;
5986 					}
5987 
5988 					continue;
5989 				}
5990 
5991 				if ($c == " ") {
5992 					$sep = $i;
5993 					$ls = $l;
5994 					$ns++;
5995 				}
5996 
5997 				$l += $this->GetCharWidthNonCore($c);
5998 
5999 				if ($l > $wmax) {
6000 
6001 					// Automatic line break
6002 					if ($sep == -1) { // Only one word
6003 
6004 						if ($i == $j) {
6005 							$i++;
6006 						}
6007 
6008 						// WORD SPACING
6009 						$this->ResetSpacing();
6010 						$tmp = rtrim(mb_substr($s, $j, $i - $j, $this->mb_enc));
6011 						$tmpOTLdata = false;
6012 
6013 						/* -- OTL -- */
6014 						if (isset($OTLdata)) {
6015 							$tmpOTLdata = $this->otl->sliceOTLdata($OTLdata, $j, $i - $j);
6016 							$this->otl->trimOTLdata($tmpOTLdata, false, true);
6017 							$this->magic_reverse_dir($tmp, $directionality, $tmpOTLdata);
6018 						}
6019 						/* -- END OTL -- */
6020 
6021 						$this->Cell($w, $h, $tmp, $b, 2, $align, $fill, $link, 0, 0, 0, 'M', 0, false, $tmpOTLdata);
6022 
6023 					} else {
6024 
6025 						$tmp = rtrim(mb_substr($s, $j, $sep - $j, $this->mb_enc));
6026 						$tmpOTLdata = false;
6027 
6028 						/* -- OTL -- */
6029 						if (isset($OTLdata)) {
6030 							$tmpOTLdata = $this->otl->sliceOTLdata($OTLdata, $j, $sep - $j);
6031 							$this->otl->trimOTLdata($tmpOTLdata, false, true);
6032 						}
6033 						/* -- END OTL -- */
6034 
6035 						if ($align === 'J') {
6036 
6037 							// JUSTIFY J using Unicode fonts (Word spacing doesn't work)
6038 							// WORD SPACING UNICODE
6039 							// Change NON_BREAKING SPACE to spaces so they are 'spaced' properly
6040 
6041 							$tmp = str_replace(chr(194) . chr(160), chr(32), $tmp);
6042 							$len_ligne = $this->GetStringWidth($tmp, false, $tmpOTLdata);
6043 							$nb_carac = mb_strlen($tmp, $this->mb_enc);
6044 							$nb_spaces = mb_substr_count($tmp, ' ', $this->mb_enc);
6045 
6046 							// Take off number of Marks
6047 							// Use GPOS OTL
6048 
6049 							if (isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'])) {
6050 								if (isset($tmpOTLdata['group']) && $tmpOTLdata['group']) {
6051 									$nb_carac -= substr_count($tmpOTLdata['group'], 'M');
6052 								}
6053 							}
6054 
6055 							list($charspacing, $ws, $kashida) = $this->GetJspacing($nb_carac, $nb_spaces, ((($wmax) - $len_ligne) * Mpdf::SCALE), $inclCursive, $tmpOTLdata);
6056 							$this->SetSpacing($charspacing, $ws);
6057 						}
6058 
6059 						if (isset($OTLdata)) {
6060 							$this->magic_reverse_dir($tmp, $directionality, $tmpOTLdata);
6061 						}
6062 
6063 						$this->Cell($w, $h, $tmp, $b, 2, $align, $fill, $link, 0, 0, 0, 'M', 0, false, $tmpOTLdata);
6064 
6065 						$i = $sep + 1;
6066 					}
6067 
6068 					if ($maxrows != false && isset($this->form) && ($this->y - $start_y) / $h > $maxrows) {
6069 						return false;
6070 					}
6071 
6072 					$sep = -1;
6073 					$j = $i;
6074 					$l = 0;
6075 					$ns = 0;
6076 					$nl++;
6077 
6078 					if ($border and $nl == 2) {
6079 						$b = $b2;
6080 					}
6081 
6082 				} else {
6083 					$i++;
6084 				}
6085 			}
6086 
6087 			// Last chunk
6088 			// WORD SPACING
6089 
6090 			$this->ResetSpacing();
6091 
6092 		} else {
6093 
6094 			while ($i < $nb) {
6095 
6096 				// Get next character
6097 				$c = $s[$i];
6098 				if ($c === "\n") {
6099 
6100 					// Explicit line break
6101 					// WORD SPACING
6102 
6103 					$this->ResetSpacing();
6104 					$this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill, $link);
6105 
6106 					if ($maxrows != false && isset($this->form) && ($this->y - $start_y) / $h > $maxrows) {
6107 						return false;
6108 					}
6109 
6110 					$i++;
6111 					$sep = -1;
6112 					$j = $i;
6113 					$l = 0;
6114 					$ns = 0;
6115 					$nl++;
6116 
6117 					if ($border and $nl == 2) {
6118 						$b = $b2;
6119 					}
6120 
6121 					continue;
6122 				}
6123 
6124 				if ($c === ' ') {
6125 					$sep = $i;
6126 					$ls = $l;
6127 					$ns++;
6128 				}
6129 
6130 				$l += $this->GetCharWidthCore($c);
6131 
6132 				if ($l > $wmax) {
6133 
6134 					// Automatic line break
6135 					if ($sep == -1) {
6136 
6137 						if ($i == $j) {
6138 							$i++;
6139 						}
6140 
6141 						// WORD SPACING
6142 						$this->ResetSpacing();
6143 						$this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill, $link);
6144 
6145 					} else {
6146 
6147 						if ($align === 'J') {
6148 
6149 							$tmp = rtrim(substr($s, $j, $sep - $j));
6150 
6151 							// JUSTIFY J using Unicode fonts (Word spacing doesn't work)
6152 							// WORD SPACING NON_UNICODE/CJK
6153 							// Change NON_BREAKING SPACE to spaces so they are 'spaced' properly
6154 
6155 							$tmp = str_replace(chr(160), chr(32), $tmp);
6156 							$len_ligne = $this->GetStringWidth($tmp);
6157 							$nb_carac = strlen($tmp);
6158 							$nb_spaces = substr_count($tmp, ' ');
6159 							$tmpOTLdata = [];
6160 
6161 							list($charspacing, $ws, $kashida) = $this->GetJspacing($nb_carac, $nb_spaces, ((($wmax) - $len_ligne) * Mpdf::SCALE), false, $tmpOTLdata);
6162 							$this->SetSpacing($charspacing, $ws);
6163 						}
6164 
6165 						$this->Cell($w, $h, substr($s, $j, $sep - $j), $b, 2, $align, $fill, $link);
6166 						$i = $sep + 1;
6167 					}
6168 
6169 					if ($maxrows != false && isset($this->form) && ($this->y - $start_y) / $h > $maxrows) {
6170 						return false;
6171 					}
6172 
6173 					$sep = -1;
6174 					$j = $i;
6175 					$l = 0;
6176 					$ns = 0;
6177 					$nl++;
6178 
6179 					if ($border and $nl == 2) {
6180 						$b = $b2;
6181 					}
6182 
6183 				} else {
6184 					$i++;
6185 				}
6186 			}
6187 
6188 			// Last chunk
6189 			// WORD SPACING
6190 
6191 			$this->ResetSpacing();
6192 		}
6193 
6194 		// Last chunk
6195 		if ($border and is_int(strpos($border, 'B'))) {
6196 			$b .= 'B';
6197 		}
6198 
6199 		if (!$this->usingCoreFont) {
6200 
6201 			$tmp = rtrim(mb_substr($s, $j, $i - $j, $this->mb_enc));
6202 			$tmpOTLdata = false;
6203 
6204 			/* -- OTL -- */
6205 			if (isset($OTLdata)) {
6206 				$tmpOTLdata = $this->otl->sliceOTLdata($OTLdata, $j, $i - $j);
6207 				$this->otl->trimOTLdata($tmpOTLdata, false, true);
6208 				$this->magic_reverse_dir($tmp, $directionality, $tmpOTLdata);
6209 			}
6210 			/* -- END OTL -- */
6211 
6212 			$this->Cell($w, $h, $tmp, $b, 2, $align, $fill, $link, 0, 0, 0, 'M', 0, false, $tmpOTLdata);
6213 		} else {
6214 			$this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill, $link);
6215 		}
6216 
6217 		$this->x = $this->lMargin;
6218 	}
6219 
6220 	/* -- DIRECTW -- */
6221 
6222 	function Write($h, $txt, $currentx = 0, $link = '', $directionality = 'ltr', $align = '', $fill = 0)
6223 	{
6224 		if (empty($this->directWrite)) {
6225 			$this->directWrite = new DirectWrite($this, $this->otl, $this->sizeConverter, $this->colorConverter);
6226 		}
6227 
6228 		$this->directWrite->Write($h, $txt, $currentx, $link, $directionality, $align, $fill);
6229 	}
6230 
6231 	/* -- END DIRECTW -- */
6232 
6233 
6234 	/* -- HTML-CSS -- */
6235 
6236 	function saveInlineProperties()
6237 	{
6238 		$saved = [];
6239 		$saved['family'] = $this->FontFamily;
6240 		$saved['style'] = $this->FontStyle;
6241 		$saved['sizePt'] = $this->FontSizePt;
6242 		$saved['size'] = $this->FontSize;
6243 		$saved['HREF'] = $this->HREF;
6244 		$saved['textvar'] = $this->textvar; // mPDF 5.7.1
6245 		$saved['OTLtags'] = $this->OTLtags; // mPDF 5.7.1
6246 		$saved['textshadow'] = $this->textshadow;
6247 		$saved['linewidth'] = $this->LineWidth;
6248 		$saved['drawcolor'] = $this->DrawColor;
6249 		$saved['textparam'] = $this->textparam;
6250 		$saved['lSpacingCSS'] = $this->lSpacingCSS;
6251 		$saved['wSpacingCSS'] = $this->wSpacingCSS;
6252 		$saved['I'] = $this->I;
6253 		$saved['B'] = $this->B;
6254 		$saved['colorarray'] = $this->colorarray;
6255 		$saved['bgcolorarray'] = $this->spanbgcolorarray;
6256 		$saved['border'] = $this->spanborddet;
6257 		$saved['color'] = $this->TextColor;
6258 		$saved['bgcolor'] = $this->FillColor;
6259 		$saved['lang'] = $this->currentLang;
6260 		$saved['fontLanguageOverride'] = $this->fontLanguageOverride; // mPDF 5.7.1
6261 		$saved['display_off'] = $this->inlineDisplayOff;
6262 
6263 		return $saved;
6264 	}
6265 
6266 	function restoreInlineProperties(&$saved)
6267 	{
6268 		$FontFamily = $saved['family'];
6269 		$this->FontStyle = $saved['style'];
6270 		$this->FontSizePt = $saved['sizePt'];
6271 		$this->FontSize = $saved['size'];
6272 
6273 		$this->currentLang = $saved['lang'];
6274 		$this->fontLanguageOverride = $saved['fontLanguageOverride']; // mPDF 5.7.1
6275 
6276 		$this->ColorFlag = ($this->FillColor != $this->TextColor); // Restore ColorFlag as well
6277 
6278 		$this->HREF = $saved['HREF'];
6279 		$this->textvar = $saved['textvar']; // mPDF 5.7.1
6280 		$this->OTLtags = $saved['OTLtags']; // mPDF 5.7.1
6281 		$this->textshadow = $saved['textshadow'];
6282 		$this->LineWidth = $saved['linewidth'];
6283 		$this->DrawColor = $saved['drawcolor'];
6284 		$this->textparam = $saved['textparam'];
6285 		$this->inlineDisplayOff = $saved['display_off'];
6286 
6287 		$this->lSpacingCSS = $saved['lSpacingCSS'];
6288 		if (($this->lSpacingCSS || $this->lSpacingCSS === '0') && strtoupper($this->lSpacingCSS) != 'NORMAL') {
6289 			$this->fixedlSpacing = $this->sizeConverter->convert($this->lSpacingCSS, $this->FontSize);
6290 		} else {
6291 			$this->fixedlSpacing = false;
6292 		}
6293 		$this->wSpacingCSS = $saved['wSpacingCSS'];
6294 		if ($this->wSpacingCSS && strtoupper($this->wSpacingCSS) != 'NORMAL') {
6295 			$this->minwSpacing = $this->sizeConverter->convert($this->wSpacingCSS, $this->FontSize);
6296 		} else {
6297 			$this->minwSpacing = 0;
6298 		}
6299 
6300 		$this->SetFont($FontFamily, $saved['style'], $saved['sizePt'], false);
6301 
6302 		$this->currentfontstyle = $saved['style'];
6303 		$this->currentfontsize = $saved['sizePt'];
6304 		$this->SetStylesArray(['B' => $saved['B'], 'I' => $saved['I']]); // mPDF 5.7.1
6305 
6306 		$this->TextColor = $saved['color'];
6307 		$this->FillColor = $saved['bgcolor'];
6308 		$this->colorarray = $saved['colorarray'];
6309 		$cor = $saved['colorarray'];
6310 		if ($cor) {
6311 			$this->SetTColor($cor);
6312 		}
6313 		$this->spanbgcolorarray = $saved['bgcolorarray'];
6314 		$cor = $saved['bgcolorarray'];
6315 		if ($cor) {
6316 			$this->SetFColor($cor);
6317 		}
6318 		$this->spanborddet = $saved['border'];
6319 	}
6320 
6321 	// Used when ColActive for tables - updated to return first block with background fill OR borders
6322 	function GetFirstBlockFill()
6323 	{
6324 		// Returns the first blocklevel that uses a bgcolor fill
6325 		$startfill = 0;
6326 		for ($i = 1; $i <= $this->blklvl; $i++) {
6327 			if ($this->blk[$i]['bgcolor'] || $this->blk[$i]['border_left']['w'] || $this->blk[$i]['border_right']['w'] || $this->blk[$i]['border_top']['w'] || $this->blk[$i]['border_bottom']['w']) {
6328 				$startfill = $i;
6329 				break;
6330 			}
6331 		}
6332 		return $startfill;
6333 	}
6334 
6335 	// -------------------------FLOWING BLOCK------------------------------------//
6336 	// The following functions were originally written by Damon Kohler           //
6337 	// --------------------------------------------------------------------------//
6338 
6339 	function saveFont()
6340 	{
6341 		$saved = [];
6342 		$saved['family'] = $this->FontFamily;
6343 		$saved['style'] = $this->FontStyle;
6344 		$saved['sizePt'] = $this->FontSizePt;
6345 		$saved['size'] = $this->FontSize;
6346 		$saved['curr'] = &$this->CurrentFont;
6347 		$saved['lang'] = $this->currentLang; // mPDF 6
6348 		$saved['color'] = $this->TextColor;
6349 		$saved['spanbgcolor'] = $this->spanbgcolor;
6350 		$saved['spanbgcolorarray'] = $this->spanbgcolorarray;
6351 		$saved['bord'] = $this->spanborder;
6352 		$saved['border'] = $this->spanborddet;
6353 		$saved['HREF'] = $this->HREF;
6354 		$saved['textvar'] = $this->textvar; // mPDF 5.7.1
6355 		$saved['textshadow'] = $this->textshadow;
6356 		$saved['linewidth'] = $this->LineWidth;
6357 		$saved['drawcolor'] = $this->DrawColor;
6358 		$saved['textparam'] = $this->textparam;
6359 		$saved['ReqFontStyle'] = $this->ReqFontStyle;
6360 		$saved['fixedlSpacing'] = $this->fixedlSpacing;
6361 		$saved['minwSpacing'] = $this->minwSpacing;
6362 		return $saved;
6363 	}
6364 
6365 	function restoreFont(&$saved, $write = true)
6366 	{
6367 		if (!isset($saved) || empty($saved)) {
6368 			return;
6369 		}
6370 
6371 		$this->FontFamily = $saved['family'];
6372 		$this->FontStyle = $saved['style'];
6373 		$this->FontSizePt = $saved['sizePt'];
6374 		$this->FontSize = $saved['size'];
6375 		$this->CurrentFont = &$saved['curr'];
6376 		$this->currentLang = $saved['lang']; // mPDF 6
6377 		$this->TextColor = $saved['color'];
6378 		$this->spanbgcolor = $saved['spanbgcolor'];
6379 		$this->spanbgcolorarray = $saved['spanbgcolorarray'];
6380 		$this->spanborder = $saved['bord'];
6381 		$this->spanborddet = $saved['border'];
6382 		$this->ColorFlag = ($this->FillColor != $this->TextColor); // Restore ColorFlag as well
6383 		$this->HREF = $saved['HREF'];
6384 		$this->fixedlSpacing = $saved['fixedlSpacing'];
6385 		$this->minwSpacing = $saved['minwSpacing'];
6386 		$this->textvar = $saved['textvar'];  // mPDF 5.7.1
6387 		$this->textshadow = $saved['textshadow'];
6388 		$this->LineWidth = $saved['linewidth'];
6389 		$this->DrawColor = $saved['drawcolor'];
6390 		$this->textparam = $saved['textparam'];
6391 		if ($write) {
6392 			$this->SetFont($saved['family'], $saved['style'], $saved['sizePt'], true, true); // force output
6393 			$fontout = (sprintf('BT /F%d %.3F Tf ET', $this->CurrentFont['i'], $this->FontSizePt));
6394 			if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['Font']) && $this->pageoutput[$this->page]['Font'] != $fontout) || !isset($this->pageoutput[$this->page]['Font']))) {
6395 				$this->writer->write($fontout);
6396 			}
6397 			$this->pageoutput[$this->page]['Font'] = $fontout;
6398 		} else {
6399 			$this->SetFont($saved['family'], $saved['style'], $saved['sizePt'], false);
6400 		}
6401 		$this->ReqFontStyle = $saved['ReqFontStyle'];
6402 	}
6403 
6404 	function newFlowingBlock($w, $h, $a = '', $is_table = false, $blockstate = 0, $newblock = true, $blockdir = 'ltr', $table_draft = false)
6405 	{
6406 		if (!$a) {
6407 			if ($blockdir == 'rtl') {
6408 				$a = 'R';
6409 			} else {
6410 				$a = 'L';
6411 			}
6412 		}
6413 		$this->flowingBlockAttr['width'] = ($w * Mpdf::SCALE);
6414 		// line height in user units
6415 		$this->flowingBlockAttr['is_table'] = $is_table;
6416 		$this->flowingBlockAttr['table_draft'] = $table_draft;
6417 		$this->flowingBlockAttr['height'] = $h;
6418 		$this->flowingBlockAttr['lineCount'] = 0;
6419 		$this->flowingBlockAttr['align'] = $a;
6420 		$this->flowingBlockAttr['font'] = [];
6421 		$this->flowingBlockAttr['content'] = [];
6422 		$this->flowingBlockAttr['contentB'] = [];
6423 		$this->flowingBlockAttr['contentWidth'] = 0;
6424 		$this->flowingBlockAttr['blockstate'] = $blockstate;
6425 
6426 		$this->flowingBlockAttr['newblock'] = $newblock;
6427 		$this->flowingBlockAttr['valign'] = 'M';
6428 		$this->flowingBlockAttr['blockdir'] = $blockdir;
6429 		$this->flowingBlockAttr['cOTLdata'] = []; // mPDF 5.7.1
6430 		$this->flowingBlockAttr['lastBidiText'] = ''; // mPDF 5.7.1
6431 		if (!empty($this->otl)) {
6432 			$this->otl->lastBidiStrongType = '';
6433 		} // *OTL*
6434 	}
6435 
6436 	function finishFlowingBlock($endofblock = false, $next = '')
6437 	{
6438 		$currentx = $this->x;
6439 		// prints out the last chunk
6440 		$is_table = $this->flowingBlockAttr['is_table'];
6441 		$table_draft = $this->flowingBlockAttr['table_draft'];
6442 		$maxWidth = & $this->flowingBlockAttr['width'];
6443 		$stackHeight = & $this->flowingBlockAttr['height'];
6444 		$align = & $this->flowingBlockAttr['align'];
6445 		$content = & $this->flowingBlockAttr['content'];
6446 		$contentB = & $this->flowingBlockAttr['contentB'];
6447 		$font = & $this->flowingBlockAttr['font'];
6448 		$contentWidth = & $this->flowingBlockAttr['contentWidth'];
6449 		$lineCount = & $this->flowingBlockAttr['lineCount'];
6450 		$valign = & $this->flowingBlockAttr['valign'];
6451 		$blockstate = $this->flowingBlockAttr['blockstate'];
6452 
6453 		$cOTLdata = & $this->flowingBlockAttr['cOTLdata']; // mPDF 5.7.1
6454 		$newblock = $this->flowingBlockAttr['newblock'];
6455 		$blockdir = $this->flowingBlockAttr['blockdir'];
6456 
6457 		// *********** BLOCK BACKGROUND COLOR *****************//
6458 		if ($this->blk[$this->blklvl]['bgcolor'] && !$is_table) {
6459 			$fill = 0;
6460 		} else {
6461 			$this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
6462 			$fill = 0;
6463 		}
6464 
6465 		$hanger = '';
6466 		// Always right trim!
6467 		// Right trim last content and adjust width if needed to justify (later)
6468 		if (isset($content[count($content) - 1]) && preg_match('/[ ]+$/', $content[count($content) - 1], $m)) {
6469 			$strip = strlen($m[0]);
6470 			$content[count($content) - 1] = substr($content[count($content) - 1], 0, (strlen($content[count($content) - 1]) - $strip));
6471 			/* -- OTL -- */
6472 			if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
6473 				$this->otl->trimOTLdata($cOTLdata[count($cOTLdata) - 1], false, true);
6474 			}
6475 			/* -- END OTL -- */
6476 		}
6477 
6478 		// the amount of space taken up so far in user units
6479 		$usedWidth = 0;
6480 
6481 		// COLS
6482 		$oldcolumn = $this->CurrCol;
6483 
6484 		if ($this->ColActive && !$is_table) {
6485 			$this->breakpoints[$this->CurrCol][] = $this->y;
6486 		} // *COLUMNS*
6487 		// Print out each chunk
6488 
6489 		/* -- TABLES -- */
6490 		if ($is_table) {
6491 			$ipaddingL = 0;
6492 			$ipaddingR = 0;
6493 			$paddingL = 0;
6494 			$paddingR = 0;
6495 		} else {
6496 			/* -- END TABLES -- */
6497 			$ipaddingL = $this->blk[$this->blklvl]['padding_left'];
6498 			$ipaddingR = $this->blk[$this->blklvl]['padding_right'];
6499 			$paddingL = ($ipaddingL * Mpdf::SCALE);
6500 			$paddingR = ($ipaddingR * Mpdf::SCALE);
6501 			$this->cMarginL = $this->blk[$this->blklvl]['border_left']['w'];
6502 			$this->cMarginR = $this->blk[$this->blklvl]['border_right']['w'];
6503 
6504 			// Added mPDF 3.0 Float DIV
6505 			$fpaddingR = 0;
6506 			$fpaddingL = 0;
6507 			/* -- CSS-FLOAT -- */
6508 			if (count($this->floatDivs)) {
6509 				list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($this->blklvl);
6510 				if ($r_exists) {
6511 					$fpaddingR = $r_width;
6512 				}
6513 				if ($l_exists) {
6514 					$fpaddingL = $l_width;
6515 				}
6516 			}
6517 			/* -- END CSS-FLOAT -- */
6518 
6519 			$usey = $this->y + 0.002;
6520 			if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 0)) {
6521 				$usey += $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'];
6522 			}
6523 			/* -- CSS-IMAGE-FLOAT -- */
6524 			// If float exists at this level
6525 			if (isset($this->floatmargins['R']) && $usey <= $this->floatmargins['R']['y1'] && $usey >= $this->floatmargins['R']['y0'] && !$this->floatmargins['R']['skipline']) {
6526 				$fpaddingR += $this->floatmargins['R']['w'];
6527 			}
6528 			if (isset($this->floatmargins['L']) && $usey <= $this->floatmargins['L']['y1'] && $usey >= $this->floatmargins['L']['y0'] && !$this->floatmargins['L']['skipline']) {
6529 				$fpaddingL += $this->floatmargins['L']['w'];
6530 			}
6531 			/* -- END CSS-IMAGE-FLOAT -- */
6532 		} // *TABLES*
6533 
6534 
6535 		$lineBox = [];
6536 
6537 		$this->_setInlineBlockHeights($lineBox, $stackHeight, $content, $font, $is_table);
6538 
6539 		if ($is_table && count($content) == 0) {
6540 			$stackHeight = 0;
6541 		}
6542 
6543 		if ($table_draft) {
6544 			$this->y += $stackHeight;
6545 			$this->objectbuffer = [];
6546 			return 0;
6547 		}
6548 
6549 		// While we're at it, check if contains cursive text
6550 		// Change NBSP to SPACE.
6551 		// Re-calculate contentWidth
6552 		$contentWidth = 0;
6553 
6554 		foreach ($content as $k => $chunk) {
6555 			$this->restoreFont($font[$k], false);
6556 			if (!isset($this->objectbuffer[$k]) || (isset($this->objectbuffer[$k]) && !$this->objectbuffer[$k])) {
6557 				// Soft Hyphens chr(173)
6558 				if (!$this->usingCoreFont) {
6559 					/* -- OTL -- */
6560 					// mPDF 5.7.1
6561 					if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
6562 						$this->otl->removeChar($chunk, $cOTLdata[$k], "\xc2\xad");
6563 						$this->otl->replaceSpace($chunk, $cOTLdata[$k]);
6564 						$content[$k] = $chunk;
6565 					} /* -- END OTL -- */ else {  // *OTL*
6566 						$content[$k] = $chunk = str_replace("\xc2\xad", '', $chunk);
6567 						$content[$k] = $chunk = str_replace(chr(194) . chr(160), chr(32), $chunk);
6568 					} // *OTL*
6569 				} elseif ($this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats') {
6570 					$content[$k] = $chunk = str_replace(chr(173), '', $chunk);
6571 					$content[$k] = $chunk = str_replace(chr(160), chr(32), $chunk);
6572 				}
6573 				$contentWidth += $this->GetStringWidth($chunk, true, (isset($cOTLdata[$k]) ? $cOTLdata[$k] : false), $this->textvar) * Mpdf::SCALE;
6574 			} elseif (isset($this->objectbuffer[$k]) && $this->objectbuffer[$k]) {
6575 				// LIST MARKERS	// mPDF 6  Lists
6576 				if ($this->objectbuffer[$k]['type'] == 'image' && isset($this->objectbuffer[$k]['listmarker']) && $this->objectbuffer[$k]['listmarker'] && $this->objectbuffer[$k]['listmarkerposition'] == 'outside') {
6577 					// do nothing
6578 				} else {
6579 					$contentWidth += $this->objectbuffer[$k]['OUTER-WIDTH'] * Mpdf::SCALE;
6580 				}
6581 			}
6582 		}
6583 
6584 		if (isset($font[count($font) - 1])) {
6585 			$lastfontreqstyle = (isset($font[count($font) - 1]['ReqFontStyle']) ? $font[count($font) - 1]['ReqFontStyle'] : '');
6586 			$lastfontstyle = (isset($font[count($font) - 1]['style']) ? $font[count($font) - 1]['style'] : '');
6587 		} else {
6588 			$lastfontreqstyle = null;
6589 			$lastfontstyle = null;
6590 		}
6591 		if ($blockdir == 'ltr' && $lastfontreqstyle && strpos($lastfontreqstyle, "I") !== false && strpos($lastfontstyle, "I") === false) { // Artificial italic
6592 			$lastitalic = $this->FontSize * 0.15 * Mpdf::SCALE;
6593 		} else {
6594 			$lastitalic = 0;
6595 		}
6596 
6597 		// Get PAGEBREAK TO TEST for height including the bottom border/padding
6598 		$check_h = max($this->divheight, $stackHeight);
6599 
6600 		// This fixes a proven bug...
6601 		if ($endofblock && $newblock && $blockstate == 0 && !$content) {
6602 			$check_h = 0;
6603 		}
6604 		// but ? needs to fix potentially more widespread...
6605 		// if (!$content) {  $check_h = 0; }
6606 
6607 		if ($this->blklvl > 0 && !$is_table) {
6608 			if ($endofblock && $blockstate > 1) {
6609 				if ($this->blk[$this->blklvl]['page_break_after_avoid']) {
6610 					$check_h += $stackHeight;
6611 				}
6612 				$check_h += ($this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w']);
6613 			}
6614 			if (($newblock && ($blockstate == 1 || $blockstate == 3) && $lineCount == 0) || ($endofblock && $blockstate == 3 && $lineCount == 0)) {
6615 				$check_h += ($this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['border_top']['w']);
6616 			}
6617 		}
6618 
6619 		// Force PAGE break if column height cannot take check-height
6620 		if ($this->ColActive && $check_h > ($this->PageBreakTrigger - $this->y0)) {
6621 			$this->SetCol($this->NbCol - 1);
6622 		}
6623 
6624 		// Avoid just border/background-color moved on to next page
6625 		if ($endofblock && $blockstate > 1 && !$content) {
6626 			$buff = $this->margBuffer;
6627 		} else {
6628 			$buff = 0;
6629 		}
6630 
6631 
6632 		// PAGEBREAK
6633 		if (!$is_table && ($this->y + $check_h) > ($this->PageBreakTrigger + $buff) and ! $this->InFooter and $this->AcceptPageBreak()) {
6634 			$bak_x = $this->x; // Current X position
6635 			// WORD SPACING
6636 			$ws = $this->ws; // Word Spacing
6637 			$charspacing = $this->charspacing; // Character Spacing
6638 			$this->ResetSpacing();
6639 
6640 			$this->AddPage($this->CurOrientation);
6641 
6642 			$this->x = $bak_x;
6643 			// Added to correct for OddEven Margins
6644 			$currentx += $this->MarginCorrection;
6645 			$this->x += $this->MarginCorrection;
6646 
6647 			// WORD SPACING
6648 			$this->SetSpacing($charspacing, $ws);
6649 		}
6650 
6651 
6652 		/* -- COLUMNS -- */
6653 		// COLS
6654 		// COLUMN CHANGE
6655 		if ($this->CurrCol != $oldcolumn) {
6656 			$currentx += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
6657 			$this->x += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
6658 			$oldcolumn = $this->CurrCol;
6659 		}
6660 
6661 
6662 		if ($this->ColActive && !$is_table) {
6663 			$this->breakpoints[$this->CurrCol][] = $this->y;
6664 		}
6665 		/* -- END COLUMNS -- */
6666 
6667 		// TOP MARGIN
6668 		if ($newblock && ($blockstate == 1 || $blockstate == 3) && ($this->blk[$this->blklvl]['margin_top']) && $lineCount == 0 && !$is_table) {
6669 			$this->DivLn($this->blk[$this->blklvl]['margin_top'], $this->blklvl - 1, true, $this->blk[$this->blklvl]['margin_collapse']);
6670 			if ($this->ColActive) {
6671 				$this->breakpoints[$this->CurrCol][] = $this->y;
6672 			} // *COLUMNS*
6673 		}
6674 
6675 		if ($newblock && ($blockstate == 1 || $blockstate == 3) && $lineCount == 0 && !$is_table) {
6676 			$this->blk[$this->blklvl]['y0'] = $this->y;
6677 			$this->blk[$this->blklvl]['startpage'] = $this->page;
6678 			if ($this->blk[$this->blklvl]['float']) {
6679 				$this->blk[$this->blklvl]['float_start_y'] = $this->y;
6680 			}
6681 			if ($this->ColActive) {
6682 				$this->breakpoints[$this->CurrCol][] = $this->y;
6683 			} // *COLUMNS*
6684 		}
6685 
6686 		// Paragraph INDENT
6687 		$WidthCorrection = 0;
6688 		if (($newblock) && ($blockstate == 1 || $blockstate == 3) && isset($this->blk[$this->blklvl]['text_indent']) && ($lineCount == 0) && (!$is_table) && ($align != 'C')) {
6689 			$ti = $this->sizeConverter->convert($this->blk[$this->blklvl]['text_indent'], $this->blk[$this->blklvl]['inner_width'], $this->blk[$this->blklvl]['InlineProperties']['size'], false);  // mPDF 5.7.4
6690 			$WidthCorrection = ($ti * Mpdf::SCALE);
6691 		}
6692 
6693 
6694 		// PADDING and BORDER spacing/fill
6695 		if (($newblock) && ($blockstate == 1 || $blockstate == 3) && (($this->blk[$this->blklvl]['padding_top']) || ($this->blk[$this->blklvl]['border_top'])) && ($lineCount == 0) && (!$is_table)) {
6696 			// $state = 0 normal; 1 top; 2 bottom; 3 top and bottom
6697 			$this->DivLn($this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'], -3, true, false, 1);
6698 			if ($this->ColActive) {
6699 				$this->breakpoints[$this->CurrCol][] = $this->y;
6700 			} // *COLUMNS*
6701 			$this->x = $currentx;
6702 		}
6703 
6704 
6705 		// Added mPDF 3.0 Float DIV
6706 		$fpaddingR = 0;
6707 		$fpaddingL = 0;
6708 		/* -- CSS-FLOAT -- */
6709 		if (count($this->floatDivs)) {
6710 			list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($this->blklvl);
6711 			if ($r_exists) {
6712 				$fpaddingR = $r_width;
6713 			}
6714 			if ($l_exists) {
6715 				$fpaddingL = $l_width;
6716 			}
6717 		}
6718 		/* -- END CSS-FLOAT -- */
6719 
6720 		$usey = $this->y + 0.002;
6721 		if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 0)) {
6722 			$usey += $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'];
6723 		}
6724 		/* -- CSS-IMAGE-FLOAT -- */
6725 		// If float exists at this level
6726 		if (isset($this->floatmargins['R']) && $usey <= $this->floatmargins['R']['y1'] && $usey >= $this->floatmargins['R']['y0'] && !$this->floatmargins['R']['skipline']) {
6727 			$fpaddingR += $this->floatmargins['R']['w'];
6728 		}
6729 		if (isset($this->floatmargins['L']) && $usey <= $this->floatmargins['L']['y1'] && $usey >= $this->floatmargins['L']['y0'] && !$this->floatmargins['L']['skipline']) {
6730 			$fpaddingL += $this->floatmargins['L']['w'];
6731 		}
6732 		/* -- END CSS-IMAGE-FLOAT -- */
6733 
6734 
6735 		if ($content) {
6736 			// In FinishFlowing Block no lines are justified as it is always last line
6737 			// but if CJKorphan has allowed content width to go over max width, use J charspacing to compress line
6738 			// JUSTIFICATION J - NOT!
6739 			$nb_carac = 0;
6740 			$nb_spaces = 0;
6741 			$jcharspacing = 0;
6742 			$jkashida = 0;
6743 			$jws = 0;
6744 			$inclCursive = false;
6745 			$dottab = false;
6746 			foreach ($content as $k => $chunk) {
6747 				if (!isset($this->objectbuffer[$k]) || (isset($this->objectbuffer[$k]) && !$this->objectbuffer[$k])) {
6748 					$nb_carac += mb_strlen($chunk, $this->mb_enc);
6749 					$nb_spaces += mb_substr_count($chunk, ' ', $this->mb_enc);
6750 					// mPDF 6
6751 					// Use GPOS OTL
6752 					$this->restoreFont($font[$k], false);
6753 					if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
6754 						if (isset($cOTLdata[$k]['group']) && $cOTLdata[$k]['group']) {
6755 							$nb_marks = substr_count($cOTLdata[$k]['group'], 'M');
6756 							$nb_carac -= $nb_marks;
6757 						}
6758 						if (preg_match("/([" . $this->pregCURSchars . "])/u", $chunk)) {
6759 							$inclCursive = true;
6760 						}
6761 					}
6762 				} else {
6763 					$nb_carac ++;  // mPDF 6 allow spacing for inline object
6764 					if ($this->objectbuffer[$k]['type'] == 'dottab') {
6765 						$dottab = $this->objectbuffer[$k]['outdent'];
6766 					}
6767 				}
6768 			}
6769 
6770 			// DIRECTIONALITY RTL
6771 			$chunkorder = range(0, count($content) - 1); // mPDF 6
6772 			/* -- OTL -- */
6773 			// mPDF 6
6774 			if ($blockdir == 'rtl' || $this->biDirectional) {
6775 				$this->otl->bidiReorder($chunkorder, $content, $cOTLdata, $blockdir);
6776 				// From this point on, $content and $cOTLdata may contain more elements (and re-ordered) compared to
6777 				// $this->objectbuffer and $font ($chunkorder contains the mapping)
6778 			}
6779 			/* -- END OTL -- */
6780 
6781 			// Remove any XAdvance from OTL data at end of line
6782 			// And correct for XPlacement on last character
6783 			// BIDI is applied
6784 			foreach ($chunkorder as $aord => $k) {
6785 				if (count($cOTLdata)) {
6786 					$this->restoreFont($font[$k], false);
6787 					// ...FinishFlowingBlock...
6788 					if ($aord == count($chunkorder) - 1 && isset($cOTLdata[$aord]['group'])) { // Last chunk on line
6789 						$nGPOS = strlen($cOTLdata[$aord]['group']) - 1; // Last character
6790 						if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL']) || isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'])) {
6791 							if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'])) {
6792 								$w = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] * 1000 / $this->CurrentFont['unitsPerEm'];
6793 							} else {
6794 								$w = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] * 1000 / $this->CurrentFont['unitsPerEm'];
6795 							}
6796 							$w *= ($this->FontSize / 1000);
6797 							$contentWidth -= $w * Mpdf::SCALE;
6798 							$cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] = 0;
6799 							$cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] = 0;
6800 						}
6801 
6802 						// If last character has an XPlacement set, adjust width calculation, and add to XAdvance to account for it
6803 						if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'])) {
6804 							$w = -$cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'] * 1000 / $this->CurrentFont['unitsPerEm'];
6805 							$w *= ($this->FontSize / 1000);
6806 							$contentWidth -= $w * Mpdf::SCALE;
6807 							$cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'];
6808 							$cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'];
6809 						}
6810 					}
6811 				}
6812 			}
6813 
6814 			// if it's justified, we need to find the char/word spacing (or if orphans have allowed length of line to go over the maxwidth)
6815 			// If "orphans" in fact is just a final space - ignore this
6816 			$lastchar = mb_substr($content[(count($chunkorder) - 1)], mb_strlen($content[(count($chunkorder) - 1)], $this->mb_enc) - 1, 1, $this->mb_enc);
6817 			if (preg_match("/[" . $this->CJKoverflow . "]/u", $lastchar)) {
6818 				$CJKoverflow = true;
6819 			} else {
6820 				$CJKoverflow = false;
6821 			}
6822 			if ((((($contentWidth + $lastitalic) > $maxWidth) && ($content[(count($chunkorder) - 1)] != ' ') ) ||
6823 				(!$endofblock && $align == 'J' && ($next == 'image' || $next == 'select' || $next == 'input' || $next == 'textarea' || ($next == 'br' && $this->justifyB4br)))) && !($CJKoverflow && $this->allowCJKoverflow)) {
6824 				// WORD SPACING
6825 				list($jcharspacing, $jws, $jkashida) = $this->GetJspacing($nb_carac, $nb_spaces, ($maxWidth - $lastitalic - $contentWidth - $WidthCorrection - (($this->cMarginL + $this->cMarginR) * Mpdf::SCALE) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * Mpdf::SCALE) )), $inclCursive, $cOTLdata);
6826 			} /* -- CJK-FONTS -- */ elseif ($this->checkCJK && $align == 'J' && $CJKoverflow && $this->allowCJKoverflow && $this->CJKforceend) {
6827 				// force-end overhang
6828 				$hanger = mb_substr($content[(count($chunkorder) - 1)], mb_strlen($content[(count($chunkorder) - 1)], $this->mb_enc) - 1, 1, $this->mb_enc);
6829 				if (preg_match("/[" . $this->CJKoverflow . "]/u", $hanger)) {
6830 					$content[(count($chunkorder) - 1)] = mb_substr($content[(count($chunkorder) - 1)], 0, mb_strlen($content[(count($chunkorder) - 1)], $this->mb_enc) - 1, $this->mb_enc);
6831 					$this->restoreFont($font[$chunkorder[count($chunkorder) - 1]], false);
6832 					$contentWidth -= $this->GetStringWidth($hanger) * Mpdf::SCALE;
6833 					$nb_carac -= 1;
6834 					list($jcharspacing, $jws, $jkashida) = $this->GetJspacing($nb_carac, $nb_spaces, ($maxWidth - $lastitalic - $contentWidth - $WidthCorrection - (($this->cMarginL + $this->cMarginR) * Mpdf::SCALE) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * Mpdf::SCALE) )), $inclCursive, $cOTLdata);
6835 				}
6836 			} /* -- END CJK-FONTS -- */
6837 
6838 			// Check if will fit at word/char spacing of previous line - if so continue it
6839 			// but only allow a maximum of $this->jSmaxWordLast and $this->jSmaxCharLast
6840 			elseif ($contentWidth < ($maxWidth - $lastitalic - $WidthCorrection - (($this->cMarginL + $this->cMarginR) * Mpdf::SCALE) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * Mpdf::SCALE))) && !$this->fixedlSpacing) {
6841 				if ($this->ws > $this->jSmaxWordLast) {
6842 					$jws = $this->jSmaxWordLast;
6843 				}
6844 				if ($this->charspacing > $this->jSmaxCharLast) {
6845 					$jcharspacing = $this->jSmaxCharLast;
6846 				}
6847 				$check = $maxWidth - $lastitalic - $WidthCorrection - $contentWidth - (($this->cMarginL + $this->cMarginR) * Mpdf::SCALE) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * Mpdf::SCALE) ) - ( $jcharspacing * $nb_carac) - ( $jws * $nb_spaces);
6848 				if ($check <= 0) {
6849 					$jcharspacing = 0;
6850 					$jws = 0;
6851 				}
6852 			}
6853 
6854 			$empty = $maxWidth - $lastitalic - $WidthCorrection - $contentWidth - (($this->cMarginL + $this->cMarginR) * Mpdf::SCALE) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * Mpdf::SCALE) );
6855 
6856 
6857 			$empty -= ($jcharspacing * ($nb_carac - 1)); // mPDF 6 nb_carac MINUS 1
6858 			$empty -= ($jws * $nb_spaces);
6859 			$empty -= ($jkashida);
6860 
6861 			$empty /= Mpdf::SCALE;
6862 
6863 			if (!$is_table) {
6864 				$this->maxPosR = max($this->maxPosR, ($this->w - $this->rMargin - $this->blk[$this->blklvl]['outer_right_margin'] - $empty));
6865 				$this->maxPosL = min($this->maxPosL, ($this->lMargin + $this->blk[$this->blklvl]['outer_left_margin'] + $empty));
6866 			}
6867 
6868 			$arraysize = count($chunkorder);
6869 
6870 			$margins = ($this->cMarginL + $this->cMarginR) + ($ipaddingL + $ipaddingR + $fpaddingR + $fpaddingR );
6871 
6872 			if (!$is_table) {
6873 				$this->DivLn($stackHeight, $this->blklvl, false);
6874 			} // false -> don't advance y
6875 
6876 			$this->x = $currentx + $this->cMarginL + $ipaddingL + $fpaddingL;
6877 			if ($dottab !== false && $blockdir == 'rtl') {
6878 				$this->x -= $dottab;
6879 			} elseif ($align == 'R') {
6880 				$this->x += $empty;
6881 			} elseif ($align == 'J' && $blockdir == 'rtl') {
6882 				$this->x += $empty;
6883 			} elseif ($align == 'C') {
6884 				$this->x += ($empty / 2);
6885 			}
6886 
6887 			// Paragraph INDENT
6888 			$WidthCorrection = 0;
6889 			if (($newblock) && ($blockstate == 1 || $blockstate == 3) && isset($this->blk[$this->blklvl]['text_indent']) && ($lineCount == 0) && (!$is_table) && ($align != 'C')) {
6890 				$ti = $this->sizeConverter->convert($this->blk[$this->blklvl]['text_indent'], $this->blk[$this->blklvl]['inner_width'], $this->blk[$this->blklvl]['InlineProperties']['size'], false);  // mPDF 5.7.4
6891 				if ($blockdir != 'rtl') {
6892 					$this->x += $ti;
6893 				} // mPDF 6
6894 			}
6895 
6896 			foreach ($chunkorder as $aord => $k) { // mPDF 5.7
6897 				$chunk = $content[$aord];
6898 				if (isset($this->objectbuffer[$k]) && $this->objectbuffer[$k]) {
6899 					$xadj = $this->x - $this->objectbuffer[$k]['OUTER-X'];
6900 					$this->objectbuffer[$k]['OUTER-X'] += $xadj;
6901 					$this->objectbuffer[$k]['BORDER-X'] += $xadj;
6902 					$this->objectbuffer[$k]['INNER-X'] += $xadj;
6903 
6904 					if ($this->objectbuffer[$k]['type'] == 'listmarker') {
6905 						$this->objectbuffer[$k]['lineBox'] = $lineBox[-1]; // Block element details for glyph-origin
6906 					}
6907 					$yadj = $this->y - $this->objectbuffer[$k]['OUTER-Y'];
6908 					if ($this->objectbuffer[$k]['type'] == 'dottab') { // mPDF 6 DOTTAB
6909 						$this->objectbuffer[$k]['lineBox'] = $lineBox[$k]; // element details for glyph-origin
6910 					}
6911 					if ($this->objectbuffer[$k]['type'] != 'dottab') { // mPDF 6 DOTTAB
6912 						$yadj += $lineBox[$k]['top'];
6913 					}
6914 					$this->objectbuffer[$k]['OUTER-Y'] += $yadj;
6915 					$this->objectbuffer[$k]['BORDER-Y'] += $yadj;
6916 					$this->objectbuffer[$k]['INNER-Y'] += $yadj;
6917 				}
6918 
6919 				$this->restoreFont($font[$k]);  // mPDF 5.7
6920 
6921 				if ($is_table && substr($align, 0, 1) == 'D' && $aord == 0) {
6922 					$dp = $this->decimal_align[substr($align, 0, 2)];
6923 					$s = preg_split('/' . preg_quote($dp, '/') . '/', $content[0], 2);  // ? needs to be /u if not core
6924 					$s0 = $this->GetStringWidth($s[0], false);
6925 					$this->x += ($this->decimal_offset - $s0);
6926 				}
6927 
6928 				$this->SetSpacing(($this->fixedlSpacing * Mpdf::SCALE) + $jcharspacing, ($this->fixedlSpacing + $this->minwSpacing) * Mpdf::SCALE + $jws);
6929 				$this->fixedlSpacing = false;
6930 				$this->minwSpacing = 0;
6931 
6932 				$save_vis = $this->visibility;
6933 				if (isset($this->textparam['visibility']) && $this->textparam['visibility'] && $this->textparam['visibility'] != $this->visibility) {
6934 					$this->SetVisibility($this->textparam['visibility']);
6935 				}
6936 
6937 				// *********** SPAN BACKGROUND COLOR ***************** //
6938 				if (isset($this->spanbgcolor) && $this->spanbgcolor) {
6939 					$cor = $this->spanbgcolorarray;
6940 					$this->SetFColor($cor);
6941 					$save_fill = $fill;
6942 					$spanfill = 1;
6943 					$fill = 1;
6944 				}
6945 				if (!empty($this->spanborddet)) {
6946 					if (strpos($contentB[$k], 'L') !== false && isset($this->spanborddet['L'])) {
6947 						$this->x += $this->spanborddet['L']['w'];
6948 					}
6949 					if (strpos($contentB[$k], 'L') === false) {
6950 						$this->spanborddet['L']['s'] = $this->spanborddet['L']['w'] = 0;
6951 					}
6952 					if (strpos($contentB[$k], 'R') === false) {
6953 						$this->spanborddet['R']['s'] = $this->spanborddet['R']['w'] = 0;
6954 					}
6955 				}
6956 				// WORD SPACING
6957 				// mPDF 5.7.1
6958 				$stringWidth = $this->GetStringWidth($chunk, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar);
6959 				$nch = mb_strlen($chunk, $this->mb_enc);
6960 				// Use GPOS OTL
6961 				if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
6962 					if (isset($cOTLdata[$aord]['group']) && $cOTLdata[$aord]['group']) {
6963 						$nch -= substr_count($cOTLdata[$aord]['group'], 'M');
6964 					}
6965 				}
6966 				$stringWidth += ( $this->charspacing * $nch / Mpdf::SCALE );
6967 
6968 				$stringWidth += ( $this->ws * mb_substr_count($chunk, ' ', $this->mb_enc) / Mpdf::SCALE );
6969 
6970 				if (isset($this->objectbuffer[$k])) {
6971 					if ($this->objectbuffer[$k]['type'] == 'dottab') {
6972 						$this->objectbuffer[$k]['OUTER-WIDTH'] +=$empty;
6973 						$this->objectbuffer[$k]['OUTER-WIDTH'] +=$this->objectbuffer[$k]['outdent'];
6974 					}
6975 					// LIST MARKERS	// mPDF 6  Lists
6976 					if ($this->objectbuffer[$k]['type'] == 'image' && isset($this->objectbuffer[$k]['listmarker']) && $this->objectbuffer[$k]['listmarker'] && $this->objectbuffer[$k]['listmarkerposition'] == 'outside') {
6977 						// do nothing
6978 					} else {
6979 						$stringWidth = $this->objectbuffer[$k]['OUTER-WIDTH'];
6980 					}
6981 				}
6982 
6983 				if ($stringWidth == 0) {
6984 					$stringWidth = 0.000001;
6985 				}
6986 				if ($aord == $arraysize - 1) { // mPDF 5.7
6987 					// mPDF 5.7.1
6988 					if ($this->checkCJK && $CJKoverflow && $align == 'J' && $this->allowCJKoverflow && $hanger && $this->CJKforceend) {
6989 						// force-end overhang
6990 						$this->Cell($stringWidth, $stackHeight, $chunk, '', 0, '', $fill, $this->HREF, $currentx, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false));  // mPDF 5.7.1
6991 						$this->Cell($this->GetStringWidth($hanger), $stackHeight, $hanger, '', 1, '', $fill, $this->HREF, $currentx, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false)); // mPDF 5.7.1
6992 					} else {
6993 						$this->Cell($stringWidth, $stackHeight, $chunk, '', 1, '', $fill, $this->HREF, $currentx, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false)); // mPDF 5.7.1
6994 					}
6995 				} else {
6996 					$this->Cell($stringWidth, $stackHeight, $chunk, '', 0, '', $fill, $this->HREF, 0, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false)); // first or middle part	// mPDF 5.7.1
6997 				}
6998 
6999 
7000 				if (!empty($this->spanborddet)) {
7001 					if (strpos($contentB[$k], 'R') !== false && $aord != $arraysize - 1) {
7002 						$this->x += $this->spanborddet['R']['w'];
7003 					}
7004 				}
7005 				// *********** SPAN BACKGROUND COLOR OFF - RESET BLOCK BGCOLOR ***************** //
7006 				if (isset($spanfill) && $spanfill) {
7007 					$fill = $save_fill;
7008 					$spanfill = 0;
7009 					if ($fill) {
7010 						$this->SetFColor($bcor);
7011 					}
7012 				}
7013 				if (isset($this->textparam['visibility']) && $this->textparam['visibility'] && $this->visibility != $save_vis) {
7014 					$this->SetVisibility($save_vis);
7015 				}
7016 			}
7017 
7018 			$this->printobjectbuffer($is_table, $blockdir);
7019 			$this->objectbuffer = [];
7020 			$this->ResetSpacing();
7021 		} // END IF CONTENT
7022 
7023 		/* -- CSS-IMAGE-FLOAT -- */
7024 		// Update values if set to skipline
7025 		if ($this->floatmargins) {
7026 			$this->_advanceFloatMargins();
7027 		}
7028 
7029 
7030 		if ($endofblock && $blockstate > 1) {
7031 			// If float exists at this level
7032 			if (isset($this->floatmargins['R']['y1'])) {
7033 				$fry1 = $this->floatmargins['R']['y1'];
7034 			} else {
7035 				$fry1 = 0;
7036 			}
7037 			if (isset($this->floatmargins['L']['y1'])) {
7038 				$fly1 = $this->floatmargins['L']['y1'];
7039 			} else {
7040 				$fly1 = 0;
7041 			}
7042 			if ($this->y < $fry1 || $this->y < $fly1) {
7043 				$drop = max($fry1, $fly1) - $this->y;
7044 				$this->DivLn($drop);
7045 				$this->x = $currentx;
7046 			}
7047 		}
7048 		/* -- END CSS-IMAGE-FLOAT -- */
7049 
7050 
7051 		// PADDING and BORDER spacing/fill
7052 		if ($endofblock && ($blockstate > 1) && ($this->blk[$this->blklvl]['padding_bottom'] || $this->blk[$this->blklvl]['border_bottom'] || $this->blk[$this->blklvl]['css_set_height']) && (!$is_table)) {
7053 			// If CSS height set, extend bottom - if on same page as block started, and CSS HEIGHT > actual height,
7054 			// and does not force pagebreak
7055 			$extra = 0;
7056 			if (isset($this->blk[$this->blklvl]['css_set_height']) && $this->blk[$this->blklvl]['css_set_height'] && $this->blk[$this->blklvl]['startpage'] == $this->page) {
7057 				// predicted height
7058 				$h1 = ($this->y - $this->blk[$this->blklvl]['y0']) + $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w'];
7059 				if ($h1 < ($this->blk[$this->blklvl]['css_set_height'] + $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['padding_top'])) {
7060 					$extra = ($this->blk[$this->blklvl]['css_set_height'] + $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['padding_top']) - $h1;
7061 				}
7062 				if ($this->y + $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w'] + $extra > $this->PageBreakTrigger) {
7063 					$extra = $this->PageBreakTrigger - ($this->y + $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w']);
7064 				}
7065 			}
7066 
7067 			// $state = 0 normal; 1 top; 2 bottom; 3 top and bottom
7068 			$this->DivLn($this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w'] + $extra, -3, true, false, 2);
7069 			$this->x = $currentx;
7070 
7071 			if ($this->ColActive) {
7072 				$this->breakpoints[$this->CurrCol][] = $this->y;
7073 			} // *COLUMNS*
7074 		}
7075 
7076 		// SET Bottom y1 of block (used for painting borders)
7077 		if (($endofblock) && ($blockstate > 1) && (!$is_table)) {
7078 			$this->blk[$this->blklvl]['y1'] = $this->y;
7079 		}
7080 
7081 		// BOTTOM MARGIN
7082 		if (($endofblock) && ($blockstate > 1) && ($this->blk[$this->blklvl]['margin_bottom']) && (!$is_table)) {
7083 			if ($this->y + $this->blk[$this->blklvl]['margin_bottom'] < $this->PageBreakTrigger and ! $this->InFooter) {
7084 				$this->DivLn($this->blk[$this->blklvl]['margin_bottom'], $this->blklvl - 1, true, $this->blk[$this->blklvl]['margin_collapse']);
7085 				if ($this->ColActive) {
7086 					$this->breakpoints[$this->CurrCol][] = $this->y;
7087 				} // *COLUMNS*
7088 			}
7089 		}
7090 
7091 		// Reset lineheight
7092 		$stackHeight = $this->divheight;
7093 	}
7094 
7095 	function printobjectbuffer($is_table = false, $blockdir = false)
7096 	{
7097 		if (!$blockdir) {
7098 			$blockdir = $this->directionality;
7099 		}
7100 
7101 		if ($is_table && $this->shrin_k > 1) {
7102 			$k = $this->shrin_k;
7103 		} else {
7104 			$k = 1;
7105 		}
7106 
7107 		$save_y = $this->y;
7108 		$save_x = $this->x;
7109 
7110 		$save_currentfontfamily = $this->FontFamily;
7111 		$save_currentfontsize = $this->FontSizePt;
7112 		$save_currentfontstyle = $this->FontStyle;
7113 
7114 		if ($blockdir == 'rtl') {
7115 			$rtlalign = 'R';
7116 		} else {
7117 			$rtlalign = 'L';
7118 		}
7119 
7120 		foreach ($this->objectbuffer as $ib => $objattr) {
7121 
7122 			if ($objattr['type'] == 'bookmark' || $objattr['type'] == 'indexentry' || $objattr['type'] == 'toc') {
7123 				$x = $objattr['OUTER-X'];
7124 				$y = $objattr['OUTER-Y'];
7125 				$this->y = $y - $this->FontSize / 2;
7126 				$this->x = $x;
7127 				if ($objattr['type'] == 'bookmark') {
7128 					$this->Bookmark($objattr['CONTENT'], $objattr['bklevel'], $y - $this->FontSize);
7129 				} // *BOOKMARKS*
7130 				if ($objattr['type'] == 'indexentry') {
7131 					$this->IndexEntry($objattr['CONTENT']);
7132 				} // *INDEX*
7133 				if ($objattr['type'] == 'toc') {
7134 					$this->TOC_Entry($objattr['CONTENT'], $objattr['toclevel'], (isset($objattr['toc_id']) ? $objattr['toc_id'] : ''));
7135 				} // *TOC*
7136 			} /* -- ANNOTATIONS -- */ elseif ($objattr['type'] == 'annot') {
7137 				if ($objattr['POS-X']) {
7138 					$x = $objattr['POS-X'];
7139 				} elseif ($this->annotMargin <> 0) {
7140 					$x = -$objattr['OUTER-X'];
7141 				} else {
7142 					$x = $objattr['OUTER-X'];
7143 				}
7144 				if ($objattr['POS-Y']) {
7145 					$y = $objattr['POS-Y'];
7146 				} else {
7147 					$y = $objattr['OUTER-Y'] - $this->FontSize / 2;
7148 				}
7149 				// Create a dummy entry in the _out/columnBuffer with position sensitive data,
7150 				// linking $y-1 in the Columnbuffer with entry in $this->columnAnnots
7151 				// and when columns are split in length will not break annotation from current line
7152 				$this->y = $y - 1;
7153 				$this->x = $x - 1;
7154 				$this->Line($x - 1, $y - 1, $x - 1, $y - 1);
7155 				$this->Annotation($objattr['CONTENT'], $x, $y, $objattr['ICON'], $objattr['AUTHOR'], $objattr['SUBJECT'], $objattr['OPACITY'], $objattr['COLOR'], (isset($objattr['POPUP']) ? $objattr['POPUP'] : ''), (isset($objattr['FILE']) ? $objattr['FILE'] : ''));
7156 			} /* -- END ANNOTATIONS -- */ else {
7157 				$y = $objattr['OUTER-Y'];
7158 				$x = $objattr['OUTER-X'];
7159 				$w = $objattr['OUTER-WIDTH'];
7160 				$h = $objattr['OUTER-HEIGHT'];
7161 				if (isset($objattr['text'])) {
7162 					$texto = $objattr['text'];
7163 				}
7164 				$this->y = $y;
7165 				$this->x = $x;
7166 				if (isset($objattr['fontfamily'])) {
7167 					$this->SetFont($objattr['fontfamily'], '', $objattr['fontsize']);
7168 				}
7169 			}
7170 
7171 			// HR
7172 			if ($objattr['type'] == 'hr') {
7173 				$this->SetDColor($objattr['color']);
7174 				switch ($objattr['align']) {
7175 					case 'C':
7176 						$empty = $objattr['OUTER-WIDTH'] - $objattr['INNER-WIDTH'];
7177 						$empty /= 2;
7178 						$x += $empty;
7179 						break;
7180 					case 'R':
7181 						$empty = $objattr['OUTER-WIDTH'] - $objattr['INNER-WIDTH'];
7182 						$x += $empty;
7183 						break;
7184 				}
7185 				$oldlinewidth = $this->LineWidth;
7186 				$this->SetLineWidth($objattr['linewidth'] / $k);
7187 				$this->y += ($objattr['linewidth'] / 2) + $objattr['margin_top'] / $k;
7188 				$this->Line($x, $this->y, $x + $objattr['INNER-WIDTH'], $this->y);
7189 				$this->SetLineWidth($oldlinewidth);
7190 				$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
7191 			}
7192 			// IMAGE
7193 			if ($objattr['type'] == 'image') {
7194 				// mPDF 5.7.3 TRANSFORMS
7195 				if (isset($objattr['transform'])) {
7196 					$this->writer->write("\n" . '% BTR'); // Begin Transform
7197 				}
7198 				if (isset($objattr['z-index']) && $objattr['z-index'] > 0 && $this->current_layer == 0) {
7199 					$this->BeginLayer($objattr['z-index']);
7200 				}
7201 				if (isset($objattr['visibility']) && $objattr['visibility'] != 'visible' && $objattr['visibility']) {
7202 					$this->SetVisibility($objattr['visibility']);
7203 				}
7204 				if (isset($objattr['opacity'])) {
7205 					$this->SetAlpha($objattr['opacity']);
7206 				}
7207 
7208 				$obiw = $objattr['INNER-WIDTH'];
7209 				$obih = $objattr['INNER-HEIGHT'];
7210 
7211 				$sx = $objattr['orig_w'] ? ($objattr['INNER-WIDTH'] * Mpdf::SCALE / $objattr['orig_w']) : INF;
7212 				$sy = $objattr['orig_h'] ? ($objattr['INNER-HEIGHT'] * Mpdf::SCALE / $objattr['orig_h']) : INF;
7213 
7214 				$rotate = 0;
7215 				if (isset($objattr['ROTATE'])) {
7216 					$rotate = $objattr['ROTATE'];
7217 				}
7218 
7219 				if ($rotate == 90) {
7220 					// Clockwise
7221 					$obiw = $objattr['INNER-HEIGHT'];
7222 					$obih = $objattr['INNER-WIDTH'];
7223 					$tr = $this->transformTranslate(0, -$objattr['INNER-WIDTH'], true);
7224 					$tr .= ' ' . $this->transformRotate(90, $objattr['INNER-X'], ($objattr['INNER-Y'] + $objattr['INNER-WIDTH']), true);
7225 					$sx = $obiw * Mpdf::SCALE / $objattr['orig_h'];
7226 					$sy = $obih * Mpdf::SCALE / $objattr['orig_w'];
7227 				} elseif ($rotate == -90 || $rotate == 270) {
7228 					// AntiClockwise
7229 					$obiw = $objattr['INNER-HEIGHT'];
7230 					$obih = $objattr['INNER-WIDTH'];
7231 					$tr = $this->transformTranslate($objattr['INNER-WIDTH'], ($objattr['INNER-HEIGHT'] - $objattr['INNER-WIDTH']), true);
7232 					$tr .= ' ' . $this->transformRotate(-90, $objattr['INNER-X'], ($objattr['INNER-Y'] + $objattr['INNER-WIDTH']), true);
7233 					$sx = $obiw * Mpdf::SCALE / $objattr['orig_h'];
7234 					$sy = $obih * Mpdf::SCALE / $objattr['orig_w'];
7235 				} elseif ($rotate == 180) {
7236 					// Mirror
7237 					$tr = $this->transformTranslate($objattr['INNER-WIDTH'], -$objattr['INNER-HEIGHT'], true);
7238 					$tr .= ' ' . $this->transformRotate(180, $objattr['INNER-X'], ($objattr['INNER-Y'] + $objattr['INNER-HEIGHT']), true);
7239 				} else {
7240 					$tr = '';
7241 				}
7242 				$tr = trim($tr);
7243 				if ($tr) {
7244 					$tr .= ' ';
7245 				}
7246 				$gradmask = '';
7247 
7248 				// mPDF 5.7.3 TRANSFORMS
7249 				$tr2 = '';
7250 				if (isset($objattr['transform'])) {
7251 					$maxsize_x = $w;
7252 					$maxsize_y = $h;
7253 					$cx = $x + $w / 2;
7254 					$cy = $y + $h / 2;
7255 					preg_match_all('/(translatex|translatey|translate|scalex|scaley|scale|rotate|skewX|skewY|skew)\((.*?)\)/is', $objattr['transform'], $m);
7256 					if (count($m[0])) {
7257 						for ($i = 0; $i < count($m[0]); $i++) {
7258 							$c = strtolower($m[1][$i]);
7259 							$v = trim($m[2][$i]);
7260 							$vv = preg_split('/[ ,]+/', $v);
7261 							if ($c == 'translate' && count($vv)) {
7262 								$translate_x = $this->sizeConverter->convert($vv[0], $maxsize_x, false, false);
7263 								if (count($vv) == 2) {
7264 									$translate_y = $this->sizeConverter->convert($vv[1], $maxsize_y, false, false);
7265 								} else {
7266 									$translate_y = 0;
7267 								}
7268 								$tr2 .= $this->transformTranslate($translate_x, $translate_y, true) . ' ';
7269 							} elseif ($c == 'translatex' && count($vv)) {
7270 								$translate_x = $this->sizeConverter->convert($vv[0], $maxsize_x, false, false);
7271 								$tr2 .= $this->transformTranslate($translate_x, 0, true) . ' ';
7272 							} elseif ($c == 'translatey' && count($vv)) {
7273 								$translate_y = $this->sizeConverter->convert($vv[1], $maxsize_y, false, false);
7274 								$tr2 .= $this->transformTranslate(0, $translate_y, true) . ' ';
7275 							} elseif ($c == 'scale' && count($vv)) {
7276 								$scale_x = $vv[0] * 100;
7277 								if (count($vv) == 2) {
7278 									$scale_y = $vv[1] * 100;
7279 								} else {
7280 									$scale_y = $scale_x;
7281 								}
7282 								$tr2 .= $this->transformScale($scale_x, $scale_y, $cx, $cy, true) . ' ';
7283 							} elseif ($c == 'scalex' && count($vv)) {
7284 								$scale_x = $vv[0] * 100;
7285 								$tr2 .= $this->transformScale($scale_x, 0, $cx, $cy, true) . ' ';
7286 							} elseif ($c == 'scaley' && count($vv)) {
7287 								$scale_y = $vv[1] * 100;
7288 								$tr2 .= $this->transformScale(0, $scale_y, $cx, $cy, true) . ' ';
7289 							} elseif ($c == 'skew' && count($vv)) {
7290 								$angle_x = $this->ConvertAngle($vv[0], false);
7291 								if (count($vv) == 2) {
7292 									$angle_y = $this->ConvertAngle($vv[1], false);
7293 								} else {
7294 									$angle_y = 0;
7295 								}
7296 								$tr2 .= $this->transformSkew($angle_x, $angle_y, $cx, $cy, true) . ' ';
7297 							} elseif ($c == 'skewx' && count($vv)) {
7298 								$angle = $this->ConvertAngle($vv[0], false);
7299 								$tr2 .= $this->transformSkew($angle, 0, $cx, $cy, true) . ' ';
7300 							} elseif ($c == 'skewy' && count($vv)) {
7301 								$angle = $this->ConvertAngle($vv[0], false);
7302 								$tr2 .= $this->transformSkew(0, $angle, $cx, $cy, true) . ' ';
7303 							} elseif ($c == 'rotate' && count($vv)) {
7304 								$angle = $this->ConvertAngle($vv[0]);
7305 								$tr2 .= $this->transformRotate($angle, $cx, $cy, true) . ' ';
7306 							}
7307 						}
7308 					}
7309 				}
7310 
7311 				// LIST MARKERS (Images)	// mPDF 6  Lists
7312 				if (isset($objattr['listmarker']) && $objattr['listmarker'] && $objattr['listmarkerposition'] == 'outside') {
7313 					$mw = $objattr['OUTER-WIDTH'];
7314 					// NB If change marker-offset, also need to alter in function _getListMarkerWidth
7315 					$adjx = $this->sizeConverter->convert($this->list_marker_offset, $this->FontSize);
7316 					if ($objattr['dir'] == 'rtl') {
7317 						$objattr['INNER-X'] += $adjx;
7318 					} else {
7319 						$objattr['INNER-X'] -= $adjx;
7320 						$objattr['INNER-X'] -= $mw;
7321 					}
7322 				}
7323 				// mPDF 5.7.3 TRANSFORMS / BACKGROUND COLOR
7324 				// Transform also affects image background
7325 				if ($tr2) {
7326 					$this->writer->write('q ' . $tr2 . ' ');
7327 				}
7328 				if (isset($objattr['bgcolor']) && $objattr['bgcolor']) {
7329 					$bgcol = $objattr['bgcolor'];
7330 					$this->SetFColor($bgcol);
7331 					$this->Rect($x, $y, $w, $h, 'F');
7332 					$this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
7333 				}
7334 				if ($tr2) {
7335 					$this->writer->write('Q');
7336 				}
7337 
7338 				/* -- BACKGROUNDS -- */
7339 				if (isset($objattr['GRADIENT-MASK'])) {
7340 					$g = $this->gradient->parseMozGradient($objattr['GRADIENT-MASK']);
7341 					if ($g) {
7342 						$dummy = $this->gradient->Gradient($objattr['INNER-X'], $objattr['INNER-Y'], $obiw, $obih, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend'], true, true);
7343 						$gradmask = '/TGS' . count($this->gradients) . ' gs ';
7344 					}
7345 				}
7346 				/* -- END BACKGROUNDS -- */
7347 				/* -- IMAGES-WMF -- */
7348 				if (isset($objattr['itype']) && $objattr['itype'] == 'wmf') {
7349 					$outstring = sprintf('q ' . $tr . $tr2 . '%.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, -$sy, $objattr['INNER-X'] * Mpdf::SCALE - $sx * $objattr['wmf_x'], (($this->h - $objattr['INNER-Y']) * Mpdf::SCALE) + $sy * $objattr['wmf_y'], $objattr['ID']); // mPDF 5.7.3 TRANSFORMS
7350 				} else { 				/* -- END IMAGES-WMF -- */
7351 					if (isset($objattr['itype']) && $objattr['itype'] == 'svg') {
7352 						$outstring = sprintf('q ' . $tr . $tr2 . '%.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, -$sy, $objattr['INNER-X'] * Mpdf::SCALE - $sx * $objattr['wmf_x'], (($this->h - $objattr['INNER-Y']) * Mpdf::SCALE) + $sy * $objattr['wmf_y'], $objattr['ID']); // mPDF 5.7.3 TRANSFORMS
7353 					} else {
7354 						$outstring = sprintf("q " . $tr . $tr2 . "%.3F 0 0 %.3F %.3F %.3F cm " . $gradmask . "/I%d Do Q", $obiw * Mpdf::SCALE, $obih * Mpdf::SCALE, $objattr['INNER-X'] * Mpdf::SCALE, ($this->h - ($objattr['INNER-Y'] + $obih )) * Mpdf::SCALE, $objattr['ID']); // mPDF 5.7.3 TRANSFORMS
7355 					}
7356 				}
7357 				$this->writer->write($outstring);
7358 				// LINK
7359 				if (isset($objattr['link'])) {
7360 					$this->Link($objattr['INNER-X'], $objattr['INNER-Y'], $objattr['INNER-WIDTH'], $objattr['INNER-HEIGHT'], $objattr['link']);
7361 				}
7362 				if (isset($objattr['opacity'])) {
7363 					$this->SetAlpha(1);
7364 				}
7365 
7366 				// mPDF 5.7.3 TRANSFORMS
7367 				// Transform also affects image borders
7368 				if ($tr2) {
7369 					$this->writer->write('q ' . $tr2 . ' ');
7370 				}
7371 				if ((isset($objattr['border_top']) && $objattr['border_top'] > 0) || (isset($objattr['border_left']) && $objattr['border_left'] > 0) || (isset($objattr['border_right']) && $objattr['border_right'] > 0) || (isset($objattr['border_bottom']) && $objattr['border_bottom'] > 0)) {
7372 					$this->PaintImgBorder($objattr, $is_table);
7373 				}
7374 				if ($tr2) {
7375 					$this->writer->write('Q');
7376 				}
7377 
7378 				if (isset($objattr['visibility']) && $objattr['visibility'] != 'visible' && $objattr['visibility']) {
7379 					$this->SetVisibility('visible');
7380 				}
7381 				if (isset($objattr['z-index']) && $objattr['z-index'] > 0 && $this->current_layer == 0) {
7382 					$this->EndLayer();
7383 				}
7384 				// mPDF 5.7.3 TRANSFORMS
7385 				if (isset($objattr['transform'])) {
7386 					$this->writer->write("\n" . '% ETR'); // End Transform
7387 				}
7388 			}
7389 
7390 			if ($objattr['type'] === 'barcode') {
7391 
7392 				$bgcol = $this->colorConverter->convert(255, $this->PDFAXwarnings);
7393 
7394 				if (isset($objattr['bgcolor']) && $objattr['bgcolor']) {
7395 					$bgcol = $objattr['bgcolor'];
7396 				}
7397 
7398 				$col = $this->colorConverter->convert(0, $this->PDFAXwarnings);
7399 
7400 				if (isset($objattr['color']) && $objattr['color']) {
7401 					$col = $objattr['color'];
7402 				}
7403 
7404 				$this->SetFColor($bgcol);
7405 				$this->Rect($objattr['BORDER-X'], $objattr['BORDER-Y'], $objattr['BORDER-WIDTH'], $objattr['BORDER-HEIGHT'], 'F');
7406 				$this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
7407 
7408 				if (isset($objattr['BORDER-WIDTH'])) {
7409 					$this->PaintImgBorder($objattr, $is_table);
7410 				}
7411 
7412 				$barcodeTypes = ['EAN13', 'ISBN', 'ISSN', 'UPCA', 'UPCE', 'EAN8'];
7413 				if (in_array($objattr['btype'], $barcodeTypes, true)) {
7414 
7415 					$this->WriteBarcode(
7416 						$objattr['code'],
7417 						$objattr['showtext'],
7418 						$objattr['INNER-X'],
7419 						$objattr['INNER-Y'],
7420 						$objattr['bsize'],
7421 						0,
7422 						0,
7423 						0,
7424 						0,
7425 						0,
7426 						$objattr['bheight'],
7427 						$bgcol,
7428 						$col,
7429 						$objattr['btype'],
7430 						$objattr['bsupp'],
7431 						(isset($objattr['bsupp_code']) ? $objattr['bsupp_code'] : ''),
7432 						$k
7433 					);
7434 
7435 				} elseif ($objattr['btype'] === 'QR') {
7436 
7437 					if (!class_exists('Mpdf\QrCode\QrCode') || !class_exists('Mpdf\QrCode\Output\Mpdf')) {
7438 						throw new \Mpdf\MpdfException('Mpdf\QrCode package was not found. Install the package from Packagist with "composer require mpdf/qrcode"');
7439 					}
7440 
7441 					$barcodeContent = str_replace('\r\n', "\r\n", $objattr['code']);
7442 					$barcodeContent = str_replace('\n', "\n", $barcodeContent);
7443 
7444 					$qrcode = new QrCode\QrCode($barcodeContent, $objattr['errorlevel']);
7445 					if ($objattr['disableborder']) {
7446 						$qrcode->disableBorder();
7447 					}
7448 
7449 					$bgColor = [255, 255, 255];
7450 					if ($objattr['bgcolor']) {
7451 						$bgColor = array_map(
7452 							function ($col) {
7453 								return intval(255 * floatval($col));
7454 							},
7455 							explode(" ", $this->SetColor($objattr['bgcolor'], 'CodeOnly'))
7456 						);
7457 					}
7458 					$color = [0, 0, 0];
7459 					if ($objattr['color']) {
7460 						$color = array_map(
7461 							function ($col) {
7462 								return intval(255 * floatval($col));
7463 							},
7464 							explode(" ", $this->SetColor($objattr['color'], 'CodeOnly'))
7465 						);
7466 					}
7467 
7468 					$out = new QrCode\Output\Mpdf();
7469 					$out->output(
7470 						$qrcode,
7471 						$this,
7472 						$objattr['INNER-X'],
7473 						$objattr['INNER-Y'],
7474 						$objattr['bsize'] * 25,
7475 						$bgColor,
7476 						$color
7477 					);
7478 
7479 					unset($qrcode);
7480 
7481 				} else {
7482 					$this->WriteBarcode2(
7483 						$objattr['code'],
7484 						$objattr['INNER-X'],
7485 						$objattr['INNER-Y'],
7486 						$objattr['bsize'],
7487 						$objattr['bheight'],
7488 						$bgcol,
7489 						$col,
7490 						$objattr['btype'],
7491 						$objattr['pr_ratio'],
7492 						$k,
7493 						$objattr['quiet_zone_left'],
7494 						$objattr['quiet_zone_right']
7495 					);
7496 				}
7497 			}
7498 
7499 			// TEXT CIRCLE
7500 			if ($objattr['type'] == 'textcircle') {
7501 				$bgcol = '';
7502 				if (isset($objattr['bgcolor']) && $objattr['bgcolor']) {
7503 					$bgcol = $objattr['bgcolor'];
7504 				}
7505 				$col = $this->colorConverter->convert(0, $this->PDFAXwarnings);
7506 				if (isset($objattr['color']) && $objattr['color']) {
7507 					$col = $objattr['color'];
7508 				}
7509 				$this->SetTColor($col);
7510 				$this->SetFColor($bgcol);
7511 				if ($bgcol) {
7512 					$this->Rect($objattr['BORDER-X'], $objattr['BORDER-Y'], $objattr['BORDER-WIDTH'], $objattr['BORDER-HEIGHT'], 'F');
7513 				}
7514 				$this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
7515 				if (isset($objattr['BORDER-WIDTH'])) {
7516 					$this->PaintImgBorder($objattr, $is_table);
7517 				}
7518 				if (empty($this->directWrite)) {
7519 					$this->directWrite = new DirectWrite($this, $this->otl, $this->sizeConverter, $this->colorConverter);
7520 				}
7521 				if (isset($objattr['top-text'])) {
7522 					$this->directWrite->CircularText($objattr['INNER-X'] + $objattr['INNER-WIDTH'] / 2, $objattr['INNER-Y'] + $objattr['INNER-HEIGHT'] / 2, $objattr['r'] / $k, $objattr['top-text'], 'top', $objattr['fontfamily'], $objattr['fontsize'] / $k, $objattr['fontstyle'], $objattr['space-width'], $objattr['char-width'], (isset($objattr['divider']) ? $objattr['divider'] : ''));
7523 				}
7524 				if (isset($objattr['bottom-text'])) {
7525 					$this->directWrite->CircularText($objattr['INNER-X'] + $objattr['INNER-WIDTH'] / 2, $objattr['INNER-Y'] + $objattr['INNER-HEIGHT'] / 2, $objattr['r'] / $k, $objattr['bottom-text'], 'bottom', $objattr['fontfamily'], $objattr['fontsize'] / $k, $objattr['fontstyle'], $objattr['space-width'], $objattr['char-width'], (isset($objattr['divider']) ? $objattr['divider'] : ''));
7526 				}
7527 			}
7528 
7529 			$this->ResetSpacing();
7530 
7531 			// LIST MARKERS (Text or bullets)	// mPDF 6  Lists
7532 			if ($objattr['type'] == 'listmarker') {
7533 				if (isset($objattr['fontfamily'])) {
7534 					$this->SetFont($objattr['fontfamily'], $objattr['fontstyle'], $objattr['fontsizept']);
7535 				}
7536 				$col = $this->colorConverter->convert(0, $this->PDFAXwarnings);
7537 				if (isset($objattr['colorarray']) && ($objattr['colorarray'])) {
7538 					$col = $objattr['colorarray'];
7539 				}
7540 
7541 				if (isset($objattr['bullet']) && $objattr['bullet']) { // Used for position "outside" only
7542 					$type = $objattr['bullet'];
7543 					$size = $objattr['size'];
7544 
7545 					if ($objattr['listmarkerposition'] == 'inside') {
7546 						$adjx = $size / 2;
7547 						if ($objattr['dir'] == 'rtl') {
7548 							$adjx += $objattr['offset'];
7549 						}
7550 						$this->x += $adjx;
7551 					} else {
7552 						$adjx = $objattr['offset'];
7553 						$adjx += $size / 2;
7554 						if ($objattr['dir'] == 'rtl') {
7555 							$this->x += $adjx;
7556 						} else {
7557 							$this->x -= $adjx;
7558 						}
7559 					}
7560 
7561 					$yadj = $objattr['lineBox']['glyphYorigin'];
7562 					if (isset($this->CurrentFont['desc']['XHeight']) && $this->CurrentFont['desc']['XHeight']) {
7563 						$xh = $this->CurrentFont['desc']['XHeight'];
7564 					} else {
7565 						$xh = 500;
7566 					}
7567 					$yadj -= ($this->FontSize * $xh / 1000) * 0.625; // Vertical height of bullet (centre) from baseline= XHeight * 0.625
7568 					$this->y += $yadj;
7569 
7570 					$this->_printListBullet($this->x, $this->y, $size, $type, $col);
7571 				} else {
7572 					$this->SetTColor($col);
7573 					$w = $this->GetStringWidth($texto);
7574 					// NB If change marker-offset, also need to alter in function _getListMarkerWidth
7575 					$adjx = $this->sizeConverter->convert($this->list_marker_offset, $this->FontSize);
7576 					if ($objattr['dir'] == 'rtl') {
7577 						$align = 'L';
7578 						$this->x += $adjx;
7579 					} else {
7580 						// Use these lines to set as marker-offset, right-aligned - default
7581 						$align = 'R';
7582 						$this->x -= $adjx;
7583 						$this->x -= $w;
7584 					}
7585 					$this->Cell($w, $this->FontSize, $texto, 0, 0, $align, 0, '', 0, 0, 0, 'T', 0, false, false, 0, $objattr['lineBox']);
7586 					$this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
7587 				}
7588 			}
7589 
7590 			// DOT-TAB
7591 			if ($objattr['type'] == 'dottab') {
7592 				if (isset($objattr['fontfamily'])) {
7593 					$this->SetFont($objattr['fontfamily'], '', $objattr['fontsize']);
7594 				}
7595 				$sp = $this->GetStringWidth(' ');
7596 				$nb = floor(($w - 2 * $sp) / $this->GetStringWidth('.'));
7597 				if ($nb > 0) {
7598 					$dots = ' ' . str_repeat('.', $nb) . ' ';
7599 				} else {
7600 					$dots = ' ';
7601 				}
7602 				$col = $this->colorConverter->convert(0, $this->PDFAXwarnings);
7603 				if (isset($objattr['colorarray']) && ($objattr['colorarray'])) {
7604 					$col = $objattr['colorarray'];
7605 				}
7606 				$this->SetTColor($col);
7607 				$save_dh = $this->divheight;
7608 				$save_sbd = $this->spanborddet;
7609 				$save_textvar = $this->textvar; // mPDF 5.7.1
7610 				$this->spanborddet = '';
7611 				$this->divheight = 0;
7612 				$this->textvar = 0x00; // mPDF 5.7.1
7613 
7614 				$this->Cell($w, $h, $dots, 0, 0, 'C', 0, '', 0, 0, 0, 'T', 0, false, false, 0, $objattr['lineBox']); // mPDF 6 DOTTAB
7615 				$this->spanborddet = $save_sbd;
7616 				$this->textvar = $save_textvar; // mPDF 5.7.1
7617 				$this->divheight = $save_dh;
7618 				$this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
7619 			}
7620 
7621 			/* -- FORMS -- */
7622 			// TEXT/PASSWORD INPUT
7623 			if ($objattr['type'] == 'input' && ($objattr['subtype'] == 'TEXT' || $objattr['subtype'] == 'PASSWORD')) {
7624 				$this->form->print_ob_text($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir);
7625 			}
7626 
7627 			// TEXTAREA
7628 			if ($objattr['type'] == 'textarea') {
7629 				$this->form->print_ob_textarea($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir);
7630 			}
7631 
7632 			// SELECT
7633 			if ($objattr['type'] == 'select') {
7634 				$this->form->print_ob_select($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir);
7635 			}
7636 
7637 
7638 			// INPUT/BUTTON as IMAGE
7639 			if ($objattr['type'] == 'input' && $objattr['subtype'] == 'IMAGE') {
7640 				$this->form->print_ob_imageinput($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir, $is_table);
7641 			}
7642 
7643 			// BUTTON
7644 			if ($objattr['type'] == 'input' && ($objattr['subtype'] == 'SUBMIT' || $objattr['subtype'] == 'RESET' || $objattr['subtype'] == 'BUTTON')) {
7645 				$this->form->print_ob_button($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir);
7646 			}
7647 
7648 			// CHECKBOX
7649 			if ($objattr['type'] == 'input' && ($objattr['subtype'] == 'CHECKBOX')) {
7650 				$this->form->print_ob_checkbox($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir, $x, $y);
7651 			}
7652 			// RADIO
7653 			if ($objattr['type'] == 'input' && ($objattr['subtype'] == 'RADIO')) {
7654 				$this->form->print_ob_radio($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir, $x, $y);
7655 			}
7656 			/* -- END FORMS -- */
7657 		}
7658 
7659 		$this->SetFont($save_currentfontfamily, $save_currentfontstyle, $save_currentfontsize);
7660 
7661 		$this->y = $save_y;
7662 		$this->x = $save_x;
7663 
7664 		unset($content);
7665 	}
7666 
7667 	function _printListBullet($x, $y, $size, $type, $color)
7668 	{
7669 		// x and y are the centre of the bullet; size is the width and/or height in mm
7670 		$fcol = $this->SetTColor($color, true);
7671 		$lcol = strtoupper($fcol); // change 0 0 0 rg to 0 0 0 RG
7672 		$this->writer->write(sprintf('q %s %s', $lcol, $fcol));
7673 		$this->writer->write('0 j 0 J [] 0 d');
7674 		if ($type == 'square') {
7675 			$size *= 0.85; // Smaller to appear the same size as circle/disc
7676 			$this->writer->write(sprintf('%.3F %.3F %.3F %.3F re f', ($x - $size / 2) * Mpdf::SCALE, ($this->h - $y + $size / 2) * Mpdf::SCALE, ($size) * Mpdf::SCALE, (-$size) * Mpdf::SCALE));
7677 		} elseif ($type == 'disc') {
7678 			$this->Circle($x, $y, $size / 2, 'F'); // Fill
7679 		} elseif ($type == 'circle') {
7680 			$lw = $size / 12; // Line width
7681 			$this->writer->write(sprintf('%.3F w ', $lw * Mpdf::SCALE));
7682 			$this->Circle($x, $y, $size / 2 - $lw / 2, 'S'); // Stroke
7683 		}
7684 		$this->writer->write('Q');
7685 	}
7686 
7687 	// mPDF 6
7688 	// Get previous character and move pointers
7689 	function _moveToPrevChar(&$contentctr, &$charctr, $content)
7690 	{
7691 		$lastchar = false;
7692 		$charctr--;
7693 		while ($charctr < 0) { // go back to previous $content[]
7694 			$contentctr--;
7695 			if ($contentctr < 0) {
7696 				return false;
7697 			}
7698 			if ($this->usingCoreFont) {
7699 				$charctr = strlen($content[$contentctr]) - 1;
7700 			} else {
7701 				$charctr = mb_strlen($content[$contentctr], $this->mb_enc) - 1;
7702 			}
7703 		}
7704 		if ($this->usingCoreFont) {
7705 			$lastchar = $content[$contentctr][$charctr];
7706 		} else {
7707 			$lastchar = mb_substr($content[$contentctr], $charctr, 1, $this->mb_enc);
7708 		}
7709 		return $lastchar;
7710 	}
7711 
7712 	// Get previous character
7713 	function _getPrevChar($contentctr, $charctr, $content)
7714 	{
7715 		$lastchar = false;
7716 		$charctr--;
7717 		while ($charctr < 0) { // go back to previous $content[]
7718 			$contentctr--;
7719 			if ($contentctr < 0) {
7720 				return false;
7721 			}
7722 			if ($this->usingCoreFont) {
7723 				$charctr = strlen($content[$contentctr]) - 1;
7724 			} else {
7725 				$charctr = mb_strlen($content[$contentctr], $this->mb_enc) - 1;
7726 			}
7727 		}
7728 		if ($this->usingCoreFont) {
7729 			$lastchar = $content[$contentctr][$charctr];
7730 		} else {
7731 			$lastchar = mb_substr($content[$contentctr], $charctr, 1, $this->mb_enc);
7732 		}
7733 		return $lastchar;
7734 	}
7735 
7736 	function WriteFlowingBlock($s, $sOTLdata)
7737 	{
7738 	// mPDF 5.7.1
7739 		$currentx = $this->x;
7740 		$is_table = $this->flowingBlockAttr['is_table'];
7741 		$table_draft = $this->flowingBlockAttr['table_draft'];
7742 		// width of all the content so far in points
7743 		$contentWidth = & $this->flowingBlockAttr['contentWidth'];
7744 		// cell width in points
7745 		$maxWidth = & $this->flowingBlockAttr['width'];
7746 		$lineCount = & $this->flowingBlockAttr['lineCount'];
7747 		// line height in user units
7748 		$stackHeight = & $this->flowingBlockAttr['height'];
7749 		$align = & $this->flowingBlockAttr['align'];
7750 		$content = & $this->flowingBlockAttr['content'];
7751 		$contentB = & $this->flowingBlockAttr['contentB'];
7752 		$font = & $this->flowingBlockAttr['font'];
7753 		$valign = & $this->flowingBlockAttr['valign'];
7754 		$blockstate = $this->flowingBlockAttr['blockstate'];
7755 		$cOTLdata = & $this->flowingBlockAttr['cOTLdata']; // mPDF 5.7.1
7756 
7757 		$newblock = $this->flowingBlockAttr['newblock'];
7758 		$blockdir = $this->flowingBlockAttr['blockdir'];
7759 
7760 		// *********** BLOCK BACKGROUND COLOR ***************** //
7761 		if ($this->blk[$this->blklvl]['bgcolor'] && !$is_table) {
7762 			$fill = 0;
7763 		} else {
7764 			$this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
7765 			$fill = 0;
7766 		}
7767 		$font[] = $this->saveFont();
7768 		$content[] = '';
7769 		$contentB[] = '';
7770 		$cOTLdata[] = $sOTLdata; // mPDF 5.7.1
7771 		$currContent = & $content[count($content) - 1];
7772 
7773 		$CJKoverflow = false;
7774 		$Oikomi = false; // mPDF 6
7775 		$hanger = '';
7776 
7777 		// COLS
7778 		$oldcolumn = $this->CurrCol;
7779 		if ($this->ColActive && !$is_table) {
7780 			$this->breakpoints[$this->CurrCol][] = $this->y;
7781 		} // *COLUMNS*
7782 
7783 		/* -- TABLES -- */
7784 		if ($is_table) {
7785 			$ipaddingL = 0;
7786 			$ipaddingR = 0;
7787 			$paddingL = 0;
7788 			$paddingR = 0;
7789 			$cpaddingadjustL = 0;
7790 			$cpaddingadjustR = 0;
7791 			// Added mPDF 3.0
7792 			$fpaddingR = 0;
7793 			$fpaddingL = 0;
7794 		} else {
7795 			/* -- END TABLES -- */
7796 			$ipaddingL = $this->blk[$this->blklvl]['padding_left'];
7797 			$ipaddingR = $this->blk[$this->blklvl]['padding_right'];
7798 			$paddingL = ($ipaddingL * Mpdf::SCALE);
7799 			$paddingR = ($ipaddingR * Mpdf::SCALE);
7800 			$this->cMarginL = $this->blk[$this->blklvl]['border_left']['w'];
7801 			$cpaddingadjustL = -$this->cMarginL;
7802 			$this->cMarginR = $this->blk[$this->blklvl]['border_right']['w'];
7803 			$cpaddingadjustR = -$this->cMarginR;
7804 			// Added mPDF 3.0 Float DIV
7805 			$fpaddingR = 0;
7806 			$fpaddingL = 0;
7807 			/* -- CSS-FLOAT -- */
7808 			if (count($this->floatDivs)) {
7809 				list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($this->blklvl);
7810 				if ($r_exists) {
7811 					$fpaddingR = $r_width;
7812 				}
7813 				if ($l_exists) {
7814 					$fpaddingL = $l_width;
7815 				}
7816 			}
7817 			/* -- END CSS-FLOAT -- */
7818 
7819 			$usey = $this->y + 0.002;
7820 			if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 0)) {
7821 				$usey += $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'];
7822 			}
7823 			/* -- CSS-IMAGE-FLOAT -- */
7824 			// If float exists at this level
7825 			if (isset($this->floatmargins['R']) && $usey <= $this->floatmargins['R']['y1'] && $usey >= $this->floatmargins['R']['y0'] && !$this->floatmargins['R']['skipline']) {
7826 				$fpaddingR += $this->floatmargins['R']['w'];
7827 			}
7828 			if (isset($this->floatmargins['L']) && $usey <= $this->floatmargins['L']['y1'] && $usey >= $this->floatmargins['L']['y0'] && !$this->floatmargins['L']['skipline']) {
7829 				$fpaddingL += $this->floatmargins['L']['w'];
7830 			}
7831 			/* -- END CSS-IMAGE-FLOAT -- */
7832 		} // *TABLES*
7833 		// OBJECTS - IMAGES & FORM Elements (NB has already skipped line/page if required - in printbuffer)
7834 		if (substr($s, 0, 3) == "\xbb\xa4\xac") { // identifier has been identified!
7835 			$objattr = $this->_getObjAttr($s);
7836 			$h_corr = 0;
7837 			if ($is_table) { // *TABLES*
7838 				$maximumW = ($maxWidth / Mpdf::SCALE) - ($this->cellPaddingL + $this->cMarginL + $this->cellPaddingR + $this->cMarginR);  // *TABLES*
7839 			} // *TABLES*
7840 			else { // *TABLES*
7841 				if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 0) && (!$is_table)) {
7842 					$h_corr = $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'];
7843 				}
7844 				$maximumW = ($maxWidth / Mpdf::SCALE) - ($this->blk[$this->blklvl]['padding_left'] + $this->blk[$this->blklvl]['border_left']['w'] + $this->blk[$this->blklvl]['padding_right'] + $this->blk[$this->blklvl]['border_right']['w'] + $fpaddingL + $fpaddingR );
7845 			} // *TABLES*
7846 			$objattr = $this->inlineObject($objattr['type'], $this->lMargin + $fpaddingL + ($contentWidth / Mpdf::SCALE), ($this->y + $h_corr), $objattr, $this->lMargin, ($contentWidth / Mpdf::SCALE), $maximumW, $stackHeight, true, $is_table);
7847 
7848 			// SET LINEHEIGHT for this line ================ RESET AT END
7849 			$stackHeight = max($stackHeight, $objattr['OUTER-HEIGHT']);
7850 			$this->objectbuffer[count($content) - 1] = $objattr;
7851 			// if (isset($objattr['vertical-align'])) { $valign = $objattr['vertical-align']; }
7852 			// else { $valign = ''; }
7853 			// LIST MARKERS	// mPDF 6  Lists
7854 			if ($objattr['type'] == 'image' && isset($objattr['listmarker']) && $objattr['listmarker'] && $objattr['listmarkerposition'] == 'outside') {
7855 				// do nothing
7856 			} else {
7857 				$contentWidth += ($objattr['OUTER-WIDTH'] * Mpdf::SCALE);
7858 			}
7859 			return;
7860 		}
7861 
7862 		$lbw = $rbw = 0; // Border widths
7863 		if (!empty($this->spanborddet)) {
7864 			if (isset($this->spanborddet['L'])) {
7865 				$lbw = $this->spanborddet['L']['w'];
7866 			}
7867 			if (isset($this->spanborddet['R'])) {
7868 				$rbw = $this->spanborddet['R']['w'];
7869 			}
7870 		}
7871 
7872 		if ($this->usingCoreFont) {
7873 			$clen = strlen($s);
7874 		} else {
7875 			$clen = mb_strlen($s, $this->mb_enc);
7876 		}
7877 
7878 		// for every character in the string
7879 		for ($i = 0; $i < $clen; $i++) {
7880 			// extract the current character
7881 			// get the width of the character in points
7882 			if ($this->usingCoreFont) {
7883 				$c = $s[$i];
7884 				// Soft Hyphens chr(173)
7885 				$cw = ($this->GetCharWidthCore($c) * Mpdf::SCALE);
7886 				if (($this->textvar & TextVars::FC_KERNING) && $i > 0) { // mPDF 5.7.1
7887 					if (isset($this->CurrentFont['kerninfo'][$s[($i - 1)]][$c])) {
7888 						$cw += ($this->CurrentFont['kerninfo'][$s[($i - 1)]][$c] * $this->FontSizePt / 1000 );
7889 					}
7890 				}
7891 			} else {
7892 				$c = mb_substr($s, $i, 1, $this->mb_enc);
7893 				$cw = ($this->GetCharWidthNonCore($c, false) * Mpdf::SCALE);
7894 				// mPDF 5.7.1
7895 				// Use OTL GPOS
7896 				if (isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF)) {
7897 					// ...WriteFlowingBlock...
7898 					// Only  add XAdvanceL (not sure at present whether RTL or LTR writing direction)
7899 					// At this point, XAdvanceL and XAdvanceR will balance
7900 					if (isset($sOTLdata['GPOSinfo'][$i]['XAdvanceL'])) {
7901 						$cw += $sOTLdata['GPOSinfo'][$i]['XAdvanceL'] * (1000 / $this->CurrentFont['unitsPerEm']) * ($this->FontSize / 1000) * Mpdf::SCALE;
7902 					}
7903 				}
7904 				if (($this->textvar & TextVars::FC_KERNING) && $i > 0) { // mPDF 5.7.1
7905 					$lastc = mb_substr($s, ($i - 1), 1, $this->mb_enc);
7906 					$ulastc = $this->UTF8StringToArray($lastc, false);
7907 					$uc = $this->UTF8StringToArray($c, false);
7908 					if (isset($this->CurrentFont['kerninfo'][$ulastc[0]][$uc[0]])) {
7909 						$cw += ($this->CurrentFont['kerninfo'][$ulastc[0]][$uc[0]] * $this->FontSizePt / 1000 );
7910 					}
7911 				}
7912 			}
7913 
7914 			if ($i == 0) {
7915 				$cw += $lbw * Mpdf::SCALE;
7916 				$contentB[(count($contentB) - 1)] .= 'L';
7917 			}
7918 			if ($i == ($clen - 1)) {
7919 				$cw += $rbw * Mpdf::SCALE;
7920 				$contentB[(count($contentB) - 1)] .= 'R';
7921 			}
7922 			if ($c == ' ') {
7923 				$currContent .= $c;
7924 				$contentWidth += $cw;
7925 				continue;
7926 			}
7927 
7928 			// Paragraph INDENT
7929 			$WidthCorrection = 0;
7930 			if (($newblock) && ($blockstate == 1 || $blockstate == 3) && isset($this->blk[$this->blklvl]['text_indent']) && ($lineCount == 0) && (!$is_table) && ($align != 'C')) {
7931 				$ti = $this->sizeConverter->convert($this->blk[$this->blklvl]['text_indent'], $this->blk[$this->blklvl]['inner_width'], $this->blk[$this->blklvl]['InlineProperties']['size'], false);  // mPDF 5.7.4
7932 				$WidthCorrection = ($ti * Mpdf::SCALE);
7933 			}
7934 			// OUTDENT
7935 			foreach ($this->objectbuffer as $k => $objattr) {   // mPDF 6 DOTTAB
7936 				if ($objattr['type'] == 'dottab') {
7937 					$WidthCorrection -= ($objattr['outdent'] * Mpdf::SCALE);
7938 					break;
7939 				}
7940 			}
7941 
7942 
7943 			// Added mPDF 3.0 Float DIV
7944 			$fpaddingR = 0;
7945 			$fpaddingL = 0;
7946 			/* -- CSS-FLOAT -- */
7947 			if (count($this->floatDivs)) {
7948 				list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($this->blklvl);
7949 				if ($r_exists) {
7950 					$fpaddingR = $r_width;
7951 				}
7952 				if ($l_exists) {
7953 					$fpaddingL = $l_width;
7954 				}
7955 			}
7956 			/* -- END CSS-FLOAT -- */
7957 
7958 			$usey = $this->y + 0.002;
7959 			if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 0)) {
7960 				$usey += $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'];
7961 			}
7962 
7963 			/* -- CSS-IMAGE-FLOAT -- */
7964 			// If float exists at this level
7965 			if (isset($this->floatmargins['R']) && $usey <= $this->floatmargins['R']['y1'] && $usey >= $this->floatmargins['R']['y0'] && !$this->floatmargins['R']['skipline']) {
7966 				$fpaddingR += $this->floatmargins['R']['w'];
7967 			}
7968 			if (isset($this->floatmargins['L']) && $usey <= $this->floatmargins['L']['y1'] && $usey >= $this->floatmargins['L']['y0'] && !$this->floatmargins['L']['skipline']) {
7969 				$fpaddingL += $this->floatmargins['L']['w'];
7970 			}
7971 			/* -- END CSS-IMAGE-FLOAT -- */
7972 
7973 
7974 			// try adding another char
7975 			if (( $contentWidth + $cw > $maxWidth - $WidthCorrection - (($this->cMarginL + $this->cMarginR) * Mpdf::SCALE) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * Mpdf::SCALE) ) + 0.001)) {// 0.001 is to correct for deviations converting mm=>pts
7976 				// it won't fit, output what we already have
7977 				$lineCount++;
7978 
7979 				// contains any content that didn't make it into this print
7980 				$savedContent = '';
7981 				$savedContentB = '';
7982 				$savedOTLdata = []; // mPDF 5.7.1
7983 				$savedFont = [];
7984 				$savedObj = [];
7985 				$savedPreOTLdata = []; // mPDF 5.7.1
7986 				$savedPreContent = [];
7987 				$savedPreContentB = [];
7988 				$savedPreFont = [];
7989 
7990 				// mPDF 6
7991 				// New line-breaking algorithm
7992 				/////////////////////
7993 				// LINE BREAKING
7994 				/////////////////////
7995 				$breakfound = false;
7996 				$contentctr = count($content) - 1;
7997 				if ($this->usingCoreFont) {
7998 					$charctr = strlen($currContent);
7999 				} else {
8000 					$charctr = mb_strlen($currContent, $this->mb_enc);
8001 				}
8002 				$checkchar = $c;
8003 				$prevchar = $this->_getPrevChar($contentctr, $charctr, $content);
8004 
8005 				/* -- CJK-FONTS -- */
8006 				// 1) CJK Overflowing a) punctuation or b) Oikomi
8007 				// Next character ($c) is suitable to add as overhanging or squeezed punctuation, or Oikomi
8008 				if ($CJKoverflow || $Oikomi) { // If flag already set
8009 					$CJKoverflow = false;
8010 					$Oikomi = false;
8011 					$breakfound = true;
8012 				}
8013 				if (!$this->usingCoreFont && !$breakfound && $this->checkCJK) {
8014 
8015 					// Get next/following character (in this chunk)
8016 					$followingchar = '';
8017 					if ($i < ($clen - 1)) {
8018 						if ($this->usingCoreFont) {
8019 							$followingchar = $s[$i + 1];
8020 						} else {
8021 							$followingchar = mb_substr($s, $i + 1, 1, $this->mb_enc);
8022 						}
8023 					}
8024 
8025 					// 1a) Overflow punctuation
8026 					if (preg_match("/[" . $this->pregCJKchars . "]/u", $prevchar) && preg_match("/[" . $this->CJKoverflow . "]/u", $checkchar) && $this->allowCJKorphans) {
8027 						// add character onto this line
8028 						$currContent .= $c;
8029 						$contentWidth += $cw;
8030 						$CJKoverflow = true; // Set flag
8031 						continue;
8032 					} elseif (preg_match("/[" . $this->pregCJKchars . "]/u", $checkchar) && $this->allowCJKorphans &&
8033 							(preg_match("/[" . $this->CJKleading . "]/u", $followingchar) || preg_match("/[" . $this->CJKfollowing . "]/u", $checkchar)) &&
8034 							!preg_match("/[" . $this->CJKleading . "]/u", $checkchar) && !preg_match("/[" . $this->CJKfollowing . "]/u", $followingchar) &&
8035 							!(preg_match("/[0-9\x{ff10}-\x{ff19}]/u", $followingchar) && preg_match("/[0-9\x{ff10}-\x{ff19}]/u", $checkchar))) {
8036 						// 1b) Try squeezing another character(s) onto this line = Oikomi, if character cannot end line
8037 						// or next character cannot start line (and not splitting CJK numerals)
8038 						// NB otherwise it move lastchar(s) to next line to keep $c company = Oidashi, which is done below in standard way
8039 						// add character onto this line
8040 						$currContent .= $c;
8041 						$contentWidth += $cw;
8042 						$Oikomi = true; // Set flag
8043 						continue;
8044 					}
8045 				}
8046 				/* -- END CJK-FONTS -- */
8047 				/* -- HYPHENATION -- */
8048 
8049 				// AUTOMATIC HYPHENATION
8050 				// 2) Automatic hyphen in current word (does not cross tags)
8051 				if (isset($this->textparam['hyphens']) && $this->textparam['hyphens'] == 1) {
8052 					$currWord = '';
8053 					// Look back and ahead to get current word
8054 					for ($ac = $charctr - 1; $ac >= 0; $ac--) {
8055 						if ($this->usingCoreFont) {
8056 							$addc = substr($currContent, $ac, 1);
8057 						} else {
8058 							$addc = mb_substr($currContent, $ac, 1, $this->mb_enc);
8059 						}
8060 						if ($addc == ' ') {
8061 							break;
8062 						}
8063 						$currWord = $addc . $currWord;
8064 					}
8065 					$start = $ac + 1;
8066 					for ($ac = $i; $ac < ($clen - 1); $ac++) {
8067 						if ($this->usingCoreFont) {
8068 							$addc = substr($s, $ac, 1);
8069 						} else {
8070 							$addc = mb_substr($s, $ac, 1, $this->mb_enc);
8071 						}
8072 						if ($addc == ' ') {
8073 							break;
8074 						}
8075 						$currWord .= $addc;
8076 					}
8077 					$ptr = $this->hyphenator->hyphenateWord($currWord, $charctr - $start);
8078 					if ($ptr > -1) {
8079 						$breakfound = [$contentctr, $start + $ptr, $contentctr, $start + $ptr, 'hyphen'];
8080 					}
8081 				}
8082 				/* -- END HYPHENATION -- */
8083 
8084 				// Search backwards to find first line-break opportunity
8085 				while ($breakfound == false && $prevchar !== false) {
8086 					$cutcontentctr = $contentctr;
8087 					$cutcharctr = $charctr;
8088 					$prevchar = $this->_moveToPrevChar($contentctr, $charctr, $content);
8089 					/////////////////////
8090 					// 3) Break at SPACE
8091 					/////////////////////
8092 					if ($prevchar == ' ') {
8093 						$breakfound = [$contentctr, $charctr, $cutcontentctr, $cutcharctr, 'discard'];
8094 					} /////////////////////
8095 					// 4) Break at U+200B in current word (Khmer, Lao & Thai Invisible word boundary, and Tibetan)
8096 					/////////////////////
8097 					elseif ($prevchar == "\xe2\x80\x8b") { // U+200B Zero-width Word Break
8098 						$breakfound = [$contentctr, $charctr, $cutcontentctr, $cutcharctr, 'discard'];
8099 					} /////////////////////
8100 					// 5) Break at Hard HYPHEN '-' or U+2010
8101 					/////////////////////
8102 					elseif (isset($this->textparam['hyphens']) && $this->textparam['hyphens'] != 2 && ($prevchar == '-' || $prevchar == "\xe2\x80\x90")) {
8103 						// Don't break a URL
8104 						// Look back to get first part of current word
8105 						$checkw = '';
8106 						for ($ac = $charctr - 1; $ac >= 0; $ac--) {
8107 							if ($this->usingCoreFont) {
8108 								$addc = substr($currContent, $ac, 1);
8109 							} else {
8110 								$addc = mb_substr($currContent, $ac, 1, $this->mb_enc);
8111 							}
8112 							if ($addc == ' ') {
8113 								break;
8114 							}
8115 							$checkw = $addc . $checkw;
8116 						}
8117 						// Don't break if HyphenMinus AND (a URL or before a numeral or before a >)
8118 						if ((!preg_match('/(http:|ftp:|https:|www\.)/', $checkw) && $checkchar != '>' && !preg_match('/[0-9]/', $checkchar)) || $prevchar == "\xe2\x80\x90") {
8119 							$breakfound = [$cutcontentctr, $cutcharctr, $cutcontentctr, $cutcharctr, 'cut'];
8120 						}
8121 					} /////////////////////
8122 					// 6) Break at Soft HYPHEN (replace with hard hyphen)
8123 					/////////////////////
8124 					elseif (isset($this->textparam['hyphens']) && $this->textparam['hyphens'] != 2 && !$this->usingCoreFont && $prevchar == "\xc2\xad") {
8125 						$breakfound = [$cutcontentctr, $cutcharctr, $cutcontentctr, $cutcharctr, 'cut'];
8126 						$content[$contentctr] = mb_substr($content[$contentctr], 0, $charctr, $this->mb_enc) . '-' . mb_substr($content[$contentctr], $charctr + 1, mb_strlen($content[$contentctr]), $this->mb_enc);
8127 						if (!empty($cOTLdata[$contentctr])) {
8128 							$cOTLdata[$contentctr]['char_data'][$charctr] = ['bidi_class' => 9, 'uni' => 45];
8129 							$cOTLdata[$contentctr]['group'][$charctr] = 'C';
8130 						}
8131 					} elseif (isset($this->textparam['hyphens']) && $this->textparam['hyphens'] != 2 && $this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats' && $prevchar == chr(173)) {
8132 						$breakfound = [$cutcontentctr, $cutcharctr, $cutcontentctr, $cutcharctr, 'cut'];
8133 						$content[$contentctr] = substr($content[$contentctr], 0, $charctr) . '-' . substr($content[$contentctr], $charctr + 1);
8134 					} /* -- CJK-FONTS -- */
8135 					/////////////////////
8136 					// 7) Break at CJK characters (unless forbidden characters to end or start line)
8137 					// CJK Avoiding line break in the middle of numerals
8138 					/////////////////////
8139 					elseif (!$this->usingCoreFont && $this->checkCJK && preg_match("/[" . $this->pregCJKchars . "]/u", $checkchar) &&
8140 						!preg_match("/[" . $this->CJKfollowing . "]/u", $checkchar) && !preg_match("/[" . $this->CJKleading . "]/u", $prevchar) &&
8141 						!(preg_match("/[0-9\x{ff10}-\x{ff19}]/u", $prevchar) && preg_match("/[0-9\x{ff10}-\x{ff19}]/u", $checkchar))) {
8142 						$breakfound = [$cutcontentctr, $cutcharctr, $cutcontentctr, $cutcharctr, 'cut'];
8143 					}
8144 					/* -- END CJK-FONTS -- */
8145 					/////////////////////
8146 					// 8) Break at OBJECT (Break before all objects here - selected objects are moved forward to next line below e.g. dottab)
8147 					/////////////////////
8148 					if (isset($this->objectbuffer[$contentctr])) {
8149 						$breakfound = [$cutcontentctr, $cutcharctr, $cutcontentctr, $cutcharctr, 'cut'];
8150 					}
8151 
8152 
8153 					$checkchar = $prevchar;
8154 				}
8155 
8156 				// If a line-break opportunity found:
8157 				if (is_array($breakfound)) {
8158 					$contentctr = $breakfound[0];
8159 					$charctr = $breakfound[1];
8160 					$cutcontentctr = $breakfound[2];
8161 					$cutcharctr = $breakfound[3];
8162 					$type = $breakfound[4];
8163 					// Cache chunks which are already processed, but now need to be passed on to the new line
8164 					for ($ix = count($content) - 1; $ix > $cutcontentctr; $ix--) {
8165 						// save and crop off any subsequent chunks
8166 						/* -- OTL -- */
8167 						if (!empty($sOTLdata)) {
8168 							$tmpOTL = array_pop($cOTLdata);
8169 							$savedPreOTLdata[] = $tmpOTL;
8170 						}
8171 						/* -- END OTL -- */
8172 						$savedPreContent[] = array_pop($content);
8173 						$savedPreContentB[] = array_pop($contentB);
8174 						$savedPreFont[] = array_pop($font);
8175 					}
8176 
8177 					// Next cache the part which will start the next line
8178 					if ($this->usingCoreFont) {
8179 						$savedPreContent[] = substr($content[$cutcontentctr], $cutcharctr);
8180 					} else {
8181 						$savedPreContent[] = mb_substr($content[$cutcontentctr], $cutcharctr, mb_strlen($content[$cutcontentctr]), $this->mb_enc);
8182 					}
8183 					$savedPreContentB[] = preg_replace('/L/', '', $contentB[$cutcontentctr]);
8184 					$savedPreFont[] = $font[$cutcontentctr];
8185 					/* -- OTL -- */
8186 					if (!empty($sOTLdata)) {
8187 						$savedPreOTLdata[] = $this->otl->splitOTLdata($cOTLdata[$cutcontentctr], $cutcharctr, $cutcharctr);
8188 					}
8189 					/* -- END OTL -- */
8190 
8191 
8192 					// Finally adjust the Current content which ends this line
8193 					if ($cutcharctr == 0 && $type == 'discard') {
8194 						array_pop($content);
8195 						array_pop($contentB);
8196 						array_pop($font);
8197 						array_pop($cOTLdata);
8198 					}
8199 
8200 					$currContent = & $content[count($content) - 1];
8201 					if ($this->usingCoreFont) {
8202 						$currContent = substr($currContent, 0, $charctr);
8203 					} else {
8204 						$currContent = mb_substr($currContent, 0, $charctr, $this->mb_enc);
8205 					}
8206 
8207 					if (!empty($sOTLdata)) {
8208 						$savedPreOTLdata[] = $this->otl->splitOTLdata($cOTLdata[(count($cOTLdata) - 1)], mb_strlen($currContent, $this->mb_enc));
8209 					}
8210 
8211 					if (strpos($contentB[(count($contentB) - 1)], 'R') !== false) {   // ???
8212 						$contentB[count($content) - 1] = preg_replace('/R/', '', $contentB[count($content) - 1]); // ???
8213 					}
8214 
8215 					if ($type == 'hyphen') {
8216 						$currContent .= '-';
8217 						if (!empty($cOTLdata[(count($cOTLdata) - 1)])) {
8218 							$cOTLdata[(count($cOTLdata) - 1)]['char_data'][] = ['bidi_class' => 9, 'uni' => 45];
8219 							$cOTLdata[(count($cOTLdata) - 1)]['group'] .= 'C';
8220 						}
8221 					}
8222 
8223 					$savedContent = '';
8224 					$savedContentB = '';
8225 					$savedFont = [];
8226 					$savedOTLdata = [];
8227 				}
8228 				// If no line-break opportunity found - split at current position
8229 				// or - Next character ($c) is suitable to add as overhanging or squeezed punctuation, or Oikomi, as set above by:
8230 				// 1) CJK Overflowing a) punctuation or b) Oikomi
8231 				// in which case $breakfound==1 and NOT array
8232 
8233 				if (!is_array($breakfound)) {
8234 					$savedFont = $this->saveFont();
8235 					if (!empty($sOTLdata)) {
8236 						$savedOTLdata = $this->otl->splitOTLdata($cOTLdata[(count($cOTLdata) - 1)], mb_strlen($currContent, $this->mb_enc));
8237 					}
8238 				}
8239 
8240 				if ($content[count($content) - 1] == '' && !isset($this->objectbuffer[count($content) - 1])) {
8241 					array_pop($content);
8242 					array_pop($contentB);
8243 					array_pop($font);
8244 					array_pop($cOTLdata);
8245 					$currContent = & $content[count($content) - 1];
8246 				}
8247 
8248 				// Right Trim current content - including CJK space, and for OTLdata
8249 				// incl. CJK - strip CJK space at end of line &#x3000; = \xe3\x80\x80 = CJK space
8250 				$currContent = $currContent ? rtrim($currContent) : '';
8251 				if ($this->checkCJK) {
8252 					$currContent = preg_replace("/\xe3\x80\x80$/", '', $currContent);
8253 				} // *CJK-FONTS*
8254 				/* -- OTL -- */
8255 				if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
8256 					$this->otl->trimOTLdata($cOTLdata[count($cOTLdata) - 1], false, true); // NB also does U+3000
8257 				}
8258 				/* -- END OTL -- */
8259 
8260 
8261 				// Selected OBJECTS are moved forward to next line, unless they come before a space or U+200B (type='discard')
8262 				if (isset($this->objectbuffer[(count($content) - 1)]) && (!isset($type) || $type != 'discard')) {
8263 					$objtype = $this->objectbuffer[(count($content) - 1)]['type'];
8264 					if ($objtype == 'dottab' || $objtype == 'bookmark' || $objtype == 'indexentry' || $objtype == 'toc' || $objtype == 'annot') {
8265 						$savedObj = array_pop($this->objectbuffer);
8266 					}
8267 				}
8268 
8269 
8270 				// Decimal alignment (cancel if wraps to > 1 line)
8271 				if ($is_table && substr($align, 0, 1) == 'D') {
8272 					$align = substr($align, 2, 1);
8273 				}
8274 
8275 				$lineBox = [];
8276 
8277 				$this->_setInlineBlockHeights($lineBox, $stackHeight, $content, $font, $is_table);
8278 
8279 				// update $contentWidth since it has changed with cropping
8280 				$contentWidth = 0;
8281 
8282 				$inclCursive = false;
8283 				foreach ($content as $k => $chunk) {
8284 					if (isset($this->objectbuffer[$k]) && $this->objectbuffer[$k]) {
8285 						// LIST MARKERS
8286 						if ($this->objectbuffer[$k]['type'] == 'image' && isset($this->objectbuffer[$k]['listmarker']) && $this->objectbuffer[$k]['listmarker']) {
8287 							if ($this->objectbuffer[$k]['listmarkerposition'] != 'outside') {
8288 								$contentWidth += $this->objectbuffer[$k]['OUTER-WIDTH'] * Mpdf::SCALE;
8289 							}
8290 						} else {
8291 							$contentWidth += $this->objectbuffer[$k]['OUTER-WIDTH'] * Mpdf::SCALE;
8292 						}
8293 					} elseif (!isset($this->objectbuffer[$k]) || (isset($this->objectbuffer[$k]) && !$this->objectbuffer[$k])) {
8294 						$this->restoreFont($font[$k], false);
8295 						if ($this->checkCJK && $k == count($content) - 1 && $CJKoverflow && $align == 'J' && $this->allowCJKoverflow && $this->CJKforceend) {
8296 							// force-end overhang
8297 							$hanger = mb_substr($chunk, mb_strlen($chunk, $this->mb_enc) - 1, 1, $this->mb_enc);
8298 							// Probably ought to do something with char_data and GPOS in cOTLdata...
8299 							$content[$k] = $chunk = mb_substr($chunk, 0, mb_strlen($chunk, $this->mb_enc) - 1, $this->mb_enc);
8300 						}
8301 
8302 						// Soft Hyphens chr(173) + Replace NBSP with SPACE + Set inclcursive if includes CURSIVE TEXT
8303 						if (!$this->usingCoreFont) {
8304 							/* -- OTL -- */
8305 							if ((isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) || !empty($sOTLdata)) {
8306 								$this->otl->removeChar($chunk, $cOTLdata[$k], "\xc2\xad");
8307 								$this->otl->replaceSpace($chunk, $cOTLdata[$k]); // NBSP -> space
8308 								if (preg_match("/([" . $this->pregCURSchars . "])/u", $chunk)) {
8309 									$inclCursive = true;
8310 								}
8311 								$content[$k] = $chunk;
8312 							} /* -- END OTL -- */ else {  // *OTL*
8313 								$content[$k] = $chunk = str_replace("\xc2\xad", '', $chunk);
8314 								$content[$k] = $chunk = str_replace(chr(194) . chr(160), chr(32), $chunk);
8315 							} // *OTL*
8316 						} elseif ($this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats') {
8317 							$content[$k] = $chunk = str_replace(chr(173), '', $chunk);
8318 							$content[$k] = $chunk = str_replace(chr(160), chr(32), $chunk);
8319 						}
8320 
8321 						$contentWidth += $this->GetStringWidth($chunk, true, (isset($cOTLdata[$k]) ? $cOTLdata[$k] : false), $this->textvar) * Mpdf::SCALE;  // mPDF 5.7.1
8322 						if (!empty($this->spanborddet)) {
8323 							if (isset($this->spanborddet['L']['w']) && strpos($contentB[$k], 'L') !== false) {
8324 								$contentWidth += $this->spanborddet['L']['w'] * Mpdf::SCALE;
8325 							}
8326 							if (isset($this->spanborddet['R']['w']) && strpos($contentB[$k], 'R') !== false) {
8327 								$contentWidth += $this->spanborddet['R']['w'] * Mpdf::SCALE;
8328 							}
8329 						}
8330 					}
8331 				}
8332 
8333 				$lastfontreqstyle = (isset($font[count($font) - 1]['ReqFontStyle']) ? $font[count($font) - 1]['ReqFontStyle'] : '');
8334 				$lastfontstyle = (isset($font[count($font) - 1]['style']) ? $font[count($font) - 1]['style'] : '');
8335 				if ($blockdir == 'ltr' && strpos($lastfontreqstyle, "I") !== false && strpos($lastfontstyle, "I") === false) { // Artificial italic
8336 					$lastitalic = $this->FontSize * 0.15 * Mpdf::SCALE;
8337 				} else {
8338 					$lastitalic = 0;
8339 				}
8340 
8341 
8342 
8343 
8344 				// NOW FORMAT THE LINE TO OUTPUT
8345 				if (!$table_draft) {
8346 					// DIRECTIONALITY RTL
8347 					$chunkorder = range(0, count($content) - 1); // mPDF 5.7
8348 					/* -- OTL -- */
8349 					// mPDF 6
8350 					if ($blockdir == 'rtl' || $this->biDirectional) {
8351 						$this->otl->bidiReorder($chunkorder, $content, $cOTLdata, $blockdir);
8352 						// From this point on, $content and $cOTLdata may contain more elements (and re-ordered) compared to
8353 						// $this->objectbuffer and $font ($chunkorder contains the mapping)
8354 					}
8355 
8356 					/* -- END OTL -- */
8357 					// Remove any XAdvance from OTL data at end of line
8358 					foreach ($chunkorder as $aord => $k) {
8359 						if (count($cOTLdata)) {
8360 							$this->restoreFont($font[$k], false);
8361 							// ...WriteFlowingBlock...
8362 							if ($aord == count($chunkorder) - 1 && isset($cOTLdata[$aord]['group'])) { // Last chunk on line
8363 								$nGPOS = strlen($cOTLdata[$aord]['group']) - 1; // Last character
8364 								if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL']) || isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'])) {
8365 									if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'])) {
8366 										$w = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] * 1000 / $this->CurrentFont['unitsPerEm'];
8367 									} else {
8368 										$w = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] * 1000 / $this->CurrentFont['unitsPerEm'];
8369 									}
8370 									$w *= ($this->FontSize / 1000);
8371 									$contentWidth -= $w * Mpdf::SCALE;
8372 									$cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] = 0;
8373 									$cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] = 0;
8374 								}
8375 
8376 								// If last character has an XPlacement set, adjust width calculation, and add to XAdvance to account for it
8377 								if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'])) {
8378 									$w = -$cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'] * 1000 / $this->CurrentFont['unitsPerEm'];
8379 									$w *= ($this->FontSize / 1000);
8380 									$contentWidth -= $w * Mpdf::SCALE;
8381 									$cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'];
8382 									$cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'];
8383 								}
8384 							}
8385 						}
8386 					}
8387 
8388 					// JUSTIFICATION J
8389 					$jcharspacing = 0;
8390 					$jws = 0;
8391 					$nb_carac = 0;
8392 					$nb_spaces = 0;
8393 					$jkashida = 0;
8394 					// if it's justified, we need to find the char/word spacing (or if hanger $this->CJKforceend)
8395 					if (($align == 'J' && !$CJKoverflow) || (($contentWidth + $lastitalic > $maxWidth - $WidthCorrection - (($this->cMarginL + $this->cMarginR) * Mpdf::SCALE) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * Mpdf::SCALE) ) + 0.001) && (!$CJKoverflow || ($CJKoverflow && !$this->allowCJKoverflow))) || $CJKoverflow && $align == 'J' && $this->allowCJKoverflow && $hanger && $this->CJKforceend) {   // 0.001 is to correct for deviations converting mm=>pts
8396 						// JUSTIFY J (Use character spacing)
8397 						// WORD SPACING
8398 						// mPDF 5.7
8399 						foreach ($chunkorder as $aord => $k) {
8400 							$chunk = isset($content[$aord]) ? $content[$aord] : '';
8401 							if (!isset($this->objectbuffer[$k]) || (isset($this->objectbuffer[$k]) && !$this->objectbuffer[$k])) {
8402 								$nb_carac += mb_strlen($chunk, $this->mb_enc);
8403 								$nb_spaces += mb_substr_count($chunk, ' ', $this->mb_enc);
8404 								// Use GPOS OTL
8405 								if (isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF)) {
8406 									if (isset($cOTLdata[$aord]['group']) && $cOTLdata[$aord]['group']) {
8407 										$nb_carac -= substr_count($cOTLdata[$aord]['group'], 'M');
8408 									}
8409 								}
8410 							} else {
8411 								$nb_carac ++;
8412 							} // mPDF 6 allow spacing for inline object
8413 						}
8414 						// GetJSpacing adds kashida spacing to GPOSinfo if appropriate for Font
8415 						list($jcharspacing, $jws, $jkashida) = $this->GetJspacing($nb_carac, $nb_spaces, ($maxWidth - $lastitalic - $contentWidth - $WidthCorrection - (($this->cMarginL + $this->cMarginR) * Mpdf::SCALE) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * Mpdf::SCALE) )), $inclCursive, $cOTLdata);
8416 					}
8417 
8418 					// WORD SPACING
8419 					$empty = $maxWidth - $lastitalic - $WidthCorrection - $contentWidth - (($this->cMarginL + $this->cMarginR) * Mpdf::SCALE) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * Mpdf::SCALE) );
8420 
8421 					$empty -= ($jcharspacing * ($nb_carac - 1)); // mPDF 6 nb_carac MINUS 1
8422 					$empty -= ($jws * $nb_spaces);
8423 					$empty -= ($jkashida);
8424 					$empty /= Mpdf::SCALE;
8425 
8426 					$b = ''; // do not use borders
8427 					// Get PAGEBREAK TO TEST for height including the top border/padding
8428 					$check_h = max($this->divheight, $stackHeight);
8429 					if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($this->blklvl > 0) && ($lineCount == 1) && (!$is_table)) {
8430 						$check_h += ($this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['border_top']['w']);
8431 					}
8432 
8433 					if ($this->ColActive && $check_h > ($this->PageBreakTrigger - $this->y0)) {
8434 						$this->SetCol($this->NbCol - 1);
8435 					}
8436 
8437 					// PAGEBREAK
8438 					// 'If' below used in order to fix "first-line of other page with justify on" bug
8439 					if (!$is_table && ($this->y + $check_h) > $this->PageBreakTrigger and ! $this->InFooter and $this->AcceptPageBreak()) {
8440 						$bak_x = $this->x; // Current X position
8441 						// WORD SPACING
8442 						$ws = $this->ws; // Word Spacing
8443 						$charspacing = $this->charspacing; // Character Spacing
8444 						$this->ResetSpacing();
8445 
8446 						$this->AddPage($this->CurOrientation);
8447 
8448 						$this->x = $bak_x;
8449 						// Added to correct for OddEven Margins
8450 						$currentx += $this->MarginCorrection;
8451 						$this->x += $this->MarginCorrection;
8452 
8453 						// WORD SPACING
8454 						$this->SetSpacing($charspacing, $ws);
8455 					}
8456 
8457 					if ($this->kwt && !$is_table) { // mPDF 5.7+
8458 						$this->printkwtbuffer();
8459 						$this->kwt = false;
8460 					}
8461 
8462 
8463 					/* -- COLUMNS -- */
8464 					// COLS
8465 					// COLUMN CHANGE
8466 					if ($this->CurrCol != $oldcolumn) {
8467 						$currentx += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
8468 						$this->x += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
8469 						$oldcolumn = $this->CurrCol;
8470 					}
8471 
8472 					if ($this->ColActive && !$is_table) {
8473 						$this->breakpoints[$this->CurrCol][] = $this->y;
8474 					} // *COLUMNS*
8475 					/* -- END COLUMNS -- */
8476 
8477 					// TOP MARGIN
8478 					if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($this->blk[$this->blklvl]['margin_top']) && ($lineCount == 1) && (!$is_table)) {
8479 						$this->DivLn($this->blk[$this->blklvl]['margin_top'], $this->blklvl - 1, true, $this->blk[$this->blklvl]['margin_collapse']);
8480 						if ($this->ColActive) {
8481 							$this->breakpoints[$this->CurrCol][] = $this->y;
8482 						} // *COLUMNS*
8483 					}
8484 
8485 
8486 					// Update y0 for top of block (used to paint border)
8487 					if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 1) && (!$is_table)) {
8488 						$this->blk[$this->blklvl]['y0'] = $this->y;
8489 						$this->blk[$this->blklvl]['startpage'] = $this->page;
8490 						if ($this->blk[$this->blklvl]['float']) {
8491 							$this->blk[$this->blklvl]['float_start_y'] = $this->y;
8492 						}
8493 					}
8494 
8495 					// TOP PADDING and BORDER spacing/fill
8496 					if (($newblock) && ($blockstate == 1 || $blockstate == 3) && (($this->blk[$this->blklvl]['padding_top']) || ($this->blk[$this->blklvl]['border_top'])) && ($lineCount == 1) && (!$is_table)) {
8497 						// $state = 0 normal; 1 top; 2 bottom; 3 top and bottom
8498 						$this->DivLn($this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'], -3, true, false, 1);
8499 						if ($this->ColActive) {
8500 							$this->breakpoints[$this->CurrCol][] = $this->y;
8501 						} // *COLUMNS*
8502 					}
8503 
8504 					$arraysize = count($chunkorder);
8505 
8506 					$margins = ($this->cMarginL + $this->cMarginR) + ($ipaddingL + $ipaddingR + $fpaddingR + $fpaddingR );
8507 
8508 					// PAINT BACKGROUND FOR THIS LINE
8509 					if (!$is_table) {
8510 						$this->DivLn($stackHeight, $this->blklvl, false);
8511 					} // false -> don't advance y
8512 
8513 					$this->x = $currentx + $this->cMarginL + $ipaddingL + $fpaddingL;
8514 					if ($align == 'R') {
8515 						$this->x += $empty;
8516 					} elseif ($align == 'C') {
8517 						$this->x += ($empty / 2);
8518 					}
8519 
8520 					// Paragraph INDENT
8521 					if (isset($this->blk[$this->blklvl]['text_indent']) && ($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 1) && (!$is_table) && ($blockdir != 'rtl') && ($align != 'C')) {
8522 						$ti = $this->sizeConverter->convert($this->blk[$this->blklvl]['text_indent'], $this->blk[$this->blklvl]['inner_width'], $this->blk[$this->blklvl]['InlineProperties']['size'], false);  // mPDF 5.7.4
8523 						$this->x += $ti;
8524 					}
8525 
8526 					// BIDI magic_reverse moved upwards from here
8527 					foreach ($chunkorder as $aord => $k) { // mPDF 5.7
8528 
8529 						$chunk = isset($content[$aord]) ? $content[$aord] : '';
8530 
8531 						if (isset($this->objectbuffer[$k]) && $this->objectbuffer[$k]) {
8532 							$xadj = $this->x - $this->objectbuffer[$k]['OUTER-X'];
8533 							$this->objectbuffer[$k]['OUTER-X'] += $xadj;
8534 							$this->objectbuffer[$k]['BORDER-X'] += $xadj;
8535 							$this->objectbuffer[$k]['INNER-X'] += $xadj;
8536 
8537 							if ($this->objectbuffer[$k]['type'] == 'listmarker') {
8538 								$this->objectbuffer[$k]['lineBox'] = $lineBox[-1]; // Block element details for glyph-origin
8539 							}
8540 							$yadj = $this->y - $this->objectbuffer[$k]['OUTER-Y'];
8541 							if ($this->objectbuffer[$k]['type'] == 'dottab') { // mPDF 6 DOTTAB
8542 								$this->objectbuffer[$k]['lineBox'] = $lineBox[$k]; // element details for glyph-origin
8543 							}
8544 							if ($this->objectbuffer[$k]['type'] != 'dottab') { // mPDF 6 DOTTAB
8545 								$yadj += $lineBox[$k]['top'];
8546 							}
8547 							$this->objectbuffer[$k]['OUTER-Y'] += $yadj;
8548 							$this->objectbuffer[$k]['BORDER-Y'] += $yadj;
8549 							$this->objectbuffer[$k]['INNER-Y'] += $yadj;
8550 						}
8551 
8552 						$this->restoreFont($font[$k]);  // mPDF 5.7
8553 
8554 						$this->SetSpacing(($this->fixedlSpacing * Mpdf::SCALE) + $jcharspacing, ($this->fixedlSpacing + $this->minwSpacing) * Mpdf::SCALE + $jws);
8555 						// Now unset these values so they don't influence GetStringwidth below or in fn. Cell
8556 						$this->fixedlSpacing = false;
8557 						$this->minwSpacing = 0;
8558 
8559 						$save_vis = $this->visibility;
8560 						if (isset($this->textparam['visibility']) && $this->textparam['visibility'] && $this->textparam['visibility'] != $this->visibility) {
8561 							$this->SetVisibility($this->textparam['visibility']);
8562 						}
8563 						// *********** SPAN BACKGROUND COLOR ***************** //
8564 						if ($this->spanbgcolor) {
8565 							$cor = $this->spanbgcolorarray;
8566 							$this->SetFColor($cor);
8567 							$save_fill = $fill;
8568 							$spanfill = 1;
8569 							$fill = 1;
8570 						}
8571 						if (!empty($this->spanborddet)) {
8572 							if (strpos($contentB[$k], 'L') !== false) {
8573 								$this->x += (isset($this->spanborddet['L']['w']) ? $this->spanborddet['L']['w'] : 0);
8574 							}
8575 							if (strpos($contentB[$k], 'L') === false) {
8576 								$this->spanborddet['L']['s'] = $this->spanborddet['L']['w'] = 0;
8577 							}
8578 							if (strpos($contentB[$k], 'R') === false) {
8579 								$this->spanborddet['R']['s'] = $this->spanborddet['R']['w'] = 0;
8580 							}
8581 						}
8582 
8583 						// WORD SPACING
8584 						// StringWidth this time includes any kashida spacing
8585 						$stringWidth = $this->GetStringWidth($chunk, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, true);
8586 
8587 						$nch = mb_strlen($chunk, $this->mb_enc);
8588 						// Use GPOS OTL
8589 						if (isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF)) {
8590 							if (isset($cOTLdata[$aord]['group']) && $cOTLdata[$aord]['group']) {
8591 								$nch -= substr_count($cOTLdata[$aord]['group'], 'M');
8592 							}
8593 						}
8594 						$stringWidth += ( $this->charspacing * $nch / Mpdf::SCALE );
8595 
8596 						$stringWidth += ( $this->ws * mb_substr_count($chunk, ' ', $this->mb_enc) / Mpdf::SCALE );
8597 
8598 						if (isset($this->objectbuffer[$k])) {
8599 							// LIST MARKERS	// mPDF 6  Lists
8600 							if ($this->objectbuffer[$k]['type'] == 'image' && isset($this->objectbuffer[$k]['listmarker']) && $this->objectbuffer[$k]['listmarker'] && $this->objectbuffer[$k]['listmarkerposition'] == 'outside') {
8601 								$stringWidth = 0;
8602 							} else {
8603 								$stringWidth = $this->objectbuffer[$k]['OUTER-WIDTH'];
8604 							}
8605 						}
8606 
8607 						if ($stringWidth == 0) {
8608 							$stringWidth = 0.000001;
8609 						}
8610 
8611 						if ($aord == $arraysize - 1) {
8612 							$stringWidth -= ( $this->charspacing / Mpdf::SCALE );
8613 							if ($this->checkCJK && $CJKoverflow && $align == 'J' && $this->allowCJKoverflow && $hanger && $this->CJKforceend) {
8614 								// force-end overhang
8615 								$this->Cell($stringWidth, $stackHeight, $chunk, '', 0, '', $fill, $this->HREF, $currentx, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false));
8616 								$this->Cell($this->GetStringWidth($hanger), $stackHeight, $hanger, '', 1, '', $fill, $this->HREF, $currentx, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false));
8617 							} else {
8618 								$this->Cell($stringWidth, $stackHeight, $chunk, '', 1, '', $fill, $this->HREF, $currentx, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false)); // mono-style line or last part (skips line)
8619 							}
8620 						} else {
8621 							$this->Cell($stringWidth, $stackHeight, $chunk, '', 0, '', $fill, $this->HREF, 0, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false)); // first or middle part
8622 						}
8623 
8624 						if (!empty($this->spanborddet)) {
8625 							if (strpos($contentB[$k], 'R') !== false && $aord != $arraysize - 1) {
8626 								$this->x += $this->spanborddet['R']['w'];
8627 							}
8628 						}
8629 						// *********** SPAN BACKGROUND COLOR OFF - RESET BLOCK BGCOLOR ***************** //
8630 						if (isset($spanfill) && $spanfill) {
8631 							$fill = $save_fill;
8632 							$spanfill = 0;
8633 							if ($fill) {
8634 								$this->SetFColor($bcor);
8635 							}
8636 						}
8637 						if (isset($this->textparam['visibility']) && $this->textparam['visibility'] && $this->visibility != $save_vis) {
8638 							$this->SetVisibility($save_vis);
8639 						}
8640 					}
8641 				} elseif ($table_draft) {
8642 					$this->y += $stackHeight;
8643 				}
8644 
8645 				if (!$is_table) {
8646 					$this->maxPosR = max($this->maxPosR, ($this->w - $this->rMargin - $this->blk[$this->blklvl]['outer_right_margin']));
8647 					$this->maxPosL = min($this->maxPosL, ($this->lMargin + $this->blk[$this->blklvl]['outer_left_margin']));
8648 				}
8649 
8650 				// move on to the next line, reset variables, tack on saved content and current char
8651 
8652 				if (!$table_draft) {
8653 					$this->printobjectbuffer($is_table, $blockdir);
8654 				}
8655 				$this->objectbuffer = [];
8656 
8657 
8658 				/* -- CSS-IMAGE-FLOAT -- */
8659 				// Update values if set to skipline
8660 				if ($this->floatmargins) {
8661 					$this->_advanceFloatMargins();
8662 				}
8663 				/* -- END CSS-IMAGE-FLOAT -- */
8664 
8665 				// Reset lineheight
8666 				$stackHeight = $this->divheight;
8667 				$valign = 'M';
8668 
8669 				$font = [];
8670 				$content = [];
8671 				$contentB = [];
8672 				$cOTLdata = []; // mPDF 5.7.1
8673 				$contentWidth = 0;
8674 				if (!empty($savedObj)) {
8675 					$this->objectbuffer[] = $savedObj;
8676 					$font[] = $savedFont;
8677 					$content[] = '';
8678 					$contentB[] = '';
8679 					$cOTLdata[] = []; // mPDF 5.7.1
8680 					$contentWidth += $savedObj['OUTER-WIDTH'] * Mpdf::SCALE;
8681 				}
8682 				if (count($savedPreContent) > 0) {
8683 					for ($ix = count($savedPreContent) - 1; $ix >= 0; $ix--) {
8684 						$font[] = $savedPreFont[$ix];
8685 						$content[] = $savedPreContent[$ix];
8686 						$contentB[] = $savedPreContentB[$ix];
8687 						if (!empty($sOTLdata)) {
8688 							$cOTLdata[] = $savedPreOTLdata[$ix];
8689 						}
8690 						$this->restoreFont($savedPreFont[$ix]);
8691 						$lbw = $rbw = 0; // Border widths
8692 						if (!empty($this->spanborddet)) {
8693 							$lbw = (isset($this->spanborddet['L']['w']) ? $this->spanborddet['L']['w'] : 0);
8694 							$rbw = (isset($this->spanborddet['R']['w']) ? $this->spanborddet['R']['w'] : 0);
8695 						}
8696 						if ($ix > 0) {
8697 							$contentWidth += $this->GetStringWidth($savedPreContent[$ix], true, (isset($savedPreOTLdata[$ix]) ? $savedPreOTLdata[$ix] : false), $this->textvar) * Mpdf::SCALE; // mPDF 5.7.1
8698 							if (strpos($savedPreContentB[$ix], 'L') !== false) {
8699 								$contentWidth += $lbw;
8700 							}
8701 							if (strpos($savedPreContentB[$ix], 'R') !== false) {
8702 								$contentWidth += $rbw;
8703 							}
8704 						}
8705 					}
8706 					$savedPreContent = [];
8707 					$savedPreContentB = [];
8708 					$savedPreOTLdata = []; // mPDF 5.7.1
8709 					$savedPreFont = [];
8710 					$content[(count($content) - 1)] .= $c;
8711 				} else {
8712 					$font[] = $savedFont;
8713 					$content[] = $savedContent . $c;
8714 					$contentB[] = $savedContentB;
8715 					$cOTLdata[] = $savedOTLdata; // mPDF 5.7.1
8716 				}
8717 
8718 				$currContent = & $content[(count($content) - 1)];
8719 				$this->restoreFont($font[(count($font) - 1)]); // mPDF 6.0
8720 
8721 				/* -- CJK-FONTS -- */
8722 				// CJK - strip CJK space at start of line
8723 				// &#x3000; = \xe3\x80\x80 = CJK space
8724 				if ($this->checkCJK && $currContent == "\xe3\x80\x80") {
8725 					$currContent = '';
8726 					if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
8727 						$this->otl->trimOTLdata($cOTLdata[count($cOTLdata) - 1], true, false); // left trim U+3000
8728 					}
8729 				}
8730 				/* -- END CJK-FONTS -- */
8731 
8732 				$lbw = $rbw = 0; // Border widths
8733 				if (!empty($this->spanborddet)) {
8734 					$lbw = (isset($this->spanborddet['L']['w']) ? $this->spanborddet['L']['w'] : 0);
8735 					$rbw = (isset($this->spanborddet['R']['w']) ? $this->spanborddet['R']['w'] : 0);
8736 				}
8737 
8738 				$contentWidth += $this->GetStringWidth($currContent, false, (isset($cOTLdata[(count($cOTLdata) - 1)]) ? $cOTLdata[(count($cOTLdata) - 1)] : false), $this->textvar) * Mpdf::SCALE; // mPDF 5.7.1
8739 				if (strpos($savedContentB, 'L') !== false) {
8740 					$contentWidth += $lbw;
8741 				}
8742 				$CJKoverflow = false;
8743 				$hanger = '';
8744 			} // another character will fit, so add it on
8745 			else {
8746 				$contentWidth += $cw;
8747 				$currContent .= $c;
8748 			}
8749 		}
8750 
8751 		unset($content);
8752 		unset($contentB);
8753 	}
8754 
8755 	// ----------------------END OF FLOWING BLOCK------------------------------------//
8756 
8757 
8758 	/* -- CSS-IMAGE-FLOAT -- */
8759 	// Update values if set to skipline
8760 	function _advanceFloatMargins()
8761 	{
8762 		// Update floatmargins - L
8763 		if (isset($this->floatmargins['L']) && $this->floatmargins['L']['skipline'] && $this->floatmargins['L']['y0'] != $this->y) {
8764 			$yadj = $this->y - $this->floatmargins['L']['y0'];
8765 			$this->floatmargins['L']['y0'] = $this->y;
8766 			$this->floatmargins['L']['y1'] += $yadj;
8767 
8768 			// Update objattr in floatbuffer
8769 			if ($this->floatbuffer[$this->floatmargins['L']['id']]['border_left']['w']) {
8770 				$this->floatbuffer[$this->floatmargins['L']['id']]['BORDER-Y'] += $yadj;
8771 			}
8772 			$this->floatbuffer[$this->floatmargins['L']['id']]['INNER-Y'] += $yadj;
8773 			$this->floatbuffer[$this->floatmargins['L']['id']]['OUTER-Y'] += $yadj;
8774 
8775 			// Unset values
8776 			$this->floatbuffer[$this->floatmargins['L']['id']]['skipline'] = false;
8777 			$this->floatmargins['L']['skipline'] = false;
8778 			$this->floatmargins['L']['id'] = '';
8779 		}
8780 		// Update floatmargins - R
8781 		if (isset($this->floatmargins['R']) && $this->floatmargins['R']['skipline'] && $this->floatmargins['R']['y0'] != $this->y) {
8782 			$yadj = $this->y - $this->floatmargins['R']['y0'];
8783 			$this->floatmargins['R']['y0'] = $this->y;
8784 			$this->floatmargins['R']['y1'] += $yadj;
8785 
8786 			// Update objattr in floatbuffer
8787 			if ($this->floatbuffer[$this->floatmargins['R']['id']]['border_left']['w']) {
8788 				$this->floatbuffer[$this->floatmargins['R']['id']]['BORDER-Y'] += $yadj;
8789 			}
8790 			$this->floatbuffer[$this->floatmargins['R']['id']]['INNER-Y'] += $yadj;
8791 			$this->floatbuffer[$this->floatmargins['R']['id']]['OUTER-Y'] += $yadj;
8792 
8793 			// Unset values
8794 			$this->floatbuffer[$this->floatmargins['R']['id']]['skipline'] = false;
8795 			$this->floatmargins['R']['skipline'] = false;
8796 			$this->floatmargins['R']['id'] = '';
8797 		}
8798 	}
8799 
8800 	/* -- END CSS-IMAGE-FLOAT -- */
8801 
8802 
8803 
8804 	/* -- END HTML-CSS -- */
8805 
8806 	function _SetTextRendering($mode)
8807 	{
8808 		if (!(($mode == 0) || ($mode == 1) || ($mode == 2))) {
8809 			throw new \Mpdf\MpdfException("Text rendering mode should be 0, 1 or 2 (value : $mode)");
8810 		}
8811 		$tr = ($mode . ' Tr');
8812 		if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['TextRendering']) && $this->pageoutput[$this->page]['TextRendering'] != $tr) || !isset($this->pageoutput[$this->page]['TextRendering']))) {
8813 			$this->writer->write($tr);
8814 		}
8815 		$this->pageoutput[$this->page]['TextRendering'] = $tr;
8816 	}
8817 
8818 	function SetTextOutline($params = [])
8819 	{
8820 		if (isset($params['outline-s']) && $params['outline-s']) {
8821 			$this->SetLineWidth($params['outline-WIDTH']);
8822 			$this->SetDColor($params['outline-COLOR']);
8823 			$tr = ('2 Tr');
8824 			if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['TextRendering']) && $this->pageoutput[$this->page]['TextRendering'] != $tr) || !isset($this->pageoutput[$this->page]['TextRendering']))) {
8825 				$this->writer->write($tr);
8826 			}
8827 			$this->pageoutput[$this->page]['TextRendering'] = $tr;
8828 		} else { // Now resets all values
8829 			$this->SetLineWidth(0.2);
8830 			$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
8831 			$this->_SetTextRendering(0);
8832 			$tr = ('0 Tr');
8833 			if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['TextRendering']) && $this->pageoutput[$this->page]['TextRendering'] != $tr) || !isset($this->pageoutput[$this->page]['TextRendering']))) {
8834 				$this->writer->write($tr);
8835 			}
8836 			$this->pageoutput[$this->page]['TextRendering'] = $tr;
8837 		}
8838 	}
8839 
8840 	function Image($file, $x, $y, $w = 0, $h = 0, $type = '', $link = '', $paint = true, $constrain = true, $watermark = false, $shownoimg = true, $allowvector = true)
8841 	{
8842 		$orig_srcpath = $file;
8843 		$this->GetFullPath($file);
8844 
8845 		$info = $this->imageProcessor->getImage($file, true, $allowvector, $orig_srcpath);
8846 		if (!$info && $paint) {
8847 			$info = $this->imageProcessor->getImage($this->noImageFile);
8848 			if ($info) {
8849 				$file = $this->noImageFile;
8850 				$w = ($info['w'] * (25.4 / $this->img_dpi));  // 14 x 16px
8851 				$h = ($info['h'] * (25.4 / $this->img_dpi));  // 14 x 16px
8852 			}
8853 		}
8854 		if (!$info) {
8855 			return false;
8856 		}
8857 		// Automatic width and height calculation if needed
8858 		if ($w == 0 and $h == 0) {
8859 			/* -- IMAGES-WMF -- */
8860 			if ($info['type'] == 'wmf') {
8861 				// WMF units are twips (1/20pt)
8862 				// divide by 20 to get points
8863 				// divide by k to get user units
8864 				$w = abs($info['w']) / (20 * Mpdf::SCALE);
8865 				$h = abs($info['h']) / (20 * Mpdf::SCALE);
8866 			} else { 			/* -- END IMAGES-WMF -- */
8867 				if ($info['type'] == 'svg') {
8868 					// returned SVG units are pts
8869 					// divide by k to get user units (mm)
8870 					$w = abs($info['w']) / Mpdf::SCALE;
8871 					$h = abs($info['h']) / Mpdf::SCALE;
8872 				} else {
8873 					// Put image at default image dpi
8874 					$w = ($info['w'] / Mpdf::SCALE) * (72 / $this->img_dpi);
8875 					$h = ($info['h'] / Mpdf::SCALE) * (72 / $this->img_dpi);
8876 				}
8877 			}
8878 		}
8879 		if ($w == 0) {
8880 			$w = abs($h * $info['w'] / $info['h']);
8881 		}
8882 		if ($h == 0) {
8883 			$h = abs($w * $info['h'] / $info['w']);
8884 		}
8885 
8886 		/* -- WATERMARK -- */
8887 		if ($watermark) {
8888 			$maxw = $this->w;
8889 			$maxh = $this->h;
8890 			// Size = D PF or array
8891 			if (is_array($this->watermark_size)) {
8892 				$w = $this->watermark_size[0];
8893 				$h = $this->watermark_size[1];
8894 			} elseif (!is_string($this->watermark_size)) {
8895 				$maxw -= $this->watermark_size * 2;
8896 				$maxh -= $this->watermark_size * 2;
8897 				$w = $maxw;
8898 				$h = abs($w * $info['h'] / $info['w']);
8899 				if ($h > $maxh) {
8900 					$h = $maxh;
8901 					$w = abs($h * $info['w'] / $info['h']);
8902 				}
8903 			} elseif ($this->watermark_size == 'F') {
8904 				if ($this->ColActive) {
8905 					$maxw = $this->w - ($this->DeflMargin + $this->DefrMargin);
8906 				} else {
8907 					$maxw = $this->pgwidth;
8908 				}
8909 				$maxh = $this->h - ($this->tMargin + $this->bMargin);
8910 				$w = $maxw;
8911 				$h = abs($w * $info['h'] / $info['w']);
8912 				if ($h > $maxh) {
8913 					$h = $maxh;
8914 					$w = abs($h * $info['w'] / $info['h']);
8915 				}
8916 			} elseif ($this->watermark_size == 'P') { // Default P
8917 				$w = $maxw;
8918 				$h = abs($w * $info['h'] / $info['w']);
8919 				if ($h > $maxh) {
8920 					$h = $maxh;
8921 					$w = abs($h * $info['w'] / $info['h']);
8922 				}
8923 			}
8924 			// Automatically resize to maximum dimensions of page if too large
8925 			if ($w > $maxw) {
8926 				$w = $maxw;
8927 				$h = abs($w * $info['h'] / $info['w']);
8928 			}
8929 			if ($h > $maxh) {
8930 				$h = $maxh;
8931 				$w = abs($h * $info['w'] / $info['h']);
8932 			}
8933 			// Position
8934 			if (is_array($this->watermark_pos)) {
8935 				$x = $this->watermark_pos[0];
8936 				$y = $this->watermark_pos[1];
8937 			} elseif ($this->watermark_pos == 'F') { // centred on printable area
8938 				if ($this->ColActive) { // *COLUMNS*
8939 					if (($this->mirrorMargins) && (($this->page) % 2 == 0)) {
8940 						$xadj = $this->DeflMargin - $this->DefrMargin;
8941 					} // *COLUMNS*
8942 					else {
8943 						$xadj = 0;
8944 					} // *COLUMNS*
8945 					$x = ($this->DeflMargin - $xadj + ($this->w - ($this->DeflMargin + $this->DefrMargin)) / 2) - ($w / 2); // *COLUMNS*
8946 				} // *COLUMNS*
8947 				else {  // *COLUMNS*
8948 					$x = ($this->lMargin + ($this->pgwidth) / 2) - ($w / 2);
8949 				} // *COLUMNS*
8950 				$y = ($this->tMargin + ($this->h - ($this->tMargin + $this->bMargin)) / 2) - ($h / 2);
8951 			} else { // default P - centred on whole page
8952 				$x = ($this->w / 2) - ($w / 2);
8953 				$y = ($this->h / 2) - ($h / 2);
8954 			}
8955 			/* -- IMAGES-WMF -- */
8956 			if ($info['type'] == 'wmf') {
8957 				$sx = $w * Mpdf::SCALE / $info['w'];
8958 				$sy = -$h * Mpdf::SCALE / $info['h'];
8959 				$outstring = sprintf('q %.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, $sy, $x * Mpdf::SCALE - $sx * $info['x'], (($this->h - $y) * Mpdf::SCALE) - $sy * $info['y'], $info['i']);
8960 			} else { 			/* -- END IMAGES-WMF -- */
8961 				if ($info['type'] == 'svg') {
8962 					$sx = $w * Mpdf::SCALE / $info['w'];
8963 					$sy = -$h * Mpdf::SCALE / $info['h'];
8964 					$outstring = sprintf('q %.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, $sy, $x * Mpdf::SCALE - $sx * $info['x'], (($this->h - $y) * Mpdf::SCALE) - $sy * $info['y'], $info['i']);
8965 				} else {
8966 					$outstring = sprintf("q %.3F 0 0 %.3F %.3F %.3F cm /I%d Do Q", $w * Mpdf::SCALE, $h * Mpdf::SCALE, $x * Mpdf::SCALE, ($this->h - ($y + $h)) * Mpdf::SCALE, $info['i']);
8967 				}
8968 			}
8969 
8970 			if ($this->watermarkImgBehind) {
8971 				$outstring = $this->watermarkImgAlpha . "\n" . $outstring . "\n" . $this->SetAlpha(1, 'Normal', true) . "\n";
8972 				$this->pages[$this->page] = preg_replace('/(___BACKGROUND___PATTERNS' . $this->uniqstr . ')/', "\n" . $outstring . "\n" . '\\1', $this->pages[$this->page]);
8973 			} else {
8974 				$this->writer->write($outstring);
8975 			}
8976 
8977 			return 0;
8978 		} // end of IF watermark
8979 		/* -- END WATERMARK -- */
8980 
8981 		if ($constrain) {
8982 			// Automatically resize to maximum dimensions of page if too large
8983 			if (isset($this->blk[$this->blklvl]['inner_width']) && $this->blk[$this->blklvl]['inner_width']) {
8984 				$maxw = $this->blk[$this->blklvl]['inner_width'];
8985 			} else {
8986 				$maxw = $this->pgwidth;
8987 			}
8988 			if ($w > $maxw) {
8989 				$w = $maxw;
8990 				$h = abs($w * $info['h'] / $info['w']);
8991 			}
8992 			if ($h > $this->h - ($this->tMargin + $this->bMargin + 1)) {  // see below - +10 to avoid drawing too close to border of page
8993 				$h = $this->h - ($this->tMargin + $this->bMargin + 1);
8994 				if ($this->fullImageHeight) {
8995 					$h = $this->fullImageHeight;
8996 				}
8997 				$w = abs($h * $info['w'] / $info['h']);
8998 			}
8999 
9000 
9001 			// Avoid drawing out of the paper(exceeding width limits).
9002 			// if ( ($x + $w) > $this->fw ) {
9003 			if (($x + $w) > $this->w) {
9004 				$x = $this->lMargin;
9005 				$y += 5;
9006 			}
9007 
9008 			$changedpage = false;
9009 			$oldcolumn = $this->CurrCol;
9010 			// Avoid drawing out of the page.
9011 			if ($y + $h > $this->PageBreakTrigger and ! $this->InFooter and $this->AcceptPageBreak()) {
9012 				$this->AddPage($this->CurOrientation);
9013 				// Added to correct for OddEven Margins
9014 				$x = $x + $this->MarginCorrection;
9015 				$y = $this->tMargin; // mPDF 5.7.3
9016 				$changedpage = true;
9017 			}
9018 			/* -- COLUMNS -- */
9019 			// COLS
9020 			// COLUMN CHANGE
9021 			if ($this->CurrCol != $oldcolumn) {
9022 				$y = $this->y0;
9023 				$x += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
9024 				$this->x += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
9025 			}
9026 			/* -- END COLUMNS -- */
9027 		} // end of IF constrain
9028 
9029 		/* -- IMAGES-WMF -- */
9030 		if ($info['type'] == 'wmf') {
9031 			$sx = $w * Mpdf::SCALE / $info['w'];
9032 			$sy = -$h * Mpdf::SCALE / $info['h'];
9033 			$outstring = sprintf('q %.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, $sy, $x * Mpdf::SCALE - $sx * $info['x'], (($this->h - $y) * Mpdf::SCALE) - $sy * $info['y'], $info['i']);
9034 		} else { 		/* -- END IMAGES-WMF -- */
9035 			if ($info['type'] == 'svg') {
9036 				$sx = $w * Mpdf::SCALE / $info['w'];
9037 				$sy = -$h * Mpdf::SCALE / $info['h'];
9038 				$outstring = sprintf('q %.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, $sy, $x * Mpdf::SCALE - $sx * $info['x'], (($this->h - $y) * Mpdf::SCALE) - $sy * $info['y'], $info['i']);
9039 			} else {
9040 				$outstring = sprintf("q %.3F 0 0 %.3F %.3F %.3F cm /I%d Do Q", $w * Mpdf::SCALE, $h * Mpdf::SCALE, $x * Mpdf::SCALE, ($this->h - ($y + $h)) * Mpdf::SCALE, $info['i']);
9041 			}
9042 		}
9043 
9044 		if ($paint) {
9045 			$this->writer->write($outstring);
9046 			if ($link) {
9047 				$this->Link($x, $y, $w, $h, $link);
9048 			}
9049 
9050 			// Avoid writing text on top of the image. // THIS WAS OUTSIDE THE if ($paint) bit!!!!!!!!!!!!!!!!
9051 			$this->y = $y + $h;
9052 		}
9053 
9054 		// Return width-height array
9055 		$sizesarray['WIDTH'] = $w;
9056 		$sizesarray['HEIGHT'] = $h;
9057 		$sizesarray['X'] = $x; // Position before painting image
9058 		$sizesarray['Y'] = $y; // Position before painting image
9059 		$sizesarray['OUTPUT'] = $outstring;
9060 
9061 		$sizesarray['IMAGE_ID'] = $info['i'];
9062 		$sizesarray['itype'] = $info['type'];
9063 		$sizesarray['set-dpi'] = (isset($info['set-dpi']) ? $info['set-dpi'] : 0);
9064 		return $sizesarray;
9065 	}
9066 
9067 	// =============================================================
9068 	// =============================================================
9069 	// =============================================================
9070 	// =============================================================
9071 	// =============================================================
9072 	/* -- HTML-CSS -- */
9073 
9074 	function _getObjAttr($t)
9075 	{
9076 		$c = explode("\xbb\xa4\xac", $t, 2);
9077 		$c = explode(",", $c[1], 2);
9078 		foreach ($c as $v) {
9079 			$v = explode("=", $v, 2);
9080 			$sp[$v[0]] = $v[1];
9081 		}
9082 		return (unserialize($sp['objattr']));
9083 	}
9084 
9085 	function inlineObject($type, $x, $y, $objattr, $Lmargin, $widthUsed, $maxWidth, $lineHeight, $paint = false, $is_table = false)
9086 	{
9087 		if ($is_table) {
9088 			$k = $this->shrin_k;
9089 		} else {
9090 			$k = 1;
9091 		}
9092 
9093 		// NB $x is only used when paint=true
9094 		// Lmargin not used
9095 		$w = 0;
9096 		if (isset($objattr['width'])) {
9097 			$w = $objattr['width'] / $k;
9098 		}
9099 		$h = 0;
9100 		if (isset($objattr['height'])) {
9101 			$h = abs($objattr['height'] / $k);
9102 		}
9103 		$widthLeft = $maxWidth - $widthUsed;
9104 		$maxHeight = $this->h - ($this->tMargin + $this->bMargin + 10);
9105 		if ($this->fullImageHeight) {
9106 			$maxHeight = $this->fullImageHeight;
9107 		}
9108 		// For Images
9109 		if (isset($objattr['border_left'])) {
9110 			$extraWidth = ($objattr['border_left']['w'] + $objattr['border_right']['w'] + $objattr['margin_left'] + $objattr['margin_right']) / $k;
9111 			$extraHeight = ($objattr['border_top']['w'] + $objattr['border_bottom']['w'] + $objattr['margin_top'] + $objattr['margin_bottom']) / $k;
9112 
9113 			if ($type == 'image' || $type == 'barcode' || $type == 'textcircle') {
9114 				$extraWidth += ($objattr['padding_left'] + $objattr['padding_right']) / $k;
9115 				$extraHeight += ($objattr['padding_top'] + $objattr['padding_bottom']) / $k;
9116 			}
9117 		}
9118 
9119 		if (!isset($objattr['vertical-align'])) {
9120 			if ($objattr['type'] == 'select') {
9121 				$objattr['vertical-align'] = 'M';
9122 			} else {
9123 				$objattr['vertical-align'] = 'BS';
9124 			}
9125 		} // mPDF 6
9126 
9127 		if ($type == 'image' || (isset($objattr['subtype']) && $objattr['subtype'] == 'IMAGE')) {
9128 			if (isset($objattr['itype']) && ($objattr['itype'] == 'wmf' || $objattr['itype'] == 'svg')) {
9129 				$file = $objattr['file'];
9130 				$info = $this->formobjects[$file];
9131 			} elseif (isset($objattr['file'])) {
9132 				$file = $objattr['file'];
9133 				$info = $this->images[$file];
9134 			}
9135 		}
9136 		if ($type == 'annot' || $type == 'bookmark' || $type == 'indexentry' || $type == 'toc') {
9137 			$w = 0.00001;
9138 			$h = 0.00001;
9139 		}
9140 
9141 		// TEST whether need to skipline
9142 		if (!$paint) {
9143 			if ($type == 'hr') { // always force new line
9144 				if (($y + $h + $lineHeight > $this->PageBreakTrigger) && !$this->InFooter && !$is_table) {
9145 					return [-2, $w, $h];
9146 				} // New page + new line
9147 				else {
9148 					return [1, $w, $h];
9149 				} // new line
9150 			} else {
9151 				// LIST MARKERS	// mPDF 6  Lists
9152 				$displayheight = $h;
9153 				$displaywidth = $w;
9154 				if ($objattr['type'] == 'image' && isset($objattr['listmarker']) && $objattr['listmarker']) {
9155 					$displayheight = 0;
9156 					if ($objattr['listmarkerposition'] == 'outside') {
9157 						$displaywidth = 0;
9158 					}
9159 				}
9160 
9161 				if ($widthUsed > 0 && $displaywidth > $widthLeft && (!$is_table || $type != 'image')) {  // New line needed
9162 					// mPDF 6  Lists
9163 					if (($y + $displayheight + $lineHeight > $this->PageBreakTrigger) && !$this->InFooter) {
9164 						return [-2, $w, $h];
9165 					} // New page + new line
9166 					return [1, $w, $h]; // new line
9167 				} elseif ($widthUsed > 0 && $displaywidth > $widthLeft && $is_table) {  // New line needed in TABLE
9168 					return [1, $w, $h]; // new line
9169 				} // Will fit on line but NEW PAGE REQUIRED
9170 				elseif (($y + $displayheight > $this->PageBreakTrigger) && !$this->InFooter && !$is_table) {
9171 					return [-1, $w, $h];
9172 				} // mPDF 6  Lists
9173 				else {
9174 					return [0, $w, $h];
9175 				}
9176 			}
9177 		}
9178 
9179 		if ($type == 'annot' || $type == 'bookmark' || $type == 'indexentry' || $type == 'toc') {
9180 			$w = 0.00001;
9181 			$h = 0.00001;
9182 			$objattr['BORDER-WIDTH'] = 0;
9183 			$objattr['BORDER-HEIGHT'] = 0;
9184 			$objattr['BORDER-X'] = $x;
9185 			$objattr['BORDER-Y'] = $y;
9186 			$objattr['INNER-WIDTH'] = 0;
9187 			$objattr['INNER-HEIGHT'] = 0;
9188 			$objattr['INNER-X'] = $x;
9189 			$objattr['INNER-Y'] = $y;
9190 		}
9191 
9192 		if ($type == 'image') {
9193 			// Automatically resize to width remaining
9194 			if ($w > ($widthLeft + 0.0001) && !$is_table) { // mPDF 5.7.4  0.0001 to allow for rounding errors when w==maxWidth
9195 				$w = $widthLeft;
9196 				$h = abs($w * $info['h'] / $info['w']);
9197 			}
9198 			$img_w = $w - $extraWidth;
9199 			$img_h = $h - $extraHeight;
9200 
9201 			$objattr['BORDER-WIDTH'] = $img_w + $objattr['padding_left'] / $k + $objattr['padding_right'] / $k + (($objattr['border_left']['w'] / $k + $objattr['border_right']['w'] / $k) / 2);
9202 			$objattr['BORDER-HEIGHT'] = $img_h + $objattr['padding_top'] / $k + $objattr['padding_bottom'] / $k + (($objattr['border_top']['w'] / $k + $objattr['border_bottom']['w'] / $k) / 2);
9203 			$objattr['BORDER-X'] = $x + $objattr['margin_left'] / $k + (($objattr['border_left']['w'] / $k) / 2);
9204 			$objattr['BORDER-Y'] = $y + $objattr['margin_top'] / $k + (($objattr['border_top']['w'] / $k) / 2);
9205 			$objattr['INNER-WIDTH'] = $img_w;
9206 			$objattr['INNER-HEIGHT'] = $img_h;
9207 			$objattr['INNER-X'] = $x + $objattr['padding_left'] / $k + $objattr['margin_left'] / $k + ($objattr['border_left']['w'] / $k);
9208 			$objattr['INNER-Y'] = $y + $objattr['padding_top'] / $k + $objattr['margin_top'] / $k + ($objattr['border_top']['w'] / $k);
9209 			$objattr['ID'] = $info['i'];
9210 		}
9211 
9212 		if ($type == 'input' && $objattr['subtype'] == 'IMAGE') {
9213 			$img_w = $w - $extraWidth;
9214 			$img_h = $h - $extraHeight;
9215 			$objattr['BORDER-WIDTH'] = $img_w + (($objattr['border_left']['w'] / $k + $objattr['border_right']['w'] / $k) / 2);
9216 			$objattr['BORDER-HEIGHT'] = $img_h + (($objattr['border_top']['w'] / $k + $objattr['border_bottom']['w'] / $k) / 2);
9217 			$objattr['BORDER-X'] = $x + $objattr['margin_left'] / $k + (($objattr['border_left']['w'] / $k) / 2);
9218 			$objattr['BORDER-Y'] = $y + $objattr['margin_top'] / $k + (($objattr['border_top']['w'] / $k) / 2);
9219 			$objattr['INNER-WIDTH'] = $img_w;
9220 			$objattr['INNER-HEIGHT'] = $img_h;
9221 			$objattr['INNER-X'] = $x + $objattr['margin_left'] / $k + ($objattr['border_left']['w'] / $k);
9222 			$objattr['INNER-Y'] = $y + $objattr['margin_top'] / $k + ($objattr['border_top']['w'] / $k);
9223 			$objattr['ID'] = $info['i'];
9224 		}
9225 
9226 		if ($type == 'barcode' || $type == 'textcircle') {
9227 			$b_w = $w - $extraWidth;
9228 			$b_h = $h - $extraHeight;
9229 			$objattr['BORDER-WIDTH'] = $b_w + $objattr['padding_left'] / $k + $objattr['padding_right'] / $k + (($objattr['border_left']['w'] / $k + $objattr['border_right']['w'] / $k) / 2);
9230 			$objattr['BORDER-HEIGHT'] = $b_h + $objattr['padding_top'] / $k + $objattr['padding_bottom'] / $k + (($objattr['border_top']['w'] / $k + $objattr['border_bottom']['w'] / $k) / 2);
9231 			$objattr['BORDER-X'] = $x + $objattr['margin_left'] / $k + (($objattr['border_left']['w'] / $k) / 2);
9232 			$objattr['BORDER-Y'] = $y + $objattr['margin_top'] / $k + (($objattr['border_top']['w'] / $k) / 2);
9233 			$objattr['INNER-X'] = $x + $objattr['padding_left'] / $k + $objattr['margin_left'] / $k + ($objattr['border_left']['w'] / $k);
9234 			$objattr['INNER-Y'] = $y + $objattr['padding_top'] / $k + $objattr['margin_top'] / $k + ($objattr['border_top']['w'] / $k);
9235 			$objattr['INNER-WIDTH'] = $b_w;
9236 			$objattr['INNER-HEIGHT'] = $b_h;
9237 		}
9238 
9239 
9240 		if ($type == 'textarea') {
9241 			// Automatically resize to width remaining
9242 			if ($w > $widthLeft && !$is_table) {
9243 				$w = $widthLeft;
9244 			}
9245 			// This used to resize height to maximum remaining on page ? why. Causes problems when in table and causing a new column
9246 			// if (($y + $h > $this->PageBreakTrigger) && !$this->InFooter) {
9247 			// 	$h=$this->h - $y - $this->bMargin;
9248 			// }
9249 		}
9250 
9251 		if ($type == 'hr') {
9252 			if ($is_table) {
9253 				$objattr['INNER-WIDTH'] = $maxWidth * $objattr['W-PERCENT'] / 100;
9254 				$objattr['width'] = $objattr['INNER-WIDTH'];
9255 				$w = $maxWidth;
9256 			} else {
9257 				if ($w > $maxWidth) {
9258 					$w = $maxWidth;
9259 				}
9260 				$objattr['INNER-WIDTH'] = $w;
9261 				$w = $maxWidth;
9262 			}
9263 		}
9264 
9265 
9266 
9267 		if (($type == 'select') || ($type == 'input' && ($objattr['subtype'] == 'TEXT' || $objattr['subtype'] == 'PASSWORD'))) {
9268 			// Automatically resize to width remaining
9269 			if ($w > $widthLeft && !$is_table) {
9270 				$w = $widthLeft;
9271 			}
9272 		}
9273 
9274 		if ($type == 'textarea' || $type == 'select' || $type == 'input') {
9275 			if (isset($objattr['fontsize'])) {
9276 				$objattr['fontsize'] /= $k;
9277 			}
9278 			if (isset($objattr['linewidth'])) {
9279 				$objattr['linewidth'] /= $k;
9280 			}
9281 		}
9282 
9283 		if (!isset($objattr['BORDER-Y'])) {
9284 			$objattr['BORDER-Y'] = 0;
9285 		}
9286 		if (!isset($objattr['BORDER-X'])) {
9287 			$objattr['BORDER-X'] = 0;
9288 		}
9289 		if (!isset($objattr['INNER-Y'])) {
9290 			$objattr['INNER-Y'] = 0;
9291 		}
9292 		if (!isset($objattr['INNER-X'])) {
9293 			$objattr['INNER-X'] = 0;
9294 		}
9295 
9296 		// Return width-height array
9297 		$objattr['OUTER-WIDTH'] = $w;
9298 		$objattr['OUTER-HEIGHT'] = $h;
9299 		$objattr['OUTER-X'] = $x;
9300 		$objattr['OUTER-Y'] = $y;
9301 		return $objattr;
9302 	}
9303 
9304 	/* -- END HTML-CSS -- */
9305 
9306 	// =============================================================
9307 	// =============================================================
9308 	// =============================================================
9309 	// =============================================================
9310 	// =============================================================
9311 
9312 	function SetLineJoin($mode = 0)
9313 	{
9314 		$s = sprintf('%d j', $mode);
9315 		if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['LineJoin']) && $this->pageoutput[$this->page]['LineJoin'] != $s) || !isset($this->pageoutput[$this->page]['LineJoin']))) {
9316 			$this->writer->write($s);
9317 		}
9318 		$this->pageoutput[$this->page]['LineJoin'] = $s;
9319 	}
9320 
9321 	function SetLineCap($mode = 2)
9322 	{
9323 		$s = sprintf('%d J', $mode);
9324 		if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['LineCap']) && $this->pageoutput[$this->page]['LineCap'] != $s) || !isset($this->pageoutput[$this->page]['LineCap']))) {
9325 			$this->writer->write($s);
9326 		}
9327 		$this->pageoutput[$this->page]['LineCap'] = $s;
9328 	}
9329 
9330 	function SetDash($black = false, $white = false)
9331 	{
9332 		if ($black and $white) {
9333 			$s = sprintf('[%.3F %.3F] 0 d', $black * Mpdf::SCALE, $white * Mpdf::SCALE);
9334 		} else {
9335 			$s = '[] 0 d';
9336 		}
9337 
9338 		if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['Dash']) && $this->pageoutput[$this->page]['Dash'] != $s) || !isset($this->pageoutput[$this->page]['Dash']))) {
9339 			$this->writer->write($s);
9340 		}
9341 
9342 		$this->pageoutput[$this->page]['Dash'] = $s;
9343 	}
9344 
9345 	function SetDisplayPreferences($preferences)
9346 	{
9347 		// String containing any or none of /HideMenubar/HideToolbar/HideWindowUI/DisplayDocTitle/CenterWindow/FitWindow
9348 
9349 		$this->DisplayPreferences .= $preferences;
9350 	}
9351 
9352 	function Ln($h = '', $collapsible = 0)
9353 	{
9354 		// Added collapsible to allow collapsible top-margin on new page
9355 		// Line feed; default value is last cell height
9356 
9357 		$margin = isset($this->blk[$this->blklvl]['outer_left_margin']) ? $this->blk[$this->blklvl]['outer_left_margin'] : 0;
9358 
9359 		$this->x = $this->lMargin + $margin;
9360 
9361 		if ($collapsible && ($this->y == $this->tMargin) && (!$this->ColActive)) {
9362 			$h = 0;
9363 		}
9364 
9365 		if (is_string($h)) {
9366 			$this->y += $this->lasth;
9367 		} else {
9368 			$this->y += $h;
9369 		}
9370 	}
9371 
9372 	/* -- HTML-CSS -- */
9373 
9374 	function DivLn($h, $level = -3, $move_y = true, $collapsible = false, $state = 0)
9375 	{
9376 		// $state = 0 normal; 1 top; 2 bottom; 3 top and bottom
9377 		// Used in Columns and keep-with-table i.e. "kwt"
9378 		// writes background block by block so it can be repositioned
9379 		// and also used in writingFlowingBlock at top and bottom of blocks to move y (not to draw/paint anything)
9380 		// adds lines (y) where DIV bgcolors are filled in
9381 		// this->x is returned as it was
9382 		// allows .00001 as nominal height used for bookmarks/annotations etc.
9383 		if ($collapsible && (sprintf("%0.4f", $this->y) == sprintf("%0.4f", $this->tMargin)) && (!$this->ColActive)) {
9384 			return;
9385 		}
9386 
9387 		// mPDF 6 Columns
9388 		//   if ($collapsible && (sprintf("%0.4f", $this->y)==sprintf("%0.4f", $this->y0)) && ($this->ColActive) && $this->CurrCol == 0) { return; }	// *COLUMNS*
9389 		if ($collapsible && (sprintf("%0.4f", $this->y) == sprintf("%0.4f", $this->y0)) && ($this->ColActive)) {
9390 			return;
9391 		} // *COLUMNS*
9392 		// Still use this method if columns or keep-with-table, as it allows repositioning later
9393 		// otherwise, now uses PaintDivBB()
9394 		if (!$this->ColActive && !$this->kwt) {
9395 			if ($move_y && !$this->ColActive) {
9396 				$this->y += $h;
9397 			}
9398 			return;
9399 		}
9400 
9401 		if ($level == -3) {
9402 			$level = $this->blklvl;
9403 		}
9404 		$firstblockfill = $this->GetFirstBlockFill();
9405 		if ($firstblockfill && $this->blklvl > 0 && $this->blklvl >= $firstblockfill) {
9406 			$last_x = 0;
9407 			$last_w = 0;
9408 			$last_fc = $this->FillColor;
9409 			$bak_x = $this->x;
9410 			$bak_h = $this->divheight;
9411 			$this->divheight = 0; // Temporarily turn off divheight - as Cell() uses it to check for PageBreak
9412 			for ($blvl = $firstblockfill; $blvl <= $level; $blvl++) {
9413 				$this->x = $this->lMargin + $this->blk[$blvl]['outer_left_margin'];
9414 				// mPDF 6
9415 				if ($this->blk[$blvl]['bgcolor']) {
9416 					$this->SetFColor($this->blk[$blvl]['bgcolorarray']);
9417 				}
9418 				if ($last_x != ($this->lMargin + $this->blk[$blvl]['outer_left_margin']) || ($last_w != $this->blk[$blvl]['width']) || $last_fc != $this->FillColor || (isset($this->blk[$blvl]['border_top']['s']) && $this->blk[$blvl]['border_top']['s']) || (isset($this->blk[$blvl]['border_bottom']['s']) && $this->blk[$blvl]['border_bottom']['s']) || (isset($this->blk[$blvl]['border_left']['s']) && $this->blk[$blvl]['border_left']['s']) || (isset($this->blk[$blvl]['border_right']['s']) && $this->blk[$blvl]['border_right']['s'])) {
9419 					$x = $this->x;
9420 					$this->Cell(($this->blk[$blvl]['width']), $h, '', '', 0, '', 1);
9421 					$this->x = $x;
9422 					if (!$this->keep_block_together && !$this->writingHTMLheader && !$this->writingHTMLfooter) {
9423 						// $state = 0 normal; 1 top; 2 bottom; 3 top and bottom
9424 						if ($blvl == $this->blklvl) {
9425 							$this->PaintDivLnBorder($state, $blvl, $h);
9426 						} else {
9427 							$this->PaintDivLnBorder(0, $blvl, $h);
9428 						}
9429 					}
9430 				}
9431 				$last_x = $this->lMargin + $this->blk[$blvl]['outer_left_margin'];
9432 				$last_w = $this->blk[$blvl]['width'];
9433 				$last_fc = $this->FillColor;
9434 			}
9435 			// Reset current block fill
9436 			if (isset($this->blk[$this->blklvl]['bgcolorarray'])) {
9437 				$bcor = $this->blk[$this->blklvl]['bgcolorarray'];
9438 				$this->SetFColor($bcor);
9439 			}
9440 			$this->x = $bak_x;
9441 			$this->divheight = $bak_h;
9442 		}
9443 		if ($move_y) {
9444 			$this->y += $h;
9445 		}
9446 	}
9447 
9448 	/* -- END HTML-CSS -- */
9449 
9450 	function SetX($x)
9451 	{
9452 		// Set x position
9453 		if ($x >= 0) {
9454 			$this->x = $x;
9455 		} else {
9456 			$this->x = $this->w + $x;
9457 		}
9458 	}
9459 
9460 	function SetY($y)
9461 	{
9462 		// Set y position and reset x
9463 		$this->x = $this->lMargin;
9464 		if ($y >= 0) {
9465 			$this->y = $y;
9466 		} else {
9467 			$this->y = $this->h + $y;
9468 		}
9469 	}
9470 
9471 	function SetXY($x, $y)
9472 	{
9473 		// Set x and y positions
9474 		$this->SetY($y);
9475 		$this->SetX($x);
9476 	}
9477 
9478 	function Output($name = '', $dest = '')
9479 	{
9480 		$this->logger->debug(sprintf('PDF generated in %.6F seconds', microtime(true) - $this->time0), ['context' => LogContext::STATISTICS]);
9481 
9482 		// Finish document if necessary
9483 		if ($this->state < 3) {
9484 			$this->Close();
9485 		}
9486 
9487 		if ($this->debug && error_get_last()) {
9488 			$e = error_get_last();
9489 			if (($e['type'] < 2048 && $e['type'] != 8) || (intval($e['type']) & intval(ini_get("error_reporting")))) {
9490 				throw new \Mpdf\MpdfException(
9491 					sprintf('Error detected. PDF file generation aborted: %s', $e['message']),
9492 					$e['type'],
9493 					1,
9494 					$e['file'],
9495 					$e['line']
9496 				);
9497 			}
9498 		}
9499 
9500 		if (($this->PDFA || $this->PDFX) && $this->encrypted) {
9501 			throw new \Mpdf\MpdfException('PDF/A1-b or PDF/X1-a does not permit encryption of documents.');
9502 		}
9503 
9504 		if (count($this->PDFAXwarnings) && (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto))) {
9505 			if ($this->PDFA) {
9506 				$standard = 'PDFA/1-b';
9507 				$option = '$mpdf->PDFAauto';
9508 			} else {
9509 				$standard = 'PDFX/1-a ';
9510 				$option = '$mpdf->PDFXauto';
9511 			}
9512 
9513 			$this->logger->warning(sprintf('PDF could not be generated as it stands as a %s compliant file.', $standard), ['context' => LogContext::PDFA_PDFX]);
9514 			$this->logger->warning(sprintf('These issues can be automatically fixed by mPDF using %s = true;', $option), ['context' => LogContext::PDFA_PDFX]);
9515 			$this->logger->warning(sprintf('Action that mPDF will take to automatically force %s compliance are shown further in the log.', $standard), ['context' => LogContext::PDFA_PDFX]);
9516 
9517 			$this->PDFAXwarnings = array_unique($this->PDFAXwarnings);
9518 			foreach ($this->PDFAXwarnings as $w) {
9519 				$this->logger->warning($w, ['context' => LogContext::PDFA_PDFX]);
9520 			}
9521 
9522 			throw new \Mpdf\MpdfException('PDFA/PDFX warnings generated. See log for further details');
9523 		}
9524 
9525 		$this->logger->debug(sprintf('Compiled in %.6F seconds', microtime(true) - $this->time0), ['context' => LogContext::STATISTICS]);
9526 		$this->logger->debug(sprintf('Peak Memory usage %s MB', number_format(memory_get_peak_usage(true) / (1024 * 1024), 2)), ['context' => LogContext::STATISTICS]);
9527 		$this->logger->debug(sprintf('PDF file size %s kB', number_format(strlen($this->buffer) / 1024)), ['context' => LogContext::STATISTICS]);
9528 		$this->logger->debug(sprintf('%d fonts used', count($this->fonts)), ['context' => LogContext::STATISTICS]);
9529 
9530 		if (is_bool($dest)) {
9531 			$dest = $dest ? Destination::DOWNLOAD : Destination::FILE;
9532 		}
9533 
9534 		$dest = strtoupper($dest);
9535 		if (empty($dest)) {
9536 			if (empty($name)) {
9537 				$name = 'mpdf.pdf';
9538 				$dest = Destination::INLINE;
9539 			} else {
9540 				$dest = Destination::FILE;
9541 			}
9542 		}
9543 
9544 		switch ($dest) {
9545 
9546 			case Destination::INLINE:
9547 
9548 				if (headers_sent($filename, $line)) {
9549 					throw new \Mpdf\MpdfException(
9550 						sprintf('Data has already been sent to output (%s at line %s), unable to output PDF file', $filename, $line)
9551 					);
9552 				}
9553 
9554 				if ($this->debug && !$this->allow_output_buffering && ob_get_contents()) {
9555 					throw new \Mpdf\MpdfException('Output has already been sent from the script - PDF file generation aborted.');
9556 				}
9557 
9558 				// We send to a browser
9559 				if (PHP_SAPI !== 'cli') {
9560 					header('Content-Type: application/pdf');
9561 
9562 					if (!isset($_SERVER['HTTP_ACCEPT_ENCODING']) || empty($_SERVER['HTTP_ACCEPT_ENCODING'])) {
9563 						// don't use length if server using compression
9564 						header('Content-Length: ' . strlen($this->buffer));
9565 					}
9566 
9567 					header('Content-disposition: inline; filename="' . $name . '"');
9568 					header('Cache-Control: public, must-revalidate, max-age=0');
9569 					header('Pragma: public');
9570 					header('X-Generator: mPDF' . ($this->exposeVersion ? (' ' . static::VERSION) : ''));
9571 					header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
9572 					header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
9573 				}
9574 
9575 				echo $this->buffer;
9576 
9577 				break;
9578 
9579 			case Destination::DOWNLOAD:
9580 
9581 				if (headers_sent()) {
9582 					throw new \Mpdf\MpdfException('Data has already been sent to output, unable to output PDF file');
9583 				}
9584 
9585 				header('Content-Description: File Transfer');
9586 				header('Content-Transfer-Encoding: binary');
9587 				header('Cache-Control: public, must-revalidate, max-age=0');
9588 				header('Pragma: public');
9589 				header('X-Generator: mPDF' . ($this->exposeVersion ? (' ' . static::VERSION) : ''));
9590 				header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
9591 				header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
9592 				header('Content-Type: application/pdf');
9593 
9594 				if (!isset($_SERVER['HTTP_ACCEPT_ENCODING']) || empty($_SERVER['HTTP_ACCEPT_ENCODING'])) {
9595 					// don't use length if server using compression
9596 					header('Content-Length: ' . strlen($this->buffer));
9597 				}
9598 
9599 				header('Content-Disposition: attachment; filename="' . $name . '"');
9600 
9601 				echo $this->buffer;
9602 
9603 				break;
9604 
9605 			case Destination::FILE:
9606 				$f = fopen($name, 'wb');
9607 
9608 				if (!$f) {
9609 					throw new \Mpdf\MpdfException(sprintf('Unable to create output file %s', $name));
9610 				}
9611 
9612 				fwrite($f, $this->buffer, strlen($this->buffer));
9613 				fclose($f);
9614 
9615 				break;
9616 
9617 			case Destination::STRING_RETURN:
9618 				$this->cache->clearOld();
9619 				return $this->buffer;
9620 
9621 			default:
9622 				throw new \Mpdf\MpdfException(sprintf('Incorrect output destination %s', $dest));
9623 		}
9624 
9625 		$this->cache->clearOld();
9626 	}
9627 
9628 	// *****************************************************************************
9629 	//                                                                             *
9630 	//                             Protected methods                               *
9631 	//                                                                             *
9632 	// *****************************************************************************
9633 	function _dochecks()
9634 	{
9635 		// Check for locale-related bug
9636 		if (1.1 == 1) {
9637 			throw new \Mpdf\MpdfException('Do not alter the locale before including mPDF');
9638 		}
9639 
9640 		// Check for decimal separator
9641 		if (sprintf('%.1f', 1.0) != '1.0') {
9642 			setlocale(LC_NUMERIC, 'C');
9643 		}
9644 
9645 		if (ini_get('mbstring.func_overload')) {
9646 			throw new \Mpdf\MpdfException('Mpdf cannot function properly with mbstring.func_overload enabled');
9647 		}
9648 
9649 		if (!function_exists('mb_substr')) {
9650 			throw new \Mpdf\MpdfException('mbstring extension must be loaded in order to run mPDF');
9651 		}
9652 
9653 		if (!function_exists('mb_regex_encoding')) {
9654 			if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
9655 				$mamp = ' If using MAMP, there is a bug in its PHP build causing this.';
9656 			}
9657 
9658 			throw new \Mpdf\MpdfException('mbstring extension with mbregex support must be loaded in order to run mPDF.' . $mamp);
9659 		}
9660 	}
9661 
9662 	function _puthtmlheaders()
9663 	{
9664 		$this->state = 2;
9665 		$nb = $this->page;
9666 		for ($n = 1; $n <= $nb; $n++) {
9667 			if ($this->mirrorMargins && $n % 2 == 0) {
9668 				$OE = 'E';
9669 			} // EVEN
9670 			else {
9671 				$OE = 'O';
9672 			}
9673 			$this->page = $n;
9674 			$pn = $this->docPageNum($n);
9675 			if ($pn) {
9676 				$pnstr = $this->pagenumPrefix . $pn . $this->pagenumSuffix;
9677 			} else {
9678 				$pnstr = '';
9679 			}
9680 
9681 			$pnt = $this->docPageNumTotal($n);
9682 
9683 			if ($pnt) {
9684 				$pntstr = $this->nbpgPrefix . $pnt . $this->nbpgSuffix;
9685 			} else {
9686 				$pntstr = '';
9687 			}
9688 
9689 			if (isset($this->saveHTMLHeader[$n][$OE])) {
9690 				$html = isset($this->saveHTMLHeader[$n][$OE]['html']) ? $this->saveHTMLHeader[$n][$OE]['html'] : '';
9691 				$this->lMargin = $this->saveHTMLHeader[$n][$OE]['ml'];
9692 				$this->rMargin = $this->saveHTMLHeader[$n][$OE]['mr'];
9693 				$this->tMargin = $this->saveHTMLHeader[$n][$OE]['mh'];
9694 				$this->bMargin = $this->saveHTMLHeader[$n][$OE]['mf'];
9695 				$this->margin_header = $this->saveHTMLHeader[$n][$OE]['mh'];
9696 				$this->margin_footer = $this->saveHTMLHeader[$n][$OE]['mf'];
9697 				$this->w = $this->saveHTMLHeader[$n][$OE]['pw'];
9698 				$this->h = $this->saveHTMLHeader[$n][$OE]['ph'];
9699 				$rotate = (isset($this->saveHTMLHeader[$n][$OE]['rotate']) ? $this->saveHTMLHeader[$n][$OE]['rotate'] : null);
9700 				$this->Reset();
9701 				$this->pageoutput[$n] = [];
9702 				$this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
9703 				$this->x = $this->lMargin;
9704 				$this->y = $this->margin_header;
9705 
9706 				// Replace of page number aliases and date format
9707 				$html = $this->aliasReplace($html, $pnstr, $pntstr, $nb);
9708 
9709 				$this->HTMLheaderPageLinks = [];
9710 				$this->HTMLheaderPageAnnots = [];
9711 				$this->HTMLheaderPageForms = [];
9712 				$this->pageBackgrounds = [];
9713 
9714 				$this->writingHTMLheader = true;
9715 				$this->WriteHTML($html, HTMLParserMode::HTML_HEADER_BUFFER);
9716 				$this->writingHTMLheader = false;
9717 				$this->Reset();
9718 				$this->pageoutput[$n] = [];
9719 
9720 				$s = $this->PrintPageBackgrounds();
9721 				$this->headerbuffer = $s . $this->headerbuffer;
9722 				$os = '';
9723 				if ($rotate) {
9724 					$os .= sprintf('q 0 -1 1 0 0 %.3F cm ', ($this->w * Mpdf::SCALE));
9725 					// To rotate the other way i.e. Header to left of page:
9726 					// $os .= sprintf('q 0 1 -1 0 %.3F %.3F cm ',($this->h*Mpdf::SCALE), (($this->rMargin - $this->lMargin )*Mpdf::SCALE));
9727 				}
9728 				$os .= $this->headerbuffer;
9729 				if ($rotate) {
9730 					$os .= ' Q' . "\n";
9731 				}
9732 
9733 				// Writes over the page background but behind any other output on page
9734 				$os = preg_replace(['/\\\\/', '/\$/'], ['\\\\\\\\', '\\\\$'], $os);
9735 
9736 				$this->pages[$n] = preg_replace('/(___HEADER___MARKER' . $this->uniqstr . ')/', "\n" . $os . "\n" . '\\1', $this->pages[$n]);
9737 
9738 				$lks = $this->HTMLheaderPageLinks;
9739 				foreach ($lks as $lk) {
9740 					if ($rotate) {
9741 						$lw = $lk[2];
9742 						$lh = $lk[3];
9743 						$lk[2] = $lh;
9744 						$lk[3] = $lw; // swap width and height
9745 						$ax = $lk[0] / Mpdf::SCALE;
9746 						$ay = $lk[1] / Mpdf::SCALE;
9747 						$bx = $ay - ($lh / Mpdf::SCALE);
9748 						$by = $this->w - $ax;
9749 						$lk[0] = $bx * Mpdf::SCALE;
9750 						$lk[1] = ($this->h - $by) * Mpdf::SCALE - $lw;
9751 					}
9752 					$this->PageLinks[$n][] = $lk;
9753 				}
9754 				/* -- FORMS -- */
9755 				foreach ($this->HTMLheaderPageForms as $f) {
9756 					$this->form->forms[$f['n']] = $f;
9757 				}
9758 				/* -- END FORMS -- */
9759 			}
9760 
9761 			if (isset($this->saveHTMLFooter[$n][$OE])) {
9762 
9763 				$html = $this->saveHTMLFooter[$this->page][$OE]['html'];
9764 
9765 				$this->lMargin = $this->saveHTMLFooter[$n][$OE]['ml'];
9766 				$this->rMargin = $this->saveHTMLFooter[$n][$OE]['mr'];
9767 				$this->tMargin = $this->saveHTMLFooter[$n][$OE]['mh'];
9768 				$this->bMargin = $this->saveHTMLFooter[$n][$OE]['mf'];
9769 				$this->margin_header = $this->saveHTMLFooter[$n][$OE]['mh'];
9770 				$this->margin_footer = $this->saveHTMLFooter[$n][$OE]['mf'];
9771 				$this->w = $this->saveHTMLFooter[$n][$OE]['pw'];
9772 				$this->h = $this->saveHTMLFooter[$n][$OE]['ph'];
9773 				$rotate = (isset($this->saveHTMLFooter[$n][$OE]['rotate']) ? $this->saveHTMLFooter[$n][$OE]['rotate'] : null);
9774 				$this->Reset();
9775 				$this->pageoutput[$n] = [];
9776 				$this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
9777 				$this->x = $this->lMargin;
9778 				$top_y = $this->y = $this->h - $this->margin_footer;
9779 
9780 				// if bottom-margin==0, corrects to avoid division by zero
9781 				if ($this->y == $this->h) {
9782 					$top_y = $this->y = ($this->h + 0.01);
9783 				}
9784 
9785 				// Replace of page number aliases and date format
9786 				$html = $this->aliasReplace($html, $pnstr, $pntstr, $nb);
9787 
9788 				$this->HTMLheaderPageLinks = [];
9789 				$this->HTMLheaderPageAnnots = [];
9790 				$this->HTMLheaderPageForms = [];
9791 				$this->pageBackgrounds = [];
9792 
9793 				$this->writingHTMLfooter = true;
9794 				$this->InFooter = true;
9795 				$this->WriteHTML($html, HTMLParserMode::HTML_HEADER_BUFFER);
9796 				$this->InFooter = false;
9797 				$this->Reset();
9798 				$this->pageoutput[$n] = [];
9799 
9800 				$fheight = $this->y - $top_y;
9801 				$adj = -$fheight;
9802 
9803 				$s = $this->PrintPageBackgrounds(-$adj);
9804 				$this->headerbuffer = $s . $this->headerbuffer;
9805 				$this->writingHTMLfooter = false; // mPDF 5.7.3  (moved after PrintPageBackgrounds so can adjust position of images in footer)
9806 
9807 				$os = '';
9808 				$os .= $this->StartTransform(true) . "\n";
9809 
9810 				if ($rotate) {
9811 					$os .= sprintf('q 0 -1 1 0 0 %.3F cm ', ($this->w * Mpdf::SCALE));
9812 					// To rotate the other way i.e. Header to left of page:
9813 					// $os .= sprintf('q 0 1 -1 0 %.3F %.3F cm ',($this->h*Mpdf::SCALE), (($this->rMargin - $this->lMargin )*Mpdf::SCALE));
9814 				}
9815 
9816 				$os .= $this->transformTranslate(0, $adj, true) . "\n";
9817 				$os .= $this->headerbuffer;
9818 
9819 				if ($rotate) {
9820 					$os .= ' Q' . "\n";
9821 				}
9822 
9823 				$os .= $this->StopTransform(true) . "\n";
9824 
9825 				// Writes over the page background but behind any other output on page
9826 				$os = preg_replace(['/\\\\/', '/\$/'], ['\\\\\\\\', '\\\\$'], $os);
9827 
9828 				$this->pages[$n] = preg_replace('/(___HEADER___MARKER' . $this->uniqstr . ')/', "\n" . $os . "\n" . '\\1', $this->pages[$n]);
9829 
9830 				$lks = $this->HTMLheaderPageLinks;
9831 
9832 				foreach ($lks as $lk) {
9833 
9834 					$lk[1] -= $adj * Mpdf::SCALE;
9835 
9836 					if ($rotate) {
9837 						$lw = $lk[2];
9838 						$lh = $lk[3];
9839 						$lk[2] = $lh;
9840 						$lk[3] = $lw; // swap width and height
9841 
9842 						$ax = $lk[0] / Mpdf::SCALE;
9843 						$ay = $lk[1] / Mpdf::SCALE;
9844 						$bx = $ay - ($lh / Mpdf::SCALE);
9845 						$by = $this->w - $ax;
9846 						$lk[0] = $bx * Mpdf::SCALE;
9847 						$lk[1] = ($this->h - $by) * Mpdf::SCALE - $lw;
9848 					}
9849 
9850 					$this->PageLinks[$n][] = $lk;
9851 				}
9852 
9853 				/* -- FORMS -- */
9854 				foreach ($this->HTMLheaderPageForms as $f) {
9855 					$f['y'] += $adj;
9856 					$this->form->forms[$f['n']] = $f;
9857 				}
9858 				/* -- END FORMS -- */
9859 			}
9860 
9861 			// Customization for https://github.com/mpdf/mpdf/issues/172
9862 			// Replace of page number aliases and date format
9863 			$this->pages[$n] = $this->aliasReplace($this->pages[$n], $pnstr, $pntstr, $nb);
9864 		}
9865 
9866 		$this->page = $nb;
9867 		$this->state = 1;
9868 	}
9869 
9870 	/* -- ANNOTATIONS -- */
9871 	function Annotation($text, $x = 0, $y = 0, $icon = 'Note', $author = '', $subject = '', $opacity = 0, $colarray = false, $popup = '', $file = '')
9872 	{
9873 		if (is_array($colarray) && count($colarray) == 3) {
9874 			$colarray = $this->colorConverter->convert('rgb(' . $colarray[0] . ',' . $colarray[1] . ',' . $colarray[2] . ')', $this->PDFAXwarnings);
9875 		}
9876 		if ($colarray === false) {
9877 			$colarray = $this->colorConverter->convert('yellow', $this->PDFAXwarnings);
9878 		}
9879 		if ($x == 0) {
9880 			$x = $this->x;
9881 		}
9882 		if ($y == 0) {
9883 			$y = $this->y;
9884 		}
9885 		$page = $this->page;
9886 		if ($page < 1) { // Document has not been started - assume it's for first page
9887 			$page = 1;
9888 			if ($x == 0) {
9889 				$x = $this->lMargin;
9890 			}
9891 			if ($y == 0) {
9892 				$y = $this->tMargin;
9893 			}
9894 		}
9895 
9896 		if ($this->PDFA || $this->PDFX) {
9897 			if (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto)) {
9898 				$this->PDFAXwarnings[] = "Annotation markers cannot be semi-transparent in PDFA1-b or PDFX/1-a, so they may make underlying text unreadable. (Annotation markers moved to right margin)";
9899 			}
9900 			$x = ($this->w) - $this->rMargin * 0.66;
9901 		}
9902 		if (!$this->annotMargin) {
9903 			$y -= $this->FontSize / 2;
9904 		}
9905 
9906 		if (!$opacity && $this->annotMargin) {
9907 			$opacity = 1;
9908 		} elseif (!$opacity) {
9909 			$opacity = $this->annotOpacity;
9910 		}
9911 
9912 		$an = ['txt' => $text, 'x' => $x, 'y' => $y, 'opt' => ['Icon' => $icon, 'T' => $author, 'Subj' => $subject, 'C' => $colarray, 'CA' => $opacity, 'popup' => $popup, 'file' => $file]];
9913 
9914 		if ($this->keep_block_together) { // don't write yet
9915 			return;
9916 		} elseif ($this->table_rotate) {
9917 			$this->tbrot_Annots[$this->page][] = $an;
9918 			return;
9919 		} elseif ($this->kwt) {
9920 			$this->kwt_Annots[$this->page][] = $an;
9921 			return;
9922 		}
9923 
9924 		if ($this->writingHTMLheader || $this->writingHTMLfooter) {
9925 			$this->HTMLheaderPageAnnots[] = $an;
9926 			return;
9927 		}
9928 
9929 		// Put an Annotation on the page
9930 		$this->PageAnnots[$page][] = $an;
9931 
9932 		/* -- COLUMNS -- */
9933 		// Save cross-reference to Column buffer
9934 		$ref = isset($this->PageAnnots[$this->page]) ? (count($this->PageAnnots[$this->page]) - 1) : -1;
9935 		$this->columnAnnots[$this->CurrCol][intval($this->x)][intval($this->y)] = $ref;
9936 		/* -- END COLUMNS -- */
9937 	}
9938 
9939 	/* -- END ANNOTATIONS -- */
9940 
9941 	function _enddoc()
9942 	{
9943 		// @log Writing Headers & Footers
9944 
9945 		$this->_puthtmlheaders();
9946 
9947 		// @log Writing Pages
9948 
9949 		// Remove references to unused fonts (usually default font)
9950 		foreach ($this->fonts as $fk => $font) {
9951 			if (isset($font['type']) && $font['type'] == 'TTF' && !$font['used']) {
9952 				if ($font['sip'] || $font['smp']) {
9953 					foreach ($font['subsetfontids'] as $k => $fid) {
9954 						foreach ($this->pages as $pn => $page) {
9955 							$this->pages[$pn] = preg_replace('/\s\/F' . $fid . ' \d[\d.]* Tf\s/is', ' ', $this->pages[$pn]);
9956 						}
9957 					}
9958 				} else {
9959 					foreach ($this->pages as $pn => $page) {
9960 						$this->pages[$pn] = preg_replace('/\s\/F' . $font['i'] . ' \d[\d.]* Tf\s/is', ' ', $this->pages[$pn]);
9961 					}
9962 				}
9963 			}
9964 		}
9965 
9966 		if (count($this->layers)) {
9967 			foreach ($this->pages as $pn => $page) {
9968 				preg_match_all('/\/OCZ-index \/ZI(\d+) BDC(.*?)(EMCZ)-index/is', $this->pages[$pn], $m1);
9969 				preg_match_all('/\/OCBZ-index \/ZI(\d+) BDC(.*?)(EMCBZ)-index/is', $this->pages[$pn], $m2);
9970 				preg_match_all('/\/OCGZ-index \/ZI(\d+) BDC(.*?)(EMCGZ)-index/is', $this->pages[$pn], $m3);
9971 				$m = [];
9972 				for ($i = 0; $i < 4; $i++) {
9973 					$m[$i] = array_merge($m1[$i], $m2[$i], $m3[$i]);
9974 				}
9975 				if (count($m[0])) {
9976 					$sortarr = [];
9977 					for ($i = 0; $i < count($m[0]); $i++) {
9978 						$key = $m[1][$i] * 2;
9979 						if ($m[3][$i] == 'EMCZ') {
9980 							$key +=2; // background first then gradient then normal
9981 						} elseif ($m[3][$i] == 'EMCGZ') {
9982 							$key +=1;
9983 						}
9984 						$sortarr[$i] = $key;
9985 					}
9986 					asort($sortarr);
9987 					foreach ($sortarr as $i => $k) {
9988 						$this->pages[$pn] = str_replace($m[0][$i], '', $this->pages[$pn]);
9989 						$this->pages[$pn] .= "\n" . $m[0][$i] . "\n";
9990 					}
9991 					$this->pages[$pn] = preg_replace('/\/OC[BG]{0,1}Z-index \/ZI(\d+) BDC/is', '/OC /ZI\\1 BDC ', $this->pages[$pn]);
9992 					$this->pages[$pn] = preg_replace('/EMC[BG]{0,1}Z-index/is', 'EMC', $this->pages[$pn]);
9993 				}
9994 			}
9995 		}
9996 
9997 		$this->pageWriter->writePages();
9998 
9999 		// @log Writing document resources
10000 
10001 		$this->resourceWriter->writeResources();
10002 
10003 		// Info
10004 		$this->writer->object();
10005 		$this->InfoRoot = $this->n;
10006 		$this->writer->write('<<');
10007 
10008 		// @log Writing document info
10009 		$this->metadataWriter->writeInfo();
10010 
10011 		$this->writer->write('>>');
10012 		$this->writer->write('endobj');
10013 
10014 		// METADATA
10015 		if ($this->PDFA || $this->PDFX) {
10016 			$this->metadataWriter->writeMetadata();
10017 		}
10018 
10019 		// OUTPUTINTENT
10020 		if ($this->PDFA || $this->PDFX || $this->ICCProfile) {
10021 			$this->metadataWriter->writeOutputIntent();
10022 		}
10023 
10024 		// Associated files
10025 		if ($this->associatedFiles) {
10026 			$this->metadataWriter->writeAssociatedFiles();
10027 		}
10028 
10029 		// Catalog
10030 		$this->writer->object();
10031 		$this->writer->write('<<');
10032 
10033 		// @log Writing document catalog
10034 
10035 		$this->metadataWriter->writeCatalog();
10036 
10037 		$this->writer->write('>>');
10038 		$this->writer->write('endobj');
10039 
10040 		// Cross-ref
10041 		$o = strlen($this->buffer);
10042 		$this->writer->write('xref');
10043 		$this->writer->write('0 ' . ($this->n + 1));
10044 		$this->writer->write('0000000000 65535 f ');
10045 
10046 		for ($i = 1; $i <= $this->n; $i++) {
10047 			$this->writer->write(sprintf('%010d 00000 n ', $this->offsets[$i]));
10048 		}
10049 
10050 		// Trailer
10051 		$this->writer->write('trailer');
10052 		$this->writer->write('<<');
10053 
10054 		$this->metadataWriter->writeTrailer();
10055 
10056 		$this->writer->write('>>');
10057 		$this->writer->write('startxref');
10058 		$this->writer->write($o);
10059 
10060 		$this->buffer .= '%%EOF';
10061 		$this->state = 3;
10062 	}
10063 
10064 	function _beginpage(
10065 		$orientation,
10066 		$mgl = '',
10067 		$mgr = '',
10068 		$mgt = '',
10069 		$mgb = '',
10070 		$mgh = '',
10071 		$mgf = '',
10072 		$ohname = '',
10073 		$ehname = '',
10074 		$ofname = '',
10075 		$efname = '',
10076 		$ohvalue = 0,
10077 		$ehvalue = 0,
10078 		$ofvalue = 0,
10079 		$efvalue = 0,
10080 		$pagesel = '',
10081 		$newformat = ''
10082 	) {
10083 		if (!($pagesel && $this->page == 1 && (sprintf("%0.4f", $this->y) == sprintf("%0.4f", $this->tMargin)))) {
10084 			$this->page++;
10085 			$this->pages[$this->page] = '';
10086 		}
10087 		$this->state = 2;
10088 		$resetHTMLHeadersrequired = false;
10089 
10090 		if ($newformat) {
10091 			$this->_setPageSize($newformat, $orientation);
10092 		}
10093 
10094 		/* -- CSS-PAGE -- */
10095 		// Paged media (page-box)
10096 		if ($pagesel || (isset($this->page_box['using']) && $this->page_box['using'])) {
10097 
10098 			if ($pagesel || $this->page == 1) {
10099 				$first = true;
10100 			} else {
10101 				$first = false;
10102 			}
10103 
10104 			if ($this->mirrorMargins && ($this->page % 2 == 0)) {
10105 				$oddEven = 'E';
10106 			} else {
10107 				$oddEven = 'O';
10108 			}
10109 
10110 			if ($pagesel) {
10111 				$psel = $pagesel;
10112 			} elseif ($this->page_box['current']) {
10113 				$psel = $this->page_box['current'];
10114 			} else {
10115 				$psel = '';
10116 			}
10117 
10118 			list($orientation, $mgl, $mgr, $mgt, $mgb, $mgh, $mgf, $hname, $fname, $bg, $resetpagenum, $pagenumstyle, $suppress, $marks, $newformat) = $this->SetPagedMediaCSS($psel, $first, $oddEven);
10119 
10120 			if ($this->mirrorMargins && ($this->page % 2 == 0)) {
10121 
10122 				if ($hname) {
10123 					$ehvalue = 1;
10124 					$ehname = $hname;
10125 				} else {
10126 					$ehvalue = -1;
10127 				}
10128 
10129 				if ($fname) {
10130 					$efvalue = 1;
10131 					$efname = $fname;
10132 				} else {
10133 					$efvalue = -1;
10134 				}
10135 
10136 			} else {
10137 
10138 				if ($hname) {
10139 					$ohvalue = 1;
10140 					$ohname = $hname;
10141 				} else {
10142 					$ohvalue = -1;
10143 				}
10144 
10145 				if ($fname) {
10146 					$ofvalue = 1;
10147 					$ofname = $fname;
10148 				} else {
10149 					$ofvalue = -1;
10150 				}
10151 			}
10152 
10153 			if ($resetpagenum || $pagenumstyle || $suppress) {
10154 				$this->PageNumSubstitutions[] = ['from' => ($this->page), 'reset' => $resetpagenum, 'type' => $pagenumstyle, 'suppress' => $suppress];
10155 			}
10156 
10157 			// PAGED MEDIA - CROP / CROSS MARKS from @PAGE
10158 			$this->show_marks = $marks;
10159 
10160 			// Background color
10161 			if (isset($bg['BACKGROUND-COLOR'])) {
10162 				$cor = $this->colorConverter->convert($bg['BACKGROUND-COLOR'], $this->PDFAXwarnings);
10163 				if ($cor) {
10164 					$this->bodyBackgroundColor = $cor;
10165 				}
10166 			} else {
10167 				$this->bodyBackgroundColor = false;
10168 			}
10169 
10170 			/* -- BACKGROUNDS -- */
10171 			if (isset($bg['BACKGROUND-GRADIENT'])) {
10172 				$this->bodyBackgroundGradient = $bg['BACKGROUND-GRADIENT'];
10173 			} else {
10174 				$this->bodyBackgroundGradient = false;
10175 			}
10176 
10177 			// Tiling Patterns
10178 			if (isset($bg['BACKGROUND-IMAGE']) && $bg['BACKGROUND-IMAGE']) {
10179 				$ret = $this->SetBackground($bg, $this->pgwidth);
10180 				if ($ret) {
10181 					$this->bodyBackgroundImage = $ret;
10182 				}
10183 			} else {
10184 				$this->bodyBackgroundImage = false;
10185 			}
10186 			/* -- END BACKGROUNDS -- */
10187 
10188 			$this->page_box['current'] = $psel;
10189 			$this->page_box['using'] = true;
10190 		}
10191 		/* -- END CSS-PAGE -- */
10192 
10193 		// Page orientation
10194 		if (!$orientation) {
10195 			$orientation = $this->DefOrientation;
10196 		} else {
10197 			$orientation = strtoupper(substr($orientation, 0, 1));
10198 			if ($orientation != $this->DefOrientation) {
10199 				$this->OrientationChanges[$this->page] = true;
10200 			}
10201 		}
10202 
10203 		if ($orientation != $this->CurOrientation || $newformat) {
10204 
10205 			// Change orientation
10206 			if ($orientation == 'P') {
10207 				$this->wPt = $this->fwPt;
10208 				$this->hPt = $this->fhPt;
10209 				$this->w = $this->fw;
10210 				$this->h = $this->fh;
10211 				if (($this->forcePortraitHeaders || $this->forcePortraitMargins) && $this->DefOrientation == 'P') {
10212 					$this->tMargin = $this->orig_tMargin;
10213 					$this->bMargin = $this->orig_bMargin;
10214 					$this->DeflMargin = $this->orig_lMargin;
10215 					$this->DefrMargin = $this->orig_rMargin;
10216 					$this->margin_header = $this->orig_hMargin;
10217 					$this->margin_footer = $this->orig_fMargin;
10218 				} else {
10219 					$resetHTMLHeadersrequired = true;
10220 				}
10221 			} else {
10222 				$this->wPt = $this->fhPt;
10223 				$this->hPt = $this->fwPt;
10224 				$this->w = $this->fh;
10225 				$this->h = $this->fw;
10226 
10227 				if (($this->forcePortraitHeaders || $this->forcePortraitMargins) && $this->DefOrientation == 'P') {
10228 					$this->tMargin = $this->orig_lMargin;
10229 					$this->bMargin = $this->orig_rMargin;
10230 					$this->DeflMargin = $this->orig_bMargin;
10231 					$this->DefrMargin = $this->orig_tMargin;
10232 					$this->margin_header = $this->orig_hMargin;
10233 					$this->margin_footer = $this->orig_fMargin;
10234 				} else {
10235 					$resetHTMLHeadersrequired = true;
10236 				}
10237 			}
10238 
10239 			$this->CurOrientation = $orientation;
10240 			$this->ResetMargins();
10241 			$this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
10242 			$this->PageBreakTrigger = $this->h - $this->bMargin;
10243 		}
10244 
10245 		$this->pageDim[$this->page]['w'] = $this->w;
10246 		$this->pageDim[$this->page]['h'] = $this->h;
10247 
10248 		$this->pageDim[$this->page]['outer_width_LR'] = isset($this->page_box['outer_width_LR']) ? $this->page_box['outer_width_LR'] : 0;
10249 		$this->pageDim[$this->page]['outer_width_TB'] = isset($this->page_box['outer_width_TB']) ? $this->page_box['outer_width_TB'] : 0;
10250 
10251 		if (!isset($this->page_box['outer_width_LR']) && !isset($this->page_box['outer_width_TB'])) {
10252 			$this->pageDim[$this->page]['bleedMargin'] = 0;
10253 		} elseif ($this->bleedMargin <= $this->page_box['outer_width_LR'] && $this->bleedMargin <= $this->page_box['outer_width_TB']) {
10254 			$this->pageDim[$this->page]['bleedMargin'] = $this->bleedMargin;
10255 		} else {
10256 			$this->pageDim[$this->page]['bleedMargin'] = min($this->page_box['outer_width_LR'], $this->page_box['outer_width_TB']) - 0.01;
10257 		}
10258 
10259 		// If Page Margins are re-defined
10260 		// strlen()>0 is used to pick up (integer) 0, (string) '0', or set value
10261 		if ((strlen($mgl) > 0 && $this->DeflMargin != $mgl) || (strlen($mgr) > 0 && $this->DefrMargin != $mgr) || (strlen($mgt) > 0 && $this->tMargin != $mgt) || (strlen($mgb) > 0 && $this->bMargin != $mgb) || (strlen($mgh) > 0 && $this->margin_header != $mgh) || (strlen($mgf) > 0 && $this->margin_footer != $mgf)) {
10262 
10263 			if (strlen($mgl) > 0) {
10264 				$this->DeflMargin = $mgl;
10265 			}
10266 
10267 			if (strlen($mgr) > 0) {
10268 				$this->DefrMargin = $mgr;
10269 			}
10270 
10271 			if (strlen($mgt) > 0) {
10272 				$this->tMargin = $mgt;
10273 			}
10274 
10275 			if (strlen($mgb) > 0) {
10276 				$this->bMargin = $mgb;
10277 			}
10278 
10279 			if (strlen($mgh) > 0) {
10280 				$this->margin_header = $mgh;
10281 			}
10282 
10283 			if (strlen($mgf) > 0) {
10284 				$this->margin_footer = $mgf;
10285 			}
10286 
10287 			$this->ResetMargins();
10288 			$this->SetAutoPageBreak($this->autoPageBreak, $this->bMargin);
10289 
10290 			$this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
10291 			$resetHTMLHeadersrequired = true;
10292 		}
10293 
10294 		$this->ResetMargins();
10295 		$this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
10296 		$this->SetAutoPageBreak($this->autoPageBreak, $this->bMargin);
10297 
10298 		// Reset column top margin
10299 		$this->y0 = $this->tMargin;
10300 
10301 		$this->x = $this->lMargin;
10302 		$this->y = $this->tMargin;
10303 		$this->FontFamily = '';
10304 
10305 		// HEADERS AND FOOTERS	// mPDF 6
10306 		if ($ohvalue < 0 || strtoupper($ohvalue) == 'OFF') {
10307 			$this->HTMLHeader = '';
10308 			$resetHTMLHeadersrequired = true;
10309 		} elseif ($ohname && $ohvalue > 0) {
10310 			if (preg_match('/^html_(.*)$/i', $ohname, $n)) {
10311 				$name = $n[1];
10312 			} else {
10313 				$name = $ohname;
10314 			}
10315 			if (isset($this->pageHTMLheaders[$name])) {
10316 				$this->HTMLHeader = $this->pageHTMLheaders[$name];
10317 			} else {
10318 				$this->HTMLHeader = '';
10319 			}
10320 			$resetHTMLHeadersrequired = true;
10321 		}
10322 
10323 		if ($ehvalue < 0 || strtoupper($ehvalue) == 'OFF') {
10324 			$this->HTMLHeaderE = '';
10325 			$resetHTMLHeadersrequired = true;
10326 		} elseif ($ehname && $ehvalue > 0) {
10327 			if (preg_match('/^html_(.*)$/i', $ehname, $n)) {
10328 				$name = $n[1];
10329 			} else {
10330 				$name = $ehname;
10331 			}
10332 			if (isset($this->pageHTMLheaders[$name])) {
10333 				$this->HTMLHeaderE = $this->pageHTMLheaders[$name];
10334 			} else {
10335 				$this->HTMLHeaderE = '';
10336 			}
10337 			$resetHTMLHeadersrequired = true;
10338 		}
10339 
10340 		if ($ofvalue < 0 || strtoupper($ofvalue) == 'OFF') {
10341 			$this->HTMLFooter = '';
10342 			$resetHTMLHeadersrequired = true;
10343 		} elseif ($ofname && $ofvalue > 0) {
10344 			if (preg_match('/^html_(.*)$/i', $ofname, $n)) {
10345 				$name = $n[1];
10346 			} else {
10347 				$name = $ofname;
10348 			}
10349 			if (isset($this->pageHTMLfooters[$name])) {
10350 				$this->HTMLFooter = $this->pageHTMLfooters[$name];
10351 			} else {
10352 				$this->HTMLFooter = '';
10353 			}
10354 			$resetHTMLHeadersrequired = true;
10355 		}
10356 
10357 		if ($efvalue < 0 || strtoupper($efvalue) == 'OFF') {
10358 			$this->HTMLFooterE = '';
10359 			$resetHTMLHeadersrequired = true;
10360 		} elseif ($efname && $efvalue > 0) {
10361 			if (preg_match('/^html_(.*)$/i', $efname, $n)) {
10362 				$name = $n[1];
10363 			} else {
10364 				$name = $efname;
10365 			}
10366 			if (isset($this->pageHTMLfooters[$name])) {
10367 				$this->HTMLFooterE = $this->pageHTMLfooters[$name];
10368 			} else {
10369 				$this->HTMLFooterE = '';
10370 			}
10371 			$resetHTMLHeadersrequired = true;
10372 		}
10373 
10374 		if ($resetHTMLHeadersrequired) {
10375 			$this->SetHTMLHeader($this->HTMLHeader);
10376 			$this->SetHTMLHeader($this->HTMLHeaderE, 'E');
10377 			$this->SetHTMLFooter($this->HTMLFooter);
10378 			$this->SetHTMLFooter($this->HTMLFooterE, 'E');
10379 		}
10380 
10381 
10382 		if (($this->mirrorMargins) && (($this->page) % 2 == 0)) { // EVEN
10383 			$this->_setAutoHeaderHeight($this->HTMLHeaderE);
10384 			$this->_setAutoFooterHeight($this->HTMLFooterE);
10385 		} else { // ODD or DEFAULT
10386 			$this->_setAutoHeaderHeight($this->HTMLHeader);
10387 			$this->_setAutoFooterHeight($this->HTMLFooter);
10388 		}
10389 
10390 		// Reset column top margin
10391 		$this->y0 = $this->tMargin;
10392 
10393 		$this->x = $this->lMargin;
10394 		$this->y = $this->tMargin;
10395 	}
10396 
10397 	// mPDF 6
10398 	function _setAutoHeaderHeight(&$htmlh)
10399 	{
10400 		/* When the setAutoTopMargin option is set to pad/stretch, only apply auto header height when a header exists */
10401 		if ($this->HTMLHeader === '' && $this->HTMLHeaderE === '') {
10402 			return;
10403 		}
10404 
10405 		if ($this->setAutoTopMargin == 'pad') {
10406 			if (isset($htmlh['h']) && $htmlh['h']) {
10407 				$h = $htmlh['h'];
10408 			} // 5.7.3
10409 			else {
10410 				$h = 0;
10411 			}
10412 			$this->tMargin = $this->margin_header + $h + $this->orig_tMargin;
10413 		} elseif ($this->setAutoTopMargin == 'stretch') {
10414 			if (isset($htmlh['h']) && $htmlh['h']) {
10415 				$h = $htmlh['h'];
10416 			} // 5.7.3
10417 			else {
10418 				$h = 0;
10419 			}
10420 			$this->tMargin = max($this->orig_tMargin, $this->margin_header + $h + $this->autoMarginPadding);
10421 		}
10422 	}
10423 
10424 	// mPDF 6
10425 	function _setAutoFooterHeight(&$htmlf)
10426 	{
10427 		/* When the setAutoTopMargin option is set to pad/stretch, only apply auto footer height when a footer exists */
10428 		if ($this->HTMLFooter === '' && $this->HTMLFooterE === '') {
10429 			return;
10430 		}
10431 
10432 		if ($this->setAutoBottomMargin == 'pad') {
10433 			if (isset($htmlf['h']) && $htmlf['h']) {
10434 				$h = $htmlf['h'];
10435 			} // 5.7.3
10436 			else {
10437 				$h = 0;
10438 			}
10439 			$this->bMargin = $this->margin_footer + $h + $this->orig_bMargin;
10440 			$this->PageBreakTrigger = $this->h - $this->bMargin;
10441 		} elseif ($this->setAutoBottomMargin == 'stretch') {
10442 			if (isset($htmlf['h']) && $htmlf['h']) {
10443 				$h = $htmlf['h'];
10444 			} // 5.7.3
10445 			else {
10446 				$h = 0;
10447 			}
10448 			$this->bMargin = max($this->orig_bMargin, $this->margin_footer + $h + $this->autoMarginPadding);
10449 			$this->PageBreakTrigger = $this->h - $this->bMargin;
10450 		}
10451 	}
10452 
10453 	function _endpage()
10454 	{
10455 		/* -- CSS-IMAGE-FLOAT -- */
10456 		$this->printfloatbuffer();
10457 		/* -- END CSS-IMAGE-FLOAT -- */
10458 
10459 		if ($this->visibility != 'visible') {
10460 			$this->SetVisibility('visible');
10461 		}
10462 		$this->EndLayer();
10463 		// End of page contents
10464 		$this->state = 1;
10465 	}
10466 
10467 	function _dounderline($x, $y, $txt, $OTLdata = false, $textvar = 0)
10468 	{
10469 		// Now print line exactly where $y secifies - called from Text() and Cell() - adjust  position there
10470 		// WORD SPACING
10471 		$w = ($this->GetStringWidth($txt, false, $OTLdata, $textvar) * Mpdf::SCALE) + ($this->charspacing * mb_strlen($txt, $this->mb_enc)) + ( $this->ws * mb_substr_count($txt, ' ', $this->mb_enc));
10472 		// Draw a line
10473 		return sprintf('%.3F %.3F m %.3F %.3F l S', $x * Mpdf::SCALE, ($this->h - $y) * Mpdf::SCALE, ($x * Mpdf::SCALE) + $w, ($this->h - $y) * Mpdf::SCALE);
10474 	}
10475 
10476 
10477 
10478 	/* -- WATERMARK -- */
10479 
10480 	// add a watermark
10481 	function watermark($texte, $angle = 45, $fontsize = 96, $alpha = 0.2)
10482 	{
10483 		if ($this->PDFA || $this->PDFX) {
10484 			throw new \Mpdf\MpdfException('PDFA and PDFX do not permit transparency, so mPDF does not allow Watermarks!');
10485 		}
10486 
10487 		if (!$this->watermark_font) {
10488 			$this->watermark_font = $this->default_font;
10489 		}
10490 
10491 		$this->SetFont($this->watermark_font, "B", $fontsize, false); // Don't output
10492 		$texte = $this->purify_utf8_text($texte);
10493 
10494 		if ($this->text_input_as_HTML) {
10495 			$texte = $this->all_entities_to_utf8($texte);
10496 		}
10497 
10498 		if ($this->usingCoreFont) {
10499 			$texte = mb_convert_encoding($texte, $this->mb_enc, 'UTF-8');
10500 		}
10501 
10502 		// DIRECTIONALITY
10503 		if (preg_match("/([" . $this->pregRTLchars . "])/u", $texte)) {
10504 			$this->biDirectional = true;
10505 		} // *OTL*
10506 
10507 		$textvar = 0;
10508 		$save_OTLtags = $this->OTLtags;
10509 		$this->OTLtags = [];
10510 		if ($this->useKerning) {
10511 			if ($this->CurrentFont['haskernGPOS']) {
10512 				$this->OTLtags['Plus'] .= ' kern';
10513 			} else {
10514 				$textvar = ($textvar | TextVars::FC_KERNING);
10515 			}
10516 		}
10517 
10518 		/* -- OTL -- */
10519 		// Use OTL OpenType Table Layout - GSUB & GPOS
10520 		if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
10521 			$texte = $this->otl->applyOTL($texte, $this->CurrentFont['useOTL']);
10522 			$OTLdata = $this->otl->OTLdata;
10523 		}
10524 		/* -- END OTL -- */
10525 		$this->OTLtags = $save_OTLtags;
10526 
10527 		$this->magic_reverse_dir($texte, $this->directionality, $OTLdata);
10528 
10529 		$this->SetAlpha($alpha);
10530 
10531 		$this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
10532 
10533 		$szfont = $fontsize;
10534 		$loop = 0;
10535 		$maxlen = (min($this->w, $this->h) ); // sets max length of text as 7/8 width/height of page
10536 
10537 		while ($loop == 0) {
10538 			$this->SetFont($this->watermark_font, "B", $szfont, false); // Don't output
10539 			$offset = ((sin(deg2rad($angle))) * ($szfont / Mpdf::SCALE));
10540 
10541 			$strlen = $this->GetStringWidth($texte, true, $OTLdata, $textvar);
10542 			if ($strlen > $maxlen - $offset) {
10543 				$szfont --;
10544 			} else {
10545 				$loop ++;
10546 			}
10547 		}
10548 
10549 		$this->SetFont($this->watermark_font, "B", $szfont - 0.1, true, true); // Output The -0.1 is because SetFont above is not written to PDF
10550 
10551 		// Repeating it will not output anything as mPDF thinks it is set
10552 		$adj = ((cos(deg2rad($angle))) * ($strlen / 2));
10553 		$opp = ((sin(deg2rad($angle))) * ($strlen / 2));
10554 
10555 		$wx = ($this->w / 2) - $adj + $offset / 3;
10556 		$wy = ($this->h / 2) + $opp;
10557 
10558 		$this->Rotate($angle, $wx, $wy);
10559 		$this->Text($wx, $wy, $texte, $OTLdata, $textvar);
10560 		$this->Rotate(0);
10561 		$this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
10562 
10563 		$this->SetAlpha(1);
10564 	}
10565 
10566 	function watermarkImg($src, $alpha = 0.2)
10567 	{
10568 		if ($this->PDFA || $this->PDFX) {
10569 			throw new \Mpdf\MpdfException('PDFA and PDFX do not permit transparency, so mPDF does not allow Watermarks!');
10570 		}
10571 
10572 		if ($this->watermarkImgBehind) {
10573 			$this->watermarkImgAlpha = $this->SetAlpha($alpha, 'Normal', true);
10574 		} else {
10575 			$this->SetAlpha($alpha, $this->watermarkImgAlphaBlend);
10576 		}
10577 
10578 		$this->Image($src, 0, 0, 0, 0, '', '', true, true, true);
10579 
10580 		if (!$this->watermarkImgBehind) {
10581 			$this->SetAlpha(1);
10582 		}
10583 	}
10584 
10585 	/* -- END WATERMARK -- */
10586 
10587 	function Rotate($angle, $x = -1, $y = -1)
10588 	{
10589 		if ($x == -1) {
10590 			$x = $this->x;
10591 		}
10592 		if ($y == -1) {
10593 			$y = $this->y;
10594 		}
10595 		if ($this->angle != 0) {
10596 			$this->writer->write('Q');
10597 		}
10598 		$this->angle = $angle;
10599 		if ($angle != 0) {
10600 			$angle*=M_PI / 180;
10601 			$c = cos($angle);
10602 			$s = sin($angle);
10603 			$cx = $x * Mpdf::SCALE;
10604 			$cy = ($this->h - $y) * Mpdf::SCALE;
10605 			$this->writer->write(sprintf('q %.5F %.5F %.5F %.5F %.3F %.3F cm 1 0 0 1 %.3F %.3F cm', $c, $s, -$s, $c, $cx, $cy, -$cx, -$cy));
10606 		}
10607 	}
10608 
10609 	function CircularText($x, $y, $r, $text, $align = 'top', $fontfamily = '', $fontsize = 0, $fontstyle = '', $kerning = 120, $fontwidth = 100, $divider = '')
10610 	{
10611 		if (empty($this->directWrite)) {
10612 			$this->directWrite = new DirectWrite($this, $this->otl, $this->sizeConverter, $this->colorConverter);
10613 		}
10614 
10615 		$this->directWrite->CircularText($x, $y, $r, $text, $align, $fontfamily, $fontsize, $fontstyle, $kerning, $fontwidth, $divider);
10616 	}
10617 
10618 	// From Invoice
10619 	function RoundedRect($x, $y, $w, $h, $r, $style = '')
10620 	{
10621 		$hp = $this->h;
10622 
10623 		if ($style == 'F') {
10624 			$op = 'f';
10625 		} elseif ($style == 'FD' or $style == 'DF') {
10626 			$op = 'B';
10627 		} else {
10628 			$op = 'S';
10629 		}
10630 
10631 		$MyArc = 4 / 3 * (sqrt(2) - 1);
10632 		$this->writer->write(sprintf('%.3F %.3F m', ($x + $r) * Mpdf::SCALE, ($hp - $y) * Mpdf::SCALE));
10633 		$xc = $x + $w - $r;
10634 		$yc = $y + $r;
10635 		$this->writer->write(sprintf('%.3F %.3F l', $xc * Mpdf::SCALE, ($hp - $y) * Mpdf::SCALE));
10636 
10637 		$this->_Arc($xc + $r * $MyArc, $yc - $r, $xc + $r, $yc - $r * $MyArc, $xc + $r, $yc);
10638 		$xc = $x + $w - $r;
10639 		$yc = $y + $h - $r;
10640 		$this->writer->write(sprintf('%.3F %.3F l', ($x + $w) * Mpdf::SCALE, ($hp - $yc) * Mpdf::SCALE));
10641 
10642 		$this->_Arc($xc + $r, $yc + $r * $MyArc, $xc + $r * $MyArc, $yc + $r, $xc, $yc + $r);
10643 		$xc = $x + $r;
10644 		$yc = $y + $h - $r;
10645 		$this->writer->write(sprintf('%.3F %.3F l', $xc * Mpdf::SCALE, ($hp - ($y + $h)) * Mpdf::SCALE));
10646 
10647 		$this->_Arc($xc - $r * $MyArc, $yc + $r, $xc - $r, $yc + $r * $MyArc, $xc - $r, $yc);
10648 		$xc = $x + $r;
10649 		$yc = $y + $r;
10650 		$this->writer->write(sprintf('%.3F %.3F l', ($x) * Mpdf::SCALE, ($hp - $yc) * Mpdf::SCALE));
10651 
10652 		$this->_Arc($xc - $r, $yc - $r * $MyArc, $xc - $r * $MyArc, $yc - $r, $xc, $yc - $r);
10653 		$this->writer->write($op);
10654 	}
10655 
10656 	function _Arc($x1, $y1, $x2, $y2, $x3, $y3)
10657 	{
10658 		$h = $this->h;
10659 		$this->writer->write(sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', $x1 * Mpdf::SCALE, ($h - $y1) * Mpdf::SCALE, $x2 * Mpdf::SCALE, ($h - $y2) * Mpdf::SCALE, $x3 * Mpdf::SCALE, ($h - $y3) * Mpdf::SCALE));
10660 	}
10661 
10662 	// ====================================================
10663 
10664 
10665 
10666 	/* -- DIRECTW -- */
10667 	function Shaded_box($text, $font = '', $fontstyle = 'B', $szfont = '', $width = '70%', $style = 'DF', $radius = 2.5, $fill = '#FFFFFF', $color = '#000000', $pad = 2)
10668 	{
10669 		// F (shading - no line),S (line, no shading),DF (both)
10670 		if (empty($this->directWrite)) {
10671 			$this->directWrite = new DirectWrite($this, $this->otl, $this->sizeConverter, $this->colorConverter);
10672 		}
10673 		$this->directWrite->Shaded_box($text, $font, $fontstyle, $szfont, $width, $style, $radius, $fill, $color, $pad);
10674 	}
10675 
10676 	/* -- END DIRECTW -- */
10677 
10678 	function UTF8StringToArray($str, $addSubset = true)
10679 	{
10680 		$out = [];
10681 		$len = strlen($str);
10682 		for ($i = 0; $i < $len; $i++) {
10683 			$uni = -1;
10684 			$h = ord($str[$i]);
10685 			if ($h <= 0x7F) {
10686 				$uni = $h;
10687 			} elseif ($h >= 0xC2) {
10688 				if (($h <= 0xDF) && ($i < $len - 1)) {
10689 					$uni = ($h & 0x1F) << 6 | (ord($str[++$i]) & 0x3F);
10690 				} elseif (($h <= 0xEF) && ($i < $len - 2)) {
10691 					$uni = ($h & 0x0F) << 12 | (ord($str[++$i]) & 0x3F) << 6 | (ord($str[++$i]) & 0x3F);
10692 				} elseif (($h <= 0xF4) && ($i < $len - 3)) {
10693 					$uni = ($h & 0x0F) << 18 | (ord($str[++$i]) & 0x3F) << 12 | (ord($str[++$i]) & 0x3F) << 6 | (ord($str[++$i]) & 0x3F);
10694 				}
10695 			}
10696 			if ($uni >= 0) {
10697 				$out[] = $uni;
10698 				if ($addSubset && isset($this->CurrentFont['subset'])) {
10699 					$this->CurrentFont['subset'][$uni] = $uni;
10700 				}
10701 			}
10702 		}
10703 		return $out;
10704 	}
10705 
10706 	// Convert utf-8 string to <HHHHHH> for Font Subsets
10707 	function UTF8toSubset($str)
10708 	{
10709 		$ret = '<';
10710 		// $str = preg_replace('/'.preg_quote($this->aliasNbPg,'/').'/', chr(7), $str );	// mPDF 6 deleted
10711 		// $str = preg_replace('/'.preg_quote($this->aliasNbPgGp,'/').'/', chr(8), $str );	// mPDF 6 deleted
10712 		$unicode = $this->UTF8StringToArray($str);
10713 		$orig_fid = $this->CurrentFont['subsetfontids'][0];
10714 		$last_fid = $this->CurrentFont['subsetfontids'][0];
10715 		foreach ($unicode as $c) {
10716 			/* 	// mPDF 6 deleted
10717 			  if ($c == 7 || $c == 8) {
10718 			  if ($orig_fid != $last_fid) {
10719 			  $ret .= '> Tj /F'.$orig_fid.' '.$this->FontSizePt.' Tf <';
10720 			  $last_fid = $orig_fid;
10721 			  }
10722 			  if ($c == 7) { $ret .= $this->aliasNbPgHex; }
10723 			  else { $ret .= $this->aliasNbPgGpHex; }
10724 			  continue;
10725 			  }
10726 			 */
10727 			if (!$this->_charDefined($this->CurrentFont['cw'], $c)) {
10728 				$c = 0;
10729 			} // mPDF 6
10730 			for ($i = 0; $i < 99; $i++) {
10731 				// return c as decimal char
10732 				$init = array_search($c, $this->CurrentFont['subsets'][$i]);
10733 				if ($init !== false) {
10734 					if ($this->CurrentFont['subsetfontids'][$i] != $last_fid) {
10735 						$ret .= '> Tj /F' . $this->CurrentFont['subsetfontids'][$i] . ' ' . $this->FontSizePt . ' Tf <';
10736 						$last_fid = $this->CurrentFont['subsetfontids'][$i];
10737 					}
10738 					$ret .= sprintf("%02s", strtoupper(dechex($init)));
10739 					break;
10740 				} // TrueType embedded SUBSETS
10741 				elseif (count($this->CurrentFont['subsets'][$i]) < 255) {
10742 					$n = count($this->CurrentFont['subsets'][$i]);
10743 					$this->CurrentFont['subsets'][$i][$n] = $c;
10744 					if ($this->CurrentFont['subsetfontids'][$i] != $last_fid) {
10745 						$ret .= '> Tj /F' . $this->CurrentFont['subsetfontids'][$i] . ' ' . $this->FontSizePt . ' Tf <';
10746 						$last_fid = $this->CurrentFont['subsetfontids'][$i];
10747 					}
10748 					$ret .= sprintf("%02s", strtoupper(dechex($n)));
10749 					break;
10750 				} elseif (!isset($this->CurrentFont['subsets'][($i + 1)])) {
10751 					// TrueType embedded SUBSETS
10752 					$this->CurrentFont['subsets'][($i + 1)] = [0 => 0];
10753 					$new_fid = count($this->fonts) + $this->extraFontSubsets + 1;
10754 					$this->CurrentFont['subsetfontids'][($i + 1)] = $new_fid;
10755 					$this->extraFontSubsets++;
10756 				}
10757 			}
10758 		}
10759 		$ret .= '>';
10760 		if ($last_fid != $orig_fid) {
10761 			$ret .= ' Tj /F' . $orig_fid . ' ' . $this->FontSizePt . ' Tf <> ';
10762 		}
10763 		return $ret;
10764 	}
10765 
10766 	/* -- CJK-FONTS -- */
10767 
10768 	// from class PDF_Chinese CJK EXTENSIONS
10769 	function AddCIDFont($family, $style, $name, &$cw, $CMap, $registry, $desc)
10770 	{
10771 		$fontkey = strtolower($family) . strtoupper($style);
10772 		if (isset($this->fonts[$fontkey])) {
10773 			throw new \Mpdf\MpdfException("Font already added: $family $style");
10774 		}
10775 		$i = count($this->fonts) + $this->extraFontSubsets + 1;
10776 		$name = str_replace(' ', '', $name);
10777 		if ($family == 'sjis') {
10778 			$up = -120;
10779 		} else {
10780 			$up = -130;
10781 		}
10782 		// ? 'up' and 'ut' do not seem to be referenced anywhere
10783 		$this->fonts[$fontkey] = ['i' => $i, 'type' => 'Type0', 'name' => $name, 'up' => $up, 'ut' => 40, 'cw' => $cw, 'CMap' => $CMap, 'registry' => $registry, 'MissingWidth' => 1000, 'desc' => $desc];
10784 	}
10785 
10786 	function AddCJKFont($family)
10787 	{
10788 
10789 		if ($this->PDFA || $this->PDFX) {
10790 			throw new \Mpdf\MpdfException("Adobe CJK fonts cannot be embedded in mPDF (required for PDFA1-b and PDFX/1-a).");
10791 		}
10792 		if ($family == 'big5') {
10793 			$this->AddBig5Font();
10794 		} elseif ($family == 'gb') {
10795 			$this->AddGBFont();
10796 		} elseif ($family == 'sjis') {
10797 			$this->AddSJISFont();
10798 		} elseif ($family == 'uhc') {
10799 			$this->AddUHCFont();
10800 		}
10801 	}
10802 
10803 	function AddBig5Font()
10804 	{
10805 		// Add Big5 font with proportional Latin
10806 		$family = 'big5';
10807 		$name = 'MSungStd-Light-Acro';
10808 		$cw = $this->Big5_widths;
10809 		$CMap = 'UniCNS-UTF16-H';
10810 		$registry = ['ordering' => 'CNS1', 'supplement' => 4];
10811 		$desc = [
10812 			'Ascent' => 880,
10813 			'Descent' => -120,
10814 			'CapHeight' => 880,
10815 			'Flags' => 6,
10816 			'FontBBox' => '[-160 -249 1015 1071]',
10817 			'ItalicAngle' => 0,
10818 			'StemV' => 93,
10819 		];
10820 		$this->AddCIDFont($family, '', $name, $cw, $CMap, $registry, $desc);
10821 		$this->AddCIDFont($family, 'B', $name . ',Bold', $cw, $CMap, $registry, $desc);
10822 		$this->AddCIDFont($family, 'I', $name . ',Italic', $cw, $CMap, $registry, $desc);
10823 		$this->AddCIDFont($family, 'BI', $name . ',BoldItalic', $cw, $CMap, $registry, $desc);
10824 	}
10825 
10826 	function AddGBFont()
10827 	{
10828 		// Add GB font with proportional Latin
10829 		$family = 'gb';
10830 		$name = 'STSongStd-Light-Acro';
10831 		$cw = $this->GB_widths;
10832 		$CMap = 'UniGB-UTF16-H';
10833 		$registry = ['ordering' => 'GB1', 'supplement' => 4];
10834 		$desc = [
10835 			'Ascent' => 880,
10836 			'Descent' => -120,
10837 			'CapHeight' => 737,
10838 			'Flags' => 6,
10839 			'FontBBox' => '[-25 -254 1000 880]',
10840 			'ItalicAngle' => 0,
10841 			'StemV' => 58,
10842 			'Style' => '<< /Panose <000000000400000000000000> >>',
10843 		];
10844 		$this->AddCIDFont($family, '', $name, $cw, $CMap, $registry, $desc);
10845 		$this->AddCIDFont($family, 'B', $name . ',Bold', $cw, $CMap, $registry, $desc);
10846 		$this->AddCIDFont($family, 'I', $name . ',Italic', $cw, $CMap, $registry, $desc);
10847 		$this->AddCIDFont($family, 'BI', $name . ',BoldItalic', $cw, $CMap, $registry, $desc);
10848 	}
10849 
10850 	function AddSJISFont()
10851 	{
10852 		// Add SJIS font with proportional Latin
10853 		$family = 'sjis';
10854 		$name = 'KozMinPro-Regular-Acro';
10855 		$cw = $this->SJIS_widths;
10856 		$CMap = 'UniJIS-UTF16-H';
10857 		$registry = ['ordering' => 'Japan1', 'supplement' => 5];
10858 		$desc = [
10859 			'Ascent' => 880,
10860 			'Descent' => -120,
10861 			'CapHeight' => 740,
10862 			'Flags' => 6,
10863 			'FontBBox' => '[-195 -272 1110 1075]',
10864 			'ItalicAngle' => 0,
10865 			'StemV' => 86,
10866 			'XHeight' => 502,
10867 		];
10868 		$this->AddCIDFont($family, '', $name, $cw, $CMap, $registry, $desc);
10869 		$this->AddCIDFont($family, 'B', $name . ',Bold', $cw, $CMap, $registry, $desc);
10870 		$this->AddCIDFont($family, 'I', $name . ',Italic', $cw, $CMap, $registry, $desc);
10871 		$this->AddCIDFont($family, 'BI', $name . ',BoldItalic', $cw, $CMap, $registry, $desc);
10872 	}
10873 
10874 	function AddUHCFont()
10875 	{
10876 		// Add UHC font with proportional Latin
10877 		$family = 'uhc';
10878 		$name = 'HYSMyeongJoStd-Medium-Acro';
10879 		$cw = $this->UHC_widths;
10880 		$CMap = 'UniKS-UTF16-H';
10881 		$registry = ['ordering' => 'Korea1', 'supplement' => 2];
10882 		$desc = [
10883 			'Ascent' => 880,
10884 			'Descent' => -120,
10885 			'CapHeight' => 720,
10886 			'Flags' => 6,
10887 			'FontBBox' => '[-28 -148 1001 880]',
10888 			'ItalicAngle' => 0,
10889 			'StemV' => 60,
10890 			'Style' => '<< /Panose <000000000600000000000000> >>',
10891 		];
10892 		$this->AddCIDFont($family, '', $name, $cw, $CMap, $registry, $desc);
10893 		$this->AddCIDFont($family, 'B', $name . ',Bold', $cw, $CMap, $registry, $desc);
10894 		$this->AddCIDFont($family, 'I', $name . ',Italic', $cw, $CMap, $registry, $desc);
10895 		$this->AddCIDFont($family, 'BI', $name . ',BoldItalic', $cw, $CMap, $registry, $desc);
10896 	}
10897 
10898 	/* -- END CJK-FONTS -- */
10899 
10900 	//////////////////////////////////////////////////////////////////////////////
10901 	//////////////////////////////////////////////////////////////////////////////
10902 	//////////////////////////////////////////////////////////////////////////////
10903 	//////////////////////////////////////////////////////////////////////////////
10904 	//////////////////////////////////////////////////////////////////////////////
10905 	//////////////////////////////////////////////////////////////////////////////
10906 	//////////////////////////////////////////////////////////////////////////////
10907 
10908 	function SetDefaultFont($font)
10909 	{
10910 		// Disallow embedded fonts to be used as defaults in PDFA
10911 		if ($this->PDFA || $this->PDFX) {
10912 			if (strtolower($font) == 'ctimes') {
10913 				$font = 'serif';
10914 			}
10915 			if (strtolower($font) == 'ccourier') {
10916 				$font = 'monospace';
10917 			}
10918 			if (strtolower($font) == 'chelvetica') {
10919 				$font = 'sans-serif';
10920 			}
10921 		}
10922 		$font = $this->SetFont($font); // returns substituted font if necessary
10923 		$this->default_font = $font;
10924 		$this->original_default_font = $font;
10925 		if (!$this->watermark_font) {
10926 			$this->watermark_font = $font;
10927 		} // *WATERMARK*
10928 		$this->defaultCSS['BODY']['FONT-FAMILY'] = $font;
10929 		$this->cssManager->CSS['BODY']['FONT-FAMILY'] = $font;
10930 	}
10931 
10932 	function SetDefaultFontSize($fontsize)
10933 	{
10934 		$this->default_font_size = $fontsize;
10935 		$this->original_default_font_size = $fontsize;
10936 		$this->SetFontSize($fontsize);
10937 		$this->defaultCSS['BODY']['FONT-SIZE'] = $fontsize . 'pt';
10938 		$this->cssManager->CSS['BODY']['FONT-SIZE'] = $fontsize . 'pt';
10939 	}
10940 
10941 	function SetDefaultBodyCSS($prop, $val)
10942 	{
10943 		if ($prop) {
10944 			$this->defaultCSS['BODY'][strtoupper($prop)] = $val;
10945 			$this->cssManager->CSS['BODY'][strtoupper($prop)] = $val;
10946 		}
10947 	}
10948 
10949 	function SetDirectionality($dir = 'ltr')
10950 	{
10951 		/* -- OTL -- */
10952 		if (strtolower($dir) == 'rtl') {
10953 			if ($this->directionality != 'rtl') {
10954 				// Swop L/R Margins so page 1 RTL is an 'even' page
10955 				$tmp = $this->DeflMargin;
10956 				$this->DeflMargin = $this->DefrMargin;
10957 				$this->DefrMargin = $tmp;
10958 				$this->orig_lMargin = $this->DeflMargin;
10959 				$this->orig_rMargin = $this->DefrMargin;
10960 
10961 				$this->SetMargins($this->DeflMargin, $this->DefrMargin, $this->tMargin);
10962 			}
10963 			$this->directionality = 'rtl';
10964 			$this->defaultAlign = 'R';
10965 			$this->defaultTableAlign = 'R';
10966 		} else {
10967 			/* -- END OTL -- */
10968 			$this->directionality = 'ltr';
10969 			$this->defaultAlign = 'L';
10970 			$this->defaultTableAlign = 'L';
10971 		} // *OTL*
10972 		$this->cssManager->CSS['BODY']['DIRECTION'] = $this->directionality;
10973 	}
10974 
10975 	// Return either a number (factor) - based on current set fontsize (if % or em) - or exact lineheight (with 'mm' after it)
10976 	function fixLineheight($v)
10977 	{
10978 		$lh = false;
10979 		if (preg_match('/^[0-9\.,]*$/', $v) && $v >= 0) {
10980 			return ($v + 0);
10981 		} elseif (strtoupper($v) == 'NORMAL' || $v == 'N') {
10982 			return 'N';  // mPDF 6
10983 		} else {
10984 			$tlh = $this->sizeConverter->convert($v, $this->FontSize, $this->FontSize, true);
10985 			if ($tlh) {
10986 				return ($tlh . 'mm');
10987 			}
10988 		}
10989 		return $this->normalLineheight;
10990 	}
10991 
10992 	function _getNormalLineheight($desc = false)
10993 	{
10994 		if (!$desc) {
10995 			$desc = $this->CurrentFont['desc'];
10996 		}
10997 		if (!isset($desc['Leading'])) {
10998 			$desc['Leading'] = 0;
10999 		}
11000 		if ($this->useFixedNormalLineHeight) {
11001 			$lh = $this->normalLineheight;
11002 		} elseif (isset($desc['Ascent']) && $desc['Ascent']) {
11003 			$lh = ($this->adjustFontDescLineheight * ($desc['Ascent'] - $desc['Descent'] + $desc['Leading']) / 1000);
11004 		} else {
11005 			$lh = $this->normalLineheight;
11006 		}
11007 		return $lh;
11008 	}
11009 
11010 	// Set a (fixed) lineheight to an actual value - either to named fontsize(pts) or default
11011 	function SetLineHeight($FontPt = '', $lh = '')
11012 	{
11013 		if (!$FontPt) {
11014 			$FontPt = $this->FontSizePt;
11015 		}
11016 		$fs = $FontPt / Mpdf::SCALE;
11017 		$this->lineheight = $this->_computeLineheight($lh, $fs);
11018 	}
11019 
11020 	function _computeLineheight($lh, $fs = '')
11021 	{
11022 		if ($this->shrin_k > 1) {
11023 			$k = $this->shrin_k;
11024 		} else {
11025 			$k = 1;
11026 		}
11027 		if (!$fs) {
11028 			$fs = $this->FontSize;
11029 		}
11030 		if ($lh == 'N') {
11031 			$lh = $this->_getNormalLineheight();
11032 		}
11033 		if (preg_match('/mm/', $lh)) {
11034 			return (((float) $lh) / $k); // convert to number
11035 		} elseif ($lh > 0) {
11036 			return ($fs * $lh);
11037 		}
11038 		return ($fs * $this->normalLineheight);
11039 	}
11040 
11041 	function _setLineYpos(&$fontsize, &$fontdesc, &$CSSlineheight, $blockYpos = false)
11042 	{
11043 		$ypos['glyphYorigin'] = 0;
11044 		$ypos['baseline-shift'] = 0;
11045 		$linegap = 0;
11046 		$leading = 0;
11047 
11048 		if (isset($fontdesc['Ascent']) && $fontdesc['Ascent'] && !$this->useFixedTextBaseline) {
11049 			// Fontsize uses font metrics - this method seems to produce results compatible with browsers (except IE9)
11050 			$ypos['boxtop'] = $fontdesc['Ascent'] / 1000 * $fontsize;
11051 			$ypos['boxbottom'] = $fontdesc['Descent'] / 1000 * $fontsize;
11052 			if (isset($fontdesc['Leading'])) {
11053 				$linegap = $fontdesc['Leading'] / 1000 * $fontsize;
11054 			}
11055 		} // Default if not set - uses baselineC
11056 		else {
11057 			$ypos['boxtop'] = (0.5 + $this->baselineC) * $fontsize;
11058 			$ypos['boxbottom'] = -(0.5 - $this->baselineC) * $fontsize;
11059 		}
11060 		$fontheight = $ypos['boxtop'] - $ypos['boxbottom'];
11061 
11062 		if ($this->shrin_k > 1) {
11063 			$shrin_k = $this->shrin_k;
11064 		} else {
11065 			$shrin_k = 1;
11066 		}
11067 
11068 		$leading = 0;
11069 		if ($CSSlineheight == 'N') {
11070 			$lh = $this->_getNormalLineheight($fontdesc);
11071 			$lineheight = ($fontsize * $lh);
11072 			$leading += $linegap; // specified in hhea or sTypo in OpenType tables
11073 		} elseif (preg_match('/mm/', $CSSlineheight)) {
11074 			$lineheight = (((float) $CSSlineheight) / $shrin_k); // convert to number
11075 		} // ??? If lineheight is a factor e.g. 1.3  ?? use factor x 1em or ? use 'normal' lineheight * factor
11076 		// Could depend on value for $text_height - a draft CSS value as set above for now
11077 		elseif ($CSSlineheight > 0) {
11078 			$lineheight = ($fontsize * $CSSlineheight);
11079 		} else {
11080 			$lineheight = ($fontsize * $this->normalLineheight);
11081 		}
11082 
11083 		// In general, calculate the "leading" - the difference between the fontheight and the lineheight
11084 		// and add half to the top and half to the bottom. BUT
11085 		// If an inline element has a font-size less than the block element, and the line-height is set as an em or % value
11086 		// it will add too much leading below the font and expand the height of the line - so just use the block element exttop/extbottom:
11087 		if (preg_match('/mm/', $CSSlineheight)
11088 				&& ($blockYpos && $ypos['boxtop'] < $blockYpos['boxtop'])
11089 				&& ($blockYpos && $ypos['boxbottom'] > $blockYpos['boxbottom'])) {
11090 
11091 			$ypos['exttop'] = $blockYpos['exttop'];
11092 			$ypos['extbottom'] = $blockYpos['extbottom'];
11093 
11094 		} else {
11095 
11096 			$leading += ($lineheight - $fontheight);
11097 
11098 			$ypos['exttop'] = $ypos['boxtop'] + $leading / 2;
11099 			$ypos['extbottom'] = $ypos['boxbottom'] - $leading / 2;
11100 		}
11101 
11102 
11103 		// TEMP ONLY FOR DEBUGGING *********************************
11104 		// $ypos['lineheight'] = $lineheight;
11105 		// $ypos['fontheight'] = $fontheight;
11106 		// $ypos['leading'] = $leading;
11107 
11108 		return $ypos;
11109 	}
11110 
11111 	/* Called from WriteFlowingBlock() and finishFlowingBlock()
11112 	  Determines the line hieght and glyph/writing position
11113 	  for each element in the line to be written */
11114 
11115 	function _setInlineBlockHeights(&$lineBox, &$stackHeight, &$content, &$font, $is_table)
11116 	{
11117 		if ($this->shrin_k > 1) {
11118 			$shrin_k = $this->shrin_k;
11119 		} else {
11120 			$shrin_k = 1;
11121 		}
11122 
11123 		$ypos = [];
11124 		$bordypos = [];
11125 		$bgypos = [];
11126 
11127 		if ($is_table) {
11128 			// FOR TABLE
11129 			$fontsize = $this->FontSize;
11130 			$fontkey = $this->FontFamily . $this->FontStyle;
11131 			$fontdesc = $this->fonts[$fontkey]['desc'];
11132 			$CSSlineheight = $this->cellLineHeight;
11133 			$line_stacking_strategy = $this->cellLineStackingStrategy; // inline-line-height [default] | block-line-height | max-height | grid-height
11134 			$line_stacking_shift = $this->cellLineStackingShift;  // consider-shifts [default] | disregard-shifts
11135 		} else {
11136 			// FOR BLOCK FONT
11137 			$fontsize = $this->blk[$this->blklvl]['InlineProperties']['size'];
11138 			$fontkey = $this->blk[$this->blklvl]['InlineProperties']['family'] . $this->blk[$this->blklvl]['InlineProperties']['style'];
11139 			$fontdesc = $this->fonts[$fontkey]['desc'];
11140 			$CSSlineheight = $this->blk[$this->blklvl]['line_height'];
11141 			// inline-line-height | block-line-height | max-height | grid-height
11142 			$line_stacking_strategy = (isset($this->blk[$this->blklvl]['line_stacking_strategy']) ? $this->blk[$this->blklvl]['line_stacking_strategy'] : 'inline-line-height');
11143 			// consider-shifts | disregard-shifts
11144 			$line_stacking_shift = (isset($this->blk[$this->blklvl]['line_stacking_shift']) ? $this->blk[$this->blklvl]['line_stacking_shift'] : 'consider-shifts');
11145 		}
11146 		$boxLineHeight = $this->_computeLineheight($CSSlineheight, $fontsize);
11147 
11148 
11149 		// First, set a "strut" using block font at index $lineBox[-1]
11150 		$ypos[-1] = $this->_setLineYpos($fontsize, $fontdesc, $CSSlineheight);
11151 
11152 		// for the block element - always taking the block EXTENDED progression including leading - which may be negative
11153 		if ($line_stacking_strategy == 'block-line-height') {
11154 			$topy = $ypos[-1]['exttop'];
11155 			$bottomy = $ypos[-1]['extbottom'];
11156 		} else {
11157 			$topy = 0;
11158 			$bottomy = 0;
11159 		}
11160 
11161 		// Get text-middle for aligning images/objects
11162 		$midpoint = $ypos[-1]['boxtop'] - (($ypos[-1]['boxtop'] - $ypos[-1]['boxbottom']) / 2);
11163 
11164 		// for images / inline objects / replaced elements
11165 		$mta = 0; // Maximum top-aligned
11166 		$mba = 0; // Maximum bottom-aligned
11167 		foreach ($content as $k => $chunk) {
11168 			if (isset($this->objectbuffer[$k]) && $this->objectbuffer[$k]['type'] == 'listmarker') {
11169 				$ypos[$k] = $ypos[-1];
11170 				// UPDATE Maximums
11171 				if ($line_stacking_strategy == 'block-line-height' || $line_stacking_strategy == 'grid-height' || $line_stacking_strategy == 'max-height') { // don't include extended block progression of all inline elements
11172 					if ($ypos[$k]['boxtop'] > $topy) {
11173 						$topy = $ypos[$k]['boxtop'];
11174 					}
11175 					if ($ypos[$k]['boxbottom'] < $bottomy) {
11176 						$bottomy = $ypos[$k]['boxbottom'];
11177 					}
11178 				} else {
11179 					if ($ypos[$k]['exttop'] > $topy) {
11180 						$topy = $ypos[$k]['exttop'];
11181 					}
11182 					if ($ypos[$k]['extbottom'] < $bottomy) {
11183 						$bottomy = $ypos[$k]['extbottom'];
11184 					}
11185 				}
11186 			} elseif (isset($this->objectbuffer[$k]) && $this->objectbuffer[$k]['type'] == 'dottab') { // mPDF 6 DOTTAB
11187 				$fontsize = $font[$k]['size'];
11188 				$fontdesc = $font[$k]['curr']['desc'];
11189 				$lh = 1;
11190 				$ypos[$k] = $this->_setLineYpos($fontsize, $fontdesc, $lh, $ypos[-1]); // Lineheight=1 fixed
11191 			} elseif (isset($this->objectbuffer[$k])) {
11192 				$oh = $this->objectbuffer[$k]['OUTER-HEIGHT'];
11193 				$va = $this->objectbuffer[$k]['vertical-align'];
11194 
11195 				if ($va == 'BS') { //  (BASELINE default)
11196 					if ($oh > $topy) {
11197 						$topy = $oh;
11198 					}
11199 				} elseif ($va == 'M') {
11200 					if (($midpoint + $oh / 2) > $topy) {
11201 						$topy = $midpoint + $oh / 2;
11202 					}
11203 					if (($midpoint - $oh / 2) < $bottomy) {
11204 						$bottomy = $midpoint - $oh / 2;
11205 					}
11206 				} elseif ($va == 'TT') {
11207 					if (($ypos[-1]['boxtop'] - $oh) < $bottomy) {
11208 						$bottomy = $ypos[-1]['boxtop'] - $oh;
11209 						$topy = max($topy, $ypos[-1]['boxtop']);
11210 					}
11211 				} elseif ($va == 'TB') {
11212 					if (($ypos[-1]['boxbottom'] + $oh) > $topy) {
11213 						$topy = $ypos[-1]['boxbottom'] + $oh;
11214 						$bottomy = min($bottomy, $ypos[-1]['boxbottom']);
11215 					}
11216 				} elseif ($va == 'T') {
11217 					if ($oh > $mta) {
11218 						$mta = $oh;
11219 					}
11220 				} elseif ($va == 'B') {
11221 					if ($oh > $mba) {
11222 						$mba = $oh;
11223 					}
11224 				}
11225 			} elseif ($content[$k] || $content[$k] === '0') {
11226 				// FOR FLOWING BLOCK
11227 				$fontsize = $font[$k]['size'];
11228 				$fontdesc = $font[$k]['curr']['desc'];
11229 				// In future could set CSS line-height from inline elements; for now, use block level:
11230 				$ypos[$k] = $this->_setLineYpos($fontsize, $fontdesc, $CSSlineheight, $ypos[-1]);
11231 
11232 				if (isset($font[$k]['textparam']['text-baseline']) && $font[$k]['textparam']['text-baseline'] != 0) {
11233 					$ypos[$k]['baseline-shift'] = $font[$k]['textparam']['text-baseline'];
11234 				}
11235 
11236 				// DO ALIGNMENT FOR BASELINES *******************
11237 				// Until most fonts have OpenType BASE tables, this won't work
11238 				// $ypos[$k] compared to $ypos[-1] or $ypos[$k-1] using $dominant_baseline and $baseline_table
11239 				// UPDATE Maximums
11240 				if ($line_stacking_strategy == 'block-line-height' || $line_stacking_strategy == 'grid-height' || $line_stacking_strategy == 'max-height') { // don't include extended block progression of all inline elements
11241 					if ($line_stacking_shift == 'disregard-shifts') {
11242 						if ($ypos[$k]['boxtop'] > $topy) {
11243 							$topy = $ypos[$k]['boxtop'];
11244 						}
11245 						if ($ypos[$k]['boxbottom'] < $bottomy) {
11246 							$bottomy = $ypos[$k]['boxbottom'];
11247 						}
11248 					} else {
11249 						if (($ypos[$k]['boxtop'] + $ypos[$k]['baseline-shift']) > $topy) {
11250 							$topy = $ypos[$k]['boxtop'] + $ypos[$k]['baseline-shift'];
11251 						}
11252 						if (($ypos[$k]['boxbottom'] + $ypos[$k]['baseline-shift']) < $bottomy) {
11253 							$bottomy = $ypos[$k]['boxbottom'] + $ypos[$k]['baseline-shift'];
11254 						}
11255 					}
11256 				} else {
11257 					if ($line_stacking_shift == 'disregard-shifts') {
11258 						if ($ypos[$k]['exttop'] > $topy) {
11259 							$topy = $ypos[$k]['exttop'];
11260 						}
11261 						if ($ypos[$k]['extbottom'] < $bottomy) {
11262 							$bottomy = $ypos[$k]['extbottom'];
11263 						}
11264 					} else {
11265 						if (($ypos[$k]['exttop'] + $ypos[$k]['baseline-shift']) > $topy) {
11266 							$topy = $ypos[$k]['exttop'] + $ypos[$k]['baseline-shift'];
11267 						}
11268 						if (($ypos[$k]['extbottom'] + $ypos[$k]['baseline-shift']) < $bottomy) {
11269 							$bottomy = $ypos[$k]['extbottom'] + $ypos[$k]['baseline-shift'];
11270 						}
11271 					}
11272 				}
11273 
11274 				// If BORDER set on inline element
11275 				if (isset($font[$k]['bord']) && $font[$k]['bord']) {
11276 					$bordfontsize = $font[$k]['textparam']['bord-decoration']['fontsize'] / $shrin_k;
11277 					$bordfontkey = $font[$k]['textparam']['bord-decoration']['fontkey'];
11278 					if ($bordfontkey != $fontkey || $bordfontsize != $fontsize || isset($font[$k]['textparam']['bord-decoration']['baseline'])) {
11279 						$bordfontdesc = $this->fonts[$bordfontkey]['desc'];
11280 						$bordypos[$k] = $this->_setLineYpos($bordfontsize, $bordfontdesc, $CSSlineheight, $ypos[-1]);
11281 						if (isset($font[$k]['textparam']['bord-decoration']['baseline']) && $font[$k]['textparam']['bord-decoration']['baseline'] != 0) {
11282 							$bordypos[$k]['baseline-shift'] = $font[$k]['textparam']['bord-decoration']['baseline'] / $shrin_k;
11283 						}
11284 					}
11285 				}
11286 				// If BACKGROUND set on inline element
11287 				if (isset($font[$k]['spanbgcolor']) && $font[$k]['spanbgcolor']) {
11288 					$bgfontsize = $font[$k]['textparam']['bg-decoration']['fontsize'] / $shrin_k;
11289 					$bgfontkey = $font[$k]['textparam']['bg-decoration']['fontkey'];
11290 					if ($bgfontkey != $fontkey || $bgfontsize != $fontsize || isset($font[$k]['textparam']['bg-decoration']['baseline'])) {
11291 						$bgfontdesc = $this->fonts[$bgfontkey]['desc'];
11292 						$bgypos[$k] = $this->_setLineYpos($bgfontsize, $bgfontdesc, $CSSlineheight, $ypos[-1]);
11293 						if (isset($font[$k]['textparam']['bg-decoration']['baseline']) && $font[$k]['textparam']['bg-decoration']['baseline'] != 0) {
11294 							$bgypos[$k]['baseline-shift'] = $font[$k]['textparam']['bg-decoration']['baseline'] / $shrin_k;
11295 						}
11296 					}
11297 				}
11298 			}
11299 		}
11300 
11301 
11302 		// TOP or BOTTOM aligned images
11303 		if ($mta > ($topy - $bottomy)) {
11304 			if (($topy - $mta) < $bottomy) {
11305 				$bottomy = $topy - $mta;
11306 			}
11307 		}
11308 		if ($mba > ($topy - $bottomy)) {
11309 			if (($bottomy + $mba) > $topy) {
11310 				$topy = $bottomy + $mba;
11311 			}
11312 		}
11313 
11314 		if ($line_stacking_strategy == 'block-line-height') { // fixed height set by block element (whether present or not)
11315 			$topy = $ypos[-1]['exttop'];
11316 			$bottomy = $ypos[-1]['extbottom'];
11317 		}
11318 
11319 		$inclusiveHeight = $topy - $bottomy;
11320 
11321 		// SET $stackHeight taking note of line_stacking_strategy
11322 		// NB inclusive height already takes account of need to consider block progression height (excludes leading set by lineheight)
11323 		// or extended block progression height (includes leading set by lineheight)
11324 		if ($line_stacking_strategy == 'block-line-height') { // fixed = extended block progression height of block element
11325 			$stackHeight = $boxLineHeight;
11326 		} elseif ($line_stacking_strategy == 'max-height') { // smallest height which includes extended block progression height of block element
11327 			// and block progression heights of inline elements (NOT extended)
11328 			$stackHeight = $inclusiveHeight;
11329 		} elseif ($line_stacking_strategy == 'grid-height') { // smallest multiple of block element lineheight to include
11330 			// block progression heights of inline elements (NOT extended)
11331 			$stackHeight = $boxLineHeight;
11332 			while ($stackHeight < $inclusiveHeight) {
11333 				$stackHeight += $boxLineHeight;
11334 			}
11335 		} else { // 'inline-line-height' = default		// smallest height which includes extended block progression height of block element
11336 			// AND extended block progression heights of inline elements
11337 			$stackHeight = $inclusiveHeight;
11338 		}
11339 
11340 		$diff = $stackHeight - $inclusiveHeight;
11341 		$topy += $diff / 2;
11342 		$bottomy -= $diff / 2;
11343 
11344 		// ADJUST $ypos => lineBox using $stackHeight; lineBox are all offsets from the top of stackHeight in mm
11345 		// and SET IMAGE OFFSETS
11346 		$lineBox[-1]['boxtop'] = $topy - $ypos[-1]['boxtop'];
11347 		$lineBox[-1]['boxbottom'] = $topy - $ypos[-1]['boxbottom'];
11348 		// $lineBox[-1]['exttop'] = $topy - $ypos[-1]['exttop'];
11349 		// $lineBox[-1]['extbottom'] = $topy - $ypos[-1]['extbottom'];
11350 		$lineBox[-1]['glyphYorigin'] = $topy - $ypos[-1]['glyphYorigin'];
11351 		$lineBox[-1]['baseline-shift'] = $ypos[-1]['baseline-shift'];
11352 
11353 		$midpoint = $lineBox[-1]['boxbottom'] - (($lineBox[-1]['boxbottom'] - $lineBox[-1]['boxtop']) / 2);
11354 
11355 		foreach ($content as $k => $chunk) {
11356 			if (isset($this->objectbuffer[$k])) {
11357 				$oh = $this->objectbuffer[$k]['OUTER-HEIGHT'];
11358 				// LIST MARKERS
11359 				if ($this->objectbuffer[$k]['type'] == 'listmarker') {
11360 					$oh = $fontsize;
11361 				} elseif ($this->objectbuffer[$k]['type'] == 'dottab') { // mPDF 6 DOTTAB
11362 					$oh = $font[$k]['size']; // == $this->objectbuffer[$k]['fontsize']/Mpdf::SCALE;
11363 					$lineBox[$k]['boxtop'] = $topy - $ypos[$k]['boxtop'];
11364 					$lineBox[$k]['boxbottom'] = $topy - $ypos[$k]['boxbottom'];
11365 					$lineBox[$k]['glyphYorigin'] = $topy - $ypos[$k]['glyphYorigin'];
11366 					$lineBox[$k]['baseline-shift'] = 0;
11367 					// continue;
11368 				}
11369 				$va = $this->objectbuffer[$k]['vertical-align']; // = $objattr['vertical-align'] = set as M,T,B,S
11370 
11371 				if ($va == 'BS') { //  (BASELINE default)
11372 					$lineBox[$k]['top'] = $lineBox[-1]['glyphYorigin'] - $oh;
11373 				} elseif ($va == 'M') {
11374 					$lineBox[$k]['top'] = $midpoint - $oh / 2;
11375 				} elseif ($va == 'TT') {
11376 					$lineBox[$k]['top'] = $lineBox[-1]['boxtop'];
11377 				} elseif ($va == 'TB') {
11378 					$lineBox[$k]['top'] = $lineBox[-1]['boxbottom'] - $oh;
11379 				} elseif ($va == 'T') {
11380 					$lineBox[$k]['top'] = 0;
11381 				} elseif ($va == 'B') {
11382 					$lineBox[$k]['top'] = $stackHeight - $oh;
11383 				}
11384 			} elseif ($content[$k] || $content[$k] === '0') {
11385 				$lineBox[$k]['boxtop'] = $topy - $ypos[$k]['boxtop'];
11386 				$lineBox[$k]['boxbottom'] = $topy - $ypos[$k]['boxbottom'];
11387 				// $lineBox[$k]['exttop'] = $topy - $ypos[$k]['exttop'];
11388 				// $lineBox[$k]['extbottom'] = $topy - $ypos[$k]['extbottom'];
11389 				$lineBox[$k]['glyphYorigin'] = $topy - $ypos[$k]['glyphYorigin'];
11390 				$lineBox[$k]['baseline-shift'] = $ypos[$k]['baseline-shift'];
11391 				if (isset($bordypos[$k]['boxtop'])) {
11392 					$lineBox[$k]['border-boxtop'] = $topy - $bordypos[$k]['boxtop'];
11393 					$lineBox[$k]['border-boxbottom'] = $topy - $bordypos[$k]['boxbottom'];
11394 					$lineBox[$k]['border-baseline-shift'] = $bordypos[$k]['baseline-shift'];
11395 				}
11396 				if (isset($bgypos[$k]['boxtop'])) {
11397 					$lineBox[$k]['background-boxtop'] = $topy - $bgypos[$k]['boxtop'];
11398 					$lineBox[$k]['background-boxbottom'] = $topy - $bgypos[$k]['boxbottom'];
11399 					$lineBox[$k]['background-baseline-shift'] = $bgypos[$k]['baseline-shift'];
11400 				}
11401 			}
11402 		}
11403 	}
11404 
11405 	function SetBasePath($str = '')
11406 	{
11407 		if (isset($_SERVER['HTTP_HOST'])) {
11408 			$host = $_SERVER['HTTP_HOST'];
11409 		} elseif (isset($_SERVER['SERVER_NAME'])) {
11410 			$host = $_SERVER['SERVER_NAME'];
11411 		} else {
11412 			$host = '';
11413 		}
11414 		if (!$str) {
11415 			if (isset($_SERVER['SCRIPT_NAME'])) {
11416 				$currentPath = dirname($_SERVER['SCRIPT_NAME']);
11417 			} else {
11418 				$currentPath = dirname($_SERVER['PHP_SELF']);
11419 			}
11420 			$currentPath = str_replace("\\", "/", $currentPath);
11421 			if ($currentPath == '/') {
11422 				$currentPath = '';
11423 			}
11424 			if ($host) {  // mPDF 6
11425 				if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] && $_SERVER['HTTPS'] !== 'off') {
11426 					$currpath = 'https://' . $host . $currentPath . '/';
11427 				} else {
11428 					$currpath = 'http://' . $host . $currentPath . '/';
11429 				}
11430 			} else {
11431 				$currpath = '';
11432 			}
11433 			$this->basepath = $currpath;
11434 			$this->basepathIsLocal = true;
11435 			return;
11436 		}
11437 		$str = preg_replace('/\?.*/', '', $str);
11438 		if (!preg_match('/(http|https|ftp):\/\/.*\//i', $str)) {
11439 			$str .= '/';
11440 		}
11441 		$str .= 'xxx'; // in case $str ends in / e.g. http://www.bbc.co.uk/
11442 		$this->basepath = dirname($str) . "/"; // returns e.g. e.g. http://www.google.com/dir1/dir2/dir3/
11443 		$this->basepath = str_replace("\\", "/", $this->basepath); // If on Windows
11444 		$tr = parse_url($this->basepath);
11445 		if (isset($tr['host']) && ($tr['host'] == $host)) {
11446 			$this->basepathIsLocal = true;
11447 		} else {
11448 			$this->basepathIsLocal = false;
11449 		}
11450 	}
11451 
11452 	public function GetFullPath(&$path, $basepath = '')
11453 	{
11454 		// When parsing CSS need to pass temporary basepath - so links are relative to current stylesheet
11455 		if (!$basepath) {
11456 			$basepath = $this->basepath;
11457 		}
11458 
11459 		// Fix path value
11460 		$path = str_replace("\\", '/', $path); // If on Windows
11461 
11462 		// mPDF 5.7.2
11463 		if (substr($path, 0, 2) === '//') {
11464 			$scheme = parse_url($basepath, PHP_URL_SCHEME);
11465 			$scheme = $scheme ?: 'http';
11466 			$path = $scheme . ':' . $path;
11467 		}
11468 
11469 		$path = preg_replace('|^./|', '', $path); // Inadvertently corrects "./path/etc" and "//www.domain.com/etc"
11470 
11471 		if (substr($path, 0, 1) == '#') {
11472 			return;
11473 		}
11474 
11475 		// Skip schemes not supported by installed stream wrappers
11476 		$wrappers = stream_get_wrappers();
11477 		$pattern = sprintf('@^(?!%s)[a-z0-9\.\-+]+:.*@i', implode('|', $wrappers));
11478 		if (preg_match($pattern, $path)) {
11479 			return;
11480 		}
11481 
11482 		if (substr($path, 0, 3) == "../") { // It is a relative link
11483 
11484 			$backtrackamount = substr_count($path, "../");
11485 			$maxbacktrack = substr_count($basepath, "/") - 3;
11486 			$filepath = str_replace("../", '', $path);
11487 			$path = $basepath;
11488 
11489 			// If it is an invalid relative link, then make it go to directory root
11490 			if ($backtrackamount > $maxbacktrack) {
11491 				$backtrackamount = $maxbacktrack;
11492 			}
11493 
11494 			// Backtrack some directories
11495 			for ($i = 0; $i < $backtrackamount + 1; $i++) {
11496 				$path = substr($path, 0, strrpos($path, "/"));
11497 			}
11498 
11499 			$path = $path . "/" . $filepath; // Make it an absolute path
11500 
11501 		} elseif ((strpos($path, ":/") === false || strpos($path, ":/") > 10) && !@is_file($path)) { // It is a local link. Ignore potential file errors
11502 
11503 			if (substr($path, 0, 1) == "/") {
11504 
11505 				$tr = parse_url($basepath);
11506 
11507 				// mPDF 5.7.2
11508 				$root = '';
11509 				if (!empty($tr['scheme'])) {
11510 					$root .= $tr['scheme'] . '://';
11511 				}
11512 
11513 				$root .= isset($tr['host']) ? $tr['host'] : '';
11514 				$root .= ((isset($tr['port']) && $tr['port']) ? (':' . $tr['port']) : ''); // mPDF 5.7.3
11515 
11516 				$path = $root . $path;
11517 
11518 			} else {
11519 				$path = $basepath . $path;
11520 			}
11521 		}
11522 		// Do nothing if it is an Absolute Link
11523 	}
11524 
11525 	function docPageNum($num = 0, $extras = false)
11526 	{
11527 		if ($num < 1) {
11528 			$num = $this->page;
11529 		}
11530 
11531 		$type = $this->defaultPageNumStyle; // set default Page Number Style
11532 		$ppgno = $num;
11533 		$suppress = 0;
11534 		$offset = 0;
11535 		$lastreset = 0;
11536 
11537 		foreach ($this->PageNumSubstitutions as $psarr) {
11538 
11539 			if ($num >= $psarr['from']) {
11540 
11541 				if ($psarr['reset']) {
11542 					if ($psarr['reset'] > 1) {
11543 						$offset = $psarr['reset'] - 1;
11544 					}
11545 					$ppgno = $num - $psarr['from'] + 1 + $offset;
11546 					$lastreset = $psarr['from'];
11547 				}
11548 
11549 				if ($psarr['type']) {
11550 					$type = $psarr['type'];
11551 				}
11552 
11553 				if (strtoupper($psarr['suppress']) == 'ON' || $psarr['suppress'] == 1) {
11554 					$suppress = 1;
11555 				} elseif (strtoupper($psarr['suppress']) == 'OFF') {
11556 					$suppress = 0;
11557 				}
11558 			}
11559 		}
11560 
11561 		if ($suppress) {
11562 			return '';
11563 		}
11564 
11565 		$ppgno = $this->_getStyledNumber($ppgno, $type);
11566 
11567 		if ($extras) {
11568 			$ppgno = $this->pagenumPrefix . $ppgno . $this->pagenumSuffix;
11569 		}
11570 
11571 		return $ppgno;
11572 	}
11573 
11574 	function docPageNumTotal($num = 0, $extras = false)
11575 	{
11576 		if ($num < 1) {
11577 			$num = $this->page;
11578 		}
11579 
11580 		$type = $this->defaultPageNumStyle; // set default Page Number Style
11581 		$ppgstart = 1;
11582 		$ppgend = count($this->pages) + 1;
11583 		$suppress = 0;
11584 		$offset = 0;
11585 
11586 		foreach ($this->PageNumSubstitutions as $psarr) {
11587 			if ($num >= $psarr['from']) {
11588 				if ($psarr['reset']) {
11589 					if ($psarr['reset'] > 1) {
11590 						$offset = $psarr['reset'] - 1;
11591 					}
11592 					$ppgstart = $psarr['from'] + $offset;
11593 					$ppgend = count($this->pages) + 1 + $offset;
11594 				}
11595 				if ($psarr['type']) {
11596 					$type = $psarr['type'];
11597 				}
11598 				if (strtoupper($psarr['suppress']) == 'ON' || $psarr['suppress'] == 1) {
11599 					$suppress = 1;
11600 				} elseif (strtoupper($psarr['suppress']) == 'OFF') {
11601 					$suppress = 0;
11602 				}
11603 			}
11604 			if ($num < $psarr['from']) {
11605 				if ($psarr['reset']) {
11606 					$ppgend = $psarr['from'] + $offset;
11607 					break;
11608 				}
11609 			}
11610 		}
11611 
11612 		if ($suppress) {
11613 			return '';
11614 		}
11615 
11616 		$ppgno = $ppgend - $ppgstart + $offset;
11617 		$ppgno = $this->_getStyledNumber($ppgno, $type);
11618 
11619 		if ($extras) {
11620 			$ppgno = $this->pagenumPrefix . $ppgno . $this->pagenumSuffix;
11621 		}
11622 
11623 		return $ppgno;
11624 	}
11625 
11626 	// mPDF 6
11627 	function _getStyledNumber($ppgno, $type, $listmarker = false)
11628 	{
11629 		if ($listmarker) {
11630 			$reverse = true; // Reverse RTL numerals (Hebrew) when using for list
11631 			$checkfont = true; // Using list - font is set, so check if character is available
11632 		} else {
11633 			$reverse = false; // For pagenumbers, RTL numerals (Hebrew) will get reversed later by bidi
11634 			$checkfont = false; // For pagenumbers - font is not set, so no check
11635 		}
11636 
11637 		$decToAlpha = new Conversion\DecToAlpha();
11638 		$decToCjk = new Conversion\DecToCjk();
11639 		$decToHebrew = new Conversion\DecToHebrew();
11640 		$decToRoman = new Conversion\DecToRoman();
11641 		$decToOther = new Conversion\DecToOther($this);
11642 
11643 		$lowertype = strtolower($type);
11644 
11645 		if ($lowertype == 'upper-latin' || $lowertype == 'upper-alpha' || $type == 'A') {
11646 
11647 			$ppgno = $decToAlpha->convert($ppgno, true);
11648 
11649 		} elseif ($lowertype == 'lower-latin' || $lowertype == 'lower-alpha' || $type == 'a') {
11650 
11651 			$ppgno = $decToAlpha->convert($ppgno, false);
11652 
11653 		} elseif ($lowertype == 'upper-roman' || $type == 'I') {
11654 
11655 			$ppgno = $decToRoman->convert($ppgno, true);
11656 
11657 		} elseif ($lowertype == 'lower-roman' || $type == 'i') {
11658 
11659 			$ppgno = $decToRoman->convert($ppgno, false);
11660 
11661 		} elseif ($lowertype == 'hebrew') {
11662 
11663 			$ppgno = $decToHebrew->convert($ppgno, $reverse);
11664 
11665 		} elseif (preg_match('/(arabic-indic|bengali|devanagari|gujarati|gurmukhi|kannada|malayalam|oriya|persian|tamil|telugu|thai|urdu|cambodian|khmer|lao|myanmar)/i', $lowertype, $m)) {
11666 
11667 			$cp = $decToOther->getCodePage($m[1]);
11668 			$ppgno = $decToOther->convert($ppgno, $cp, $checkfont);
11669 
11670 		} elseif ($lowertype == 'cjk-decimal') {
11671 
11672 			$ppgno = $decToCjk->convert($ppgno);
11673 
11674 		}
11675 
11676 		return $ppgno;
11677 	}
11678 
11679 	function docPageSettings($num = 0)
11680 	{
11681 		// Returns current type (numberstyle), suppression state for this page number;
11682 		// reset is only returned if set for this page number
11683 		if ($num < 1) {
11684 			$num = $this->page;
11685 		}
11686 
11687 		$type = $this->defaultPageNumStyle; // set default Page Number Style
11688 		$ppgno = $num;
11689 		$suppress = 0;
11690 		$offset = 0;
11691 		$reset = '';
11692 
11693 		foreach ($this->PageNumSubstitutions as $psarr) {
11694 			if ($num >= $psarr['from']) {
11695 				if ($psarr['reset']) {
11696 					if ($psarr['reset'] > 1) {
11697 						$offset = $psarr['reset'] - 1;
11698 					}
11699 					$ppgno = $num - $psarr['from'] + 1 + $offset;
11700 				}
11701 				if ($psarr['type']) {
11702 					$type = $psarr['type'];
11703 				}
11704 				if (strtoupper($psarr['suppress']) == 'ON' || $psarr['suppress'] == 1) {
11705 					$suppress = 1;
11706 				} elseif (strtoupper($psarr['suppress']) == 'OFF') {
11707 					$suppress = 0;
11708 				}
11709 			}
11710 			if ($num == $psarr['from']) {
11711 				$reset = $psarr['reset'];
11712 			}
11713 		}
11714 
11715 		if ($suppress) {
11716 			$suppress = 'on';
11717 		} else {
11718 			$suppress = 'off';
11719 		}
11720 
11721 		return [$type, $suppress, $reset];
11722 	}
11723 
11724 	function RestartDocTemplate()
11725 	{
11726 		$this->docTemplateStart = $this->page;
11727 	}
11728 
11729 	// Page header
11730 	function Header($content = '')
11731 	{
11732 
11733 		$this->cMarginL = 0;
11734 		$this->cMarginR = 0;
11735 
11736 
11737 		if (($this->mirrorMargins && ($this->page % 2 == 0) && $this->HTMLHeaderE) || ($this->mirrorMargins && ($this->page % 2 == 1) && $this->HTMLHeader) || (!$this->mirrorMargins && $this->HTMLHeader)) {
11738 			$this->writeHTMLHeaders();
11739 			return;
11740 		}
11741 	}
11742 
11743 	/* -- TABLES -- */
11744 	function TableHeaderFooter($content = '', $tablestartpage = '', $tablestartcolumn = '', $horf = 'H', $level = 0, $firstSpread = true, $finalSpread = true)
11745 	{
11746 		if (($horf == 'H' || $horf == 'F') && !empty($content)) { // mPDF 5.7.2
11747 			$table = &$this->table[1][1];
11748 
11749 			// mPDF 5.7.2
11750 			if ($horf == 'F') { // Table Footer
11751 				$firstrow = count($table['cells']) - $table['footernrows'];
11752 				$lastrow = count($table['cells']) - 1;
11753 			} else {  // Table Header
11754 				$firstrow = 0;
11755 				$lastrow = $table['headernrows'] - 1;
11756 			}
11757 			if (empty($content[$firstrow])) {
11758 				if ($this->debug) {
11759 					throw new \Mpdf\MpdfException("<tfoot> must precede <tbody> in a table");
11760 				} else {
11761 					return;
11762 				}
11763 			}
11764 
11765 
11766 			// Advance down page by half width of top border
11767 			if ($horf == 'H') { // Only if header
11768 				if ($table['borders_separate']) {
11769 					$adv = $table['border_spacing_V'] / 2 + $table['border_details']['T']['w'] + $table['padding']['T'];
11770 				} else {
11771 					$adv = $table['max_cell_border_width']['T'] / 2;
11772 				}
11773 				if ($adv) {
11774 					if ($this->table_rotate) {
11775 						$this->y += ($adv);
11776 					} else {
11777 						$this->DivLn($adv, $this->blklvl, true);
11778 					}
11779 				}
11780 			}
11781 
11782 			$topy = $content[$firstrow][0]['y'] - $this->y;
11783 
11784 			for ($i = $firstrow; $i <= $lastrow; $i++) {
11785 				$y = $this->y;
11786 
11787 				/* -- COLUMNS -- */
11788 				// If outside columns, this is done in PaintDivBB
11789 				if ($this->ColActive) {
11790 					// OUTER FILL BGCOLOR of DIVS
11791 					if ($this->blklvl > 0) {
11792 						$firstblockfill = $this->GetFirstBlockFill();
11793 						if ($firstblockfill && $this->blklvl >= $firstblockfill) {
11794 							$divh = $content[$i][0]['h'];
11795 							$bak_x = $this->x;
11796 							$this->DivLn($divh, -3, false);
11797 							// Reset current block fill
11798 							$bcor = $this->blk[$this->blklvl]['bgcolorarray'];
11799 							$this->SetFColor($bcor);
11800 							$this->x = $bak_x;
11801 						}
11802 					}
11803 				}
11804 				/* -- END COLUMNS -- */
11805 
11806 				$colctr = 0;
11807 				foreach ($content[$i] as $tablehf) {
11808 					$colctr++;
11809 					$y = Arrays::get($tablehf, 'y', null) - $topy;
11810 					$this->y = $y;
11811 					// Set some cell values
11812 					$x = Arrays::get($tablehf, 'x', null);
11813 					if (($this->mirrorMargins) && ($tablestartpage == 'ODD') && (($this->page) % 2 == 0)) { // EVEN
11814 						$x = $x + $this->MarginCorrection;
11815 					} elseif (($this->mirrorMargins) && ($tablestartpage == 'EVEN') && (($this->page) % 2 == 1)) { // ODD
11816 						$x = $x + $this->MarginCorrection;
11817 					}
11818 					/* -- COLUMNS -- */
11819 					// Added to correct for Columns
11820 					if ($this->ColActive) {
11821 						if ($this->directionality == 'rtl') { // *OTL*
11822 							$x -= ($this->CurrCol - $tablestartcolumn) * ($this->ColWidth + $this->ColGap); // *OTL*
11823 						} // *OTL*
11824 						else { // *OTL*
11825 							$x += ($this->CurrCol - $tablestartcolumn) * ($this->ColWidth + $this->ColGap);
11826 						} // *OTL*
11827 					}
11828 					/* -- END COLUMNS -- */
11829 
11830 					if ($colctr == 1) {
11831 						$x0 = $x;
11832 					}
11833 
11834 					// mPDF ITERATION
11835 					if ($this->iterationCounter) {
11836 						foreach ($tablehf['textbuffer'] as $k => $t) {
11837 							if (!is_array($t[0]) && preg_match('/{iteration ([a-zA-Z0-9_]+)}/', $t[0], $m)) {
11838 								$vname = '__' . $m[1] . '_';
11839 								if (!isset($this->$vname)) {
11840 									$this->$vname = 1;
11841 								} else {
11842 									$this->$vname++;
11843 								}
11844 								$tablehf['textbuffer'][$k][0] = preg_replace('/{iteration ' . $m[1] . '}/', $this->$vname, $tablehf['textbuffer'][$k][0]);
11845 							}
11846 						}
11847 					}
11848 
11849 					$w = Arrays::get($tablehf, 'w', null);
11850 					$h = Arrays::get($tablehf, 'h', null);
11851 					$va = Arrays::get($tablehf, 'va', null);
11852 					$R = Arrays::get($tablehf, 'R', null);
11853 					$direction = Arrays::get($tablehf, 'direction', null);
11854 					$mih = Arrays::get($tablehf, 'mih', null);
11855 					$border = Arrays::get($tablehf, 'border', null);
11856 					$border_details = Arrays::get($tablehf, 'border_details', null);
11857 					$padding = Arrays::get($tablehf, 'padding', null);
11858 					$this->tabletheadjustfinished = true;
11859 
11860 					$textbuffer = Arrays::get($tablehf, 'textbuffer', null);
11861 
11862 					// Align
11863 					$align = Arrays::get($tablehf, 'a', null);
11864 					$this->cellTextAlign = $align;
11865 
11866 					$this->cellLineHeight = Arrays::get($tablehf, 'cellLineHeight', null);
11867 					$this->cellLineStackingStrategy = Arrays::get($tablehf, 'cellLineStackingStrategy', null);
11868 					$this->cellLineStackingShift = Arrays::get($tablehf, 'cellLineStackingShift', null);
11869 
11870 					$this->x = $x;
11871 
11872 					if ($this->ColActive) {
11873 						if ($table['borders_separate']) {
11874 							$tablefill = isset($table['bgcolor'][-1]) ? $table['bgcolor'][-1] : 0;
11875 							if ($tablefill) {
11876 								$color = $this->colorConverter->convert($tablefill, $this->PDFAXwarnings);
11877 								if ($color) {
11878 									$xadj = ($table['border_spacing_H'] / 2);
11879 									$yadj = ($table['border_spacing_V'] / 2);
11880 									$wadj = $table['border_spacing_H'];
11881 									$hadj = $table['border_spacing_V'];
11882 									if ($i == $firstrow && $horf == 'H') {  // Top
11883 										$yadj += $table['padding']['T'] + $table['border_details']['T']['w'];
11884 										$hadj += $table['padding']['T'] + $table['border_details']['T']['w'];
11885 									}
11886 									if (($i == ($lastrow) || (isset($tablehf['rowspan']) && ($i + $tablehf['rowspan']) == ($lastrow + 1)) || (!isset($tablehf['rowspan']) && ($i + 1) == ($lastrow + 1))) && $horf == 'F') { // Bottom
11887 										$hadj += $table['padding']['B'] + $table['border_details']['B']['w'];
11888 									}
11889 									if ($colctr == 1) {  // Left
11890 										$xadj += $table['padding']['L'] + $table['border_details']['L']['w'];
11891 										$wadj += $table['padding']['L'] + $table['border_details']['L']['w'];
11892 									}
11893 									if ($colctr == count($content[$i])) { // Right
11894 										$wadj += $table['padding']['R'] + $table['border_details']['R']['w'];
11895 									}
11896 									$this->SetFColor($color);
11897 									$this->Rect($x - $xadj, $y - $yadj, $w + $wadj, $h + $hadj, 'F');
11898 								}
11899 							}
11900 						}
11901 					}
11902 
11903 					if ($table['empty_cells'] != 'hide' || !empty($textbuffer) || !$table['borders_separate']) {
11904 						$paintcell = true;
11905 					} else {
11906 						$paintcell = false;
11907 					}
11908 
11909 					// Vertical align
11910 					if ($R && intval($R) > 0 && isset($va) && $va != 'B') {
11911 						$va = 'B';
11912 					}
11913 
11914 					if (!isset($va) || empty($va) || $va == 'M') {
11915 						$this->y += ($h - $mih) / 2;
11916 					} elseif (isset($va) && $va == 'B') {
11917 						$this->y += $h - $mih;
11918 					}
11919 
11920 
11921 					// TABLE ROW OR CELL FILL BGCOLOR
11922 					$fill = 0;
11923 					if (isset($tablehf['bgcolor']) && $tablehf['bgcolor'] && $tablehf['bgcolor'] != 'transparent') {
11924 						$fill = $tablehf['bgcolor'];
11925 						$leveladj = 6;
11926 					} elseif (isset($content[$i][0]['trbgcolor']) && $content[$i][0]['trbgcolor'] && $content[$i][0]['trbgcolor'] != 'transparent') { // Row color
11927 						$fill = $content[$i][0]['trbgcolor'];
11928 						$leveladj = 3;
11929 					}
11930 					if ($fill && $paintcell) {
11931 						$color = $this->colorConverter->convert($fill, $this->PDFAXwarnings);
11932 						if ($color) {
11933 							if ($table['borders_separate']) {
11934 								if ($this->ColActive) {
11935 									$this->SetFColor($color);
11936 									$this->Rect($x + ($table['border_spacing_H'] / 2), $y + ($table['border_spacing_V'] / 2), $w - $table['border_spacing_H'], $h - $table['border_spacing_V'], 'F');
11937 								} else {
11938 									$this->tableBackgrounds[$level * 9 + $leveladj][] = ['gradient' => false, 'x' => ($x + ($table['border_spacing_H'] / 2)), 'y' => ($y + ($table['border_spacing_V'] / 2)), 'w' => ($w - $table['border_spacing_H']), 'h' => ($h - $table['border_spacing_V']), 'col' => $color];
11939 								}
11940 							} else {
11941 								if ($this->ColActive) {
11942 									$this->SetFColor($color);
11943 									$this->Rect($x, $y, $w, $h, 'F');
11944 								} else {
11945 									$this->tableBackgrounds[$level * 9 + $leveladj][] = ['gradient' => false, 'x' => $x, 'y' => $y, 'w' => $w, 'h' => $h, 'col' => $color];
11946 								}
11947 							}
11948 						}
11949 					}
11950 
11951 
11952 					/* -- BACKGROUNDS -- */
11953 					if (isset($tablehf['gradient']) && $tablehf['gradient'] && $paintcell) {
11954 						$g = $this->gradient->parseBackgroundGradient($tablehf['gradient']);
11955 						if ($g) {
11956 							if ($table['borders_separate']) {
11957 								$px = $x + ($table['border_spacing_H'] / 2);
11958 								$py = $y + ($table['border_spacing_V'] / 2);
11959 								$pw = $w - $table['border_spacing_H'];
11960 								$ph = $h - $table['border_spacing_V'];
11961 							} else {
11962 								$px = $x;
11963 								$py = $y;
11964 								$pw = $w;
11965 								$ph = $h;
11966 							}
11967 							if ($this->ColActive) {
11968 								$this->gradient->Gradient($px, $py, $pw, $ph, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend']);
11969 							} else {
11970 								$this->tableBackgrounds[$level * 9 + 7][] = ['gradient' => true, 'x' => $px, 'y' => $py, 'w' => $pw, 'h' => $ph, 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => ''];
11971 							}
11972 						}
11973 					}
11974 
11975 					if (isset($tablehf['background-image']) && $paintcell) {
11976 						if ($tablehf['background-image']['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $tablehf['background-image']['gradient'])) {
11977 							$g = $this->gradient->parseMozGradient($tablehf['background-image']['gradient']);
11978 							if ($g) {
11979 								if ($table['borders_separate']) {
11980 									$px = $x + ($table['border_spacing_H'] / 2);
11981 									$py = $y + ($table['border_spacing_V'] / 2);
11982 									$pw = $w - $table['border_spacing_H'];
11983 									$ph = $h - $table['border_spacing_V'];
11984 								} else {
11985 									$px = $x;
11986 									$py = $y;
11987 									$pw = $w;
11988 									$ph = $h;
11989 								}
11990 								if ($this->ColActive) {
11991 									$this->gradient->Gradient($px, $py, $pw, $ph, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend']);
11992 								} else {
11993 									$this->tableBackgrounds[$level * 9 + 7][] = ['gradient' => true, 'x' => $px, 'y' => $py, 'w' => $pw, 'h' => $ph, 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => ''];
11994 								}
11995 							}
11996 						} elseif ($tablehf['background-image']['image_id']) { // Background pattern
11997 							$n = count($this->patterns) + 1;
11998 							if ($table['borders_separate']) {
11999 								$px = $x + ($table['border_spacing_H'] / 2);
12000 								$py = $y + ($table['border_spacing_V'] / 2);
12001 								$pw = $w - $table['border_spacing_H'];
12002 								$ph = $h - $table['border_spacing_V'];
12003 							} else {
12004 								$px = $x;
12005 								$py = $y;
12006 								$pw = $w;
12007 								$ph = $h;
12008 							}
12009 							if ($this->ColActive) {
12010 								list($orig_w, $orig_h, $x_repeat, $y_repeat) = $this->_resizeBackgroundImage($tablehf['background-image']['orig_w'], $tablehf['background-image']['orig_h'], $pw, $ph, $tablehf['background-image']['resize'], $tablehf['background-image']['x_repeat'], $tablehf['background-image']['y_repeat']);
12011 								$this->patterns[$n] = ['x' => $px, 'y' => $py, 'w' => $pw, 'h' => $ph, 'pgh' => $this->h, 'image_id' => $tablehf['background-image']['image_id'], 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $tablehf['background-image']['x_pos'], 'y_pos' => $tablehf['background-image']['y_pos'], 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat, 'itype' => $tablehf['background-image']['itype']];
12012 								if ($tablehf['background-image']['opacity'] > 0 && $tablehf['background-image']['opacity'] < 1) {
12013 									$opac = $this->SetAlpha($tablehf['background-image']['opacity'], 'Normal', true);
12014 								} else {
12015 									$opac = '';
12016 								}
12017 								$this->writer->write(sprintf('q /Pattern cs /P%d scn %s %.3F %.3F %.3F %.3F re f Q', $n, $opac, $px * Mpdf::SCALE, ($this->h - $py) * Mpdf::SCALE, $pw * Mpdf::SCALE, -$ph * Mpdf::SCALE));
12018 							} else {
12019 								$this->tableBackgrounds[$level * 9 + 8][] = ['x' => $px, 'y' => $py, 'w' => $pw, 'h' => $ph, 'image_id' => $tablehf['background-image']['image_id'], 'orig_w' => $tablehf['background-image']['orig_w'], 'orig_h' => $tablehf['background-image']['orig_h'], 'x_pos' => $tablehf['background-image']['x_pos'], 'y_pos' => $tablehf['background-image']['y_pos'], 'x_repeat' => $tablehf['background-image']['x_repeat'], 'y_repeat' => $tablehf['background-image']['y_repeat'], 'clippath' => '', 'resize' => $tablehf['background-image']['resize'], 'opacity' => $tablehf['background-image']['opacity'], 'itype' => $tablehf['background-image']['itype']];
12020 							}
12021 						}
12022 					}
12023 					/* -- END BACKGROUNDS -- */
12024 
12025 					// Cell Border
12026 					if ($table['borders_separate'] && $paintcell && $border) {
12027 						$this->_tableRect($x + ($table['border_spacing_H'] / 2) + ($border_details['L']['w'] / 2), $y + ($table['border_spacing_V'] / 2) + ($border_details['T']['w'] / 2), $w - $table['border_spacing_H'] - ($border_details['L']['w'] / 2) - ($border_details['R']['w'] / 2), $h - $table['border_spacing_V'] - ($border_details['T']['w'] / 2) - ($border_details['B']['w'] / 2), $border, $border_details, false, $table['borders_separate']);
12028 					} elseif ($paintcell && $border) {
12029 						$this->_tableRect($x, $y, $w, $h, $border, $border_details, true, $table['borders_separate']);   // true causes buffer
12030 					}
12031 
12032 					// Print cell content
12033 					if (!empty($textbuffer)) {
12034 						if ($horf == 'F' && preg_match('/{colsum([0-9]*)[_]*}/', $textbuffer[0][0], $m)) {
12035 							$rep = sprintf("%01." . intval($m[1]) . "f", $this->colsums[$colctr - 1]);
12036 							$textbuffer[0][0] = preg_replace('/{colsum[0-9_]*}/', $rep, $textbuffer[0][0]);
12037 						}
12038 
12039 						if ($R) {
12040 							$cellPtSize = $textbuffer[0][11] / $this->shrin_k;
12041 							if (!$cellPtSize) {
12042 								$cellPtSize = $this->default_font_size;
12043 							}
12044 							$cellFontHeight = ($cellPtSize / Mpdf::SCALE);
12045 							$opx = $this->x;
12046 							$opy = $this->y;
12047 							$angle = intval($R);
12048 
12049 							// Only allow 45 - 90 degrees (when bottom-aligned) or -90
12050 							if ($angle > 90) {
12051 								$angle = 90;
12052 							} elseif ($angle > 0 && (isset($va) && $va != 'B')) {
12053 								$angle = 90;
12054 							} elseif ($angle > 0 && $angle < 45) {
12055 								$angle = 45;
12056 							} elseif ($angle < 0) {
12057 								$angle = -90;
12058 							}
12059 
12060 							$offset = ((sin(deg2rad($angle))) * 0.37 * $cellFontHeight);
12061 							if (isset($align) && $align == 'R') {
12062 								$this->x += ($w) + ($offset) - ($cellFontHeight / 3) - ($padding['R'] + $border_details['R']['w']);
12063 							} elseif (!isset($align) || $align == 'C') {
12064 								$this->x += ($w / 2) + ($offset);
12065 							} else {
12066 								$this->x += ($offset) + ($cellFontHeight / 3) + ($padding['L'] + $border_details['L']['w']);
12067 							}
12068 							$str = '';
12069 							foreach ($tablehf['textbuffer'] as $t) {
12070 								$str .= $t[0] . ' ';
12071 							}
12072 							$str = rtrim($str);
12073 
12074 							if (!isset($va) || $va == 'M') {
12075 								$this->y -= ($h - $mih) / 2; // Undo what was added earlier VERTICAL ALIGN
12076 								if ($angle > 0) {
12077 									$this->y += (($h - $mih) / 2) + ($padding['T'] + $border_details['T']['w']) + ($mih - ($padding['T'] + $border_details['T']['w'] + $border_details['B']['w'] + $padding['B']));
12078 								} elseif ($angle < 0) {
12079 									$this->y += (($h - $mih) / 2) + ($padding['T'] + $border_details['T']['w']);
12080 								}
12081 							} elseif (isset($va) && $va == 'B') {
12082 								$this->y -= $h - $mih; // Undo what was added earlier VERTICAL ALIGN
12083 								if ($angle > 0) {
12084 									$this->y += $h - ($border_details['B']['w'] + $padding['B']);
12085 								} elseif ($angle < 0) {
12086 									$this->y += $h - $mih + ($padding['T'] + $border_details['T']['w']);
12087 								}
12088 							} elseif (isset($va) && $va == 'T') {
12089 								if ($angle > 0) {
12090 									$this->y += $mih - ($border_details['B']['w'] + $padding['B']);
12091 								} elseif ($angle < 0) {
12092 									$this->y += ($padding['T'] + $border_details['T']['w']);
12093 								}
12094 							}
12095 
12096 							$this->Rotate($angle, $this->x, $this->y);
12097 							$s_fs = $this->FontSizePt;
12098 							$s_f = $this->FontFamily;
12099 							$s_st = $this->FontStyle;
12100 							if (!empty($textbuffer[0][3])) { // Font Color
12101 								$cor = $textbuffer[0][3];
12102 								$this->SetTColor($cor);
12103 							}
12104 							$this->SetFont($textbuffer[0][4], $textbuffer[0][2], $cellPtSize, true, true);
12105 
12106 							$this->magic_reverse_dir($str, $this->directionality, $textbuffer[0][18]);
12107 							$this->Text($this->x, $this->y, $str, $textbuffer[0][18], $textbuffer[0][8]); // textvar
12108 							$this->Rotate(0);
12109 							$this->SetFont($s_f, $s_st, $s_fs, true, true);
12110 							$this->SetTColor(0);
12111 							$this->x = $opx;
12112 							$this->y = $opy;
12113 						} else {
12114 							if ($table['borders_separate']) { // NB twice border width
12115 								$xadj = $border_details['L']['w'] + $padding['L'] + ($table['border_spacing_H'] / 2);
12116 								$wadj = $border_details['L']['w'] + $border_details['R']['w'] + $padding['L'] + $padding['R'] + $table['border_spacing_H'];
12117 								$yadj = $border_details['T']['w'] + $padding['T'] + ($table['border_spacing_H'] / 2);
12118 							} else {
12119 								$xadj = $border_details['L']['w'] / 2 + $padding['L'];
12120 								$wadj = ($border_details['L']['w'] + $border_details['R']['w']) / 2 + $padding['L'] + $padding['R'];
12121 								$yadj = $border_details['T']['w'] / 2 + $padding['T'];
12122 							}
12123 
12124 							$this->divwidth = $w - ($wadj);
12125 							$this->x += $xadj;
12126 							$this->y += $yadj;
12127 							$this->printbuffer($textbuffer, '', true, false, $direction);
12128 						}
12129 					}
12130 					$textbuffer = [];
12131 
12132 					/* -- BACKGROUNDS -- */
12133 					if (!$this->ColActive) {
12134 						if (isset($content[$i][0]['trgradients']) && ($colctr == 1 || $table['borders_separate'])) {
12135 							$g = $this->gradient->parseBackgroundGradient($content[$i][0]['trgradients']);
12136 							if ($g) {
12137 								$gx = $x0;
12138 								$gy = $y;
12139 								$gh = $h;
12140 								$gw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
12141 								if ($table['borders_separate']) {
12142 									$gw -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['padding']['R'] + $table['border_details']['R']['w'] + $table['border_spacing_H']);
12143 									$clx = $x + ($table['border_spacing_H'] / 2);
12144 									$cly = $y + ($table['border_spacing_V'] / 2);
12145 									$clw = $w - $table['border_spacing_H'];
12146 									$clh = $h - $table['border_spacing_V'];
12147 									// Set clipping path
12148 									$s = $this->_setClippingPath($clx, $cly, $clw, $clh); // mPDF 6
12149 									$this->tableBackgrounds[$level * 9 + 4][] = ['gradient' => true, 'x' => $gx + ($table['border_spacing_H'] / 2), 'y' => $gy + ($table['border_spacing_V'] / 2), 'w' => $gw - $table['border_spacing_V'], 'h' => $gh - $table['border_spacing_H'], 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => $s];
12150 								} else {
12151 									$this->tableBackgrounds[$level * 9 + 4][] = ['gradient' => true, 'x' => $gx, 'y' => $gy, 'w' => $gw, 'h' => $gh, 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => ''];
12152 								}
12153 							}
12154 						}
12155 
12156 						if (isset($content[$i][0]['trbackground-images']) && ($colctr == 1 || $table['borders_separate'])) {
12157 							if ($content[$i][0]['trbackground-images']['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $content[$i][0]['trbackground-images']['gradient'])) {
12158 								$g = $this->gradient->parseMozGradient($content[$i][0]['trbackground-images']['gradient']);
12159 								if ($g) {
12160 									$gx = $x0;
12161 									$gy = $y;
12162 									$gh = $h;
12163 									$gw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
12164 									if ($table['borders_separate']) {
12165 										$gw -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['padding']['R'] + $table['border_details']['R']['w'] + $table['border_spacing_H']);
12166 										$clx = $x + ($table['border_spacing_H'] / 2);
12167 										$cly = $y + ($table['border_spacing_V'] / 2);
12168 										$clw = $w - $table['border_spacing_H'];
12169 										$clh = $h - $table['border_spacing_V'];
12170 										// Set clipping path
12171 										$s = $this->_setClippingPath($clx, $cly, $clw, $clh); // mPDF 6
12172 										$this->tableBackgrounds[$level * 9 + 4][] = ['gradient' => true, 'x' => $gx + ($table['border_spacing_H'] / 2), 'y' => $gy + ($table['border_spacing_V'] / 2), 'w' => $gw - $table['border_spacing_V'], 'h' => $gh - $table['border_spacing_H'], 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => $s];
12173 									} else {
12174 										$this->tableBackgrounds[$level * 9 + 4][] = ['gradient' => true, 'x' => $gx, 'y' => $gy, 'w' => $gw, 'h' => $gh, 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => ''];
12175 									}
12176 								}
12177 							} else {
12178 								$image_id = $content[$i][0]['trbackground-images']['image_id'];
12179 								$orig_w = $content[$i][0]['trbackground-images']['orig_w'];
12180 								$orig_h = $content[$i][0]['trbackground-images']['orig_h'];
12181 								$x_pos = $content[$i][0]['trbackground-images']['x_pos'];
12182 								$y_pos = $content[$i][0]['trbackground-images']['y_pos'];
12183 								$x_repeat = $content[$i][0]['trbackground-images']['x_repeat'];
12184 								$y_repeat = $content[$i][0]['trbackground-images']['y_repeat'];
12185 								$resize = $content[$i][0]['trbackground-images']['resize'];
12186 								$opacity = $content[$i][0]['trbackground-images']['opacity'];
12187 								$itype = $content[$i][0]['trbackground-images']['itype'];
12188 
12189 								$clippath = '';
12190 								$gx = $x0;
12191 								$gy = $y;
12192 								$gh = $h;
12193 								$gw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
12194 								if ($table['borders_separate']) {
12195 									$gw -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['padding']['R'] + $table['border_details']['R']['w'] + $table['border_spacing_H']);
12196 									$clx = $x + ($table['border_spacing_H'] / 2);
12197 									$cly = $y + ($table['border_spacing_V'] / 2);
12198 									$clw = $w - $table['border_spacing_H'];
12199 									$clh = $h - $table['border_spacing_V'];
12200 									// Set clipping path
12201 									$s = $this->_setClippingPath($clx, $cly, $clw, $clh); // mPDF 6
12202 									$this->tableBackgrounds[$level * 9 + 5][] = ['x' => $gx + ($table['border_spacing_H'] / 2), 'y' => $gy + ($table['border_spacing_V'] / 2), 'w' => $gw - $table['border_spacing_V'], 'h' => $gh - $table['border_spacing_H'], 'image_id' => $image_id, 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $x_pos, 'y_pos' => $y_pos, 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat, 'clippath' => $s, 'resize' => $resize, 'opacity' => $opacity, 'itype' => $itype];
12203 								} else {
12204 									$this->tableBackgrounds[$level * 9 + 5][] = ['x' => $gx, 'y' => $gy, 'w' => $gw, 'h' => $gh, 'image_id' => $image_id, 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $x_pos, 'y_pos' => $y_pos, 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat, 'clippath' => '', 'resize' => $resize, 'opacity' => $opacity, 'itype' => $itype];
12205 								}
12206 							}
12207 						}
12208 					}
12209 					/* -- END BACKGROUNDS -- */
12210 
12211 					// TABLE BORDER - if separate OR collapsed and only table border
12212 					if (($table['borders_separate'] || ($this->simpleTables && !$table['simple']['border'])) && $table['border']) {
12213 						$halfspaceL = $table['padding']['L'] + ($table['border_spacing_H'] / 2);
12214 						$halfspaceR = $table['padding']['R'] + ($table['border_spacing_H'] / 2);
12215 						$halfspaceT = $table['padding']['T'] + ($table['border_spacing_V'] / 2);
12216 						$halfspaceB = $table['padding']['B'] + ($table['border_spacing_V'] / 2);
12217 						$tbx = $x;
12218 						$tby = $y;
12219 						$tbw = $w;
12220 						$tbh = $h;
12221 						$tab_bord = 0;
12222 						$corner = '';
12223 						if ($i == $firstrow && $horf == 'H') {  // Top
12224 							$tby -= $halfspaceT + ($table['border_details']['T']['w'] / 2);
12225 							$tbh += $halfspaceT + ($table['border_details']['T']['w'] / 2);
12226 							$this->setBorder($tab_bord, Border::TOP);
12227 							$corner .= 'T';
12228 						}
12229 						if (($i == ($lastrow) || (isset($tablehf['rowspan']) && ($i + $tablehf['rowspan']) == ($lastrow + 1))) && $horf == 'F') { // Bottom
12230 							$tbh += $halfspaceB + ($table['border_details']['B']['w'] / 2);
12231 							$this->setBorder($tab_bord, Border::BOTTOM);
12232 							$corner .= 'B';
12233 						}
12234 						if ($colctr == 1 && $firstSpread) { // Left
12235 							$tbx -= $halfspaceL + ($table['border_details']['L']['w'] / 2);
12236 							$tbw += $halfspaceL + ($table['border_details']['L']['w'] / 2);
12237 							$this->setBorder($tab_bord, Border::LEFT);
12238 							$corner .= 'L';
12239 						}
12240 						if ($colctr == count($content[$i]) && $finalSpread) { // Right
12241 							$tbw += $halfspaceR + ($table['border_details']['R']['w'] / 2);
12242 							$this->setBorder($tab_bord, Border::RIGHT);
12243 							$corner .= 'R';
12244 						}
12245 						$this->_tableRect($tbx, $tby, $tbw, $tbh, $tab_bord, $table['border_details'], false, $table['borders_separate'], 'table', $corner, $table['border_spacing_V'], $table['border_spacing_H']);
12246 					}
12247 				}// end column $content
12248 				$this->y = $y + $h; // Update y coordinate
12249 			}// end row $i
12250 			unset($table);
12251 			$this->colsums = [];
12252 		}
12253 	}
12254 
12255 	/* -- END TABLES -- */
12256 
12257 	function SetHTMLHeader($header = '', $OE = '', $write = false)
12258 	{
12259 
12260 		$height = 0;
12261 		if (is_array($header) && isset($header['html']) && $header['html']) {
12262 			$Hhtml = $header['html'];
12263 			if ($this->setAutoTopMargin) {
12264 				if (isset($header['h'])) {
12265 					$height = $header['h'];
12266 				} else {
12267 					$height = $this->_getHtmlHeight($Hhtml);
12268 				}
12269 			}
12270 		} elseif (!is_array($header) && $header) {
12271 			$Hhtml = $header;
12272 			if ($this->setAutoTopMargin) {
12273 				$height = $this->_getHtmlHeight($Hhtml);
12274 			}
12275 		} else {
12276 			$Hhtml = '';
12277 		}
12278 
12279 		if ($OE !== 'E') {
12280 			$OE = 'O';
12281 		}
12282 
12283 		if ($OE === 'E') {
12284 			if ($Hhtml) {
12285 				$this->HTMLHeaderE = [];
12286 				$this->HTMLHeaderE['html'] = $Hhtml;
12287 				$this->HTMLHeaderE['h'] = $height;
12288 			} else {
12289 				$this->HTMLHeaderE = '';
12290 			}
12291 		} else {
12292 			if ($Hhtml) {
12293 				$this->HTMLHeader = [];
12294 				$this->HTMLHeader['html'] = $Hhtml;
12295 				$this->HTMLHeader['h'] = $height;
12296 			} else {
12297 				$this->HTMLHeader = '';
12298 			}
12299 		}
12300 
12301 		if (!$this->mirrorMargins && $OE == 'E') {
12302 			return;
12303 		}
12304 		if ($Hhtml == '') {
12305 			return;
12306 		}
12307 
12308 		if ($this->setAutoTopMargin == 'pad') {
12309 			$this->tMargin = $this->margin_header + $height + $this->orig_tMargin;
12310 			if (isset($this->saveHTMLHeader[$this->page][$OE]['mt'])) {
12311 				$this->saveHTMLHeader[$this->page][$OE]['mt'] = $this->tMargin;
12312 			}
12313 		} elseif ($this->setAutoTopMargin == 'stretch') {
12314 			$this->tMargin = max($this->orig_tMargin, $this->margin_header + $height + $this->autoMarginPadding);
12315 			if (isset($this->saveHTMLHeader[$this->page][$OE]['mt'])) {
12316 				$this->saveHTMLHeader[$this->page][$OE]['mt'] = $this->tMargin;
12317 			}
12318 		}
12319 		if ($write && $this->state != 0 && (($this->mirrorMargins && $OE == 'E' && ($this->page) % 2 == 0) || ($this->mirrorMargins && $OE != 'E' && ($this->page) % 2 == 1) || !$this->mirrorMargins)) {
12320 			$this->writeHTMLHeaders();
12321 		}
12322 	}
12323 
12324 	function SetHTMLFooter($footer = '', $OE = '')
12325 	{
12326 		$height = 0;
12327 		if (is_array($footer) && isset($footer['html']) && $footer['html']) {
12328 			$Fhtml = $footer['html'];
12329 			if ($this->setAutoBottomMargin) {
12330 				if (isset($footer['h'])) {
12331 					$height = $footer['h'];
12332 				} else {
12333 					$height = $this->_getHtmlHeight($Fhtml);
12334 				}
12335 			}
12336 		} elseif (!is_array($footer) && $footer) {
12337 			$Fhtml = $footer;
12338 			if ($this->setAutoBottomMargin) {
12339 				$height = $this->_getHtmlHeight($Fhtml);
12340 			}
12341 		} else {
12342 			$Fhtml = '';
12343 		}
12344 
12345 		if ($OE !== 'E') {
12346 			$OE = 'O';
12347 		}
12348 
12349 		if ($OE === 'E') {
12350 			if ($Fhtml) {
12351 				$this->HTMLFooterE = [];
12352 				$this->HTMLFooterE['html'] = $Fhtml;
12353 				$this->HTMLFooterE['h'] = $height;
12354 			} else {
12355 				$this->HTMLFooterE = '';
12356 			}
12357 		} else {
12358 			if ($Fhtml) {
12359 				$this->HTMLFooter = [];
12360 				$this->HTMLFooter['html'] = $Fhtml;
12361 				$this->HTMLFooter['h'] = $height;
12362 			} else {
12363 				$this->HTMLFooter = '';
12364 			}
12365 		}
12366 
12367 		if (!$this->mirrorMargins && $OE == 'E') {
12368 			return;
12369 		}
12370 
12371 		if ($Fhtml == '') {
12372 			return false;
12373 		}
12374 
12375 		if ($this->setAutoBottomMargin == 'pad') {
12376 			$this->bMargin = $this->margin_footer + $height + $this->orig_bMargin;
12377 			$this->PageBreakTrigger = $this->h - $this->bMargin;
12378 			if (isset($this->saveHTMLHeader[$this->page][$OE]['mb'])) {
12379 				$this->saveHTMLHeader[$this->page][$OE]['mb'] = $this->bMargin;
12380 			}
12381 		} elseif ($this->setAutoBottomMargin == 'stretch') {
12382 			$this->bMargin = max($this->orig_bMargin, $this->margin_footer + $height + $this->autoMarginPadding);
12383 			$this->PageBreakTrigger = $this->h - $this->bMargin;
12384 			if (isset($this->saveHTMLHeader[$this->page][$OE]['mb'])) {
12385 				$this->saveHTMLHeader[$this->page][$OE]['mb'] = $this->bMargin;
12386 			}
12387 		}
12388 	}
12389 
12390 	function _getHtmlHeight($html)
12391 	{
12392 		$save_state = $this->state;
12393 		if ($this->state == 0) {
12394 			$this->AddPage($this->CurOrientation);
12395 		}
12396 		$this->state = 2;
12397 		$this->Reset();
12398 		$this->pageoutput[$this->page] = [];
12399 		$save_x = $this->x;
12400 		$save_y = $this->y;
12401 		$this->x = $this->lMargin;
12402 		$this->y = $this->margin_header;
12403 
12404 		// Replace of page number aliases and date format
12405 		$pnstr = $this->pagenumPrefix . $this->docPageNum($this->page) . $this->pagenumSuffix;
12406 		$pntstr = $this->nbpgPrefix . $this->docPageNumTotal($this->page) . $this->nbpgSuffix;
12407 		$nb = $this->page;
12408 		$html = $this->aliasReplace($html, $pnstr, $pntstr, $nb);
12409 
12410 		$this->HTMLheaderPageLinks = [];
12411 		$this->HTMLheaderPageAnnots = [];
12412 		$this->HTMLheaderPageForms = [];
12413 		$savepb = $this->pageBackgrounds;
12414 		$this->writingHTMLheader = true;
12415 		$this->WriteHTML($html, HTMLParserMode::HTML_HEADER_BUFFER);
12416 		$this->writingHTMLheader = false;
12417 		$h = ($this->y - $this->margin_header);
12418 		$this->Reset();
12419 
12420 		// mPDF 5.7.2 - Clear in case Float used in Header/Footer
12421 		$this->blk[0]['blockContext'] = 0;
12422 		$this->blk[0]['float_endpos'] = 0;
12423 
12424 		$this->pageoutput[$this->page] = [];
12425 		$this->headerbuffer = '';
12426 		$this->pageBackgrounds = $savepb;
12427 		$this->x = $save_x;
12428 		$this->y = $save_y;
12429 		$this->state = $save_state;
12430 
12431 		if ($save_state == 0) {
12432 			unset($this->pages[1]);
12433 			$this->page = 0;
12434 		}
12435 		return $h;
12436 	}
12437 
12438 	// Called internally from Header
12439 	function writeHTMLHeaders()
12440 	{
12441 
12442 		if ($this->mirrorMargins && ($this->page) % 2 == 0) {
12443 			$OE = 'E';
12444 		} else {
12445 			$OE = 'O';
12446 		}
12447 
12448 		if ($OE === 'E') {
12449 			$this->saveHTMLHeader[$this->page][$OE]['html'] = $this->HTMLHeaderE['html'];
12450 		} else {
12451 			$this->saveHTMLHeader[$this->page][$OE]['html'] = $this->HTMLHeader['html'];
12452 		}
12453 
12454 		if ($this->forcePortraitHeaders && $this->CurOrientation == 'L' && $this->CurOrientation != $this->DefOrientation) {
12455 			$this->saveHTMLHeader[$this->page][$OE]['rotate'] = true;
12456 			$this->saveHTMLHeader[$this->page][$OE]['ml'] = $this->tMargin;
12457 			$this->saveHTMLHeader[$this->page][$OE]['mr'] = $this->bMargin;
12458 			$this->saveHTMLHeader[$this->page][$OE]['mh'] = $this->margin_header;
12459 			$this->saveHTMLHeader[$this->page][$OE]['mf'] = $this->margin_footer;
12460 			$this->saveHTMLHeader[$this->page][$OE]['pw'] = $this->h;
12461 			$this->saveHTMLHeader[$this->page][$OE]['ph'] = $this->w;
12462 		} else {
12463 			$this->saveHTMLHeader[$this->page][$OE]['ml'] = $this->lMargin;
12464 			$this->saveHTMLHeader[$this->page][$OE]['mr'] = $this->rMargin;
12465 			$this->saveHTMLHeader[$this->page][$OE]['mh'] = $this->margin_header;
12466 			$this->saveHTMLHeader[$this->page][$OE]['mf'] = $this->margin_footer;
12467 			$this->saveHTMLHeader[$this->page][$OE]['pw'] = $this->w;
12468 			$this->saveHTMLHeader[$this->page][$OE]['ph'] = $this->h;
12469 		}
12470 	}
12471 
12472 	function writeHTMLFooters()
12473 	{
12474 
12475 		if ($this->mirrorMargins && ($this->page) % 2 == 0) {
12476 			$OE = 'E';
12477 		} else {
12478 			$OE = 'O';
12479 		}
12480 
12481 		if ($OE === 'E') {
12482 			$this->saveHTMLFooter[$this->page][$OE]['html'] = $this->HTMLFooterE['html'];
12483 		} else {
12484 			$this->saveHTMLFooter[$this->page][$OE]['html'] = $this->HTMLFooter['html'];
12485 		}
12486 
12487 		if ($this->forcePortraitHeaders && $this->CurOrientation == 'L' && $this->CurOrientation != $this->DefOrientation) {
12488 			$this->saveHTMLFooter[$this->page][$OE]['rotate'] = true;
12489 			$this->saveHTMLFooter[$this->page][$OE]['ml'] = $this->tMargin;
12490 			$this->saveHTMLFooter[$this->page][$OE]['mr'] = $this->bMargin;
12491 			$this->saveHTMLFooter[$this->page][$OE]['mt'] = $this->rMargin;
12492 			$this->saveHTMLFooter[$this->page][$OE]['mb'] = $this->lMargin;
12493 			$this->saveHTMLFooter[$this->page][$OE]['mh'] = $this->margin_header;
12494 			$this->saveHTMLFooter[$this->page][$OE]['mf'] = $this->margin_footer;
12495 			$this->saveHTMLFooter[$this->page][$OE]['pw'] = $this->h;
12496 			$this->saveHTMLFooter[$this->page][$OE]['ph'] = $this->w;
12497 		} else {
12498 			$this->saveHTMLFooter[$this->page][$OE]['ml'] = $this->lMargin;
12499 			$this->saveHTMLFooter[$this->page][$OE]['mr'] = $this->rMargin;
12500 			$this->saveHTMLFooter[$this->page][$OE]['mt'] = $this->tMargin;
12501 			$this->saveHTMLFooter[$this->page][$OE]['mb'] = $this->bMargin;
12502 			$this->saveHTMLFooter[$this->page][$OE]['mh'] = $this->margin_header;
12503 			$this->saveHTMLFooter[$this->page][$OE]['mf'] = $this->margin_footer;
12504 			$this->saveHTMLFooter[$this->page][$OE]['pw'] = $this->w;
12505 			$this->saveHTMLFooter[$this->page][$OE]['ph'] = $this->h;
12506 		}
12507 	}
12508 
12509 	// mPDF 6
12510 	function _shareHeaderFooterWidth($cl, $cc, $cr)
12511 	{
12512 	// mPDF 6
12513 		$l = mb_strlen($cl, 'UTF-8');
12514 		$c = mb_strlen($cc, 'UTF-8');
12515 		$r = mb_strlen($cr, 'UTF-8');
12516 		$s = max($l, $r);
12517 		$tw = $c + 2 * $s;
12518 		if ($tw > 0) {
12519 			return [intval($s * 100 / $tw), intval($c * 100 / $tw), intval($s * 100 / $tw)];
12520 		} else {
12521 			return [33, 33, 33];
12522 		}
12523 	}
12524 
12525 	// mPDF 6
12526 	// Create an HTML header/footer from array (non-HTML header/footer)
12527 	function _createHTMLheaderFooter($arr, $hf)
12528 	{
12529 		$lContent = (isset($arr['L']['content']) ? $arr['L']['content'] : '');
12530 		$cContent = (isset($arr['C']['content']) ? $arr['C']['content'] : '');
12531 		$rContent = (isset($arr['R']['content']) ? $arr['R']['content'] : '');
12532 
12533 		list($lw, $cw, $rw) = $this->_shareHeaderFooterWidth($lContent, $cContent, $rContent);
12534 
12535 		if ($hf == 'H') {
12536 			$valign = 'bottom';
12537 			$vpadding = '0 0 ' . $this->header_line_spacing . 'em 0';
12538 		} else {
12539 			$valign = 'top';
12540 			$vpadding = '' . $this->footer_line_spacing . 'em 0 0 0';
12541 		}
12542 
12543 		if ($this->directionality == 'rtl') { // table columns get reversed so need different text-alignment
12544 			$talignL = 'right';
12545 			$talignR = 'left';
12546 		} else {
12547 			$talignL = 'left';
12548 			$talignR = 'right';
12549 		}
12550 
12551 		$html = '<table width="100%" style="border-collapse: collapse; margin: 0; vertical-align: ' . $valign . '; color: #000000; ';
12552 
12553 		if (isset($arr['line']) && $arr['line']) {
12554 			$html .= ' border-' . $valign . ': 0.1mm solid #000000;';
12555 		}
12556 
12557 		$html .= '">';
12558 		$html .= '<tr>';
12559 		$html .= '<td width="' . $lw . '%" style="padding: ' . $vpadding . '; text-align: ' . $talignL . '; ';
12560 
12561 		if (isset($arr['L']['font-family'])) {
12562 			$html .= ' font-family: ' . $arr['L']['font-family'] . ';';
12563 		}
12564 
12565 		if (isset($arr['L']['color'])) {
12566 			$html .= ' color: ' . $arr['L']['color'] . ';';
12567 		}
12568 
12569 		if (isset($arr['L']['font-size'])) {
12570 			$html .= ' font-size: ' . $arr['L']['font-size'] . 'pt;';
12571 		}
12572 
12573 		if (isset($arr['L']['font-style'])) {
12574 			if ($arr['L']['font-style'] == 'B' || $arr['L']['font-style'] == 'BI') {
12575 				$html .= ' font-weight: bold;';
12576 			}
12577 			if ($arr['L']['font-style'] == 'I' || $arr['L']['font-style'] == 'BI') {
12578 				$html .= ' font-style: italic;';
12579 			}
12580 		}
12581 
12582 		$html .= '">' . $lContent . '</td>';
12583 		$html .= '<td width="' . $cw . '%" style="padding: ' . $vpadding . '; text-align: center; ';
12584 
12585 		if (isset($arr['C']['font-family'])) {
12586 			$html .= ' font-family: ' . $arr['C']['font-family'] . ';';
12587 		}
12588 
12589 		if (isset($arr['C']['color'])) {
12590 			$html .= ' color: ' . $arr['C']['color'] . ';';
12591 		}
12592 
12593 		if (isset($arr['C']['font-size'])) {
12594 			$html .= ' font-size: ' . $arr['C']['font-size'] . 'pt;';
12595 		}
12596 
12597 		if (isset($arr['C']['font-style'])) {
12598 			if ($arr['C']['font-style'] == 'B' || $arr['C']['font-style'] == 'BI') {
12599 				$html .= ' font-weight: bold;';
12600 			}
12601 			if ($arr['C']['font-style'] == 'I' || $arr['C']['font-style'] == 'BI') {
12602 				$html .= ' font-style: italic;';
12603 			}
12604 		}
12605 
12606 		$html .= '">' . $cContent . '</td>';
12607 		$html .= '<td width="' . $rw . '%" style="padding: ' . $vpadding . '; text-align: ' . $talignR . '; ';
12608 
12609 		if (isset($arr['R']['font-family'])) {
12610 			$html .= ' font-family: ' . $arr['R']['font-family'] . ';';
12611 		}
12612 
12613 		if (isset($arr['R']['color'])) {
12614 			$html .= ' color: ' . $arr['R']['color'] . ';';
12615 		}
12616 
12617 		if (isset($arr['R']['font-size'])) {
12618 			$html .= ' font-size: ' . $arr['R']['font-size'] . 'pt;';
12619 		}
12620 
12621 		if (isset($arr['R']['font-style'])) {
12622 			if ($arr['R']['font-style'] == 'B' || $arr['R']['font-style'] == 'BI') {
12623 				$html .= ' font-weight: bold;';
12624 			}
12625 			if ($arr['R']['font-style'] == 'I' || $arr['R']['font-style'] == 'BI') {
12626 				$html .= ' font-style: italic;';
12627 			}
12628 		}
12629 
12630 		$html .= '">' . $rContent . '</td>';
12631 		$html .= '</tr></table>';
12632 
12633 		return $html;
12634 	}
12635 
12636 	function DefHeaderByName($name, $arr)
12637 	{
12638 		if (!$name) {
12639 			$name = '_nonhtmldefault';
12640 		}
12641 		$html = $this->_createHTMLheaderFooter($arr, 'H');
12642 
12643 		$this->pageHTMLheaders[$name]['html'] = $html;
12644 		$this->pageHTMLheaders[$name]['h'] = $this->_getHtmlHeight($html);
12645 	}
12646 
12647 	function DefFooterByName($name, $arr)
12648 	{
12649 		if (!$name) {
12650 			$name = '_nonhtmldefault';
12651 		}
12652 		$html = $this->_createHTMLheaderFooter($arr, 'F');
12653 
12654 		$this->pageHTMLfooters[$name]['html'] = $html;
12655 		$this->pageHTMLfooters[$name]['h'] = $this->_getHtmlHeight($html);
12656 	}
12657 
12658 	function SetHeaderByName($name, $side = 'O', $write = false)
12659 	{
12660 		if (!$name) {
12661 			$name = '_nonhtmldefault';
12662 		}
12663 		$this->SetHTMLHeader($this->pageHTMLheaders[$name], $side, $write);
12664 	}
12665 
12666 	function SetFooterByName($name, $side = 'O')
12667 	{
12668 		if (!$name) {
12669 			$name = '_nonhtmldefault';
12670 		}
12671 		$this->SetHTMLFooter($this->pageHTMLfooters[$name], $side);
12672 	}
12673 
12674 	function DefHTMLHeaderByName($name, $html)
12675 	{
12676 		if (!$name) {
12677 			$name = '_default';
12678 		}
12679 
12680 		$this->pageHTMLheaders[$name]['html'] = $html;
12681 		$this->pageHTMLheaders[$name]['h'] = $this->_getHtmlHeight($html);
12682 	}
12683 
12684 	function DefHTMLFooterByName($name, $html)
12685 	{
12686 		if (!$name) {
12687 			$name = '_default';
12688 		}
12689 
12690 		$this->pageHTMLfooters[$name]['html'] = $html;
12691 		$this->pageHTMLfooters[$name]['h'] = $this->_getHtmlHeight($html);
12692 	}
12693 
12694 	function SetHTMLHeaderByName($name, $side = 'O', $write = false)
12695 	{
12696 		if (!$name) {
12697 			$name = '_default';
12698 		}
12699 		$this->SetHTMLHeader($this->pageHTMLheaders[$name], $side, $write);
12700 	}
12701 
12702 	function SetHTMLFooterByName($name, $side = 'O')
12703 	{
12704 		if (!$name) {
12705 			$name = '_default';
12706 		}
12707 		$this->SetHTMLFooter($this->pageHTMLfooters[$name], $side);
12708 	}
12709 
12710 	function SetHeader($Harray = [], $side = '', $write = false)
12711 	{
12712 		$oddhtml = '';
12713 		$evenhtml = '';
12714 
12715 		if (is_string($Harray)) {
12716 
12717 			if (strlen($Harray) === 0) {
12718 
12719 				$oddhtml = '';
12720 				$evenhtml = '';
12721 
12722 			} elseif (strpos($Harray, '|') !== false) {
12723 
12724 				$hdet = explode('|', $Harray);
12725 
12726 				list($lw, $cw, $rw) = $this->_shareHeaderFooterWidth($hdet[0], $hdet[1], $hdet[2]);
12727 				$oddhtml = '<table width="100%" style="border-collapse: collapse; margin: 0; vertical-align: bottom; color: #000000; ';
12728 
12729 				if ($this->defaultheaderfontsize) {
12730 					$oddhtml .= ' font-size: ' . $this->defaultheaderfontsize . 'pt;';
12731 				}
12732 
12733 				if ($this->defaultheaderfontstyle) {
12734 
12735 					if ($this->defaultheaderfontstyle == 'B' || $this->defaultheaderfontstyle == 'BI') {
12736 						$oddhtml .= ' font-weight: bold;';
12737 					}
12738 
12739 					if ($this->defaultheaderfontstyle == 'I' || $this->defaultheaderfontstyle == 'BI') {
12740 						$oddhtml .= ' font-style: italic;';
12741 					}
12742 				}
12743 
12744 				if ($this->defaultheaderline) {
12745 					$oddhtml .= ' border-bottom: 0.1mm solid #000000;';
12746 				}
12747 
12748 				$oddhtml .= '">';
12749 				$oddhtml .= '<tr>';
12750 				$oddhtml .= '<td width="' . $lw . '%" style="padding: 0 0 ' . $this->header_line_spacing . 'em 0; text-align: left; ">' . $hdet[0] . '</td>';
12751 				$oddhtml .= '<td width="' . $cw . '%" style="padding: 0 0 ' . $this->header_line_spacing . 'em 0; text-align: center; ">' . $hdet[1] . '</td>';
12752 				$oddhtml .= '<td width="' . $rw . '%" style="padding: 0 0 ' . $this->header_line_spacing . 'em 0; text-align: right; ">' . $hdet[2] . '</td>';
12753 				$oddhtml .= '</tr></table>';
12754 
12755 				$evenhtml = '<table width="100%" style="border-collapse: collapse; margin: 0; vertical-align: bottom; color: #000000; ';
12756 
12757 				if ($this->defaultheaderfontsize) {
12758 					$evenhtml .= ' font-size: ' . $this->defaultheaderfontsize . 'pt;';
12759 				}
12760 
12761 				if ($this->defaultheaderfontstyle) {
12762 					if ($this->defaultheaderfontstyle == 'B' || $this->defaultheaderfontstyle == 'BI') {
12763 						$evenhtml .= ' font-weight: bold;';
12764 					}
12765 					if ($this->defaultheaderfontstyle == 'I' || $this->defaultheaderfontstyle == 'BI') {
12766 						$evenhtml .= ' font-style: italic;';
12767 					}
12768 				}
12769 
12770 				if ($this->defaultheaderline) {
12771 					$evenhtml .= ' border-bottom: 0.1mm solid #000000;';
12772 				}
12773 
12774 				$evenhtml .= '">';
12775 				$evenhtml .= '<tr>';
12776 				$evenhtml .= '<td width="' . $rw . '%" style="padding: 0 0 ' . $this->header_line_spacing . 'em 0; text-align: left; ">' . $hdet[2] . '</td>';
12777 				$evenhtml .= '<td width="' . $cw . '%" style="padding: 0 0 ' . $this->header_line_spacing . 'em 0; text-align: center; ">' . $hdet[1] . '</td>';
12778 				$evenhtml .= '<td width="' . $lw . '%" style="padding: 0 0 ' . $this->header_line_spacing . 'em 0; text-align: right; ">' . $hdet[0] . '</td>';
12779 				$evenhtml .= '</tr></table>';
12780 
12781 			} else {
12782 
12783 				$oddhtml = '<div style="margin: 0; color: #000000; ';
12784 
12785 				if ($this->defaultheaderfontsize) {
12786 					$oddhtml .= ' font-size: ' . $this->defaultheaderfontsize . 'pt;';
12787 				}
12788 
12789 				if ($this->defaultheaderfontstyle) {
12790 
12791 					if ($this->defaultheaderfontstyle == 'B' || $this->defaultheaderfontstyle == 'BI') {
12792 						$oddhtml .= ' font-weight: bold;';
12793 					}
12794 
12795 					if ($this->defaultheaderfontstyle == 'I' || $this->defaultheaderfontstyle == 'BI') {
12796 						$oddhtml .= ' font-style: italic;';
12797 					}
12798 				}
12799 
12800 				if ($this->defaultheaderline) {
12801 					$oddhtml .= ' border-bottom: 0.1mm solid #000000;';
12802 				}
12803 
12804 				$oddhtml .= 'text-align: right; ">' . $Harray . '</div>';
12805 				$evenhtml = '<div style="margin: 0; color: #000000; ';
12806 
12807 				if ($this->defaultheaderfontsize) {
12808 					$evenhtml .= ' font-size: ' . $this->defaultheaderfontsize . 'pt;';
12809 				}
12810 
12811 				if ($this->defaultheaderfontstyle) {
12812 
12813 					if ($this->defaultheaderfontstyle == 'B' || $this->defaultheaderfontstyle == 'BI') {
12814 						$evenhtml .= ' font-weight: bold;';
12815 					}
12816 
12817 					if ($this->defaultheaderfontstyle == 'I' || $this->defaultheaderfontstyle == 'BI') {
12818 						$evenhtml .= ' font-style: italic;';
12819 					}
12820 				}
12821 
12822 				if ($this->defaultheaderline) {
12823 					$evenhtml .= ' border-bottom: 0.1mm solid #000000;';
12824 				}
12825 
12826 				$evenhtml .= 'text-align: left; ">' . $Harray . '</div>';
12827 			}
12828 
12829 		} elseif (is_array($Harray) && !empty($Harray)) {
12830 
12831 			$odd = null;
12832 			$even = null;
12833 
12834 			if ($side === 'O') {
12835 				$odd = $Harray;
12836 			} elseif ($side === 'E') {
12837 				$even = $Harray;
12838 			} else {
12839 				$odd = Arrays::get($Harray, 'odd', null);
12840 				$even = Arrays::get($Harray, 'even', null);
12841 			}
12842 
12843 			$oddhtml = $this->_createHTMLheaderFooter($odd, 'H');
12844 			$evenhtml = $this->_createHTMLheaderFooter($even, 'H');
12845 		}
12846 
12847 		if ($side === 'E') {
12848 			$this->SetHTMLHeader($evenhtml, 'E', $write);
12849 		} elseif ($side === 'O') {
12850 			$this->SetHTMLHeader($oddhtml, 'O', $write);
12851 		} else {
12852 			$this->SetHTMLHeader($oddhtml, 'O', $write);
12853 			$this->SetHTMLHeader($evenhtml, 'E', $write);
12854 		}
12855 	}
12856 
12857 	function SetFooter($Farray = [], $side = '')
12858 	{
12859 		$oddhtml = '';
12860 		$evenhtml = '';
12861 
12862 		if (is_string($Farray)) {
12863 
12864 			if (strlen($Farray) == 0) {
12865 
12866 				$oddhtml = '';
12867 				$evenhtml = '';
12868 
12869 			} elseif (strpos($Farray, '|') !== false) {
12870 
12871 				$hdet = explode('|', $Farray);
12872 				$oddhtml = '<table width="100%" style="border-collapse: collapse; margin: 0; vertical-align: top; color: #000000; ';
12873 
12874 				if ($this->defaultfooterfontsize) {
12875 					$oddhtml .= ' font-size: ' . $this->defaultfooterfontsize . 'pt;';
12876 				}
12877 
12878 				if ($this->defaultfooterfontstyle) {
12879 					if ($this->defaultfooterfontstyle == 'B' || $this->defaultfooterfontstyle == 'BI') {
12880 						$oddhtml .= ' font-weight: bold;';
12881 					}
12882 					if ($this->defaultfooterfontstyle == 'I' || $this->defaultfooterfontstyle == 'BI') {
12883 						$oddhtml .= ' font-style: italic;';
12884 					}
12885 				}
12886 
12887 				if ($this->defaultfooterline) {
12888 					$oddhtml .= ' border-top: 0.1mm solid #000000;';
12889 				}
12890 
12891 				$oddhtml .= '">';
12892 				$oddhtml .= '<tr>';
12893 				$oddhtml .= '<td width="33%" style="padding: ' . $this->footer_line_spacing . 'em 0 0 0; text-align: left; ">' . $hdet[0] . '</td>';
12894 				$oddhtml .= '<td width="33%" style="padding: ' . $this->footer_line_spacing . 'em 0 0 0; text-align: center; ">' . $hdet[1] . '</td>';
12895 				$oddhtml .= '<td width="33%" style="padding: ' . $this->footer_line_spacing . 'em 0 0 0; text-align: right; ">' . $hdet[2] . '</td>';
12896 				$oddhtml .= '</tr></table>';
12897 
12898 				$evenhtml = '<table width="100%" style="border-collapse: collapse; margin: 0; vertical-align: top; color: #000000; ';
12899 
12900 				if ($this->defaultfooterfontsize) {
12901 					$evenhtml .= ' font-size: ' . $this->defaultfooterfontsize . 'pt;';
12902 				}
12903 
12904 				if ($this->defaultfooterfontstyle) {
12905 
12906 					if ($this->defaultfooterfontstyle == 'B' || $this->defaultfooterfontstyle == 'BI') {
12907 						$evenhtml .= ' font-weight: bold;';
12908 					}
12909 
12910 					if ($this->defaultfooterfontstyle == 'I' || $this->defaultfooterfontstyle == 'BI') {
12911 						$evenhtml .= ' font-style: italic;';
12912 					}
12913 				}
12914 
12915 				if ($this->defaultfooterline) {
12916 					$evenhtml .= ' border-top: 0.1mm solid #000000;';
12917 				}
12918 
12919 				$evenhtml .= '">';
12920 				$evenhtml .= '<tr>';
12921 				$evenhtml .= '<td width="33%" style="padding: ' . $this->footer_line_spacing . 'em 0 0 0; text-align: left; ">' . $hdet[2] . '</td>';
12922 				$evenhtml .= '<td width="33%" style="padding: ' . $this->footer_line_spacing . 'em 0 0 0; text-align: center; ">' . $hdet[1] . '</td>';
12923 				$evenhtml .= '<td width="33%" style="padding: ' . $this->footer_line_spacing . 'em 0 0 0; text-align: right; ">' . $hdet[0] . '</td>';
12924 				$evenhtml .= '</tr></table>';
12925 
12926 			} else {
12927 
12928 				$oddhtml = '<div style="margin: 0; color: #000000; ';
12929 
12930 				if ($this->defaultfooterfontsize) {
12931 					$oddhtml .= ' font-size: ' . $this->defaultfooterfontsize . 'pt;';
12932 				}
12933 
12934 				if ($this->defaultfooterfontstyle) {
12935 
12936 					if ($this->defaultfooterfontstyle == 'B' || $this->defaultfooterfontstyle == 'BI') {
12937 						$oddhtml .= ' font-weight: bold;';
12938 					}
12939 
12940 					if ($this->defaultfooterfontstyle == 'I' || $this->defaultfooterfontstyle == 'BI') {
12941 						$oddhtml .= ' font-style: italic;';
12942 					}
12943 				}
12944 
12945 				if ($this->defaultfooterline) {
12946 					$oddhtml .= ' border-top: 0.1mm solid #000000;';
12947 				}
12948 
12949 				$oddhtml .= 'text-align: right; ">' . $Farray . '</div>';
12950 
12951 				$evenhtml = '<div style="margin: 0; color: #000000; ';
12952 
12953 				if ($this->defaultfooterfontsize) {
12954 					$evenhtml .= ' font-size: ' . $this->defaultfooterfontsize . 'pt;';
12955 				}
12956 
12957 				if ($this->defaultfooterfontstyle) {
12958 
12959 					if ($this->defaultfooterfontstyle == 'B' || $this->defaultfooterfontstyle == 'BI') {
12960 						$evenhtml .= ' font-weight: bold;';
12961 					}
12962 
12963 					if ($this->defaultfooterfontstyle == 'I' || $this->defaultfooterfontstyle == 'BI') {
12964 						$evenhtml .= ' font-style: italic;';
12965 					}
12966 				}
12967 
12968 				if ($this->defaultfooterline) {
12969 					$evenhtml .= ' border-top: 0.1mm solid #000000;';
12970 				}
12971 
12972 				$evenhtml .= 'text-align: left; ">' . $Farray . '</div>';
12973 			}
12974 
12975 		} elseif (is_array($Farray)) {
12976 
12977 			$odd = null;
12978 			$even = null;
12979 
12980 			if ($side === 'O') {
12981 				$odd = $Farray;
12982 			} elseif ($side == 'E') {
12983 				$even = $Farray;
12984 			} else {
12985 				$odd = Arrays::get($Farray, 'odd', null);
12986 				$even = Arrays::get($Farray, 'even', null);
12987 			}
12988 
12989 			$oddhtml = $this->_createHTMLheaderFooter($odd, 'F');
12990 			$evenhtml = $this->_createHTMLheaderFooter($even, 'F');
12991 		}
12992 
12993 		if ($side === 'E') {
12994 			$this->SetHTMLFooter($evenhtml, 'E');
12995 		} elseif ($side === 'O') {
12996 			$this->SetHTMLFooter($oddhtml, 'O');
12997 		} else {
12998 			$this->SetHTMLFooter($oddhtml, 'O');
12999 			$this->SetHTMLFooter($evenhtml, 'E');
13000 		}
13001 	}
13002 
13003 	/* -- WATERMARK -- */
13004 
13005 	function SetWatermarkText($txt = '', $alpha = -1)
13006 	{
13007 		if ($alpha >= 0) {
13008 			$this->watermarkTextAlpha = $alpha;
13009 		}
13010 		$this->watermarkText = $txt;
13011 	}
13012 
13013 	function SetWatermarkImage($src, $alpha = -1, $size = 'D', $pos = 'F')
13014 	{
13015 		if ($alpha >= 0) {
13016 			$this->watermarkImageAlpha = $alpha;
13017 		}
13018 		$this->watermarkImage = $src;
13019 		$this->watermark_size = $size;
13020 		$this->watermark_pos = $pos;
13021 	}
13022 
13023 	/* -- END WATERMARK -- */
13024 
13025 	// Page footer
13026 	function Footer()
13027 	{
13028 		/* -- CSS-PAGE -- */
13029 		// PAGED MEDIA - CROP / CROSS MARKS from @PAGE
13030 		if ($this->show_marks == 'CROP' || $this->show_marks == 'CROPCROSS') {
13031 			// Show TICK MARKS
13032 			$this->SetLineWidth(0.1); // = 0.1 mm
13033 			$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
13034 			$l = $this->cropMarkLength;
13035 			$m = $this->cropMarkMargin; // Distance of crop mark from margin
13036 			$b = $this->nonPrintMargin; // Non-printable border at edge of paper sheet
13037 			$ax1 = $b;
13038 			$bx = $this->page_box['outer_width_LR'] - $m;
13039 			$ax = max($ax1, $bx - $l);
13040 			$cx1 = $this->w - $b;
13041 			$dx = $this->w - $this->page_box['outer_width_LR'] + $m;
13042 			$cx = min($cx1, $dx + $l);
13043 			$ay1 = $b;
13044 			$by = $this->page_box['outer_width_TB'] - $m;
13045 			$ay = max($ay1, $by - $l);
13046 			$cy1 = $this->h - $b;
13047 			$dy = $this->h - $this->page_box['outer_width_TB'] + $m;
13048 			$cy = min($cy1, $dy + $l);
13049 
13050 			$this->Line($ax, $this->page_box['outer_width_TB'], $bx, $this->page_box['outer_width_TB']);
13051 			$this->Line($cx, $this->page_box['outer_width_TB'], $dx, $this->page_box['outer_width_TB']);
13052 			$this->Line($ax, $this->h - $this->page_box['outer_width_TB'], $bx, $this->h - $this->page_box['outer_width_TB']);
13053 			$this->Line($cx, $this->h - $this->page_box['outer_width_TB'], $dx, $this->h - $this->page_box['outer_width_TB']);
13054 			$this->Line($this->page_box['outer_width_LR'], $ay, $this->page_box['outer_width_LR'], $by);
13055 			$this->Line($this->page_box['outer_width_LR'], $cy, $this->page_box['outer_width_LR'], $dy);
13056 			$this->Line($this->w - $this->page_box['outer_width_LR'], $ay, $this->w - $this->page_box['outer_width_LR'], $by);
13057 			$this->Line($this->w - $this->page_box['outer_width_LR'], $cy, $this->w - $this->page_box['outer_width_LR'], $dy);
13058 
13059 			if ($this->printers_info) {
13060 				$hd = date('Y-m-d H:i') . '  Page ' . $this->page . ' of {nb}';
13061 				$this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
13062 				$this->SetFont('arial', '', 7.5, true, true);
13063 				$this->x = $this->page_box['outer_width_LR'] + 1.5;
13064 				$this->y = 1;
13065 				$this->Cell(0, $this->FontSize, $hd, 0, 0, 'L', 0, '', 0, 0, 0, 'M');
13066 				$this->SetFont($this->default_font, '', $this->original_default_font_size);
13067 			}
13068 		}
13069 		if ($this->show_marks == 'CROSS' || $this->show_marks == 'CROPCROSS') {
13070 			$this->SetLineWidth(0.1); // = 0.1 mm
13071 			$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
13072 			$l = 14 / 2; // longer length of the cross line (half)
13073 			$w = 6 / 2; // shorter width of the cross line (half)
13074 			$r = 1.2; // radius of circle
13075 			$m = $this->crossMarkMargin; // Distance of cross mark from margin
13076 			$x1 = $this->page_box['outer_width_LR'] - $m;
13077 			$x2 = $this->w - $this->page_box['outer_width_LR'] + $m;
13078 			$y1 = $this->page_box['outer_width_TB'] - $m;
13079 			$y2 = $this->h - $this->page_box['outer_width_TB'] + $m;
13080 			// Left
13081 			$this->Circle($x1, $this->h / 2, $r, 'S');
13082 			$this->Line($x1 - $w, $this->h / 2, $x1 + $w, $this->h / 2);
13083 			$this->Line($x1, $this->h / 2 - $l, $x1, $this->h / 2 + $l);
13084 			// Right
13085 			$this->Circle($x2, $this->h / 2, $r, 'S');
13086 			$this->Line($x2 - $w, $this->h / 2, $x2 + $w, $this->h / 2);
13087 			$this->Line($x2, $this->h / 2 - $l, $x2, $this->h / 2 + $l);
13088 			// Top
13089 			$this->Circle($this->w / 2, $y1, $r, 'S');
13090 			$this->Line($this->w / 2, $y1 - $w, $this->w / 2, $y1 + $w);
13091 			$this->Line($this->w / 2 - $l, $y1, $this->w / 2 + $l, $y1);
13092 			// Bottom
13093 			$this->Circle($this->w / 2, $y2, $r, 'S');
13094 			$this->Line($this->w / 2, $y2 - $w, $this->w / 2, $y2 + $w);
13095 			$this->Line($this->w / 2 - $l, $y2, $this->w / 2 + $l, $y2);
13096 		}
13097 
13098 		/* -- END CSS-PAGE -- */
13099 
13100 		// mPDF 6
13101 		// If @page set non-HTML headers/footers named, they were not read until later in the HTML code - so now set them
13102 		if ($this->page == 1) {
13103 			if ($this->firstPageBoxHeader) {
13104 				if (isset($this->pageHTMLheaders[$this->firstPageBoxHeader])) {
13105 					$this->HTMLHeader = $this->pageHTMLheaders[$this->firstPageBoxHeader];
13106 				}
13107 				$this->Header();
13108 			}
13109 			if ($this->firstPageBoxFooter) {
13110 				if (isset($this->pageHTMLfooters[$this->firstPageBoxFooter])) {
13111 					$this->HTMLFooter = $this->pageHTMLfooters[$this->firstPageBoxFooter];
13112 				}
13113 			}
13114 			$this->firstPageBoxHeader = '';
13115 			$this->firstPageBoxFooter = '';
13116 		}
13117 
13118 
13119 		if (($this->mirrorMargins && ($this->page % 2 == 0) && $this->HTMLFooterE) || ($this->mirrorMargins && ($this->page % 2 == 1) && $this->HTMLFooter) || (!$this->mirrorMargins && $this->HTMLFooter)) {
13120 			$this->writeHTMLFooters();
13121 		}
13122 
13123 		/* -- WATERMARK -- */
13124 		if (($this->watermarkText) && ($this->showWatermarkText)) {
13125 			$this->watermark($this->watermarkText, $this->watermarkAngle, 120, $this->watermarkTextAlpha); // Watermark text
13126 		}
13127 		if (($this->watermarkImage) && ($this->showWatermarkImage)) {
13128 			$this->watermarkImg($this->watermarkImage, $this->watermarkImageAlpha); // Watermark image
13129 		}
13130 		/* -- END WATERMARK -- */
13131 	}
13132 
13133 	/* -- HTML-CSS -- */
13134 
13135 	/**
13136 	 * Write HTML code to the document
13137 	 *
13138 	 * Also used internally to parse HTML into buffers
13139 	 *
13140 	 * @param string $html
13141 	 * @param int    $mode  Use HTMLParserMode constants. Controls what parts of the $html code is parsed.
13142 	 * @param bool   $init  Clears and sets buffers to Top level block etc.
13143 	 * @param bool   $close If false leaves buffers etc. in current state, so that it can continue a block etc.
13144 	 */
13145 	function WriteHTML($html, $mode = HTMLParserMode::DEFAULT_MODE, $init = true, $close = true)
13146 	{
13147 		/* Check $html is an integer, float, string, boolean or class with __toString(), otherwise throw exception */
13148 		if (is_scalar($html) === false) {
13149 			if (!is_object($html) || ! method_exists($html, '__toString')) {
13150 				throw new \Mpdf\MpdfException('WriteHTML() requires $html be an integer, float, string, boolean or an object with the __toString() magic method.');
13151 			}
13152 		}
13153 
13154 		// Check the mode is valid
13155 		if (in_array($mode, HTMLParserMode::getAllModes(), true) === false) {
13156 			throw new \Mpdf\MpdfException('WriteHTML() requires $mode to be one of the modes defined in HTMLParserMode');
13157 		}
13158 
13159 		/* Cast $html as a string */
13160 		$html = (string) $html;
13161 
13162 		// @log Parsing CSS & Headers
13163 
13164 		if ($init) {
13165 			$this->headerbuffer = '';
13166 			$this->textbuffer = [];
13167 			$this->fixedPosBlockSave = [];
13168 		}
13169 		if ($mode === HTMLParserMode::HEADER_CSS) {
13170 			$html = '<style> ' . $html . ' </style>';
13171 		} // stylesheet only
13172 
13173 		if ($this->allow_charset_conversion) {
13174 			if ($mode === HTMLParserMode::DEFAULT_MODE) {
13175 				$this->ReadCharset($html);
13176 			}
13177 			if ($this->charset_in && $mode !== HTMLParserMode::HTML_HEADER_BUFFER) {
13178 				$success = iconv($this->charset_in, 'UTF-8//TRANSLIT', $html);
13179 				if ($success) {
13180 					$html = $success;
13181 				}
13182 			}
13183 		}
13184 
13185 		$html = $this->purify_utf8($html, false);
13186 		if ($init) {
13187 			$this->blklvl = 0;
13188 			$this->lastblocklevelchange = 0;
13189 			$this->blk = [];
13190 			$this->initialiseBlock($this->blk[0]);
13191 			$this->blk[0]['width'] = & $this->pgwidth;
13192 			$this->blk[0]['inner_width'] = & $this->pgwidth;
13193 			$this->blk[0]['blockContext'] = $this->blockContext;
13194 		}
13195 
13196 		$zproperties = [];
13197 		if ($mode === HTMLParserMode::DEFAULT_MODE || $mode === HTMLParserMode::HEADER_CSS) {
13198 			$this->ReadMetaTags($html);
13199 
13200 			if (preg_match('/<base[^>]*href=["\']([^"\'>]*)["\']/i', $html, $m)) {
13201 				$this->SetBasePath($m[1]);
13202 			}
13203 			$html = $this->cssManager->ReadCSS($html);
13204 
13205 			if ($this->autoLangToFont && !$this->usingCoreFont && preg_match('/<html [^>]*lang=[\'\"](.*?)[\'\"]/ism', $html, $m)) {
13206 				$html_lang = $m[1];
13207 			}
13208 
13209 			if (preg_match('/<html [^>]*dir=[\'\"]\s*rtl\s*[\'\"]/ism', $html)) {
13210 				$zproperties['DIRECTION'] = 'rtl';
13211 			}
13212 
13213 			// allow in-line CSS for body tag to be parsed // Get <body> tag inline CSS
13214 			if (preg_match('/<body([^>]*)>(.*?)<\/body>/ism', $html, $m) || preg_match('/<body([^>]*)>(.*)$/ism', $html, $m)) {
13215 				$html = $m[2];
13216 				// Changed to allow style="background: url('bg.jpg')"
13217 				if (preg_match('/style=[\"](.*?)[\"]/ism', $m[1], $mm) || preg_match('/style=[\'](.*?)[\']/ism', $m[1], $mm)) {
13218 					$zproperties = $this->cssManager->readInlineCSS($mm[1]);
13219 				}
13220 				if (preg_match('/dir=[\'\"]\s*rtl\s*[\'\"]/ism', $m[1])) {
13221 					$zproperties['DIRECTION'] = 'rtl';
13222 				}
13223 				if (isset($html_lang) && $html_lang) {
13224 					$zproperties['LANG'] = $html_lang;
13225 				}
13226 				if ($this->autoLangToFont && !$this->onlyCoreFonts && preg_match('/lang=[\'\"](.*?)[\'\"]/ism', $m[1], $mm)) {
13227 					$zproperties['LANG'] = $mm[1];
13228 				}
13229 			}
13230 		}
13231 		$properties = $this->cssManager->MergeCSS('BLOCK', 'BODY', '');
13232 		if ($zproperties) {
13233 			$properties = $this->cssManager->array_merge_recursive_unique($properties, $zproperties);
13234 		}
13235 
13236 		if (isset($properties['DIRECTION']) && $properties['DIRECTION']) {
13237 			$this->cssManager->CSS['BODY']['DIRECTION'] = $properties['DIRECTION'];
13238 		}
13239 		if (!isset($this->cssManager->CSS['BODY']['DIRECTION'])) {
13240 			$this->cssManager->CSS['BODY']['DIRECTION'] = $this->directionality;
13241 		} else {
13242 			$this->SetDirectionality($this->cssManager->CSS['BODY']['DIRECTION']);
13243 		}
13244 
13245 		$this->setCSS($properties, '', 'BODY');
13246 
13247 		$this->blk[0]['InlineProperties'] = $this->saveInlineProperties();
13248 
13249 		if ($mode === HTMLParserMode::HEADER_CSS) {
13250 			return '';
13251 		}
13252 		if (!isset($this->cssManager->CSS['BODY'])) {
13253 			$this->cssManager->CSS['BODY'] = [];
13254 		}
13255 
13256 		/* -- BACKGROUNDS -- */
13257 		if (isset($properties['BACKGROUND-GRADIENT'])) {
13258 			$this->bodyBackgroundGradient = $properties['BACKGROUND-GRADIENT'];
13259 		}
13260 
13261 		if (isset($properties['BACKGROUND-IMAGE']) && $properties['BACKGROUND-IMAGE']) {
13262 			$ret = $this->SetBackground($properties, $this->pgwidth);
13263 			if ($ret) {
13264 				$this->bodyBackgroundImage = $ret;
13265 			}
13266 		}
13267 		/* -- END BACKGROUNDS -- */
13268 
13269 		/* -- CSS-PAGE -- */
13270 		// If page-box is set
13271 		if ($this->state == 0 && ((isset($this->cssManager->CSS['@PAGE']) && $this->cssManager->CSS['@PAGE']) || (isset($this->cssManager->CSS['@PAGE>>PSEUDO>>FIRST']) && $this->cssManager->CSS['@PAGE>>PSEUDO>>FIRST']))) { // mPDF 5.7.3
13272 			$this->page_box['current'] = '';
13273 			$this->page_box['using'] = true;
13274 			list($pborientation, $pbmgl, $pbmgr, $pbmgt, $pbmgb, $pbmgh, $pbmgf, $hname, $fname, $bg, $resetpagenum, $pagenumstyle, $suppress, $marks, $newformat) = $this->SetPagedMediaCSS('', false, 'O');
13275 			$this->DefOrientation = $this->CurOrientation = $pborientation;
13276 			$this->orig_lMargin = $this->DeflMargin = $pbmgl;
13277 			$this->orig_rMargin = $this->DefrMargin = $pbmgr;
13278 			$this->orig_tMargin = $this->tMargin = $pbmgt;
13279 			$this->orig_bMargin = $this->bMargin = $pbmgb;
13280 			$this->orig_hMargin = $this->margin_header = $pbmgh;
13281 			$this->orig_fMargin = $this->margin_footer = $pbmgf;
13282 			list($pborientation, $pbmgl, $pbmgr, $pbmgt, $pbmgb, $pbmgh, $pbmgf, $hname, $fname, $bg, $resetpagenum, $pagenumstyle, $suppress, $marks, $newformat) = $this->SetPagedMediaCSS('', true, 'O'); // first page
13283 			$this->show_marks = $marks;
13284 			if ($hname) {
13285 				$this->firstPageBoxHeader = $hname;
13286 			}
13287 			if ($fname) {
13288 				$this->firstPageBoxFooter = $fname;
13289 			}
13290 		}
13291 		/* -- END CSS-PAGE -- */
13292 
13293 		$parseonly = false;
13294 		$this->bufferoutput = false;
13295 		if ($mode == HTMLParserMode::HTML_PARSE_NO_WRITE) {
13296 			$parseonly = true;
13297 			// Close any open block tags
13298 			$arr = [];
13299 			$ai = 0;
13300 			for ($b = $this->blklvl; $b > 0; $b--) {
13301 				$this->tag->CloseTag($this->blk[$b]['tag'], $arr, $ai);
13302 			}
13303 			// Output any text left in buffer
13304 			if (count($this->textbuffer)) {
13305 				$this->printbuffer($this->textbuffer);
13306 			}
13307 			$this->textbuffer = [];
13308 		} elseif ($mode === HTMLParserMode::HTML_HEADER_BUFFER) {
13309 			// Close any open block tags
13310 			$arr = [];
13311 			$ai = 0;
13312 			for ($b = $this->blklvl; $b > 0; $b--) {
13313 				$this->tag->CloseTag($this->blk[$b]['tag'], $arr, $ai);
13314 			}
13315 			// Output any text left in buffer
13316 			if (count($this->textbuffer)) {
13317 				$this->printbuffer($this->textbuffer);
13318 			}
13319 			$this->bufferoutput = true;
13320 			$this->textbuffer = [];
13321 			$this->headerbuffer = '';
13322 			$properties = $this->cssManager->MergeCSS('BLOCK', 'BODY', '');
13323 			$this->setCSS($properties, '', 'BODY');
13324 		}
13325 
13326 		mb_internal_encoding('UTF-8');
13327 
13328 		$html = $this->AdjustHTML($html, $this->tabSpaces); // Try to make HTML look more like XHTML
13329 
13330 		if ($this->autoScriptToLang) {
13331 			$html = $this->markScriptToLang($html);
13332 		}
13333 
13334 		preg_match_all('/<htmlpageheader([^>]*)>(.*?)<\/htmlpageheader>/si', $html, $h);
13335 		for ($i = 0; $i < count($h[1]); $i++) {
13336 			if (preg_match('/name=[\'|\"](.*?)[\'|\"]/', $h[1][$i], $n)) {
13337 				$this->pageHTMLheaders[$n[1]]['html'] = $h[2][$i];
13338 				$this->pageHTMLheaders[$n[1]]['h'] = $this->_getHtmlHeight($h[2][$i]);
13339 			}
13340 		}
13341 		preg_match_all('/<htmlpagefooter([^>]*)>(.*?)<\/htmlpagefooter>/si', $html, $f);
13342 		for ($i = 0; $i < count($f[1]); $i++) {
13343 			if (preg_match('/name=[\'|\"](.*?)[\'|\"]/', $f[1][$i], $n)) {
13344 				$this->pageHTMLfooters[$n[1]]['html'] = $f[2][$i];
13345 				$this->pageHTMLfooters[$n[1]]['h'] = $this->_getHtmlHeight($f[2][$i]);
13346 			}
13347 		}
13348 
13349 		$html = preg_replace('/<htmlpageheader.*?<\/htmlpageheader>/si', '', $html);
13350 		$html = preg_replace('/<htmlpagefooter.*?<\/htmlpagefooter>/si', '', $html);
13351 
13352 		if ($this->state == 0 && ($mode === HTMLParserMode::DEFAULT_MODE || $mode === HTMLParserMode::HTML_BODY)) {
13353 			$this->AddPage($this->CurOrientation);
13354 		}
13355 
13356 
13357 		if (isset($hname) && preg_match('/^html_(.*)$/i', $hname, $n)) {
13358 			$this->SetHTMLHeader($this->pageHTMLheaders[$n[1]], 'O', true);
13359 		}
13360 		if (isset($fname) && preg_match('/^html_(.*)$/i', $fname, $n)) {
13361 			$this->SetHTMLFooter($this->pageHTMLfooters[$n[1]], 'O');
13362 		}
13363 
13364 
13365 
13366 		$html = str_replace('<?', '< ', $html); // Fix '<?XML' bug from HTML code generated by MS Word
13367 
13368 		$this->checkSIP = false;
13369 		$this->checkSMP = false;
13370 		$this->checkCJK = false;
13371 		if ($this->onlyCoreFonts) {
13372 			$html = $this->SubstituteChars($html);
13373 		} else {
13374 			if (preg_match("/([" . $this->pregRTLchars . "])/u", $html)) {
13375 				$this->biDirectional = true;
13376 			} // *OTL*
13377 			if (preg_match("/([\x{20000}-\x{2FFFF}])/u", $html)) {
13378 				$this->checkSIP = true;
13379 			}
13380 			if (preg_match("/([\x{10000}-\x{1FFFF}])/u", $html)) {
13381 				$this->checkSMP = true;
13382 			}
13383 			/* -- CJK-FONTS -- */
13384 			if (preg_match("/([" . $this->pregCJKchars . "])/u", $html)) {
13385 				$this->checkCJK = true;
13386 			}
13387 			/* -- END CJK-FONTS -- */
13388 		}
13389 
13390 		// Don't allow non-breaking spaces that are converted to substituted chars or will break anyway and mess up table width calc.
13391 		$html = str_replace('<tta>160</tta>', chr(32), $html);
13392 		$html = str_replace('</tta><tta>', '|', $html);
13393 		$html = str_replace('</tts><tts>', '|', $html);
13394 		$html = str_replace('</ttz><ttz>', '|', $html);
13395 
13396 		// Add new supported tags in the DisableTags function
13397 		$html = strip_tags($html, $this->enabledtags); // remove all unsupported tags, but the ones inside the 'enabledtags' string
13398 		// Explode the string in order to parse the HTML code
13399 		$a = preg_split('/<(.*?)>/ms', $html, -1, PREG_SPLIT_DELIM_CAPTURE);
13400 		// ? more accurate regexp that allows e.g. <a name="Silly <name>">
13401 		// if changing - also change in fn.SubstituteChars()
13402 		// $a = preg_split ('/<((?:[^<>]+(?:"[^"]*"|\'[^\']*\')?)+)>/ms', $html, -1, PREG_SPLIT_DELIM_CAPTURE);
13403 
13404 		if ($this->mb_enc) {
13405 			mb_internal_encoding($this->mb_enc);
13406 		}
13407 		$pbc = 0;
13408 		$this->subPos = -1;
13409 		$cnt = count($a);
13410 		for ($i = 0; $i < $cnt; $i++) {
13411 			$e = $a[$i];
13412 			if ($i % 2 == 0) {
13413 				// TEXT
13414 				if ($this->blk[$this->blklvl]['hide']) {
13415 					continue;
13416 				}
13417 				if ($this->inlineDisplayOff) {
13418 					continue;
13419 				}
13420 				if ($this->inMeter) {
13421 					continue;
13422 				}
13423 
13424 				if ($this->inFixedPosBlock) {
13425 					$this->fixedPosBlock .= $e;
13426 					continue;
13427 				} // *CSS-POSITION*
13428 				if (strlen($e) == 0) {
13429 					continue;
13430 				}
13431 
13432 				if ($this->ignorefollowingspaces && !$this->ispre) {
13433 					if (strlen(ltrim($e)) == 0) {
13434 						continue;
13435 					}
13436 					if ($this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats' && substr($e, 0, 1) == ' ') {
13437 						$this->ignorefollowingspaces = false;
13438 						$e = ltrim($e);
13439 					}
13440 				}
13441 
13442 				$this->OTLdata = null;  // mPDF 5.7.1
13443 
13444 				$e = UtfString::strcode2utf($e);
13445 				$e = $this->lesser_entity_decode($e);
13446 
13447 				if ($this->usingCoreFont) {
13448 					// If core font is selected in document which is not onlyCoreFonts - substitute with non-core font
13449 					if ($this->useSubstitutions && !$this->onlyCoreFonts && $this->subPos < $i && !$this->specialcontent) {
13450 						$cnt += $this->SubstituteCharsNonCore($a, $i, $e);
13451 					}
13452 					// CONVERT ENCODING
13453 					$e = mb_convert_encoding($e, $this->mb_enc, 'UTF-8');
13454 					if ($this->textvar & TextVars::FT_UPPERCASE) {
13455 						$e = mb_strtoupper($e, $this->mb_enc);
13456 					} // mPDF 5.7.1
13457 					elseif ($this->textvar & TextVars::FT_LOWERCASE) {
13458 						$e = mb_strtolower($e, $this->mb_enc);
13459 					} // mPDF 5.7.1
13460 					elseif ($this->textvar & TextVars::FT_CAPITALIZE) {
13461 						$e = mb_convert_case($e, MB_CASE_TITLE, "UTF-8");
13462 					} // mPDF 5.7.1
13463 				} else {
13464 					if ($this->checkSIP && $this->CurrentFont['sipext'] && $this->subPos < $i && (!$this->specialcontent || !$this->useActiveForms)) {
13465 						$cnt += $this->SubstituteCharsSIP($a, $i, $e);
13466 					}
13467 
13468 					if ($this->useSubstitutions && !$this->onlyCoreFonts && $this->CurrentFont['type'] != 'Type0' && $this->subPos < $i && (!$this->specialcontent || !$this->useActiveForms)) {
13469 						$cnt += $this->SubstituteCharsMB($a, $i, $e);
13470 					}
13471 
13472 					if ($this->textvar & TextVars::FT_UPPERCASE) {
13473 						$e = mb_strtoupper($e, $this->mb_enc);
13474 					} elseif ($this->textvar & TextVars::FT_LOWERCASE) {
13475 						$e = mb_strtolower($e, $this->mb_enc);
13476 					} elseif ($this->textvar & TextVars::FT_CAPITALIZE) {
13477 						$e = mb_convert_case($e, MB_CASE_TITLE, "UTF-8");
13478 					}
13479 
13480 					/* -- OTL -- */
13481 					// Use OTL OpenType Table Layout - GSUB & GPOS
13482 					if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL'] && (!$this->specialcontent || !$this->useActiveForms)) {
13483 						if (!$this->otl) {
13484 							$this->otl = new Otl($this, $this->fontCache);
13485 						}
13486 						$e = $this->otl->applyOTL($e, $this->CurrentFont['useOTL']);
13487 						$this->OTLdata = $this->otl->OTLdata;
13488 						$this->otl->removeChar($e, $this->OTLdata, "\xef\xbb\xbf"); // Remove ZWNBSP (also Byte order mark FEFF)
13489 					} /* -- END OTL -- */
13490 					else {
13491 						// removes U+200E/U+200F LTR and RTL mark and U+200C/U+200D Zero-width Joiner and Non-joiner
13492 						$e = preg_replace("/[\xe2\x80\x8c\xe2\x80\x8d\xe2\x80\x8e\xe2\x80\x8f]/u", '', $e);
13493 						$e = preg_replace("/[\xef\xbb\xbf]/u", '', $e); // Remove ZWNBSP (also Byte order mark FEFF)
13494 					}
13495 				}
13496 
13497 				if (($this->tts) || ($this->ttz) || ($this->tta)) {
13498 					$es = explode('|', $e);
13499 					$e = '';
13500 					foreach ($es as $val) {
13501 						$e .= chr($val);
13502 					}
13503 				}
13504 
13505 				//  FORM ELEMENTS
13506 				if ($this->specialcontent) {
13507 					/* -- FORMS -- */
13508 					// SELECT tag (form element)
13509 					if ($this->specialcontent == "type=select") {
13510 						$e = ltrim($e);
13511 						if (!empty($this->OTLdata)) {
13512 							$this->otl->trimOTLdata($this->OTLdata, true, false);
13513 						} // *OTL*
13514 						$stringwidth = $this->GetStringWidth($e);
13515 						if (!isset($this->selectoption['MAXWIDTH']) || $stringwidth > $this->selectoption['MAXWIDTH']) {
13516 							$this->selectoption['MAXWIDTH'] = $stringwidth;
13517 						}
13518 						if (!isset($this->selectoption['SELECTED']) || $this->selectoption['SELECTED'] == '') {
13519 							$this->selectoption['SELECTED'] = $e;
13520 							if (!empty($this->OTLdata)) {
13521 								$this->selectoption['SELECTED-OTLDATA'] = $this->OTLdata;
13522 							} // *OTL*
13523 						}
13524 						// Active Forms
13525 						if (isset($this->selectoption['ACTIVE']) && $this->selectoption['ACTIVE']) {
13526 							$this->selectoption['ITEMS'][] = ['exportValue' => $this->selectoption['currentVAL'], 'content' => $e, 'selected' => $this->selectoption['currentSEL']];
13527 						}
13528 						$this->OTLdata = [];
13529 					} // TEXTAREA
13530 					else {
13531 						$objattr = unserialize($this->specialcontent);
13532 						$objattr['text'] = $e;
13533 						$objattr['OTLdata'] = $this->OTLdata;
13534 						$this->OTLdata = [];
13535 						$te = "\xbb\xa4\xactype=textarea,objattr=" . serialize($objattr) . "\xbb\xa4\xac";
13536 						if ($this->tdbegin) {
13537 							$this->_saveCellTextBuffer($te, $this->HREF);
13538 						} else {
13539 							$this->_saveTextBuffer($te, $this->HREF);
13540 						}
13541 					}
13542 					/* -- END FORMS -- */
13543 				} // TABLE
13544 				elseif ($this->tableLevel) {
13545 					/* -- TABLES -- */
13546 					if ($this->tdbegin) {
13547 						if (($this->ignorefollowingspaces) && !$this->ispre) {
13548 							$e = ltrim($e);
13549 							if (!empty($this->OTLdata)) {
13550 								$this->otl->trimOTLdata($this->OTLdata, true, false);
13551 							} // *OTL*
13552 						}
13553 						if ($e || $e === '0') {
13554 							if ($this->blockjustfinished && $this->cell[$this->row][$this->col]['s'] > 0) {
13555 								$this->_saveCellTextBuffer("\n");
13556 								if (!isset($this->cell[$this->row][$this->col]['maxs'])) {
13557 									$this->cell[$this->row][$this->col]['maxs'] = $this->cell[$this->row][$this->col]['s'];
13558 								} elseif ($this->cell[$this->row][$this->col]['maxs'] < $this->cell[$this->row][$this->col]['s']) {
13559 									$this->cell[$this->row][$this->col]['maxs'] = $this->cell[$this->row][$this->col]['s'];
13560 								}
13561 								$this->cell[$this->row][$this->col]['s'] = 0; // reset
13562 							}
13563 							$this->blockjustfinished = false;
13564 
13565 							if (!isset($this->cell[$this->row][$this->col]['R']) || !$this->cell[$this->row][$this->col]['R']) {
13566 								if (isset($this->cell[$this->row][$this->col]['s'])) {
13567 									$this->cell[$this->row][$this->col]['s'] += $this->GetStringWidth($e, false, $this->OTLdata, $this->textvar);
13568 								} else {
13569 									$this->cell[$this->row][$this->col]['s'] = $this->GetStringWidth($e, false, $this->OTLdata, $this->textvar);
13570 								}
13571 								if (!empty($this->spanborddet)) {
13572 									$this->cell[$this->row][$this->col]['s'] += (isset($this->spanborddet['L']['w']) ? $this->spanborddet['L']['w'] : 0) + (isset($this->spanborddet['R']['w']) ? $this->spanborddet['R']['w'] : 0);
13573 								}
13574 							}
13575 
13576 							$this->_saveCellTextBuffer($e, $this->HREF);
13577 
13578 							if (substr($this->cell[$this->row][$this->col]['a'], 0, 1) == 'D') {
13579 
13580 								$dp = $this->decimal_align[substr($this->cell[$this->row][$this->col]['a'], 0, 2)];
13581 								$s = preg_split('/' . preg_quote($dp, '/') . '/', $e, 2);  // ? needs to be /u if not core
13582 								$s0 = $this->GetStringWidth($s[0], false);
13583 
13584 								if (isset($s[1]) && $s[1]) {
13585 									$s1 = $this->GetStringWidth(($s[1] . $dp), false);
13586 								} else {
13587 									$s1 = 0;
13588 								}
13589 
13590 								if (!isset($this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'][$this->col]['maxs0'])) {
13591 									if ($this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'] === false) {
13592 										$this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'] = [];
13593 									}
13594 									$this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'][$this->col]['maxs0'] = $s0;
13595 								} else {
13596 									$this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'][$this->col]['maxs0'] = max($s0, $this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'][$this->col]['maxs0']);
13597 								}
13598 
13599 								if (!isset($this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'][$this->col]['maxs1'])) {
13600 									$this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'][$this->col]['maxs1'] = $s1;
13601 								} else {
13602 									$this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'][$this->col]['maxs1'] = max($s1, $this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'][$this->col]['maxs1']);
13603 								}
13604 							}
13605 
13606 							$this->nestedtablejustfinished = false;
13607 							$this->linebreakjustfinished = false;
13608 						}
13609 					}
13610 					/* -- END TABLES -- */
13611 				} // ALL ELSE
13612 				else {
13613 					if ($this->ignorefollowingspaces && !$this->ispre) {
13614 						$e = ltrim($e);
13615 						if (!empty($this->OTLdata)) {
13616 							$this->otl->trimOTLdata($this->OTLdata, true, false);
13617 						} // *OTL*
13618 					}
13619 					if ($e || $e === '0') {
13620 						$this->_saveTextBuffer($e, $this->HREF);
13621 					}
13622 				}
13623 				if ($e || $e === '0') {
13624 					$this->ignorefollowingspaces = false; // mPDF 6
13625 				}
13626 				if (substr($e, -1, 1) == ' ' && !$this->ispre && $this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats') {
13627 					$this->ignorefollowingspaces = true;
13628 				}
13629 			} else { // TAG **
13630 				if (isset($e[0]) && $e[0] == '/') {
13631 					$endtag = trim(strtoupper(substr($e, 1)));
13632 
13633 					/* -- CSS-POSITION -- */
13634 					// mPDF 6
13635 					if ($this->inFixedPosBlock) {
13636 						if (in_array($endtag, $this->outerblocktags) || in_array($endtag, $this->innerblocktags)) {
13637 							$this->fixedPosBlockDepth--;
13638 						}
13639 						if ($this->fixedPosBlockDepth == 0) {
13640 							$this->fixedPosBlockSave[] = [$this->fixedPosBlock, $this->fixedPosBlockBBox, $this->page];
13641 							$this->fixedPosBlock = '';
13642 							$this->inFixedPosBlock = false;
13643 							continue;
13644 						}
13645 						$this->fixedPosBlock .= '<' . $e . '>';
13646 						continue;
13647 					}
13648 					/* -- END CSS-POSITION -- */
13649 
13650 					// mPDF 6
13651 					// Correct for tags where HTML5 specifies optional end tags (see also OpenTag() )
13652 					if ($this->allow_html_optional_endtags && !$parseonly) {
13653 						if (isset($this->blk[$this->blklvl]['tag'])) {
13654 							$closed = false;
13655 							// li end tag may be omitted if there is no more content in the parent element
13656 							if (!$closed && $this->blk[$this->blklvl]['tag'] == 'LI' && $endtag != 'LI' && (in_array($endtag, $this->outerblocktags) || in_array($endtag, $this->innerblocktags))) {
13657 								$this->tag->CloseTag('LI', $a, $i);
13658 								$closed = true;
13659 							}
13660 							// dd end tag may be omitted if there is no more content in the parent element
13661 							if (!$closed && $this->blk[$this->blklvl]['tag'] == 'DD' && $endtag != 'DD' && (in_array($endtag, $this->outerblocktags) || in_array($endtag, $this->innerblocktags))) {
13662 								$this->tag->CloseTag('DD', $a, $i);
13663 								$closed = true;
13664 							}
13665 							// p end tag may be omitted if there is no more content in the parent element and the parent element is not an A element [??????]
13666 							if (!$closed && $this->blk[$this->blklvl]['tag'] == 'P' && $endtag != 'P' && (in_array($endtag, $this->outerblocktags) || in_array($endtag, $this->innerblocktags))) {
13667 								$this->tag->CloseTag('P', $a, $i);
13668 								$closed = true;
13669 							}
13670 							// option end tag may be omitted if there is no more content in the parent element
13671 							if (!$closed && $this->blk[$this->blklvl]['tag'] == 'OPTION' && $endtag != 'OPTION' && (in_array($endtag, $this->outerblocktags) || in_array($endtag, $this->innerblocktags))) {
13672 								$this->tag->CloseTag('OPTION', $a, $i);
13673 								$closed = true;
13674 							}
13675 						}
13676 						/* -- TABLES -- */
13677 						// Check for Table tags where HTML specifies optional end tags,
13678 						if ($endtag == 'TABLE') {
13679 							if ($this->lastoptionaltag == 'THEAD' || $this->lastoptionaltag == 'TBODY' || $this->lastoptionaltag == 'TFOOT') {
13680 								$this->tag->CloseTag($this->lastoptionaltag, $a, $i);
13681 							}
13682 							if ($this->lastoptionaltag == 'TR') {
13683 								$this->tag->CloseTag('TR', $a, $i);
13684 							}
13685 							if ($this->lastoptionaltag == 'TD' || $this->lastoptionaltag == 'TH') {
13686 								$this->tag->CloseTag($this->lastoptionaltag, $a, $i);
13687 								$this->tag->CloseTag('TR', $a, $i);
13688 							}
13689 						}
13690 						if ($endtag == 'THEAD' || $endtag == 'TBODY' || $endtag == 'TFOOT') {
13691 							if ($this->lastoptionaltag == 'TR') {
13692 								$this->tag->CloseTag('TR', $a, $i);
13693 							}
13694 							if ($this->lastoptionaltag == 'TD' || $this->lastoptionaltag == 'TH') {
13695 								$this->tag->CloseTag($this->lastoptionaltag, $a, $i);
13696 								$this->tag->CloseTag('TR', $a, $i);
13697 							}
13698 						}
13699 						if ($endtag == 'TR') {
13700 							if ($this->lastoptionaltag == 'TD' || $this->lastoptionaltag == 'TH') {
13701 								$this->tag->CloseTag($this->lastoptionaltag, $a, $i);
13702 							}
13703 						}
13704 						/* -- END TABLES -- */
13705 					}
13706 
13707 
13708 					// mPDF 6
13709 					if ($this->blk[$this->blklvl]['hide']) {
13710 						if (in_array($endtag, $this->outerblocktags) || in_array($endtag, $this->innerblocktags)) {
13711 							unset($this->blk[$this->blklvl]);
13712 							$this->blklvl--;
13713 						}
13714 						continue;
13715 					}
13716 
13717 					// mPDF 6
13718 					$this->tag->CloseTag($endtag, $a, $i); // mPDF 6
13719 				} else { // OPENING TAG
13720 					if ($this->blk[$this->blklvl]['hide']) {
13721 						if (strpos($e, ' ')) {
13722 							$te = strtoupper(substr($e, 0, strpos($e, ' ')));
13723 						} else {
13724 							$te = strtoupper($e);
13725 						}
13726 						// mPDF 6
13727 						if ($te == 'THEAD' || $te == 'TBODY' || $te == 'TFOOT' || $te == 'TR' || $te == 'TD' || $te == 'TH') {
13728 							$this->lastoptionaltag = $te;
13729 						}
13730 						if (in_array($te, $this->outerblocktags) || in_array($te, $this->innerblocktags)) {
13731 							$this->blklvl++;
13732 							$this->blk[$this->blklvl]['hide'] = true;
13733 							$this->blk[$this->blklvl]['tag'] = $te; // mPDF 6
13734 						}
13735 						continue;
13736 					}
13737 
13738 					/* -- CSS-POSITION -- */
13739 					if ($this->inFixedPosBlock) {
13740 						if (strpos($e, ' ')) {
13741 							$te = strtoupper(substr($e, 0, strpos($e, ' ')));
13742 						} else {
13743 							$te = strtoupper($e);
13744 						}
13745 						$this->fixedPosBlock .= '<' . $e . '>';
13746 						if (in_array($te, $this->outerblocktags) || in_array($te, $this->innerblocktags)) {
13747 							$this->fixedPosBlockDepth++;
13748 						}
13749 						continue;
13750 					}
13751 					/* -- END CSS-POSITION -- */
13752 					$regexp = '|=\'(.*?)\'|s'; // eliminate single quotes, if any
13753 					$e = preg_replace($regexp, "=\"\$1\"", $e);
13754 					// changes anykey=anyvalue to anykey="anyvalue" (only do this inside [some] tags)
13755 					if (substr($e, 0, 10) != 'pageheader' && substr($e, 0, 10) != 'pagefooter' && substr($e, 0, 12) != 'tocpagebreak' && substr($e, 0, 10) != 'indexentry' && substr($e, 0, 8) != 'tocentry') { // mPDF 6  (ZZZ99H)
13756 						$regexp = '| (\\w+?)=([^\\s>"]+)|si';
13757 						$e = preg_replace($regexp, " \$1=\"\$2\"", $e);
13758 					}
13759 
13760 					$e = preg_replace('/ (\\S+?)\s*=\s*"/i', " \\1=\"", $e);
13761 
13762 					// Fix path values, if needed
13763 					$orig_srcpath = '';
13764 					if ((stristr($e, "href=") !== false) or ( stristr($e, "src=") !== false)) {
13765 						$regexp = '/ (href|src)\s*=\s*"(.*?)"/i';
13766 						preg_match($regexp, $e, $auxiliararray);
13767 						if (isset($auxiliararray[2])) {
13768 							$path = $auxiliararray[2];
13769 						} else {
13770 							$path = '';
13771 						}
13772 						if (trim($path) != '' && !(stristr($e, "src=") !== false && substr($path, 0, 4) == 'var:') && substr($path, 0, 1) != '@') {
13773 							$path = htmlspecialchars_decode($path); // mPDF 5.7.4 URLs
13774 							$orig_srcpath = $path;
13775 							$this->GetFullPath($path);
13776 							$regexp = '/ (href|src)="(.*?)"/i';
13777 							$e = preg_replace($regexp, ' \\1="' . $path . '"', $e);
13778 						}
13779 					}//END of Fix path values
13780 					// Extract attributes
13781 					$contents = [];
13782 					$contents1 = [];
13783 					$contents2 = [];
13784 					// Changed to allow style="background: url('bg.jpg')"
13785 					// Changed to improve performance; maximum length of \S (attribute) = 16
13786 					// Increase allowed attribute name to 32 - cutting off "toc-even-header-name" etc.
13787 					preg_match_all('/\\S{1,32}=["][^"]*["]/', $e, $contents1);
13788 					preg_match_all('/\\S{1,32}=[\'][^\']*[\']/i', $e, $contents2);
13789 
13790 					$contents = array_merge($contents1, $contents2);
13791 					preg_match('/\\S+/', $e, $a2);
13792 					$tag = (isset($a2[0]) ? strtoupper($a2[0]) : '');
13793 					$attr = [];
13794 					if ($orig_srcpath) {
13795 						$attr['ORIG_SRC'] = $orig_srcpath;
13796 					}
13797 					if (!empty($contents)) {
13798 						foreach ($contents[0] as $v) {
13799 							// Changed to allow style="background: url('bg.jpg')"
13800 							if (preg_match('/^([^=]*)=["]?([^"]*)["]?$/', $v, $a3) || preg_match('/^([^=]*)=[\']?([^\']*)[\']?$/', $v, $a3)) {
13801 								if (strtoupper($a3[1]) == 'ID' || strtoupper($a3[1]) == 'CLASS') { // 4.2.013 Omits STYLE
13802 									$attr[strtoupper($a3[1])] = trim(strtoupper($a3[2]));
13803 								} // includes header-style-right etc. used for <pageheader>
13804 								elseif (preg_match('/^(HEADER|FOOTER)-STYLE/i', $a3[1])) {
13805 									$attr[strtoupper($a3[1])] = trim(strtoupper($a3[2]));
13806 								} else {
13807 									$attr[strtoupper($a3[1])] = trim($a3[2]);
13808 								}
13809 							}
13810 						}
13811 					}
13812 					$this->tag->OpenTag($tag, $attr, $a, $i); // mPDF 6
13813 					/* -- CSS-POSITION -- */
13814 					if ($this->inFixedPosBlock) {
13815 						$this->fixedPosBlockBBox = [$tag, $attr, $this->x, $this->y];
13816 						$this->fixedPosBlock = '';
13817 						$this->fixedPosBlockDepth = 1;
13818 					}
13819 					/* -- END CSS-POSITION -- */
13820 					if (preg_match('/\/$/', $e)) {
13821 						$this->tag->CloseTag($tag, $a, $i);
13822 					}
13823 				}
13824 			} // end TAG
13825 		} // end of	foreach($a as $i=>$e)
13826 
13827 		if ($close) {
13828 			// Close any open block tags
13829 			for ($b = $this->blklvl; $b > 0; $b--) {
13830 				$this->tag->CloseTag($this->blk[$b]['tag'], $a, $i);
13831 			}
13832 
13833 			// Output any text left in buffer
13834 			if (count($this->textbuffer) && !$parseonly) {
13835 				$this->printbuffer($this->textbuffer);
13836 			}
13837 			if (!$parseonly) {
13838 				$this->textbuffer = [];
13839 			}
13840 
13841 			/* -- CSS-FLOAT -- */
13842 			// If ended with a float, need to move to end page
13843 			$currpos = $this->page * 1000 + $this->y;
13844 			if (isset($this->blk[$this->blklvl]['float_endpos']) && $this->blk[$this->blklvl]['float_endpos'] > $currpos) {
13845 				$old_page = $this->page;
13846 				$new_page = intval($this->blk[$this->blklvl]['float_endpos'] / 1000);
13847 				if ($old_page != $new_page) {
13848 					$s = $this->PrintPageBackgrounds();
13849 					// Writes after the marker so not overwritten later by page background etc.
13850 					$this->pages[$this->page] = preg_replace('/(___BACKGROUND___PATTERNS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->pages[$this->page]);
13851 					$this->pageBackgrounds = [];
13852 					$this->page = $new_page;
13853 					$this->ResetMargins();
13854 					$this->Reset();
13855 					$this->pageoutput[$this->page] = [];
13856 				}
13857 				$this->y = (round($this->blk[$this->blklvl]['float_endpos'] * 1000) % 1000000) / 1000; // mod changes operands to integers before processing
13858 			}
13859 			/* -- END CSS-FLOAT -- */
13860 
13861 			/* -- CSS-IMAGE-FLOAT -- */
13862 			$this->printfloatbuffer();
13863 			/* -- END CSS-IMAGE-FLOAT -- */
13864 
13865 			// Create Internal Links, if needed
13866 			if (!empty($this->internallink)) {
13867 
13868 				foreach ($this->internallink as $k => $v) {
13869 
13870 					if (strpos($k, "#") !== false) {
13871 						continue;
13872 					}
13873 
13874 					if (!is_array($v)) {
13875 						continue;
13876 					}
13877 
13878 					$ypos = $v['Y'];
13879 					$pagenum = $v['PAGE'];
13880 					$sharp = "#";
13881 
13882 					while (array_key_exists($sharp . $k, $this->internallink)) {
13883 						$internallink = $this->internallink[$sharp . $k];
13884 						$this->SetLink($internallink, $ypos, $pagenum);
13885 						$sharp .= "#";
13886 					}
13887 				}
13888 			}
13889 
13890 			$this->bufferoutput = false;
13891 
13892 			/* -- CSS-POSITION -- */
13893 			if (count($this->fixedPosBlockSave)) {
13894 				foreach ($this->fixedPosBlockSave as $fpbs) {
13895 					$old_page = $this->page;
13896 					$this->page = $fpbs[2];
13897 					$this->WriteFixedPosHTML($fpbs[0], 0, 0, 100, 100, 'auto', $fpbs[1]);  // 0,0,10,10 are overwritten by bbox
13898 					$this->page = $old_page;
13899 				}
13900 				$this->fixedPosBlockSave = [];
13901 			}
13902 			/* -- END CSS-POSITION -- */
13903 		}
13904 	}
13905 
13906 	/* -- CSS-POSITION -- */
13907 
13908 	function WriteFixedPosHTML($html, $x, $y, $w, $h, $overflow = 'visible', $bounding = [])
13909 	{
13910 		// $overflow can be 'hidden', 'visible' or 'auto' - 'auto' causes autofit to size
13911 		// Annotations disabled - enabled in mPDF 5.0
13912 		// Links do work
13913 		// Will always go on current page (or start Page 1 if required)
13914 		// Probably INCOMPATIBLE WITH keep with table, columns etc.
13915 		// Called externally or interally via <div style="position: [fixed|absolute]">
13916 		// When used internally, $x $y $w $h and $overflow are all overridden by $bounding
13917 
13918 		$overflow = strtolower($overflow);
13919 		if ($this->state == 0) {
13920 			$this->AddPage($this->CurOrientation);
13921 		}
13922 		$save_y = $this->y;
13923 		$save_x = $this->x;
13924 		$this->fullImageHeight = $this->h;
13925 		$save_cols = false;
13926 		/* -- COLUMNS -- */
13927 		if ($this->ColActive) {
13928 			$save_cols = true;
13929 			$save_nbcol = $this->NbCol; // other values of gap and vAlign will not change by setting Columns off
13930 			$this->SetColumns(0);
13931 		}
13932 		/* -- END COLUMNS -- */
13933 		$save_annots = $this->title2annots; // *ANNOTATIONS*
13934 		$this->writingHTMLheader = true; // a FIX to stop pagebreaks etc.
13935 		$this->writingHTMLfooter = true;
13936 		$this->InFooter = true; // suppresses autopagebreaks
13937 		$save_bgs = $this->pageBackgrounds;
13938 		$checkinnerhtml = preg_replace('/\s/', '', $html);
13939 		$rotate = 0;
13940 
13941 		if ($w > $this->w) {
13942 			$x = 0;
13943 			$w = $this->w;
13944 		}
13945 		if ($h > $this->h) {
13946 			$y = 0;
13947 			$h = $this->h;
13948 		}
13949 		if ($x > $this->w) {
13950 			$x = $this->w - $w;
13951 		}
13952 		if ($y > $this->h) {
13953 			$y = $this->h - $h;
13954 		}
13955 
13956 		if (!empty($bounding)) {
13957 			// $cont_ containing block = full physical page (position: absolute) or page inside margins (position: fixed)
13958 			// $bbox_ Bounding box is the <div> which is positioned absolutely/fixed
13959 			// top/left/right/bottom/width/height/background*/border*/padding*/margin* are taken from bounding
13960 			// font*[family/size/style/weight]/line-height/text*[align/decoration/transform/indent]/color are transferred to $inner
13961 			// as an enclosing <div> (after having checked ID/CLASS)
13962 			// $x, $y, $w, $h are inside of $bbox_ = containing box for $inner_
13963 			// $inner_ InnerHTML is the contents of that block to be output
13964 			$tag = $bounding[0];
13965 			$attr = $bounding[1];
13966 			$orig_x0 = $bounding[2];
13967 			$orig_y0 = $bounding[3];
13968 
13969 			// As in WriteHTML() initialising
13970 			$this->blklvl = 0;
13971 			$this->lastblocklevelchange = 0;
13972 			$this->blk = [];
13973 			$this->initialiseBlock($this->blk[0]);
13974 
13975 			$this->blk[0]['width'] = & $this->pgwidth;
13976 			$this->blk[0]['inner_width'] = & $this->pgwidth;
13977 
13978 			$this->blk[0]['blockContext'] = $this->blockContext;
13979 
13980 			$properties = $this->cssManager->MergeCSS('BLOCK', 'BODY', '');
13981 			$this->setCSS($properties, '', 'BODY');
13982 			$this->blklvl = 1;
13983 			$this->initialiseBlock($this->blk[1]);
13984 			$this->blk[1]['tag'] = $tag;
13985 			$this->blk[1]['attr'] = $attr;
13986 			$this->Reset();
13987 			$p = $this->cssManager->MergeCSS('BLOCK', $tag, $attr);
13988 			if (isset($p['ROTATE']) && ($p['ROTATE'] == 90 || $p['ROTATE'] == -90 || $p['ROTATE'] == 180)) {
13989 				$rotate = $p['ROTATE'];
13990 			} // mPDF 6
13991 			if (isset($p['OVERFLOW'])) {
13992 				$overflow = strtolower($p['OVERFLOW']);
13993 			}
13994 			if (strtolower($p['POSITION']) == 'fixed') {
13995 				$cont_w = $this->pgwidth; // $this->blk[0]['inner_width'];
13996 				$cont_h = $this->h - $this->tMargin - $this->bMargin;
13997 				$cont_x = $this->lMargin;
13998 				$cont_y = $this->tMargin;
13999 			} else {
14000 				$cont_w = $this->w; // ABSOLUTE;
14001 				$cont_h = $this->h;
14002 				$cont_x = 0;
14003 				$cont_y = 0;
14004 			}
14005 
14006 			// Pass on in-line properties to the innerhtml
14007 			$css = '';
14008 			if (isset($p['TEXT-ALIGN'])) {
14009 				$css .= 'text-align: ' . strtolower($p['TEXT-ALIGN']) . '; ';
14010 			}
14011 			if (isset($p['TEXT-TRANSFORM'])) {
14012 				$css .= 'text-transform: ' . strtolower($p['TEXT-TRANSFORM']) . '; ';
14013 			}
14014 			if (isset($p['TEXT-INDENT'])) {
14015 				$css .= 'text-indent: ' . strtolower($p['TEXT-INDENT']) . '; ';
14016 			}
14017 			if (isset($p['TEXT-DECORATION'])) {
14018 				$css .= 'text-decoration: ' . strtolower($p['TEXT-DECORATION']) . '; ';
14019 			}
14020 			if (isset($p['FONT-FAMILY'])) {
14021 				$css .= 'font-family: ' . strtolower($p['FONT-FAMILY']) . '; ';
14022 			}
14023 			if (isset($p['FONT-STYLE'])) {
14024 				$css .= 'font-style: ' . strtolower($p['FONT-STYLE']) . '; ';
14025 			}
14026 			if (isset($p['FONT-WEIGHT'])) {
14027 				$css .= 'font-weight: ' . strtolower($p['FONT-WEIGHT']) . '; ';
14028 			}
14029 			if (isset($p['FONT-SIZE'])) {
14030 				$css .= 'font-size: ' . strtolower($p['FONT-SIZE']) . '; ';
14031 			}
14032 			if (isset($p['LINE-HEIGHT'])) {
14033 				$css .= 'line-height: ' . strtolower($p['LINE-HEIGHT']) . '; ';
14034 			}
14035 			if (isset($p['TEXT-SHADOW'])) {
14036 				$css .= 'text-shadow: ' . strtolower($p['TEXT-SHADOW']) . '; ';
14037 			}
14038 			if (isset($p['LETTER-SPACING'])) {
14039 				$css .= 'letter-spacing: ' . strtolower($p['LETTER-SPACING']) . '; ';
14040 			}
14041 			// mPDF 6
14042 			if (isset($p['FONT-VARIANT-POSITION'])) {
14043 				$css .= 'font-variant-position: ' . strtolower($p['FONT-VARIANT-POSITION']) . '; ';
14044 			}
14045 			if (isset($p['FONT-VARIANT-CAPS'])) {
14046 				$css .= 'font-variant-caps: ' . strtolower($p['FONT-VARIANT-CAPS']) . '; ';
14047 			}
14048 			if (isset($p['FONT-VARIANT-LIGATURES'])) {
14049 				$css .= 'font-variant-ligatures: ' . strtolower($p['FONT-VARIANT-LIGATURES']) . '; ';
14050 			}
14051 			if (isset($p['FONT-VARIANT-NUMERIC'])) {
14052 				$css .= 'font-variant-numeric: ' . strtolower($p['FONT-VARIANT-NUMERIC']) . '; ';
14053 			}
14054 			if (isset($p['FONT-VARIANT-ALTERNATES'])) {
14055 				$css .= 'font-variant-alternates: ' . strtolower($p['FONT-VARIANT-ALTERNATES']) . '; ';
14056 			}
14057 			if (isset($p['FONT-FEATURE-SETTINGS'])) {
14058 				$css .= 'font-feature-settings: ' . strtolower($p['FONT-FEATURE-SETTINGS']) . '; ';
14059 			}
14060 			if (isset($p['FONT-LANGUAGE-OVERRIDE'])) {
14061 				$css .= 'font-language-override: ' . strtolower($p['FONT-LANGUAGE-OVERRIDE']) . '; ';
14062 			}
14063 			if (isset($p['FONT-KERNING'])) {
14064 				$css .= 'font-kerning: ' . strtolower($p['FONT-KERNING']) . '; ';
14065 			}
14066 
14067 			if (isset($p['COLOR'])) {
14068 				$css .= 'color: ' . strtolower($p['COLOR']) . '; ';
14069 			}
14070 			if (isset($p['Z-INDEX'])) {
14071 				$css .= 'z-index: ' . $p['Z-INDEX'] . '; ';
14072 			}
14073 			if ($css) {
14074 				$html = '<div style="' . $css . '">' . $html . '</div>';
14075 			}
14076 			// Copy over (only) the properties to set for border and background
14077 			$pb = [];
14078 			$pb['MARGIN-TOP'] = (isset($p['MARGIN-TOP']) ? $p['MARGIN-TOP'] : '');
14079 			$pb['MARGIN-RIGHT'] = (isset($p['MARGIN-RIGHT']) ? $p['MARGIN-RIGHT'] : '');
14080 			$pb['MARGIN-BOTTOM'] = (isset($p['MARGIN-BOTTOM']) ? $p['MARGIN-BOTTOM'] : '');
14081 			$pb['MARGIN-LEFT'] = (isset($p['MARGIN-LEFT']) ? $p['MARGIN-LEFT'] : '');
14082 			$pb['PADDING-TOP'] = (isset($p['PADDING-TOP']) ? $p['PADDING-TOP'] : '');
14083 			$pb['PADDING-RIGHT'] = (isset($p['PADDING-RIGHT']) ? $p['PADDING-RIGHT'] : '');
14084 			$pb['PADDING-BOTTOM'] = (isset($p['PADDING-BOTTOM']) ? $p['PADDING-BOTTOM'] : '');
14085 			$pb['PADDING-LEFT'] = (isset($p['PADDING-LEFT']) ? $p['PADDING-LEFT'] : '');
14086 			$pb['BORDER-TOP'] = (isset($p['BORDER-TOP']) ? $p['BORDER-TOP'] : '');
14087 			$pb['BORDER-RIGHT'] = (isset($p['BORDER-RIGHT']) ? $p['BORDER-RIGHT'] : '');
14088 			$pb['BORDER-BOTTOM'] = (isset($p['BORDER-BOTTOM']) ? $p['BORDER-BOTTOM'] : '');
14089 			$pb['BORDER-LEFT'] = (isset($p['BORDER-LEFT']) ? $p['BORDER-LEFT'] : '');
14090 			if (isset($p['BORDER-TOP-LEFT-RADIUS-H'])) {
14091 				$pb['BORDER-TOP-LEFT-RADIUS-H'] = $p['BORDER-TOP-LEFT-RADIUS-H'];
14092 			}
14093 			if (isset($p['BORDER-TOP-LEFT-RADIUS-V'])) {
14094 				$pb['BORDER-TOP-LEFT-RADIUS-V'] = $p['BORDER-TOP-LEFT-RADIUS-V'];
14095 			}
14096 			if (isset($p['BORDER-TOP-RIGHT-RADIUS-H'])) {
14097 				$pb['BORDER-TOP-RIGHT-RADIUS-H'] = $p['BORDER-TOP-RIGHT-RADIUS-H'];
14098 			}
14099 			if (isset($p['BORDER-TOP-RIGHT-RADIUS-V'])) {
14100 				$pb['BORDER-TOP-RIGHT-RADIUS-V'] = $p['BORDER-TOP-RIGHT-RADIUS-V'];
14101 			}
14102 			if (isset($p['BORDER-BOTTOM-LEFT-RADIUS-H'])) {
14103 				$pb['BORDER-BOTTOM-LEFT-RADIUS-H'] = $p['BORDER-BOTTOM-LEFT-RADIUS-H'];
14104 			}
14105 			if (isset($p['BORDER-BOTTOM-LEFT-RADIUS-V'])) {
14106 				$pb['BORDER-BOTTOM-LEFT-RADIUS-V'] = $p['BORDER-BOTTOM-LEFT-RADIUS-V'];
14107 			}
14108 			if (isset($p['BORDER-BOTTOM-RIGHT-RADIUS-H'])) {
14109 				$pb['BORDER-BOTTOM-RIGHT-RADIUS-H'] = $p['BORDER-BOTTOM-RIGHT-RADIUS-H'];
14110 			}
14111 			if (isset($p['BORDER-BOTTOM-RIGHT-RADIUS-V'])) {
14112 				$pb['BORDER-BOTTOM-RIGHT-RADIUS-V'] = $p['BORDER-BOTTOM-RIGHT-RADIUS-V'];
14113 			}
14114 			if (isset($p['BACKGROUND-COLOR'])) {
14115 				$pb['BACKGROUND-COLOR'] = $p['BACKGROUND-COLOR'];
14116 			}
14117 			if (isset($p['BOX-SHADOW'])) {
14118 				$pb['BOX-SHADOW'] = $p['BOX-SHADOW'];
14119 			}
14120 			/* -- BACKGROUNDS -- */
14121 			if (isset($p['BACKGROUND-IMAGE'])) {
14122 				$pb['BACKGROUND-IMAGE'] = $p['BACKGROUND-IMAGE'];
14123 			}
14124 			if (isset($p['BACKGROUND-IMAGE-RESIZE'])) {
14125 				$pb['BACKGROUND-IMAGE-RESIZE'] = $p['BACKGROUND-IMAGE-RESIZE'];
14126 			}
14127 			if (isset($p['BACKGROUND-IMAGE-OPACITY'])) {
14128 				$pb['BACKGROUND-IMAGE-OPACITY'] = $p['BACKGROUND-IMAGE-OPACITY'];
14129 			}
14130 			if (isset($p['BACKGROUND-REPEAT'])) {
14131 				$pb['BACKGROUND-REPEAT'] = $p['BACKGROUND-REPEAT'];
14132 			}
14133 			if (isset($p['BACKGROUND-POSITION'])) {
14134 				$pb['BACKGROUND-POSITION'] = $p['BACKGROUND-POSITION'];
14135 			}
14136 			if (isset($p['BACKGROUND-GRADIENT'])) {
14137 				$pb['BACKGROUND-GRADIENT'] = $p['BACKGROUND-GRADIENT'];
14138 			}
14139 			if (isset($p['BACKGROUND-SIZE'])) {
14140 				$pb['BACKGROUND-SIZE'] = $p['BACKGROUND-SIZE'];
14141 			}
14142 			if (isset($p['BACKGROUND-ORIGIN'])) {
14143 				$pb['BACKGROUND-ORIGIN'] = $p['BACKGROUND-ORIGIN'];
14144 			}
14145 			if (isset($p['BACKGROUND-CLIP'])) {
14146 				$pb['BACKGROUND-CLIP'] = $p['BACKGROUND-CLIP'];
14147 			}
14148 
14149 			/* -- END BACKGROUNDS -- */
14150 
14151 			$this->setCSS($pb, 'BLOCK', $tag);
14152 
14153 			// ================================================================
14154 			$bbox_br = $this->blk[1]['border_right']['w'];
14155 			$bbox_bl = $this->blk[1]['border_left']['w'];
14156 			$bbox_bt = $this->blk[1]['border_top']['w'];
14157 			$bbox_bb = $this->blk[1]['border_bottom']['w'];
14158 			$bbox_pr = $this->blk[1]['padding_right'];
14159 			$bbox_pl = $this->blk[1]['padding_left'];
14160 			$bbox_pt = $this->blk[1]['padding_top'];
14161 			$bbox_pb = $this->blk[1]['padding_bottom'];
14162 			$bbox_mr = $this->blk[1]['margin_right'];
14163 			if (isset($p['MARGIN-RIGHT']) && strtolower($p['MARGIN-RIGHT']) == 'auto') {
14164 				$bbox_mr = 'auto';
14165 			}
14166 			$bbox_ml = $this->blk[1]['margin_left'];
14167 			if (isset($p['MARGIN-LEFT']) && strtolower($p['MARGIN-LEFT']) == 'auto') {
14168 				$bbox_ml = 'auto';
14169 			}
14170 			$bbox_mt = $this->blk[1]['margin_top'];
14171 			if (isset($p['MARGIN-TOP']) && strtolower($p['MARGIN-TOP']) == 'auto') {
14172 				$bbox_mt = 'auto';
14173 			}
14174 			$bbox_mb = $this->blk[1]['margin_bottom'];
14175 			if (isset($p['MARGIN-BOTTOM']) && strtolower($p['MARGIN-BOTTOM']) == 'auto') {
14176 				$bbox_mb = 'auto';
14177 			}
14178 			if (isset($p['LEFT']) && strtolower($p['LEFT']) != 'auto') {
14179 				$bbox_left = $this->sizeConverter->convert($p['LEFT'], $cont_w, $this->FontSize, false);
14180 			} else {
14181 				$bbox_left = 'auto';
14182 			}
14183 			if (isset($p['TOP']) && strtolower($p['TOP']) != 'auto') {
14184 				$bbox_top = $this->sizeConverter->convert($p['TOP'], $cont_h, $this->FontSize, false);
14185 			} else {
14186 				$bbox_top = 'auto';
14187 			}
14188 			if (isset($p['RIGHT']) && strtolower($p['RIGHT']) != 'auto') {
14189 				$bbox_right = $this->sizeConverter->convert($p['RIGHT'], $cont_w, $this->FontSize, false);
14190 			} else {
14191 				$bbox_right = 'auto';
14192 			}
14193 			if (isset($p['BOTTOM']) && strtolower($p['BOTTOM']) != 'auto') {
14194 				$bbox_bottom = $this->sizeConverter->convert($p['BOTTOM'], $cont_h, $this->FontSize, false);
14195 			} else {
14196 				$bbox_bottom = 'auto';
14197 			}
14198 			if (isset($p['WIDTH']) && strtolower($p['WIDTH']) != 'auto') {
14199 				$inner_w = $this->sizeConverter->convert($p['WIDTH'], $cont_w, $this->FontSize, false);
14200 			} else {
14201 				$inner_w = 'auto';
14202 			}
14203 			if (isset($p['HEIGHT']) && strtolower($p['HEIGHT']) != 'auto') {
14204 				$inner_h = $this->sizeConverter->convert($p['HEIGHT'], $cont_h, $this->FontSize, false);
14205 			} else {
14206 				$inner_h = 'auto';
14207 			}
14208 
14209 			// If bottom or right pos are set and not left / top - save this to adjust rotated block later
14210 			if ($rotate == 90 || $rotate == -90) { // mPDF 6
14211 				if ($bbox_left === 'auto' && $bbox_right !== 'auto') {
14212 					$rot_rpos = $bbox_right;
14213 				} else {
14214 					$rot_rpos = false;
14215 				}
14216 				if ($bbox_top === 'auto' && $bbox_bottom !== 'auto') {
14217 					$rot_bpos = $bbox_bottom;
14218 				} else {
14219 					$rot_bpos = false;
14220 				}
14221 			}
14222 
14223 			// ================================================================
14224 			if ($checkinnerhtml == '' && $inner_h === 'auto') {
14225 				$inner_h = 0.0001;
14226 			}
14227 			if ($checkinnerhtml == '' && $inner_w === 'auto') {
14228 				$inner_w = 2 * $this->GetCharWidth('W', false);
14229 			}
14230 			// ================================================================
14231 			// Algorithm from CSS2.1  See http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-height
14232 			// mPD 5.3.14
14233 			// Special case (not CSS) if all not specified, centre vertically on page
14234 			$bbox_top_orig = '';
14235 			if ($bbox_top === 'auto' && $inner_h === 'auto' && $bbox_bottom === 'auto' && $bbox_mt === 'auto' && $bbox_mb === 'auto') {
14236 				$bbox_top_orig = $bbox_top;
14237 				if ($bbox_mt === 'auto') {
14238 					$bbox_mt = 0;
14239 				}
14240 				if ($bbox_mb === 'auto') {
14241 					$bbox_mb = 0;
14242 				}
14243 				$bbox_top = $orig_y0 - $bbox_mt - $cont_y;
14244 				// solve for $bbox_bottom when content_h known - $inner_h=='auto' && $bbox_bottom=='auto'
14245 			} // mPD 5.3.14
14246 			elseif ($bbox_top === 'auto' && $inner_h === 'auto' && $bbox_bottom === 'auto') {
14247 				$bbox_top_orig = $bbox_top = $orig_y0 - $cont_y;
14248 				if ($bbox_mt === 'auto') {
14249 					$bbox_mt = 0;
14250 				}
14251 				if ($bbox_mb === 'auto') {
14252 					$bbox_mb = 0;
14253 				}
14254 				// solve for $bbox_bottom when content_h known - $inner_h=='auto' && $bbox_bottom=='auto'
14255 			} elseif ($bbox_top !== 'auto' && $inner_h !== 'auto' && $bbox_bottom !== 'auto') {
14256 				if ($bbox_mt === 'auto' && $bbox_mb === 'auto') {
14257 					$x = $cont_h - $bbox_top - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_bottom;
14258 					$bbox_mt = $bbox_mb = ($x / 2);
14259 				} elseif ($bbox_mt === 'auto') {
14260 					$bbox_mt = $cont_h - $bbox_top - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mb - $bbox_bottom;
14261 				} elseif ($bbox_mb === 'auto') {
14262 					$bbox_mb = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_bottom;
14263 				} else {
14264 					$bbox_bottom = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mt;
14265 				}
14266 			} else {
14267 				if ($bbox_mt === 'auto') {
14268 					$bbox_mt = 0;
14269 				}
14270 				if ($bbox_mb === 'auto') {
14271 					$bbox_mb = 0;
14272 				}
14273 				if ($bbox_top === 'auto' && $inner_h === 'auto' && $bbox_bottom !== 'auto') {
14274 					// solve for $bbox_top when content_h known - $inner_h=='auto' && $bbox_top =='auto'
14275 				} elseif ($bbox_top === 'auto' && $bbox_bottom === 'auto' && $inner_h !== 'auto') {
14276 					$bbox_top = $orig_y0 - $bbox_mt - $cont_y;
14277 					$bbox_bottom = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mt;
14278 				} elseif ($inner_h === 'auto' && $bbox_bottom === 'auto' && $bbox_top !== 'auto') {
14279 					// solve for $bbox_bottom when content_h known - $inner_h=='auto' && $bbox_bottom=='auto'
14280 				} elseif ($bbox_top === 'auto' && $inner_h !== 'auto' && $bbox_bottom !== 'auto') {
14281 					$bbox_top = $cont_h - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mt - $bbox_bottom;
14282 				} elseif ($inner_h === 'auto' && $bbox_top !== 'auto' && $bbox_bottom !== 'auto') {
14283 					$inner_h = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $bbox_pb - $bbox_bb - $bbox_mt - $bbox_bottom;
14284 				} elseif ($bbox_bottom === 'auto' && $bbox_top !== 'auto' && $inner_h !== 'auto') {
14285 					$bbox_bottom = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mt;
14286 				}
14287 			}
14288 
14289 			// THEN DO SAME FOR WIDTH
14290 			// http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width
14291 			if ($bbox_left === 'auto' && $inner_w === 'auto' && $bbox_right === 'auto') {
14292 				if ($bbox_ml === 'auto') {
14293 					$bbox_ml = 0;
14294 				}
14295 				if ($bbox_mr === 'auto') {
14296 					$bbox_mr = 0;
14297 				}
14298 				// IF containing element RTL, should set $bbox_right
14299 				$bbox_left = $orig_x0 - $bbox_ml - $cont_x;
14300 				// solve for $bbox_right when content_w known - $inner_w=='auto' && $bbox_right=='auto'
14301 			} elseif ($bbox_left !== 'auto' && $inner_w !== 'auto' && $bbox_right !== 'auto') {
14302 				if ($bbox_ml === 'auto' && $bbox_mr === 'auto') {
14303 					$x = $cont_w - $bbox_left - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_right;
14304 					$bbox_ml = $bbox_mr = ($x / 2);
14305 				} elseif ($bbox_ml === 'auto') {
14306 					$bbox_ml = $cont_w - $bbox_left - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_mr - $bbox_right;
14307 				} elseif ($bbox_mr === 'auto') {
14308 					$bbox_mr = $cont_w - $bbox_left - $bbox_ml - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_right;
14309 				} else {
14310 					$bbox_right = $cont_w - $bbox_left - $bbox_ml - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_ml;
14311 				}
14312 			} else {
14313 				if ($bbox_ml === 'auto') {
14314 					$bbox_ml = 0;
14315 				}
14316 				if ($bbox_mr === 'auto') {
14317 					$bbox_mr = 0;
14318 				}
14319 				if ($bbox_left === 'auto' && $inner_w === 'auto' && $bbox_right !== 'auto') {
14320 					// solve for $bbox_left when content_w known - $inner_w=='auto' && $bbox_left =='auto'
14321 				} elseif ($bbox_left === 'auto' && $bbox_right === 'auto' && $inner_w !== 'auto') {
14322 					// IF containing element RTL, should set $bbox_right
14323 					$bbox_left = $orig_x0 - $bbox_ml - $cont_x;
14324 					$bbox_right = $cont_w - $bbox_left - $bbox_ml - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_ml;
14325 				} elseif ($inner_w === 'auto' && $bbox_right === 'auto' && $bbox_left !== 'auto') {
14326 					// solve for $bbox_right when content_w known - $inner_w=='auto' && $bbox_right=='auto'
14327 				} elseif ($bbox_left === 'auto' && $inner_w !== 'auto' && $bbox_right !== 'auto') {
14328 					$bbox_left = $cont_w - $bbox_ml - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_ml - $bbox_right;
14329 				} elseif ($inner_w === 'auto' && $bbox_left !== 'auto' && $bbox_right !== 'auto') {
14330 					$inner_w = $cont_w - $bbox_left - $bbox_ml - $bbox_bl - $bbox_pl - $bbox_pr - $bbox_br - $bbox_ml - $bbox_right;
14331 				} elseif ($bbox_right === 'auto' && $bbox_left !== 'auto' && $inner_w !== 'auto') {
14332 					$bbox_right = $cont_w - $bbox_left - $bbox_ml - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_ml;
14333 				}
14334 			}
14335 
14336 			// ================================================================
14337 			// ================================================================
14338 			/* -- BACKGROUNDS -- */
14339 			if (isset($pb['BACKGROUND-IMAGE']) && $pb['BACKGROUND-IMAGE']) {
14340 				$ret = $this->SetBackground($pb, $this->blk[1]['inner_width']);
14341 				if ($ret) {
14342 					$this->blk[1]['background-image'] = $ret;
14343 				}
14344 			}
14345 			/* -- END BACKGROUNDS -- */
14346 
14347 			$bbox_top_auto = $bbox_top === 'auto';
14348 			$bbox_left_auto = $bbox_left === 'auto';
14349 			$bbox_right_auto = $bbox_right === 'auto';
14350 			$bbox_bottom_auto = $bbox_bottom === 'auto';
14351 
14352 			$bbox_top = is_numeric($bbox_top) ? $bbox_top : 0;
14353 			$bbox_left = is_numeric($bbox_left) ? $bbox_left : 0;
14354 			$bbox_right = is_numeric($bbox_right) ? $bbox_right : 0;
14355 			$bbox_bottom = is_numeric($bbox_bottom) ? $bbox_bottom : 0;
14356 
14357 			$y = $cont_y + $bbox_top + $bbox_mt + $bbox_bt + $bbox_pt;
14358 			$h = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $bbox_pb - $bbox_bb - $bbox_mb - $bbox_bottom;
14359 
14360 			$x = $cont_x + $bbox_left + $bbox_ml + $bbox_bl + $bbox_pl;
14361 			$w = $cont_w - $bbox_left - $bbox_ml - $bbox_bl - $bbox_pl - $bbox_pr - $bbox_br - $bbox_mr - $bbox_right;
14362 
14363 			// Set (temporary) values for x y w h to do first paint, if values are auto
14364 			if ($inner_h === 'auto' && $bbox_top_auto) {
14365 				$y = $cont_y + $bbox_mt + $bbox_bt + $bbox_pt;
14366 				$h = $cont_h - ($bbox_bottom + $bbox_mt + $bbox_mb + $bbox_bt + $bbox_bb + $bbox_pt + $bbox_pb);
14367 			} elseif ($inner_h === 'auto' && $bbox_bottom_auto) {
14368 				$y = $cont_y + $bbox_top + $bbox_mt + $bbox_bt + $bbox_pt;
14369 				$h = $cont_h - ($bbox_top + $bbox_mt + $bbox_mb + $bbox_bt + $bbox_bb + $bbox_pt + $bbox_pb);
14370 			}
14371 			if ($inner_w === 'auto' && $bbox_left_auto) {
14372 				$x = $cont_x + $bbox_ml + $bbox_bl + $bbox_pl;
14373 				$w = $cont_w - ($bbox_right + $bbox_ml + $bbox_mr + $bbox_bl + $bbox_br + $bbox_pl + $bbox_pr);
14374 			} elseif ($inner_w === 'auto' && $bbox_right_auto) {
14375 				$x = $cont_x + $bbox_left + $bbox_ml + $bbox_bl + $bbox_pl;
14376 				$w = $cont_w - ($bbox_left + $bbox_ml + $bbox_mr + $bbox_bl + $bbox_br + $bbox_pl + $bbox_pr);
14377 			}
14378 
14379 			$bbox_y = $cont_y + $bbox_top + $bbox_mt;
14380 			$bbox_x = $cont_x + $bbox_left + $bbox_ml;
14381 
14382 			$saved_block1 = $this->blk[1];
14383 
14384 			unset($p);
14385 			unset($pb);
14386 
14387 			// ================================================================
14388 			if ($inner_w === 'auto') { // do a first write
14389 				$this->lMargin = $x;
14390 				$this->rMargin = $this->w - $w - $x;
14391 
14392 				// SET POSITION & FONT VALUES
14393 				$this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
14394 				$this->pageoutput[$this->page] = [];
14395 				$this->x = $x;
14396 				$this->y = $y;
14397 				$this->HTMLheaderPageLinks = [];
14398 				$this->HTMLheaderPageAnnots = [];
14399 				$this->HTMLheaderPageForms = [];
14400 				$this->pageBackgrounds = [];
14401 				$this->maxPosR = 0;
14402 				$this->maxPosL = $this->w; // For RTL
14403 				$this->WriteHTML($html, HTMLParserMode::HTML_HEADER_BUFFER);
14404 				$inner_w = $this->maxPosR - $this->lMargin;
14405 				if ($bbox_right_auto) {
14406 					$bbox_right = $cont_w - $bbox_left - $bbox_ml - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_ml;
14407 				} elseif ($bbox_left_auto) {
14408 					$bbox_left = $cont_w - $bbox_ml - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_ml - $bbox_right;
14409 					$bbox_x = $cont_x + $bbox_left + $bbox_ml;
14410 					$inner_x = $bbox_x + $bbox_bl + $bbox_pl;
14411 					$x = $inner_x;
14412 				}
14413 
14414 				$w = $inner_w;
14415 				$bbox_y = $cont_y + $bbox_top + $bbox_mt;
14416 				$bbox_x = $cont_x + $bbox_left + $bbox_ml;
14417 			}
14418 
14419 			if ($inner_h === 'auto') { // do a first write
14420 
14421 				$this->lMargin = $x;
14422 				$this->rMargin = $this->w - $w - $x;
14423 
14424 				// SET POSITION & FONT VALUES
14425 				$this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
14426 				$this->pageoutput[$this->page] = [];
14427 				$this->x = $x;
14428 				$this->y = $y;
14429 				$this->HTMLheaderPageLinks = [];
14430 				$this->HTMLheaderPageAnnots = [];
14431 				$this->HTMLheaderPageForms = [];
14432 				$this->pageBackgrounds = [];
14433 				$this->WriteHTML($html, HTMLParserMode::HTML_HEADER_BUFFER);
14434 				$inner_h = $this->y - $y;
14435 
14436 				if ($overflow != 'hidden' && $overflow != 'visible') { // constrained
14437 					if (($this->y + $bbox_pb + $bbox_bb) > ($cont_y + $cont_h)) {
14438 						$adj = ($this->y + $bbox_pb + $bbox_bb) - ($cont_y + $cont_h);
14439 						$inner_h -= $adj;
14440 					}
14441 				}
14442 				if ($bbox_bottom_auto && $bbox_top_orig === 'auto') {
14443 					$bbox_bottom = $bbox_top = ($cont_h - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mb) / 2;
14444 					if ($overflow != 'hidden' && $overflow != 'visible') { // constrained
14445 						if ($bbox_top < 0) {
14446 							$bbox_top = 0;
14447 							$inner_h = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $bbox_pb - $bbox_bb - $bbox_mb - $bbox_bottom;
14448 						}
14449 					}
14450 					$bbox_y = $cont_y + $bbox_top + $bbox_mt;
14451 					$inner_y = $bbox_y + $bbox_bt + $bbox_pt;
14452 					$y = $inner_y;
14453 				} elseif ($bbox_bottom_auto) {
14454 					$bbox_bottom = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mb;
14455 				} elseif ($bbox_top_auto) {
14456 					$bbox_top = $cont_h - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mb - $bbox_bottom;
14457 					if ($overflow != 'hidden' && $overflow != 'visible') { // constrained
14458 						if ($bbox_top < 0) {
14459 							$bbox_top = 0;
14460 							$inner_h = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $bbox_pb - $bbox_bb - $bbox_mb - $bbox_bottom;
14461 						}
14462 					}
14463 					$bbox_y = $cont_y + $bbox_top + $bbox_mt;
14464 					$inner_y = $bbox_y + $bbox_bt + $bbox_pt;
14465 					$y = $inner_y;
14466 				}
14467 				$h = $inner_h;
14468 				$bbox_y = $cont_y + $bbox_top + $bbox_mt;
14469 				$bbox_x = $cont_x + $bbox_left + $bbox_ml;
14470 			}
14471 
14472 			$inner_w = $w;
14473 			$inner_h = $h;
14474 		}
14475 
14476 		$this->lMargin = $x;
14477 		$this->rMargin = $this->w - $w - $x;
14478 
14479 		// SET POSITION & FONT VALUES
14480 		$this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
14481 		$this->pageoutput[$this->page] = [];
14482 
14483 		$this->x = $x;
14484 		$this->y = $y;
14485 
14486 		$this->HTMLheaderPageLinks = [];
14487 		$this->HTMLheaderPageAnnots = [];
14488 		$this->HTMLheaderPageForms = [];
14489 
14490 		$this->pageBackgrounds = [];
14491 
14492 		$this->WriteHTML($html, HTMLParserMode::HTML_HEADER_BUFFER);
14493 
14494 		$actual_h = $this->y - $y;
14495 		$use_w = $w;
14496 		$use_h = $h;
14497 		$ratio = $actual_h / $use_w;
14498 
14499 		if ($overflow != 'hidden' && $overflow != 'visible') {
14500 			$target = $h / $w;
14501 			if ($target > 0) {
14502 				if (($ratio / $target) > 1) {
14503 					$nl = ceil($actual_h / $this->lineheight);
14504 					$l = $use_w * $nl;
14505 					$est_w = sqrt(($l * $this->lineheight) / $target) * 0.8;
14506 					$use_w += ($est_w - $use_w) - ($w / 100);
14507 				}
14508 				$bpcstart = ($ratio / $target);
14509 				$bpcctr = 1;
14510 
14511 				while (($ratio / $target) > 1) {
14512 					// @log 'Auto-sizing fixed-position block $bpcctr++
14513 
14514 					$this->x = $x;
14515 					$this->y = $y;
14516 
14517 					if (($ratio / $target) > 1.5 || ($ratio / $target) < 0.6) {
14518 						$use_w += ($w / $this->incrementFPR1);
14519 					} elseif (($ratio / $target) > 1.2 || ($ratio / $target) < 0.85) {
14520 						$use_w += ($w / $this->incrementFPR2);
14521 					} elseif (($ratio / $target) > 1.1 || ($ratio / $target) < 0.91) {
14522 						$use_w += ($w / $this->incrementFPR3);
14523 					} else {
14524 						$use_w += ($w / $this->incrementFPR4);
14525 					}
14526 
14527 					$use_h = $use_w * $target;
14528 					$this->rMargin = $this->w - $use_w - $x;
14529 					$this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
14530 					$this->HTMLheaderPageLinks = [];
14531 					$this->HTMLheaderPageAnnots = [];
14532 					$this->HTMLheaderPageForms = [];
14533 					$this->pageBackgrounds = [];
14534 					$this->WriteHTML($html, HTMLParserMode::HTML_HEADER_BUFFER);
14535 					$actual_h = $this->y - $y;
14536 					$ratio = $actual_h / $use_w;
14537 				}
14538 			}
14539 		}
14540 
14541 		$shrink_f = $w / $use_w;
14542 
14543 		// ================================================================
14544 
14545 		$this->pages[$this->page] .= '___BEFORE_BORDERS___';
14546 		$block_s = $this->PrintPageBackgrounds(); // Save to print later inside clipping path
14547 		$this->pageBackgrounds = [];
14548 
14549 		// ================================================================
14550 
14551 		if ($rotate == 90 || $rotate == -90) { // mPDF 6
14552 			$prerotw = $bbox_bl + $bbox_pl + $inner_w + $bbox_pr + $bbox_br;
14553 			$preroth = $bbox_bt + $bbox_pt + $inner_h + $bbox_pb + $bbox_bb;
14554 			$rot_start = " q\n";
14555 			if ($rotate == 90) {
14556 				if ($rot_rpos !== false) {
14557 					$adjw = $prerotw;
14558 				} // width before rotation
14559 				else {
14560 					$adjw = $preroth;
14561 				} // height before rotation
14562 				if ($rot_bpos !== false) {
14563 					$adjh = -$prerotw + $preroth;
14564 				} else {
14565 					$adjh = 0;
14566 				}
14567 			} else {
14568 				if ($rot_rpos !== false) {
14569 					$adjw = $prerotw - $preroth;
14570 				} else {
14571 					$adjw = 0;
14572 				}
14573 				if ($rot_bpos !== false) {
14574 					$adjh = $preroth;
14575 				} // height before rotation
14576 				else {
14577 					$adjh = $prerotw;
14578 				} // width before rotation
14579 			}
14580 			$rot_start .= $this->transformTranslate($adjw, $adjh, true) . "\n";
14581 			$rot_start .= $this->transformRotate($rotate, $bbox_x, $bbox_y, true) . "\n";
14582 			$rot_end = " Q\n";
14583 		} elseif ($rotate == 180) { // mPDF 6
14584 			$rot_start = " q\n";
14585 			$rot_start .= $this->transformTranslate($bbox_bl + $bbox_pl + $inner_w + $bbox_pr + $bbox_br, $bbox_bt + $bbox_pt + $inner_h + $bbox_pb + $bbox_bb, true) . "\n";
14586 			$rot_start .= $this->transformRotate(180, $bbox_x, $bbox_y, true) . "\n";
14587 			$rot_end = " Q\n";
14588 		} else {
14589 			$rot_start = '';
14590 			$rot_end = '';
14591 		}
14592 
14593 		// ================================================================
14594 		if (!empty($bounding)) {
14595 			// WHEN HEIGHT // BOTTOM EDGE IS KNOWN and $this->y is set to the bottom
14596 			// Re-instate saved $this->blk[1]
14597 			$this->blk[1] = $saved_block1;
14598 
14599 			// These are only needed when painting border/background
14600 			$this->blk[1]['width'] = $bbox_w = $cont_w - $bbox_left - $bbox_ml - $bbox_mr - $bbox_right;
14601 			$this->blk[1]['x0'] = $bbox_x;
14602 			$this->blk[1]['y0'] = $bbox_y;
14603 			$this->blk[1]['startpage'] = $this->page;
14604 			$this->blk[1]['y1'] = $bbox_y + $bbox_bt + $bbox_pt + $inner_h + $bbox_pb + $bbox_bb;
14605 			$this->writer->write($rot_start);
14606 			$this->PaintDivBB('', 0, 1); // Prints borders and sets backgrounds in $this->pageBackgrounds
14607 			$this->writer->write($rot_end);
14608 		}
14609 
14610 		$s = $this->PrintPageBackgrounds();
14611 		$s = $rot_start . $s . $rot_end;
14612 		$this->pages[$this->page] = preg_replace('/___BEFORE_BORDERS___/', "\n" . $s . "\n", $this->pages[$this->page]);
14613 		$this->pageBackgrounds = [];
14614 
14615 		$this->writer->write($rot_start);
14616 
14617 		// Clipping Output
14618 		if ($overflow == 'hidden') {
14619 			// Bounding rectangle to clip
14620 			$clip_y1 = $this->y;
14621 			if (!empty($bounding) && ($this->y + $bbox_pb + $bbox_bb) > ($bbox_y + $bbox_bt + $bbox_pt + $inner_h + $bbox_pb + $bbox_bb )) {
14622 				$clip_y1 = ($bbox_y + $bbox_bt + $bbox_pt + $inner_h + $bbox_pb + $bbox_bb ) - ($bbox_pb + $bbox_bb);
14623 			}
14624 			// $op = 'W* n';	// Clipping
14625 			$op = 'W n'; // Clipping alternative mode
14626 			$this->writer->write("q");
14627 			$ch = $clip_y1 - $y;
14628 			$this->writer->write(sprintf('%.3F %.3F %.3F %.3F re %s', $x * Mpdf::SCALE, ($this->h - $y) * Mpdf::SCALE, $w * Mpdf::SCALE, -$ch * Mpdf::SCALE, $op));
14629 			if (!empty($block_s)) {
14630 				$tmp = "q\n" . sprintf('%.3F %.3F %.3F %.3F re %s', $x * Mpdf::SCALE, ($this->h - $y) * Mpdf::SCALE, $w * Mpdf::SCALE, -$ch * Mpdf::SCALE, $op);
14631 				$tmp .= "\n" . $block_s . "\nQ";
14632 				$block_s = $tmp;
14633 			}
14634 		}
14635 
14636 
14637 		if (!empty($block_s)) {
14638 			if ($shrink_f != 1) { // i.e. autofit has resized the box
14639 				$tmp = "q\n" . $this->transformScale(($shrink_f * 100), ($shrink_f * 100), $x, $y, true);
14640 				$tmp .= "\n" . $block_s . "\nQ";
14641 				$block_s = $tmp;
14642 			}
14643 			$this->writer->write($block_s);
14644 		}
14645 
14646 
14647 
14648 		if ($shrink_f != 1) { // i.e. autofit has resized the box
14649 			$this->StartTransform();
14650 			$this->transformScale(($shrink_f * 100), ($shrink_f * 100), $x, $y);
14651 		}
14652 
14653 		$this->writer->write($this->headerbuffer);
14654 
14655 		if ($shrink_f != 1) { // i.e. autofit has resized the box
14656 			$this->StopTransform();
14657 		}
14658 
14659 		if ($overflow == 'hidden') {
14660 			// End clipping
14661 			$this->writer->write("Q");
14662 		}
14663 
14664 		$this->writer->write($rot_end);
14665 
14666 
14667 		// Page Links
14668 		foreach ($this->HTMLheaderPageLinks as $lk) {
14669 			if ($rotate) {
14670 				$tmp = $lk[2]; // Switch h - w
14671 				$lk[2] = $lk[3];
14672 				$lk[3] = $tmp;
14673 
14674 				$lx1 = (($lk[0] / Mpdf::SCALE));
14675 				$ly1 = (($this->h - ($lk[1] / Mpdf::SCALE)));
14676 				if ($rotate == 90) {
14677 					$adjx = -($lx1 - $bbox_x) + ($preroth - ($ly1 - $bbox_y));
14678 					$adjy = -($ly1 - $bbox_y) + ($lx1 - $bbox_x);
14679 					$lk[2] = -$lk[2];
14680 				} elseif ($rotate == -90) {
14681 					$adjx = -($lx1 - $bbox_x) + ($ly1 - $bbox_y);
14682 					$adjy = -($ly1 - $bbox_y) - ($lx1 - $bbox_x) + $prerotw;
14683 					$lk[3] = -$lk[3];
14684 				}
14685 				if ($rot_rpos !== false) {
14686 					$adjx += $prerotw - $preroth;
14687 				}
14688 				if ($rot_bpos !== false) {
14689 					$adjy += $preroth - $prerotw;
14690 				}
14691 				$lx1 += $adjx;
14692 				$ly1 += $adjy;
14693 
14694 				$lk[0] = $lx1 * Mpdf::SCALE;
14695 				$lk[1] = ($this->h - $ly1) * Mpdf::SCALE;
14696 			}
14697 			if ($shrink_f != 1) {  // i.e. autofit has resized the box
14698 				$lx1 = (($lk[0] / Mpdf::SCALE) - $x);
14699 				$lx2 = $x + ($lx1 * $shrink_f);
14700 				$lk[0] = $lx2 * Mpdf::SCALE;
14701 				$ly1 = (($this->h - ($lk[1] / Mpdf::SCALE)) - $y);
14702 				$ly2 = $y + ($ly1 * $shrink_f);
14703 				$lk[1] = ($this->h - $ly2) * Mpdf::SCALE;
14704 				$lk[2] *= $shrink_f; // width
14705 				$lk[3] *= $shrink_f; // height
14706 			}
14707 			$this->PageLinks[$this->page][] = $lk;
14708 		}
14709 
14710 		foreach ($this->HTMLheaderPageForms as $n => $f) {
14711 			if ($shrink_f != 1) {  // i.e. autofit has resized the box
14712 				$f['x'] = $x + (($f['x'] - $x) * $shrink_f);
14713 				$f['y'] = $y + (($f['y'] - $y) * $shrink_f);
14714 				$f['w'] *= $shrink_f;
14715 				$f['h'] *= $shrink_f;
14716 				$f['style']['fontsize'] *= $shrink_f;
14717 			}
14718 			$this->form->forms[$f['n']] = $f;
14719 		}
14720 		// Page Annotations
14721 		foreach ($this->HTMLheaderPageAnnots as $lk) {
14722 			if ($rotate) {
14723 				if ($rotate == 90) {
14724 					$adjx = -($lk['x'] - $bbox_x) + ($preroth - ($lk['y'] - $bbox_y));
14725 					$adjy = -($lk['y'] - $bbox_y) + ($lk['x'] - $bbox_x);
14726 				} elseif ($rotate == -90) {
14727 					$adjx = -($lk['x'] - $bbox_x) + ($lk['y'] - $bbox_y);
14728 					$adjy = -($lk['y'] - $bbox_y) - ($lk['x'] - $bbox_x) + $prerotw;
14729 				}
14730 				if ($rot_rpos !== false) {
14731 					$adjx += $prerotw - $preroth;
14732 				}
14733 				if ($rot_bpos !== false) {
14734 					$adjy += $preroth - $prerotw;
14735 				}
14736 				$lk['x'] += $adjx;
14737 				$lk['y'] += $adjy;
14738 			}
14739 			if ($shrink_f != 1) {  // i.e. autofit has resized the box
14740 				$lk['x'] = $x + (($lk['x'] - $x) * $shrink_f);
14741 				$lk['y'] = $y + (($lk['y'] - $y) * $shrink_f);
14742 			}
14743 			$this->PageAnnots[$this->page][] = $lk;
14744 		}
14745 
14746 		// Restore
14747 		$this->headerbuffer = '';
14748 		$this->HTMLheaderPageLinks = [];
14749 		$this->HTMLheaderPageAnnots = [];
14750 		$this->HTMLheaderPageForms = [];
14751 		$this->pageBackgrounds = $save_bgs;
14752 		$this->writingHTMLheader = false;
14753 
14754 		$this->writingHTMLfooter = false;
14755 		$this->fullImageHeight = false;
14756 		$this->ResetMargins();
14757 		$this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
14758 		$this->SetXY($save_x, $save_y);
14759 		$this->title2annots = $save_annots; // *ANNOTATIONS*
14760 		$this->InFooter = false; // turns back on autopagebreaks
14761 		$this->pageoutput[$this->page] = [];
14762 		$this->pageoutput[$this->page]['Font'] = '';
14763 		/* -- COLUMNS -- */
14764 		if ($save_cols) {
14765 			$this->SetColumns($save_nbcol, $this->colvAlign, $this->ColGap);
14766 		}
14767 		/* -- END COLUMNS -- */
14768 	}
14769 
14770 	/* -- END CSS-POSITION -- */
14771 
14772 	function initialiseBlock(&$blk)
14773 	{
14774 		$blk['margin_top'] = 0;
14775 		$blk['margin_left'] = 0;
14776 		$blk['margin_bottom'] = 0;
14777 		$blk['margin_right'] = 0;
14778 		$blk['padding_top'] = 0;
14779 		$blk['padding_left'] = 0;
14780 		$blk['padding_bottom'] = 0;
14781 		$blk['padding_right'] = 0;
14782 		$blk['border_top']['w'] = 0;
14783 		$blk['border_left']['w'] = 0;
14784 		$blk['border_bottom']['w'] = 0;
14785 		$blk['border_right']['w'] = 0;
14786 		$blk['direction'] = 'ltr';
14787 		$blk['hide'] = false;
14788 		$blk['outer_left_margin'] = 0;
14789 		$blk['outer_right_margin'] = 0;
14790 		$blk['cascadeCSS'] = [];
14791 		$blk['block-align'] = false;
14792 		$blk['bgcolor'] = false;
14793 		$blk['page_break_after_avoid'] = false;
14794 		$blk['keep_block_together'] = false;
14795 		$blk['float'] = false;
14796 		$blk['line_height'] = '';
14797 		$blk['margin_collapse'] = false;
14798 	}
14799 
14800 	function border_details($bd)
14801 	{
14802 		$prop = preg_split('/\s+/', trim($bd));
14803 
14804 		if (isset($this->blk[$this->blklvl]['inner_width'])) {
14805 			$refw = $this->blk[$this->blklvl]['inner_width'];
14806 		} elseif (isset($this->blk[$this->blklvl - 1]['inner_width'])) {
14807 			$refw = $this->blk[$this->blklvl - 1]['inner_width'];
14808 		} else {
14809 			$refw = $this->w;
14810 		}
14811 		if (count($prop) == 1) {
14812 			$bsize = $this->sizeConverter->convert($prop[0], $refw, $this->FontSize, false);
14813 			if ($bsize > 0) {
14814 				return ['s' => 1, 'w' => $bsize, 'c' => $this->colorConverter->convert(0, $this->PDFAXwarnings), 'style' => 'solid'];
14815 			} else {
14816 				return ['w' => 0, 's' => 0];
14817 			}
14818 		} elseif (count($prop) == 2) {
14819 			// 1px solid
14820 			if (in_array($prop[1], $this->borderstyles) || $prop[1] == 'none' || $prop[1] == 'hidden') {
14821 				$prop[2] = '';
14822 			} // solid #000000
14823 			elseif (in_array($prop[0], $this->borderstyles) || $prop[0] == 'none' || $prop[0] == 'hidden') {
14824 				$prop[0] = '';
14825 				$prop[1] = $prop[0];
14826 				$prop[2] = $prop[1];
14827 			} // 1px #000000
14828 			else {
14829 				$prop[1] = '';
14830 				$prop[2] = $prop[1];
14831 			}
14832 		} elseif (count($prop) == 3) {
14833 			// Change #000000 1px solid to 1px solid #000000 (proper)
14834 			if (substr($prop[0], 0, 1) == '#') {
14835 				$tmp = $prop[0];
14836 				$prop[0] = $prop[1];
14837 				$prop[1] = $prop[2];
14838 				$prop[2] = $tmp;
14839 			} // Change solid #000000 1px to 1px solid #000000 (proper)
14840 			elseif (substr($prop[0], 1, 1) == '#') {
14841 				$tmp = $prop[1];
14842 				$prop[0] = $prop[2];
14843 				$prop[1] = $prop[0];
14844 				$prop[2] = $tmp;
14845 			} // Change solid 1px #000000 to 1px solid #000000 (proper)
14846 			elseif (in_array($prop[0], $this->borderstyles) || $prop[0] == 'none' || $prop[0] == 'hidden') {
14847 				$tmp = $prop[0];
14848 				$prop[0] = $prop[1];
14849 				$prop[1] = $tmp;
14850 			}
14851 		} else {
14852 			return ['w' => 0, 's' => 0];
14853 		}
14854 		// Size
14855 		$bsize = $this->sizeConverter->convert($prop[0], $refw, $this->FontSize, false);
14856 		// color
14857 		$coul = $this->colorConverter->convert($prop[2], $this->PDFAXwarnings); // returns array
14858 		// Style
14859 		$prop[1] = strtolower($prop[1]);
14860 		if (in_array($prop[1], $this->borderstyles) && $bsize > 0) {
14861 			$on = 1;
14862 		} elseif ($prop[1] == 'hidden') {
14863 			$on = 1;
14864 			$bsize = 0;
14865 			$coul = '';
14866 		} elseif ($prop[1] == 'none') {
14867 			$on = 0;
14868 			$bsize = 0;
14869 			$coul = '';
14870 		} else {
14871 			$on = 0;
14872 			$bsize = 0;
14873 			$coul = '';
14874 			$prop[1] = '';
14875 		}
14876 		return ['s' => $on, 'w' => $bsize, 'c' => $coul, 'style' => $prop[1], 'dom' => 0];
14877 	}
14878 
14879 	/* -- END HTML-CSS -- */
14880 
14881 
14882 	/* -- BORDER-RADIUS -- */
14883 
14884 	function _borderPadding($a, $b, &$px, &$py)
14885 	{
14886 		// $px and py are padding long axis (x) and short axis (y)
14887 		$added = 0; // extra padding
14888 
14889 		$x = $a - $px;
14890 		$y = $b - $py;
14891 		// Check if Falls within ellipse of border radius
14892 		if (( (($x + $added) * ($x + $added)) / ($a * $a) + (($y + $added) * ($y + $added)) / ($b * $b) ) <= 1) {
14893 			return false;
14894 		}
14895 
14896 		$t = atan2($y, $x);
14897 
14898 		$newx = $b / sqrt((($b * $b) / ($a * $a)) + ( tan($t) * tan($t) ));
14899 		$newy = $a / sqrt((($a * $a) / ($b * $b)) + ( (1 / tan($t)) * (1 / tan($t)) ));
14900 		$px = max($px, $a - $newx + $added);
14901 		$py = max($py, $b - $newy + $added);
14902 	}
14903 
14904 	/* -- END BORDER-RADIUS -- */
14905 	/* -- HTML-CSS -- */
14906 	/* -- CSS-PAGE -- */
14907 
14908 	function SetPagedMediaCSS($name, $first, $oddEven)
14909 	{
14910 		if ($oddEven == 'E') {
14911 			if ($this->directionality == 'rtl') {
14912 				$side = 'R';
14913 			} else {
14914 				$side = 'L';
14915 			}
14916 		} else {
14917 			if ($this->directionality == 'rtl') {
14918 				$side = 'L';
14919 			} else {
14920 				$side = 'R';
14921 			}
14922 		}
14923 		$name = strtoupper($name);
14924 		$p = [];
14925 		$p['SIZE'] = 'AUTO';
14926 
14927 		// Uses mPDF original margins as default
14928 		$p['MARGIN-RIGHT'] = strval($this->orig_rMargin) . 'mm';
14929 		$p['MARGIN-LEFT'] = strval($this->orig_lMargin) . 'mm';
14930 		$p['MARGIN-TOP'] = strval($this->orig_tMargin) . 'mm';
14931 		$p['MARGIN-BOTTOM'] = strval($this->orig_bMargin) . 'mm';
14932 		$p['MARGIN-HEADER'] = strval($this->orig_hMargin) . 'mm';
14933 		$p['MARGIN-FOOTER'] = strval($this->orig_fMargin) . 'mm';
14934 
14935 		// Basic page + selector
14936 		if (isset($this->cssManager->CSS['@PAGE'])) {
14937 			$zp = $this->cssManager->CSS['@PAGE'];
14938 		} else {
14939 			$zp = [];
14940 		}
14941 		if (is_array($zp) && !empty($zp)) {
14942 			$p = array_merge($p, $zp);
14943 		}
14944 
14945 		if (isset($p['EVEN-HEADER-NAME']) && $oddEven == 'E') {
14946 			$p['HEADER'] = $p['EVEN-HEADER-NAME'];
14947 			unset($p['EVEN-HEADER-NAME']);
14948 		}
14949 		if (isset($p['ODD-HEADER-NAME']) && $oddEven != 'E') {
14950 			$p['HEADER'] = $p['ODD-HEADER-NAME'];
14951 			unset($p['ODD-HEADER-NAME']);
14952 		}
14953 		if (isset($p['EVEN-FOOTER-NAME']) && $oddEven == 'E') {
14954 			$p['FOOTER'] = $p['EVEN-FOOTER-NAME'];
14955 			unset($p['EVEN-FOOTER-NAME']);
14956 		}
14957 		if (isset($p['ODD-FOOTER-NAME']) && $oddEven != 'E') {
14958 			$p['FOOTER'] = $p['ODD-FOOTER-NAME'];
14959 			unset($p['ODD-FOOTER-NAME']);
14960 		}
14961 
14962 		// If right/Odd page
14963 		if (isset($this->cssManager->CSS['@PAGE>>PSEUDO>>RIGHT']) && $side == 'R') {
14964 			$zp = $this->cssManager->CSS['@PAGE>>PSEUDO>>RIGHT'];
14965 		} else {
14966 			$zp = [];
14967 		}
14968 		if (isset($zp['SIZE'])) {
14969 			unset($zp['SIZE']);
14970 		}
14971 		if (isset($zp['SHEET-SIZE'])) {
14972 			unset($zp['SHEET-SIZE']);
14973 		}
14974 		// Disallow margin-left or -right on :LEFT or :RIGHT
14975 		if (isset($zp['MARGIN-LEFT'])) {
14976 			unset($zp['MARGIN-LEFT']);
14977 		}
14978 		if (isset($zp['MARGIN-RIGHT'])) {
14979 			unset($zp['MARGIN-RIGHT']);
14980 		}
14981 		if (is_array($zp) && !empty($zp)) {
14982 			$p = array_merge($p, $zp);
14983 		}
14984 
14985 		// If left/Even page
14986 		if (isset($this->cssManager->CSS['@PAGE>>PSEUDO>>LEFT']) && $side == 'L') {
14987 			$zp = $this->cssManager->CSS['@PAGE>>PSEUDO>>LEFT'];
14988 		} else {
14989 			$zp = [];
14990 		}
14991 		if (isset($zp['SIZE'])) {
14992 			unset($zp['SIZE']);
14993 		}
14994 		if (isset($zp['SHEET-SIZE'])) {
14995 			unset($zp['SHEET-SIZE']);
14996 		}
14997 		// Disallow margin-left or -right on :LEFT or :RIGHT
14998 		if (isset($zp['MARGIN-LEFT'])) {
14999 			unset($zp['MARGIN-LEFT']);
15000 		}
15001 		if (isset($zp['MARGIN-RIGHT'])) {
15002 			unset($zp['MARGIN-RIGHT']);
15003 		}
15004 		if (is_array($zp) && !empty($zp)) {
15005 			$p = array_merge($p, $zp);
15006 		}
15007 
15008 		// If first page
15009 		if (isset($this->cssManager->CSS['@PAGE>>PSEUDO>>FIRST']) && $first) {
15010 			$zp = $this->cssManager->CSS['@PAGE>>PSEUDO>>FIRST'];
15011 		} else {
15012 			$zp = [];
15013 		}
15014 		if (isset($zp['SIZE'])) {
15015 			unset($zp['SIZE']);
15016 		}
15017 		if (isset($zp['SHEET-SIZE'])) {
15018 			unset($zp['SHEET-SIZE']);
15019 		}
15020 		// Disallow margin-left or -right on :FIRST	// mPDF 5.7.3
15021 		if (isset($zp['MARGIN-LEFT'])) {
15022 			unset($zp['MARGIN-LEFT']);
15023 		}
15024 		if (isset($zp['MARGIN-RIGHT'])) {
15025 			unset($zp['MARGIN-RIGHT']);
15026 		}
15027 		if (is_array($zp) && !empty($zp)) {
15028 			$p = array_merge($p, $zp);
15029 		}
15030 
15031 		// If named page
15032 		if ($name) {
15033 			if (isset($this->cssManager->CSS['@PAGE>>NAMED>>' . $name])) {
15034 				$zp = $this->cssManager->CSS['@PAGE>>NAMED>>' . $name];
15035 			} else {
15036 				$zp = [];
15037 			}
15038 			if (is_array($zp) && !empty($zp)) {
15039 				$p = array_merge($p, $zp);
15040 			}
15041 
15042 			if (isset($p['EVEN-HEADER-NAME']) && $oddEven == 'E') {
15043 				$p['HEADER'] = $p['EVEN-HEADER-NAME'];
15044 				unset($p['EVEN-HEADER-NAME']);
15045 			}
15046 			if (isset($p['ODD-HEADER-NAME']) && $oddEven != 'E') {
15047 				$p['HEADER'] = $p['ODD-HEADER-NAME'];
15048 				unset($p['ODD-HEADER-NAME']);
15049 			}
15050 			if (isset($p['EVEN-FOOTER-NAME']) && $oddEven == 'E') {
15051 				$p['FOOTER'] = $p['EVEN-FOOTER-NAME'];
15052 				unset($p['EVEN-FOOTER-NAME']);
15053 			}
15054 			if (isset($p['ODD-FOOTER-NAME']) && $oddEven != 'E') {
15055 				$p['FOOTER'] = $p['ODD-FOOTER-NAME'];
15056 				unset($p['ODD-FOOTER-NAME']);
15057 			}
15058 
15059 			// If named right/Odd page
15060 			if (isset($this->cssManager->CSS['@PAGE>>NAMED>>' . $name . '>>PSEUDO>>RIGHT']) && $side == 'R') {
15061 				$zp = $this->cssManager->CSS['@PAGE>>NAMED>>' . $name . '>>PSEUDO>>RIGHT'];
15062 			} else {
15063 				$zp = [];
15064 			}
15065 			if (isset($zp['SIZE'])) {
15066 				unset($zp['SIZE']);
15067 			}
15068 			if (isset($zp['SHEET-SIZE'])) {
15069 				unset($zp['SHEET-SIZE']);
15070 			}
15071 			// Disallow margin-left or -right on :LEFT or :RIGHT
15072 			if (isset($zp['MARGIN-LEFT'])) {
15073 				unset($zp['MARGIN-LEFT']);
15074 			}
15075 			if (isset($zp['MARGIN-RIGHT'])) {
15076 				unset($zp['MARGIN-RIGHT']);
15077 			}
15078 			if (is_array($zp) && !empty($zp)) {
15079 				$p = array_merge($p, $zp);
15080 			}
15081 
15082 			// If named left/Even page
15083 			if (isset($this->cssManager->CSS['@PAGE>>NAMED>>' . $name . '>>PSEUDO>>LEFT']) && $side == 'L') {
15084 				$zp = $this->cssManager->CSS['@PAGE>>NAMED>>' . $name . '>>PSEUDO>>LEFT'];
15085 			} else {
15086 				$zp = [];
15087 			}
15088 			if (isset($zp['SIZE'])) {
15089 				unset($zp['SIZE']);
15090 			}
15091 			if (isset($zp['SHEET-SIZE'])) {
15092 				unset($zp['SHEET-SIZE']);
15093 			}
15094 			// Disallow margin-left or -right on :LEFT or :RIGHT
15095 			if (isset($zp['MARGIN-LEFT'])) {
15096 				unset($zp['MARGIN-LEFT']);
15097 			}
15098 			if (isset($zp['MARGIN-RIGHT'])) {
15099 				unset($zp['MARGIN-RIGHT']);
15100 			}
15101 			if (is_array($zp) && !empty($zp)) {
15102 				$p = array_merge($p, $zp);
15103 			}
15104 
15105 			// If named first page
15106 			if (isset($this->cssManager->CSS['@PAGE>>NAMED>>' . $name . '>>PSEUDO>>FIRST']) && $first) {
15107 				$zp = $this->cssManager->CSS['@PAGE>>NAMED>>' . $name . '>>PSEUDO>>FIRST'];
15108 			} else {
15109 				$zp = [];
15110 			}
15111 			if (isset($zp['SIZE'])) {
15112 				unset($zp['SIZE']);
15113 			}
15114 			if (isset($zp['SHEET-SIZE'])) {
15115 				unset($zp['SHEET-SIZE']);
15116 			}
15117 			// Disallow margin-left or -right on :FIRST	// mPDF 5.7.3
15118 			if (isset($zp['MARGIN-LEFT'])) {
15119 				unset($zp['MARGIN-LEFT']);
15120 			}
15121 			if (isset($zp['MARGIN-RIGHT'])) {
15122 				unset($zp['MARGIN-RIGHT']);
15123 			}
15124 			if (is_array($zp) && !empty($zp)) {
15125 				$p = array_merge($p, $zp);
15126 			}
15127 		}
15128 
15129 		$orientation = $mgl = $mgr = $mgt = $mgb = $mgh = $mgf = '';
15130 		$header = $footer = '';
15131 		$resetpagenum = $pagenumstyle = $suppress = '';
15132 		$marks = '';
15133 		$bg = [];
15134 
15135 		$newformat = '';
15136 
15137 
15138 		if (isset($p['SHEET-SIZE']) && is_array($p['SHEET-SIZE'])) {
15139 			$newformat = $p['SHEET-SIZE'];
15140 			if ($newformat[0] > $newformat[1]) { // landscape
15141 				$newformat = array_reverse($newformat);
15142 				$p['ORIENTATION'] = 'L';
15143 			} else {
15144 				$p['ORIENTATION'] = 'P';
15145 			}
15146 			$this->_setPageSize($newformat, $p['ORIENTATION']);
15147 		}
15148 
15149 		if (isset($p['SIZE']) && is_array($p['SIZE']) && !$newformat) {
15150 			if ($p['SIZE']['W'] > $p['SIZE']['H']) {
15151 				$p['ORIENTATION'] = 'L';
15152 			} else {
15153 				$p['ORIENTATION'] = 'P';
15154 			}
15155 		}
15156 		if (is_array($p['SIZE'])) {
15157 			if ($p['SIZE']['W'] > $this->fw) {
15158 				$p['SIZE']['W'] = $this->fw;
15159 			} // mPD 4.2 use fw not fPt
15160 			if ($p['SIZE']['H'] > $this->fh) {
15161 				$p['SIZE']['H'] = $this->fh;
15162 			}
15163 			if (($p['ORIENTATION'] == $this->DefOrientation && !$newformat) || ($newformat && $p['ORIENTATION'] == 'P')) {
15164 				$outer_width_LR = ($this->fw - $p['SIZE']['W']) / 2;
15165 				$outer_width_TB = ($this->fh - $p['SIZE']['H']) / 2;
15166 			} else {
15167 				$outer_width_LR = ($this->fh - $p['SIZE']['W']) / 2;
15168 				$outer_width_TB = ($this->fw - $p['SIZE']['H']) / 2;
15169 			}
15170 			$pgw = $p['SIZE']['W'];
15171 			$pgh = $p['SIZE']['H'];
15172 		} else { // AUTO LANDSCAPE PORTRAIT
15173 			$outer_width_LR = 0;
15174 			$outer_width_TB = 0;
15175 			if (!$newformat) {
15176 				if (strtoupper($p['SIZE']) == 'AUTO') {
15177 					$p['ORIENTATION'] = $this->DefOrientation;
15178 				} elseif (strtoupper($p['SIZE']) == 'LANDSCAPE') {
15179 					$p['ORIENTATION'] = 'L';
15180 				} else {
15181 					$p['ORIENTATION'] = 'P';
15182 				}
15183 			}
15184 			if (($p['ORIENTATION'] == $this->DefOrientation && !$newformat) || ($newformat && $p['ORIENTATION'] == 'P')) {
15185 				$pgw = $this->fw;
15186 				$pgh = $this->fh;
15187 			} else {
15188 				$pgw = $this->fh;
15189 				$pgh = $this->fw;
15190 			}
15191 		}
15192 
15193 		if (isset($p['HEADER']) && $p['HEADER']) {
15194 			$header = $p['HEADER'];
15195 		}
15196 		if (isset($p['FOOTER']) && $p['FOOTER']) {
15197 			$footer = $p['FOOTER'];
15198 		}
15199 		if (isset($p['RESETPAGENUM']) && $p['RESETPAGENUM']) {
15200 			$resetpagenum = $p['RESETPAGENUM'];
15201 		}
15202 		if (isset($p['PAGENUMSTYLE']) && $p['PAGENUMSTYLE']) {
15203 			$pagenumstyle = $p['PAGENUMSTYLE'];
15204 		}
15205 		if (isset($p['SUPPRESS']) && $p['SUPPRESS']) {
15206 			$suppress = $p['SUPPRESS'];
15207 		}
15208 
15209 		if (isset($p['MARKS'])) {
15210 			if (preg_match('/cross/i', $p['MARKS']) && preg_match('/crop/i', $p['MARKS'])) {
15211 				$marks = 'CROPCROSS';
15212 			} elseif (strtoupper($p['MARKS']) == 'CROP') {
15213 				$marks = 'CROP';
15214 			} elseif (strtoupper($p['MARKS']) == 'CROSS') {
15215 				$marks = 'CROSS';
15216 			}
15217 		}
15218 
15219 		if (isset($p['BACKGROUND-COLOR']) && $p['BACKGROUND-COLOR']) {
15220 			$bg['BACKGROUND-COLOR'] = $p['BACKGROUND-COLOR'];
15221 		}
15222 		/* -- BACKGROUNDS -- */
15223 		if (isset($p['BACKGROUND-GRADIENT']) && $p['BACKGROUND-GRADIENT']) {
15224 			$bg['BACKGROUND-GRADIENT'] = $p['BACKGROUND-GRADIENT'];
15225 		}
15226 		if (isset($p['BACKGROUND-IMAGE']) && $p['BACKGROUND-IMAGE']) {
15227 			$bg['BACKGROUND-IMAGE'] = $p['BACKGROUND-IMAGE'];
15228 		}
15229 		if (isset($p['BACKGROUND-REPEAT']) && $p['BACKGROUND-REPEAT']) {
15230 			$bg['BACKGROUND-REPEAT'] = $p['BACKGROUND-REPEAT'];
15231 		}
15232 		if (isset($p['BACKGROUND-POSITION']) && $p['BACKGROUND-POSITION']) {
15233 			$bg['BACKGROUND-POSITION'] = $p['BACKGROUND-POSITION'];
15234 		}
15235 		if (isset($p['BACKGROUND-IMAGE-RESIZE']) && $p['BACKGROUND-IMAGE-RESIZE']) {
15236 			$bg['BACKGROUND-IMAGE-RESIZE'] = $p['BACKGROUND-IMAGE-RESIZE'];
15237 		}
15238 		if (isset($p['BACKGROUND-IMAGE-OPACITY'])) {
15239 			$bg['BACKGROUND-IMAGE-OPACITY'] = $p['BACKGROUND-IMAGE-OPACITY'];
15240 		}
15241 		/* -- END BACKGROUNDS -- */
15242 
15243 		if (isset($p['MARGIN-LEFT'])) {
15244 			$mgl = $this->sizeConverter->convert($p['MARGIN-LEFT'], $pgw) + $outer_width_LR;
15245 		}
15246 		if (isset($p['MARGIN-RIGHT'])) {
15247 			$mgr = $this->sizeConverter->convert($p['MARGIN-RIGHT'], $pgw) + $outer_width_LR;
15248 		}
15249 		if (isset($p['MARGIN-BOTTOM'])) {
15250 			$mgb = $this->sizeConverter->convert($p['MARGIN-BOTTOM'], $pgh) + $outer_width_TB;
15251 		}
15252 		if (isset($p['MARGIN-TOP'])) {
15253 			$mgt = $this->sizeConverter->convert($p['MARGIN-TOP'], $pgh) + $outer_width_TB;
15254 		}
15255 		if (isset($p['MARGIN-HEADER'])) {
15256 			$mgh = $this->sizeConverter->convert($p['MARGIN-HEADER'], $pgh) + $outer_width_TB;
15257 		}
15258 		if (isset($p['MARGIN-FOOTER'])) {
15259 			$mgf = $this->sizeConverter->convert($p['MARGIN-FOOTER'], $pgh) + $outer_width_TB;
15260 		}
15261 
15262 		if (isset($p['ORIENTATION']) && $p['ORIENTATION']) {
15263 			$orientation = $p['ORIENTATION'];
15264 		}
15265 		$this->page_box['outer_width_LR'] = $outer_width_LR; // Used in MARKS:crop etc.
15266 		$this->page_box['outer_width_TB'] = $outer_width_TB;
15267 
15268 		return [$orientation, $mgl, $mgr, $mgt, $mgb, $mgh, $mgf, $header, $footer, $bg, $resetpagenum, $pagenumstyle, $suppress, $marks, $newformat];
15269 	}
15270 
15271 	/* -- END CSS-PAGE -- */
15272 
15273 
15274 
15275 	/* -- CSS-FLOAT -- */
15276 
15277 	// Added mPDF 3.0 Float DIV - CLEAR
15278 	function ClearFloats($clear, $blklvl = 0)
15279 	{
15280 		list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($blklvl, true);
15281 		$end = $currpos = ($this->page * 1000 + $this->y);
15282 		if ($clear == 'BOTH' && ($l_exists || $r_exists)) {
15283 			$this->pageoutput[$this->page] = [];
15284 			$end = max($l_max, $r_max, $currpos);
15285 		} elseif ($clear == 'RIGHT' && $r_exists) {
15286 			$this->pageoutput[$this->page] = [];
15287 			$end = max($r_max, $currpos);
15288 		} elseif ($clear == 'LEFT' && $l_exists) {
15289 			$this->pageoutput[$this->page] = [];
15290 			$end = max($l_max, $currpos);
15291 		} else {
15292 			return;
15293 		}
15294 		$old_page = $this->page;
15295 		$new_page = intval($end / 1000);
15296 		if ($old_page != $new_page) {
15297 			$s = $this->PrintPageBackgrounds();
15298 			// Writes after the marker so not overwritten later by page background etc.
15299 			$this->pages[$this->page] = preg_replace('/(___BACKGROUND___PATTERNS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->pages[$this->page]);
15300 			$this->pageBackgrounds = [];
15301 			$this->page = $new_page;
15302 		}
15303 		$this->ResetMargins();
15304 		$this->pageoutput[$this->page] = [];
15305 
15306 		$this->y = (round($end * 1000) % 1000000) / 1000; // mod changes operands to integers before processing
15307 	}
15308 
15309 	// Added mPDF 3.0 Float DIV
15310 	function GetFloatDivInfo($blklvl = 0, $clear = false)
15311 	{
15312 		// If blklvl specified, only returns floats at that level - for ClearFloats
15313 		$l_exists = false;
15314 		$r_exists = false;
15315 		$l_max = 0;
15316 		$r_max = 0;
15317 		$l_width = 0;
15318 		$r_width = 0;
15319 		if (count($this->floatDivs)) {
15320 			$currpos = ($this->page * 1000 + $this->y);
15321 			foreach ($this->floatDivs as $f) {
15322 				if (($clear && $f['blockContext'] == $this->blk[$blklvl]['blockContext']) || (!$clear && $currpos >= $f['startpos'] && $currpos < ($f['endpos'] - 0.001) && $f['blklvl'] > $blklvl && $f['blockContext'] == $this->blk[$blklvl]['blockContext'])) {
15323 					if ($f['side'] == 'L') {
15324 						$l_exists = true;
15325 						$l_max = max($l_max, $f['endpos']);
15326 						$l_width = max($l_width, $f['w']);
15327 					}
15328 					if ($f['side'] == 'R') {
15329 						$r_exists = true;
15330 						$r_max = max($r_max, $f['endpos']);
15331 						$r_width = max($r_width, $f['w']);
15332 					}
15333 				}
15334 			}
15335 		}
15336 		return [$l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width];
15337 	}
15338 
15339 	/* -- END CSS-FLOAT -- */
15340 
15341 	// LIST MARKERS	// mPDF 6  Lists
15342 	function _setListMarker($listitemtype, $listitemimage, $listitemposition)
15343 	{
15344 		// if position:inside (and NOT table) - output now as a textbuffer; (so if next is block, will move to new line)
15345 		// elseif position:outside (and NOT table) - output in front of first textbuffer output by setting listitem (cf. _saveTextBuffer)
15346 		$e = '';
15347 		$this->listitem = '';
15348 		$spacer = ' ';
15349 		// IMAGE
15350 		if ($listitemimage && $listitemimage != 'none') {
15351 			$listitemimage = trim(preg_replace('/url\(["\']*(.*?)["\']*\)/', '\\1', $listitemimage));
15352 
15353 			// ? Restrict maximum height/width of list marker??
15354 			$maxWidth = 100;
15355 			$maxHeight = 100;
15356 
15357 			$objattr = [];
15358 			$objattr['margin_top'] = 0;
15359 			$objattr['margin_bottom'] = 0;
15360 			$objattr['margin_left'] = 0;
15361 			$objattr['margin_right'] = 0;
15362 			$objattr['padding_top'] = 0;
15363 			$objattr['padding_bottom'] = 0;
15364 			$objattr['padding_left'] = 0;
15365 			$objattr['padding_right'] = 0;
15366 			$objattr['width'] = 0;
15367 			$objattr['height'] = 0;
15368 			$objattr['border_top']['w'] = 0;
15369 			$objattr['border_bottom']['w'] = 0;
15370 			$objattr['border_left']['w'] = 0;
15371 			$objattr['border_right']['w'] = 0;
15372 			$objattr['visibility'] = 'visible';
15373 			$srcpath = $listitemimage;
15374 			$orig_srcpath = $listitemimage;
15375 
15376 			$objattr['vertical-align'] = 'BS'; // vertical alignment of marker (baseline)
15377 			$w = 0;
15378 			$h = 0;
15379 
15380 			// Image file
15381 			$info = $this->imageProcessor->getImage($srcpath, true, true, $orig_srcpath);
15382 			if (!$info) {
15383 				return;
15384 			}
15385 
15386 			if ($info['w'] == 0 && $info['h'] == 0) {
15387 				$info['h'] = $this->sizeConverter->convert('1em', $this->blk[$this->blklvl]['inner_width'], $this->FontSize, false);
15388 			}
15389 
15390 			$objattr['file'] = $srcpath;
15391 
15392 			// Default width and height calculation if needed
15393 			if ($w == 0 and $h == 0) {
15394 				/* -- IMAGES-WMF -- */
15395 				if ($info['type'] == 'wmf') {
15396 					// WMF units are twips (1/20pt)
15397 					// divide by 20 to get points
15398 					// divide by k to get user units
15399 					$w = abs($info['w']) / (20 * Mpdf::SCALE);
15400 					$h = abs($info['h']) / (20 * Mpdf::SCALE);
15401 				} else { 				/* -- END IMAGES-WMF -- */
15402 					if ($info['type'] == 'svg') {
15403 						// SVG units are pixels
15404 						$w = abs($info['w']) / Mpdf::SCALE;
15405 						$h = abs($info['h']) / Mpdf::SCALE;
15406 					} else {
15407 						// Put image at default image dpi
15408 						$w = ($info['w'] / Mpdf::SCALE) * (72 / $this->img_dpi);
15409 						$h = ($info['h'] / Mpdf::SCALE) * (72 / $this->img_dpi);
15410 					}
15411 				}
15412 			}
15413 			// IF WIDTH OR HEIGHT SPECIFIED
15414 			if ($w == 0) {
15415 				$w = abs($h * $info['w'] / $info['h']);
15416 			}
15417 			if ($h == 0) {
15418 				$h = abs($w * $info['h'] / $info['w']);
15419 			}
15420 
15421 			if ($w > $maxWidth) {
15422 				$w = $maxWidth;
15423 				$h = abs($w * $info['h'] / $info['w']);
15424 			}
15425 
15426 			if ($h > $maxHeight) {
15427 				$h = $maxHeight;
15428 				$w = abs($h * $info['w'] / $info['h']);
15429 			}
15430 
15431 			$objattr['type'] = 'image';
15432 			$objattr['itype'] = $info['type'];
15433 
15434 			$objattr['orig_h'] = $info['h'];
15435 			$objattr['orig_w'] = $info['w'];
15436 
15437 			/* -- IMAGES-WMF -- */
15438 			if ($info['type'] == 'wmf') {
15439 				$objattr['wmf_x'] = $info['x'];
15440 				$objattr['wmf_y'] = $info['y'];
15441 			} else { 			/* -- END IMAGES-WMF -- */
15442 				if ($info['type'] == 'svg') {
15443 					$objattr['wmf_x'] = $info['x'];
15444 					$objattr['wmf_y'] = $info['y'];
15445 				}
15446 			}
15447 
15448 			$objattr['height'] = $h;
15449 			$objattr['width'] = $w;
15450 			$objattr['image_height'] = $h;
15451 			$objattr['image_width'] = $w;
15452 
15453 			$objattr['dir'] = (isset($this->blk[$this->blklvl]['direction']) ? $this->blk[$this->blklvl]['direction'] : 'ltr');
15454 			$objattr['listmarker'] = true;
15455 
15456 			$objattr['listmarkerposition'] = $listitemposition;
15457 
15458 			$e = "\xbb\xa4\xactype=image,objattr=" . serialize($objattr) . "\xbb\xa4\xac";
15459 			$this->_saveTextBuffer($e);
15460 
15461 			if ($listitemposition == 'inside') {
15462 				$e = $spacer;
15463 				$this->_saveTextBuffer($e);
15464 			}
15465 		} elseif ($listitemtype == 'disc' || $listitemtype == 'circle' || $listitemtype == 'square') { // SYMBOL (needs new font)
15466 			$objattr = [];
15467 			$objattr['type'] = 'listmarker';
15468 			$objattr['listmarkerposition'] = $listitemposition;
15469 			$objattr['width'] = 0;
15470 			$size = $this->sizeConverter->convert($this->list_symbol_size, $this->FontSize);
15471 			$objattr['size'] = $size;
15472 			$objattr['offset'] = $this->sizeConverter->convert($this->list_marker_offset, $this->FontSize);
15473 
15474 			if ($listitemposition == 'inside') {
15475 				$objattr['width'] = $size + $objattr['offset'];
15476 			}
15477 
15478 			$objattr['height'] = $this->FontSize;
15479 			$objattr['vertical-align'] = 'T';
15480 			$objattr['text'] = '';
15481 			$objattr['dir'] = (isset($this->blk[$this->blklvl]['direction']) ? $this->blk[$this->blklvl]['direction'] : 'ltr');
15482 			$objattr['bullet'] = $listitemtype;
15483 			$objattr['colorarray'] = $this->colorarray;
15484 			$objattr['fontfamily'] = $this->FontFamily;
15485 			$objattr['fontsize'] = $this->FontSize;
15486 			$objattr['fontsizept'] = $this->FontSizePt;
15487 			$objattr['fontstyle'] = $this->FontStyle;
15488 
15489 			$e = "\xbb\xa4\xactype=listmarker,objattr=" . serialize($objattr) . "\xbb\xa4\xac";
15490 			$this->listitem = $this->_saveTextBuffer($e, '', '', true); // true returns array
15491 
15492 		} elseif (preg_match('/U\+([a-fA-F0-9]+)/i', $listitemtype, $m)) { // SYMBOL 2 (needs new font)
15493 
15494 			if ($this->_charDefined($this->CurrentFont['cw'], hexdec($m[1]))) {
15495 				$list_item_marker = UtfString::codeHex2utf($m[1]);
15496 			} else {
15497 				$list_item_marker = '-';
15498 			}
15499 			if (preg_match('/rgb\(.*?\)/', $listitemtype, $m)) {
15500 				$list_item_color = $this->colorConverter->convert($m[0], $this->PDFAXwarnings);
15501 			} else {
15502 				$list_item_color = '';
15503 			}
15504 
15505 			// SAVE then SET COLR
15506 			$save_colorarray = $this->colorarray;
15507 			if ($list_item_color) {
15508 				$this->colorarray = $list_item_color;
15509 			}
15510 
15511 			if ($listitemposition == 'inside') {
15512 				$e = $list_item_marker . $spacer;
15513 				$this->_saveTextBuffer($e);
15514 			} else {
15515 				$objattr = [];
15516 				$objattr['type'] = 'listmarker';
15517 				$objattr['width'] = 0;
15518 				$objattr['height'] = $this->FontSize;
15519 				$objattr['vertical-align'] = 'T';
15520 				$objattr['text'] = $list_item_marker;
15521 				$objattr['dir'] = (isset($this->blk[$this->blklvl]['direction']) ? $this->blk[$this->blklvl]['direction'] : 'ltr');
15522 				$objattr['colorarray'] = $this->colorarray;
15523 				$objattr['fontfamily'] = $this->FontFamily;
15524 				$objattr['fontsize'] = $this->FontSize;
15525 				$objattr['fontsizept'] = $this->FontSizePt;
15526 				$objattr['fontstyle'] = $this->FontStyle;
15527 				$e = "\xbb\xa4\xactype=listmarker,objattr=" . serialize($objattr) . "\xbb\xa4\xac";
15528 				$this->listitem = $this->_saveTextBuffer($e, '', '', true); // true returns array
15529 			}
15530 
15531 			// RESET COLOR
15532 			$this->colorarray = $save_colorarray;
15533 
15534 		} else { // TEXT
15535 			$counter = $this->listcounter[$this->listlvl];
15536 
15537 			if ($listitemtype == 'none') {
15538 				return;
15539 			}
15540 
15541 			$num = $this->_getStyledNumber($counter, $listitemtype, true);
15542 
15543 			if ($listitemposition == 'inside') {
15544 				$e = $num . $this->list_number_suffix . $spacer;
15545 				$this->_saveTextBuffer($e);
15546 			} else {
15547 				if (isset($this->blk[$this->blklvl]['direction']) && $this->blk[$this->blklvl]['direction'] == 'rtl') {
15548 					// REPLACE MIRRORED RTL $this->list_number_suffix  e.g. ) -> (  (NB could use Ucdn::$mirror_pairs)
15549 					$m = strtr($this->list_number_suffix, ")]}", "([{") . $num;
15550 				} else {
15551 					$m = $num . $this->list_number_suffix;
15552 				}
15553 
15554 				$objattr = [];
15555 				$objattr['type'] = 'listmarker';
15556 				$objattr['width'] = 0;
15557 				$objattr['height'] = $this->FontSize;
15558 				$objattr['vertical-align'] = 'T';
15559 				$objattr['text'] = $m;
15560 				$objattr['dir'] = (isset($this->blk[$this->blklvl]['direction']) ? $this->blk[$this->blklvl]['direction'] : 'ltr');
15561 				$objattr['colorarray'] = $this->colorarray;
15562 				$objattr['fontfamily'] = $this->FontFamily;
15563 				$objattr['fontsize'] = $this->FontSize;
15564 				$objattr['fontsizept'] = $this->FontSizePt;
15565 				$objattr['fontstyle'] = $this->FontStyle;
15566 				$e = "\xbb\xa4\xactype=listmarker,objattr=" . serialize($objattr) . "\xbb\xa4\xac";
15567 
15568 				$this->listitem = $this->_saveTextBuffer($e, '', '', true); // true returns array
15569 			}
15570 		}
15571 	}
15572 
15573 	// mPDF Lists
15574 	function _getListMarkerWidth(&$currblk, &$a, &$i)
15575 	{
15576 		$blt_width = 0;
15577 
15578 		$markeroffset = $this->sizeConverter->convert($this->list_marker_offset, $this->FontSize);
15579 
15580 		// Get Maximum number in the list
15581 		$maxnum = $this->listcounter[$this->listlvl];
15582 		if ($currblk['list_style_type'] != 'disc' && $currblk['list_style_type'] != 'circle' && $currblk['list_style_type'] != 'square') {
15583 			$lvl = 1;
15584 			for ($j = $i + 2; $j < count($a); $j+=2) {
15585 				$e = $a[$j];
15586 				if (!$e) {
15587 					continue;
15588 				}
15589 				if ($e[0] == '/') { // end tag
15590 					$e = strtoupper(substr($e, 1));
15591 					if ($e == 'OL' || $e == 'UL') {
15592 						if ($lvl == 1) {
15593 							break;
15594 						}
15595 						$lvl--;
15596 					}
15597 				} else { // opening tag
15598 					if (strpos($e, ' ')) {
15599 						$e = substr($e, 0, strpos($e, ' '));
15600 					}
15601 					$e = strtoupper($e);
15602 					if ($e == 'LI') {
15603 						if ($lvl == 1) {
15604 							$maxnum++;
15605 						}
15606 					} elseif ($e == 'OL' || $e == 'UL') {
15607 						$lvl++;
15608 					}
15609 				}
15610 			}
15611 		}
15612 
15613 		$decToAlpha = new Conversion\DecToAlpha();
15614 		$decToRoman = new Conversion\DecToRoman();
15615 		$decToOther = new Conversion\DecToOther($this);
15616 
15617 		switch ($currblk['list_style_type']) {
15618 			case 'decimal':
15619 			case '1':
15620 				$blt_width = $this->GetStringWidth(str_repeat('5', strlen($maxnum)) . $this->list_number_suffix);
15621 				break;
15622 			case 'none':
15623 				$blt_width = 0;
15624 				break;
15625 			case 'upper-alpha':
15626 			case 'upper-latin':
15627 			case 'A':
15628 				$maxnumA = $decToAlpha->convert($maxnum, true);
15629 				if ($maxnum < 13) {
15630 					$blt_width = $this->GetStringWidth('D' . $this->list_number_suffix);
15631 				} else {
15632 					$blt_width = $this->GetStringWidth(str_repeat('W', strlen($maxnumA)) . $this->list_number_suffix);
15633 				}
15634 				break;
15635 			case 'lower-alpha':
15636 			case 'lower-latin':
15637 			case 'a':
15638 				$maxnuma = $decToAlpha->convert($maxnum, false);
15639 				if ($maxnum < 13) {
15640 					$blt_width = $this->GetStringWidth('b' . $this->list_number_suffix);
15641 				} else {
15642 					$blt_width = $this->GetStringWidth(str_repeat('m', strlen($maxnuma)) . $this->list_number_suffix);
15643 				}
15644 				break;
15645 			case 'upper-roman':
15646 			case 'I':
15647 				if ($maxnum > 87) {
15648 					$bbit = 87;
15649 				} elseif ($maxnum > 86) {
15650 					$bbit = 86;
15651 				} elseif ($maxnum > 37) {
15652 					$bbit = 38;
15653 				} elseif ($maxnum > 36) {
15654 					$bbit = 37;
15655 				} elseif ($maxnum > 27) {
15656 					$bbit = 28;
15657 				} elseif ($maxnum > 26) {
15658 					$bbit = 27;
15659 				} elseif ($maxnum > 17) {
15660 					$bbit = 18;
15661 				} elseif ($maxnum > 16) {
15662 					$bbit = 17;
15663 				} elseif ($maxnum > 7) {
15664 					$bbit = 8;
15665 				} elseif ($maxnum > 6) {
15666 					$bbit = 7;
15667 				} elseif ($maxnum > 3) {
15668 					$bbit = 4;
15669 				} else {
15670 					$bbit = $maxnum;
15671 				}
15672 
15673 				$maxlnum = $decToRoman->convert($bbit, true);
15674 				$blt_width = $this->GetStringWidth($maxlnum . $this->list_number_suffix);
15675 
15676 				break;
15677 			case 'lower-roman':
15678 			case 'i':
15679 				if ($maxnum > 87) {
15680 					$bbit = 87;
15681 				} elseif ($maxnum > 86) {
15682 					$bbit = 86;
15683 				} elseif ($maxnum > 37) {
15684 					$bbit = 38;
15685 				} elseif ($maxnum > 36) {
15686 					$bbit = 37;
15687 				} elseif ($maxnum > 27) {
15688 					$bbit = 28;
15689 				} elseif ($maxnum > 26) {
15690 					$bbit = 27;
15691 				} elseif ($maxnum > 17) {
15692 					$bbit = 18;
15693 				} elseif ($maxnum > 16) {
15694 					$bbit = 17;
15695 				} elseif ($maxnum > 7) {
15696 					$bbit = 8;
15697 				} elseif ($maxnum > 6) {
15698 					$bbit = 7;
15699 				} elseif ($maxnum > 3) {
15700 					$bbit = 4;
15701 				} else {
15702 					$bbit = $maxnum;
15703 				}
15704 				$maxlnum = $decToRoman->convert($bbit, false);
15705 				$blt_width = $this->GetStringWidth($maxlnum . $this->list_number_suffix);
15706 				break;
15707 
15708 			case 'disc':
15709 			case 'circle':
15710 			case 'square':
15711 				$size = $this->sizeConverter->convert($this->list_symbol_size, $this->FontSize);
15712 				$offset = $this->sizeConverter->convert($this->list_marker_offset, $this->FontSize);
15713 				$blt_width = $size + $offset;
15714 				break;
15715 
15716 			case 'arabic-indic':
15717 				$blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(3, 0x0660), strlen($maxnum)) . $this->list_number_suffix);
15718 				break;
15719 			case 'persian':
15720 			case 'urdu':
15721 				$blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(3, 0x06F0), strlen($maxnum)) . $this->list_number_suffix);
15722 				break;
15723 			case 'bengali':
15724 				$blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(3, 0x09E6), strlen($maxnum)) . $this->list_number_suffix);
15725 				break;
15726 			case 'devanagari':
15727 				$blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(3, 0x0966), strlen($maxnum)) . $this->list_number_suffix);
15728 				break;
15729 			case 'gujarati':
15730 				$blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(3, 0x0AE6), strlen($maxnum)) . $this->list_number_suffix);
15731 				break;
15732 			case 'gurmukhi':
15733 				$blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(3, 0x0A66), strlen($maxnum)) . $this->list_number_suffix);
15734 				break;
15735 			case 'kannada':
15736 				$blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(3, 0x0CE6), strlen($maxnum)) . $this->list_number_suffix);
15737 				break;
15738 			case 'malayalam':
15739 				$blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(6, 0x0D66), strlen($maxnum)) . $this->list_number_suffix);
15740 				break;
15741 			case 'oriya':
15742 				$blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(3, 0x0B66), strlen($maxnum)) . $this->list_number_suffix);
15743 				break;
15744 			case 'telugu':
15745 				$blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(3, 0x0C66), strlen($maxnum)) . $this->list_number_suffix);
15746 				break;
15747 			case 'tamil':
15748 				$blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(9, 0x0BE6), strlen($maxnum)) . $this->list_number_suffix);
15749 				break;
15750 			case 'thai':
15751 				$blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(5, 0x0E50), strlen($maxnum)) . $this->list_number_suffix);
15752 				break;
15753 			default:
15754 				$blt_width = $this->GetStringWidth(str_repeat('5', strlen($maxnum)) . $this->list_number_suffix);
15755 				break;
15756 		}
15757 
15758 		return ($blt_width + $markeroffset);
15759 	}
15760 
15761 	function _saveTextBuffer($t, $link = '', $intlink = '', $return = false)
15762 	{
15763 	// mPDF 6  Lists
15764 		$arr = [];
15765 		$arr[0] = $t;
15766 		if (isset($link) && $link) {
15767 			$arr[1] = $link;
15768 		}
15769 		$arr[2] = $this->currentfontstyle;
15770 		if (isset($this->colorarray) && $this->colorarray) {
15771 			$arr[3] = $this->colorarray;
15772 		}
15773 		$arr[4] = $this->currentfontfamily;
15774 		$arr[5] = $this->currentLang; // mPDF 6
15775 		if (isset($intlink) && $intlink) {
15776 			$arr[7] = $intlink;
15777 		}
15778 		// mPDF 6
15779 		// If Kerning set for OTL, and useOTL has positive value, but has not set for this particular script,
15780 		// set for kerning via kern table
15781 		// e.g. Latin script when useOTL set as 0x80
15782 		if (isset($this->OTLtags['Plus']) && strpos($this->OTLtags['Plus'], 'kern') !== false && empty($this->OTLdata['GPOSinfo'])) {
15783 			$this->textvar = ($this->textvar | TextVars::FC_KERNING);
15784 		}
15785 		$arr[8] = $this->textvar; // mPDF 5.7.1
15786 		if (isset($this->textparam) && $this->textparam) {
15787 			$arr[9] = $this->textparam;
15788 		}
15789 		if (isset($this->spanbgcolorarray) && $this->spanbgcolorarray) {
15790 			$arr[10] = $this->spanbgcolorarray;
15791 		}
15792 		$arr[11] = $this->currentfontsize;
15793 		if (isset($this->ReqFontStyle) && $this->ReqFontStyle) {
15794 			$arr[12] = $this->ReqFontStyle;
15795 		}
15796 		if (isset($this->lSpacingCSS) && $this->lSpacingCSS) {
15797 			$arr[14] = $this->lSpacingCSS;
15798 		}
15799 		if (isset($this->wSpacingCSS) && $this->wSpacingCSS) {
15800 			$arr[15] = $this->wSpacingCSS;
15801 		}
15802 		if (isset($this->spanborddet) && $this->spanborddet) {
15803 			$arr[16] = $this->spanborddet;
15804 		}
15805 		if (isset($this->textshadow) && $this->textshadow) {
15806 			$arr[17] = $this->textshadow;
15807 		}
15808 		if (isset($this->OTLdata) && $this->OTLdata) {
15809 			$arr[18] = $this->OTLdata;
15810 			$this->OTLdata = [];
15811 		} // mPDF 5.7.1
15812 		else {
15813 			$arr[18] = null;
15814 		}
15815 		// mPDF 6  Lists
15816 		if ($return) {
15817 			return ($arr);
15818 		}
15819 		if ($this->listitem) {
15820 			$this->textbuffer[] = $this->listitem;
15821 			$this->listitem = [];
15822 		}
15823 		$this->textbuffer[] = $arr;
15824 	}
15825 
15826 	function _saveCellTextBuffer($t, $link = '', $intlink = '')
15827 	{
15828 		$arr = [];
15829 		$arr[0] = $t;
15830 		if (isset($link) && $link) {
15831 			$arr[1] = $link;
15832 		}
15833 		$arr[2] = $this->currentfontstyle;
15834 		if (isset($this->colorarray) && $this->colorarray) {
15835 			$arr[3] = $this->colorarray;
15836 		}
15837 		$arr[4] = $this->currentfontfamily;
15838 		if (isset($intlink) && $intlink) {
15839 			$arr[7] = $intlink;
15840 		}
15841 		// mPDF 6
15842 		// If Kerning set for OTL, and useOTL has positive value, but has not set for this particular script,
15843 		// set for kerning via kern table
15844 		// e.g. Latin script when useOTL set as 0x80
15845 		if (isset($this->OTLtags['Plus']) && strpos($this->OTLtags['Plus'], 'kern') !== false && empty($this->OTLdata['GPOSinfo'])) {
15846 			$this->textvar = ($this->textvar | TextVars::FC_KERNING);
15847 		}
15848 		$arr[8] = $this->textvar; // mPDF 5.7.1
15849 		if (isset($this->textparam) && $this->textparam) {
15850 			$arr[9] = $this->textparam;
15851 		}
15852 		if (isset($this->spanbgcolorarray) && $this->spanbgcolorarray) {
15853 			$arr[10] = $this->spanbgcolorarray;
15854 		}
15855 		$arr[11] = $this->currentfontsize;
15856 		if (isset($this->ReqFontStyle) && $this->ReqFontStyle) {
15857 			$arr[12] = $this->ReqFontStyle;
15858 		}
15859 		if (isset($this->lSpacingCSS) && $this->lSpacingCSS) {
15860 			$arr[14] = $this->lSpacingCSS;
15861 		}
15862 		if (isset($this->wSpacingCSS) && $this->wSpacingCSS) {
15863 			$arr[15] = $this->wSpacingCSS;
15864 		}
15865 		if (isset($this->spanborddet) && $this->spanborddet) {
15866 			$arr[16] = $this->spanborddet;
15867 		}
15868 		if (isset($this->textshadow) && $this->textshadow) {
15869 			$arr[17] = $this->textshadow;
15870 		}
15871 		if (isset($this->OTLdata) && $this->OTLdata) {
15872 			$arr[18] = $this->OTLdata;
15873 			$this->OTLdata = [];
15874 		} // mPDF 5.7.1
15875 		else {
15876 			$arr[18] = null;
15877 		}
15878 		$this->cell[$this->row][$this->col]['textbuffer'][] = $arr;
15879 	}
15880 
15881 	function printbuffer($arrayaux, $blockstate = 0, $is_table = false, $table_draft = false, $cell_dir = '')
15882 	{
15883 		// $blockstate = 0;	// NO margins/padding
15884 		// $blockstate = 1;	// Top margins/padding only
15885 		// $blockstate = 2;	// Bottom margins/padding only
15886 		// $blockstate = 3;	// Top & bottom margins/padding
15887 		$this->spanbgcolorarray = '';
15888 		$this->spanbgcolor = false;
15889 		$this->spanborder = false;
15890 		$this->spanborddet = [];
15891 		$paint_ht_corr = 0;
15892 		/* -- CSS-FLOAT -- */
15893 		if (count($this->floatDivs)) {
15894 			list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($this->blklvl);
15895 			if (($this->blk[$this->blklvl]['inner_width'] - $l_width - $r_width) < (2 * $this->GetCharWidth('W', false))) {
15896 				// Too narrow to fit - try to move down past L or R float
15897 				if ($l_max < $r_max && ($this->blk[$this->blklvl]['inner_width'] - $r_width) > (2 * $this->GetCharWidth('W', false))) {
15898 					$this->ClearFloats('LEFT', $this->blklvl);
15899 				} elseif ($r_max < $l_max && ($this->blk[$this->blklvl]['inner_width'] - $l_width) > (2 * $this->GetCharWidth('W', false))) {
15900 					$this->ClearFloats('RIGHT', $this->blklvl);
15901 				} else {
15902 					$this->ClearFloats('BOTH', $this->blklvl);
15903 				}
15904 			}
15905 		}
15906 		/* -- END CSS-FLOAT -- */
15907 		$bak_y = $this->y;
15908 		$bak_x = $this->x;
15909 		$align = '';
15910 		if (!$is_table) {
15911 			if (isset($this->blk[$this->blklvl]['align']) && $this->blk[$this->blklvl]['align']) {
15912 				$align = $this->blk[$this->blklvl]['align'];
15913 			}
15914 			// Block-align is set by e.g. <.. align="center"> Takes priority for this block but not inherited
15915 			if (isset($this->blk[$this->blklvl]['block-align']) && $this->blk[$this->blklvl]['block-align']) {
15916 				$align = $this->blk[$this->blklvl]['block-align'];
15917 			}
15918 			if (isset($this->blk[$this->blklvl]['direction'])) {
15919 				$blockdir = $this->blk[$this->blklvl]['direction'];
15920 			} else {
15921 				$blockdir = "";
15922 			}
15923 			$this->divwidth = $this->blk[$this->blklvl]['width'];
15924 		} else {
15925 			$align = $this->cellTextAlign;
15926 			$blockdir = $cell_dir;
15927 		}
15928 		$oldpage = $this->page;
15929 
15930 		// ADDED for Out of Block now done as Flowing Block
15931 		if ($this->divwidth == 0) {
15932 			$this->divwidth = $this->pgwidth;
15933 		}
15934 
15935 		if (!$is_table) {
15936 			$this->SetLineHeight($this->FontSizePt, $this->blk[$this->blklvl]['line_height']);
15937 		}
15938 		$this->divheight = $this->lineheight;
15939 		$old_height = $this->divheight;
15940 
15941 		// As a failsafe - if font has been set but not output to page
15942 		if (!$table_draft) {
15943 			$this->SetFont($this->default_font, '', $this->default_font_size, true, true); // force output to page
15944 		}
15945 
15946 		$this->newFlowingBlock($this->divwidth, $this->divheight, $align, $is_table, $blockstate, true, $blockdir, $table_draft);
15947 
15948 		$array_size = count($arrayaux);
15949 
15950 		// Added - Otherwise <div><div><p> did not output top margins/padding for 1st/2nd div
15951 		if ($array_size == 0) {
15952 			$this->finishFlowingBlock(true);
15953 		} // true = END of flowing block
15954 		// mPDF 6
15955 		// ALL the chunks of textbuffer need to have at least basic OTLdata set
15956 		// First make sure each element/chunk has the OTLdata for Bidi set.
15957 		for ($i = 0; $i < $array_size; $i++) {
15958 			if (empty($arrayaux[$i][18])) {
15959 				if (substr($arrayaux[$i][0], 0, 3) == "\xbb\xa4\xac") { // object identifier has been identified!
15960 					$unicode = [0xFFFC]; // Object replacement character
15961 				} else {
15962 					$unicode = $this->UTF8StringToArray($arrayaux[$i][0], false);
15963 				}
15964 				$is_strong = false;
15965 				$this->getBasicOTLdata($arrayaux[$i][18], $unicode, $is_strong);
15966 			}
15967 			// Gets messed up if try and use core fonts inside a paragraph of text which needs to be BiDi re-ordered or OTLdata set
15968 			if (($blockdir == 'rtl' || $this->biDirectional) && isset($arrayaux[$i][4]) && in_array($arrayaux[$i][4], ['ccourier', 'ctimes', 'chelvetica', 'csymbol', 'czapfdingbats'])) {
15969 				throw new \Mpdf\MpdfException("You cannot use core fonts in a document which contains RTL text.");
15970 			}
15971 		}
15972 		// mPDF 6
15973 		// Process bidirectional text ready for bidi-re-ordering (which is done after line-breaks are established in WriteFlowingBlock etc.)
15974 		if (($blockdir == 'rtl' || $this->biDirectional) && !$table_draft) {
15975 			if (empty($this->otl)) {
15976 				$this->otl = new Otl($this, $this->fontCache);
15977 			}
15978 			$this->otl->bidiPrepare($arrayaux, $blockdir);
15979 			$array_size = count($arrayaux);
15980 		}
15981 
15982 
15983 		// Remove empty items // mPDF 6
15984 		for ($i = $array_size - 1; $i > 0; $i--) {
15985 			if (empty($arrayaux[$i][0]) && (isset($arrayaux[$i][16]) && $arrayaux[$i][16] !== '0') && empty($arrayaux[$i][7])) {
15986 				unset($arrayaux[$i]);
15987 			}
15988 		}
15989 
15990 		// Correct adjoining borders for inline elements
15991 		if (isset($arrayaux[0][16])) {
15992 			$lastspanborder = $arrayaux[0][16];
15993 		} else {
15994 			$lastspanborder = false;
15995 		}
15996 		for ($i = 1; $i < $array_size; $i++) {
15997 			if (isset($arrayaux[$i][16]) && $arrayaux[$i][16] == $lastspanborder &&
15998 				((!isset($arrayaux[$i][9]['bord-decoration']) && !isset($arrayaux[$i - 1][9]['bord-decoration'])) ||
15999 				(isset($arrayaux[$i][9]['bord-decoration']) && isset($arrayaux[$i - 1][9]['bord-decoration']) && $arrayaux[$i][9]['bord-decoration'] == $arrayaux[$i - 1][9]['bord-decoration'])
16000 				)
16001 			) {
16002 				if (isset($arrayaux[$i][16]['R'])) {
16003 					$lastspanborder = $arrayaux[$i][16];
16004 				} else {
16005 					$lastspanborder = false;
16006 				}
16007 				$arrayaux[$i][16]['L']['s'] = 0;
16008 				$arrayaux[$i][16]['L']['w'] = 0;
16009 				$arrayaux[$i - 1][16]['R']['s'] = 0;
16010 				$arrayaux[$i - 1][16]['R']['w'] = 0;
16011 			} else {
16012 				if (isset($arrayaux[$i][16]['R'])) {
16013 					$lastspanborder = $arrayaux[$i][16];
16014 				} else {
16015 					$lastspanborder = false;
16016 				}
16017 			}
16018 		}
16019 
16020 		for ($i = 0; $i < $array_size; $i++) {
16021 			// COLS
16022 			$oldcolumn = $this->CurrCol;
16023 			$vetor = isset($arrayaux[$i]) ? $arrayaux[$i] : null;
16024 			if ($i == 0 && $vetor[0] != "\n" && ! $this->ispre) {
16025 				$vetor[0] = ltrim($vetor[0]);
16026 				if (!empty($vetor[18])) {
16027 					$this->otl->trimOTLdata($vetor[18], true, false);
16028 				} // *OTL*
16029 			}
16030 
16031 			// FIXED TO ALLOW IT TO SHOW '0'
16032 			if (empty($vetor[0]) && !($vetor[0] === '0') && empty($vetor[7])) { // Ignore empty text and not carrying an internal link
16033 				// Check if it is the last element. If so then finish printing the block
16034 				if ($i == ($array_size - 1)) {
16035 					$this->finishFlowingBlock(true);
16036 				} // true = END of flowing block
16037 				continue;
16038 			}
16039 
16040 
16041 			// Activating buffer properties
16042 			if (isset($vetor[11]) && $vetor[11] != '') {   // Font Size
16043 				if ($is_table && $this->shrin_k) {
16044 					$this->SetFontSize($vetor[11] / $this->shrin_k, false);
16045 				} else {
16046 					$this->SetFontSize($vetor[11], false);
16047 				}
16048 			}
16049 
16050 			if (isset($vetor[17]) && !empty($vetor[17])) { // TextShadow
16051 				$this->textshadow = $vetor[17];
16052 			}
16053 			if (isset($vetor[16]) && !empty($vetor[16])) { // Border
16054 				$this->spanborddet = $vetor[16];
16055 				$this->spanborder = true;
16056 			}
16057 
16058 			if (isset($vetor[15])) {   // Word spacing
16059 				$this->wSpacingCSS = $vetor[15];
16060 				if ($this->wSpacingCSS && strtoupper($this->wSpacingCSS) != 'NORMAL') {
16061 					$this->minwSpacing = $this->sizeConverter->convert($this->wSpacingCSS, $this->FontSize) / $this->shrin_k; // mPDF 5.7.3
16062 				}
16063 			}
16064 			if (isset($vetor[14])) {   // Letter spacing
16065 				$this->lSpacingCSS = $vetor[14];
16066 				if (($this->lSpacingCSS || $this->lSpacingCSS === '0') && strtoupper($this->lSpacingCSS) != 'NORMAL') {
16067 					$this->fixedlSpacing = $this->sizeConverter->convert($this->lSpacingCSS, $this->FontSize) / $this->shrin_k; // mPDF 5.7.3
16068 				}
16069 			}
16070 
16071 
16072 			if (isset($vetor[10]) and ! empty($vetor[10])) { // Background color
16073 				$this->spanbgcolorarray = $vetor[10];
16074 				$this->spanbgcolor = true;
16075 			}
16076 			if (isset($vetor[9]) and ! empty($vetor[9])) { // Text parameters - Outline + hyphens
16077 				$this->textparam = $vetor[9];
16078 				$this->SetTextOutline($this->textparam);
16079 				// mPDF 5.7.3  inline text-decoration parameters
16080 				if ($is_table && $this->shrin_k) {
16081 					if (isset($this->textparam['text-baseline'])) {
16082 						$this->textparam['text-baseline'] /= $this->shrin_k;
16083 					}
16084 					if (isset($this->textparam['decoration-baseline'])) {
16085 						$this->textparam['decoration-baseline'] /= $this->shrin_k;
16086 					}
16087 					if (isset($this->textparam['decoration-fontsize'])) {
16088 						$this->textparam['decoration-fontsize'] /= $this->shrin_k;
16089 					}
16090 				}
16091 			}
16092 			if (isset($vetor[8])) {  // mPDF 5.7.1
16093 				$this->textvar = $vetor[8];
16094 			}
16095 			if (isset($vetor[7]) and $vetor[7] != '') { // internal target: <a name="anyvalue">
16096 				$ily = $this->y;
16097 				if ($this->table_rotate) {
16098 					$this->internallink[$vetor[7]] = ["Y" => $ily, "PAGE" => $this->page, "tbrot" => true];
16099 				} elseif ($this->kwt) {
16100 					$this->internallink[$vetor[7]] = ["Y" => $ily, "PAGE" => $this->page, "kwt" => true];
16101 				} elseif ($this->ColActive) {
16102 					$this->internallink[$vetor[7]] = ["Y" => $ily, "PAGE" => $this->page, "col" => $this->CurrCol];
16103 				} elseif (!$this->keep_block_together) {
16104 					$this->internallink[$vetor[7]] = ["Y" => $ily, "PAGE" => $this->page];
16105 				}
16106 				if (empty($vetor[0])) { // Ignore empty text
16107 					// Check if it is the last element. If so then finish printing the block
16108 					if ($i == ($array_size - 1)) {
16109 						$this->finishFlowingBlock(true);
16110 					} // true = END of flowing block
16111 					continue;
16112 				}
16113 			}
16114 			if (isset($vetor[5]) and $vetor[5] != '') {  // Language	// mPDF 6
16115 				$this->currentLang = $vetor[5];
16116 			}
16117 			if (isset($vetor[4]) and $vetor[4] != '') {  // Font Family
16118 				$font = $this->SetFont($vetor[4], $this->FontStyle, 0, false);
16119 			}
16120 			if (!empty($vetor[3])) { // Font Color
16121 				$cor = $vetor[3];
16122 				$this->SetTColor($cor);
16123 			}
16124 			if (isset($vetor[2]) and $vetor[2] != '') { // Bold,Italic styles
16125 				$this->SetStyles($vetor[2]);
16126 			}
16127 
16128 			if (isset($vetor[12]) and $vetor[12] != '') { // Requested Bold,Italic
16129 				$this->ReqFontStyle = $vetor[12];
16130 			}
16131 			if (isset($vetor[1]) and $vetor[1] != '') { // LINK
16132 				if (strpos($vetor[1], ".") === false && strpos($vetor[1], "@") !== 0) { // assuming every external link has a dot indicating extension (e.g: .html .txt .zip www.somewhere.com etc.)
16133 					// Repeated reference to same anchor?
16134 					while (array_key_exists($vetor[1], $this->internallink)) {
16135 						$vetor[1] = "#" . $vetor[1];
16136 					}
16137 					$this->internallink[$vetor[1]] = $this->AddLink();
16138 					$vetor[1] = $this->internallink[$vetor[1]];
16139 				}
16140 				$this->HREF = $vetor[1];     // HREF link style set here ******
16141 			}
16142 
16143 			// SPECIAL CONTENT - IMAGES & FORM OBJECTS
16144 			// Print-out special content
16145 
16146 			if (substr($vetor[0], 0, 3) == "\xbb\xa4\xac") { // identifier has been identified!
16147 				$objattr = $this->_getObjAttr($vetor[0]);
16148 
16149 				/* -- TABLES -- */
16150 				if ($objattr['type'] == 'nestedtable') {
16151 					if ($objattr['nestedcontent']) {
16152 						$level = $objattr['level'];
16153 						$table = &$this->table[$level][$objattr['table']];
16154 
16155 						if ($table_draft) {
16156 							$this->y += $this->table[($level + 1)][$objattr['nestedcontent']]['h']; // nested table height
16157 							$this->finishFlowingBlock(false, 'nestedtable');
16158 						} else {
16159 							$cell = &$table['cells'][$objattr['row']][$objattr['col']];
16160 							$this->finishFlowingBlock(false, 'nestedtable');
16161 							$save_dw = $this->divwidth;
16162 							$save_buffer = $this->cellBorderBuffer;
16163 							$this->cellBorderBuffer = [];
16164 							$ncx = $this->x;
16165 							list($dummyx, $w) = $this->_tableGetWidth($table, $objattr['row'], $objattr['col']);
16166 							$ntw = $this->table[($level + 1)][$objattr['nestedcontent']]['w']; // nested table width
16167 							if (!$this->simpleTables) {
16168 								if ($this->packTableData) {
16169 									list($bt, $br, $bb, $bl) = $this->_getBorderWidths($cell['borderbin']);
16170 								} else {
16171 									$br = $cell['border_details']['R']['w'];
16172 									$bl = $cell['border_details']['L']['w'];
16173 								}
16174 								if ($table['borders_separate']) {
16175 									$innerw = $w - $bl - $br - $cell['padding']['L'] - $cell['padding']['R'] - $table['border_spacing_H'];
16176 								} else {
16177 									$innerw = $w - $bl / 2 - $br / 2 - $cell['padding']['L'] - $cell['padding']['R'];
16178 								}
16179 							} elseif ($this->simpleTables) {
16180 								if ($table['borders_separate']) {
16181 									$innerw = $w - $table['simple']['border_details']['L']['w'] - $table['simple']['border_details']['R']['w'] - $cell['padding']['L'] - $cell['padding']['R'] - $table['border_spacing_H'];
16182 								} else {
16183 									$innerw = $w - $table['simple']['border_details']['L']['w'] / 2 - $table['simple']['border_details']['R']['w'] / 2 - $cell['padding']['L'] - $cell['padding']['R'];
16184 								}
16185 							}
16186 							if ($cell['a'] == 'C' || $this->table[($level + 1)][$objattr['nestedcontent']]['a'] == 'C') {
16187 								$ncx += ($innerw - $ntw) / 2;
16188 							} elseif ($cell['a'] == 'R' || $this->table[($level + 1)][$objattr['nestedcontent']]['a'] == 'R') {
16189 								$ncx += $innerw - $ntw;
16190 							}
16191 							$this->x = $ncx;
16192 
16193 							$this->_tableWrite($this->table[($level + 1)][$objattr['nestedcontent']]);
16194 							$this->cellBorderBuffer = $save_buffer;
16195 							$this->x = $bak_x;
16196 							$this->divwidth = $save_dw;
16197 						}
16198 
16199 						$this->newFlowingBlock($this->divwidth, $this->divheight, $align, $is_table, $blockstate, false, $blockdir, $table_draft);
16200 					}
16201 				} else {
16202 					/* -- END TABLES -- */
16203 					if ($is_table) { // *TABLES*
16204 						$maxWidth = $this->divwidth;  // *TABLES*
16205 					} // *TABLES*
16206 					else { // *TABLES*
16207 						$maxWidth = $this->divwidth - ($this->blk[$this->blklvl]['padding_left'] + $this->blk[$this->blklvl]['border_left']['w'] + $this->blk[$this->blklvl]['padding_right'] + $this->blk[$this->blklvl]['border_right']['w']);
16208 					} // *TABLES*
16209 
16210 					/* -- CSS-IMAGE-FLOAT -- */
16211 					// If float (already) exists at this level
16212 					if (isset($this->floatmargins['R']) && $this->y <= $this->floatmargins['R']['y1'] && $this->y >= $this->floatmargins['R']['y0']) {
16213 						$maxWidth -= $this->floatmargins['R']['w'];
16214 					}
16215 					if (isset($this->floatmargins['L']) && $this->y <= $this->floatmargins['L']['y1'] && $this->y >= $this->floatmargins['L']['y0']) {
16216 						$maxWidth -= $this->floatmargins['L']['w'];
16217 					}
16218 					/* -- END CSS-IMAGE-FLOAT -- */
16219 
16220 					list($skipln) = $this->inlineObject($objattr['type'], '', $this->y, $objattr, $this->lMargin, ($this->flowingBlockAttr['contentWidth'] / Mpdf::SCALE), $maxWidth, $this->flowingBlockAttr['height'], false, $is_table);
16221 					//  1 -> New line needed because of width
16222 					// -1 -> Will fit width on line but NEW PAGE REQUIRED because of height
16223 					// -2 -> Will not fit on line therefore needs new line but thus NEW PAGE REQUIRED
16224 					$iby = $this->y;
16225 					$oldpage = $this->page;
16226 					$oldcol = $this->CurrCol;
16227 					if (($skipln == 1 || $skipln == -2) && !isset($objattr['float'])) {
16228 						$this->finishFlowingBlock(false, $objattr['type']);
16229 						$this->newFlowingBlock($this->divwidth, $this->divheight, $align, $is_table, $blockstate, false, $blockdir, $table_draft);
16230 					}
16231 
16232 					if (!$table_draft) {
16233 						$thispage = $this->page;
16234 						if ($this->CurrCol != $oldcol) {
16235 							$changedcol = true;
16236 						} else {
16237 							$changedcol = false;
16238 						}
16239 
16240 						// the previous lines can already have triggered page break or column change
16241 						if (!$changedcol && $skipln < 0 && $this->AcceptPageBreak() && $thispage == $oldpage) {
16242 							$this->AddPage($this->CurOrientation);
16243 
16244 							// Added to correct Images already set on line before page advanced
16245 							// i.e. if second inline image on line is higher than first and forces new page
16246 							if (count($this->objectbuffer)) {
16247 								$yadj = $iby - $this->y;
16248 								foreach ($this->objectbuffer as $ib => $val) {
16249 									if ($this->objectbuffer[$ib]['OUTER-Y']) {
16250 										$this->objectbuffer[$ib]['OUTER-Y'] -= $yadj;
16251 									}
16252 									if ($this->objectbuffer[$ib]['BORDER-Y']) {
16253 										$this->objectbuffer[$ib]['BORDER-Y'] -= $yadj;
16254 									}
16255 									if ($this->objectbuffer[$ib]['INNER-Y']) {
16256 										$this->objectbuffer[$ib]['INNER-Y'] -= $yadj;
16257 									}
16258 								}
16259 							}
16260 						}
16261 
16262 						// Added to correct for OddEven Margins
16263 						if ($this->page != $oldpage) {
16264 							if (($this->page - $oldpage) % 2 == 1) {
16265 								$bak_x += $this->MarginCorrection;
16266 							}
16267 							$oldpage = $this->page;
16268 							$y = $this->tMargin - $paint_ht_corr;
16269 							$this->oldy = $this->tMargin - $paint_ht_corr;
16270 							$old_height = 0;
16271 						}
16272 						$this->x = $bak_x;
16273 						/* -- COLUMNS -- */
16274 						// COLS
16275 						// OR COLUMN CHANGE
16276 						if ($this->CurrCol != $oldcolumn) {
16277 							if ($this->directionality == 'rtl') { // *OTL*
16278 								$bak_x -= ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap); // *OTL*
16279 							} // *OTL*
16280 							else { // *OTL*
16281 								$bak_x += ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap);
16282 							} // *OTL*
16283 							$this->x = $bak_x;
16284 							$oldcolumn = $this->CurrCol;
16285 							$y = $this->y0 - $paint_ht_corr;
16286 							$this->oldy = $this->y0 - $paint_ht_corr;
16287 							$old_height = 0;
16288 						}
16289 						/* -- END COLUMNS -- */
16290 					}
16291 
16292 					/* -- CSS-IMAGE-FLOAT -- */
16293 					if ($objattr['type'] == 'image' && isset($objattr['float'])) {
16294 						$fy = $this->y;
16295 
16296 						// DIV TOP MARGIN/BORDER/PADDING
16297 						if ($this->flowingBlockAttr['newblock'] && ($this->flowingBlockAttr['blockstate'] == 1 || $this->flowingBlockAttr['blockstate'] == 3) && $this->flowingBlockAttr['lineCount'] == 0) {
16298 							$fy += $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'];
16299 						}
16300 
16301 						if ($objattr['float'] == 'R') {
16302 							$fx = $this->w - $this->rMargin - $objattr['width'] - ($this->blk[$this->blklvl]['outer_right_margin'] + $this->blk[$this->blklvl]['border_right']['w'] + $this->blk[$this->blklvl]['padding_right']);
16303 						} elseif ($objattr['float'] == 'L') {
16304 							$fx = $this->lMargin + ($this->blk[$this->blklvl]['outer_left_margin'] + $this->blk[$this->blklvl]['border_left']['w'] + $this->blk[$this->blklvl]['padding_left']);
16305 						}
16306 						$w = $objattr['width'];
16307 						$h = abs($objattr['height']);
16308 
16309 						$widthLeft = $maxWidth - ($this->flowingBlockAttr['contentWidth'] / Mpdf::SCALE);
16310 						$maxHeight = $this->h - ($this->tMargin + $this->margin_header + $this->bMargin + 10);
16311 						// For Images
16312 						$extraWidth = ($objattr['border_left']['w'] + $objattr['border_right']['w'] + $objattr['margin_left'] + $objattr['margin_right']);
16313 						$extraHeight = ($objattr['border_top']['w'] + $objattr['border_bottom']['w'] + $objattr['margin_top'] + $objattr['margin_bottom']);
16314 
16315 						if ($objattr['itype'] == 'wmf' || $objattr['itype'] == 'svg') {
16316 							$file = $objattr['file'];
16317 							$info = $this->formobjects[$file];
16318 						} else {
16319 							$file = $objattr['file'];
16320 							$info = $this->images[$file];
16321 						}
16322 						$img_w = $w - $extraWidth;
16323 						$img_h = $h - $extraHeight;
16324 						if ($objattr['border_left']['w']) {
16325 							$objattr['BORDER-WIDTH'] = $img_w + (($objattr['border_left']['w'] + $objattr['border_right']['w']) / 2);
16326 							$objattr['BORDER-HEIGHT'] = $img_h + (($objattr['border_top']['w'] + $objattr['border_bottom']['w']) / 2);
16327 							$objattr['BORDER-X'] = $fx + $objattr['margin_left'] + (($objattr['border_left']['w']) / 2);
16328 							$objattr['BORDER-Y'] = $fy + $objattr['margin_top'] + (($objattr['border_top']['w']) / 2);
16329 						}
16330 						$objattr['INNER-WIDTH'] = $img_w;
16331 						$objattr['INNER-HEIGHT'] = $img_h;
16332 						$objattr['INNER-X'] = $fx + $objattr['margin_left'] + ($objattr['border_left']['w']);
16333 						$objattr['INNER-Y'] = $fy + $objattr['margin_top'] + ($objattr['border_top']['w']);
16334 						$objattr['ID'] = $info['i'];
16335 						$objattr['OUTER-WIDTH'] = $w;
16336 						$objattr['OUTER-HEIGHT'] = $h;
16337 						$objattr['OUTER-X'] = $fx;
16338 						$objattr['OUTER-Y'] = $fy;
16339 						if ($objattr['float'] == 'R') {
16340 							// If R float already exists at this level
16341 							$this->floatmargins['R']['skipline'] = false;
16342 							if (isset($this->floatmargins['R']['y1']) && $this->floatmargins['R']['y1'] > 0 && $fy < $this->floatmargins['R']['y1']) {
16343 								$this->WriteFlowingBlock($vetor[0], $vetor[18]);  // mPDF 5.7.1
16344 							} // If L float already exists at this level
16345 							elseif (isset($this->floatmargins['L']['y1']) && $this->floatmargins['L']['y1'] > 0 && $fy < $this->floatmargins['L']['y1']) {
16346 								// Final check distance between floats is not now too narrow to fit text
16347 								$mw = 2 * $this->GetCharWidth('W', false);
16348 								if (($this->blk[$this->blklvl]['inner_width'] - $w - $this->floatmargins['L']['w']) < $mw) {
16349 									$this->WriteFlowingBlock($vetor[0], $vetor[18]);  // mPDF 5.7.1
16350 								} else {
16351 									$this->floatmargins['R']['x'] = $fx;
16352 									$this->floatmargins['R']['w'] = $w;
16353 									$this->floatmargins['R']['y0'] = $fy;
16354 									$this->floatmargins['R']['y1'] = $fy + $h;
16355 									if ($skipln == 1) {
16356 										$this->floatmargins['R']['skipline'] = true;
16357 										$this->floatmargins['R']['id'] = count($this->floatbuffer) + 0;
16358 										$objattr['skipline'] = true;
16359 									}
16360 									$this->floatbuffer[] = $objattr;
16361 								}
16362 							} else {
16363 								$this->floatmargins['R']['x'] = $fx;
16364 								$this->floatmargins['R']['w'] = $w;
16365 								$this->floatmargins['R']['y0'] = $fy;
16366 								$this->floatmargins['R']['y1'] = $fy + $h;
16367 								if ($skipln == 1) {
16368 									$this->floatmargins['R']['skipline'] = true;
16369 									$this->floatmargins['R']['id'] = count($this->floatbuffer) + 0;
16370 									$objattr['skipline'] = true;
16371 								}
16372 								$this->floatbuffer[] = $objattr;
16373 							}
16374 						} elseif ($objattr['float'] == 'L') {
16375 							// If L float already exists at this level
16376 							$this->floatmargins['L']['skipline'] = false;
16377 							if (isset($this->floatmargins['L']['y1']) && $this->floatmargins['L']['y1'] > 0 && $fy < $this->floatmargins['L']['y1']) {
16378 								$this->floatmargins['L']['skipline'] = false;
16379 								$this->WriteFlowingBlock($vetor[0], $vetor[18]);  // mPDF 5.7.1
16380 							} // If R float already exists at this level
16381 							elseif (isset($this->floatmargins['R']['y1']) && $this->floatmargins['R']['y1'] > 0 && $fy < $this->floatmargins['R']['y1']) {
16382 								// Final check distance between floats is not now too narrow to fit text
16383 								$mw = 2 * $this->GetCharWidth('W', false);
16384 								if (($this->blk[$this->blklvl]['inner_width'] - $w - $this->floatmargins['R']['w']) < $mw) {
16385 									$this->WriteFlowingBlock($vetor[0], $vetor[18]);  // mPDF 5.7.1
16386 								} else {
16387 									$this->floatmargins['L']['x'] = $fx + $w;
16388 									$this->floatmargins['L']['w'] = $w;
16389 									$this->floatmargins['L']['y0'] = $fy;
16390 									$this->floatmargins['L']['y1'] = $fy + $h;
16391 									if ($skipln == 1) {
16392 										$this->floatmargins['L']['skipline'] = true;
16393 										$this->floatmargins['L']['id'] = count($this->floatbuffer) + 0;
16394 										$objattr['skipline'] = true;
16395 									}
16396 									$this->floatbuffer[] = $objattr;
16397 								}
16398 							} else {
16399 								$this->floatmargins['L']['x'] = $fx + $w;
16400 								$this->floatmargins['L']['w'] = $w;
16401 								$this->floatmargins['L']['y0'] = $fy;
16402 								$this->floatmargins['L']['y1'] = $fy + $h;
16403 								if ($skipln == 1) {
16404 									$this->floatmargins['L']['skipline'] = true;
16405 									$this->floatmargins['L']['id'] = count($this->floatbuffer) + 0;
16406 									$objattr['skipline'] = true;
16407 								}
16408 								$this->floatbuffer[] = $objattr;
16409 							}
16410 						}
16411 					} else {
16412 						/* -- END CSS-IMAGE-FLOAT -- */
16413 						$this->WriteFlowingBlock($vetor[0], (isset($vetor[18]) ? $vetor[18] : null));  // mPDF 5.7.1
16414 						/* -- CSS-IMAGE-FLOAT -- */
16415 					}
16416 					/* -- END CSS-IMAGE-FLOAT -- */
16417 				} // *TABLES*
16418 			} // END If special content
16419 			else { // THE text
16420 				if ($this->tableLevel) {
16421 					$paint_ht_corr = 0;
16422 				} // To move the y up when new column/page started if div border needed
16423 				else {
16424 					$paint_ht_corr = $this->blk[$this->blklvl]['border_top']['w'];
16425 				}
16426 
16427 				if ($vetor[0] == "\n") { // We are reading a <BR> now turned into newline ("\n")
16428 					if ($this->flowingBlockAttr['content']) {
16429 						$this->finishFlowingBlock(false, 'br');
16430 					} elseif ($is_table) {
16431 						$this->y+= $this->_computeLineheight($this->cellLineHeight);
16432 					} elseif (!$is_table) {
16433 						$this->DivLn($this->lineheight);
16434 						if ($this->ColActive) {
16435 							$this->breakpoints[$this->CurrCol][] = $this->y;
16436 						} // *COLUMNS*
16437 					}
16438 					// Added to correct for OddEven Margins
16439 					if ($this->page != $oldpage) {
16440 						if (($this->page - $oldpage) % 2 == 1) {
16441 							$bak_x += $this->MarginCorrection;
16442 						}
16443 						$oldpage = $this->page;
16444 						$y = $this->tMargin - $paint_ht_corr;
16445 						$this->oldy = $this->tMargin - $paint_ht_corr;
16446 						$old_height = 0;
16447 					}
16448 					$this->x = $bak_x;
16449 					/* -- COLUMNS -- */
16450 					// COLS
16451 					// OR COLUMN CHANGE
16452 					if ($this->CurrCol != $oldcolumn) {
16453 						if ($this->directionality == 'rtl') { // *OTL*
16454 							$bak_x -= ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap); // *OTL*
16455 						} // *OTL*
16456 						else { // *OTL*
16457 							$bak_x += ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap);
16458 						} // *OTL*
16459 						$this->x = $bak_x;
16460 						$oldcolumn = $this->CurrCol;
16461 						$y = $this->y0 - $paint_ht_corr;
16462 						$this->oldy = $this->y0 - $paint_ht_corr;
16463 						$old_height = 0;
16464 					}
16465 					/* -- END COLUMNS -- */
16466 					$this->newFlowingBlock($this->divwidth, $this->divheight, $align, $is_table, $blockstate, false, $blockdir, $table_draft);
16467 				} else {
16468 					$this->WriteFlowingBlock($vetor[0], $vetor[18]);  // mPDF 5.7.1
16469 					// Added to correct for OddEven Margins
16470 					if ($this->page != $oldpage) {
16471 						if (($this->page - $oldpage) % 2 == 1) {
16472 							$bak_x += $this->MarginCorrection;
16473 							$this->x = $bak_x;
16474 						}
16475 						$oldpage = $this->page;
16476 						$y = $this->tMargin - $paint_ht_corr;
16477 						$this->oldy = $this->tMargin - $paint_ht_corr;
16478 						$old_height = 0;
16479 					}
16480 					/* -- COLUMNS -- */
16481 					// COLS
16482 					// OR COLUMN CHANGE
16483 					if ($this->CurrCol != $oldcolumn) {
16484 						if ($this->directionality == 'rtl') { // *OTL*
16485 							$bak_x -= ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap); // *OTL*
16486 						} // *OTL*
16487 						else { // *OTL*
16488 							$bak_x += ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap);
16489 						} // *OTL*
16490 						$this->x = $bak_x;
16491 						$oldcolumn = $this->CurrCol;
16492 						$y = $this->y0 - $paint_ht_corr;
16493 						$this->oldy = $this->y0 - $paint_ht_corr;
16494 						$old_height = 0;
16495 					}
16496 					/* -- END COLUMNS -- */
16497 				}
16498 			}
16499 
16500 			// Check if it is the last element. If so then finish printing the block
16501 			if ($i == ($array_size - 1)) {
16502 				$this->finishFlowingBlock(true); // true = END of flowing block
16503 				// Added to correct for OddEven Margins
16504 				if ($this->page != $oldpage) {
16505 					if (($this->page - $oldpage) % 2 == 1) {
16506 						$bak_x += $this->MarginCorrection;
16507 						$this->x = $bak_x;
16508 					}
16509 					$oldpage = $this->page;
16510 					$y = $this->tMargin - $paint_ht_corr;
16511 					$this->oldy = $this->tMargin - $paint_ht_corr;
16512 					$old_height = 0;
16513 				}
16514 
16515 				/* -- COLUMNS -- */
16516 				// COLS
16517 				// OR COLUMN CHANGE
16518 				if ($this->CurrCol != $oldcolumn) {
16519 					if ($this->directionality == 'rtl') { // *OTL*
16520 						$bak_x -= ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap); // *OTL*
16521 					} // *OTL*
16522 					else { // *OTL*
16523 						$bak_x += ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap);
16524 					} // *OTL*
16525 					$this->x = $bak_x;
16526 					$oldcolumn = $this->CurrCol;
16527 					$y = $this->y0 - $paint_ht_corr;
16528 					$this->oldy = $this->y0 - $paint_ht_corr;
16529 					$old_height = 0;
16530 				}
16531 				/* -- END COLUMNS -- */
16532 			}
16533 
16534 			// RESETTING VALUES
16535 			$this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
16536 			$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
16537 			$this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
16538 			$this->colorarray = '';
16539 			$this->spanbgcolorarray = '';
16540 			$this->spanbgcolor = false;
16541 			$this->spanborder = false;
16542 			$this->spanborddet = [];
16543 			$this->HREF = '';
16544 			$this->textparam = [];
16545 			$this->SetTextOutline();
16546 
16547 			$this->textvar = 0x00; // mPDF 5.7.1
16548 			$this->OTLtags = [];
16549 			$this->textshadow = '';
16550 
16551 			$this->currentfontfamily = '';
16552 			$this->currentfontsize = '';
16553 			$this->currentfontstyle = '';
16554 			$this->currentLang = $this->default_lang;  // mPDF 6
16555 			$this->RestrictUnicodeFonts($this->default_available_fonts); // mPDF 6
16556 			/* -- TABLES -- */
16557 			if ($this->tableLevel) {
16558 				$this->SetLineHeight('', $this->table[1][1]['cellLineHeight']); // *TABLES*
16559 			} else { 			/* -- END TABLES -- */
16560 				if (isset($this->blk[$this->blklvl]['line_height']) && $this->blk[$this->blklvl]['line_height']) {
16561 					$this->SetLineHeight('', $this->blk[$this->blklvl]['line_height']); // sets default line height
16562 				}
16563 			}
16564 			$this->ResetStyles();
16565 			$this->lSpacingCSS = '';
16566 			$this->wSpacingCSS = '';
16567 			$this->fixedlSpacing = false;
16568 			$this->minwSpacing = 0;
16569 			$this->SetDash();
16570 			$this->dash_on = false;
16571 			$this->dotted_on = false;
16572 		}//end of for(i=0;i<arraysize;i++)
16573 
16574 		$this->Reset(); // mPDF 6
16575 		// PAINT DIV BORDER	// DISABLED IN COLUMNS AS DOESN'T WORK WHEN BROKEN ACROSS COLS??
16576 		if ((isset($this->blk[$this->blklvl]['border']) || isset($this->blk[$this->blklvl]['bgcolor']) || isset($this->blk[$this->blklvl]['box_shadow'])) && $blockstate && ($this->y != $this->oldy)) {
16577 			$bottom_y = $this->y; // Does not include Bottom Margin
16578 			if (isset($this->blk[$this->blklvl]['startpage']) && $this->blk[$this->blklvl]['startpage'] != $this->page && $blockstate != 1) {
16579 				$this->PaintDivBB('pagetop', $blockstate);
16580 			} elseif ($blockstate != 1) {
16581 				$this->PaintDivBB('', $blockstate);
16582 			}
16583 			$this->y = $bottom_y;
16584 			$this->x = $bak_x;
16585 		}
16586 
16587 		// Reset Font
16588 		$this->SetFontSize($this->default_font_size, false);
16589 		if ($table_draft) {
16590 			$ch = $this->y - $bak_y;
16591 			$this->y = $bak_y;
16592 			$this->x = $bak_x;
16593 			return $ch;
16594 		}
16595 	}
16596 
16597 	function _setDashBorder($style, $div, $cp, $side)
16598 	{
16599 		if ($style == 'dashed' && (($side == 'L' || $side == 'R') || ($side == 'T' && $div != 'pagetop' && !$cp) || ($side == 'B' && $div != 'pagebottom') )) {
16600 			$dashsize = 2; // final dash will be this + 1*linewidth
16601 			$dashsizek = 1.5; // ratio of Dash/Blank
16602 			$this->SetDash($dashsize, ($dashsize / $dashsizek) + ($this->LineWidth * 2));
16603 		} elseif ($style == 'dotted' || ($side == 'T' && ($div == 'pagetop' || $cp)) || ($side == 'B' && $div == 'pagebottom')) {
16604 			// Round join and cap
16605 			$this->SetLineJoin(1);
16606 			$this->SetLineCap(1);
16607 			$this->SetDash(0.001, ($this->LineWidth * 3));
16608 		}
16609 	}
16610 
16611 	function _setBorderLine($b, $k = 1)
16612 	{
16613 		$this->SetLineWidth($b['w'] / $k);
16614 		$this->SetDColor($b['c']);
16615 		if ($b['c'][0] == 5) { // RGBa
16616 			$this->SetAlpha(ord($b['c'][4]) / 100, 'Normal', false, 'S'); // mPDF 5.7.2
16617 		} elseif ($b['c'][0] == 6) { // CMYKa
16618 			$this->SetAlpha(ord($b['c'][5]) / 100, 'Normal', false, 'S'); // mPDF 5.7.2
16619 		}
16620 	}
16621 
16622 	function PaintDivBB($divider = '', $blockstate = 0, $blvl = 0)
16623 	{
16624 		// Borders & backgrounds are done elsewhere for columns - messes up the repositioning in printcolumnbuffer
16625 		if ($this->ColActive) {
16626 			return;
16627 		} // *COLUMNS*
16628 		if ($this->keep_block_together) {
16629 			return;
16630 		} // mPDF 6
16631 		$save_y = $this->y;
16632 		if (!$blvl) {
16633 			$blvl = $this->blklvl;
16634 		}
16635 		$x0 = $x1 = $y0 = $y1 = 0;
16636 
16637 		// Added mPDF 3.0 Float DIV
16638 		if (isset($this->blk[$blvl]['bb_painted'][$this->page]) && $this->blk[$blvl]['bb_painted'][$this->page]) {
16639 			return;
16640 		} // *CSS-FLOAT*
16641 
16642 		if (isset($this->blk[$blvl]['x0'])) {
16643 			$x0 = $this->blk[$blvl]['x0'];
16644 		} // left
16645 		if (isset($this->blk[$blvl]['y1'])) {
16646 			$y1 = $this->blk[$blvl]['y1'];
16647 		} // bottom
16648 		// Added mPDF 3.0 Float DIV - ensures backgrounds/borders are drawn to bottom of page
16649 		if ($y1 == 0) {
16650 			if ($divider == 'pagebottom') {
16651 				$y1 = $this->h - $this->bMargin;
16652 			} else {
16653 				$y1 = $this->y;
16654 			}
16655 		}
16656 
16657 		$continuingpage = (isset($this->blk[$blvl]['startpage']) && $this->blk[$blvl]['startpage'] != $this->page);
16658 
16659 		if (isset($this->blk[$blvl]['y0'])) {
16660 			$y0 = $this->blk[$blvl]['y0'];
16661 		}
16662 		$h = $y1 - $y0;
16663 		$w = $this->blk[$blvl]['width'];
16664 		$x1 = $x0 + $w;
16665 
16666 		// Set border-widths as used here
16667 		$border_top = $this->blk[$blvl]['border_top']['w'];
16668 		$border_bottom = $this->blk[$blvl]['border_bottom']['w'];
16669 		$border_left = $this->blk[$blvl]['border_left']['w'];
16670 		$border_right = $this->blk[$blvl]['border_right']['w'];
16671 		if (!$this->blk[$blvl]['border_top'] || $divider == 'pagetop' || $continuingpage) {
16672 			$border_top = 0;
16673 		}
16674 		if (!$this->blk[$blvl]['border_bottom'] || $blockstate == 1 || $divider == 'pagebottom') {
16675 			$border_bottom = 0;
16676 		}
16677 
16678 		$brTL_H = 0;
16679 		$brTL_V = 0;
16680 		$brTR_H = 0;
16681 		$brTR_V = 0;
16682 		$brBL_H = 0;
16683 		$brBL_V = 0;
16684 		$brBR_H = 0;
16685 		$brBR_V = 0;
16686 
16687 		$brset = false;
16688 		/* -- BORDER-RADIUS -- */
16689 		if (isset($this->blk[$blvl]['border_radius_TL_H'])) {
16690 			$brTL_H = $this->blk[$blvl]['border_radius_TL_H'];
16691 			$brset = true;
16692 		}
16693 		if (isset($this->blk[$blvl]['border_radius_TL_V'])) {
16694 			$brTL_V = $this->blk[$blvl]['border_radius_TL_V'];
16695 			$brset = true;
16696 		}
16697 		if (isset($this->blk[$blvl]['border_radius_TR_H'])) {
16698 			$brTR_H = $this->blk[$blvl]['border_radius_TR_H'];
16699 			$brset = true;
16700 		}
16701 		if (isset($this->blk[$blvl]['border_radius_TR_V'])) {
16702 			$brTR_V = $this->blk[$blvl]['border_radius_TR_V'];
16703 			$brset = true;
16704 		}
16705 		if (isset($this->blk[$blvl]['border_radius_BR_H'])) {
16706 			$brBR_H = $this->blk[$blvl]['border_radius_BR_H'];
16707 			$brset = true;
16708 		}
16709 		if (isset($this->blk[$blvl]['border_radius_BR_V'])) {
16710 			$brBR_V = $this->blk[$blvl]['border_radius_BR_V'];
16711 			$brset = true;
16712 		}
16713 		if (isset($this->blk[$blvl]['border_radius_BL_H'])) {
16714 			$brBL_H = $this->blk[$blvl]['border_radius_BL_H'];
16715 			$brset = true;
16716 		}
16717 		if (isset($this->blk[$blvl]['border_radius_BL_V'])) {
16718 			$brBL_V = $this->blk[$blvl]['border_radius_BL_V'];
16719 			$brset = true;
16720 		}
16721 
16722 		if (!$this->blk[$blvl]['border_top'] || $divider == 'pagetop' || $continuingpage) {
16723 			$brTL_H = 0;
16724 			$brTL_V = 0;
16725 			$brTR_H = 0;
16726 			$brTR_V = 0;
16727 		}
16728 		if (!$this->blk[$blvl]['border_bottom'] || $blockstate == 1 || $divider == 'pagebottom') {
16729 			$brBL_H = 0;
16730 			$brBL_V = 0;
16731 			$brBR_H = 0;
16732 			$brBR_V = 0;
16733 		}
16734 
16735 		// Disallow border-radius if it is smaller than the border width.
16736 		if ($brTL_H < min($border_left, $border_top)) {
16737 			$brTL_H = $brTL_V = 0;
16738 		}
16739 		if ($brTL_V < min($border_left, $border_top)) {
16740 			$brTL_V = $brTL_H = 0;
16741 		}
16742 		if ($brTR_H < min($border_right, $border_top)) {
16743 			$brTR_H = $brTR_V = 0;
16744 		}
16745 		if ($brTR_V < min($border_right, $border_top)) {
16746 			$brTR_V = $brTR_H = 0;
16747 		}
16748 		if ($brBL_H < min($border_left, $border_bottom)) {
16749 			$brBL_H = $brBL_V = 0;
16750 		}
16751 		if ($brBL_V < min($border_left, $border_bottom)) {
16752 			$brBL_V = $brBL_H = 0;
16753 		}
16754 		if ($brBR_H < min($border_right, $border_bottom)) {
16755 			$brBR_H = $brBR_V = 0;
16756 		}
16757 		if ($brBR_V < min($border_right, $border_bottom)) {
16758 			$brBR_V = $brBR_H = 0;
16759 		}
16760 
16761 		// CHECK FOR radii that sum to > width or height of div ********
16762 		$f = min($h / ($brTL_V + $brBL_V + 0.001), $h / ($brTR_V + $brBR_V + 0.001), $w / ($brTL_H + $brTR_H + 0.001), $w / ($brBL_H + $brBR_H + 0.001));
16763 		if ($f < 1) {
16764 			$brTL_H *= $f;
16765 			$brTL_V *= $f;
16766 			$brTR_H *= $f;
16767 			$brTR_V *= $f;
16768 			$brBL_H *= $f;
16769 			$brBL_V *= $f;
16770 			$brBR_H *= $f;
16771 			$brBR_V *= $f;
16772 		}
16773 		/* -- END BORDER-RADIUS -- */
16774 
16775 		$tbcol = $this->colorConverter->convert(255, $this->PDFAXwarnings);
16776 		for ($l = 0; $l <= $blvl; $l++) {
16777 			if ($this->blk[$l]['bgcolor']) {
16778 				$tbcol = $this->blk[$l]['bgcolorarray'];
16779 			}
16780 		}
16781 
16782 		// BORDERS
16783 		if (isset($this->blk[$blvl]['y0']) && $this->blk[$blvl]['y0']) {
16784 			$y0 = $this->blk[$blvl]['y0'];
16785 		}
16786 		$h = $y1 - $y0;
16787 		$w = $this->blk[$blvl]['width'];
16788 
16789 		if ($this->blk[$blvl]['border_top'] && $divider != 'pagetop' && !$continuingpage) {
16790 			$tbd = $this->blk[$blvl]['border_top'];
16791 
16792 			$legend = '';
16793 			$legbreakL = 0;
16794 			$legbreakR = 0;
16795 			// BORDER LEGEND
16796 			if (isset($this->blk[$blvl]['border_legend']) && $this->blk[$blvl]['border_legend']) {
16797 				$legend = $this->blk[$blvl]['border_legend']; // Same structure array as textbuffer
16798 				$txt = $legend[0] = ltrim($legend[0]);
16799 				if (!empty($legend[18])) {
16800 					$this->otl->trimOTLdata($legend[18], true, false);
16801 				} // *OTL*
16802 				// Set font, size, style, color
16803 				$this->SetFont($legend[4], $legend[2], $legend[11]);
16804 				if (isset($legend[3]) && $legend[3]) {
16805 					$cor = $legend[3];
16806 					$this->SetTColor($cor);
16807 				}
16808 				$stringWidth = $this->GetStringWidth($txt, true, $legend[18], $legend[8]);
16809 				$save_x = $this->x;
16810 				$save_y = $this->y;
16811 				$save_currentfontfamily = $this->FontFamily;
16812 				$save_currentfontsize = $this->FontSizePt;
16813 				$save_currentfontstyle = $this->FontStyle;
16814 				$this->y = $y0 - $this->FontSize / 2 + $this->blk[$blvl]['border_top']['w'] / 2;
16815 				$this->x = $x0 + $this->blk[$blvl]['padding_left'] + $this->blk[$blvl]['border_left']['w'];
16816 
16817 				// Set the distance from the border line to the text ? make configurable variable
16818 				$gap = 0.2 * $this->FontSize;
16819 				$legbreakL = $this->x - $gap;
16820 				$legbreakR = $this->x + $stringWidth + $gap;
16821 				$this->magic_reverse_dir($txt, $this->blk[$blvl]['direction'], $legend[18]);
16822 				$fill = '';
16823 				$this->Cell($stringWidth, $this->FontSize, $txt, '', 0, 'C', $fill, '', 0, 0, 0, 'M', $fill, false, $legend[18], $legend[8]);
16824 				// Reset
16825 				$this->x = $save_x;
16826 				$this->y = $save_y;
16827 				$this->SetFont($save_currentfontfamily, $save_currentfontstyle, $save_currentfontsize);
16828 				$this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
16829 			}
16830 
16831 			if (isset($tbd['s']) && $tbd['s']) {
16832 				if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
16833 					$this->writer->write('q');
16834 					$this->SetLineWidth(0);
16835 					$this->writer->write(sprintf('%.3F %.3F m ', ($x0) * Mpdf::SCALE, ($this->h - ($y0)) * Mpdf::SCALE));
16836 					$this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $border_left) * Mpdf::SCALE, ($this->h - ($y0 + $border_top)) * Mpdf::SCALE));
16837 					$this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $w - $border_right) * Mpdf::SCALE, ($this->h - ($y0 + $border_top)) * Mpdf::SCALE));
16838 					$this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $w) * Mpdf::SCALE, ($this->h - ($y0)) * Mpdf::SCALE));
16839 					$this->writer->write(' h W n '); // Ends path no-op & Sets the clipping path
16840 				}
16841 
16842 				$this->_setBorderLine($tbd);
16843 				if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
16844 					$legbreakL -= $border_top / 2; // because line cap different
16845 					$legbreakR += $border_top / 2;
16846 					$this->_setDashBorder($tbd['style'], $divider, $continuingpage, 'T');
16847 				} /* -- BORDER-RADIUS -- */ elseif (($brTL_V && $brTL_H) || ($brTR_V && $brTR_H) || $tbd['style'] == 'solid' || $tbd['style'] == 'double') {
16848 					$this->SetLineJoin(0);
16849 					$this->SetLineCap(0);
16850 				}
16851 				$s = '';
16852 				if ($brTR_H && $brTR_V) {
16853 					$s .= ($this->_EllipseArc($x0 + $w - $brTR_H, $y0 + $brTR_V, $brTR_H - $border_top / 2, $brTR_V - $border_top / 2, 1, 2, true)) . "\n";
16854 				} else { 				/* -- END BORDER-RADIUS -- */
16855 					if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
16856 						$s .= (sprintf('%.3F %.3F m ', ($x0 + $w) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
16857 					} else {
16858 						$s .= (sprintf('%.3F %.3F m ', ($x0 + $w - ($border_top / 2)) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
16859 					}
16860 				}
16861 				/* -- BORDER-RADIUS -- */
16862 				if ($brTL_H && $brTL_V) {
16863 					if ($legend) {
16864 						if ($legbreakR < ($x0 + $w - $brTR_H)) {
16865 							$s .= (sprintf('%.3F %.3F l ', $legbreakR * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
16866 						}
16867 						if ($legbreakL > ($x0 + $brTL_H )) {
16868 							$s .= (sprintf('%.3F %.3F m ', $legbreakL * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
16869 							$s .= (sprintf('%.3F %.3F l ', ($x0 + $brTL_H ) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE) . "\n");
16870 						} else {
16871 							$s .= (sprintf('%.3F %.3F m ', ($x0 + $brTL_H ) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
16872 						}
16873 					} else {
16874 						$s .= (sprintf('%.3F %.3F l ', ($x0 + $brTL_H ) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
16875 					}
16876 					$s .= ($this->_EllipseArc($x0 + $brTL_H, $y0 + $brTL_V, $brTL_H - $border_top / 2, $brTL_V - $border_top / 2, 2, 1)) . "\n";
16877 				} else {
16878 					/* -- END BORDER-RADIUS -- */
16879 					if ($legend) {
16880 						if ($legbreakR < ($x0 + $w)) {
16881 							$s .= (sprintf('%.3F %.3F l ', $legbreakR * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
16882 						}
16883 						if ($legbreakL > ($x0)) {
16884 							$s .= (sprintf('%.3F %.3F m ', $legbreakL * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
16885 							if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
16886 								$s .= (sprintf('%.3F %.3F l ', ($x0) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
16887 							} else {
16888 								$s .= (sprintf('%.3F %.3F l ', ($x0 + ($border_top / 2)) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
16889 							}
16890 						} elseif ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
16891 							$s .= (sprintf('%.3F %.3F m ', ($x0) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
16892 						} else {
16893 							$s .= (sprintf('%.3F %.3F m ', ($x0 + $border_top / 2) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
16894 						}
16895 					} elseif ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
16896 						$s .= (sprintf('%.3F %.3F l ', ($x0) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
16897 					} else {
16898 						$s .= (sprintf('%.3F %.3F l ', ($x0 + ($border_top / 2)) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
16899 					}
16900 					/* -- BORDER-RADIUS -- */
16901 				}
16902 				/* -- END BORDER-RADIUS -- */
16903 				$s .= 'S' . "\n";
16904 				$this->writer->write($s);
16905 
16906 				if ($tbd['style'] == 'double') {
16907 					$this->SetLineWidth($tbd['w'] / 3);
16908 					$this->SetDColor($tbcol);
16909 					$this->writer->write($s);
16910 				}
16911 				if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
16912 					$this->writer->write('Q');
16913 				}
16914 
16915 				// Reset Corners and Dash off
16916 				$this->SetLineWidth(0.1);
16917 				$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
16918 				$this->SetLineJoin(2);
16919 				$this->SetLineCap(2);
16920 				$this->SetDash();
16921 			}
16922 		}
16923 		// Reinstate line above for dotted line divider when block border crosses a page
16924 		// elseif ($divider == 'pagetop' || $continuingpage) {
16925 
16926 		if ($this->blk[$blvl]['border_bottom'] && $blockstate != 1 && $divider != 'pagebottom') {
16927 			$tbd = $this->blk[$blvl]['border_bottom'];
16928 			if (isset($tbd['s']) && $tbd['s']) {
16929 				if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
16930 					$this->writer->write('q');
16931 					$this->SetLineWidth(0);
16932 					$this->writer->write(sprintf('%.3F %.3F m ', ($x0) * Mpdf::SCALE, ($this->h - ($y0 + $h)) * Mpdf::SCALE));
16933 					$this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $border_left) * Mpdf::SCALE, ($this->h - ($y0 + $h - $border_bottom)) * Mpdf::SCALE));
16934 					$this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $w - $border_right) * Mpdf::SCALE, ($this->h - ($y0 + $h - $border_bottom)) * Mpdf::SCALE));
16935 					$this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $w) * Mpdf::SCALE, ($this->h - ($y0 + $h)) * Mpdf::SCALE));
16936 					$this->writer->write(' h W n '); // Ends path no-op & Sets the clipping path
16937 				}
16938 
16939 				$this->_setBorderLine($tbd);
16940 				if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
16941 					$this->_setDashBorder($tbd['style'], $divider, $continuingpage, 'B');
16942 				} /* -- BORDER-RADIUS -- */ elseif (($brBL_V && $brBL_H) || ($brBR_V && $brBR_H) || $tbd['style'] == 'solid' || $tbd['style'] == 'double') {
16943 					$this->SetLineJoin(0);
16944 					$this->SetLineCap(0);
16945 				}
16946 				$s = '';
16947 				if ($brBL_H && $brBL_V) {
16948 					$s .= ($this->_EllipseArc($x0 + $brBL_H, $y0 + $h - $brBL_V, $brBL_H - $border_bottom / 2, $brBL_V - $border_bottom / 2, 3, 2, true)) . "\n";
16949 				} else { 				/* -- END BORDER-RADIUS -- */
16950 					if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
16951 						$s .= (sprintf('%.3F %.3F m ', ($x0) * Mpdf::SCALE, ($this->h - ($y0 + $h - ($border_bottom / 2))) * Mpdf::SCALE)) . "\n";
16952 					} else {
16953 						$s .= (sprintf('%.3F %.3F m ', ($x0 + ($border_bottom / 2)) * Mpdf::SCALE, ($this->h - ($y0 + $h - ($border_bottom / 2))) * Mpdf::SCALE)) . "\n";
16954 					}
16955 				}
16956 				/* -- BORDER-RADIUS -- */
16957 				if ($brBR_H && $brBR_V) {
16958 					$s .= (sprintf('%.3F %.3F l ', ($x0 + $w - ($border_bottom / 2) - $brBR_H ) * Mpdf::SCALE, ($this->h - ($y0 + $h - ($border_bottom / 2))) * Mpdf::SCALE)) . "\n";
16959 					$s .= ($this->_EllipseArc($x0 + $w - $brBR_H, $y0 + $h - $brBR_V, $brBR_H - $border_bottom / 2, $brBR_V - $border_bottom / 2, 4, 1)) . "\n";
16960 				} else { 				/* -- END BORDER-RADIUS -- */
16961 					if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
16962 						$s .= (sprintf('%.3F %.3F l ', ($x0 + $w) * Mpdf::SCALE, ($this->h - ($y0 + $h - ($border_bottom / 2))) * Mpdf::SCALE)) . "\n";
16963 					} else {
16964 						$s .= (sprintf('%.3F %.3F l ', ($x0 + $w - ($border_bottom / 2)) * Mpdf::SCALE, ($this->h - ($y0 + $h - ($border_bottom / 2))) * Mpdf::SCALE)) . "\n";
16965 					}
16966 				}
16967 				$s .= 'S' . "\n";
16968 				$this->writer->write($s);
16969 
16970 				if ($tbd['style'] == 'double') {
16971 					$this->SetLineWidth($tbd['w'] / 3);
16972 					$this->SetDColor($tbcol);
16973 					$this->writer->write($s);
16974 				}
16975 				if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
16976 					$this->writer->write('Q');
16977 				}
16978 
16979 				// Reset Corners and Dash off
16980 				$this->SetLineWidth(0.1);
16981 				$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
16982 				$this->SetLineJoin(2);
16983 				$this->SetLineCap(2);
16984 				$this->SetDash();
16985 			}
16986 		}
16987 		// Reinstate line below for dotted line divider when block border crosses a page
16988 		// elseif ($blockstate == 1 || $divider == 'pagebottom') {
16989 
16990 		if ($this->blk[$blvl]['border_left']) {
16991 			$tbd = $this->blk[$blvl]['border_left'];
16992 			if (isset($tbd['s']) && $tbd['s']) {
16993 				if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
16994 					$this->writer->write('q');
16995 					$this->SetLineWidth(0);
16996 					$this->writer->write(sprintf('%.3F %.3F m ', ($x0) * Mpdf::SCALE, ($this->h - ($y0)) * Mpdf::SCALE));
16997 					$this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $border_left) * Mpdf::SCALE, ($this->h - ($y0 + $border_top)) * Mpdf::SCALE));
16998 					$this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $border_left) * Mpdf::SCALE, ($this->h - ($y0 + $h - $border_bottom)) * Mpdf::SCALE));
16999 					$this->writer->write(sprintf('%.3F %.3F l ', ($x0) * Mpdf::SCALE, ($this->h - ($y0 + $h)) * Mpdf::SCALE));
17000 					$this->writer->write(' h W n '); // Ends path no-op & Sets the clipping path
17001 				}
17002 
17003 				$this->_setBorderLine($tbd);
17004 				if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
17005 					$this->_setDashBorder($tbd['style'], $divider, $continuingpage, 'L');
17006 				} /* -- BORDER-RADIUS -- */ elseif (($brTL_V && $brTL_H) || ($brBL_V && $brBL_H) || $tbd['style'] == 'solid' || $tbd['style'] == 'double') {
17007 					$this->SetLineJoin(0);
17008 					$this->SetLineCap(0);
17009 				}
17010 				$s = '';
17011 				if ($brTL_V && $brTL_H) {
17012 					$s .= ($this->_EllipseArc($x0 + $brTL_H, $y0 + $brTL_V, $brTL_H - $border_left / 2, $brTL_V - $border_left / 2, 2, 2, true)) . "\n";
17013 				} else { 				/* -- END BORDER-RADIUS -- */
17014 					if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
17015 						$s .= (sprintf('%.3F %.3F m ', ($x0 + ($border_left / 2)) * Mpdf::SCALE, ($this->h - ($y0)) * Mpdf::SCALE)) . "\n";
17016 					} else {
17017 						$s .= (sprintf('%.3F %.3F m ', ($x0 + ($border_left / 2)) * Mpdf::SCALE, ($this->h - ($y0 + ($border_left / 2))) * Mpdf::SCALE)) . "\n";
17018 					}
17019 				}
17020 				/* -- BORDER-RADIUS -- */
17021 				if ($brBL_V && $brBL_H) {
17022 					$s .= (sprintf('%.3F %.3F l ', ($x0 + ($border_left / 2)) * Mpdf::SCALE, ($this->h - ($y0 + $h - ($border_left / 2) - $brBL_V) ) * Mpdf::SCALE)) . "\n";
17023 					$s .= ($this->_EllipseArc($x0 + $brBL_H, $y0 + $h - $brBL_V, $brBL_H - $border_left / 2, $brBL_V - $border_left / 2, 3, 1)) . "\n";
17024 				} else { 				/* -- END BORDER-RADIUS -- */
17025 					if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
17026 						$s .= (sprintf('%.3F %.3F l ', ($x0 + ($border_left / 2)) * Mpdf::SCALE, ($this->h - ($y0 + $h) ) * Mpdf::SCALE)) . "\n";
17027 					} else {
17028 						$s .= (sprintf('%.3F %.3F l ', ($x0 + ($border_left / 2)) * Mpdf::SCALE, ($this->h - ($y0 + $h - ($border_left / 2)) ) * Mpdf::SCALE)) . "\n";
17029 					}
17030 				}
17031 				$s .= 'S' . "\n";
17032 				$this->writer->write($s);
17033 
17034 				if ($tbd['style'] == 'double') {
17035 					$this->SetLineWidth($tbd['w'] / 3);
17036 					$this->SetDColor($tbcol);
17037 					$this->writer->write($s);
17038 				}
17039 				if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
17040 					$this->writer->write('Q');
17041 				}
17042 
17043 				// Reset Corners and Dash off
17044 				$this->SetLineWidth(0.1);
17045 				$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
17046 				$this->SetLineJoin(2);
17047 				$this->SetLineCap(2);
17048 				$this->SetDash();
17049 			}
17050 		}
17051 		if ($this->blk[$blvl]['border_right']) {
17052 			$tbd = $this->blk[$blvl]['border_right'];
17053 			if (isset($tbd['s']) && $tbd['s']) {
17054 				if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
17055 					$this->writer->write('q');
17056 					$this->SetLineWidth(0);
17057 					$this->writer->write(sprintf('%.3F %.3F m ', ($x0 + $w) * Mpdf::SCALE, ($this->h - ($y0)) * Mpdf::SCALE));
17058 					$this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $w - $border_right) * Mpdf::SCALE, ($this->h - ($y0 + $border_top)) * Mpdf::SCALE));
17059 					$this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $w - $border_right) * Mpdf::SCALE, ($this->h - ($y0 + $h - $border_bottom)) * Mpdf::SCALE));
17060 					$this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $w) * Mpdf::SCALE, ($this->h - ($y0 + $h)) * Mpdf::SCALE));
17061 					$this->writer->write(' h W n '); // Ends path no-op & Sets the clipping path
17062 				}
17063 
17064 				$this->_setBorderLine($tbd);
17065 				if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
17066 					$this->_setDashBorder($tbd['style'], $divider, $continuingpage, 'R');
17067 				} /* -- BORDER-RADIUS -- */ elseif (($brTR_V && $brTR_H) || ($brBR_V && $brBR_H) || $tbd['style'] == 'solid' || $tbd['style'] == 'double') {
17068 					$this->SetLineJoin(0);
17069 					$this->SetLineCap(0);
17070 				}
17071 				$s = '';
17072 				if ($brBR_V && $brBR_H) {
17073 					$s .= ($this->_EllipseArc($x0 + $w - $brBR_H, $y0 + $h - $brBR_V, $brBR_H - $border_right / 2, $brBR_V - $border_right / 2, 4, 2, true)) . "\n";
17074 				} else { 				/* -- END BORDER-RADIUS -- */
17075 					if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
17076 						$s .= (sprintf('%.3F %.3F m ', ($x0 + $w - ($border_right / 2)) * Mpdf::SCALE, ($this->h - ($y0 + $h)) * Mpdf::SCALE)) . "\n";
17077 					} else {
17078 						$s .= (sprintf('%.3F %.3F m ', ($x0 + $w - ($border_right / 2)) * Mpdf::SCALE, ($this->h - ($y0 + $h - ($border_right / 2))) * Mpdf::SCALE)) . "\n";
17079 					}
17080 				}
17081 				/* -- BORDER-RADIUS -- */
17082 				if ($brTR_V && $brTR_H) {
17083 					$s .= (sprintf('%.3F %.3F l ', ($x0 + $w - ($border_right / 2)) * Mpdf::SCALE, ($this->h - ($y0 + ($border_right / 2) + $brTR_V) ) * Mpdf::SCALE)) . "\n";
17084 					$s .= ($this->_EllipseArc($x0 + $w - $brTR_H, $y0 + $brTR_V, $brTR_H - $border_right / 2, $brTR_V - $border_right / 2, 1, 1)) . "\n";
17085 				} else { 				/* -- END BORDER-RADIUS -- */
17086 					if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
17087 						$s .= (sprintf('%.3F %.3F l ', ($x0 + $w - ($border_right / 2)) * Mpdf::SCALE, ($this->h - ($y0) ) * Mpdf::SCALE)) . "\n";
17088 					} else {
17089 						$s .= (sprintf('%.3F %.3F l ', ($x0 + $w - ($border_right / 2)) * Mpdf::SCALE, ($this->h - ($y0 + ($border_right / 2)) ) * Mpdf::SCALE)) . "\n";
17090 					}
17091 				}
17092 				$s .= 'S' . "\n";
17093 				$this->writer->write($s);
17094 
17095 				if ($tbd['style'] == 'double') {
17096 					$this->SetLineWidth($tbd['w'] / 3);
17097 					$this->SetDColor($tbcol);
17098 					$this->writer->write($s);
17099 				}
17100 				if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
17101 					$this->writer->write('Q');
17102 				}
17103 
17104 				// Reset Corners and Dash off
17105 				$this->SetLineWidth(0.1);
17106 				$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
17107 				$this->SetLineJoin(2);
17108 				$this->SetLineCap(2);
17109 				$this->SetDash();
17110 			}
17111 		}
17112 
17113 
17114 		$this->SetDash();
17115 		$this->y = $save_y;
17116 
17117 
17118 		// BACKGROUNDS are disabled in columns/kbt/headers - messes up the repositioning in printcolumnbuffer
17119 		if ($this->ColActive || $this->kwt || $this->keep_block_together) {
17120 			return;
17121 		}
17122 
17123 
17124 		$bgx0 = $x0;
17125 		$bgx1 = $x1;
17126 		$bgy0 = $y0;
17127 		$bgy1 = $y1;
17128 
17129 		// Defined br values represent the radius of the outer curve - need to take border-width/2 from each radius for drawing the borders
17130 		if (isset($this->blk[$blvl]['background_clip']) && $this->blk[$blvl]['background_clip'] == 'padding-box') {
17131 			$brbgTL_H = max(0, $brTL_H - $this->blk[$blvl]['border_left']['w']);
17132 			$brbgTL_V = max(0, $brTL_V - $this->blk[$blvl]['border_top']['w']);
17133 			$brbgTR_H = max(0, $brTR_H - $this->blk[$blvl]['border_right']['w']);
17134 			$brbgTR_V = max(0, $brTR_V - $this->blk[$blvl]['border_top']['w']);
17135 			$brbgBL_H = max(0, $brBL_H - $this->blk[$blvl]['border_left']['w']);
17136 			$brbgBL_V = max(0, $brBL_V - $this->blk[$blvl]['border_bottom']['w']);
17137 			$brbgBR_H = max(0, $brBR_H - $this->blk[$blvl]['border_right']['w']);
17138 			$brbgBR_V = max(0, $brBR_V - $this->blk[$blvl]['border_bottom']['w']);
17139 			$bgx0 += $this->blk[$blvl]['border_left']['w'];
17140 			$bgx1 -= $this->blk[$blvl]['border_right']['w'];
17141 			if ($this->blk[$blvl]['border_top'] && $divider != 'pagetop' && !$continuingpage) {
17142 				$bgy0 += $this->blk[$blvl]['border_top']['w'];
17143 			}
17144 			if ($this->blk[$blvl]['border_bottom'] && $blockstate != 1 && $divider != 'pagebottom') {
17145 				$bgy1 -= $this->blk[$blvl]['border_bottom']['w'];
17146 			}
17147 		} elseif (isset($this->blk[$blvl]['background_clip']) && $this->blk[$blvl]['background_clip'] == 'content-box') {
17148 			$brbgTL_H = max(0, $brTL_H - $this->blk[$blvl]['border_left']['w'] - $this->blk[$blvl]['padding_left']);
17149 			$brbgTL_V = max(0, $brTL_V - $this->blk[$blvl]['border_top']['w'] - $this->blk[$blvl]['padding_top']);
17150 			$brbgTR_H = max(0, $brTR_H - $this->blk[$blvl]['border_right']['w'] - $this->blk[$blvl]['padding_right']);
17151 			$brbgTR_V = max(0, $brTR_V - $this->blk[$blvl]['border_top']['w'] - $this->blk[$blvl]['padding_top']);
17152 			$brbgBL_H = max(0, $brBL_H - $this->blk[$blvl]['border_left']['w'] - $this->blk[$blvl]['padding_left']);
17153 			$brbgBL_V = max(0, $brBL_V - $this->blk[$blvl]['border_bottom']['w'] - $this->blk[$blvl]['padding_bottom']);
17154 			$brbgBR_H = max(0, $brBR_H - $this->blk[$blvl]['border_right']['w'] - $this->blk[$blvl]['padding_right']);
17155 			$brbgBR_V = max(0, $brBR_V - $this->blk[$blvl]['border_bottom']['w'] - $this->blk[$blvl]['padding_bottom']);
17156 			$bgx0 += $this->blk[$blvl]['border_left']['w'] + $this->blk[$blvl]['padding_left'];
17157 			$bgx1 -= $this->blk[$blvl]['border_right']['w'] + $this->blk[$blvl]['padding_right'];
17158 			if (($this->blk[$blvl]['border_top']['w'] || $this->blk[$blvl]['padding_top']) && $divider != 'pagetop' && !$continuingpage) {
17159 				$bgy0 += $this->blk[$blvl]['border_top']['w'] + $this->blk[$blvl]['padding_top'];
17160 			}
17161 			if (($this->blk[$blvl]['border_bottom']['w'] || $this->blk[$blvl]['padding_bottom']) && $blockstate != 1 && $divider != 'pagebottom') {
17162 				$bgy1 -= $this->blk[$blvl]['border_bottom']['w'] + $this->blk[$blvl]['padding_bottom'];
17163 			}
17164 		} else {
17165 			$brbgTL_H = $brTL_H;
17166 			$brbgTL_V = $brTL_V;
17167 			$brbgTR_H = $brTR_H;
17168 			$brbgTR_V = $brTR_V;
17169 			$brbgBL_H = $brBL_H;
17170 			$brbgBL_V = $brBL_V;
17171 			$brbgBR_H = $brBR_H;
17172 			$brbgBR_V = $brBR_V;
17173 		}
17174 
17175 		// Set clipping path
17176 		$s = ' q 0 w '; // Line width=0
17177 		$s .= sprintf('%.3F %.3F m ', ($bgx0 + $brbgTL_H ) * Mpdf::SCALE, ($this->h - $bgy0) * Mpdf::SCALE); // start point TL before the arc
17178 		/* -- BORDER-RADIUS -- */
17179 		if ($brbgTL_H || $brbgTL_V) {
17180 			$s .= $this->_EllipseArc($bgx0 + $brbgTL_H, $bgy0 + $brbgTL_V, $brbgTL_H, $brbgTL_V, 2); // segment 2 TL
17181 		}
17182 		/* -- END BORDER-RADIUS -- */
17183 		$s .= sprintf('%.3F %.3F l ', ($bgx0) * Mpdf::SCALE, ($this->h - ($bgy1 - $brbgBL_V )) * Mpdf::SCALE); // line to BL
17184 		/* -- BORDER-RADIUS -- */
17185 		if ($brbgBL_H || $brbgBL_V) {
17186 			$s .= $this->_EllipseArc($bgx0 + $brbgBL_H, $bgy1 - $brbgBL_V, $brbgBL_H, $brbgBL_V, 3); // segment 3 BL
17187 		}
17188 		/* -- END BORDER-RADIUS -- */
17189 		$s .= sprintf('%.3F %.3F l ', ($bgx1 - $brbgBR_H ) * Mpdf::SCALE, ($this->h - ($bgy1)) * Mpdf::SCALE); // line to BR
17190 		/* -- BORDER-RADIUS -- */
17191 		if ($brbgBR_H || $brbgBR_V) {
17192 			$s .= $this->_EllipseArc($bgx1 - $brbgBR_H, $bgy1 - $brbgBR_V, $brbgBR_H, $brbgBR_V, 4); // segment 4 BR
17193 		}
17194 		/* -- END BORDER-RADIUS -- */
17195 		$s .= sprintf('%.3F %.3F l ', ($bgx1) * Mpdf::SCALE, ($this->h - ($bgy0 + $brbgTR_V)) * Mpdf::SCALE); // line to TR
17196 		/* -- BORDER-RADIUS -- */
17197 		if ($brbgTR_H || $brbgTR_V) {
17198 			$s .= $this->_EllipseArc($bgx1 - $brbgTR_H, $bgy0 + $brbgTR_V, $brbgTR_H, $brbgTR_V, 1); // segment 1 TR
17199 		}
17200 		/* -- END BORDER-RADIUS -- */
17201 		$s .= sprintf('%.3F %.3F l ', ($bgx0 + $brbgTL_H ) * Mpdf::SCALE, ($this->h - $bgy0) * Mpdf::SCALE); // line to TL
17202 		// Box Shadow
17203 		$shadow = '';
17204 		if (isset($this->blk[$blvl]['box_shadow']) && $this->blk[$blvl]['box_shadow'] && $h > 0) {
17205 			foreach ($this->blk[$blvl]['box_shadow'] as $sh) {
17206 				// Colors
17207 				if ($sh['col'][0] == 1) {
17208 					$colspace = 'Gray';
17209 					if ($sh['col'][2] == 1) {
17210 						$col1 = '1' . $sh['col'][1] . '1' . $sh['col'][3];
17211 					} else {
17212 						$col1 = '1' . $sh['col'][1] . '1' . chr(100);
17213 					}
17214 					$col2 = '1' . $sh['col'][1] . '1' . chr(0);
17215 				} elseif ($sh['col'][0] == 4) { // CMYK
17216 					$colspace = 'CMYK';
17217 					$col1 = '6' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . $sh['col'][4] . chr(100);
17218 					$col2 = '6' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . $sh['col'][4] . chr(0);
17219 				} elseif ($sh['col'][0] == 5) { // RGBa
17220 					$colspace = 'RGB';
17221 					$col1 = '5' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . $sh['col'][4];
17222 					$col2 = '5' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . chr(0);
17223 				} elseif ($sh['col'][0] == 6) { // CMYKa
17224 					$colspace = 'CMYK';
17225 					$col1 = '6' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . $sh['col'][4] . $sh['col'][5];
17226 					$col2 = '6' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . $sh['col'][4] . chr(0);
17227 				} else {
17228 					$colspace = 'RGB';
17229 					$col1 = '5' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . chr(100);
17230 					$col2 = '5' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . chr(0);
17231 				}
17232 
17233 				// Use clipping path as set above (and rectangle around page) to clip area outside box
17234 				$shadow .= $s; // Use the clipping path with W*
17235 				$shadow .= sprintf('0 %.3F m %.3F %.3F l ', $this->h * Mpdf::SCALE, $this->w * Mpdf::SCALE, $this->h * Mpdf::SCALE);
17236 				$shadow .= sprintf('%.3F 0 l 0 0 l 0 %.3F l ', $this->w * Mpdf::SCALE, $this->h * Mpdf::SCALE);
17237 				$shadow .= 'W n' . "\n";
17238 
17239 				$sh['blur'] = abs($sh['blur']); // cannot have negative blur value
17240 				// Ensure spread/blur do not make effective shadow width/height < 0
17241 				// Could do more complex things but this just adjusts spread value
17242 				if (-$sh['spread'] + $sh['blur'] / 2 > min($w / 2, $h / 2)) {
17243 					$sh['spread'] = $sh['blur'] / 2 - min($w / 2, $h / 2) + 0.01;
17244 				}
17245 				// Shadow Offset
17246 				if ($sh['x'] || $sh['y']) {
17247 					$shadow .= sprintf(' q 1 0 0 1 %.4F %.4F cm', $sh['x'] * Mpdf::SCALE, -$sh['y'] * Mpdf::SCALE) . "\n";
17248 				}
17249 
17250 				// Set path for INNER shadow
17251 				$shadow .= ' q 0 w ';
17252 				$shadow .= $this->SetFColor($col1, true) . "\n";
17253 				if ($col1[0] == 5 && ord($col1[4]) < 100) { // RGBa
17254 					$shadow .= $this->SetAlpha(ord($col1[4]) / 100, 'Normal', true, 'F') . "\n";
17255 				} elseif ($col1[0] == 6 && ord($col1[5]) < 100) { // CMYKa
17256 					$shadow .= $this->SetAlpha(ord($col1[5]) / 100, 'Normal', true, 'F') . "\n";
17257 				} elseif ($col1[0] == 1 && $col1[2] == 1 && ord($col1[3]) < 100) { // Gray
17258 					$shadow .= $this->SetAlpha(ord($col1[3]) / 100, 'Normal', true, 'F') . "\n";
17259 				}
17260 
17261 				// Blur edges
17262 				$mag = 0.551784; // Bezier Control magic number for 4-part spline for circle/ellipse
17263 				$mag2 = 0.551784; // Bezier Control magic number to fill in edge of blurred rectangle
17264 				$d1 = $sh['spread'] + $sh['blur'] / 2;
17265 				$d2 = $sh['spread'] - $sh['blur'] / 2;
17266 				$bl = $sh['blur'];
17267 				$x00 = $x0 - $d1;
17268 				$y00 = $y0 - $d1;
17269 				$w00 = $w + $d1 * 2;
17270 				$h00 = $h + $d1 * 2;
17271 
17272 				// If any border-radius is greater width-negative spread(inner edge), ignore radii for shadow or screws up
17273 				$flatten = false;
17274 				if (max($brbgTR_H, $brbgTL_H, $brbgBR_H, $brbgBL_H) >= $w + $d2) {
17275 					$flatten = true;
17276 				}
17277 				if (max($brbgTR_V, $brbgTL_V, $brbgBR_V, $brbgBL_V) >= $h + $d2) {
17278 					$flatten = true;
17279 				}
17280 
17281 
17282 				// TOP RIGHT corner
17283 				$p1x = $x00 + $w00 - $d1 - $brbgTR_H;
17284 				$p1c2x = $p1x + ($d2 + $brbgTR_H) * $mag;
17285 				$p1y = $y00 + $bl;
17286 				$p2x = $x00 + $w00 - $d1 - $brbgTR_H;
17287 				$p2c2x = $p2x + ($d1 + $brbgTR_H) * $mag;
17288 				$p2y = $y00;
17289 				$p2c1y = $p2y + $bl / 2;
17290 				$p3x = $x00 + $w00;
17291 				$p3c2x = $p3x - $bl / 2;
17292 				$p3y = $y00 + $d1 + $brbgTR_V;
17293 				$p3c1y = $p3y - ($d1 + $brbgTR_V) * $mag;
17294 				$p4x = $x00 + $w00 - $bl;
17295 				$p4y = $y00 + $d1 + $brbgTR_V;
17296 				$p4c2y = $p4y - ($d2 + $brbgTR_V) * $mag;
17297 				if (-$d2 > min($brbgTR_H, $brbgTR_V) || $flatten) {
17298 					$p1x = $x00 + $w00 - $bl;
17299 					$p1c2x = $p1x;
17300 					$p2x = $x00 + $w00 - $bl;
17301 					$p2c2x = $p2x + $bl * $mag2;
17302 					$p3y = $y00 + $bl;
17303 					$p3c1y = $p3y - $bl * $mag2;
17304 					$p4y = $y00 + $bl;
17305 					$p4c2y = $p4y;
17306 				}
17307 
17308 				$shadow .= sprintf('%.3F %.3F m ', ($p1x ) * Mpdf::SCALE, ($this->h - ($p1y )) * Mpdf::SCALE);
17309 				$shadow .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', ($p1c2x) * Mpdf::SCALE, ($this->h - ($p1y)) * Mpdf::SCALE, ($p4x) * Mpdf::SCALE, ($this->h - ($p4c2y)) * Mpdf::SCALE, ($p4x) * Mpdf::SCALE, ($this->h - ($p4y)) * Mpdf::SCALE);
17310 				$patch_array[0]['f'] = 0;
17311 				$patch_array[0]['points'] = [$p1x, $p1y, $p1x, $p1y,
17312 					$p2x, $p2c1y, $p2x, $p2y, $p2c2x, $p2y,
17313 					$p3x, $p3c1y, $p3x, $p3y, $p3c2x, $p3y,
17314 					$p4x, $p4y, $p4x, $p4y, $p4x, $p4c2y,
17315 					$p1c2x, $p1y];
17316 				$patch_array[0]['colors'] = [$col1, $col2, $col2, $col1];
17317 
17318 
17319 				// RIGHT
17320 				$p1x = $x00 + $w00; // control point only matches p3 preceding
17321 				$p1y = $y00 + $d1 + $brbgTR_V;
17322 				$p2x = $x00 + $w00 - $bl; // control point only matches p4 preceding
17323 				$p2y = $y00 + $d1 + $brbgTR_V;
17324 				$p3x = $x00 + $w00 - $bl;
17325 				$p3y = $y00 + $h00 - $d1 - $brbgBR_V;
17326 				$p4x = $x00 + $w00;
17327 				$p4c1x = $p4x - $bl / 2;
17328 				$p4y = $y00 + $h00 - $d1 - $brbgBR_V;
17329 				if (-$d2 > min($brbgTR_H, $brbgTR_V) || $flatten) {
17330 					$p1y = $y00 + $bl;
17331 					$p2y = $y00 + $bl;
17332 				}
17333 				if (-$d2 > min($brbgBR_H, $brbgBR_V) || $flatten) {
17334 					$p3y = $y00 + $h00 - $bl;
17335 					$p4y = $y00 + $h00 - $bl;
17336 				}
17337 
17338 				$shadow .= sprintf('%.3F %.3F l ', ($p3x ) * Mpdf::SCALE, ($this->h - ($p3y )) * Mpdf::SCALE);
17339 				$patch_array[1]['f'] = 2;
17340 				$patch_array[1]['points'] = [$p2x, $p2y,
17341 					$p3x, $p3y, $p3x, $p3y, $p3x, $p3y,
17342 					$p4c1x, $p4y, $p4x, $p4y, $p4x, $p4y,
17343 					$p1x, $p1y];
17344 				$patch_array[1]['colors'] = [$col1, $col2];
17345 
17346 
17347 				// BOTTOM RIGHT corner
17348 				$p1x = $x00 + $w00 - $bl;  // control points only matches p3 preceding
17349 				$p1y = $y00 + $h00 - $d1 - $brbgBR_V;
17350 				$p1c2y = $p1y + ($d2 + $brbgBR_V) * $mag;
17351 				$p2x = $x00 + $w00;     // control point only matches p4 preceding
17352 				$p2y = $y00 + $h00 - $d1 - $brbgBR_V;
17353 				$p2c2y = $p2y + ($d1 + $brbgBR_V) * $mag;
17354 				$p3x = $x00 + $w00 - $d1 - $brbgBR_H;
17355 				$p3c1x = $p3x + ($d1 + $brbgBR_H) * $mag;
17356 				$p3y = $y00 + $h00;
17357 				$p3c2y = $p3y - $bl / 2;
17358 				$p4x = $x00 + $w00 - $d1 - $brbgBR_H;
17359 				$p4c2x = $p4x + ($d2 + $brbgBR_H) * $mag;
17360 				$p4y = $y00 + $h00 - $bl;
17361 
17362 				if (-$d2 > min($brbgBR_H, $brbgBR_V) || $flatten) {
17363 					$p1y = $y00 + $h00 - $bl;
17364 					$p1c2y = $p1y;
17365 					$p2y = $y00 + $h00 - $bl;
17366 					$p2c2y = $p2y + $bl * $mag2;
17367 					$p3x = $x00 + $w00 - $bl;
17368 					$p3c1x = $p3x + $bl * $mag2;
17369 					$p4x = $x00 + $w00 - $bl;
17370 					$p4c2x = $p4x;
17371 				}
17372 
17373 				$shadow .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', ($p1x) * Mpdf::SCALE, ($this->h - ($p1c2y)) * Mpdf::SCALE, ($p4c2x) * Mpdf::SCALE, ($this->h - ($p4y)) * Mpdf::SCALE, ($p4x) * Mpdf::SCALE, ($this->h - ($p4y)) * Mpdf::SCALE);
17374 				$patch_array[2]['f'] = 2;
17375 				$patch_array[2]['points'] = [$p2x, $p2c2y,
17376 					$p3c1x, $p3y, $p3x, $p3y, $p3x, $p3c2y,
17377 					$p4x, $p4y, $p4x, $p4y, $p4c2x, $p4y,
17378 					$p1x, $p1c2y];
17379 				$patch_array[2]['colors'] = [$col2, $col1];
17380 
17381 
17382 
17383 				// BOTTOM
17384 				$p1x = $x00 + $w00 - $d1 - $brbgBR_H; // control point only matches p3 preceding
17385 				$p1y = $y00 + $h00;
17386 				$p2x = $x00 + $w00 - $d1 - $brbgBR_H; // control point only matches p4 preceding
17387 				$p2y = $y00 + $h00 - $bl;
17388 				$p3x = $x00 + $d1 + $brbgBL_H;
17389 				$p3y = $y00 + $h00 - $bl;
17390 				$p4x = $x00 + $d1 + $brbgBL_H;
17391 				$p4y = $y00 + $h00;
17392 				$p4c1y = $p4y - $bl / 2;
17393 
17394 				if (-$d2 > min($brbgBR_H, $brbgBR_V) || $flatten) {
17395 					$p1x = $x00 + $w00 - $bl;
17396 					$p2x = $x00 + $w00 - $bl;
17397 				}
17398 				if (-$d2 > min($brbgBL_H, $brbgBL_V) || $flatten) {
17399 					$p3x = $x00 + $bl;
17400 					$p4x = $x00 + $bl;
17401 				}
17402 
17403 				$shadow .= sprintf('%.3F %.3F l ', ($p3x ) * Mpdf::SCALE, ($this->h - ($p3y )) * Mpdf::SCALE);
17404 				$patch_array[3]['f'] = 2;
17405 				$patch_array[3]['points'] = [$p2x, $p2y,
17406 					$p3x, $p3y, $p3x, $p3y, $p3x, $p3y,
17407 					$p4x, $p4c1y, $p4x, $p4y, $p4x, $p4y,
17408 					$p1x, $p1y];
17409 				$patch_array[3]['colors'] = [$col1, $col2];
17410 
17411 				// BOTTOM LEFT corner
17412 				$p1x = $x00 + $d1 + $brbgBL_H;
17413 				$p1c2x = $p1x - ($d2 + $brbgBL_H) * $mag; // control points only matches p3 preceding
17414 				$p1y = $y00 + $h00 - $bl;
17415 				$p2x = $x00 + $d1 + $brbgBL_H;
17416 				$p2c2x = $p2x - ($d1 + $brbgBL_H) * $mag; // control point only matches p4 preceding
17417 				$p2y = $y00 + $h00;
17418 				$p3x = $x00;
17419 				$p3c2x = $p3x + $bl / 2;
17420 				$p3y = $y00 + $h00 - $d1 - $brbgBL_V;
17421 				$p3c1y = $p3y + ($d1 + $brbgBL_V) * $mag;
17422 				$p4x = $x00 + $bl;
17423 				$p4y = $y00 + $h00 - $d1 - $brbgBL_V;
17424 				$p4c2y = $p4y + ($d2 + $brbgBL_V) * $mag;
17425 				if (-$d2 > min($brbgBL_H, $brbgBL_V) || $flatten) {
17426 					$p1x = $x00 + $bl;
17427 					$p1c2x = $p1x;
17428 					$p2x = $x00 + $bl;
17429 					$p2c2x = $p2x - $bl * $mag2;
17430 					$p3y = $y00 + $h00 - $bl;
17431 					$p3c1y = $p3y + $bl * $mag2;
17432 					$p4y = $y00 + $h00 - $bl;
17433 					$p4c2y = $p4y;
17434 				}
17435 
17436 				$shadow .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', ($p1c2x) * Mpdf::SCALE, ($this->h - ($p1y)) * Mpdf::SCALE, ($p4x) * Mpdf::SCALE, ($this->h - ($p4c2y)) * Mpdf::SCALE, ($p4x) * Mpdf::SCALE, ($this->h - ($p4y)) * Mpdf::SCALE);
17437 				$patch_array[4]['f'] = 2;
17438 				$patch_array[4]['points'] = [$p2c2x, $p2y,
17439 					$p3x, $p3c1y, $p3x, $p3y, $p3c2x, $p3y,
17440 					$p4x, $p4y, $p4x, $p4y, $p4x, $p4c2y,
17441 					$p1c2x, $p1y];
17442 				$patch_array[4]['colors'] = [$col2, $col1];
17443 
17444 
17445 				// LEFT - joins on the right (C3-C4 of previous): f = 2
17446 				$p1x = $x00; // control point only matches p3 preceding
17447 				$p1y = $y00 + $h00 - $d1 - $brbgBL_V;
17448 				$p2x = $x00 + $bl; // control point only matches p4 preceding
17449 				$p2y = $y00 + $h00 - $d1 - $brbgBL_V;
17450 				$p3x = $x00 + $bl;
17451 				$p3y = $y00 + $d1 + $brbgTL_V;
17452 				$p4x = $x00;
17453 				$p4c1x = $p4x + $bl / 2;
17454 				$p4y = $y00 + $d1 + $brbgTL_V;
17455 				if (-$d2 > min($brbgBL_H, $brbgBL_V) || $flatten) {
17456 					$p1y = $y00 + $h00 - $bl;
17457 					$p2y = $y00 + $h00 - $bl;
17458 				}
17459 				if (-$d2 > min($brbgTL_H, $brbgTL_V) || $flatten) {
17460 					$p3y = $y00 + $bl;
17461 					$p4y = $y00 + $bl;
17462 				}
17463 
17464 				$shadow .= sprintf('%.3F %.3F l ', ($p3x ) * Mpdf::SCALE, ($this->h - ($p3y )) * Mpdf::SCALE);
17465 				$patch_array[5]['f'] = 2;
17466 				$patch_array[5]['points'] = [$p2x, $p2y,
17467 					$p3x, $p3y, $p3x, $p3y, $p3x, $p3y,
17468 					$p4c1x, $p4y, $p4x, $p4y, $p4x, $p4y,
17469 					$p1x, $p1y];
17470 				$patch_array[5]['colors'] = [$col1, $col2];
17471 
17472 				// TOP LEFT corner
17473 				$p1x = $x00 + $bl;  // control points only matches p3 preceding
17474 				$p1y = $y00 + $d1 + $brbgTL_V;
17475 				$p1c2y = $p1y - ($d2 + $brbgTL_V) * $mag;
17476 				$p2x = $x00;   // control point only matches p4 preceding
17477 				$p2y = $y00 + $d1 + $brbgTL_V;
17478 				$p2c2y = $p2y - ($d1 + $brbgTL_V) * $mag;
17479 				$p3x = $x00 + $d1 + $brbgTL_H;
17480 				$p3c1x = $p3x - ($d1 + $brbgTL_H) * $mag;
17481 				$p3y = $y00;
17482 				$p3c2y = $p3y + $bl / 2;
17483 				$p4x = $x00 + $d1 + $brbgTL_H;
17484 				$p4c2x = $p4x - ($d2 + $brbgTL_H) * $mag;
17485 				$p4y = $y00 + $bl;
17486 
17487 				if (-$d2 > min($brbgTL_H, $brbgTL_V) || $flatten) {
17488 					$p1y = $y00 + $bl;
17489 					$p1c2y = $p1y;
17490 					$p2y = $y00 + $bl;
17491 					$p2c2y = $p2y - $bl * $mag2;
17492 					$p3x = $x00 + $bl;
17493 					$p3c1x = $p3x - $bl * $mag2;
17494 					$p4x = $x00 + $bl;
17495 					$p4c2x = $p4x;
17496 				}
17497 
17498 				$shadow .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', ($p1x) * Mpdf::SCALE, ($this->h - ($p1c2y)) * Mpdf::SCALE, ($p4c2x) * Mpdf::SCALE, ($this->h - ($p4y)) * Mpdf::SCALE, ($p4x) * Mpdf::SCALE, ($this->h - ($p4y)) * Mpdf::SCALE);
17499 				$patch_array[6]['f'] = 2;
17500 				$patch_array[6]['points'] = [$p2x, $p2c2y,
17501 					$p3c1x, $p3y, $p3x, $p3y, $p3x, $p3c2y,
17502 					$p4x, $p4y, $p4x, $p4y, $p4c2x, $p4y,
17503 					$p1x, $p1c2y];
17504 				$patch_array[6]['colors'] = [$col2, $col1];
17505 
17506 
17507 				// TOP - joins on the right (C3-C4 of previous): f = 2
17508 				$p1x = $x00 + $d1 + $brbgTL_H; // control point only matches p3 preceding
17509 				$p1y = $y00;
17510 				$p2x = $x00 + $d1 + $brbgTL_H; // control point only matches p4 preceding
17511 				$p2y = $y00 + $bl;
17512 				$p3x = $x00 + $w00 - $d1 - $brbgTR_H;
17513 				$p3y = $y00 + $bl;
17514 				$p4x = $x00 + $w00 - $d1 - $brbgTR_H;
17515 				$p4y = $y00;
17516 				$p4c1y = $p4y + $bl / 2;
17517 				if (-$d2 > min($brbgTL_H, $brbgTL_V) || $flatten) {
17518 					$p1x = $x00 + $bl;
17519 					$p2x = $x00 + $bl;
17520 				}
17521 				if (-$d2 > min($brbgTR_H, $brbgTR_V) || $flatten) {
17522 					$p3x = $x00 + $w00 - $bl;
17523 					$p4x = $x00 + $w00 - $bl;
17524 				}
17525 
17526 				$shadow .= sprintf('%.3F %.3F l ', ($p3x ) * Mpdf::SCALE, ($this->h - ($p3y )) * Mpdf::SCALE);
17527 				$patch_array[7]['f'] = 2;
17528 				$patch_array[7]['points'] = [$p2x, $p2y,
17529 					$p3x, $p3y, $p3x, $p3y, $p3x, $p3y,
17530 					$p4x, $p4c1y, $p4x, $p4y, $p4x, $p4y,
17531 					$p1x, $p1y];
17532 				$patch_array[7]['colors'] = [$col1, $col2];
17533 
17534 				$shadow .= ' h f Q ' . "\n"; // Close path and Fill the inner solid shadow
17535 
17536 				if ($bl) {
17537 					$shadow .= $this->gradient->CoonsPatchMesh($x00, $y00, $w00, $h00, $patch_array, $x00, $x00 + $w00, $y00, $y00 + $h00, $colspace, true);
17538 				}
17539 
17540 				if ($sh['x'] || $sh['y']) {
17541 					$shadow .= ' Q' . "\n";  // Shadow Offset
17542 				}
17543 				$shadow .= ' Q' . "\n"; // Ends path no-op & Sets the clipping path
17544 			}
17545 		}
17546 
17547 		$s .= ' W n '; // Ends path no-op & Sets the clipping path
17548 
17549 		if ($this->blk[$blvl]['bgcolor']) {
17550 			$this->pageBackgrounds[$blvl][] = [
17551 				'x' => $x0,
17552 				'y' => $y0,
17553 				'w' => $w,
17554 				'h' => $h,
17555 				'col' => $this->blk[$blvl]['bgcolorarray'],
17556 				'clippath' => $s,
17557 				'visibility' => $this->visibility,
17558 				'shadow' => $shadow,
17559 				'z-index' => $this->current_layer,
17560 			];
17561 		} elseif ($shadow) {
17562 			$this->pageBackgrounds[$blvl][] = [
17563 				'x' => 0,
17564 				'y' => 0,
17565 				'w' => 0,
17566 				'h' => 0,
17567 				'shadowonly' => true,
17568 				'col' => '',
17569 				'clippath' => '',
17570 				'visibility' => $this->visibility,
17571 				'shadow' => $shadow,
17572 				'z-index' => $this->current_layer,
17573 			];
17574 		}
17575 
17576 		/* -- BACKGROUNDS -- */
17577 		if (isset($this->blk[$blvl]['gradient'])) {
17578 			$g = $this->gradient->parseBackgroundGradient($this->blk[$blvl]['gradient']);
17579 			if ($g) {
17580 				$gx = $x0;
17581 				$gy = $y0;
17582 				$this->pageBackgrounds[$blvl][] = [
17583 					'gradient' => true,
17584 					'x' => $gx,
17585 					'y' => $gy,
17586 					'w' => $w,
17587 					'h' => $h,
17588 					'gradtype' => $g['type'],
17589 					'stops' => $g['stops'],
17590 					'colorspace' => $g['colorspace'],
17591 					'coords' => $g['coords'],
17592 					'extend' => $g['extend'],
17593 					'clippath' => $s,
17594 					'visibility' => $this->visibility,
17595 					'z-index' => $this->current_layer
17596 				];
17597 			}
17598 		}
17599 
17600 		if (isset($this->blk[$blvl]['background-image'])) {
17601 			if (isset($this->blk[$blvl]['background-image']['gradient']) && $this->blk[$blvl]['background-image']['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $this->blk[$blvl]['background-image']['gradient'])) {
17602 				$g = $this->gradient->parseMozGradient($this->blk[$blvl]['background-image']['gradient']);
17603 				if ($g) {
17604 					$gx = $x0;
17605 					$gy = $y0;
17606 					// origin specifies the background-positioning-area (bpa)
17607 					if ($this->blk[$blvl]['background-image']['origin'] == 'padding-box') {
17608 						$gx += $this->blk[$blvl]['border_left']['w'];
17609 						$w -= ($this->blk[$blvl]['border_left']['w'] + $this->blk[$blvl]['border_right']['w']);
17610 						if ($this->blk[$blvl]['border_top'] && $divider != 'pagetop' && !$continuingpage) {
17611 							$gy += $this->blk[$blvl]['border_top']['w'];
17612 						}
17613 						if ($this->blk[$blvl]['border_bottom'] && $blockstate != 1 && $divider != 'pagebottom') {
17614 							$gy1 = $y1 - $this->blk[$blvl]['border_bottom']['w'];
17615 						} else {
17616 							$gy1 = $y1;
17617 						}
17618 						$h = $gy1 - $gy;
17619 					} elseif ($this->blk[$blvl]['background-image']['origin'] == 'content-box') {
17620 						$gx += $this->blk[$blvl]['border_left']['w'] + $this->blk[$blvl]['padding_left'];
17621 						$w -= ($this->blk[$blvl]['border_left']['w'] + $this->blk[$blvl]['padding_left'] + $this->blk[$blvl]['border_right']['w'] + $this->blk[$blvl]['padding_right']);
17622 						if ($this->blk[$blvl]['border_top'] && $divider != 'pagetop' && !$continuingpage) {
17623 							$gy += $this->blk[$blvl]['border_top']['w'] + $this->blk[$blvl]['padding_top'];
17624 						}
17625 						if ($this->blk[$blvl]['border_bottom'] && $blockstate != 1 && $divider != 'pagebottom') {
17626 							$gy1 = $y1 - ($this->blk[$blvl]['border_bottom']['w'] + $this->blk[$blvl]['padding_bottom']);
17627 						} else {
17628 							$gy1 = $y1 - $this->blk[$blvl]['padding_bottom'];
17629 						}
17630 						$h = $gy1 - $gy;
17631 					}
17632 
17633 					if (isset($this->blk[$blvl]['background-image']['size']['w']) && $this->blk[$blvl]['background-image']['size']['w']) {
17634 						$size = $this->blk[$blvl]['background-image']['size'];
17635 						if ($size['w'] != 'contain' && $size['w'] != 'cover') {
17636 							if (stristr($size['w'], '%')) {
17637 								$size['w'] = (float) $size['w'];
17638 								$size['w'] /= 100;
17639 								$w *= $size['w'];
17640 							} elseif ($size['w'] != 'auto') {
17641 								$w = $size['w'];
17642 							}
17643 							if (stristr($size['h'], '%')) {
17644 								$size['h'] = (float) $size['h'];
17645 								$size['h'] /= 100;
17646 								$h *= $size['h'];
17647 							} elseif ($size['h'] != 'auto') {
17648 								$h = $size['h'];
17649 							}
17650 						}
17651 					}
17652 					$this->pageBackgrounds[$blvl][] = [
17653 						'gradient' => true,
17654 						'x' => $gx,
17655 						'y' => $gy,
17656 						'w' => $w,
17657 						'h' => $h,
17658 						'gradtype' => $g['type'],
17659 						'stops' => $g['stops'],
17660 						'colorspace' => $g['colorspace'],
17661 						'coords' => $g['coords'],
17662 						'extend' => $g['extend'],
17663 						'clippath' => $s,
17664 						'visibility' => $this->visibility,
17665 						'z-index' => $this->current_layer
17666 					];
17667 				}
17668 
17669 			} else {
17670 
17671 				$image_id = $this->blk[$blvl]['background-image']['image_id'];
17672 				$orig_w = $this->blk[$blvl]['background-image']['orig_w'];
17673 				$orig_h = $this->blk[$blvl]['background-image']['orig_h'];
17674 				$x_pos = $this->blk[$blvl]['background-image']['x_pos'];
17675 				$y_pos = $this->blk[$blvl]['background-image']['y_pos'];
17676 				$x_repeat = $this->blk[$blvl]['background-image']['x_repeat'];
17677 				$y_repeat = $this->blk[$blvl]['background-image']['y_repeat'];
17678 				$resize = $this->blk[$blvl]['background-image']['resize'];
17679 				$opacity = $this->blk[$blvl]['background-image']['opacity'];
17680 				$itype = $this->blk[$blvl]['background-image']['itype'];
17681 				$size = $this->blk[$blvl]['background-image']['size'];
17682 				// origin specifies the background-positioning-area (bpa)
17683 
17684 				$bpa = ['x' => $x0, 'y' => $y0, 'w' => $w, 'h' => $h];
17685 
17686 				if ($this->blk[$blvl]['background-image']['origin'] == 'padding-box') {
17687 
17688 					$bpa['x'] = $x0 + $this->blk[$blvl]['border_left']['w'];
17689 					$bpa['w'] = $w - ($this->blk[$blvl]['border_left']['w'] + $this->blk[$blvl]['border_right']['w']);
17690 					if ($this->blk[$blvl]['border_top'] && $divider != 'pagetop' && !$continuingpage) {
17691 						$bpa['y'] = $y0 + $this->blk[$blvl]['border_top']['w'];
17692 					} else {
17693 						$bpa['y'] = $y0;
17694 					}
17695 					if ($this->blk[$blvl]['border_bottom'] && $blockstate != 1 && $divider != 'pagebottom') {
17696 						$bpay = $y1 - $this->blk[$blvl]['border_bottom']['w'];
17697 					} else {
17698 						$bpay = $y1;
17699 					}
17700 					$bpa['h'] = $bpay - $bpa['y'];
17701 
17702 				} elseif ($this->blk[$blvl]['background-image']['origin'] == 'content-box') {
17703 
17704 					$bpa['x'] = $x0 + $this->blk[$blvl]['border_left']['w'] + $this->blk[$blvl]['padding_left'];
17705 					$bpa['w'] = $w - ($this->blk[$blvl]['border_left']['w'] + $this->blk[$blvl]['padding_left'] + $this->blk[$blvl]['border_right']['w'] + $this->blk[$blvl]['padding_right']);
17706 					if ($this->blk[$blvl]['border_top'] && $divider != 'pagetop' && !$continuingpage) {
17707 						$bpa['y'] = $y0 + $this->blk[$blvl]['border_top']['w'] + $this->blk[$blvl]['padding_top'];
17708 					} else {
17709 						$bpa['y'] = $y0 + $this->blk[$blvl]['padding_top'];
17710 					}
17711 					if ($this->blk[$blvl]['border_bottom'] && $blockstate != 1 && $divider != 'pagebottom') {
17712 						$bpay = $y1 - ($this->blk[$blvl]['border_bottom']['w'] + $this->blk[$blvl]['padding_bottom']);
17713 					} else {
17714 						$bpay = $y1 - $this->blk[$blvl]['padding_bottom'];
17715 					}
17716 					$bpa['h'] = $bpay - $bpa['y'];
17717 
17718 				}
17719 
17720 				$this->pageBackgrounds[$blvl][] = [
17721 					'x' => $x0,
17722 					'y' => $y0,
17723 					'w' => $w,
17724 					'h' => $h,
17725 					'image_id' => $image_id,
17726 					'orig_w' => $orig_w,
17727 					'orig_h' => $orig_h,
17728 					'x_pos' => $x_pos,
17729 					'y_pos' => $y_pos,
17730 					'x_repeat' => $x_repeat,
17731 					'y_repeat' => $y_repeat,
17732 					'clippath' => $s,
17733 					'resize' => $resize,
17734 					'opacity' => $opacity,
17735 					'itype' => $itype,
17736 					'visibility' => $this->visibility,
17737 					'z-index' => $this->current_layer,
17738 					'size' => $size,
17739 					'bpa' => $bpa
17740 				];
17741 			}
17742 		}
17743 		/* -- END BACKGROUNDS -- */
17744 
17745 		// Float DIV
17746 		$this->blk[$blvl]['bb_painted'][$this->page] = true;
17747 	}
17748 	/* -- BORDER-RADIUS -- */
17749 
17750 	function _EllipseArc($x0, $y0, $rx, $ry, $seg = 1, $part = false, $start = false)
17751 	{
17752 		// Anticlockwise segment 1-4 TR-TL-BL-BR (part=1 or 2)
17753 		$s = '';
17754 
17755 		if ($rx < 0) {
17756 			$rx = 0;
17757 		}
17758 
17759 		if ($ry < 0) {
17760 			$ry = 0;
17761 		}
17762 
17763 		$rx *= Mpdf::SCALE;
17764 		$ry *= Mpdf::SCALE;
17765 
17766 		$astart = 0;
17767 
17768 		if ($seg == 1) { // Top Right
17769 			$afinish = 90;
17770 			$nSeg = 4;
17771 		} elseif ($seg == 2) { // Top Left
17772 			$afinish = 180;
17773 			$nSeg = 8;
17774 		} elseif ($seg == 3) { // Bottom Left
17775 			$afinish = 270;
17776 			$nSeg = 12;
17777 		} else {   // Bottom Right
17778 			$afinish = 360;
17779 			$nSeg = 16;
17780 		}
17781 
17782 		$astart = deg2rad((float) $astart);
17783 		$afinish = deg2rad((float) $afinish);
17784 
17785 		$totalAngle = $afinish - $astart;
17786 		$dt = $totalAngle / $nSeg; // segment angle
17787 		$dtm = $dt / 3;
17788 		$x0 *= Mpdf::SCALE;
17789 		$y0 = ($this->h - $y0) * Mpdf::SCALE;
17790 		$t1 = $astart;
17791 		$a0 = $x0 + ($rx * cos($t1));
17792 		$b0 = $y0 + ($ry * sin($t1));
17793 		$c0 = -$rx * sin($t1);
17794 		$d0 = $ry * cos($t1);
17795 		$op = false;
17796 
17797 		for ($i = 1; $i <= $nSeg; $i++) {
17798 			// Draw this bit of the total curve
17799 			$t1 = ($i * $dt) + $astart;
17800 			$a1 = $x0 + ($rx * cos($t1));
17801 			$b1 = $y0 + ($ry * sin($t1));
17802 			$c1 = -$rx * sin($t1);
17803 			$d1 = $ry * cos($t1);
17804 			if ($i > ($nSeg - 4) && (!$part || ($part == 1 && $i <= $nSeg - 2) || ($part == 2 && $i > $nSeg - 2))) {
17805 				if ($start && !$op) {
17806 					$s .= sprintf('%.3F %.3F m ', $a0, $b0);
17807 				}
17808 				$s .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', ($a0 + ($c0 * $dtm)), ($b0 + ($d0 * $dtm)), ($a1 - ($c1 * $dtm)), ($b1 - ($d1 * $dtm)), $a1, $b1);
17809 				$op = true;
17810 			}
17811 			$a0 = $a1;
17812 			$b0 = $b1;
17813 			$c0 = $c1;
17814 			$d0 = $d1;
17815 		}
17816 
17817 		return $s;
17818 	}
17819 
17820 	/* -- END BORDER-RADIUS -- */
17821 
17822 	function PaintDivLnBorder($state = 0, $blvl = 0, $h = 0)
17823 	{
17824 		// $state = 0 normal; 1 top; 2 bottom; 3 top and bottom
17825 		$this->ColDetails[$this->CurrCol]['bottom_margin'] = $this->y + $h;
17826 
17827 		$save_y = $this->y;
17828 
17829 		$w = $this->blk[$blvl]['width'];
17830 		$x0 = $this->x;    // left
17831 		$y0 = $this->y;    // top
17832 		$x1 = $this->x + $w;   // bottom
17833 		$y1 = $this->y + $h;   // bottom
17834 		$continuingpage = (isset($this->blk[$blvl]['startpage']) && $this->blk[$blvl]['startpage'] != $this->page);
17835 
17836 		if ($this->blk[$blvl]['border_top'] && ($state == 1 || $state == 3)) {
17837 			$tbd = $this->blk[$blvl]['border_top'];
17838 			if (isset($tbd['s']) && $tbd['s']) {
17839 				$this->_setBorderLine($tbd);
17840 				$this->y = $y0 + ($tbd['w'] / 2);
17841 				if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
17842 					$this->_setDashBorder($tbd['style'], '', $continuingpage, 'T');
17843 					$this->Line($x0 + ($tbd['w'] / 2), $this->y, $x0 + $w - ($tbd['w'] / 2), $this->y);
17844 				} else {
17845 					$this->SetLineJoin(0);
17846 					$this->SetLineCap(0);
17847 					$this->Line($x0, $this->y, $x0 + $w, $this->y);
17848 				}
17849 				$this->y += $tbd['w'];
17850 				// Reset Corners and Dash off
17851 				$this->SetLineJoin(2);
17852 				$this->SetLineCap(2);
17853 				$this->SetDash();
17854 			}
17855 		}
17856 		if ($this->blk[$blvl]['border_left']) {
17857 			$tbd = $this->blk[$blvl]['border_left'];
17858 			if (isset($tbd['s']) && $tbd['s']) {
17859 				$this->_setBorderLine($tbd);
17860 				if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
17861 					$this->y = $y0 + ($tbd['w'] / 2);
17862 					$this->_setDashBorder($tbd['style'], '', $continuingpage, 'L');
17863 					$this->Line($x0 + ($tbd['w'] / 2), $this->y, $x0 + ($tbd['w'] / 2), $y0 + $h - ($tbd['w'] / 2));
17864 				} else {
17865 					$this->y = $y0;
17866 					$this->SetLineJoin(0);
17867 					$this->SetLineCap(0);
17868 					$this->Line($x0 + ($tbd['w'] / 2), $this->y, $x0 + ($tbd['w'] / 2), $y0 + $h);
17869 				}
17870 				$this->y += $tbd['w'];
17871 				// Reset Corners and Dash off
17872 				$this->SetLineJoin(2);
17873 				$this->SetLineCap(2);
17874 				$this->SetDash();
17875 			}
17876 		}
17877 		if ($this->blk[$blvl]['border_right']) {
17878 			$tbd = $this->blk[$blvl]['border_right'];
17879 			if (isset($tbd['s']) && $tbd['s']) {
17880 				$this->_setBorderLine($tbd);
17881 				if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
17882 					$this->y = $y0 + ($tbd['w'] / 2);
17883 					$this->_setDashBorder($tbd['style'], '', $continuingpage, 'R');
17884 					$this->Line($x0 + $w - ($tbd['w'] / 2), $this->y, $x0 + $w - ($tbd['w'] / 2), $y0 + $h - ($tbd['w'] / 2));
17885 				} else {
17886 					$this->y = $y0;
17887 					$this->SetLineJoin(0);
17888 					$this->SetLineCap(0);
17889 					$this->Line($x0 + $w - ($tbd['w'] / 2), $this->y, $x0 + $w - ($tbd['w'] / 2), $y0 + $h);
17890 				}
17891 				$this->y += $tbd['w'];
17892 				// Reset Corners and Dash off
17893 				$this->SetLineJoin(2);
17894 				$this->SetLineCap(2);
17895 				$this->SetDash();
17896 			}
17897 		}
17898 		if ($this->blk[$blvl]['border_bottom'] && $state > 1) {
17899 			$tbd = $this->blk[$blvl]['border_bottom'];
17900 			if (isset($tbd['s']) && $tbd['s']) {
17901 				$this->_setBorderLine($tbd);
17902 				$this->y = $y0 + $h - ($tbd['w'] / 2);
17903 				if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
17904 					$this->_setDashBorder($tbd['style'], '', $continuingpage, 'B');
17905 					$this->Line($x0 + ($tbd['w'] / 2), $this->y, $x0 + $w - ($tbd['w'] / 2), $this->y);
17906 				} else {
17907 					$this->SetLineJoin(0);
17908 					$this->SetLineCap(0);
17909 					$this->Line($x0, $this->y, $x0 + $w, $this->y);
17910 				}
17911 				$this->y += $tbd['w'];
17912 				// Reset Corners and Dash off
17913 				$this->SetLineJoin(2);
17914 				$this->SetLineCap(2);
17915 				$this->SetDash();
17916 			}
17917 		}
17918 		$this->SetDash();
17919 		$this->y = $save_y;
17920 	}
17921 
17922 	function PaintImgBorder($objattr, $is_table)
17923 	{
17924 		// Borders are disabled in columns - messes up the repositioning in printcolumnbuffer
17925 		if ($this->ColActive) {
17926 			return;
17927 		} // *COLUMNS*
17928 		if ($is_table) {
17929 			$k = $this->shrin_k;
17930 		} else {
17931 			$k = 1;
17932 		}
17933 		$h = (isset($objattr['BORDER-HEIGHT']) ? $objattr['BORDER-HEIGHT'] : 0);
17934 		$w = (isset($objattr['BORDER-WIDTH']) ? $objattr['BORDER-WIDTH'] : 0);
17935 		$x0 = (isset($objattr['BORDER-X']) ? $objattr['BORDER-X'] : 0);
17936 		$y0 = (isset($objattr['BORDER-Y']) ? $objattr['BORDER-Y'] : 0);
17937 
17938 		// BORDERS
17939 		if ($objattr['border_top']) {
17940 			$tbd = $objattr['border_top'];
17941 			if (!empty($tbd['s'])) {
17942 				$this->_setBorderLine($tbd, $k);
17943 				if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
17944 					$this->_setDashBorder($tbd['style'], '', '', 'T');
17945 				}
17946 				$this->Line($x0, $y0, $x0 + $w, $y0);
17947 				// Reset Corners and Dash off
17948 				$this->SetLineJoin(2);
17949 				$this->SetLineCap(2);
17950 				$this->SetDash();
17951 			}
17952 		}
17953 		if ($objattr['border_left']) {
17954 			$tbd = $objattr['border_left'];
17955 			if (!empty($tbd['s'])) {
17956 				$this->_setBorderLine($tbd, $k);
17957 				if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
17958 					$this->_setDashBorder($tbd['style'], '', '', 'L');
17959 				}
17960 				$this->Line($x0, $y0, $x0, $y0 + $h);
17961 				// Reset Corners and Dash off
17962 				$this->SetLineJoin(2);
17963 				$this->SetLineCap(2);
17964 				$this->SetDash();
17965 			}
17966 		}
17967 		if ($objattr['border_right']) {
17968 			$tbd = $objattr['border_right'];
17969 			if (!empty($tbd['s'])) {
17970 				$this->_setBorderLine($tbd, $k);
17971 				if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
17972 					$this->_setDashBorder($tbd['style'], '', '', 'R');
17973 				}
17974 				$this->Line($x0 + $w, $y0, $x0 + $w, $y0 + $h);
17975 				// Reset Corners and Dash off
17976 				$this->SetLineJoin(2);
17977 				$this->SetLineCap(2);
17978 				$this->SetDash();
17979 			}
17980 		}
17981 		if ($objattr['border_bottom']) {
17982 			$tbd = $objattr['border_bottom'];
17983 			if (!empty($tbd['s'])) {
17984 				$this->_setBorderLine($tbd, $k);
17985 				if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
17986 					$this->_setDashBorder($tbd['style'], '', '', 'B');
17987 				}
17988 				$this->Line($x0, $y0 + $h, $x0 + $w, $y0 + $h);
17989 				// Reset Corners and Dash off
17990 				$this->SetLineJoin(2);
17991 				$this->SetLineCap(2);
17992 				$this->SetDash();
17993 			}
17994 		}
17995 		$this->SetDash();
17996 		$this->SetAlpha(1);
17997 	}
17998 
17999 	/* -- END HTML-CSS -- */
18000 
18001 	function Reset()
18002 	{
18003 		$this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
18004 		$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
18005 		$this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
18006 		$this->SetAlpha(1);
18007 		$this->colorarray = '';
18008 
18009 		$this->spanbgcolorarray = '';
18010 		$this->spanbgcolor = false;
18011 		$this->spanborder = false;
18012 		$this->spanborddet = [];
18013 
18014 		$this->ResetStyles();
18015 
18016 		$this->HREF = '';
18017 		$this->textparam = [];
18018 		$this->SetTextOutline();
18019 
18020 		$this->textvar = 0x00; // mPDF 5.7.1
18021 		$this->OTLtags = [];
18022 		$this->textshadow = '';
18023 
18024 		$this->currentLang = $this->default_lang;  // mPDF 6
18025 		$this->RestrictUnicodeFonts($this->default_available_fonts); // mPDF 6
18026 		$this->SetFont($this->default_font, '', 0, false);
18027 		$this->SetFontSize($this->default_font_size, false);
18028 
18029 		$this->currentfontfamily = '';
18030 		$this->currentfontsize = '';
18031 		$this->currentfontstyle = '';
18032 
18033 		if ($this->tableLevel && isset($this->table[1][1]['cellLineHeight'])) {
18034 			$this->SetLineHeight('', $this->table[1][1]['cellLineHeight']);
18035 		} else {
18036 			if (isset($this->blk[$this->blklvl]['line_height']) && $this->blk[$this->blklvl]['line_height']) {
18037 				$this->SetLineHeight('', $this->blk[$this->blklvl]['line_height']); // sets default line height
18038 			}
18039 		}
18040 
18041 		$this->lSpacingCSS = '';
18042 		$this->wSpacingCSS = '';
18043 		$this->fixedlSpacing = false;
18044 		$this->minwSpacing = 0;
18045 		$this->SetDash(); // restore to no dash
18046 		$this->dash_on = false;
18047 		$this->dotted_on = false;
18048 		$this->divwidth = 0;
18049 		$this->divheight = 0;
18050 		$this->cellTextAlign = '';
18051 		$this->cellLineHeight = '';
18052 		$this->cellLineStackingStrategy = '';
18053 		$this->cellLineStackingShift = '';
18054 		$this->oldy = -1;
18055 
18056 		$bodystyle = [];
18057 
18058 		if (isset($this->cssManager->CSS['BODY']['FONT-STYLE'])) {
18059 			$bodystyle['FONT-STYLE'] = $this->cssManager->CSS['BODY']['FONT-STYLE'];
18060 		}
18061 
18062 		if (isset($this->cssManager->CSS['BODY']['FONT-WEIGHT'])) {
18063 			$bodystyle['FONT-WEIGHT'] = $this->cssManager->CSS['BODY']['FONT-WEIGHT'];
18064 		}
18065 
18066 		if (isset($this->cssManager->CSS['BODY']['COLOR'])) {
18067 			$bodystyle['COLOR'] = $this->cssManager->CSS['BODY']['COLOR'];
18068 		}
18069 
18070 		if (isset($bodystyle)) {
18071 			$this->setCSS($bodystyle, 'BLOCK', 'BODY');
18072 		}
18073 	}
18074 
18075 	/* -- HTML-CSS -- */
18076 
18077 	function ReadMetaTags($html)
18078 	{
18079 		// changes anykey=anyvalue to anykey="anyvalue" (only do this when this happens inside tags)
18080 		$regexp = '/ (\\w+?)=([^\\s>"]+)/si';
18081 		$html = preg_replace($regexp, " \$1=\"\$2\"", $html);
18082 		if (preg_match('/<title>(.*?)<\/title>/si', $html, $m)) {
18083 			$this->SetTitle($m[1]);
18084 		}
18085 		preg_match_all('/<meta [^>]*?(name|content)="([^>]*?)" [^>]*?(name|content)="([^>]*?)".*?>/si', $html, $aux);
18086 		$firstattr = $aux[1];
18087 		$secondattr = $aux[3];
18088 		for ($i = 0; $i < count($aux[0]); $i++) {
18089 			$name = ( strtoupper($firstattr[$i]) == "NAME" ) ? strtoupper($aux[2][$i]) : strtoupper($aux[4][$i]);
18090 			$content = ( strtoupper($firstattr[$i]) == "CONTENT" ) ? $aux[2][$i] : $aux[4][$i];
18091 			switch ($name) {
18092 				case "KEYWORDS":
18093 					$this->SetKeywords($content);
18094 					break;
18095 				case "AUTHOR":
18096 					$this->SetAuthor($content);
18097 					break;
18098 				case "DESCRIPTION":
18099 					$this->SetSubject($content);
18100 					break;
18101 			}
18102 		}
18103 	}
18104 
18105 	function ReadCharset($html)
18106 	{
18107 		// Charset conversion
18108 		if ($this->allow_charset_conversion) {
18109 			if (preg_match('/<head.*charset=([^\'\"\s]*).*<\/head>/si', $html, $m)) {
18110 				if (strtoupper($m[1]) != 'UTF-8') {
18111 					$this->charset_in = strtoupper($m[1]);
18112 				}
18113 			}
18114 		}
18115 	}
18116 
18117 	function setCSS($arrayaux, $type = '', $tag = '')
18118 	{
18119 	// type= INLINE | BLOCK | TABLECELL // tag= BODY
18120 		if (!is_array($arrayaux)) {
18121 			return; // Removes PHP Warning
18122 		}
18123 
18124 		// mPDF 5.7.3  inline text-decoration parameters
18125 		$preceeding_fontkey = $this->FontFamily . $this->FontStyle;
18126 		$preceeding_fontsize = $this->FontSize;
18127 		$spanbordset = false;
18128 		$spanbgset = false;
18129 		// mPDF 6
18130 		$prevlevel = (($this->blklvl == 0) ? 0 : $this->blklvl - 1);
18131 
18132 		// Set font size first so that e.g. MARGIN 0.83em works on font size for this element
18133 		if (isset($arrayaux['FONT-SIZE'])) {
18134 			$v = $arrayaux['FONT-SIZE'];
18135 			$firstLetter = substr($v, 0, 1);
18136 			if (is_numeric($firstLetter) || ($firstLetter === '.')) {
18137 				if ($type == 'BLOCK' && $this->blklvl > 0 && isset($this->blk[$this->blklvl - 1]['InlineProperties']) && isset($this->blk[$this->blklvl - 1]['InlineProperties']['size'])) {
18138 					$mmsize = $this->sizeConverter->convert($v, $this->blk[$this->blklvl - 1]['InlineProperties']['size']);
18139 				} elseif ($type == 'TABLECELL') {
18140 					$mmsize = $this->sizeConverter->convert($v, $this->default_font_size / Mpdf::SCALE);
18141 				} else {
18142 					$mmsize = $this->sizeConverter->convert($v, $this->FontSize);
18143 				}
18144 				$this->SetFontSize($mmsize * (Mpdf::SCALE), false); // Get size in points (pt)
18145 			} else {
18146 				$v = strtoupper($v);
18147 				if (isset($this->fontsizes[$v])) {
18148 					$this->SetFontSize($this->fontsizes[$v] * $this->default_font_size, false);
18149 				}
18150 			}
18151 			if ($tag == 'BODY') {
18152 				$this->SetDefaultFontSize($this->FontSizePt);
18153 			}
18154 		}
18155 
18156 		// mPDF 6
18157 		if (isset($arrayaux['LANG']) && $arrayaux['LANG']) {
18158 			if ($this->autoLangToFont && !$this->usingCoreFont) {
18159 				if ($arrayaux['LANG'] != $this->default_lang && $arrayaux['LANG'] != 'UTF-8') {
18160 					list ($coreSuitable, $mpdf_pdf_unifont) = $this->languageToFont->getLanguageOptions($arrayaux['LANG'], $this->useAdobeCJK);
18161 					if ($mpdf_pdf_unifont) {
18162 						$arrayaux['FONT-FAMILY'] = $mpdf_pdf_unifont;
18163 					}
18164 					if ($tag == 'BODY') {
18165 						$this->default_lang = $arrayaux['LANG'];
18166 					}
18167 				}
18168 			}
18169 			$this->currentLang = $arrayaux['LANG'];
18170 		}
18171 
18172 		// FOR INLINE and BLOCK OR 'BODY'
18173 		if (isset($arrayaux['FONT-FAMILY'])) {
18174 			$v = $arrayaux['FONT-FAMILY'];
18175 			// If it is a font list, get all font types
18176 			$aux_fontlist = explode(",", $v);
18177 			$found = 0;
18178 			foreach ($aux_fontlist as $f) {
18179 				$fonttype = trim($f);
18180 				$fonttype = preg_replace('/["\']*(.*?)["\']*/', '\\1', $fonttype);
18181 				$fonttype = preg_replace('/ /', '', $fonttype);
18182 				$v = strtolower(trim($fonttype));
18183 				if (isset($this->fonttrans[$v]) && $this->fonttrans[$v]) {
18184 					$v = $this->fonttrans[$v];
18185 				}
18186 				if ((!$this->onlyCoreFonts && in_array($v, $this->available_unifonts)) ||
18187 					in_array($v, ['ccourier', 'ctimes', 'chelvetica']) ||
18188 					($this->onlyCoreFonts && in_array($v, ['courier', 'times', 'helvetica', 'arial'])) ||
18189 					in_array($v, ['sjis', 'uhc', 'big5', 'gb'])) {
18190 					$fonttype = $v;
18191 					$found = 1;
18192 					break;
18193 				}
18194 			}
18195 			if (!$found) {
18196 				foreach ($aux_fontlist as $f) {
18197 					$fonttype = trim($f);
18198 					$fonttype = preg_replace('/["\']*(.*?)["\']*/', '\\1', $fonttype);
18199 					$fonttype = preg_replace('/ /', '', $fonttype);
18200 					$v = strtolower(trim($fonttype));
18201 					if (isset($this->fonttrans[$v]) && $this->fonttrans[$v]) {
18202 						$v = $this->fonttrans[$v];
18203 					}
18204 					if (in_array($v, $this->sans_fonts) || in_array($v, $this->serif_fonts) || in_array($v, $this->mono_fonts)) {
18205 						$fonttype = $v;
18206 						break;
18207 					}
18208 				}
18209 			}
18210 
18211 			if ($tag == 'BODY') {
18212 				$this->SetDefaultFont($fonttype);
18213 			}
18214 			$this->SetFont($fonttype, $this->currentfontstyle, 0, false);
18215 		} else {
18216 			$this->SetFont($this->currentfontfamily, $this->currentfontstyle, 0, false);
18217 		}
18218 
18219 		foreach ($arrayaux as $k => $v) {
18220 			if ($type != 'INLINE' && $tag != 'BODY' && $type != 'TABLECELL') {
18221 				switch ($k) {
18222 					// BORDERS
18223 					case 'BORDER-TOP':
18224 						$this->blk[$this->blklvl]['border_top'] = $this->border_details($v);
18225 						if ($this->blk[$this->blklvl]['border_top']['s']) {
18226 							$this->blk[$this->blklvl]['border'] = 1;
18227 						}
18228 						break;
18229 					case 'BORDER-BOTTOM':
18230 						$this->blk[$this->blklvl]['border_bottom'] = $this->border_details($v);
18231 						if ($this->blk[$this->blklvl]['border_bottom']['s']) {
18232 							$this->blk[$this->blklvl]['border'] = 1;
18233 						}
18234 						break;
18235 					case 'BORDER-LEFT':
18236 						$this->blk[$this->blklvl]['border_left'] = $this->border_details($v);
18237 						if ($this->blk[$this->blklvl]['border_left']['s']) {
18238 							$this->blk[$this->blklvl]['border'] = 1;
18239 						}
18240 						break;
18241 					case 'BORDER-RIGHT':
18242 						$this->blk[$this->blklvl]['border_right'] = $this->border_details($v);
18243 						if ($this->blk[$this->blklvl]['border_right']['s']) {
18244 							$this->blk[$this->blklvl]['border'] = 1;
18245 						}
18246 						break;
18247 
18248 					// PADDING
18249 					case 'PADDING-TOP':
18250 						$this->blk[$this->blklvl]['padding_top'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18251 						break;
18252 					case 'PADDING-BOTTOM':
18253 						$this->blk[$this->blklvl]['padding_bottom'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18254 						break;
18255 					case 'PADDING-LEFT':
18256 						if (($tag == 'UL' || $tag == 'OL') && $v == 'auto') {
18257 							$this->blk[$this->blklvl]['padding_left'] = 'auto';
18258 							break;
18259 						}
18260 						$this->blk[$this->blklvl]['padding_left'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18261 						break;
18262 					case 'PADDING-RIGHT':
18263 						if (($tag == 'UL' || $tag == 'OL') && $v == 'auto') {
18264 							$this->blk[$this->blklvl]['padding_right'] = 'auto';
18265 							break;
18266 						}
18267 						$this->blk[$this->blklvl]['padding_right'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18268 						break;
18269 
18270 					// MARGINS
18271 					case 'MARGIN-TOP':
18272 						$tmp = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18273 						if (isset($this->blk[$this->blklvl]['lastbottommargin'])) {
18274 							if ($tmp > $this->blk[$this->blklvl]['lastbottommargin']) {
18275 								$tmp -= $this->blk[$this->blklvl]['lastbottommargin'];
18276 							} else {
18277 								$tmp = 0;
18278 							}
18279 						}
18280 						$this->blk[$this->blklvl]['margin_top'] = $tmp;
18281 						break;
18282 					case 'MARGIN-BOTTOM':
18283 						$this->blk[$this->blklvl]['margin_bottom'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18284 						break;
18285 					case 'MARGIN-LEFT':
18286 						$this->blk[$this->blklvl]['margin_left'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18287 						break;
18288 					case 'MARGIN-RIGHT':
18289 						$this->blk[$this->blklvl]['margin_right'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18290 						break;
18291 
18292 					/* -- BORDER-RADIUS -- */
18293 					case 'BORDER-TOP-LEFT-RADIUS-H':
18294 						$this->blk[$this->blklvl]['border_radius_TL_H'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18295 						break;
18296 					case 'BORDER-TOP-LEFT-RADIUS-V':
18297 						$this->blk[$this->blklvl]['border_radius_TL_V'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18298 						break;
18299 					case 'BORDER-TOP-RIGHT-RADIUS-H':
18300 						$this->blk[$this->blklvl]['border_radius_TR_H'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18301 						break;
18302 					case 'BORDER-TOP-RIGHT-RADIUS-V':
18303 						$this->blk[$this->blklvl]['border_radius_TR_V'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18304 						break;
18305 					case 'BORDER-BOTTOM-LEFT-RADIUS-H':
18306 						$this->blk[$this->blklvl]['border_radius_BL_H'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18307 						break;
18308 					case 'BORDER-BOTTOM-LEFT-RADIUS-V':
18309 						$this->blk[$this->blklvl]['border_radius_BL_V'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18310 						break;
18311 					case 'BORDER-BOTTOM-RIGHT-RADIUS-H':
18312 						$this->blk[$this->blklvl]['border_radius_BR_H'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18313 						break;
18314 					case 'BORDER-BOTTOM-RIGHT-RADIUS-V':
18315 						$this->blk[$this->blklvl]['border_radius_BR_V'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18316 						break;
18317 					/* -- END BORDER-RADIUS -- */
18318 
18319 					case 'BOX-SHADOW':
18320 						$bs = $this->cssManager->setCSSboxshadow($v);
18321 						if ($bs) {
18322 							$this->blk[$this->blklvl]['box_shadow'] = $bs;
18323 						}
18324 						break;
18325 
18326 					case 'BACKGROUND-CLIP':
18327 						if (strtoupper($v) == 'PADDING-BOX') {
18328 							$this->blk[$this->blklvl]['background_clip'] = 'padding-box';
18329 						} elseif (strtoupper($v) == 'CONTENT-BOX') {
18330 							$this->blk[$this->blklvl]['background_clip'] = 'content-box';
18331 						}
18332 						break;
18333 
18334 					case 'PAGE-BREAK-AFTER':
18335 						if (strtoupper($v) == 'AVOID') {
18336 							$this->blk[$this->blklvl]['page_break_after_avoid'] = true;
18337 						} elseif (strtoupper($v) == 'ALWAYS' || strtoupper($v) == 'LEFT' || strtoupper($v) == 'RIGHT') {
18338 							$this->blk[$this->blklvl]['page_break_after'] = strtoupper($v);
18339 						}
18340 						break;
18341 
18342 					// mPDF 6 pagebreaktype
18343 					case 'BOX-DECORATION-BREAK':
18344 						if (strtoupper($v) == 'CLONE') {
18345 							$this->blk[$this->blklvl]['box_decoration_break'] = 'clone';
18346 						} elseif (strtoupper($v) == 'SLICE') {
18347 							$this->blk[$this->blklvl]['box_decoration_break'] = 'slice';
18348 						}
18349 						break;
18350 
18351 					case 'WIDTH':
18352 						if (strtoupper($v) != 'AUTO') {
18353 							$this->blk[$this->blklvl]['css_set_width'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18354 						}
18355 						break;
18356 
18357 					// mPDF 6  Lists
18358 					// LISTS
18359 					case 'LIST-STYLE-TYPE':
18360 						$this->blk[$this->blklvl]['list_style_type'] = strtolower($v);
18361 						break;
18362 					case 'LIST-STYLE-IMAGE':
18363 						$this->blk[$this->blklvl]['list_style_image'] = strtolower($v);
18364 						break;
18365 					case 'LIST-STYLE-POSITION':
18366 						$this->blk[$this->blklvl]['list_style_position'] = strtolower($v);
18367 						break;
18368 				}//end of switch($k)
18369 			}
18370 
18371 
18372 			if ($type != 'INLINE' && $type != 'TABLECELL') { // All block-level, including BODY tag
18373 				switch ($k) {
18374 					case 'TEXT-INDENT':
18375 						// Computed value - to inherit
18376 						$this->blk[$this->blklvl]['text_indent'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false) . 'mm';
18377 						break;
18378 
18379 					case 'MARGIN-COLLAPSE': // Custom tag to collapse margins at top and bottom of page
18380 						if (strtoupper($v) == 'COLLAPSE') {
18381 							$this->blk[$this->blklvl]['margin_collapse'] = true;
18382 						}
18383 						break;
18384 
18385 					case 'LINE-HEIGHT':
18386 						$this->blk[$this->blklvl]['line_height'] = $this->fixLineheight($v);
18387 						if (!$this->blk[$this->blklvl]['line_height']) {
18388 							$this->blk[$this->blklvl]['line_height'] = 'N';
18389 						} // mPDF 6
18390 						break;
18391 
18392 					// mPDF 6
18393 					case 'LINE-STACKING-STRATEGY':
18394 						$this->blk[$this->blklvl]['line_stacking_strategy'] = strtolower($v);
18395 						break;
18396 
18397 					case 'LINE-STACKING-SHIFT':
18398 						$this->blk[$this->blklvl]['line_stacking_shift'] = strtolower($v);
18399 						break;
18400 
18401 					case 'TEXT-ALIGN': // left right center justify
18402 						switch (strtoupper($v)) {
18403 							case 'LEFT':
18404 								$this->blk[$this->blklvl]['align'] = "L";
18405 								break;
18406 							case 'CENTER':
18407 								$this->blk[$this->blklvl]['align'] = "C";
18408 								break;
18409 							case 'RIGHT':
18410 								$this->blk[$this->blklvl]['align'] = "R";
18411 								break;
18412 							case 'JUSTIFY':
18413 								$this->blk[$this->blklvl]['align'] = "J";
18414 								break;
18415 						}
18416 						break;
18417 
18418 					/* -- BACKGROUNDS -- */
18419 					case 'BACKGROUND-GRADIENT':
18420 						if ($type == 'BLOCK') {
18421 							$this->blk[$this->blklvl]['gradient'] = $v;
18422 						}
18423 						break;
18424 					/* -- END BACKGROUNDS -- */
18425 
18426 					case 'DIRECTION':
18427 						if ($v) {
18428 							$this->blk[$this->blklvl]['direction'] = strtolower($v);
18429 						}
18430 						break;
18431 				}
18432 			}
18433 
18434 			// FOR INLINE ONLY
18435 			if ($type == 'INLINE') {
18436 				switch ($k) {
18437 					case 'DISPLAY':
18438 						if (strtoupper($v) == 'NONE') {
18439 							$this->inlineDisplayOff = true;
18440 						}
18441 						break;
18442 					case 'DIRECTION':
18443 						break;
18444 				}
18445 			}
18446 			// FOR INLINE ONLY
18447 			if ($type == 'INLINE') {
18448 				switch ($k) {
18449 					// BORDERS
18450 					case 'BORDER-TOP':
18451 						$this->spanborddet['T'] = $this->border_details($v);
18452 						$this->spanborder = true;
18453 						$spanbordset = true;
18454 						break;
18455 					case 'BORDER-BOTTOM':
18456 						$this->spanborddet['B'] = $this->border_details($v);
18457 						$this->spanborder = true;
18458 						$spanbordset = true;
18459 						break;
18460 					case 'BORDER-LEFT':
18461 						$this->spanborddet['L'] = $this->border_details($v);
18462 						$this->spanborder = true;
18463 						$spanbordset = true;
18464 						break;
18465 					case 'BORDER-RIGHT':
18466 						$this->spanborddet['R'] = $this->border_details($v);
18467 						$this->spanborder = true;
18468 						$spanbordset = true;
18469 						break;
18470 					case 'VISIBILITY': // block is set in OpenTag
18471 						$v = strtolower($v);
18472 						if ($v == 'visible' || $v == 'hidden' || $v == 'printonly' || $v == 'screenonly') {
18473 							$this->textparam['visibility'] = $v;
18474 						}
18475 						break;
18476 				}//end of switch($k)
18477 			}
18478 
18479 			if ($type != 'TABLECELL') {
18480 				// FOR INLINE and BLOCK
18481 				switch ($k) {
18482 					case 'TEXT-ALIGN': // left right center justify
18483 						if (strtoupper($v) == 'NOJUSTIFY' && $this->blk[$this->blklvl]['align'] == "J") {
18484 							$this->blk[$this->blklvl]['align'] = "";
18485 						}
18486 						break;
18487 					// bgcolor only - to stay consistent with original html2fpdf
18488 					case 'BACKGROUND':
18489 					case 'BACKGROUND-COLOR':
18490 						$cor = $this->colorConverter->convert($v, $this->PDFAXwarnings);
18491 						if ($cor) {
18492 							if ($tag == 'BODY') {
18493 								$this->bodyBackgroundColor = $cor;
18494 							} elseif ($type == 'INLINE') {
18495 								$this->spanbgcolorarray = $cor;
18496 								$this->spanbgcolor = true;
18497 								$spanbgset = true;
18498 							} else {
18499 								$this->blk[$this->blklvl]['bgcolorarray'] = $cor;
18500 								$this->blk[$this->blklvl]['bgcolor'] = true;
18501 							}
18502 						} elseif ($type != 'INLINE') {
18503 							if ($this->ColActive) {
18504 								$this->blk[$this->blklvl]['bgcolorarray'] = $this->blk[$prevlevel]['bgcolorarray'];
18505 								$this->blk[$this->blklvl]['bgcolor'] = $this->blk[$prevlevel]['bgcolor'];
18506 							}
18507 						}
18508 						break;
18509 
18510 					case 'VERTICAL-ALIGN': // super and sub only dealt with here e.g. <SUB> and <SUP>
18511 						switch (strtoupper($v)) {
18512 							case 'SUPER':
18513 								$this->textvar = ($this->textvar | TextVars::FA_SUPERSCRIPT); // mPDF 5.7.1
18514 								$this->textvar = ($this->textvar & ~TextVars::FA_SUBSCRIPT);
18515 								// mPDF 5.7.3  inline text-decoration parameters
18516 								if (isset($this->textparam['text-baseline'])) {
18517 									$this->textparam['text-baseline'] += ($this->baselineSup) * $preceeding_fontsize;
18518 								} else {
18519 									$this->textparam['text-baseline'] = ($this->baselineSup) * $preceeding_fontsize;
18520 								}
18521 								break;
18522 							case 'SUB':
18523 								$this->textvar = ($this->textvar | TextVars::FA_SUBSCRIPT);
18524 								$this->textvar = ($this->textvar & ~TextVars::FA_SUPERSCRIPT);
18525 								// mPDF 5.7.3  inline text-decoration parameters
18526 								if (isset($this->textparam['text-baseline'])) {
18527 									$this->textparam['text-baseline'] += ($this->baselineSub) * $preceeding_fontsize;
18528 								} else {
18529 									$this->textparam['text-baseline'] = ($this->baselineSub) * $preceeding_fontsize;
18530 								}
18531 								break;
18532 							case 'BASELINE':
18533 								$this->textvar = ($this->textvar & ~TextVars::FA_SUBSCRIPT);
18534 								$this->textvar = ($this->textvar & ~TextVars::FA_SUPERSCRIPT);
18535 								// mPDF 5.7.3  inline text-decoration parameters
18536 								if (isset($this->textparam['text-baseline'])) {
18537 									unset($this->textparam['text-baseline']);
18538 								}
18539 								break;
18540 							// mPDF 5.7.3  inline text-decoration parameters
18541 							default:
18542 								$lh = $this->_computeLineheight($this->blk[$this->blklvl]['line_height']);
18543 								$sz = $this->sizeConverter->convert($v, $lh, $this->FontSize, false);
18544 								$this->textvar = ($this->textvar & ~TextVars::FA_SUBSCRIPT);
18545 								$this->textvar = ($this->textvar & ~TextVars::FA_SUPERSCRIPT);
18546 								if ($sz) {
18547 									if ($sz > 0) {
18548 										$this->textvar = ($this->textvar | TextVars::FA_SUPERSCRIPT);
18549 									} else {
18550 										$this->textvar = ($this->textvar | TextVars::FA_SUBSCRIPT);
18551 									}
18552 									if (isset($this->textparam['text-baseline'])) {
18553 										$this->textparam['text-baseline'] += $sz;
18554 									} else {
18555 										$this->textparam['text-baseline'] = $sz;
18556 									}
18557 								}
18558 						}
18559 						break;
18560 				}//end of switch($k)
18561 			}
18562 
18563 
18564 			// FOR ALL
18565 			switch ($k) {
18566 				case 'LETTER-SPACING':
18567 					$this->lSpacingCSS = $v;
18568 					if (($this->lSpacingCSS || $this->lSpacingCSS === '0') && strtoupper($this->lSpacingCSS) != 'NORMAL') {
18569 						$this->fixedlSpacing = $this->sizeConverter->convert($this->lSpacingCSS, $this->FontSize);
18570 					}
18571 					break;
18572 
18573 				case 'WORD-SPACING':
18574 					$this->wSpacingCSS = $v;
18575 					if ($this->wSpacingCSS && strtoupper($this->wSpacingCSS) != 'NORMAL') {
18576 						$this->minwSpacing = $this->sizeConverter->convert($this->wSpacingCSS, $this->FontSize);
18577 					}
18578 					break;
18579 
18580 				case 'FONT-STYLE': // italic normal oblique
18581 					switch (strtoupper($v)) {
18582 						case 'ITALIC':
18583 						case 'OBLIQUE':
18584 							$this->SetStyle('I', true);
18585 							break;
18586 						case 'NORMAL':
18587 							$this->SetStyle('I', false);
18588 							break;
18589 					}
18590 					break;
18591 
18592 				case 'FONT-WEIGHT': // normal bold // Does not support: bolder, lighter, 100..900(step value=100)
18593 					switch (strtoupper($v)) {
18594 						case 'BOLD':
18595 							$this->SetStyle('B', true);
18596 							break;
18597 						case 'NORMAL':
18598 							$this->SetStyle('B', false);
18599 							break;
18600 					}
18601 					break;
18602 
18603 				case 'FONT-KERNING':
18604 					if (strtoupper($v) == 'NORMAL' || (strtoupper($v) == 'AUTO' && $this->useKerning)) {
18605 						/* -- OTL -- */
18606 						if ($this->CurrentFont['haskernGPOS']) {
18607 							if (isset($this->OTLtags['Plus'])) {
18608 								$this->OTLtags['Plus'] .= ' kern';
18609 							} else {
18610 								$this->OTLtags['Plus'] = ' kern';
18611 							}
18612 						} /* -- END OTL -- */ else {  // *OTL*
18613 							$this->textvar = ($this->textvar | TextVars::FC_KERNING);
18614 						} // *OTL*
18615 					} elseif (strtoupper($v) == 'NONE' || (strtoupper($v) == 'AUTO' && !$this->useKerning)) {
18616 						if (isset($this->OTLtags['Plus'])) {
18617 							$this->OTLtags['Plus'] = str_replace('kern', '', $this->OTLtags['Plus']); // *OTL*
18618 						}
18619 						if (isset($this->OTLtags['FFPlus'])) {
18620 							$this->OTLtags['FFPlus'] = preg_replace('/kern[\d]*/', '', $this->OTLtags['FFPlus']);
18621 						}
18622 						$this->textvar = ($this->textvar & ~TextVars::FC_KERNING);
18623 					}
18624 					break;
18625 
18626 				/* -- OTL -- */
18627 				case 'FONT-LANGUAGE-OVERRIDE':
18628 					$v = strtoupper($v);
18629 					if (strpos($v, 'NORMAL') !== false) {
18630 						$this->fontLanguageOverride = '';
18631 					} else {
18632 						$this->fontLanguageOverride = trim($v);
18633 					}
18634 					break;
18635 
18636 
18637 				case 'FONT-VARIANT-POSITION':
18638 					if (isset($this->OTLtags['Plus'])) {
18639 						$this->OTLtags['Plus'] = str_replace(['sups', 'subs'], '', $this->OTLtags['Plus']);
18640 					}
18641 					switch (strtoupper($v)) {
18642 						case 'SUPER':
18643 							$this->OTLtags['Plus'] .= ' sups';
18644 							break;
18645 						case 'SUB':
18646 							$this->OTLtags['Plus'] .= ' subs';
18647 							break;
18648 						case 'NORMAL':
18649 							break;
18650 					}
18651 					break;
18652 
18653 				case 'FONT-VARIANT-CAPS':
18654 					$v = strtoupper($v);
18655 					if (!isset($this->OTLtags['Plus'])) {
18656 						$this->OTLtags['Plus'] = '';
18657 					}
18658 					$this->OTLtags['Plus'] = str_replace(['c2sc', 'smcp', 'c2pc', 'pcap', 'unic', 'titl'], '', $this->OTLtags['Plus']);
18659 					$this->textvar = ($this->textvar & ~TextVars::FC_SMALLCAPS);   // ?????????????? <small-caps>
18660 					if (strpos($v, 'ALL-SMALL-CAPS') !== false) {
18661 						$this->OTLtags['Plus'] .= ' c2sc smcp';
18662 					} elseif (strpos($v, 'SMALL-CAPS') !== false) {
18663 						if (isset($this->CurrentFont['hassmallcapsGSUB']) && $this->CurrentFont['hassmallcapsGSUB']) {
18664 							$this->OTLtags['Plus'] .= ' smcp';
18665 						} else {
18666 							$this->textvar = ($this->textvar | TextVars::FC_SMALLCAPS);
18667 						}
18668 					} elseif (strpos($v, 'ALL-PETITE-CAPS') !== false) {
18669 						$this->OTLtags['Plus'] .= ' c2pc pcap';
18670 					} elseif (strpos($v, 'PETITE-CAPS') !== false) {
18671 						$this->OTLtags['Plus'] .= ' pcap';
18672 					} elseif (strpos($v, 'UNICASE') !== false) {
18673 						$this->OTLtags['Plus'] .= ' unic';
18674 					} elseif (strpos($v, 'TITLING-CAPS') !== false) {
18675 						$this->OTLtags['Plus'] .= ' titl';
18676 					}
18677 					break;
18678 
18679 				case 'FONT-VARIANT-LIGATURES':
18680 					$v = strtoupper($v);
18681 					if (!isset($this->OTLtags['Plus'])) {
18682 						$this->OTLtags['Plus'] = '';
18683 					}
18684 					if (!isset($this->OTLtags['Minus'])) {
18685 						$this->OTLtags['Minus'] = '';
18686 					}
18687 					if (strpos($v, 'NORMAL') !== false) {
18688 						$this->OTLtags['Minus'] = str_replace(['liga', 'clig', 'calt'], '', $this->OTLtags['Minus']);
18689 						$this->OTLtags['Plus'] = str_replace(['dlig', 'hlig'], '', $this->OTLtags['Plus']);
18690 					} elseif (strpos($v, 'NONE') !== false) {
18691 						$this->OTLtags['Minus'] .= ' liga clig calt';
18692 						$this->OTLtags['Plus'] = str_replace(['dlig', 'hlig'], '', $this->OTLtags['Plus']);
18693 					}
18694 					if (strpos($v, 'NO-COMMON-LIGATURES') !== false) {
18695 						$this->OTLtags['Minus'] .= ' liga clig';
18696 					} elseif (strpos($v, 'COMMON-LIGATURES') !== false) {
18697 						$this->OTLtags['Minus'] = str_replace(['liga', 'clig'], '', $this->OTLtags['Minus']);
18698 					}
18699 					if (strpos($v, 'NO-CONTEXTUAL') !== false) {
18700 						$this->OTLtags['Minus'] .= ' calt';
18701 					} elseif (strpos($v, 'CONTEXTUAL') !== false) {
18702 						$this->OTLtags['Minus'] = str_replace('calt', '', $this->OTLtags['Minus']);
18703 					}
18704 					if (strpos($v, 'NO-DISCRETIONARY-LIGATURES') !== false) {
18705 						$this->OTLtags['Plus'] = str_replace('dlig', '', $this->OTLtags['Plus']);
18706 					} elseif (strpos($v, 'DISCRETIONARY-LIGATURES') !== false) {
18707 						$this->OTLtags['Plus'] .= ' dlig';
18708 					}
18709 					if (strpos($v, 'NO-HISTORICAL-LIGATURES') !== false) {
18710 						$this->OTLtags['Plus'] = str_replace('hlig', '', $this->OTLtags['Plus']);
18711 					} elseif (strpos($v, 'HISTORICAL-LIGATURES') !== false) {
18712 						$this->OTLtags['Plus'] .= ' hlig';
18713 					}
18714 
18715 					break;
18716 
18717 				case 'FONT-VARIANT-NUMERIC':
18718 					$v = strtoupper($v);
18719 					if (!isset($this->OTLtags['Plus'])) {
18720 						$this->OTLtags['Plus'] = '';
18721 					}
18722 					if (strpos($v, 'NORMAL') !== false) {
18723 						$this->OTLtags['Plus'] = str_replace(['ordn', 'zero', 'lnum', 'onum', 'pnum', 'tnum', 'frac', 'afrc'], '', $this->OTLtags['Plus']);
18724 					}
18725 					if (strpos($v, 'ORDINAL') !== false) {
18726 						$this->OTLtags['Plus'] .= ' ordn';
18727 					}
18728 					if (strpos($v, 'SLASHED-ZERO') !== false) {
18729 						$this->OTLtags['Plus'] .= ' zero';
18730 					}
18731 					if (strpos($v, 'LINING-NUMS') !== false) {
18732 						$this->OTLtags['Plus'] .= ' lnum';
18733 						$this->OTLtags['Plus'] = str_replace('onum', '', $this->OTLtags['Plus']);
18734 					} elseif (strpos($v, 'OLDSTYLE-NUMS') !== false) {
18735 						$this->OTLtags['Plus'] .= ' onum';
18736 						$this->OTLtags['Plus'] = str_replace('lnum', '', $this->OTLtags['Plus']);
18737 					}
18738 					if (strpos($v, 'PROPORTIONAL-NUMS') !== false) {
18739 						$this->OTLtags['Plus'] .= ' pnum';
18740 						$this->OTLtags['Plus'] = str_replace('tnum', '', $this->OTLtags['Plus']);
18741 					} elseif (strpos($v, 'TABULAR-NUMS') !== false) {
18742 						$this->OTLtags['Plus'] .= ' tnum';
18743 						$this->OTLtags['Plus'] = str_replace('pnum', '', $this->OTLtags['Plus']);
18744 					}
18745 					if (strpos($v, 'DIAGONAL-FRACTIONS') !== false) {
18746 						$this->OTLtags['Plus'] .= ' frac';
18747 						$this->OTLtags['Plus'] = str_replace('afrc', '', $this->OTLtags['Plus']);
18748 					} elseif (strpos($v, 'STACKED-FRACTIONS') !== false) {
18749 						$this->OTLtags['Plus'] .= ' afrc';
18750 						$this->OTLtags['Plus'] = str_replace('frac', '', $this->OTLtags['Plus']);
18751 					}
18752 					break;
18753 
18754 				case 'FONT-VARIANT-ALTERNATES':  // Only supports historical-forms
18755 					$v = strtoupper($v);
18756 					if (!isset($this->OTLtags['Plus'])) {
18757 						$this->OTLtags['Plus'] = '';
18758 					}
18759 					if (strpos($v, 'NORMAL') !== false) {
18760 						$this->OTLtags['Plus'] = str_replace('hist', '', $this->OTLtags['Plus']);
18761 					}
18762 					if (strpos($v, 'HISTORICAL-FORMS') !== false) {
18763 						$this->OTLtags['Plus'] .= ' hist';
18764 					}
18765 					break;
18766 
18767 
18768 				case 'FONT-FEATURE-SETTINGS':
18769 					$v = strtolower($v);
18770 					if (strpos($v, 'normal') !== false) {
18771 						$this->OTLtags['FFMinus'] = '';
18772 						$this->OTLtags['FFPlus'] = '';
18773 					} else {
18774 						if (!isset($this->OTLtags['FFPlus'])) {
18775 							$this->OTLtags['FFPlus'] = '';
18776 						}
18777 						if (!isset($this->OTLtags['FFMinus'])) {
18778 							$this->OTLtags['FFMinus'] = '';
18779 						}
18780 						$tags = preg_split('/[,]/', $v);
18781 						foreach ($tags as $t) {
18782 							if (preg_match('/[\"\']([a-zA-Z0-9]{4})[\"\']\s*(on|off|\d*){0,1}/', $t, $m)) {
18783 								if ($m[2] == 'off' || $m[2] === '0') {
18784 									if (strpos($this->OTLtags['FFMinus'], $m[1]) === false) {
18785 										$this->OTLtags['FFMinus'] .= ' ' . $m[1];
18786 									}
18787 									$this->OTLtags['FFPlus'] = preg_replace('/' . $m[1] . '[\d]*/', '', $this->OTLtags['FFPlus']);
18788 								} else {
18789 									if ($m[2] == 'on') {
18790 										$m[2] = '1';
18791 									}
18792 									if (strpos($this->OTLtags['FFPlus'], $m[1]) === false) {
18793 										$this->OTLtags['FFPlus'] .= ' ' . $m[1] . $m[2];
18794 									}
18795 									$this->OTLtags['FFMinus'] = str_replace($m[1], '', $this->OTLtags['FFMinus']);
18796 								}
18797 							}
18798 						}
18799 					}
18800 					break;
18801 				/* -- END OTL -- */
18802 
18803 
18804 				case 'TEXT-TRANSFORM': // none uppercase lowercase // Does support: capitalize
18805 					switch (strtoupper($v)) { // Not working 100%
18806 						case 'CAPITALIZE':
18807 							$this->textvar = ($this->textvar | TextVars::FT_CAPITALIZE); // mPDF 5.7.1
18808 							$this->textvar = ($this->textvar & ~TextVars::FT_UPPERCASE); // mPDF 5.7.1
18809 							$this->textvar = ($this->textvar & ~TextVars::FT_LOWERCASE); // mPDF 5.7.1
18810 							break;
18811 						case 'UPPERCASE':
18812 							$this->textvar = ($this->textvar | TextVars::FT_UPPERCASE); // mPDF 5.7.1
18813 							$this->textvar = ($this->textvar & ~TextVars::FT_LOWERCASE); // mPDF 5.7.1
18814 							$this->textvar = ($this->textvar & ~TextVars::FT_CAPITALIZE); // mPDF 5.7.1
18815 							break;
18816 						case 'LOWERCASE':
18817 							$this->textvar = ($this->textvar | TextVars::FT_LOWERCASE); // mPDF 5.7.1
18818 							$this->textvar = ($this->textvar & ~TextVars::FT_UPPERCASE); // mPDF 5.7.1
18819 							$this->textvar = ($this->textvar & ~TextVars::FT_CAPITALIZE); // mPDF 5.7.1
18820 							break;
18821 						case 'NONE':
18822 							break;
18823 							$this->textvar = ($this->textvar & ~TextVars::FT_UPPERCASE); // mPDF 5.7.1
18824 							$this->textvar = ($this->textvar & ~TextVars::FT_LOWERCASE); // mPDF 5.7.1
18825 							$this->textvar = ($this->textvar & ~TextVars::FT_CAPITALIZE); // mPDF 5.7.1
18826 					}
18827 					break;
18828 
18829 				case 'TEXT-SHADOW':
18830 					$ts = $this->cssManager->setCSStextshadow($v);
18831 					if ($ts) {
18832 						$this->textshadow = $ts;
18833 					}
18834 					break;
18835 
18836 				case 'HYPHENS':
18837 					if (strtoupper($v) == 'NONE') {
18838 						$this->textparam['hyphens'] = 2;
18839 					} elseif (strtoupper($v) == 'AUTO') {
18840 						$this->textparam['hyphens'] = 1;
18841 					} elseif (strtoupper($v) == 'MANUAL') {
18842 						$this->textparam['hyphens'] = 0;
18843 					}
18844 					break;
18845 
18846 				case 'TEXT-OUTLINE':
18847 					if (strtoupper($v) == 'NONE') {
18848 						$this->textparam['outline-s'] = false;
18849 					}
18850 					break;
18851 
18852 				case 'TEXT-OUTLINE-WIDTH':
18853 				case 'OUTLINE-WIDTH':
18854 					switch (strtoupper($v)) {
18855 						case 'THIN':
18856 							$v = '0.03em';
18857 							break;
18858 						case 'MEDIUM':
18859 							$v = '0.05em';
18860 							break;
18861 						case 'THICK':
18862 							$v = '0.07em';
18863 							break;
18864 					}
18865 					$w = $this->sizeConverter->convert($v, $this->FontSize, $this->FontSize);
18866 					if ($w) {
18867 						$this->textparam['outline-WIDTH'] = $w;
18868 						$this->textparam['outline-s'] = true;
18869 					} else {
18870 						$this->textparam['outline-s'] = false;
18871 					}
18872 					break;
18873 
18874 				case 'TEXT-OUTLINE-COLOR':
18875 				case 'OUTLINE-COLOR':
18876 					if (strtoupper($v) == 'INVERT') {
18877 						if ($this->colorarray) {
18878 							$cor = $this->colorarray;
18879 							$this->textparam['outline-COLOR'] = $this->colorConverter->invert($cor);
18880 						} else {
18881 							$this->textparam['outline-COLOR'] = $this->colorConverter->convert(255, $this->PDFAXwarnings);
18882 						}
18883 					} else {
18884 						$cor = $this->colorConverter->convert($v, $this->PDFAXwarnings);
18885 						if ($cor) {
18886 							$this->textparam['outline-COLOR'] = $cor;
18887 						}
18888 					}
18889 					break;
18890 
18891 				case 'COLOR': // font color
18892 					$cor = $this->colorConverter->convert($v, $this->PDFAXwarnings);
18893 					if ($cor) {
18894 						$this->colorarray = $cor;
18895 						$this->SetTColor($cor);
18896 					}
18897 					break;
18898 			}//end of switch($k)
18899 		}//end of foreach
18900 		// mPDF 5.7.3  inline text-decoration parameters
18901 		// Needs to be set at the end - after vertical-align = super/sub, so that textparam['text-baseline'] is set
18902 		if (isset($arrayaux['TEXT-DECORATION'])) {
18903 			$v = $arrayaux['TEXT-DECORATION']; // none underline line-through (strikeout) // Does not support: blink
18904 			if (stristr($v, 'LINE-THROUGH')) {
18905 				$this->textvar = ($this->textvar | TextVars::FD_LINETHROUGH);
18906 				// mPDF 5.7.3  inline text-decoration parameters
18907 				if (isset($this->textparam['text-baseline'])) {
18908 					$this->textparam['s-decoration']['baseline'] = $this->textparam['text-baseline'];
18909 				} else {
18910 					$this->textparam['s-decoration']['baseline'] = 0;
18911 				}
18912 				$this->textparam['s-decoration']['fontkey'] = $this->FontFamily . $this->FontStyle;
18913 				$this->textparam['s-decoration']['fontsize'] = $this->FontSize;
18914 				$this->textparam['s-decoration']['color'] = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
18915 			}
18916 			if (stristr($v, 'UNDERLINE')) {
18917 				$this->textvar = ($this->textvar | TextVars::FD_UNDERLINE);
18918 				// mPDF 5.7.3  inline text-decoration parameters
18919 				if (isset($this->textparam['text-baseline'])) {
18920 					$this->textparam['u-decoration']['baseline'] = $this->textparam['text-baseline'];
18921 				} else {
18922 					$this->textparam['u-decoration']['baseline'] = 0;
18923 				}
18924 				$this->textparam['u-decoration']['fontkey'] = $this->FontFamily . $this->FontStyle;
18925 				$this->textparam['u-decoration']['fontsize'] = $this->FontSize;
18926 				$this->textparam['u-decoration']['color'] = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
18927 			}
18928 			if (stristr($v, 'OVERLINE')) {
18929 				$this->textvar = ($this->textvar | TextVars::FD_OVERLINE);
18930 				// mPDF 5.7.3  inline text-decoration parameters
18931 				if (isset($this->textparam['text-baseline'])) {
18932 					$this->textparam['o-decoration']['baseline'] = $this->textparam['text-baseline'];
18933 				} else {
18934 					$this->textparam['o-decoration']['baseline'] = 0;
18935 				}
18936 				$this->textparam['o-decoration']['fontkey'] = $this->FontFamily . $this->FontStyle;
18937 				$this->textparam['o-decoration']['fontsize'] = $this->FontSize;
18938 				$this->textparam['o-decoration']['color'] = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
18939 			}
18940 			if (stristr($v, 'NONE')) {
18941 				$this->textvar = ($this->textvar & ~TextVars::FD_UNDERLINE);
18942 				$this->textvar = ($this->textvar & ~TextVars::FD_LINETHROUGH);
18943 				$this->textvar = ($this->textvar & ~TextVars::FD_OVERLINE);
18944 				// mPDF 5.7.3  inline text-decoration parameters
18945 				if (isset($this->textparam['u-decoration'])) {
18946 					unset($this->textparam['u-decoration']);
18947 				}
18948 				if (isset($this->textparam['s-decoration'])) {
18949 					unset($this->textparam['s-decoration']);
18950 				}
18951 				if (isset($this->textparam['o-decoration'])) {
18952 					unset($this->textparam['o-decoration']);
18953 				}
18954 			}
18955 		}
18956 		// mPDF 6
18957 		if ($spanbordset) { // BORDER has been set on this INLINE element
18958 			if (isset($this->textparam['text-baseline'])) {
18959 				$this->textparam['bord-decoration']['baseline'] = $this->textparam['text-baseline'];
18960 			} else {
18961 				$this->textparam['bord-decoration']['baseline'] = 0;
18962 			}
18963 			$this->textparam['bord-decoration']['fontkey'] = $this->FontFamily . $this->FontStyle;
18964 			$this->textparam['bord-decoration']['fontsize'] = $this->FontSize;
18965 		}
18966 		if ($spanbgset) { // BACKGROUND[-COLOR] has been set on this INLINE element
18967 			if (isset($this->textparam['text-baseline'])) {
18968 				$this->textparam['bg-decoration']['baseline'] = $this->textparam['text-baseline'];
18969 			} else {
18970 				$this->textparam['bg-decoration']['baseline'] = 0;
18971 			}
18972 			$this->textparam['bg-decoration']['fontkey'] = $this->FontFamily . $this->FontStyle;
18973 			$this->textparam['bg-decoration']['fontsize'] = $this->FontSize;
18974 		}
18975 	}
18976 
18977 	/* -- END HTML-CSS -- */
18978 
18979 	function SetStyle($tag, $enable)
18980 	{
18981 		$this->$tag = $enable;
18982 		$style = '';
18983 		foreach (['B', 'I'] as $s) {
18984 			if ($this->$s) {
18985 				$style .= $s;
18986 			}
18987 		}
18988 		$this->currentfontstyle = $style;
18989 		$this->SetFont('', $style, 0, false);
18990 	}
18991 
18992 	// Set multiple styles at one time
18993 	function SetStylesArray($arr)
18994 	{
18995 		$style = '';
18996 		foreach (['B', 'I'] as $s) {
18997 			if (isset($arr[$s])) {
18998 				if ($arr[$s]) {
18999 					$this->$s = true;
19000 					$style .= $s;
19001 				} else {
19002 					$this->$s = false;
19003 				}
19004 			} elseif ($this->$s) {
19005 				$style .= $s;
19006 			}
19007 		}
19008 		$this->currentfontstyle = $style;
19009 		$this->SetFont('', $style, 0, false);
19010 	}
19011 
19012 	// Set multiple styles at one $str e.g. "BI"
19013 	function SetStyles($str)
19014 	{
19015 		$style = '';
19016 		foreach (['B', 'I'] as $s) {
19017 			if (strpos($str, $s) !== false) {
19018 				$this->$s = true;
19019 				$style .= $s;
19020 			} else {
19021 				$this->$s = false;
19022 			}
19023 		}
19024 		$this->currentfontstyle = $style;
19025 		$this->SetFont('', $style, 0, false);
19026 	}
19027 
19028 	function ResetStyles()
19029 	{
19030 		foreach (['B', 'I'] as $s) {
19031 			$this->$s = false;
19032 		}
19033 		$this->currentfontstyle = '';
19034 		$this->SetFont('', '', 0, false);
19035 	}
19036 
19037 	function DisableTags($str = '')
19038 	{
19039 		if ($str == '') { // enable all tags
19040 			// Insert new supported tags in the long string below.
19041 			$this->enabledtags = "<a><acronym><address><article><aside><b><bdi><bdo><big><blockquote><br><caption><center><cite><code><del><details><dd><div><dl><dt><em><fieldset><figcaption><figure><font><form><h1><h2><h3><h4><h5><h6><hgroup><hr><i><img><input><ins><kbd><legend><li><main><mark><meter><nav><ol><option><p><pre><progress><q><s><samp><section><select><small><span><strike><strong><sub><summary><sup><table><tbody><td><template><textarea><tfoot><th><thead><time><tr><tt><u><ul><var><footer><header><annotation><bookmark><textcircle><barcode><dottab><indexentry><indexinsert><watermarktext><watermarkimage><tts><ttz><tta><column_break><columnbreak><newcolumn><newpage><page_break><pagebreak><formfeed><columns><toc><tocentry><tocpagebreak><pageheader><pagefooter><setpageheader><setpagefooter><sethtmlpageheader><sethtmlpagefooter>";
19042 		} else {
19043 			$str = explode(",", $str);
19044 			foreach ($str as $v) {
19045 				$this->enabledtags = str_replace(trim($v), '', $this->enabledtags);
19046 			}
19047 		}
19048 	}
19049 
19050 	/* -- TABLES -- */
19051 
19052 	function TableCheckMinWidth($maxwidth, $forcewrap = 0, $textbuffer = [], $checkletter = false)
19053 	{
19054 	// mPDF 6
19055 		$acclength = 0; // mPDF 6 (accumulated length across > 1 chunk)
19056 		$acclongest = 0; // mPDF 6 (accumulated length max across > 1 chunk)
19057 		$biggestword = 0;
19058 		$toonarrow = false;
19059 		if ((count($textbuffer) == 0) or ( (count($textbuffer) == 1) && ($textbuffer[0][0] == ''))) {
19060 			return 0;
19061 		}
19062 
19063 		foreach ($textbuffer as $chunk) {
19064 			$line = $chunk[0];
19065 			$OTLdata = (isset($chunk[18]) ? $chunk[18] : null);
19066 
19067 			// mPDF ITERATION
19068 			if ($this->iterationCounter) {
19069 				$line = preg_replace('/{iteration ([a-zA-Z0-9_]+)}/', '\\1', $line);
19070 			}
19071 
19072 			// IMAGES & FORM ELEMENTS
19073 			if (substr($line, 0, 3) == "\xbb\xa4\xac") { // inline object - FORM element or IMAGE!
19074 				$objattr = $this->_getObjAttr($line);
19075 				if ($objattr['type'] != 'hr' && isset($objattr['width']) && ($objattr['width'] / $this->shrin_k) > ($maxwidth + 0.0001)) {
19076 					if (($objattr['width'] / $this->shrin_k) > $biggestword) {
19077 						$biggestword = ($objattr['width'] / $this->shrin_k);
19078 					}
19079 					$toonarrow = true;
19080 				}
19081 				continue;
19082 			}
19083 
19084 			if ($line == "\n") {
19085 				$acclength = 0; // mPDF 6 (accumulated length across > 1 chunk)
19086 				continue;
19087 			}
19088 			$line = trim($line);
19089 			if (!empty($OTLdata)) {
19090 				$this->otl->trimOTLdata($OTLdata, true, true);
19091 			} // *OTL*
19092 			// SET FONT SIZE/STYLE from $chunk[n]
19093 			// FONTSIZE
19094 			if (isset($chunk[11]) and $chunk[11] != '') {
19095 				if ($this->shrin_k) {
19096 					$this->SetFontSize($chunk[11] / $this->shrin_k, false);
19097 				} else {
19098 					$this->SetFontSize($chunk[11], false);
19099 				}
19100 			}
19101 			// FONTFAMILY
19102 			if (isset($chunk[4]) and $chunk[4] != '') {
19103 				$font = $this->SetFont($chunk[4], $this->FontStyle, 0, false);
19104 			}
19105 			// B I
19106 			if (isset($chunk[2]) and $chunk[2] != '') {
19107 				$this->SetStyles($chunk[2]);
19108 			}
19109 
19110 			$lbw = $rbw = 0; // Border widths
19111 			if (isset($chunk[16]) && !empty($chunk[16])) { // Border
19112 				$this->spanborddet = $chunk[16];
19113 				$lbw = (isset($this->spanborddet['L']['w']) ? $this->spanborddet['L']['w'] : 0);
19114 				$rbw = (isset($this->spanborddet['R']['w']) ? $this->spanborddet['R']['w'] : 0);
19115 			}
19116 			if (isset($chunk[15])) {   // Word spacing
19117 				$this->wSpacingCSS = $chunk[15];
19118 				if ($this->wSpacingCSS && strtoupper($this->wSpacingCSS) != 'NORMAL') {
19119 					$this->minwSpacing = $this->sizeConverter->convert($this->wSpacingCSS, $this->FontSize) / $this->shrin_k; // mPDF 5.7.3
19120 				}
19121 			}
19122 			if (isset($chunk[14])) {   // Letter spacing
19123 				$this->lSpacingCSS = $chunk[14];
19124 				if (($this->lSpacingCSS || $this->lSpacingCSS === '0') && strtoupper($this->lSpacingCSS) != 'NORMAL') {
19125 					$this->fixedlSpacing = $this->sizeConverter->convert($this->lSpacingCSS, $this->FontSize) / $this->shrin_k; // mPDF 5.7.3
19126 				}
19127 			}
19128 			if (isset($chunk[8])) { // mPDF 5.7.1
19129 				$this->textvar = $chunk[8];
19130 			}
19131 
19132 			// mPDF 6
19133 			// If overflow==wrap ($checkletter) OR (No word breaks and contains CJK)
19134 			if ($checkletter || (!preg_match('/(\xe2\x80\x8b| )/', trim($line)) && preg_match("/([" . $this->pregCJKchars . "])/u", $line) )) {
19135 				if (preg_match("/([" . $this->pregCJKchars . "])/u", $line)) {
19136 					$checkCJK = true;
19137 				} else {
19138 					$checkCJK = false;
19139 				}
19140 
19141 				$letters = preg_split('//u', $line);
19142 				foreach ($letters as $k => $letter) {
19143 					// mPDF 6
19144 					if ($checkCJK) {
19145 						if (preg_match("/[" . $this->CJKleading . "]/u", $letter) && $k > 0) {
19146 							$letter = $letters[$k - 1] . $letter;
19147 						}
19148 						if (preg_match("/[" . $this->CJKfollowing . "]/u", $letter) && $k < (count($letters) - 1)) {
19149 							$letter = $letter . $letters[$k + 1];
19150 						}
19151 					}
19152 
19153 					$letterwidth = $this->GetStringWidth($letter, false, false, $chunk[8]); // Pass $textvar ($chunk[8]), but do OTLdata here
19154 					// so don't have to split OTLdata for each word
19155 					if ($k == 0) {
19156 						$letterwidth += $lbw;
19157 					}
19158 					if ($k == (count($letters) - 1)) {
19159 						$letterwidth += $rbw;
19160 					}
19161 
19162 					// Warn user that maxwidth is insufficient
19163 					if ($letterwidth > $maxwidth + 0.0001) {
19164 						if ($letterwidth > $biggestword) {
19165 							$biggestword = $letterwidth;
19166 						}
19167 						$toonarrow = true;
19168 					}
19169 				}
19170 			} else {
19171 				// mPDF 6
19172 				// Need to account for any XAdvance in GPOSinfo (OTLdata = $chunk[18])
19173 				$wordXAdvance = [];
19174 				if (isset($chunk[18]) && $chunk[18]) {
19175 					preg_match_all('/(\xe2\x80\x8b| )/', $line, $spaces, PREG_OFFSET_CAPTURE); // U+200B Zero Width word boundary, or space
19176 					$lastoffset = 0;
19177 					$k = -1; // Added so that if no spaces found, "last word" later is calculated for the one and only word
19178 					foreach ($spaces[0] as $k => $m) {
19179 						$offset = $m[1];
19180 						// ...TableCheckMinWidth...
19181 						// At this point, BIDI not applied, Writing direction is not set, and XAdvanceL balances XAdvanceR
19182 						for ($n = $lastoffset; $n < $offset; $n++) {
19183 							if (isset($chunk[18]['GPOSinfo'][$n]['XAdvanceL'])) {
19184 								if (isset($wordXAdvance[$k])) {
19185 									$wordXAdvance[$k] += $chunk[18]['GPOSinfo'][$n]['XAdvanceL'];
19186 								} else {
19187 									$wordXAdvance[$k] = $chunk[18]['GPOSinfo'][$n]['XAdvanceL'];
19188 								}
19189 							}
19190 						}
19191 						$lastoffset = $offset + 1;
19192 					}
19193 
19194 					$k++;  // last word
19195 					foreach ($chunk[18]['GPOSinfo'] as $n => $gpos) {
19196 						if ($n >= $lastoffset && isset($chunk[18]['GPOSinfo'][$n]['XAdvanceL'])) {
19197 							if (isset($wordXAdvance[$k])) {
19198 								$wordXAdvance[$k] += $chunk[18]['GPOSinfo'][$n]['XAdvanceL'];
19199 							} else {
19200 								$wordXAdvance[$k] = $chunk[18]['GPOSinfo'][$n]['XAdvanceL'];
19201 							}
19202 						}
19203 					}
19204 				}
19205 
19206 				$words = preg_split('/(\xe2\x80\x8b| )/', $line); // U+200B Zero Width word boundary, or space
19207 				foreach ($words as $k => $word) {
19208 					$word = trim($word);
19209 					$wordwidth = $this->GetStringWidth($word, false, false, $chunk[8]); // Pass $textvar ($chunk[8]), but do OTLdata here
19210 					// so don't have to split OTLdata for each word
19211 					if (isset($wordXAdvance[$k])) {
19212 						$wordwidth += ($wordXAdvance[$k] * 1000 / $this->CurrentFont['unitsPerEm']) * ($this->FontSize / 1000);
19213 					}
19214 					if ($k == 0) {
19215 						$wordwidth += $lbw;
19216 					}
19217 					if ($k == (count($words) - 1)) {
19218 						$wordwidth += $rbw;
19219 					}
19220 
19221 					// mPDF 6
19222 					if (count($words) == 1 && substr($chunk[0], 0, 1) != ' ') {
19223 						$acclength += $wordwidth;
19224 					} elseif (count($words) > 1 && $k == 0 && substr($chunk[0], 0, 1) != ' ') {
19225 						$acclength += $wordwidth;
19226 					} else {
19227 						$acclength = $wordwidth;
19228 					}
19229 					$acclongest = max($acclongest, $acclength);
19230 					if (count($words) == 1 && substr($chunk[0], -1, 1) == ' ') {
19231 						$acclength = 0;
19232 					} elseif (count($words) > 1 && ($k != (count($words) - 1) || substr($chunk[0], -1, 1) == ' ')) {
19233 						$acclength = 0;
19234 					}
19235 
19236 					// Warn user that maxwidth is insufficient
19237 					if ($wordwidth > $maxwidth + 0.0001) {
19238 						if ($wordwidth > $biggestword) {
19239 							$biggestword = $wordwidth;
19240 						}
19241 						$toonarrow = true;
19242 					}
19243 				}
19244 			}
19245 
19246 			// mPDF 6  Accumulated length of biggest word - across multiple chunks
19247 			if ($acclongest > $maxwidth + 0.0001) {
19248 				if ($acclongest > $biggestword) {
19249 					$biggestword = $acclongest;
19250 				}
19251 				$toonarrow = true;
19252 			}
19253 
19254 			// RESET FONT SIZE/STYLE
19255 			// RESETTING VALUES
19256 			// Now we must deactivate what we have used
19257 			if (isset($chunk[2]) and $chunk[2] != '') {
19258 				$this->ResetStyles();
19259 			}
19260 			if (isset($chunk[4]) and $chunk[4] != '') {
19261 				$this->SetFont($this->default_font, $this->FontStyle, 0, false);
19262 			}
19263 			if (isset($chunk[11]) and $chunk[11] != '') {
19264 				$this->SetFontSize($this->default_font_size, false);
19265 			}
19266 			$this->spanborddet = [];
19267 			$this->textvar = 0x00; // mPDF 5.7.1
19268 			$this->OTLtags = [];
19269 			$this->lSpacingCSS = '';
19270 			$this->wSpacingCSS = '';
19271 			$this->fixedlSpacing = false;
19272 			$this->minwSpacing = 0;
19273 		}
19274 
19275 		// Return -(wordsize) if word is bigger than maxwidth
19276 		// ADDED
19277 		if (($toonarrow) && ($this->table_error_report)) {
19278 			throw new \Mpdf\MpdfException("Word is too long to fit in table - " . $this->table_error_report_param);
19279 		}
19280 		if ($toonarrow) {
19281 			return -$biggestword;
19282 		} else {
19283 			return 1;
19284 		}
19285 	}
19286 
19287 	function shrinkTable(&$table, $k)
19288 	{
19289 		$table['border_spacing_H'] /= $k;
19290 		$table['border_spacing_V'] /= $k;
19291 
19292 		$table['padding']['T'] /= $k;
19293 		$table['padding']['R'] /= $k;
19294 		$table['padding']['B'] /= $k;
19295 		$table['padding']['L'] /= $k;
19296 
19297 		$table['margin']['T'] /= $k;
19298 		$table['margin']['R'] /= $k;
19299 		$table['margin']['B'] /= $k;
19300 		$table['margin']['L'] /= $k;
19301 
19302 		$table['border_details']['T']['w'] /= $k;
19303 		$table['border_details']['R']['w'] /= $k;
19304 		$table['border_details']['B']['w'] /= $k;
19305 		$table['border_details']['L']['w'] /= $k;
19306 
19307 		if (isset($table['max_cell_border_width']['T'])) {
19308 			$table['max_cell_border_width']['T'] /= $k;
19309 		}
19310 		if (isset($table['max_cell_border_width']['R'])) {
19311 			$table['max_cell_border_width']['R'] /= $k;
19312 		}
19313 		if (isset($table['max_cell_border_width']['B'])) {
19314 			$table['max_cell_border_width']['B'] /= $k;
19315 		}
19316 		if (isset($table['max_cell_border_width']['L'])) {
19317 			$table['max_cell_border_width']['L'] /= $k;
19318 		}
19319 
19320 		if ($this->simpleTables) {
19321 			$table['simple']['border_details']['T']['w'] /= $k;
19322 			$table['simple']['border_details']['R']['w'] /= $k;
19323 			$table['simple']['border_details']['B']['w'] /= $k;
19324 			$table['simple']['border_details']['L']['w'] /= $k;
19325 		}
19326 
19327 		$table['miw'] /= $k;
19328 		$table['maw'] /= $k;
19329 
19330 		for ($j = 0; $j < $table['nc']; $j++) { // columns
19331 
19332 			$table['wc'][$j]['miw'] = isset($table['wc'][$j]['miw']) ? $table['wc'][$j]['miw'] : 0;
19333 			$table['wc'][$j]['maw'] = isset($table['wc'][$j]['maw']) ? $table['wc'][$j]['maw'] : 0;
19334 
19335 			$table['wc'][$j]['miw'] /= $k;
19336 			$table['wc'][$j]['maw'] /= $k;
19337 
19338 			if (isset($table['decimal_align'][$j]['maxs0']) && $table['decimal_align'][$j]['maxs0']) {
19339 				$table['decimal_align'][$j]['maxs0'] /= $k;
19340 			}
19341 
19342 			if (isset($table['decimal_align'][$j]['maxs1']) && $table['decimal_align'][$j]['maxs1']) {
19343 				$table['decimal_align'][$j]['maxs1'] /= $k;
19344 			}
19345 
19346 			if (isset($table['wc'][$j]['absmiw']) && $table['wc'][$j]['absmiw']) {
19347 				$table['wc'][$j]['absmiw'] /= $k;
19348 			}
19349 
19350 			for ($i = 0; $i < $table['nr']; $i++) { // rows
19351 
19352 				$c = &$table['cells'][$i][$j];
19353 
19354 				if (isset($c) && $c) {
19355 
19356 					if (!$this->simpleTables) {
19357 
19358 						if ($this->packTableData) {
19359 
19360 							$cell = $this->_unpackCellBorder($c['borderbin']);
19361 
19362 							$cell['border_details']['T']['w'] /= $k;
19363 							$cell['border_details']['R']['w'] /= $k;
19364 							$cell['border_details']['B']['w'] /= $k;
19365 							$cell['border_details']['L']['w'] /= $k;
19366 							$cell['border_details']['mbw']['TL'] /= $k;
19367 							$cell['border_details']['mbw']['TR'] /= $k;
19368 							$cell['border_details']['mbw']['BL'] /= $k;
19369 							$cell['border_details']['mbw']['BR'] /= $k;
19370 							$cell['border_details']['mbw']['LT'] /= $k;
19371 							$cell['border_details']['mbw']['LB'] /= $k;
19372 							$cell['border_details']['mbw']['RT'] /= $k;
19373 							$cell['border_details']['mbw']['RB'] /= $k;
19374 
19375 							$c['borderbin'] = $this->_packCellBorder($cell);
19376 
19377 						} else {
19378 
19379 							$c['border_details']['T']['w'] /= $k;
19380 							$c['border_details']['R']['w'] /= $k;
19381 							$c['border_details']['B']['w'] /= $k;
19382 							$c['border_details']['L']['w'] /= $k;
19383 							$c['border_details']['mbw']['TL'] /= $k;
19384 							$c['border_details']['mbw']['TR'] /= $k;
19385 							$c['border_details']['mbw']['BL'] /= $k;
19386 							$c['border_details']['mbw']['BR'] /= $k;
19387 							$c['border_details']['mbw']['LT'] /= $k;
19388 							$c['border_details']['mbw']['LB'] /= $k;
19389 							$c['border_details']['mbw']['RT'] /= $k;
19390 							$c['border_details']['mbw']['RB'] /= $k;
19391 						}
19392 					}
19393 
19394 					$c['padding']['T'] /= $k;
19395 					$c['padding']['R'] /= $k;
19396 					$c['padding']['B'] /= $k;
19397 					$c['padding']['L'] /= $k;
19398 
19399 					$c['maxs'] = isset($c['maxs']) ? $c['maxs'] /= $k : null;
19400 					$c['w'] = isset($c['w']) ? $c['w'] /= $k : null;
19401 
19402 					$c['s'] = isset($c['s']) ? $c['s'] /= $k : 0;
19403 					$c['h'] = isset($c['h']) ? $c['h'] /= $k : null;
19404 
19405 					$c['miw'] = isset($c['miw']) ? $c['miw'] /= $k : 0;
19406 					$c['maw'] = isset($c['maw']) ? $c['maw'] /= $k : 0;
19407 
19408 					$c['absmiw'] = isset($c['absmiw']) ? $c['absmiw'] /= $k : null;
19409 
19410 					$c['nestedmaw'] = isset($c['nestedmaw']) ? $c['nestedmaw'] /= $k : null;
19411 					$c['nestedmiw'] = isset($c['nestedmiw']) ? $c['nestedmiw'] /= $k : null;
19412 
19413 					if (isset($c['textbuffer'])) {
19414 						foreach ($c['textbuffer'] as $n => $tb) {
19415 							if (!empty($tb[16])) {
19416 								!isset($c['textbuffer'][$n][16]['T']) || $c['textbuffer'][$n][16]['T']['w'] /= $k;
19417 								!isset($c['textbuffer'][$n][16]['B']) || $c['textbuffer'][$n][16]['B']['w'] /= $k;
19418 								!isset($c['textbuffer'][$n][16]['L']) || $c['textbuffer'][$n][16]['L']['w'] /= $k;
19419 								!isset($c['textbuffer'][$n][16]['R']) || $c['textbuffer'][$n][16]['R']['w'] /= $k;
19420 							}
19421 						}
19422 					}
19423 
19424 					unset($c);
19425 				}
19426 
19427 			} // rows
19428 		} // columns
19429 	}
19430 
19431 	function read_short(&$fh)
19432 	{
19433 		$s = fread($fh, 2);
19434 		$a = (ord($s[0]) << 8) + ord($s[1]);
19435 		if ($a & (1 << 15)) {
19436 			$a = ($a - (1 << 16));
19437 		}
19438 		return $a;
19439 	}
19440 
19441 	function _packCellBorder($cell)
19442 	{
19443 		if (!is_array($cell) || !isset($cell)) {
19444 			return '';
19445 		}
19446 
19447 		if (!$this->packTableData) {
19448 			return $cell;
19449 		}
19450 		// = 186 bytes
19451 		$bindata = pack("nnda6A10nnda6A10nnda6A10nnda6A10nd9", $cell['border'], $cell['border_details']['R']['s'], $cell['border_details']['R']['w'], $cell['border_details']['R']['c'], $cell['border_details']['R']['style'], $cell['border_details']['R']['dom'], $cell['border_details']['L']['s'], $cell['border_details']['L']['w'], $cell['border_details']['L']['c'], $cell['border_details']['L']['style'], $cell['border_details']['L']['dom'], $cell['border_details']['T']['s'], $cell['border_details']['T']['w'], $cell['border_details']['T']['c'], $cell['border_details']['T']['style'], $cell['border_details']['T']['dom'], $cell['border_details']['B']['s'], $cell['border_details']['B']['w'], $cell['border_details']['B']['c'], $cell['border_details']['B']['style'], $cell['border_details']['B']['dom'], $cell['border_details']['mbw']['BL'], $cell['border_details']['mbw']['BR'], $cell['border_details']['mbw']['RT'], $cell['border_details']['mbw']['RB'], $cell['border_details']['mbw']['TL'], $cell['border_details']['mbw']['TR'], $cell['border_details']['mbw']['LT'], $cell['border_details']['mbw']['LB'], (isset($cell['border_details']['cellposdom']) ? $cell['border_details']['cellposdom'] : 0));
19452 		return $bindata;
19453 	}
19454 
19455 	function _getBorderWidths($bindata)
19456 	{
19457 		if (!$bindata) {
19458 			return [0, 0, 0, 0];
19459 		}
19460 		if (!$this->packTableData) {
19461 			return [$bindata['border_details']['T']['w'], $bindata['border_details']['R']['w'], $bindata['border_details']['B']['w'], $bindata['border_details']['L']['w']];
19462 		}
19463 
19464 		$bd = unpack("nbord/nrs/drw/a6rca/A10rst/nrd/nls/dlw/a6lca/A10lst/nld/nts/dtw/a6tca/A10tst/ntd/nbs/dbw/a6bca/A10bst/nbd/dmbl/dmbr/dmrt/dmrb/dmtl/dmtr/dmlt/dmlb/dcpd", $bindata);
19465 		$cell['border_details']['R']['w'] = $bd['rw'];
19466 		$cell['border_details']['L']['w'] = $bd['lw'];
19467 		$cell['border_details']['T']['w'] = $bd['tw'];
19468 		$cell['border_details']['B']['w'] = $bd['bw'];
19469 		return [$bd['tw'], $bd['rw'], $bd['bw'], $bd['lw']];
19470 	}
19471 
19472 	function _unpackCellBorder($bindata)
19473 	{
19474 		if (!$bindata) {
19475 			return [];
19476 		}
19477 		if (!$this->packTableData) {
19478 			return $bindata;
19479 		}
19480 
19481 		$bd = unpack("nbord/nrs/drw/a6rca/A10rst/nrd/nls/dlw/a6lca/A10lst/nld/nts/dtw/a6tca/A10tst/ntd/nbs/dbw/a6bca/A10bst/nbd/dmbl/dmbr/dmrt/dmrb/dmtl/dmtr/dmlt/dmlb/dcpd", $bindata);
19482 
19483 		$cell['border'] = $bd['bord'];
19484 		$cell['border_details']['R']['s'] = $bd['rs'];
19485 		$cell['border_details']['R']['w'] = $bd['rw'];
19486 		$cell['border_details']['R']['c'] = str_pad($bd['rca'], 6, "\x00");
19487 		$cell['border_details']['R']['style'] = trim($bd['rst']);
19488 		$cell['border_details']['R']['dom'] = $bd['rd'];
19489 
19490 		$cell['border_details']['L']['s'] = $bd['ls'];
19491 		$cell['border_details']['L']['w'] = $bd['lw'];
19492 		$cell['border_details']['L']['c'] = str_pad($bd['lca'], 6, "\x00");
19493 		$cell['border_details']['L']['style'] = trim($bd['lst']);
19494 		$cell['border_details']['L']['dom'] = $bd['ld'];
19495 
19496 		$cell['border_details']['T']['s'] = $bd['ts'];
19497 		$cell['border_details']['T']['w'] = $bd['tw'];
19498 		$cell['border_details']['T']['c'] = str_pad($bd['tca'], 6, "\x00");
19499 		$cell['border_details']['T']['style'] = trim($bd['tst']);
19500 		$cell['border_details']['T']['dom'] = $bd['td'];
19501 
19502 		$cell['border_details']['B']['s'] = $bd['bs'];
19503 		$cell['border_details']['B']['w'] = $bd['bw'];
19504 		$cell['border_details']['B']['c'] = str_pad($bd['bca'], 6, "\x00");
19505 		$cell['border_details']['B']['style'] = trim($bd['bst']);
19506 		$cell['border_details']['B']['dom'] = $bd['bd'];
19507 
19508 		$cell['border_details']['mbw']['BL'] = $bd['mbl'];
19509 		$cell['border_details']['mbw']['BR'] = $bd['mbr'];
19510 		$cell['border_details']['mbw']['RT'] = $bd['mrt'];
19511 		$cell['border_details']['mbw']['RB'] = $bd['mrb'];
19512 		$cell['border_details']['mbw']['TL'] = $bd['mtl'];
19513 		$cell['border_details']['mbw']['TR'] = $bd['mtr'];
19514 		$cell['border_details']['mbw']['LT'] = $bd['mlt'];
19515 		$cell['border_details']['mbw']['LB'] = $bd['mlb'];
19516 		$cell['border_details']['cellposdom'] = $bd['cpd'];
19517 
19518 
19519 		return($cell);
19520 	}
19521 
19522 	////////////////////////TABLE CODE (from PDFTable)/////////////////////////////////////
19523 	////////////////////////TABLE CODE (from PDFTable)/////////////////////////////////////
19524 	////////////////////////TABLE CODE (from PDFTable)/////////////////////////////////////
19525 	// table		Array of (w, h, bc, nr, wc, hr, cells)
19526 	// w			Width of table
19527 	// h			Height of table
19528 	// nc			Number column
19529 	// nr			Number row
19530 	// hr			List of height of each row
19531 	// wc			List of width of each column
19532 	// cells		List of cells of each rows, cells[i][j] is a cell in the table
19533 	function _tableColumnWidth(&$table, $firstpass = false)
19534 	{
19535 		$cs = &$table['cells'];
19536 
19537 		$nc = $table['nc'];
19538 		$nr = $table['nr'];
19539 		$listspan = [];
19540 
19541 		if ($table['borders_separate']) {
19542 			$tblbw = $table['border_details']['L']['w'] + $table['border_details']['R']['w'] + $table['margin']['L'] + $table['margin']['R'] + $table['padding']['L'] + $table['padding']['R'] + $table['border_spacing_H'];
19543 		} else {
19544 			$tblbw = $table['max_cell_border_width']['L'] / 2 + $table['max_cell_border_width']['R'] / 2 + $table['margin']['L'] + $table['margin']['R'];
19545 		}
19546 
19547 		// ADDED table['l'][colno]
19548 		// = total length of text approx (using $c['s']) in that column - used to approximately distribute col widths in _tableWidth
19549 		//
19550 		for ($j = 0; $j < $nc; $j++) { // columns
19551 			$wc = &$table['wc'][$j];
19552 			for ($i = 0; $i < $nr; $i++) { // rows
19553 				if (isset($cs[$i][$j]) && $cs[$i][$j]) {
19554 					$c = &$cs[$i][$j];
19555 
19556 					if ($this->simpleTables) {
19557 						if ($table['borders_separate']) { // NB twice border width
19558 							$extrcw = $table['simple']['border_details']['L']['w'] + $table['simple']['border_details']['R']['w'] + $c['padding']['L'] + $c['padding']['R'] + $table['border_spacing_H'];
19559 						} else {
19560 							$extrcw = $table['simple']['border_details']['L']['w'] / 2 + $table['simple']['border_details']['R']['w'] / 2 + $c['padding']['L'] + $c['padding']['R'];
19561 						}
19562 					} else {
19563 						if ($this->packTableData) {
19564 							list($bt, $br, $bb, $bl) = $this->_getBorderWidths($c['borderbin']);
19565 						} else {
19566 							$br = $c['border_details']['R']['w'];
19567 							$bl = $c['border_details']['L']['w'];
19568 						}
19569 						if ($table['borders_separate']) { // NB twice border width
19570 							$extrcw = $bl + $br + $c['padding']['L'] + $c['padding']['R'] + $table['border_spacing_H'];
19571 						} else {
19572 							$extrcw = $bl / 2 + $br / 2 + $c['padding']['L'] + $c['padding']['R'];
19573 						}
19574 					}
19575 
19576 					// $mw = $this->GetStringWidth('W') + $extrcw ;
19577 					$mw = $extrcw; // mPDF 6
19578 					if (substr($c['a'], 0, 1) == 'D') {
19579 						$mw = $table['decimal_align'][$j]['maxs0'] + $table['decimal_align'][$j]['maxs1'] + $extrcw;
19580 					}
19581 
19582 					$c['absmiw'] = $mw;
19583 
19584 					if (isset($c['R']) && $c['R']) {
19585 						$c['maw'] = $c['miw'] = $this->FontSize + $extrcw;
19586 						if (isset($c['w'])) { // If cell width is specified
19587 							if ($c['miw'] < $c['w']) {
19588 								$c['miw'] = $c['w'];
19589 							}
19590 						}
19591 						if (!isset($c['colspan'])) {
19592 							if ($wc['miw'] < $c['miw']) {
19593 								$wc['miw'] = $c['miw'];
19594 							}
19595 							if ($wc['maw'] < $c['maw']) {
19596 								$wc['maw'] = $c['maw'];
19597 							}
19598 
19599 							if ($firstpass) {
19600 								if (isset($table['l'][$j])) {
19601 									$table['l'][$j] += $c['miw'];
19602 								} else {
19603 									$table['l'][$j] = $c['miw'];
19604 								}
19605 							}
19606 						}
19607 						if ($c['miw'] > $wc['miw']) {
19608 							$wc['miw'] = $c['miw'];
19609 						}
19610 						if ($wc['miw'] > $wc['maw']) {
19611 							$wc['maw'] = $wc['miw'];
19612 						}
19613 						continue;
19614 					}
19615 
19616 					if ($firstpass) {
19617 						if (isset($c['s'])) {
19618 							$c['s'] += $extrcw;
19619 						}
19620 						if (isset($c['maxs'])) {
19621 							$c['maxs'] += $extrcw;
19622 						}
19623 						if (isset($c['nestedmiw'])) {
19624 							$c['nestedmiw'] += $extrcw;
19625 						}
19626 						if (isset($c['nestedmaw'])) {
19627 							$c['nestedmaw'] += $extrcw;
19628 						}
19629 					}
19630 
19631 
19632 					// If minimum width has already been set by a nested table or inline object (image/form), use it
19633 					if (isset($c['nestedmiw']) && (!isset($this->table[1][1]['overflow']) || $this->table[1][1]['overflow'] != 'visible')) {
19634 						$miw = $c['nestedmiw'];
19635 					} else {
19636 						$miw = $mw;
19637 					}
19638 
19639 					if (isset($c['maxs']) && $c['maxs'] != '') {
19640 						$c['s'] = $c['maxs'];
19641 					}
19642 
19643 					// If maximum width has already been set by a nested table, use it
19644 					if (isset($c['nestedmaw'])) {
19645 						$c['maw'] = $c['nestedmaw'];
19646 					} else {
19647 						$c['maw'] = $c['s'];
19648 					}
19649 
19650 					if (isset($table['overflow']) && $table['overflow'] == 'visible' && $table['level'] == 1) {
19651 						if (($c['maw'] + $tblbw) > $this->blk[$this->blklvl]['inner_width']) {
19652 							$c['maw'] = $this->blk[$this->blklvl]['inner_width'] - $tblbw;
19653 						}
19654 					}
19655 
19656 					if (isset($c['nowrap']) && $c['nowrap']) {
19657 						$miw = $c['maw'];
19658 					}
19659 
19660 					if (isset($c['wpercent']) && $firstpass) {
19661 						if (isset($c['colspan'])) { // Not perfect - but % set on colspan is shared equally on cols.
19662 							for ($k = 0; $k < $c['colspan']; $k++) {
19663 								$table['wc'][($j + $k)]['wpercent'] = $c['wpercent'] / $c['colspan'];
19664 							}
19665 						} else {
19666 							if (isset($table['w']) && $table['w']) {
19667 								$c['w'] = $c['wpercent'] / 100 * ($table['w'] - $tblbw );
19668 							}
19669 							$wc['wpercent'] = $c['wpercent'];
19670 						}
19671 					}
19672 
19673 					if (isset($table['overflow']) && $table['overflow'] == 'visible' && $table['level'] == 1) {
19674 						if (isset($c['w']) && ($c['w'] + $tblbw) > $this->blk[$this->blklvl]['inner_width']) {
19675 							$c['w'] = $this->blk[$this->blklvl]['inner_width'] - $tblbw;
19676 						}
19677 					}
19678 
19679 
19680 					if (isset($c['w'])) { // If cell width is specified
19681 						if ($miw < $c['w']) {
19682 							$c['miw'] = $c['w'];
19683 						} // Cell min width = that specified
19684 						if ($miw > $c['w']) {
19685 							$c['miw'] = $c['w'] = $miw;
19686 						} // If width specified is less than minimum allowed (W) increase it
19687 						// mPDF 5.7.4  Do not set column width in colspan
19688 						// cf. http://www.mpdf1.com/forum/discussion/2221/colspan-bug
19689 						if (!isset($c['colspan'])) {
19690 							if (!isset($wc['w'])) {
19691 								$wc['w'] = 1;
19692 							}  // If the Col width is not specified = set it to 1
19693 						}
19694 						// mPDF 5.7.3  cf. http://www.mpdf1.com/forum/discussion/1648/nested-table-bug-
19695 						$c['maw'] = $c['w'];
19696 					} else {
19697 						$c['miw'] = $miw;
19698 					} // If cell width not specified -> set Cell min width it to minimum allowed (W)
19699 
19700 					if (isset($c['miw']) && $c['maw'] < $c['miw']) {
19701 						$c['maw'] = $c['miw'];
19702 					} // If Cell max width < Minwidth - increase it to =
19703 					if (!isset($c['colspan'])) {
19704 						if (isset($c['miw']) && $wc['miw'] < $c['miw']) {
19705 							$wc['miw'] = $c['miw'];
19706 						} // Update Col Minimum and maximum widths
19707 						if ($wc['maw'] < $c['maw']) {
19708 							$wc['maw'] = $c['maw'];
19709 						}
19710 						if ((isset($wc['absmiw']) && $wc['absmiw'] < $c['absmiw']) || !isset($wc['absmiw'])) {
19711 							$wc['absmiw'] = $c['absmiw'];
19712 						} // Update Col Minimum and maximum widths
19713 
19714 						if (isset($table['l'][$j])) {
19715 							$table['l'][$j] += $c['s'];
19716 						} else {
19717 							$table['l'][$j] = $c['s'];
19718 						}
19719 					} else {
19720 						$listspan[] = [$i, $j];
19721 					}
19722 
19723 					// Check if minimum width of the whole column is big enough for largest word to fit
19724 					// mPDF 6
19725 					if (isset($c['textbuffer'])) {
19726 						if (isset($table['overflow']) && $table['overflow'] == 'wrap') {
19727 							$letter = true;
19728 						} // check for maximum width of letters
19729 						else {
19730 							$letter = false;
19731 						}
19732 						$minwidth = $this->TableCheckMinWidth($wc['miw'] - $extrcw, 0, $c['textbuffer'], $letter);
19733 					} else {
19734 						$minwidth = 0;
19735 					}
19736 					if ($minwidth < 0) {
19737 						// increase minimum width
19738 						if (!isset($c['colspan'])) {
19739 							$wc['miw'] = max((isset($wc['miw']) ? $wc['miw'] : 0), ((-$minwidth) + $extrcw));
19740 						} else {
19741 							$c['miw'] = max((isset($c['miw']) ? $c['miw'] : 0), ((-$minwidth) + $extrcw));
19742 						}
19743 					}
19744 					if (!isset($c['colspan'])) {
19745 						if ($wc['miw'] > $wc['maw']) {
19746 							$wc['maw'] = $wc['miw'];
19747 						} // update maximum width, if needed
19748 					}
19749 				}
19750 				unset($c);
19751 			}//rows
19752 		}//columns
19753 		// COLUMN SPANS
19754 		$wc = &$table['wc'];
19755 		foreach ($listspan as $span) {
19756 			list($i, $j) = $span;
19757 			$c = &$cs[$i][$j];
19758 			$lc = $j + $c['colspan'];
19759 			if ($lc > $nc) {
19760 				$lc = $nc;
19761 			}
19762 			$wis = $wisa = 0;
19763 			$was = $wasa = 0;
19764 			$list = [];
19765 			for ($k = $j; $k < $lc; $k++) {
19766 				if (isset($table['l'][$k])) {
19767 					if ($c['R']) {
19768 						$table['l'][$k] += $c['miw'] / $c['colspan'];
19769 					} else {
19770 						$table['l'][$k] += $c['s'] / $c['colspan'];
19771 					}
19772 				} else {
19773 					if ($c['R']) {
19774 						$table['l'][$k] = $c['miw'] / $c['colspan'];
19775 					} else {
19776 						$table['l'][$k] = $c['s'] / $c['colspan'];
19777 					}
19778 				}
19779 				$wis += $wc[$k]['miw'];   // $wis is the sum of the column miw in the colspan
19780 				$was += $wc[$k]['maw'];   // $was is the sum of the column maw in the colspan
19781 				if (!isset($c['w'])) {
19782 					$list[] = $k;
19783 					$wisa += $wc[$k]['miw']; // $wisa is the sum of the column miw in cells with no width specified in the colspan
19784 					$wasa += $wc[$k]['maw']; // $wasa is the sum of the column maw in cells with no width specified in the colspan
19785 				}
19786 			}
19787 			if ($c['miw'] > $wis) {
19788 				if (!$wis) {
19789 					for ($k = $j; $k < $lc; $k++) {
19790 						$wc[$k]['miw'] = $c['miw'] / $c['colspan'];
19791 					}
19792 				} elseif (!count($list) && $wis != 0) {
19793 					$wi = $c['miw'] - $wis;
19794 					for ($k = $j; $k < $lc; $k++) {
19795 						$wc[$k]['miw'] += ($wc[$k]['miw'] / $wis) * $wi;
19796 					}
19797 				} else {
19798 					$wi = $c['miw'] - $wis;
19799 					// mPDF 5.7.2   Extra min width distributed proportionately to all cells in colspan without a specified width
19800 					// cf. http://www.mpdf1.com/forum/discussion/1607#Item_4
19801 					foreach ($list as $k) {
19802 						if (!isset($wc[$k]['w']) || !$wc[$k]['w']) {
19803 							$wc[$k]['miw'] += ($wc[$k]['miw'] / $wisa) * $wi;
19804 						}
19805 					} // mPDF 5.7.2
19806 				}
19807 			}
19808 			if ($c['maw'] > $was) {
19809 				if (!$wis) {
19810 					for ($k = $j; $k < $lc; $k++) {
19811 						$wc[$k]['maw'] = $c['maw'] / $c['colspan'];
19812 					}
19813 				} elseif (!count($list) && $was != 0) {
19814 					$wi = $c['maw'] - $was;
19815 					for ($k = $j; $k < $lc; $k++) {
19816 						$wc[$k]['maw'] += ($wc[$k]['maw'] / $was) * $wi;
19817 					}
19818 				} else {
19819 					$wi = $c['maw'] - $was;
19820 					// mPDF 5.7.4  Extra max width distributed evenly to all cells in colspan without a specified width
19821 					// cf. http://www.mpdf1.com/forum/discussion/2221/colspan-bug
19822 					foreach ($list as $k) {
19823 						$wc[$k]['maw'] += $wi / count($list);
19824 					}
19825 				}
19826 			}
19827 			unset($c);
19828 		}
19829 
19830 		$checkminwidth = 0;
19831 		$checkmaxwidth = 0;
19832 		$totallength = 0;
19833 
19834 		for ($i = 0; $i < $nc; $i++) {
19835 			$checkminwidth += $table['wc'][$i]['miw'];
19836 			$checkmaxwidth += $table['wc'][$i]['maw'];
19837 			$totallength += isset($table['l']) ? $table['l'][$i] : 0;
19838 		}
19839 
19840 		if (!isset($table['w']) && $firstpass) {
19841 			$sumpc = 0;
19842 			$notset = 0;
19843 			for ($i = 0; $i < $nc; $i++) {
19844 				if (isset($table['wc'][$i]['wpercent']) && $table['wc'][$i]['wpercent']) {
19845 					$sumpc += $table['wc'][$i]['wpercent'];
19846 				} else {
19847 					$notset++;
19848 				}
19849 			}
19850 
19851 			// If sum of widths as %  >= 100% and not all columns are set
19852 			// Set a nominal width of 1% for unset columns
19853 			if ($sumpc >= 100 && $notset) {
19854 				for ($i = 0; $i < $nc; $i++) {
19855 					if ((!isset($table['wc'][$i]['wpercent']) || !$table['wc'][$i]['wpercent']) &&
19856 						(!isset($table['wc'][$i]['w']) || !$table['wc'][$i]['w'])) {
19857 						$table['wc'][$i]['wpercent'] = 1;
19858 					}
19859 				}
19860 			}
19861 
19862 
19863 			if ($sumpc) { // if any percents are set
19864 				$sumnonpc = (100 - $sumpc);
19865 				$sumpc = max($sumpc, 100);
19866 				$miwleft = 0;
19867 				$miwleftcount = 0;
19868 				$miwsurplusnonpc = 0;
19869 				$maxcalcmiw = 0;
19870 				$mawleft = 0;
19871 				$mawleftcount = 0;
19872 				$mawsurplusnonpc = 0;
19873 				$maxcalcmaw = 0;
19874 				$mawnon = 0;
19875 				$miwnon = 0;
19876 				for ($i = 0; $i < $nc; $i++) {
19877 					if (isset($table['wc'][$i]['wpercent'])) {
19878 						$maxcalcmiw = max($maxcalcmiw, ($table['wc'][$i]['miw'] * $sumpc / $table['wc'][$i]['wpercent']));
19879 						$maxcalcmaw = max($maxcalcmaw, ($table['wc'][$i]['maw'] * $sumpc / $table['wc'][$i]['wpercent']));
19880 					} else {
19881 						$miwleft += $table['wc'][$i]['miw'];
19882 						$mawleft += $table['wc'][$i]['maw'];
19883 						if (!isset($table['wc'][$i]['w'])) {
19884 							$miwleftcount++;
19885 							$mawleftcount++;
19886 						}
19887 					}
19888 				}
19889 				if ($miwleft && $sumnonpc > 0) {
19890 					$miwnon = $miwleft * 100 / $sumnonpc;
19891 				}
19892 				if ($mawleft && $sumnonpc > 0) {
19893 					$mawnon = $mawleft * 100 / $sumnonpc;
19894 				}
19895 				if (($miwnon > $checkminwidth || $maxcalcmiw > $checkminwidth) && $this->keep_table_proportions) {
19896 					if ($miwnon > $maxcalcmiw) {
19897 						$miwsurplusnonpc = round((($miwnon * $sumnonpc / 100) - $miwleft), 3);
19898 						$checkminwidth = $miwnon;
19899 					} else {
19900 						$checkminwidth = $maxcalcmiw;
19901 					}
19902 					for ($i = 0; $i < $nc; $i++) {
19903 						if (isset($table['wc'][$i]['wpercent'])) {
19904 							$newmiw = $checkminwidth * $table['wc'][$i]['wpercent'] / 100;
19905 							if ($table['wc'][$i]['miw'] < $newmiw) {
19906 								$table['wc'][$i]['miw'] = $newmiw;
19907 							}
19908 							$table['wc'][$i]['w'] = 1;
19909 						} elseif ($miwsurplusnonpc && !$table['wc'][$i]['w']) {
19910 							$table['wc'][$i]['miw'] += $miwsurplusnonpc / $miwleftcount;
19911 						}
19912 					}
19913 				}
19914 				if (($mawnon > $checkmaxwidth || $maxcalcmaw > $checkmaxwidth)) {
19915 					if ($mawnon > $maxcalcmaw) {
19916 						$mawsurplusnonpc = round((($mawnon * $sumnonpc / 100) - $mawleft), 3);
19917 						$checkmaxwidth = $mawnon;
19918 					} else {
19919 						$checkmaxwidth = $maxcalcmaw;
19920 					}
19921 					for ($i = 0; $i < $nc; $i++) {
19922 						if (isset($table['wc'][$i]['wpercent'])) {
19923 							$newmaw = $checkmaxwidth * $table['wc'][$i]['wpercent'] / 100;
19924 							if ($table['wc'][$i]['maw'] < $newmaw) {
19925 								$table['wc'][$i]['maw'] = $newmaw;
19926 							}
19927 							$table['wc'][$i]['w'] = 1;
19928 						} elseif ($mawsurplusnonpc && !$table['wc'][$i]['w']) {
19929 							$table['wc'][$i]['maw'] += $mawsurplusnonpc / $mawleftcount;
19930 						}
19931 						if ($table['wc'][$i]['maw'] < $table['wc'][$i]['miw']) {
19932 							$table['wc'][$i]['maw'] = $table['wc'][$i]['miw'];
19933 						}
19934 					}
19935 				}
19936 				if ($checkminwidth > $checkmaxwidth) {
19937 					$checkmaxwidth = $checkminwidth;
19938 				}
19939 			}
19940 		}
19941 
19942 		if (isset($table['wpercent']) && $table['wpercent']) {
19943 			$checkminwidth *= (100 / $table['wpercent']);
19944 			$checkmaxwidth *= (100 / $table['wpercent']);
19945 		}
19946 
19947 
19948 		$checkminwidth += $tblbw;
19949 		$checkmaxwidth += $tblbw;
19950 
19951 		// Table['miw'] set by percent in first pass may be larger than sum of column miw
19952 		if ((isset($table['miw']) && $checkminwidth > $table['miw']) || !isset($table['miw'])) {
19953 			$table['miw'] = $checkminwidth;
19954 		}
19955 		if ((isset($table['maw']) && $checkmaxwidth > $table['maw']) || !isset($table['maw'])) {
19956 			$table['maw'] = $checkmaxwidth;
19957 		}
19958 		$table['tl'] = $totallength;
19959 
19960 		// mPDF 6
19961 		if ($this->table_rotate) {
19962 			$mxw = $this->tbrot_maxw;
19963 		} else {
19964 			$mxw = $this->blk[$this->blklvl]['inner_width'];
19965 		}
19966 
19967 		if (!isset($table['overflow'])) {
19968 			$table['overflow'] = null;
19969 		}
19970 
19971 		if ($table['overflow'] == 'visible') {
19972 			return [0, 0];
19973 		} elseif ($table['overflow'] == 'hidden' && !$this->table_rotate && !$this->ColActive && $checkminwidth > $mxw) {
19974 			$table['w'] = $table['miw'];
19975 			return [0, 0];
19976 		}
19977 		// elseif ($table['overflow']=='wrap') { return array(0,0); }	// mPDF 6
19978 
19979 		if (isset($table['w']) && $table['w']) {
19980 
19981 			if ($table['w'] >= $checkminwidth && $table['w'] <= $mxw) {
19982 				$table['maw'] = $mxw = $table['w'];
19983 			} elseif ($table['w'] >= $checkminwidth && $table['w'] > $mxw && $this->keep_table_proportions) {
19984 				$checkminwidth = $table['w'];
19985 			} elseif ($table['w'] < $checkminwidth && $checkminwidth < $mxw && $this->keep_table_proportions) {
19986 				$table['maw'] = $table['w'] = $checkminwidth;
19987 			} else {
19988 				unset($table['w']);
19989 			}
19990 		}
19991 
19992 		$ratio = $checkminwidth / $mxw;
19993 
19994 		if ($checkminwidth > $mxw) {
19995 			return [($ratio + 0.001), $checkminwidth]; // 0.001 to allow for rounded numbers when resizing
19996 		}
19997 
19998 		unset($cs);
19999 
20000 		return [0, 0];
20001 	}
20002 
20003 	function _tableWidth(&$table)
20004 	{
20005 		$widthcols = &$table['wc'];
20006 		$numcols = $table['nc'];
20007 		$tablewidth = 0;
20008 
20009 		if ($table['borders_separate']) {
20010 			$tblbw = $table['border_details']['L']['w'] + $table['border_details']['R']['w'] + $table['margin']['L'] + $table['margin']['R'] + $table['padding']['L'] + $table['padding']['R'] + $table['border_spacing_H'];
20011 		} else {
20012 			$tblbw = $table['max_cell_border_width']['L'] / 2 + $table['max_cell_border_width']['R'] / 2 + $table['margin']['L'] + $table['margin']['R'];
20013 		}
20014 
20015 		if ($table['level'] > 1 && isset($table['w'])) {
20016 
20017 			if (isset($table['wpercent']) && $table['wpercent']) {
20018 				$table['w'] = $temppgwidth = (($table['w'] - $tblbw) * $table['wpercent'] / 100) + $tblbw;
20019 			} else {
20020 				$temppgwidth = $table['w'];
20021 			}
20022 
20023 		} elseif ($this->table_rotate) {
20024 
20025 			$temppgwidth = $this->tbrot_maxw;
20026 
20027 			// If it is less than 1/20th of the remaining page height to finish the DIV (i.e. DIV padding + table bottom margin) then allow for this
20028 			$enddiv = $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w'];
20029 
20030 			if ($enddiv / $temppgwidth < 0.05) {
20031 				$temppgwidth -= $enddiv;
20032 			}
20033 
20034 		} else {
20035 
20036 			if (isset($table['w']) && $table['w'] < $this->blk[$this->blklvl]['inner_width']) {
20037 				$notfullwidth = 1;
20038 				$temppgwidth = $table['w'];
20039 			} elseif ($table['overflow'] == 'visible' && $table['level'] == 1) {
20040 				$temppgwidth = null;
20041 			} elseif ($table['overflow'] == 'hidden' && !$this->ColActive && isset($table['w']) && $table['w'] > $this->blk[$this->blklvl]['inner_width'] && $table['w'] == $table) {
20042 				// $temppgwidth = $this->blk[$this->blklvl]['inner_width'];
20043 				$temppgwidth = $table['w'];
20044 			} else {
20045 				$temppgwidth = $this->blk[$this->blklvl]['inner_width'];
20046 			}
20047 
20048 		}
20049 
20050 		$totaltextlength = 0; // Added - to sum $table['l'][colno]
20051 		$totalatextlength = 0; // Added - to sum $table['l'][colno] for those columns where width not set
20052 		$percentages_set = 0;
20053 
20054 		for ($i = 0; $i < $numcols; $i++) {
20055 			if (isset($widthcols[$i]['wpercent'])) {
20056 				$tablewidth += $widthcols[$i]['maw'];
20057 				$percentages_set = 1;
20058 			} elseif (isset($widthcols[$i]['w'])) {
20059 				$tablewidth += $widthcols[$i]['miw'];
20060 			} else {
20061 				$tablewidth += $widthcols[$i]['maw'];
20062 			}
20063 			$totaltextlength += isset($table['l']) ? $table['l'][$i] : 0;
20064 		}
20065 
20066 		if (!$totaltextlength) {
20067 			$totaltextlength = 1;
20068 		}
20069 
20070 		$tablewidth += $tblbw; // Outer half of table borders
20071 
20072 		if ($tablewidth > $temppgwidth) {
20073 			$table['w'] = $temppgwidth;
20074 		} elseif ($tablewidth < $temppgwidth && !isset($table['w']) && $percentages_set) { // if any widths set as percentages and max width fits < page width
20075 			$table['w'] = $table['maw'];
20076 		}
20077 
20078 		// if table width is set and is > allowed width
20079 		if (isset($table['w']) && $table['w'] > $temppgwidth) {
20080 			$table['w'] = $temppgwidth;
20081 		}
20082 
20083 		// IF the table width is now set - Need to distribute columns widths
20084 		// mPDF 5.7.3
20085 		// If the table width is already set to the maximum width (e.g. nested table), then use maximum column widths exactly
20086 		if (isset($table['w']) && ($table['w'] == $tablewidth) && !$percentages_set) {
20087 
20088 			// This sets the columns all to maximum width
20089 			for ($i = 0; $i < $numcols; $i++) {
20090 				$widthcols[$i] = $widthcols[$i]['maw'];
20091 			}
20092 
20093 		} elseif (isset($table['w'])) { // elseif the table width is set distribute width using algorithm
20094 
20095 			$wis = $wisa = 0;
20096 			$list = [];
20097 			$notsetlist = [];
20098 
20099 			for ($i = 0; $i < $numcols; $i++) {
20100 				$wis += $widthcols[$i]['miw'];
20101 				if (!isset($widthcols[$i]['w']) || ($widthcols[$i]['w'] && $table['w'] > $temppgwidth && !$this->keep_table_proportions && !$notfullwidth )) {
20102 					$list[] = $i;
20103 					$wisa += $widthcols[$i]['miw'];
20104 					$totalatextlength += $table['l'][$i];
20105 				}
20106 			}
20107 
20108 			if (!$totalatextlength) {
20109 				$totalatextlength = 1;
20110 			}
20111 
20112 			// Allocate spare (more than col's minimum width) across the cols according to their approx total text length
20113 			// Do it by setting minimum width here
20114 			if ($table['w'] > $wis + $tblbw) {
20115 
20116 				// First set any cell widths set as percentages
20117 				if ($table['w'] < $temppgwidth || $this->keep_table_proportions) {
20118 					for ($k = 0; $k < $numcols; $k++) {
20119 						if (isset($widthcols[$k]['wpercent'])) {
20120 							$curr = $widthcols[$k]['miw'];
20121 							$widthcols[$k]['miw'] = ($table['w'] - $tblbw) * $widthcols[$k]['wpercent'] / 100;
20122 							$wis += $widthcols[$k]['miw'] - $curr;
20123 							$wisa += $widthcols[$k]['miw'] - $curr;
20124 						}
20125 					}
20126 				}
20127 
20128 				// Now allocate surplus up to maximum width of each column
20129 				$surplus = 0;
20130 				$ttl = 0; // number of surplus columns
20131 
20132 				if (!count($list)) {
20133 
20134 					$wi = ($table['w'] - ($wis + $tblbw)); // i.e. extra space to distribute
20135 
20136 					for ($k = 0; $k < $numcols; $k++) {
20137 
20138 						$spareratio = ($table['l'][$k] / $totaltextlength); //  gives ratio to divide up free space
20139 
20140 						// Don't allocate more than Maximum required width - save rest in surplus
20141 						if ($widthcols[$k]['miw'] + ($wi * $spareratio) >= $widthcols[$k]['maw']) { // mPDF 5.7.3
20142 							$surplus += ($wi * $spareratio) - ($widthcols[$k]['maw'] - $widthcols[$k]['miw']);
20143 							$widthcols[$k]['miw'] = $widthcols[$k]['maw'];
20144 						} else {
20145 							$notsetlist[] = $k;
20146 							$ttl += $table['l'][$k];
20147 							$widthcols[$k]['miw'] += ($wi * $spareratio);
20148 						}
20149 					}
20150 
20151 				} else {
20152 
20153 					$wi = ($table['w'] - ($wis + $tblbw)); // i.e. extra space to distribute
20154 
20155 					foreach ($list as $k) {
20156 
20157 						$spareratio = ($table['l'][$k] / $totalatextlength); //  gives ratio to divide up free space
20158 
20159 						// Don't allocate more than Maximum required width - save rest in surplus
20160 						if ($widthcols[$k]['miw'] + ($wi * $spareratio) >= $widthcols[$k]['maw']) { // mPDF 5.7.3
20161 							$surplus += ($wi * $spareratio) - ($widthcols[$k]['maw'] - $widthcols[$k]['miw']);
20162 							$widthcols[$k]['miw'] = $widthcols[$k]['maw'];
20163 						} else {
20164 							$notsetlist[] = $k;
20165 							$ttl += $table['l'][$k];
20166 							$widthcols[$k]['miw'] += ($wi * $spareratio);
20167 						}
20168 					}
20169 				}
20170 
20171 				// If surplus still left over apportion it across columns
20172 				if ($surplus) {
20173 
20174 					if (count($notsetlist) && count($notsetlist) < $numcols) { // if some are set only add to remaining - otherwise add to all of them
20175 						foreach ($notsetlist as $i) {
20176 							if ($ttl) {
20177 								$widthcols[$i]['miw'] += $surplus * $table['l'][$i] / $ttl;
20178 							}
20179 						}
20180 					} elseif (count($list) && count($list) < $numcols) { // If some widths are defined, and others have been added up to their maxmum
20181 						foreach ($list as $i) {
20182 							$widthcols[$i]['miw'] += $surplus / count($list);
20183 						}
20184 					} elseif ($numcols) { // If all columns
20185 						$ttl = array_sum($table['l']);
20186 						if ($ttl) {
20187 							for ($i = 0; $i < $numcols; $i++) {
20188 								$widthcols[$i]['miw'] += $surplus * $table['l'][$i] / $ttl;
20189 							}
20190 						}
20191 					}
20192 				}
20193 			}
20194 
20195 			// This sets the columns all to minimum width (which has been increased above if appropriate)
20196 			for ($i = 0; $i < $numcols; $i++) {
20197 				$widthcols[$i] = $widthcols[$i]['miw'];
20198 			}
20199 
20200 			// TABLE NOT WIDE ENOUGH EVEN FOR MINIMUM CONTENT WIDTH
20201 			// If sum of column widths set are too wide for table
20202 			$checktablewidth = 0;
20203 			for ($i = 0; $i < $numcols; $i++) {
20204 				$checktablewidth += $widthcols[$i];
20205 			}
20206 
20207 			if ($checktablewidth > ($temppgwidth + 0.001 - $tblbw)) {
20208 
20209 				$usedup = 0;
20210 				$numleft = 0;
20211 
20212 				for ($i = 0; $i < $numcols; $i++) {
20213 					if ((isset($widthcols[$i]) && $widthcols[$i] > (($temppgwidth - $tblbw) / $numcols)) && (!isset($widthcols[$i]['w']))) {
20214 						$numleft++;
20215 						unset($widthcols[$i]);
20216 					} else {
20217 						$usedup += $widthcols[$i];
20218 					}
20219 				}
20220 
20221 				for ($i = 0; $i < $numcols; $i++) {
20222 					if (!isset($widthcols[$i]) || !$widthcols[$i]) {
20223 						$widthcols[$i] = ((($temppgwidth - $tblbw) - $usedup) / ($numleft));
20224 					}
20225 				}
20226 			}
20227 
20228 		} else { // table has no width defined
20229 
20230 			$table['w'] = $tablewidth;
20231 
20232 			for ($i = 0; $i < $numcols; $i++) {
20233 
20234 				if (isset($widthcols[$i]['wpercent']) && $this->keep_table_proportions) {
20235 					$colwidth = $widthcols[$i]['maw'];
20236 				} elseif (isset($widthcols[$i]['w'])) {
20237 					$colwidth = $widthcols[$i]['miw'];
20238 				} else {
20239 					$colwidth = $widthcols[$i]['maw'];
20240 				}
20241 
20242 				unset($widthcols[$i]);
20243 				$widthcols[$i] = $colwidth;
20244 
20245 			}
20246 		}
20247 
20248 		if ($table['overflow'] === 'visible' && $table['level'] == 1) {
20249 
20250 			if ($tablewidth > $this->blk[$this->blklvl]['inner_width']) {
20251 
20252 				for ($j = 0; $j < $numcols; $j++) { // columns
20253 
20254 					for ($i = 0; $i < $table['nr']; $i++) { // rows
20255 
20256 						if (isset($table['cells'][$i][$j]) && $table['cells'][$i][$j]) {
20257 
20258 							$colspan = (isset($table['cells'][$i][$j]['colspan']) ? $table['cells'][$i][$j]['colspan'] : 1);
20259 
20260 							if ($colspan > 1) {
20261 								$w = 0;
20262 
20263 								for ($c = $j; $c < ($j + $colspan); $c++) {
20264 									$w += $widthcols[$c];
20265 								}
20266 
20267 								if ($w > $this->blk[$this->blklvl]['inner_width']) {
20268 									$diff = $w - ($this->blk[$this->blklvl]['inner_width'] - $tblbw);
20269 									for ($c = $j; $c < ($j + $colspan); $c++) {
20270 										$widthcols[$c] -= $diff * ($widthcols[$c] / $w);
20271 									}
20272 									$table['w'] -= $diff;
20273 									$table['csp'][$j] = $w - $diff;
20274 								}
20275 							}
20276 						}
20277 					}
20278 				}
20279 			}
20280 
20281 			$pgNo = 0;
20282 			$currWc = 0;
20283 
20284 			for ($i = 0; $i < $numcols; $i++) { // columns
20285 
20286 				if (isset($table['csp'][$i])) {
20287 					$w = $table['csp'][$i];
20288 					unset($table['csp'][$i]);
20289 				} else {
20290 					$w = $widthcols[$i];
20291 				}
20292 
20293 				if (($currWc + $w + $tblbw) > $this->blk[$this->blklvl]['inner_width']) {
20294 					$pgNo++;
20295 					$currWc = $widthcols[$i];
20296 				} else {
20297 					$currWc += $widthcols[$i];
20298 				}
20299 
20300 				$table['colPg'][$i] = $pgNo;
20301 			}
20302 		}
20303 	}
20304 
20305 	function _tableHeight(&$table)
20306 	{
20307 		$level = $table['level'];
20308 		$levelid = $table['levelid'];
20309 		$cells = &$table['cells'];
20310 		$numcols = $table['nc'];
20311 		$numrows = $table['nr'];
20312 		$listspan = [];
20313 		$checkmaxheight = 0;
20314 		$headerrowheight = 0;
20315 		$checkmaxheightplus = 0;
20316 		$headerrowheightplus = 0;
20317 		$firstrowheight = 0;
20318 
20319 		$footerrowheight = 0;
20320 		$footerrowheightplus = 0;
20321 		if ($this->table_rotate) {
20322 			$temppgheight = $this->tbrot_maxh;
20323 			$remainingpage = $this->tbrot_maxh;
20324 		} else {
20325 			$temppgheight = ($this->h - $this->bMargin - $this->tMargin) - $this->kwt_height;
20326 			$remainingpage = ($this->h - $this->bMargin - $this->y) - $this->kwt_height;
20327 
20328 			// If it is less than 1/20th of the remaining page height to finish the DIV (i.e. DIV padding + table bottom margin)
20329 			// then allow for this
20330 			$enddiv = $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w'] + $table['margin']['B'];
20331 			if ($remainingpage > $enddiv && $enddiv / $remainingpage < 0.05) {
20332 				$remainingpage -= $enddiv;
20333 			} elseif ($remainingpage == 0) {
20334 				$remainingpage = 0.001;
20335 			}
20336 			if ($temppgheight > $enddiv && $enddiv / $temppgheight < 0.05) {
20337 				$temppgheight -= $enddiv;
20338 			} elseif ($temppgheight == 0) {
20339 				$temppgheight = 0.001;
20340 			}
20341 		}
20342 		if ($remainingpage < 0) {
20343 			$remainingpage = 0.001;
20344 		}
20345 		if ($temppgheight < 0) {
20346 			$temppgheight = 0.001;
20347 		}
20348 
20349 		for ($i = 0; $i < $numrows; $i++) { // rows
20350 			$heightrow = &$table['hr'][$i];
20351 			for ($j = 0; $j < $numcols; $j++) { // columns
20352 				if (isset($cells[$i][$j]) && $cells[$i][$j]) {
20353 					$c = &$cells[$i][$j];
20354 
20355 					if ($this->simpleTables) {
20356 						if ($table['borders_separate']) { // NB twice border width
20357 							$extraWLR = ($table['simple']['border_details']['L']['w'] + $table['simple']['border_details']['R']['w']) + ($c['padding']['L'] + $c['padding']['R']) + $table['border_spacing_H'];
20358 							$extrh = ($table['simple']['border_details']['T']['w'] + $table['simple']['border_details']['B']['w']) + ($c['padding']['T'] + $c['padding']['B']) + $table['border_spacing_V'];
20359 						} else {
20360 							$extraWLR = ($table['simple']['border_details']['L']['w'] + $table['simple']['border_details']['R']['w']) / 2 + ($c['padding']['L'] + $c['padding']['R']);
20361 							$extrh = ($table['simple']['border_details']['T']['w'] + $table['simple']['border_details']['B']['w']) / 2 + ($c['padding']['T'] + $c['padding']['B']);
20362 						}
20363 					} else {
20364 						if ($this->packTableData) {
20365 							list($bt, $br, $bb, $bl) = $this->_getBorderWidths($c['borderbin']);
20366 						} else {
20367 							$bt = $c['border_details']['T']['w'];
20368 							$bb = $c['border_details']['B']['w'];
20369 							$br = $c['border_details']['R']['w'];
20370 							$bl = $c['border_details']['L']['w'];
20371 						}
20372 						if ($table['borders_separate']) { // NB twice border width
20373 							$extraWLR = $bl + $br + $c['padding']['L'] + $c['padding']['R'] + $table['border_spacing_H'];
20374 							$extrh = $bt + $bb + $c['padding']['T'] + $c['padding']['B'] + $table['border_spacing_V'];
20375 						} else {
20376 							$extraWLR = $bl / 2 + $br / 2 + $c['padding']['L'] + $c['padding']['R'];
20377 							$extrh = $bt / 2 + $bb / 2 + $c['padding']['T'] + $c['padding']['B'];
20378 						}
20379 					}
20380 
20381 					if ($table['overflow'] == 'visible' && $level == 1) {
20382 						list($x, $cw) = $this->_splitTableGetWidth($table, $i, $j);
20383 					} else {
20384 						list($x, $cw) = $this->_tableGetWidth($table, $i, $j);
20385 					}
20386 
20387 
20388 					// Get CELL HEIGHT
20389 					// ++ extra parameter forces wrap to break word
20390 					if ($c['R'] && isset($c['textbuffer'])) {
20391 						$str = '';
20392 						foreach ($c['textbuffer'] as $t) {
20393 							$str .= $t[0] . ' ';
20394 						}
20395 						$str = rtrim($str);
20396 						$s_fs = $this->FontSizePt;
20397 						$s_f = $this->FontFamily;
20398 						$s_st = $this->FontStyle;
20399 						$this->SetFont($c['textbuffer'][0][4], $c['textbuffer'][0][2], $c['textbuffer'][0][11] / $this->shrin_k, true, true);
20400 						$tempch = $this->GetStringWidth($str, true, $c['textbuffer'][0][18], $c['textbuffer'][0][8]);
20401 						if ($c['R'] >= 45 && $c['R'] < 90) {
20402 							$tempch = ((sin(deg2rad($c['R']))) * $tempch ) + ((sin(deg2rad($c['R']))) * (($c['textbuffer'][0][11] / Mpdf::SCALE) / $this->shrin_k));
20403 						}
20404 						$this->SetFont($s_f, $s_st, $s_fs, true, true);
20405 						$ch = ($tempch ) + $extrh;
20406 					} else {
20407 						if (isset($c['textbuffer']) && !empty($c['textbuffer'])) {
20408 							$this->cellLineHeight = $c['cellLineHeight'];
20409 							$this->cellLineStackingStrategy = $c['cellLineStackingStrategy'];
20410 							$this->cellLineStackingShift = $c['cellLineStackingShift'];
20411 							$this->divwidth = $cw - $extraWLR;
20412 							$tempch = $this->printbuffer($c['textbuffer'], '', true, true);
20413 						} else {
20414 							$tempch = 0;
20415 						}
20416 
20417 						// Added cellpadding top and bottom. (Lineheight already adjusted)
20418 						$ch = $tempch + $extrh;
20419 					}
20420 					// If height is defined and it is bigger than calculated $ch then update values
20421 					if (isset($c['h']) && $c['h'] > $ch) {
20422 						$c['mih'] = $ch; // in order to keep valign working
20423 						$ch = $c['h'];
20424 					} else {
20425 						$c['mih'] = $ch;
20426 					}
20427 					if (isset($c['rowspan'])) {
20428 						$listspan[] = [$i, $j];
20429 					} elseif ($heightrow < $ch) {
20430 						$heightrow = $ch;
20431 					}
20432 
20433 					// this is the extra used in _tableWrite to determine whether to trigger a page change
20434 					if ($table['borders_separate']) {
20435 						if ($i == ($numrows - 1) || (isset($c['rowspan']) && ($i + $c['rowspan']) == ($numrows))) {
20436 							$extra = $table['margin']['B'] + $table['padding']['B'] + $table['border_details']['B']['w'] + $table['border_spacing_V'] / 2;
20437 						} else {
20438 							$extra = $table['border_spacing_V'] / 2;
20439 						}
20440 					} else {
20441 						if (!$this->simpleTables) {
20442 							$extra = $bb / 2;
20443 						} elseif ($this->simpleTables) {
20444 							$extra = $table['simple']['border_details']['B']['w'] / 2;
20445 						}
20446 					}
20447 					if (isset($table['is_thead'][$i]) && $table['is_thead'][$i]) {
20448 						if ($j == 0) {
20449 							$headerrowheight += $ch;
20450 							$headerrowheightplus += $ch + $extra;
20451 						}
20452 					} elseif (isset($table['is_tfoot'][$i]) && $table['is_tfoot'][$i]) {
20453 						if ($j == 0) {
20454 							$footerrowheight += $ch;
20455 							$footerrowheightplus += $ch + $extra;
20456 						}
20457 					} else {
20458 						$checkmaxheight = max($checkmaxheight, $ch);
20459 						$checkmaxheightplus = max($checkmaxheightplus, $ch + $extra);
20460 					}
20461 					if ($this->tableLevel == 1 && $i == (isset($table['headernrows']) ? $table['headernrows'] : 0)) {
20462 						$firstrowheight = max($ch, $firstrowheight);
20463 					}
20464 					unset($c);
20465 				}
20466 			}//end of columns
20467 		}//end of rows
20468 
20469 		$heightrow = &$table['hr'];
20470 		foreach ($listspan as $span) {
20471 			list($i, $j) = $span;
20472 			$c = &$cells[$i][$j];
20473 			$lr = $i + $c['rowspan'];
20474 			if ($lr > $numrows) {
20475 				$lr = $numrows;
20476 			}
20477 			$hs = $hsa = 0;
20478 			$list = [];
20479 			for ($k = $i; $k < $lr; $k++) {
20480 				$hs += $heightrow[$k];
20481 				// mPDF 6
20482 				$sh = false; // specified height
20483 				for ($m = 0; $m < $numcols; $m++) { // columns
20484 					$tc = &$cells[$k][$m];
20485 					if (isset($tc['rowspan'])) {
20486 						continue;
20487 					}
20488 					if (isset($tc['h'])) {
20489 						$sh = true;
20490 						break;
20491 					}
20492 				}
20493 				if (!$sh) {
20494 					$list[] = $k;
20495 				}
20496 			}
20497 
20498 			if ($table['borders_separate']) {
20499 				if ($i == ($numrows - 1) || ($i + $c['rowspan']) == ($numrows)) {
20500 					$extra = $table['margin']['B'] + $table['padding']['B'] + $table['border_details']['B']['w'] + $table['border_spacing_V'] / 2;
20501 				} else {
20502 					$extra = $table['border_spacing_V'] / 2;
20503 				}
20504 			} else {
20505 				if (!$this->simpleTables) {
20506 					if ($this->packTableData) {
20507 						list($bt, $br, $bb, $bl) = $this->_getBorderWidths($c['borderbin']);
20508 					} else {
20509 						$bb = $c['border_details']['B']['w'];
20510 					}
20511 					$extra = $bb / 2;
20512 				} elseif ($this->simpleTables) {
20513 					$extra = $table['simple']['border_details']['B']['w'] / 2;
20514 				}
20515 			}
20516 			if (!empty($table['is_thead'][$i])) {
20517 				$headerrowheight = max($headerrowheight, $hs);
20518 				$headerrowheightplus = max($headerrowheightplus, $hs + $extra);
20519 			} elseif (!empty($table['is_tfoot'][$i])) {
20520 				$footerrowheight = max($footerrowheight, $hs);
20521 				$footerrowheightplus = max($footerrowheightplus, $hs + $extra);
20522 			} else {
20523 				$checkmaxheight = max($checkmaxheight, $hs);
20524 				$checkmaxheightplus = max($checkmaxheightplus, $hs + $extra);
20525 			}
20526 			if ($this->tableLevel == 1 && $i == (isset($table['headernrows']) ? $table['headernrows'] : 0)) {
20527 				$firstrowheight = max($hs, $firstrowheight);
20528 			}
20529 
20530 			if ($c['mih'] > $hs) {
20531 				if (!$hs) {
20532 					for ($k = $i; $k < $lr; $k++) {
20533 						$heightrow[$k] = $c['mih'] / $c['rowspan'];
20534 					}
20535 				} elseif (!count($list)) { // no rows in the rowspan have a height specified, so share amongst all rows equally
20536 					$hi = $c['mih'] - $hs;
20537 					for ($k = $i; $k < $lr; $k++) {
20538 						$heightrow[$k] += ($heightrow[$k] / $hs) * $hi;
20539 					}
20540 				} else {
20541 					$hi = $c['mih'] - $hs; // mPDF 6
20542 					foreach ($list as $k) {
20543 						$heightrow[$k] += $hi / (count($list)); // mPDF 6
20544 					}
20545 				}
20546 			}
20547 			unset($c);
20548 
20549 			// If rowspans overlap so that one or more rows do not have a height set...
20550 			// i.e. for one or more rows, the only cells (explicit) in that row have rowspan>1
20551 			// so heightrow is still == 0
20552 			if ($heightrow[$i] == 0) {
20553 				// Get row extent to analyse above and below
20554 				$top = $i;
20555 				foreach ($listspan as $checkspan) {
20556 					list($cki, $ckj) = $checkspan;
20557 					$c = &$cells[$cki][$ckj];
20558 					if (isset($c['rowspan']) && $c['rowspan'] > 1) {
20559 						if (($cki + $c['rowspan'] - 1) >= $i) {
20560 							$top = min($top, $cki);
20561 						}
20562 					}
20563 				}
20564 				$bottom = $i + $c['rowspan'] - 1;
20565 				// Check for overconstrained conditions
20566 				for ($k = $top; $k <= $bottom; $k++) {
20567 					// if ['hr'] for any of the others is also 0, then abort (too complicated)
20568 					if ($k != $i && $heightrow[$k] == 0) {
20569 						break(1);
20570 					}
20571 					// check again that top and bottom are not crossed by rowspans - or abort (too complicated)
20572 					if ($k == $top) {
20573 						// ???? take account of colspan as well???
20574 						for ($m = 0; $m < $numcols; $m++) { // columns
20575 							if (!isset($cells[$k][$m]) || $cells[$k][$m] == 0) {
20576 								break(2);
20577 							}
20578 						}
20579 					} elseif ($k == $bottom) {
20580 						// ???? take account of colspan as well???
20581 						for ($m = 0; $m < $numcols; $m++) { // columns
20582 							$c = &$cells[$k][$m];
20583 							if (isset($c['rowspan']) && $c['rowspan'] > 1) {
20584 								break(2);
20585 							}
20586 						}
20587 					}
20588 				}
20589 				// By columns add up col height using ['h'] if set or ['mih'] if not
20590 				// Intentionally do not substract border-spacing
20591 				$colH = [];
20592 				$extH = 0;
20593 				$newhr = [];
20594 				for ($m = 0; $m < $numcols; $m++) { // columns
20595 					for ($k = $top; $k <= $bottom; $k++) {
20596 						if (isset($cells[$k][$m]) && $cells[$k][$m] != 0) {
20597 							$c = &$cells[$k][$m];
20598 							if (isset($c['h']) && $c['h']) {
20599 								$useh = $c['h'];
20600 							} // ???? take account of colspan as well???
20601 							else {
20602 								$useh = $c['mih'];
20603 							}
20604 							if (isset($colH[$m])) {
20605 								$colH[$m] += $useh;
20606 							} else {
20607 								$colH[$m] = $useh;
20608 							}
20609 							if (!isset($c['rowspan']) || $c['rowspan'] < 2) {
20610 								$newhr[$k] = max((isset($newhr[$k]) ? $newhr[$k] : 0), $useh);
20611 							}
20612 						}
20613 					}
20614 					$extH = max($extH, $colH[$m]); // mPDF 6
20615 				}
20616 				$newhr[$i] = $extH - array_sum($newhr);
20617 				for ($k = $top; $k <= $bottom; $k++) {
20618 					$heightrow[$k] = $newhr[$k];
20619 				}
20620 			}
20621 
20622 
20623 			unset($c);
20624 		}
20625 
20626 		$table['h'] = array_sum($heightrow);
20627 		unset($heightrow);
20628 
20629 		if ($table['borders_separate']) {
20630 			$table['h'] += $table['margin']['T'] + $table['margin']['B'] + $table['border_details']['T']['w'] + $table['border_details']['B']['w'] + $table['border_spacing_V'] + $table['padding']['T'] + $table['padding']['B'];
20631 		} else {
20632 			$table['h'] += $table['margin']['T'] + $table['margin']['B'] + $table['max_cell_border_width']['T'] / 2 + $table['max_cell_border_width']['B'] / 2;
20633 		}
20634 
20635 		$maxrowheight = $checkmaxheightplus + $headerrowheightplus + $footerrowheightplus;
20636 		$maxfirstrowheight = $firstrowheight + $headerrowheightplus + $footerrowheightplus; // includes thead, 1st row and tfoot
20637 		return [$table['h'], $maxrowheight, $temppgheight, $remainingpage, $maxfirstrowheight];
20638 	}
20639 
20640 	function _tableGetWidth(&$table, $i, $j)
20641 	{
20642 		$cell = &$table['cells'][$i][$j];
20643 		if ($cell) {
20644 			if (isset($cell['x0'])) {
20645 				return [$cell['x0'], $cell['w0']];
20646 			}
20647 			$x = 0;
20648 			$widthcols = &$table['wc'];
20649 			for ($k = 0; $k < $j; $k++) {
20650 				$x += $widthcols[$k];
20651 			}
20652 			$w = $widthcols[$j];
20653 			if (isset($cell['colspan'])) {
20654 				for ($k = $j + $cell['colspan'] - 1; $k > $j; $k--) {
20655 					$w += $widthcols[$k];
20656 				}
20657 			}
20658 			$cell['x0'] = $x;
20659 			$cell['w0'] = $w;
20660 			return [$x, $w];
20661 		}
20662 		return [0, 0];
20663 	}
20664 
20665 	function _splitTableGetWidth(&$table, $i, $j)
20666 	{
20667 		$cell = &$table['cells'][$i][$j];
20668 		if ($cell) {
20669 			if (isset($cell['x0'])) {
20670 				return [$cell['x0'], $cell['w0']];
20671 			}
20672 			$x = 0;
20673 			$widthcols = &$table['wc'];
20674 			$pg = $table['colPg'][$j];
20675 			for ($k = 0; $k < $j; $k++) {
20676 				if ($table['colPg'][$k] == $pg) {
20677 					$x += $widthcols[$k];
20678 				}
20679 			}
20680 			$w = $widthcols[$j];
20681 			if (isset($cell['colspan'])) {
20682 				for ($k = $j + $cell['colspan'] - 1; $k > $j; $k--) {
20683 					if ($table['colPg'][$k] == $pg) {
20684 						$w += $widthcols[$k];
20685 					}
20686 				}
20687 			}
20688 			$cell['x0'] = $x;
20689 			$cell['w0'] = $w;
20690 			return [$x, $w];
20691 		}
20692 		return [0, 0];
20693 	}
20694 
20695 	function _tableGetHeight(&$table, $i, $j)
20696 	{
20697 		$cell = &$table['cells'][$i][$j];
20698 		if ($cell) {
20699 			if (isset($cell['y0'])) {
20700 				return [$cell['y0'], $cell['h0']];
20701 			}
20702 			$y = 0;
20703 			$heightrow = &$table['hr'];
20704 			for ($k = 0; $k < $i; $k++) {
20705 				$y += $heightrow[$k];
20706 			}
20707 			$h = $heightrow[$i];
20708 			if (isset($cell['rowspan'])) {
20709 				for ($k = $i + $cell['rowspan'] - 1; $k > $i; $k--) {
20710 					if (array_key_exists($k, $heightrow)) {
20711 						$h += $heightrow[$k];
20712 					} else {
20713 						$this->logger->debug('Possible non-wellformed HTML markup in a table', ['context' => LogContext::HTML_MARKUP]);
20714 					}
20715 				}
20716 			}
20717 			$cell['y0'] = $y;
20718 			$cell['h0'] = $h;
20719 			return [$y, $h];
20720 		}
20721 		return [0, 0];
20722 	}
20723 
20724 	function _tableGetMaxRowHeight($table, $row)
20725 	{
20726 		if ($row == $table['nc'] - 1) {
20727 			return $table['hr'][$row];
20728 		}
20729 		$maxrowheight = $table['hr'][$row];
20730 		for ($i = $row + 1; $i < $table['nr']; $i++) {
20731 			$cellsset = 0;
20732 			for ($j = 0; $j < $table['nc']; $j++) {
20733 				if ($table['cells'][$i][$j]) {
20734 					if (isset($table['cells'][$i][$j]['colspan'])) {
20735 						$cellsset += $table['cells'][$i][$j]['colspan'];
20736 					} else {
20737 						$cellsset += 1;
20738 					}
20739 				}
20740 			}
20741 			if ($cellsset == $table['nc']) {
20742 				return $maxrowheight;
20743 			} else {
20744 				$maxrowheight += $table['hr'][$i];
20745 			}
20746 		}
20747 		return $maxrowheight;
20748 	}
20749 
20750 	// CHANGED TO ALLOW TABLE BORDER TO BE SPECIFIED CORRECTLY - added border_details
20751 	function _tableRect($x, $y, $w, $h, $bord = -1, $details = [], $buffer = false, $bSeparate = false, $cort = 'cell', $tablecorner = '', $bsv = 0, $bsh = 0)
20752 	{
20753 		$cellBorderOverlay = [];
20754 
20755 		if ($bord == -1) {
20756 			$this->Rect($x, $y, $w, $h);
20757 		} elseif ($this->simpleTables && ($cort == 'cell')) {
20758 			$this->SetLineWidth($details['L']['w']);
20759 			if ($details['L']['c']) {
20760 				$this->SetDColor($details['L']['c']);
20761 			} else {
20762 				$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
20763 			}
20764 			$this->SetLineJoin(0);
20765 			$this->Rect($x, $y, $w, $h);
20766 		} elseif ($bord) {
20767 			if (!$bSeparate && $buffer) {
20768 				$priority = 'LRTB';
20769 				for ($p = 0; $p < strlen($priority); $p++) {
20770 					$side = $priority[$p];
20771 					$details['p'] = $side;
20772 
20773 					$dom = 0;
20774 					if (isset($details[$side]['w'])) {
20775 						$dom += ($details[$side]['w'] * 100000);
20776 					}
20777 					if (isset($details[$side]['style'])) {
20778 						$dom += (array_search($details[$side]['style'], $this->borderstyles) * 100);
20779 					}
20780 					if (isset($details[$side]['dom'])) {
20781 						$dom += ($details[$side]['dom'] * 10);
20782 					}
20783 
20784 					// Precedence to darker colours at joins
20785 					$coldom = 0;
20786 					if (isset($details[$side]['c']) && is_array($details[$side]['c'])) {
20787 						if ($details[$side]['c'][0] == 3) {  // RGB
20788 							$coldom = 10 - (((ord($details[$side]['c'][1]) * 1.00) + (ord($details[$side]['c'][2]) * 1.00) + (ord($details[$side]['c'][3]) * 1.00)) / 76.5);
20789 						}
20790 					} // 10 black - 0 white
20791 					if ($coldom) {
20792 						$dom += $coldom;
20793 					}
20794 					// Lastly precedence to RIGHT and BOTTOM cells at joins
20795 					if (isset($details['cellposdom'])) {
20796 						$dom += $details['cellposdom'];
20797 					}
20798 
20799 					$save = false;
20800 					if ($side == 'T' && $this->issetBorder($bord, Border::TOP)) {
20801 						$cbord = Border::TOP;
20802 						$save = true;
20803 					} elseif ($side == 'L' && $this->issetBorder($bord, Border::LEFT)) {
20804 						$cbord = Border::LEFT;
20805 						$save = true;
20806 					} elseif ($side == 'R' && $this->issetBorder($bord, Border::RIGHT)) {
20807 						$cbord = Border::RIGHT;
20808 						$save = true;
20809 					} elseif ($side == 'B' && $this->issetBorder($bord, Border::BOTTOM)) {
20810 						$cbord = Border::BOTTOM;
20811 						$save = true;
20812 					}
20813 
20814 					if ($save) {
20815 						$this->cellBorderBuffer[] = pack("A16nCnda6A10d14", str_pad(sprintf("%08.7f", $dom), 16, "0", STR_PAD_LEFT), $cbord, ord($side), $details[$side]['s'], $details[$side]['w'], $details[$side]['c'], $details[$side]['style'], $x, $y, $w, $h, $details['mbw']['BL'], $details['mbw']['BR'], $details['mbw']['RT'], $details['mbw']['RB'], $details['mbw']['TL'], $details['mbw']['TR'], $details['mbw']['LT'], $details['mbw']['LB'], $details['cellposdom'], 0);
20816 						if ($details[$side]['style'] == 'ridge' || $details[$side]['style'] == 'groove' || $details[$side]['style'] == 'inset' || $details[$side]['style'] == 'outset' || $details[$side]['style'] == 'double') {
20817 							$details[$side]['overlay'] = true;
20818 							$this->cellBorderBuffer[] = pack("A16nCnda6A10d14", str_pad(sprintf("%08.7f", ($dom + 4)), 16, "0", STR_PAD_LEFT), $cbord, ord($side), $details[$side]['s'], $details[$side]['w'], $details[$side]['c'], $details[$side]['style'], $x, $y, $w, $h, $details['mbw']['BL'], $details['mbw']['BR'], $details['mbw']['RT'], $details['mbw']['RB'], $details['mbw']['TL'], $details['mbw']['TR'], $details['mbw']['LT'], $details['mbw']['LB'], $details['cellposdom'], 1);
20819 						}
20820 					}
20821 				}
20822 				return;
20823 			}
20824 
20825 			if (isset($details['p']) && strlen($details['p']) > 1) {
20826 				$priority = $details['p'];
20827 			} else {
20828 				$priority = 'LTRB';
20829 			}
20830 			$Tw = 0;
20831 			$Rw = 0;
20832 			$Bw = 0;
20833 			$Lw = 0;
20834 			if (isset($details['T']['w'])) {
20835 				$Tw = $details['T']['w'];
20836 			}
20837 			if (isset($details['R']['w'])) {
20838 				$Rw = $details['R']['w'];
20839 			}
20840 			if (isset($details['B']['w'])) {
20841 				$Bw = $details['B']['w'];
20842 			}
20843 			if (isset($details['L']['w'])) {
20844 				$Lw = $details['L']['w'];
20845 			}
20846 
20847 			$x2 = $x + $w;
20848 			$y2 = $y + $h;
20849 			$oldlinewidth = $this->LineWidth;
20850 
20851 			for ($p = 0; $p < strlen($priority); $p++) {
20852 				$side = $priority[$p];
20853 				$xadj = 0;
20854 				$xadj2 = 0;
20855 				$yadj = 0;
20856 				$yadj2 = 0;
20857 				$print = false;
20858 				if ($Tw && $side == 'T' && $this->issetBorder($bord, Border::TOP)) { // TOP
20859 					$ly1 = $y;
20860 					$ly2 = $y;
20861 					$lx1 = $x;
20862 					$lx2 = $x2;
20863 					$this->SetLineWidth($Tw);
20864 					if ($cort == 'cell' || strpos($tablecorner, 'L') !== false) {
20865 						if ($Tw > $Lw) {
20866 							$xadj = ($Tw - $Lw) / 2;
20867 						}
20868 						if ($Tw < $Lw) {
20869 							$xadj = ($Tw + $Lw) / 2;
20870 						}
20871 					} else {
20872 						$xadj = $Tw / 2 - $bsh / 2;
20873 					}
20874 					if ($cort == 'cell' || strpos($tablecorner, 'R') !== false) {
20875 						if ($Tw > $Rw) {
20876 							$xadj2 = ($Tw - $Rw) / 2;
20877 						}
20878 						if ($Tw < $Rw) {
20879 							$xadj2 = ($Tw + $Rw) / 2;
20880 						}
20881 					} else {
20882 						$xadj2 = $Tw / 2 - $bsh / 2;
20883 					}
20884 					if (!$bSeparate && !empty($details['mbw']) && !empty($details['mbw']['TL'])) {
20885 						$xadj = ($Tw - $details['mbw']['TL']) / 2;
20886 					}
20887 					if (!$bSeparate && !empty($details['mbw']) && !empty($details['mbw']['TR'])) {
20888 						$xadj2 = ($Tw - $details['mbw']['TR']) / 2;
20889 					}
20890 					$print = true;
20891 				}
20892 				if ($Lw && $side == 'L' && $this->issetBorder($bord, Border::LEFT)) { // LEFT
20893 					$ly1 = $y;
20894 					$ly2 = $y2;
20895 					$lx1 = $x;
20896 					$lx2 = $x;
20897 					$this->SetLineWidth($Lw);
20898 					if ($cort == 'cell' || strpos($tablecorner, 'T') !== false) {
20899 						if ($Lw > $Tw) {
20900 							$yadj = ($Lw - $Tw) / 2;
20901 						}
20902 						if ($Lw < $Tw) {
20903 							$yadj = ($Lw + $Tw) / 2;
20904 						}
20905 					} else {
20906 						$yadj = $Lw / 2 - $bsv / 2;
20907 					}
20908 					if ($cort == 'cell' || strpos($tablecorner, 'B') !== false) {
20909 						if ($Lw > $Bw) {
20910 							$yadj2 = ($Lw - $Bw) / 2;
20911 						}
20912 						if ($Lw < $Bw) {
20913 							$yadj2 = ($Lw + $Bw) / 2;
20914 						}
20915 					} else {
20916 						$yadj2 = $Lw / 2 - $bsv / 2;
20917 					}
20918 					if (!$bSeparate && $details['mbw']['LT']) {
20919 						$yadj = ($Lw - $details['mbw']['LT']) / 2;
20920 					}
20921 					if (!$bSeparate && $details['mbw']['LB']) {
20922 						$yadj2 = ($Lw - $details['mbw']['LB']) / 2;
20923 					}
20924 					$print = true;
20925 				}
20926 				if ($Rw && $side == 'R' && $this->issetBorder($bord, Border::RIGHT)) { // RIGHT
20927 					$ly1 = $y;
20928 					$ly2 = $y2;
20929 					$lx1 = $x2;
20930 					$lx2 = $x2;
20931 					$this->SetLineWidth($Rw);
20932 					if ($cort == 'cell' || strpos($tablecorner, 'T') !== false) {
20933 						if ($Rw < $Tw) {
20934 							$yadj = ($Rw + $Tw) / 2;
20935 						}
20936 						if ($Rw > $Tw) {
20937 							$yadj = ($Rw - $Tw) / 2;
20938 						}
20939 					} else {
20940 						$yadj = $Rw / 2 - $bsv / 2;
20941 					}
20942 
20943 					if ($cort == 'cell' || strpos($tablecorner, 'B') !== false) {
20944 						if ($Rw > $Bw) {
20945 							$yadj2 = ($Rw - $Bw) / 2;
20946 						}
20947 						if ($Rw < $Bw) {
20948 							$yadj2 = ($Rw + $Bw) / 2;
20949 						}
20950 					} else {
20951 						$yadj2 = $Rw / 2 - $bsv / 2;
20952 					}
20953 
20954 					if (!$bSeparate && !empty($details['mbw']) && !empty($details['mbw']['RT'])) {
20955 						$yadj = ($Rw - $details['mbw']['RT']) / 2;
20956 					}
20957 					if (!$bSeparate && !empty($details['mbw']) && !empty($details['mbw']['RB'])) {
20958 						$yadj2 = ($Rw - $details['mbw']['RB']) / 2;
20959 					}
20960 					$print = true;
20961 				}
20962 				if ($Bw && $side == 'B' && $this->issetBorder($bord, Border::BOTTOM)) { // BOTTOM
20963 					$ly1 = $y2;
20964 					$ly2 = $y2;
20965 					$lx1 = $x;
20966 					$lx2 = $x2;
20967 					$this->SetLineWidth($Bw);
20968 					if ($cort == 'cell' || strpos($tablecorner, 'L') !== false) {
20969 						if ($Bw > $Lw) {
20970 							$xadj = ($Bw - $Lw) / 2;
20971 						}
20972 						if ($Bw < $Lw) {
20973 							$xadj = ($Bw + $Lw) / 2;
20974 						}
20975 					} else {
20976 						$xadj = $Bw / 2 - $bsh / 2;
20977 					}
20978 					if ($cort == 'cell' || strpos($tablecorner, 'R') !== false) {
20979 						if ($Bw > $Rw) {
20980 							$xadj2 = ($Bw - $Rw) / 2;
20981 						}
20982 						if ($Bw < $Rw) {
20983 							$xadj2 = ($Bw + $Rw) / 2;
20984 						}
20985 					} else {
20986 						$xadj2 = $Bw / 2 - $bsh / 2;
20987 					}
20988 					if (!$bSeparate && isset($details['mbw']) && isset($details['mbw']['BL'])) {
20989 						$xadj = ($Bw - $details['mbw']['BL']) / 2;
20990 					}
20991 					if (!$bSeparate && isset($details['mbw']) && isset($details['mbw']['BR'])) {
20992 						$xadj2 = ($Bw - $details['mbw']['BR']) / 2;
20993 					}
20994 					$print = true;
20995 				}
20996 
20997 				// Now draw line
20998 				if ($print) {
20999 					/* -- TABLES-ADVANCED-BORDERS -- */
21000 					if ($details[$side]['style'] == 'double') {
21001 						if (!isset($details[$side]['overlay']) || !$details[$side]['overlay'] || $bSeparate) {
21002 							if ($details[$side]['c']) {
21003 								$this->SetDColor($details[$side]['c']);
21004 							} else {
21005 								$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
21006 							}
21007 							$this->Line($lx1 + $xadj, $ly1 + $yadj, $lx2 - $xadj2, $ly2 - $yadj2);
21008 						}
21009 						if ((isset($details[$side]['overlay']) && $details[$side]['overlay']) || $bSeparate) {
21010 							if ($bSeparate && $cort == 'table') {
21011 								if ($side == 'T') {
21012 									$xadj -= $this->LineWidth / 2;
21013 									$xadj2 -= $this->LineWidth;
21014 									if ($this->issetBorder($bord, Border::LEFT)) {
21015 										$xadj += $this->LineWidth / 2;
21016 									}
21017 									if ($this->issetBorder($bord, Border::RIGHT)) {
21018 										$xadj2 += $this->LineWidth;
21019 									}
21020 								}
21021 								if ($side == 'L') {
21022 									$yadj -= $this->LineWidth / 2;
21023 									$yadj2 -= $this->LineWidth;
21024 									if ($this->issetBorder($bord, Border::TOP)) {
21025 										$yadj += $this->LineWidth / 2;
21026 									}
21027 									if ($this->issetBorder($bord, Border::BOTTOM)) {
21028 										$yadj2 += $this->LineWidth;
21029 									}
21030 								}
21031 								if ($side == 'B') {
21032 									$xadj -= $this->LineWidth / 2;
21033 									$xadj2 -= $this->LineWidth;
21034 									if ($this->issetBorder($bord, Border::LEFT)) {
21035 										$xadj += $this->LineWidth / 2;
21036 									}
21037 									if ($this->issetBorder($bord, Border::RIGHT)) {
21038 										$xadj2 += $this->LineWidth;
21039 									}
21040 								}
21041 								if ($side == 'R') {
21042 									$yadj -= $this->LineWidth / 2;
21043 									$yadj2 -= $this->LineWidth;
21044 									if ($this->issetBorder($bord, Border::TOP)) {
21045 										$yadj += $this->LineWidth / 2;
21046 									}
21047 									if ($this->issetBorder($bord, Border::BOTTOM)) {
21048 										$yadj2 += $this->LineWidth;
21049 									}
21050 								}
21051 							}
21052 
21053 							$this->SetLineWidth($this->LineWidth / 3);
21054 
21055 							$tbcol = $this->colorConverter->convert(255, $this->PDFAXwarnings);
21056 							for ($l = 0; $l <= $this->blklvl; $l++) {
21057 								if ($this->blk[$l]['bgcolor']) {
21058 									$tbcol = ($this->blk[$l]['bgcolorarray']);
21059 								}
21060 							}
21061 
21062 							if ($bSeparate) {
21063 								$cellBorderOverlay[] = [
21064 									'x' => $lx1 + $xadj,
21065 									'y' => $ly1 + $yadj,
21066 									'x2' => $lx2 - $xadj2,
21067 									'y2' => $ly2 - $yadj2,
21068 									'col' => $tbcol,
21069 									'lw' => $this->LineWidth,
21070 								];
21071 							} else {
21072 								$this->SetDColor($tbcol);
21073 								$this->Line($lx1 + $xadj, $ly1 + $yadj, $lx2 - $xadj2, $ly2 - $yadj2);
21074 							}
21075 						}
21076 					} elseif (isset($details[$side]['style']) && ($details[$side]['style'] == 'ridge' || $details[$side]['style'] == 'groove' || $details[$side]['style'] == 'inset' || $details[$side]['style'] == 'outset')) {
21077 						if (!isset($details[$side]['overlay']) || !$details[$side]['overlay'] || $bSeparate) {
21078 							if ($details[$side]['c']) {
21079 								$this->SetDColor($details[$side]['c']);
21080 							} else {
21081 								$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
21082 							}
21083 							if ($details[$side]['style'] == 'outset' || $details[$side]['style'] == 'groove') {
21084 								$nc = $this->colorConverter->darken($details[$side]['c']);
21085 								$this->SetDColor($nc);
21086 							} elseif ($details[$side]['style'] == 'ridge' || $details[$side]['style'] == 'inset') {
21087 								$nc = $this->colorConverter->lighten($details[$side]['c']);
21088 								$this->SetDColor($nc);
21089 							}
21090 							$this->Line($lx1 + $xadj, $ly1 + $yadj, $lx2 - $xadj2, $ly2 - $yadj2);
21091 						}
21092 						if ((isset($details[$side]['overlay']) && $details[$side]['overlay']) || $bSeparate) {
21093 							if ($details[$side]['c']) {
21094 								$this->SetDColor($details[$side]['c']);
21095 							} else {
21096 								$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
21097 							}
21098 							$doubleadj = ($this->LineWidth) / 3;
21099 							$this->SetLineWidth($this->LineWidth / 2);
21100 							$xadj3 = $yadj3 = $wadj3 = $hadj3 = 0;
21101 
21102 							if ($details[$side]['style'] == 'ridge' || $details[$side]['style'] == 'inset') {
21103 								$nc = $this->colorConverter->darken($details[$side]['c']);
21104 
21105 								if ($bSeparate && $cort == 'table') {
21106 									if ($side == 'T') {
21107 										$yadj3 = $this->LineWidth / 2;
21108 										$xadj3 = -$this->LineWidth / 2;
21109 										$wadj3 = $this->LineWidth;
21110 										if ($this->issetBorder($bord, Border::LEFT)) {
21111 											$xadj3 += $this->LineWidth;
21112 											$wadj3 -= $this->LineWidth;
21113 										}
21114 										if ($this->issetBorder($bord, Border::RIGHT)) {
21115 											$wadj3 -= $this->LineWidth * 2;
21116 										}
21117 									}
21118 									if ($side == 'L') {
21119 										$xadj3 = $this->LineWidth / 2;
21120 										$yadj3 = -$this->LineWidth / 2;
21121 										$hadj3 = $this->LineWidth;
21122 										if ($this->issetBorder($bord, Border::TOP)) {
21123 											$yadj3 += $this->LineWidth;
21124 											$hadj3 -= $this->LineWidth;
21125 										}
21126 										if ($this->issetBorder($bord, Border::BOTTOM)) {
21127 											$hadj3 -= $this->LineWidth * 2;
21128 										}
21129 									}
21130 									if ($side == 'B') {
21131 										$yadj3 = $this->LineWidth / 2;
21132 										$xadj3 = -$this->LineWidth / 2;
21133 										$wadj3 = $this->LineWidth;
21134 									}
21135 									if ($side == 'R') {
21136 										$xadj3 = $this->LineWidth / 2;
21137 										$yadj3 = -$this->LineWidth / 2;
21138 										$hadj3 = $this->LineWidth;
21139 									}
21140 								} elseif ($side == 'T') {
21141 									$yadj3 = $this->LineWidth / 2;
21142 									$xadj3 = $this->LineWidth / 2;
21143 									$wadj3 = -$this->LineWidth * 2;
21144 								} elseif ($side == 'L') {
21145 									$xadj3 = $this->LineWidth / 2;
21146 									$yadj3 = $this->LineWidth / 2;
21147 									$hadj3 = -$this->LineWidth * 2;
21148 								} elseif ($side == 'B' && $bSeparate) {
21149 									$yadj3 = $this->LineWidth / 2;
21150 									$wadj3 = $this->LineWidth / 2;
21151 								} elseif ($side == 'R' && $bSeparate) {
21152 									$xadj3 = $this->LineWidth / 2;
21153 									$hadj3 = $this->LineWidth / 2;
21154 								} elseif ($side == 'B') {
21155 									$yadj3 = $this->LineWidth / 2;
21156 									$xadj3 = $this->LineWidth / 2;
21157 								} elseif ($side == 'R') {
21158 									$xadj3 = $this->LineWidth / 2;
21159 									$yadj3 = $this->LineWidth / 2;
21160 								}
21161 							} else {
21162 								$nc = $this->colorConverter->lighten($details[$side]['c']);
21163 
21164 								if ($bSeparate && $cort == 'table') {
21165 									if ($side == 'T') {
21166 										$yadj3 = $this->LineWidth / 2;
21167 										$xadj3 = -$this->LineWidth / 2;
21168 										$wadj3 = $this->LineWidth;
21169 										if ($this->issetBorder($bord, Border::LEFT)) {
21170 											$xadj3 += $this->LineWidth;
21171 											$wadj3 -= $this->LineWidth;
21172 										}
21173 									}
21174 									if ($side == 'L') {
21175 										$xadj3 = $this->LineWidth / 2;
21176 										$yadj3 = -$this->LineWidth / 2;
21177 										$hadj3 = $this->LineWidth;
21178 										if ($this->issetBorder($bord, Border::TOP)) {
21179 											$yadj3 += $this->LineWidth;
21180 											$hadj3 -= $this->LineWidth;
21181 										}
21182 									}
21183 									if ($side == 'B') {
21184 										$yadj3 = $this->LineWidth / 2;
21185 										$xadj3 = -$this->LineWidth / 2;
21186 										$wadj3 = $this->LineWidth;
21187 										if ($this->issetBorder($bord, Border::LEFT)) {
21188 											$xadj3 += $this->LineWidth;
21189 											$wadj3 -= $this->LineWidth;
21190 										}
21191 									}
21192 									if ($side == 'R') {
21193 										$xadj3 = $this->LineWidth / 2;
21194 										$yadj3 = -$this->LineWidth / 2;
21195 										$hadj3 = $this->LineWidth;
21196 										if ($this->issetBorder($bord, Border::TOP)) {
21197 											$yadj3 += $this->LineWidth;
21198 											$hadj3 -= $this->LineWidth;
21199 										}
21200 									}
21201 								} elseif ($side == 'T') {
21202 									$yadj3 = $this->LineWidth / 2;
21203 									$xadj3 = $this->LineWidth / 2;
21204 								} elseif ($side == 'L') {
21205 									$xadj3 = $this->LineWidth / 2;
21206 									$yadj3 = $this->LineWidth / 2;
21207 								} elseif ($side == 'B' && $bSeparate) {
21208 									$yadj3 = $this->LineWidth / 2;
21209 									$xadj3 = $this->LineWidth / 2;
21210 								} elseif ($side == 'R' && $bSeparate) {
21211 									$xadj3 = $this->LineWidth / 2;
21212 									$yadj3 = $this->LineWidth / 2;
21213 								} elseif ($side == 'B') {
21214 									$yadj3 = $this->LineWidth / 2;
21215 									$xadj3 = -$this->LineWidth / 2;
21216 									$wadj3 = $this->LineWidth;
21217 								} elseif ($side == 'R') {
21218 									$xadj3 = $this->LineWidth / 2;
21219 									$yadj3 = -$this->LineWidth / 2;
21220 									$hadj3 = $this->LineWidth;
21221 								}
21222 							}
21223 
21224 							if ($bSeparate) {
21225 								$cellBorderOverlay[] = [
21226 									'x' => $lx1 + $xadj + $xadj3,
21227 									'y' => $ly1 + $yadj + $yadj3,
21228 									'x2' => $lx2 - $xadj2 + $xadj3 + $wadj3,
21229 									'y2' => $ly2 - $yadj2 + $yadj3 + $hadj3,
21230 									'col' => $nc,
21231 									'lw' => $this->LineWidth,
21232 								];
21233 							} else {
21234 								$this->SetDColor($nc);
21235 								$this->Line($lx1 + $xadj + $xadj3, $ly1 + $yadj + $yadj3, $lx2 - $xadj2 + $xadj3 + $wadj3, $ly2 - $yadj2 + $yadj3 + $hadj3);
21236 							}
21237 						}
21238 					} else {
21239 						/* -- END TABLES-ADVANCED-BORDERS -- */
21240 						if ($details[$side]['style'] == 'dashed') {
21241 							$dashsize = 2; // final dash will be this + 1*linewidth
21242 							$dashsizek = 1.5; // ratio of Dash/Blank
21243 							$this->SetDash($dashsize, ($dashsize / $dashsizek) + ($this->LineWidth * 2));
21244 						} elseif ($details[$side]['style'] == 'dotted') {
21245 							$this->SetLineJoin(1);
21246 							$this->SetLineCap(1);
21247 							$this->SetDash(0.001, ($this->LineWidth * 2));
21248 						}
21249 						if ($details[$side]['c']) {
21250 							$this->SetDColor($details[$side]['c']);
21251 						} else {
21252 							$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
21253 						}
21254 						$this->Line($lx1 + $xadj, $ly1 + $yadj, $lx2 - $xadj2, $ly2 - $yadj2);
21255 						/* -- TABLES-ADVANCED-BORDERS -- */
21256 					}
21257 					/* -- END TABLES-ADVANCED-BORDERS -- */
21258 
21259 					// Reset Corners
21260 					$this->SetDash();
21261 					// BUTT style line cap
21262 					$this->SetLineCap(2);
21263 				}
21264 			}
21265 
21266 			if ($bSeparate && count($cellBorderOverlay)) {
21267 				foreach ($cellBorderOverlay as $cbo) {
21268 					$this->SetLineWidth($cbo['lw']);
21269 					$this->SetDColor($cbo['col']);
21270 					$this->Line($cbo['x'], $cbo['y'], $cbo['x2'], $cbo['y2']);
21271 				}
21272 			}
21273 
21274 			// $this->SetLineWidth($oldlinewidth);
21275 			// $this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
21276 		}
21277 	}
21278 
21279 	/* -- TABLES -- */
21280 	/* -- TABLES-ADVANCED-BORDERS -- */
21281 
21282 	/* -- END TABLES-ADVANCED-BORDERS -- */
21283 
21284 	function setBorder(&$var, $flag, $set = true)
21285 	{
21286 		$flag = intval($flag);
21287 		if ($set) {
21288 			$set = true;
21289 		}
21290 		$var = intval($var);
21291 		$var = $set ? ($var | $flag) : ($var & ~$flag);
21292 	}
21293 
21294 	function issetBorder($var, $flag)
21295 	{
21296 		$flag = intval($flag);
21297 		$var = intval($var);
21298 		return (($var & $flag) == $flag);
21299 	}
21300 
21301 	function _table2cellBorder(&$tableb, &$cbdb, &$cellb, $bval)
21302 	{
21303 		if ($tableb && $tableb['w'] > $cbdb['w']) {
21304 			$cbdb = $tableb;
21305 			$this->setBorder($cellb, $bval);
21306 		} elseif ($tableb && $tableb['w'] == $cbdb['w'] && array_search($tableb['style'], $this->borderstyles) > array_search($cbdb['style'], $this->borderstyles)) {
21307 			$cbdb = $tableb;
21308 			$this->setBorder($cellb, $bval);
21309 		}
21310 	}
21311 
21312 	// FIX BORDERS ********************************************
21313 	function _fixTableBorders(&$table)
21314 	{
21315 		if (!$table['borders_separate'] && $table['border_details']['L']['w']) {
21316 			$table['max_cell_border_width']['L'] = $table['border_details']['L']['w'];
21317 		}
21318 		if (!$table['borders_separate'] && $table['border_details']['R']['w']) {
21319 			$table['max_cell_border_width']['R'] = $table['border_details']['R']['w'];
21320 		}
21321 		if (!$table['borders_separate'] && $table['border_details']['T']['w']) {
21322 			$table['max_cell_border_width']['T'] = $table['border_details']['T']['w'];
21323 		}
21324 		if (!$table['borders_separate'] && $table['border_details']['B']['w']) {
21325 			$table['max_cell_border_width']['B'] = $table['border_details']['B']['w'];
21326 		}
21327 		if ($this->simpleTables) {
21328 			return;
21329 		}
21330 		$cells = &$table['cells'];
21331 		$numcols = $table['nc'];
21332 		$numrows = $table['nr'];
21333 		/* -- TABLES-ADVANCED-BORDERS -- */
21334 		if (isset($table['topntail']) && $table['topntail']) {
21335 			$tntborddet = $this->border_details($table['topntail']);
21336 		}
21337 		if (isset($table['thead-underline']) && $table['thead-underline']) {
21338 			$thuborddet = $this->border_details($table['thead-underline']);
21339 		}
21340 		/* -- END TABLES-ADVANCED-BORDERS -- */
21341 
21342 		for ($i = 0; $i < $numrows; $i++) { // Rows
21343 			for ($j = 0; $j < $numcols; $j++) { // Columns
21344 				if (isset($cells[$i][$j]) && $cells[$i][$j]) {
21345 					$cell = &$cells[$i][$j];
21346 					if ($this->packTableData) {
21347 						$cbord = $this->_unpackCellBorder($cell['borderbin']);
21348 					} else {
21349 						$cbord = &$cells[$i][$j];
21350 					}
21351 
21352 					// mPDF 5.7.3
21353 					if (!$cbord['border'] && $cbord['border'] !== 0 && isset($table['border']) && $table['border'] && $this->table_border_attr_set) {
21354 						$cbord['border'] = $table['border'];
21355 						$cbord['border_details'] = $table['border_details'];
21356 					}
21357 
21358 					if (isset($cell['colspan']) && $cell['colspan'] > 1) {
21359 						$ccolsp = $cell['colspan'];
21360 					} else {
21361 						$ccolsp = 1;
21362 					}
21363 					if (isset($cell['rowspan']) && $cell['rowspan'] > 1) {
21364 						$crowsp = $cell['rowspan'];
21365 					} else {
21366 						$crowsp = 1;
21367 					}
21368 
21369 					$cbord['border_details']['cellposdom'] = ((($i + 1) / $numrows) / 10000 ) + ((($j + 1) / $numcols) / 10 );
21370 					// Inherit Cell border from Table border
21371 					if ($this->table_border_css_set && !$table['borders_separate']) {
21372 						if ($i == 0) {
21373 							$this->_table2cellBorder($table['border_details']['T'], $cbord['border_details']['T'], $cbord['border'], Border::TOP);
21374 						}
21375 						if ($i == ($numrows - 1) || ($i + $crowsp) == ($numrows)) {
21376 							$this->_table2cellBorder($table['border_details']['B'], $cbord['border_details']['B'], $cbord['border'], Border::BOTTOM);
21377 						}
21378 						if ($j == 0) {
21379 							$this->_table2cellBorder($table['border_details']['L'], $cbord['border_details']['L'], $cbord['border'], Border::LEFT);
21380 						}
21381 						if ($j == ($numcols - 1) || ($j + $ccolsp) == ($numcols)) {
21382 							$this->_table2cellBorder($table['border_details']['R'], $cbord['border_details']['R'], $cbord['border'], Border::RIGHT);
21383 						}
21384 					}
21385 
21386 					/* -- TABLES-ADVANCED-BORDERS -- */
21387 					$fixbottom = true;
21388 					if (isset($table['topntail']) && $table['topntail']) {
21389 						if ($i == 0) {
21390 							$cbord['border_details']['T'] = $tntborddet;
21391 							$this->setBorder($cbord['border'], Border::TOP);
21392 						}
21393 						if ($this->tableLevel == 1 && $table['headernrows'] > 0 && $i == $table['headernrows'] - 1) {
21394 							$cbord['border_details']['B'] = $tntborddet;
21395 							$this->setBorder($cbord['border'], Border::BOTTOM);
21396 							$fixbottom = false;
21397 						} elseif ($this->tableLevel == 1 && $table['headernrows'] > 0 && $i == $table['headernrows']) {
21398 							if (!$table['borders_separate']) {
21399 								$cbord['border_details']['T'] = $tntborddet;
21400 								$this->setBorder($cbord['border'], Border::TOP);
21401 							}
21402 						}
21403 						if ($this->tableLevel == 1 && $table['footernrows'] > 0 && $i == ($numrows - $table['footernrows'] - 1)) {
21404 							if (!$table['borders_separate']) {
21405 								$cbord['border_details']['B'] = $tntborddet;
21406 								$this->setBorder($cbord['border'], Border::BOTTOM);
21407 								$fixbottom = false;
21408 							}
21409 						} elseif ($this->tableLevel == 1 && $table['footernrows'] > 0 && $i == ($numrows - $table['footernrows'])) {
21410 							$cbord['border_details']['T'] = $tntborddet;
21411 							$this->setBorder($cbord['border'], Border::TOP);
21412 						}
21413 						if ($this->tabletheadjustfinished) { // $this->tabletheadjustfinished called from tableheader
21414 							if (!$table['borders_separate']) {
21415 								$cbord['border_details']['T'] = $tntborddet;
21416 								$this->setBorder($cbord['border'], Border::TOP);
21417 							}
21418 						}
21419 						if ($i == ($numrows - 1) || ($i + $crowsp) == ($numrows)) {
21420 							$cbord['border_details']['B'] = $tntborddet;
21421 							$this->setBorder($cbord['border'], Border::BOTTOM);
21422 						}
21423 					}
21424 					if (isset($table['thead-underline']) && $table['thead-underline']) {
21425 						if ($table['borders_separate']) {
21426 							if ($i == 0) {
21427 								$cbord['border_details']['B'] = $thuborddet;
21428 								$this->setBorder($cbord['border'], Border::BOTTOM);
21429 								$fixbottom = false;
21430 							}
21431 						} else {
21432 							if ($this->tableLevel == 1 && $table['headernrows'] > 0 && $i == $table['headernrows'] - 1) {
21433 								$cbord['border_details']['T'] = $thuborddet;
21434 								$this->setBorder($cbord['border'], Border::TOP);
21435 							} elseif ($this->tabletheadjustfinished) { // $this->tabletheadjustfinished called from tableheader
21436 								$cbord['border_details']['T'] = $thuborddet;
21437 								$this->setBorder($cbord['border'], Border::TOP);
21438 							}
21439 						}
21440 					}
21441 
21442 					// Collapse Border - Algorithm for conflicting borders
21443 					// Hidden >> Width >> double>solid>dashed>dotted... >> style set on cell>table >> top/left>bottom/right
21444 					// Do not turn off border which is overridden
21445 					// Needed for page break for TOP/BOTTOM both to be defined in Collapsed borders
21446 					// Means it is painted twice. (Left/Right can still disable overridden border)
21447 					if (!$table['borders_separate']) {
21448 
21449 						if (($i < ($numrows - 1) || ($i + $crowsp) < $numrows ) && $fixbottom) { // Bottom
21450 
21451 							for ($cspi = 0; $cspi < $ccolsp; $cspi++) {
21452 
21453 								// already defined Top for adjacent cell below
21454 								if (isset($cells[($i + $crowsp)][$j + $cspi])) {
21455 									if ($this->packTableData) {
21456 										$adjc = $cells[($i + $crowsp)][$j + $cspi];
21457 										$celladj = $this->_unpackCellBorder($adjc['borderbin']);
21458 									} else {
21459 										$celladj = & $cells[($i + $crowsp)][$j + $cspi];
21460 									}
21461 								} else {
21462 									$celladj = false;
21463 								}
21464 
21465 								if (isset($celladj['border_details']['T']['s']) && $celladj['border_details']['T']['s'] == 1) {
21466 
21467 									$csadj = $celladj['border_details']['T']['w'];
21468 									$csthis = $cbord['border_details']['B']['w'];
21469 
21470 									// Hidden
21471 									if ($cbord['border_details']['B']['style'] == 'hidden') {
21472 
21473 										$celladj['border_details']['T'] = $cbord['border_details']['B'];
21474 										$this->setBorder($celladj['border'], Border::TOP, false);
21475 										$this->setBorder($cbord['border'], Border::BOTTOM, false);
21476 
21477 									} elseif ($celladj['border_details']['T']['style'] == 'hidden') {
21478 
21479 										$cbord['border_details']['B'] = $celladj['border_details']['T'];
21480 										$this->setBorder($cbord['border'], Border::BOTTOM, false);
21481 										$this->setBorder($celladj['border'], Border::TOP, false);
21482 
21483 									} elseif ($csthis > $csadj) { // Width
21484 
21485 										if (!isset($cells[($i + $crowsp)][$j + $cspi]['colspan']) || (isset($cells[($i + $crowsp)][$j + $cspi]['colspan']) && $cells[($i + $crowsp)][$j + $cspi]['colspan'] < 2)) { // don't overwrite bordering cells that span
21486 											$celladj['border_details']['T'] = $cbord['border_details']['B'];
21487 											$this->setBorder($cbord['border'], Border::BOTTOM);
21488 										}
21489 
21490 									} elseif ($csadj > $csthis) {
21491 
21492 										if ($ccolsp < 2) { // don't overwrite this cell if it spans
21493 											$cbord['border_details']['B'] = $celladj['border_details']['T'];
21494 											$this->setBorder($celladj['border'], Border::TOP);
21495 										}
21496 
21497 									} elseif (array_search($cbord['border_details']['B']['style'], $this->borderstyles) > array_search($celladj['border_details']['T']['style'], $this->borderstyles)) { // double>solid>dashed>dotted...
21498 
21499 										if (!isset($cells[($i + $crowsp)][$j + $cspi]['colspan']) || (isset($cells[($i + $crowsp)][$j + $cspi]['colspan']) && $cells[($i + $crowsp)][$j + $cspi]['colspan'] < 2)) { // don't overwrite bordering cells that span
21500 											$celladj['border_details']['T'] = $cbord['border_details']['B'];
21501 											$this->setBorder($cbord['border'], Border::BOTTOM);
21502 										}
21503 
21504 									} elseif (array_search($celladj['border_details']['T']['style'], $this->borderstyles) > array_search($cbord['border_details']['B']['style'], $this->borderstyles)) {
21505 
21506 										if ($ccolsp < 2) { // don't overwrite this cell if it spans
21507 											$cbord['border_details']['B'] = $celladj['border_details']['T'];
21508 											$this->setBorder($celladj['border'], Border::TOP);
21509 										}
21510 
21511 									} elseif ($celladj['border_details']['T']['dom'] > $celladj['border_details']['B']['dom']) { // Style set on cell vs. table
21512 
21513 										if ($ccolsp < 2) { // don't overwrite this cell if it spans
21514 											$cbord['border_details']['B'] = $celladj['border_details']['T'];
21515 											$this->setBorder($celladj['border'], Border::TOP);
21516 										}
21517 
21518 									} else { // Style set on cell vs. table  - OR - LEFT/TOP (cell) in preference to BOTTOM/RIGHT
21519 
21520 										if (!isset($cells[($i + $crowsp)][$j + $cspi]['colspan']) || (isset($cells[($i + $crowsp)][$j + $cspi]['colspan']) && $cells[($i + $crowsp)][$j + $cspi]['colspan'] < 2)) { // don't overwrite bordering cells that span
21521 											$celladj['border_details']['T'] = $cbord['border_details']['B'];
21522 											$this->setBorder($cbord['border'], Border::BOTTOM);
21523 										}
21524 
21525 									}
21526 
21527 								} elseif ($celladj) {
21528 
21529 									if (!isset($cells[($i + $crowsp)][$j + $cspi]['colspan']) || (isset($cells[($i + $crowsp)][$j + $cspi]['colspan']) && $cells[($i + $crowsp)][$j + $cspi]['colspan'] < 2)) { // don't overwrite bordering cells that span
21530 										$celladj['border_details']['T'] = $cbord['border_details']['B'];
21531 									}
21532 
21533 								}
21534 
21535 								// mPDF 5.7.4
21536 								if ($celladj && $this->packTableData) {
21537 									$cells[$i + $crowsp][$j + $cspi]['borderbin'] = $this->_packCellBorder($celladj);
21538 								}
21539 
21540 								unset($celladj);
21541 							}
21542 						}
21543 
21544 						if ($j < ($numcols - 1) || ($j + $ccolsp) < $numcols) { // Right-Left
21545 
21546 							for ($cspi = 0; $cspi < $crowsp; $cspi++) {
21547 
21548 								// already defined Left for adjacent cell to R
21549 								if (isset($cells[($i + $cspi)][$j + $ccolsp])) {
21550 									if ($this->packTableData) {
21551 										$adjc = $cells[($i + $cspi)][$j + $ccolsp];
21552 										$celladj = $this->_unpackCellBorder($adjc['borderbin']);
21553 									} else {
21554 										$celladj = & $cells[$i + $cspi][$j + $ccolsp];
21555 									}
21556 								} else {
21557 									$celladj = false;
21558 								}
21559 								if ($celladj && $celladj['border_details']['L']['s'] == 1) {
21560 									$csadj = $celladj['border_details']['L']['w'];
21561 									$csthis = $cbord['border_details']['R']['w'];
21562 									// Hidden
21563 									if ($cbord['border_details']['R']['style'] == 'hidden') {
21564 										$celladj['border_details']['L'] = $cbord['border_details']['R'];
21565 										$this->setBorder($celladj['border'], Border::LEFT, false);
21566 										$this->setBorder($cbord['border'], Border::RIGHT, false);
21567 									} elseif ($celladj['border_details']['L']['style'] == 'hidden') {
21568 										$cbord['border_details']['R'] = $celladj['border_details']['L'];
21569 										$this->setBorder($cbord['border'], Border::RIGHT, false);
21570 										$this->setBorder($celladj['border'], Border::LEFT, false);
21571 									} // Width
21572 									elseif ($csthis > $csadj) {
21573 										if (!isset($cells[($i + $cspi)][$j + $ccolsp]['rowspan']) || (isset($cells[($i + $cspi)][$j + $ccolsp]['rowspan']) && $cells[($i + $cspi)][$j + $ccolsp]['rowspan'] < 2)) { // don't overwrite bordering cells that span
21574 											$celladj['border_details']['L'] = $cbord['border_details']['R'];
21575 											$this->setBorder($cbord['border'], Border::RIGHT);
21576 											$this->setBorder($celladj['border'], Border::LEFT, false);
21577 										}
21578 									} elseif ($csadj > $csthis) {
21579 										if ($crowsp < 2) { // don't overwrite this cell if it spans
21580 											$cbord['border_details']['R'] = $celladj['border_details']['L'];
21581 											$this->setBorder($cbord['border'], Border::RIGHT, false);
21582 											$this->setBorder($celladj['border'], Border::LEFT);
21583 										}
21584 									} // double>solid>dashed>dotted...
21585 									elseif (array_search($cbord['border_details']['R']['style'], $this->borderstyles) > array_search($celladj['border_details']['L']['style'], $this->borderstyles)) {
21586 										if (!isset($cells[($i + $cspi)][$j + $ccolsp]['rowspan']) || (isset($cells[($i + $cspi)][$j + $ccolsp]['rowspan']) && $cells[($i + $cspi)][$j + $ccolsp]['rowspan'] < 2)) { // don't overwrite bordering cells that span
21587 											$celladj['border_details']['L'] = $cbord['border_details']['R'];
21588 											$this->setBorder($celladj['border'], Border::LEFT, false);
21589 											$this->setBorder($cbord['border'], Border::RIGHT);
21590 										}
21591 									} elseif (array_search($celladj['border_details']['L']['style'], $this->borderstyles) > array_search($cbord['border_details']['R']['style'], $this->borderstyles)) {
21592 										if ($crowsp < 2) { // don't overwrite this cell if it spans
21593 											$cbord['border_details']['R'] = $celladj['border_details']['L'];
21594 											$this->setBorder($cbord['border'], Border::RIGHT, false);
21595 											$this->setBorder($celladj['border'], Border::LEFT);
21596 										}
21597 									} // Style set on cell vs. table
21598 									elseif ($celladj['border_details']['L']['dom'] > $cbord['border_details']['R']['dom']) {
21599 										if ($crowsp < 2) { // don't overwrite this cell if it spans
21600 											$cbord['border_details']['R'] = $celladj['border_details']['L'];
21601 											$this->setBorder($celladj['border'], Border::LEFT);
21602 										}
21603 									} // Style set on cell vs. table  - OR - LEFT/TOP (cell) in preference to BOTTOM/RIGHT
21604 									else {
21605 										if (!isset($cells[($i + $cspi)][$j + $ccolsp]['rowspan']) || (isset($cells[($i + $cspi)][$j + $ccolsp]['rowspan']) && $cells[($i + $cspi)][$j + $ccolsp]['rowspan'] < 2)) { // don't overwrite bordering cells that span
21606 											$celladj['border_details']['L'] = $cbord['border_details']['R'];
21607 											$this->setBorder($cbord['border'], Border::RIGHT);
21608 										}
21609 									}
21610 								} elseif ($celladj) {
21611 									// if right-cell border is not set
21612 									if (!isset($cells[($i + $cspi)][$j + $ccolsp]['rowspan']) || (isset($cells[($i + $cspi)][$j + $ccolsp]['rowspan']) && $cells[($i + $cspi)][$j + $ccolsp]['rowspan'] < 2)) { // don't overwrite bordering cells that span
21613 										$celladj['border_details']['L'] = $cbord['border_details']['R'];
21614 									}
21615 								}
21616 								// mPDF 5.7.4
21617 								if ($celladj && $this->packTableData) {
21618 									$cells[$i + $cspi][$j + $ccolsp]['borderbin'] = $this->_packCellBorder($celladj);
21619 								}
21620 								unset($celladj);
21621 							}
21622 						}
21623 					}
21624 
21625 
21626 					// Set maximum cell border width meeting at LRTB edges of cell - used for extended cell border
21627 					// ['border_details']['mbw']['LT'] = meeting border width - Left border - Top end
21628 					if (!$table['borders_separate']) {
21629 
21630 						$cbord['border_details']['mbw']['BL'] = max($cbord['border_details']['mbw']['BL'], $cbord['border_details']['L']['w']);
21631 						$cbord['border_details']['mbw']['BR'] = max($cbord['border_details']['mbw']['BR'], $cbord['border_details']['R']['w']);
21632 						$cbord['border_details']['mbw']['RT'] = max($cbord['border_details']['mbw']['RT'], $cbord['border_details']['T']['w']);
21633 						$cbord['border_details']['mbw']['RB'] = max($cbord['border_details']['mbw']['RB'], $cbord['border_details']['B']['w']);
21634 						$cbord['border_details']['mbw']['TL'] = max($cbord['border_details']['mbw']['TL'], $cbord['border_details']['L']['w']);
21635 						$cbord['border_details']['mbw']['TR'] = max($cbord['border_details']['mbw']['TR'], $cbord['border_details']['R']['w']);
21636 						$cbord['border_details']['mbw']['LT'] = max($cbord['border_details']['mbw']['LT'], $cbord['border_details']['T']['w']);
21637 						$cbord['border_details']['mbw']['LB'] = max($cbord['border_details']['mbw']['LB'], $cbord['border_details']['B']['w']);
21638 
21639 						if (($i + $crowsp) < $numrows && isset($cells[$i + $crowsp][$j])) { // Has Bottom adjoining cell
21640 
21641 							if ($this->packTableData) {
21642 								$adjc = $cells[$i + $crowsp][$j];
21643 								$celladj = $this->_unpackCellBorder($adjc['borderbin']);
21644 							} else {
21645 								$celladj = & $cells[$i + $crowsp][$j];
21646 							}
21647 
21648 							$cbord['border_details']['mbw']['BL'] = max(
21649 								$cbord['border_details']['mbw']['BL'],
21650 								$celladj ? $celladj['border_details']['L']['w'] : 0,
21651 								$celladj ? $celladj['border_details']['mbw']['TL']: 0
21652 							);
21653 
21654 							$cbord['border_details']['mbw']['BR'] = max(
21655 								$cbord['border_details']['mbw']['BR'],
21656 								$celladj ? $celladj['border_details']['R']['w'] : 0,
21657 								$celladj ? $celladj['border_details']['mbw']['TR']: 0
21658 							);
21659 
21660 							$cbord['border_details']['mbw']['LB'] = max(
21661 								$cbord['border_details']['mbw']['LB'],
21662 								$celladj ? $celladj['border_details']['mbw']['LT'] : 0
21663 							);
21664 
21665 							$cbord['border_details']['mbw']['RB'] = max(
21666 								$cbord['border_details']['mbw']['RB'],
21667 								$celladj ? $celladj['border_details']['mbw']['RT'] : 0
21668 							);
21669 
21670 							unset($celladj);
21671 						}
21672 
21673 						if (($j + $ccolsp) < $numcols && isset($cells[$i][$j + $ccolsp])) { // Has Right adjoining cell
21674 
21675 							if ($this->packTableData) {
21676 								$adjc = $cells[$i][$j + $ccolsp];
21677 								$celladj = $this->_unpackCellBorder($adjc['borderbin']);
21678 							} else {
21679 								$celladj = & $cells[$i][$j + $ccolsp];
21680 							}
21681 
21682 							$cbord['border_details']['mbw']['RT'] = max(
21683 								$cbord['border_details']['mbw']['RT'],
21684 								$celladj ? $celladj['border_details']['T']['w'] : 0,
21685 								$celladj ? $celladj['border_details']['mbw']['LT'] : 0
21686 							);
21687 
21688 							$cbord['border_details']['mbw']['RB'] = max(
21689 								$cbord['border_details']['mbw']['RB'],
21690 								$celladj ? $celladj['border_details']['B']['w'] : 0,
21691 								$celladj ? $celladj['border_details']['mbw']['LB'] : 0
21692 							);
21693 
21694 							$cbord['border_details']['mbw']['TR'] = max(
21695 								$cbord['border_details']['mbw']['TR'],
21696 								$celladj ? $celladj['border_details']['mbw']['TL'] : 0
21697 							);
21698 
21699 							$cbord['border_details']['mbw']['BR'] = max(
21700 								$cbord['border_details']['mbw']['BR'],
21701 								$celladj ? $celladj['border_details']['mbw']['BL'] : 0
21702 							);
21703 
21704 							unset($celladj);
21705 						}
21706 
21707 						if ($i > 0 && isset($cells[$i - 1][$j]) && is_array($cells[$i - 1][$j]) && (($this->packTableData && $cells[$i - 1][$j]['borderbin']) || $cells[$i - 1][$j]['border'])) { // Has Top adjoining cell
21708 
21709 							if ($this->packTableData) {
21710 								$adjc = $cells[$i - 1][$j];
21711 								$celladj = $this->_unpackCellBorder($adjc['borderbin']);
21712 							} else {
21713 								$celladj = & $cells[$i - 1][$j];
21714 							}
21715 
21716 							$cbord['border_details']['mbw']['TL'] = max(
21717 								$cbord['border_details']['mbw']['TL'],
21718 								$celladj ? $celladj['border_details']['L']['w'] : 0,
21719 								$celladj ? $celladj['border_details']['mbw']['BL'] : 0
21720 							);
21721 
21722 							$cbord['border_details']['mbw']['TR'] = max(
21723 								$cbord['border_details']['mbw']['TR'],
21724 								$celladj ? $celladj['border_details']['R']['w'] : 0,
21725 								$celladj ? $celladj['border_details']['mbw']['BR'] : 0
21726 							);
21727 
21728 							$cbord['border_details']['mbw']['LT'] = max(
21729 								$cbord['border_details']['mbw']['LT'],
21730 								$celladj ? $celladj['border_details']['mbw']['LB'] : 0
21731 							);
21732 
21733 							$cbord['border_details']['mbw']['RT'] = max(
21734 								$cbord['border_details']['mbw']['RT'],
21735 								$celladj ? $celladj['border_details']['mbw']['RB'] : 0
21736 							);
21737 
21738 							if ($celladj['border_details']['mbw']['BL']) {
21739 								$celladj['border_details']['mbw']['BL'] = max($cbord['border_details']['mbw']['TL'], $celladj['border_details']['mbw']['BL']);
21740 							}
21741 
21742 							if ($celladj['border_details']['mbw']['BR']) {
21743 								$celladj['border_details']['mbw']['BR'] = max($celladj['border_details']['mbw']['BR'], $cbord['border_details']['mbw']['TR']);
21744 							}
21745 
21746 							if ($this->packTableData) {
21747 								$cells[$i - 1][$j]['borderbin'] = $this->_packCellBorder($celladj);
21748 							}
21749 							unset($celladj);
21750 						}
21751 
21752 						if ($j > 0 && isset($cells[$i][$j - 1]) && is_array($cells[$i][$j - 1]) && (($this->packTableData && $cells[$i][$j - 1]['borderbin']) || $cells[$i][$j - 1]['border'])) { // Has Left adjoining cell
21753 
21754 							if ($this->packTableData) {
21755 								$adjc = $cells[$i][$j - 1];
21756 								$celladj = $this->_unpackCellBorder($adjc['borderbin']);
21757 							} else {
21758 								$celladj = & $cells[$i][$j - 1];
21759 							}
21760 
21761 							$cbord['border_details']['mbw']['LT'] = max(
21762 								$cbord['border_details']['mbw']['LT'],
21763 								$celladj ? $celladj['border_details']['T']['w'] : 0,
21764 								$celladj ? $celladj['border_details']['mbw']['RT'] : 0
21765 							);
21766 
21767 							$cbord['border_details']['mbw']['LB'] = max(
21768 								$cbord['border_details']['mbw']['LB'],
21769 								$celladj ? $celladj['border_details']['B']['w'] : 0,
21770 								$celladj ? $celladj['border_details']['mbw']['RB'] : 0
21771 							);
21772 
21773 							$cbord['border_details']['mbw']['BL'] = max(
21774 								$cbord['border_details']['mbw']['BL'],
21775 								$celladj ? $celladj['border_details']['mbw']['BR'] : 0
21776 							);
21777 
21778 							$cbord['border_details']['mbw']['TL'] = max(
21779 								$cbord['border_details']['mbw']['TL'],
21780 								$celladj ? $celladj['border_details']['mbw']['TR'] : 0
21781 							);
21782 
21783 							if ($celladj['border_details']['mbw']['RT']) {
21784 								$celladj['border_details']['mbw']['RT'] = max($celladj['border_details']['mbw']['RT'], $cbord['border_details']['mbw']['LT']);
21785 							}
21786 
21787 							if ($celladj['border_details']['mbw']['RB']) {
21788 								$celladj['border_details']['mbw']['RB'] = max($celladj['border_details']['mbw']['RB'], $cbord['border_details']['mbw']['LB']);
21789 							}
21790 
21791 							if ($this->packTableData) {
21792 								$cells[$i][$j - 1]['borderbin'] = $this->_packCellBorder($celladj);
21793 							}
21794 
21795 							unset($celladj);
21796 						}
21797 
21798 
21799 						// Update maximum cell border width at LRTB edges of table - used for overall table width
21800 						if ($j == 0 && $cbord['border_details']['L']['w']) {
21801 							$table['max_cell_border_width']['L'] = max($table['max_cell_border_width']['L'], $cbord['border_details']['L']['w']);
21802 						}
21803 						if (($j == ($numcols - 1) || ($j + $ccolsp) == $numcols ) && $cbord['border_details']['R']['w']) {
21804 							$table['max_cell_border_width']['R'] = max($table['max_cell_border_width']['R'], $cbord['border_details']['R']['w']);
21805 						}
21806 						if ($i == 0 && $cbord['border_details']['T']['w']) {
21807 							$table['max_cell_border_width']['T'] = max($table['max_cell_border_width']['T'], $cbord['border_details']['T']['w']);
21808 						}
21809 						if (($i == ($numrows - 1) || ($i + $crowsp) == $numrows ) && $cbord['border_details']['B']['w']) {
21810 							$table['max_cell_border_width']['B'] = max($table['max_cell_border_width']['B'], $cbord['border_details']['B']['w']);
21811 						}
21812 					}
21813 					/* -- END TABLES-ADVANCED-BORDERS -- */
21814 
21815 					if ($this->packTableData) {
21816 						$cell['borderbin'] = $this->_packCellBorder($cbord);
21817 					}
21818 
21819 					unset($cbord);
21820 
21821 					unset($cell);
21822 				}
21823 			}
21824 		}
21825 		unset($cell);
21826 	}
21827 
21828 	// END FIX BORDERS ************************************************************************************
21829 
21830 	function _reverseTableDir(&$table)
21831 	{
21832 		$cells = &$table['cells'];
21833 		$numcols = $table['nc'];
21834 		$numrows = $table['nr'];
21835 		for ($i = 0; $i < $numrows; $i++) { // Rows
21836 			$row = [];
21837 			for ($j = ($numcols - 1); $j >= 0; $j--) { // Columns
21838 				if (isset($cells[$i][$j]) && $cells[$i][$j]) {
21839 					$cell = &$cells[$i][$j];
21840 					$col = $numcols - $j - 1;
21841 					if (isset($cell['colspan']) && $cell['colspan'] > 1) {
21842 						$col -= ($cell['colspan'] - 1);
21843 					}
21844 					// Nested content
21845 					if (isset($cell['textbuffer'])) {
21846 						for ($n = 0; $n < count($cell['textbuffer']); $n++) {
21847 							$t = $cell['textbuffer'][$n][0];
21848 							if (substr($t, 0, 19) == "\xbb\xa4\xactype=nestedtable") {
21849 								$objattr = $this->_getObjAttr($t);
21850 								$objattr['col'] = $col;
21851 								$cell['textbuffer'][$n][0] = "\xbb\xa4\xactype=nestedtable,objattr=" . serialize($objattr) . "\xbb\xa4\xac";
21852 								$this->table[($this->tableLevel + 1)][$objattr['nestedcontent']]['nestedpos'][1] = $col;
21853 							}
21854 						}
21855 					}
21856 					$row[$col] = $cells[$i][$j];
21857 					unset($cell);
21858 				}
21859 			}
21860 			for ($f = 0; $f < $numcols; $f++) {
21861 				if (!isset($row[$f])) {
21862 					$row[$f] = 0;
21863 				}
21864 			}
21865 			$table['cells'][$i] = $row;
21866 		}
21867 	}
21868 
21869 	function _tableWrite(&$table, $split = false, $startrow = 0, $startcol = 0, $splitpg = 0, $rety = 0)
21870 	{
21871 		$level = $table['level'];
21872 		$levelid = $table['levelid'];
21873 
21874 		$cells = &$table['cells'];
21875 		$numcols = $table['nc'];
21876 		$numrows = $table['nr'];
21877 		$maxbwtop = 0;
21878 		if ($this->ColActive && $level == 1) {
21879 			$this->breakpoints[$this->CurrCol][] = $this->y;
21880 		} // *COLUMNS*
21881 
21882 		if (!$split || ($startrow == 0 && $splitpg == 0) || $startrow > 0) {
21883 			// TABLE TOP MARGIN
21884 			if ($table['margin']['T']) {
21885 				if (!$this->table_rotate && $level == 1) {
21886 					$this->DivLn($table['margin']['T'], $this->blklvl, true, 1);  // collapsible
21887 				} else {
21888 					$this->y += ($table['margin']['T']);
21889 				}
21890 			}
21891 			// Advance down page by half width of top border
21892 			if ($table['borders_separate']) {
21893 				if ($startrow > 0 && (!isset($table['is_thead']) || count($table['is_thead']) == 0)) {
21894 					$adv = $table['border_spacing_V'] / 2;
21895 				} else {
21896 					$adv = $table['padding']['T'] + $table['border_details']['T']['w'] + $table['border_spacing_V'] / 2;
21897 				}
21898 			} else {
21899 				$adv = $table['max_cell_border_width']['T'] / 2;
21900 			}
21901 			if (!$this->table_rotate && $level == 1) {
21902 				$this->DivLn($adv);
21903 			} else {
21904 				$this->y += $adv;
21905 			}
21906 		}
21907 
21908 		if ($level == 1) {
21909 			$this->x = $this->lMargin + $this->blk[$this->blklvl]['outer_left_margin'] + $this->blk[$this->blklvl]['padding_left'] + $this->blk[$this->blklvl]['border_left']['w'];
21910 			$x0 = $this->x;
21911 			$y0 = $this->y;
21912 			$right = $x0 + $this->blk[$this->blklvl]['inner_width'];
21913 			$outerfilled = $this->y; // Keep track of how far down the outer DIV bgcolor is painted (NB rowspans)
21914 			$this->outerfilled = $this->y;
21915 			$this->colsums = [];
21916 		} else {
21917 			$x0 = $this->x;
21918 			$y0 = $this->y;
21919 			$right = $x0 + $table['w'];
21920 		}
21921 
21922 		if ($this->table_rotate) {
21923 			$temppgwidth = $this->tbrot_maxw;
21924 			$this->PageBreakTrigger = $pagetrigger = $y0 + ($this->blk[$this->blklvl]['inner_width']);
21925 			if ($level == 1) {
21926 				$this->tbrot_y0 = $this->y - $adv - $table['margin']['T'];
21927 				$this->tbrot_x0 = $this->x;
21928 				$this->tbrot_w = $table['w'];
21929 				if ($table['borders_separate']) {
21930 					$this->tbrot_h = $table['margin']['T'] + $table['padding']['T'] + $table['border_details']['T']['w'] + $table['border_spacing_V'] / 2;
21931 				} else {
21932 					$this->tbrot_h = $table['margin']['T'] + $table['padding']['T'] + $table['max_cell_border_width']['T'];
21933 				}
21934 			}
21935 		} else {
21936 			$this->PageBreakTrigger = $pagetrigger = ($this->h - $this->bMargin);
21937 			if ($level == 1) {
21938 				$temppgwidth = $this->blk[$this->blklvl]['inner_width'];
21939 				if (isset($table['a']) and ( $table['w'] < $this->blk[$this->blklvl]['inner_width'])) {
21940 					if ($table['a'] == 'C') {
21941 						$x0 += ((($right - $x0) - $table['w']) / 2);
21942 					} elseif ($table['a'] == 'R') {
21943 						$x0 = $right - $table['w'];
21944 					}
21945 				}
21946 			} else {
21947 				$temppgwidth = $table['w'];
21948 			}
21949 		}
21950 		if (!isset($table['overflow'])) {
21951 			$table['overflow'] = null;
21952 		}
21953 		if ($table['overflow'] == 'hidden' && $level == 1 && !$this->table_rotate && !$this->ColActive) {
21954 			// Bounding rectangle to clip
21955 			$this->tableClipPath = sprintf('q %.3F %.3F %.3F %.3F re W n', $x0 * Mpdf::SCALE, $this->h * Mpdf::SCALE, $this->blk[$this->blklvl]['inner_width'] * Mpdf::SCALE, -$this->h * Mpdf::SCALE);
21956 			$this->writer->write($this->tableClipPath);
21957 		} else {
21958 			$this->tableClipPath = '';
21959 		}
21960 
21961 
21962 		if ($table['borders_separate']) {
21963 			$indent = $table['margin']['L'] + $table['border_details']['L']['w'] + $table['padding']['L'] + $table['border_spacing_H'] / 2;
21964 		} else {
21965 			$indent = $table['margin']['L'] + $table['max_cell_border_width']['L'] / 2;
21966 		}
21967 		$x0 += $indent;
21968 
21969 		$returny = 0;
21970 		$lastCol = 0;
21971 		$tableheader = [];
21972 		$tablefooter = [];
21973 		$tableheaderrowheight = 0;
21974 		$tablefooterrowheight = 0;
21975 		$footery = 0;
21976 
21977 		// mPD 3.0 Set the Page & Column where table starts
21978 		if (($this->mirrorMargins) && (($this->page) % 2 == 0)) { // EVEN
21979 			$tablestartpage = 'EVEN';
21980 		} elseif (($this->mirrorMargins) && (($this->page) % 2 == 1)) { // ODD
21981 			$tablestartpage = 'ODD';
21982 		} else {
21983 			$tablestartpage = '';
21984 		}
21985 		if ($this->ColActive) {
21986 			$tablestartcolumn = $this->CurrCol;
21987 		} else {
21988 			$tablestartcolumn = '';
21989 		}
21990 
21991 		$y = $h = 0;
21992 		for ($i = 0; $i < $numrows; $i++) { // Rows
21993 			if (isset($table['is_tfoot'][$i]) && $table['is_tfoot'][$i] && $level == 1) {
21994 				$tablefooterrowheight += $table['hr'][$i];
21995 				$tablefooter[$i][0]['trbackground-images'] = $table['trbackground-images'][$i];
21996 				$tablefooter[$i][0]['trgradients'] = $table['trgradients'][$i];
21997 				$tablefooter[$i][0]['trbgcolor'] = $table['bgcolor'][$i];
21998 				for ($j = $startcol; $j < $numcols; $j++) { // Columns
21999 					if (isset($cells[$i][$j]) && $cells[$i][$j]) {
22000 						$cell = &$cells[$i][$j];
22001 						if ($split) {
22002 							if ($table['colPg'][$j] != $splitpg) {
22003 								continue;
22004 							}
22005 							list($x, $w) = $this->_splitTableGetWidth($table, $i, $j);
22006 							$js = $j - $startcol;
22007 						} else {
22008 							list($x, $w) = $this->_tableGetWidth($table, $i, $j);
22009 							$js = $j;
22010 						}
22011 
22012 						list($y, $h) = $this->_tableGetHeight($table, $i, $j);
22013 						$x += $x0;
22014 						$y += $y0;
22015 						// Get info of tfoot ==>> table footer
22016 						$tablefooter[$i][$js]['x'] = $x;
22017 						$tablefooter[$i][$js]['y'] = $y;
22018 						$tablefooter[$i][$js]['h'] = $h;
22019 						$tablefooter[$i][$js]['w'] = $w;
22020 						if (isset($cell['textbuffer'])) {
22021 							$tablefooter[$i][$js]['textbuffer'] = $cell['textbuffer'];
22022 						} else {
22023 							$tablefooter[$i][$js]['textbuffer'] = '';
22024 						}
22025 						$tablefooter[$i][$js]['a'] = $cell['a'];
22026 						$tablefooter[$i][$js]['R'] = $cell['R'];
22027 						$tablefooter[$i][$js]['va'] = $cell['va'];
22028 						$tablefooter[$i][$js]['mih'] = $cell['mih'];
22029 						if (isset($cell['gradient'])) {
22030 							$tablefooter[$i][$js]['gradient'] = $cell['gradient']; // *BACKGROUNDS*
22031 						}
22032 						if (isset($cell['background-image'])) {
22033 							$tablefooter[$i][$js]['background-image'] = $cell['background-image']; // *BACKGROUNDS*
22034 						}
22035 
22036 						// CELL FILL BGCOLOR
22037 						if (!$this->simpleTables) {
22038 							if ($this->packTableData) {
22039 								$c = $this->_unpackCellBorder($cell['borderbin']);
22040 								$tablefooter[$i][$js]['border'] = $c['border'];
22041 								$tablefooter[$i][$js]['border_details'] = $c['border_details'];
22042 							} else {
22043 								$tablefooter[$i][$js]['border'] = $cell['border'];
22044 								$tablefooter[$i][$js]['border_details'] = $cell['border_details'];
22045 							}
22046 						} elseif ($this->simpleTables) {
22047 							$tablefooter[$i][$js]['border'] = $table['simple']['border'];
22048 							$tablefooter[$i][$js]['border_details'] = $table['simple']['border_details'];
22049 						}
22050 						$tablefooter[$i][$js]['bgcolor'] = $cell['bgcolor'];
22051 						$tablefooter[$i][$js]['padding'] = $cell['padding'];
22052 						if (isset($cell['rowspan'])) {
22053 							$tablefooter[$i][$js]['rowspan'] = $cell['rowspan'];
22054 						}
22055 						if (isset($cell['colspan'])) {
22056 							$tablefooter[$i][$js]['colspan'] = $cell['colspan'];
22057 						}
22058 						if (isset($cell['direction'])) {
22059 							$tablefooter[$i][$js]['direction'] = $cell['direction'];
22060 						}
22061 						if (isset($cell['cellLineHeight'])) {
22062 							$tablefooter[$i][$js]['cellLineHeight'] = $cell['cellLineHeight'];
22063 						}
22064 						if (isset($cell['cellLineStackingStrategy'])) {
22065 							$tablefooter[$i][$js]['cellLineStackingStrategy'] = $cell['cellLineStackingStrategy'];
22066 						}
22067 						if (isset($cell['cellLineStackingShift'])) {
22068 							$tablefooter[$i][$js]['cellLineStackingShift'] = $cell['cellLineStackingShift'];
22069 						}
22070 					}
22071 				}
22072 			}
22073 		}
22074 
22075 		if ($level == 1) {
22076 			$this->writer->write('___TABLE___BACKGROUNDS' . $this->uniqstr);
22077 		}
22078 		$tableheaderadj = 0;
22079 		$tablefooteradj = 0;
22080 
22081 		$tablestartpageno = $this->page;
22082 
22083 		// Draw Table Contents and Borders
22084 		for ($i = 0; $i < $numrows; $i++) { // Rows
22085 			if ($split && $startrow > 0) {
22086 				$thnr = (isset($table['is_thead']) ? count($table['is_thead']) : 0);
22087 				if ($i >= $thnr && $i < $startrow) {
22088 					continue;
22089 				}
22090 				if ($i == $startrow) {
22091 					$returny = $rety - $tableheaderrowheight;
22092 				}
22093 			}
22094 
22095 			// Get Maximum row/cell height in row - including rowspan>1 + 1 overlapping
22096 			$maxrowheight = $this->_tableGetMaxRowHeight($table, $i);
22097 
22098 			$skippage = false;
22099 			$newpagestarted = false;
22100 			for ($j = $startcol; $j < $numcols; $j++) { // Columns
22101 				if ($split) {
22102 					if ($table['colPg'][$j] > $splitpg) {
22103 						break;
22104 					}
22105 					$lastCol = $j;
22106 				}
22107 				if (isset($cells[$i][$j]) && $cells[$i][$j]) {
22108 					$cell = &$cells[$i][$j];
22109 					if ($split) {
22110 						$lastCol = $j + (isset($cell['colspan']) ? ($cell['colspan'] - 1) : 0);
22111 						list($x, $w) = $this->_splitTableGetWidth($table, $i, $j);
22112 					} else {
22113 						list($x, $w) = $this->_tableGetWidth($table, $i, $j);
22114 					}
22115 
22116 					list($y, $h) = $this->_tableGetHeight($table, $i, $j);
22117 					$x += $x0;
22118 					$y += $y0;
22119 					$y -= $returny;
22120 
22121 					if ($table['borders_separate']) {
22122 						if (!empty($tablefooter) || $i == ($numrows - 1) || (isset($cell['rowspan']) && ($i + $cell['rowspan']) == $numrows) || (!isset($cell['rowspan']) && ($i + 1) == $numrows)) {
22123 							$extra = $table['padding']['B'] + $table['border_details']['B']['w'] + $table['border_spacing_V'] / 2;
22124 							// $extra = $table['margin']['B'] + $table['padding']['B'] + $table['border_details']['B']['w'] + $table['border_spacing_V']/2;
22125 						} else {
22126 							$extra = $table['border_spacing_V'] / 2;
22127 						}
22128 					} else {
22129 						$extra = $table['max_cell_border_width']['B'] / 2;
22130 					}
22131 
22132 					if ($j == $startcol && ((($y + $maxrowheight + $extra ) > ($pagetrigger + 0.001)) || (($this->keepColumns || !$this->ColActive) && !empty($tablefooter) && ($y + $maxrowheight + $tablefooterrowheight + $extra) > $pagetrigger) && ($this->tableLevel == 1 && $i < ($numrows - $table['headernrows']))) && ($y0 > 0 || $x0 > 0) && !$this->InFooter && $this->autoPageBreak) {
22133 						if (!$skippage) {
22134 							$finalSpread = true;
22135 							$firstSpread = true;
22136 							if ($split) {
22137 								for ($t = $startcol; $t < $numcols; $t++) {
22138 									// Are there more columns to print on a next page?
22139 									if ($table['colPg'][$t] > $splitpg) {
22140 										$finalSpread = false;
22141 										break;
22142 									}
22143 								}
22144 								if ($startcol > 0) {
22145 									$firstSpread = false;
22146 								}
22147 							}
22148 
22149 							if (($this->keepColumns || !$this->ColActive) && !empty($tablefooter) && $i > 0) {
22150 								$this->y = $y;
22151 								$ya = $this->y;
22152 								$this->TableHeaderFooter($tablefooter, $tablestartpage, $tablestartcolumn, 'F', $level, $firstSpread, $finalSpread);
22153 								if ($this->table_rotate) {
22154 									$this->tbrot_h += $this->y - $ya;
22155 								}
22156 								$tablefooteradj = $this->y - $ya;
22157 							}
22158 							$y -= $y0;
22159 							$returny += $y;
22160 
22161 							$oldcolumn = $this->CurrCol;
22162 							if ($this->AcceptPageBreak()) {
22163 								$newpagestarted = true;
22164 								$this->y = $y + $y0;
22165 
22166 								// Move down to account for border-spacing or
22167 								// extra half border width in case page breaks in middle
22168 								if ($i > 0 && !$this->table_rotate && $level == 1 && !$this->ColActive) {
22169 									if ($table['borders_separate']) {
22170 										$adv = $table['border_spacing_V'] / 2;
22171 										// If table footer
22172 										if (($this->keepColumns || !$this->ColActive) && !empty($tablefooter) && $i > 0) {
22173 											$adv += ($table['padding']['B'] + $table['border_details']['B']['w']);
22174 										}
22175 									} else {
22176 										$maxbwtop = 0;
22177 										$maxbwbottom = 0;
22178 										if (!$this->simpleTables) {
22179 											if (!empty($tablefooter)) {
22180 												$maxbwbottom = $table['max_cell_border_width']['B'];
22181 											} else {
22182 												$brow = $i - 1;
22183 												for ($ctj = 0; $ctj < $numcols; $ctj++) {
22184 													if (isset($cells[$brow][$ctj]) && $cells[$brow][$ctj]) {
22185 														if ($this->packTableData) {
22186 															list($bt, $br, $bb, $bl) = $this->_getBorderWidths($cells[$brow][$ctj]['borderbin']);
22187 														} else {
22188 															$bb = $cells[$brow][$ctj]['border_details']['B']['w'];
22189 														}
22190 														$maxbwbottom = max($maxbwbottom, $bb);
22191 													}
22192 												}
22193 											}
22194 											if (!empty($tableheader)) {
22195 												$maxbwtop = $table['max_cell_border_width']['T'];
22196 											} else {
22197 												$trow = $i - 1;
22198 												for ($ctj = 0; $ctj < $numcols; $ctj++) {
22199 													if (isset($cells[$trow][$ctj]) && $cells[$trow][$ctj]) {
22200 														if ($this->packTableData) {
22201 															list($bt, $br, $bb, $bl) = $this->_getBorderWidths($cells[$trow][$ctj]['borderbin']);
22202 														} else {
22203 															$bt = $cells[$trow][$ctj]['border_details']['T']['w'];
22204 														}
22205 														$maxbwtop = max($maxbwtop, $bt);
22206 													}
22207 												}
22208 											}
22209 										} elseif ($this->simpleTables) {
22210 											$maxbwtop = $table['simple']['border_details']['T']['w'];
22211 											$maxbwbottom = $table['simple']['border_details']['B']['w'];
22212 										}
22213 										$adv = $maxbwbottom / 2;
22214 									}
22215 									$this->y += $adv;
22216 								}
22217 
22218 								// Rotated table split over pages - needs this->y for borders/backgrounds
22219 								if ($i > 0 && $this->table_rotate && $level == 1) {
22220 									// 		$this->y = $y0 + $this->tbrot_w;
22221 								}
22222 
22223 								if ($this->tableClipPath) {
22224 									$this->writer->write("Q");
22225 								}
22226 
22227 								$bx = $x0;
22228 								$by = $y0;
22229 
22230 								if ($table['borders_separate']) {
22231 									$bx -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['border_spacing_H'] / 2);
22232 									if ($tablestartpageno != $this->page) { // IF already broken across a previous pagebreak
22233 										$by += $table['max_cell_border_width']['T'] / 2;
22234 										if (empty($tableheader)) {
22235 											$by -= ($table['border_spacing_V'] / 2);
22236 										}
22237 									} else {
22238 										$by -= ($table['padding']['T'] + $table['border_details']['T']['w'] + $table['border_spacing_V'] / 2);
22239 									}
22240 								} elseif ($tablestartpageno != $this->page && !empty($tableheader)) {
22241 									$by += $maxbwtop / 2;
22242 								}
22243 
22244 								$by -= $tableheaderadj;
22245 								$bh = $this->y - $by + $tablefooteradj;
22246 								if (!$table['borders_separate']) {
22247 									$bh -= $adv;
22248 								}
22249 								if ($split) {
22250 									$bw = 0;
22251 									for ($t = $startcol; $t < $numcols; $t++) {
22252 										if ($table['colPg'][$t] == $splitpg) {
22253 											$bw += $table['wc'][$t];
22254 										}
22255 										if ($table['colPg'][$t] > $splitpg) {
22256 											break;
22257 										}
22258 									}
22259 									if ($table['borders_separate']) {
22260 										if ($firstSpread) {
22261 											$bw += $table['padding']['L'] + $table['border_details']['L']['w'] + $table['border_spacing_H'];
22262 										} else {
22263 											$bx += ($table['padding']['L'] + $table['border_details']['L']['w']);
22264 											$bw += $table['border_spacing_H'];
22265 										}
22266 										if ($finalSpread) {
22267 											$bw += $table['padding']['R'] + $table['border_details']['R']['w'] / 2 + $table['border_spacing_H'];
22268 										}
22269 									}
22270 								} else {
22271 									$bw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
22272 								}
22273 
22274 								if ($this->splitTableBorderWidth && ($this->keepColumns || !$this->ColActive) && empty($tablefooter) && $i > 0 && $table['border_details']['B']['w']) {
22275 									$prevDrawColor = $this->DrawColor;
22276 									$lw = $this->LineWidth;
22277 									$this->SetLineWidth($this->splitTableBorderWidth);
22278 									$this->SetDColor($table['border_details']['B']['c']);
22279 									$this->SetLineJoin(0);
22280 									$this->SetLineCap(0);
22281 									$blx = $bx;
22282 									$blw = $bw;
22283 									if (!$table['borders_separate']) {
22284 										$blx -= ($table['max_cell_border_width']['L'] / 2);
22285 										$blw += ($table['max_cell_border_width']['L'] / 2 + $table['max_cell_border_width']['R'] / 2);
22286 									}
22287 									$this->Line($blx, $this->y + ($this->splitTableBorderWidth / 2), $blx + $blw, $this->y + ($this->splitTableBorderWidth / 2));
22288 									$this->DrawColor = $prevDrawColor;
22289 									$this->writer->write($this->DrawColor);
22290 									$this->SetLineWidth($lw);
22291 									$this->SetLineJoin(2);
22292 									$this->SetLineCap(2);
22293 								}
22294 
22295 								if (!$this->ColActive && ($i > 0 || $j > 0)) {
22296 									if (isset($table['bgcolor'][-1])) {
22297 										$color = $this->colorConverter->convert($table['bgcolor'][-1], $this->PDFAXwarnings);
22298 										if ($color) {
22299 											if (!$table['borders_separate']) {
22300 												$bh -= $table['max_cell_border_width']['B'] / 2;
22301 											}
22302 											$this->tableBackgrounds[$level * 9][] = ['gradient' => false, 'x' => $bx, 'y' => $by, 'w' => $bw, 'h' => $bh, 'col' => $color];
22303 										}
22304 									}
22305 
22306 									/* -- BACKGROUNDS -- */
22307 									if (isset($table['gradient'])) {
22308 										$g = $this->gradient->parseBackgroundGradient($table['gradient']);
22309 										if ($g) {
22310 											$this->tableBackgrounds[$level * 9 + 1][] = ['gradient' => true, 'x' => $bx, 'y' => $by, 'w' => $bw, 'h' => $bh, 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => ''];
22311 										}
22312 									}
22313 
22314 									if (isset($table['background-image'])) {
22315 										if ($table['background-image']['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $table['background-image']['gradient'])) {
22316 											$g = $this->gradient->parseMozGradient($table['background-image']['gradient']);
22317 											if ($g) {
22318 												$this->tableBackgrounds[$level * 9 + 1][] = ['gradient' => true, 'x' => $bx, 'y' => $by, 'w' => $bw, 'h' => $bh, 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => ''];
22319 											}
22320 										} else {
22321 											$image_id = $table['background-image']['image_id'];
22322 											$orig_w = $table['background-image']['orig_w'];
22323 											$orig_h = $table['background-image']['orig_h'];
22324 											$x_pos = $table['background-image']['x_pos'];
22325 											$y_pos = $table['background-image']['y_pos'];
22326 											$x_repeat = $table['background-image']['x_repeat'];
22327 											$y_repeat = $table['background-image']['y_repeat'];
22328 											$resize = $table['background-image']['resize'];
22329 											$opacity = $table['background-image']['opacity'];
22330 											$itype = $table['background-image']['itype'];
22331 											$this->tableBackgrounds[$level * 9 + 2][] = ['x' => $bx, 'y' => $by, 'w' => $bw, 'h' => $bh, 'image_id' => $image_id, 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $x_pos, 'y_pos' => $y_pos, 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat, 'clippath' => '', 'resize' => $resize, 'opacity' => $opacity, 'itype' => $itype];
22332 										}
22333 									}
22334 									/* -- END BACKGROUNDS -- */
22335 								}
22336 
22337 								// $this->AcceptPageBreak() has moved tablebuffer to $this->pages content
22338 								if ($this->tableBackgrounds) {
22339 									$s = $this->PrintTableBackgrounds();
22340 									if ($this->bufferoutput) {
22341 										$this->headerbuffer = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->headerbuffer);
22342 										$this->headerbuffer = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', " ", $this->headerbuffer);
22343 									} else {
22344 										$this->pages[$this->page] = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->pages[$this->page]);
22345 										$this->pages[$this->page] = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', " ", $this->pages[$this->page]);
22346 									}
22347 									$this->tableBackgrounds = [];
22348 								}
22349 
22350 								if ($split) {
22351 									if ($i == 0 && $j == 0) {
22352 										$y0 = -1;
22353 									} elseif ($finalSpread) {
22354 										$splitpg = 0;
22355 										$startcol = 0;
22356 										$startrow = $i;
22357 									} else {
22358 										$splitpg++;
22359 										$startcol = $t;
22360 										$returny -= $y;
22361 									}
22362 									return [false, $startrow, $startcol, $splitpg, $returny, $y0];
22363 								}
22364 
22365 								$this->AddPage($this->CurOrientation);
22366 
22367 								$this->writer->write('___TABLE___BACKGROUNDS' . $this->uniqstr);
22368 
22369 
22370 								if ($this->tableClipPath) {
22371 									$this->writer->write($this->tableClipPath);
22372 								}
22373 
22374 								// Added to correct for OddEven Margins
22375 								$x = $x + $this->MarginCorrection;
22376 								$x0 = $x0 + $this->MarginCorrection;
22377 
22378 								if ($this->splitTableBorderWidth && ($this->keepColumns || !$this->ColActive) && empty($tableheader) && $i > 0 && $table['border_details']['T']['w']) {
22379 									$prevDrawColor = $this->DrawColor;
22380 									$lw = $this->LineWidth;
22381 									$this->SetLineWidth($this->splitTableBorderWidth);
22382 									$this->SetDColor($table['border_details']['T']['c']);
22383 									$this->SetLineJoin(0);
22384 									$this->SetLineCap(0);
22385 									$blx += $this->MarginCorrection;
22386 									$this->Line($blx, $this->y - ($this->splitTableBorderWidth / 2), $blx + $blw, $this->y - ($this->splitTableBorderWidth / 2));
22387 									$this->DrawColor = $prevDrawColor;
22388 									$this->writer->write($this->DrawColor);
22389 									$this->SetLineWidth($lw);
22390 									$this->SetLineJoin(2);
22391 									$this->SetLineCap(2);
22392 								}
22393 
22394 								// Move down to account for half of top border-spacing or
22395 								// extra half border width in case page was broken in middle
22396 								if ($i > 0 && !$this->table_rotate && $level == 1 && $table['headernrows'] == 0) {
22397 									if ($table['borders_separate']) {
22398 										$adv = $table['border_spacing_V'] / 2;
22399 									} else {
22400 										$maxbwtop = 0;
22401 										for ($ctj = 0; $ctj < $numcols; $ctj++) {
22402 											if (isset($cells[$i][$ctj]) && $cells[$i][$ctj]) {
22403 												if (!$this->simpleTables) {
22404 													if ($this->packTableData) {
22405 														list($bt, $br, $bb, $bl) = $this->_getBorderWidths($cells[$i][$ctj]['borderbin']);
22406 													} else {
22407 														$bt = $cells[$i][$ctj]['border_details']['T']['w'];
22408 													}
22409 													$maxbwtop = max($maxbwtop, $bt);
22410 												} elseif ($this->simpleTables) {
22411 													$maxbwtop = max($maxbwtop, $table['simple']['border_details']['T']['w']);
22412 												}
22413 											}
22414 										}
22415 										$adv = $maxbwtop / 2;
22416 									}
22417 									$this->y += $adv;
22418 								}
22419 
22420 
22421 								if ($this->table_rotate) {
22422 									$this->tbrot_x0 = $this->lMargin + $this->blk[$this->blklvl]['outer_left_margin'] + $this->blk[$this->blklvl]['padding_left'] + $this->blk[$this->blklvl]['border_left']['w'];
22423 									if ($table['borders_separate']) {
22424 										$this->tbrot_h = $table['margin']['T'] + $table['padding']['T'] + $table['border_details']['T']['w'] + $table['border_spacing_V'] / 2;
22425 									} else {
22426 										$this->tbrot_h = $table['margin']['T'] + $table['max_cell_border_width']['T'];
22427 									}
22428 									$this->tbrot_y0 = $this->y;
22429 									$pagetrigger = $y0 - $tableheaderadj + ($this->blk[$this->blklvl]['inner_width']);
22430 								} else {
22431 									$pagetrigger = $this->PageBreakTrigger;
22432 								}
22433 
22434 								if ($this->kwt_saved && $level == 1) {
22435 									$this->kwt_moved = true;
22436 								}
22437 
22438 
22439 								if (!empty($tableheader)) {
22440 									$ya = $this->y;
22441 									$this->TableHeaderFooter($tableheader, $tablestartpage, $tablestartcolumn, 'H', $level);
22442 									if ($this->table_rotate) {
22443 										$this->tbrot_h = $this->y - $ya;
22444 									}
22445 									$tableheaderadj = $this->y - $ya;
22446 								} elseif ($i == 0 && !$this->table_rotate && $level == 1 && !$this->ColActive) {
22447 									// Advance down page
22448 									if ($table['borders_separate']) {
22449 										$adv = $table['border_spacing_V'] / 2 + $table['border_details']['T']['w'] + $table['padding']['T'];
22450 									} else {
22451 										$adv = $table['max_cell_border_width']['T'] / 2;
22452 									}
22453 									if ($adv) {
22454 										if ($this->table_rotate) {
22455 											$this->y += ($adv);
22456 										} else {
22457 											$this->DivLn($adv, $this->blklvl, true);
22458 										}
22459 									}
22460 								}
22461 
22462 								$outerfilled = 0;
22463 								$y = $y0 = $this->y;
22464 							}
22465 
22466 							/* -- COLUMNS -- */
22467 							// COLS
22468 							// COLUMN CHANGE
22469 							if ($this->CurrCol != $oldcolumn) {
22470 								// Added to correct for Columns
22471 								$x += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
22472 								$x0 += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
22473 								if ($this->CurrCol == 0) {  // just added a page - possibly with tableheader
22474 									$y0 = $this->y;  // this->y0 is global used by Columns - $y0 is internal to tablewrite
22475 								} else {
22476 									$y0 = $this->y0;  // this->y0 is global used by Columns - $y0 is internal to tablewrite
22477 								}
22478 								$y = $y0;
22479 								$outerfilled = 0;
22480 								if ($this->CurrCol != 0 && ($this->keepColumns && $this->ColActive) && !empty($tableheader) && $i > 0) {
22481 									$this->x = $x;
22482 									$this->y = $y;
22483 									$this->TableHeaderFooter($tableheader, $tablestartpage, $tablestartcolumn, 'H', $level);
22484 									$y0 = $y = $this->y;
22485 								}
22486 							}
22487 							/* -- END COLUMNS -- */
22488 						}
22489 						$skippage = true;
22490 					}
22491 
22492 					$this->x = $x;
22493 					$this->y = $y;
22494 
22495 					if ($this->kwt_saved && $level == 1) {
22496 						$this->printkwtbuffer();
22497 						$x0 = $x = $this->x;
22498 						$y0 = $y = $this->y;
22499 						$this->kwt_moved = false;
22500 						$this->kwt_saved = false;
22501 					}
22502 
22503 
22504 					// Set the Page & Column where table actually starts
22505 					if ($i == 0 && $j == 0 && $level == 1) {
22506 						if (($this->mirrorMargins) && (($this->page) % 2 == 0)) {    // EVEN
22507 							$tablestartpage = 'EVEN';
22508 						} elseif (($this->mirrorMargins) && (($this->page) % 2 == 1)) {    // ODD
22509 							$tablestartpage = 'ODD';
22510 						} else {
22511 							$tablestartpage = '';
22512 						}
22513 						$tablestartpageno = $this->page;
22514 						if ($this->ColActive) {
22515 							$tablestartcolumn = $this->CurrCol;
22516 						} // *COLUMNS*
22517 					}
22518 
22519 					// ALIGN
22520 					$align = $cell['a'];
22521 
22522 					/* -- COLUMNS -- */
22523 					// If outside columns, this is done in PaintDivBB
22524 					if ($this->ColActive) {
22525 						// OUTER FILL BGCOLOR of DIVS
22526 						if ($this->blklvl > 0 && ($j == 0) && !$this->table_rotate && $level == 1) {
22527 							$firstblockfill = $this->GetFirstBlockFill();
22528 							if ($firstblockfill && $this->blklvl >= $firstblockfill) {
22529 								$divh = $maxrowheight;
22530 								// Last row
22531 								if ((!isset($cell['rowspan']) && $i == $numrows - 1) || (isset($cell['rowspan']) && (($i == $numrows - 1 && $cell['rowspan'] < 2) || ($cell['rowspan'] > 1 && ($i + $cell['rowspan'] - 1) == $numrows - 1)))) {
22532 									if ($table['borders_separate']) {
22533 										$adv = $table['margin']['B'] + $table['padding']['B'] + $table['border_details']['B']['w'] + $table['border_spacing_V'] / 2;
22534 									} else {
22535 										$adv = $table['margin']['B'] + $table['max_cell_border_width']['B'] / 2;
22536 									}
22537 									$divh += $adv;  // last row: fill bottom half of bottom border (y advanced at end)
22538 								}
22539 
22540 								if (($this->y + $divh) > $outerfilled) { // if not already painted by previous rowspan
22541 									$bak_x = $this->x;
22542 									$bak_y = $this->y;
22543 									if ($outerfilled > $this->y) {
22544 										$divh = ($this->y + $divh) - $outerfilled;
22545 										$this->y = $outerfilled;
22546 									}
22547 
22548 									$this->DivLn($divh, -3, false);
22549 									$outerfilled = $this->y + $divh;
22550 									// Reset current block fill
22551 									$bcor = $this->blk[$this->blklvl]['bgcolorarray'];
22552 									if ($bcor) {
22553 										$this->SetFColor($bcor);
22554 									}
22555 									$this->x = $bak_x;
22556 									$this->y = $bak_y;
22557 								}
22558 							}
22559 						}
22560 					}
22561 
22562 					// TABLE BACKGROUND FILL BGCOLOR - for cellSpacing
22563 					if ($this->ColActive) {
22564 						if ($table['borders_separate']) {
22565 							$fill = isset($table['bgcolor'][-1]) ? $table['bgcolor'][-1] : 0;
22566 							if ($fill) {
22567 								$color = $this->colorConverter->convert($fill, $this->PDFAXwarnings);
22568 								if ($color) {
22569 									$xadj = ($table['border_spacing_H'] / 2);
22570 									$yadj = ($table['border_spacing_V'] / 2);
22571 									$wadj = $table['border_spacing_H'];
22572 									$hadj = $table['border_spacing_V'];
22573 									if ($i == 0) {  // Top
22574 										$yadj += $table['padding']['T'] + $table['border_details']['T']['w'];
22575 										$hadj += $table['padding']['T'] + $table['border_details']['T']['w'];
22576 									}
22577 									if ($j == 0) {  // Left
22578 										$xadj += $table['padding']['L'] + $table['border_details']['L']['w'];
22579 										$wadj += $table['padding']['L'] + $table['border_details']['L']['w'];
22580 									}
22581 									if ($i == ($numrows - 1) || (isset($cell['rowspan']) && ($i + $cell['rowspan']) == $numrows) || (!isset($cell['rowspan']) && ($i + 1) == $numrows)) { // Bottom
22582 										$hadj += $table['padding']['B'] + $table['border_details']['B']['w'];
22583 									}
22584 									if ($j == ($numcols - 1) || (isset($cell['colspan']) && ($j + $cell['colspan']) == $numcols) || (!isset($cell['colspan']) && ($j + 1) == $numcols)) { // Right
22585 										$wadj += $table['padding']['R'] + $table['border_details']['R']['w'];
22586 									}
22587 									$this->SetFColor($color);
22588 									$this->Rect($x - $xadj, $y - $yadj, $w + $wadj, $h + $hadj, 'F');
22589 								}
22590 							}
22591 						}
22592 					}
22593 					/* -- END COLUMNS -- */
22594 
22595 					if ($table['empty_cells'] != 'hide' || !empty($cell['textbuffer']) || (isset($cell['nestedcontent']) && $cell['nestedcontent']) || !$table['borders_separate']) {
22596 						$paintcell = true;
22597 					} else {
22598 						$paintcell = false;
22599 					}
22600 
22601 					// Set Borders
22602 					$bord = 0;
22603 					$bord_det = [];
22604 
22605 					if (!$this->simpleTables) {
22606 						if ($this->packTableData) {
22607 							$c = $this->_unpackCellBorder($cell['borderbin']);
22608 							$bord = $c['border'];
22609 							$bord_det = $c['border_details'];
22610 						} else {
22611 							$bord = $cell['border'];
22612 							$bord_det = $cell['border_details'];
22613 						}
22614 					} elseif ($this->simpleTables) {
22615 						$bord = $table['simple']['border'];
22616 						$bord_det = $table['simple']['border_details'];
22617 					}
22618 
22619 					// TABLE ROW OR CELL FILL BGCOLOR
22620 					$fill = 0;
22621 					if (isset($cell['bgcolor']) && $cell['bgcolor'] && $cell['bgcolor'] != 'transparent') {
22622 						$fill = $cell['bgcolor'];
22623 						$leveladj = 6;
22624 					} elseif (isset($table['bgcolor'][$i]) && $table['bgcolor'][$i] && $table['bgcolor'][$i] != 'transparent') { // Row color
22625 						$fill = $table['bgcolor'][$i];
22626 						$leveladj = 3;
22627 					}
22628 					if ($fill && $paintcell) {
22629 						$color = $this->colorConverter->convert($fill, $this->PDFAXwarnings);
22630 						if ($color) {
22631 							if ($table['borders_separate']) {
22632 								if ($this->ColActive) {
22633 									$this->SetFColor($color);
22634 									$this->Rect($x + ($table['border_spacing_H'] / 2), $y + ($table['border_spacing_V'] / 2), $w - $table['border_spacing_H'], $h - $table['border_spacing_V'], 'F');
22635 								} else {
22636 									$this->tableBackgrounds[$level * 9 + $leveladj][] = ['gradient' => false, 'x' => ($x + ($table['border_spacing_H'] / 2)), 'y' => ($y + ($table['border_spacing_V'] / 2)), 'w' => ($w - $table['border_spacing_H']), 'h' => ($h - $table['border_spacing_V']), 'col' => $color];
22637 								}
22638 							} else {
22639 								if ($this->ColActive) {
22640 									$this->SetFColor($color);
22641 									$this->Rect($x, $y, $w, $h, 'F');
22642 								} else {
22643 									$this->tableBackgrounds[$level * 9 + $leveladj][] = ['gradient' => false, 'x' => $x, 'y' => $y, 'w' => $w, 'h' => $h, 'col' => $color];
22644 								}
22645 							}
22646 						}
22647 					}
22648 
22649 					/* -- BACKGROUNDS -- */
22650 					if (isset($cell['gradient']) && $cell['gradient'] && $paintcell) {
22651 						$g = $this->gradient->parseBackgroundGradient($cell['gradient']);
22652 						if ($g) {
22653 							if ($table['borders_separate']) {
22654 								$px = $x + ($table['border_spacing_H'] / 2);
22655 								$py = $y + ($table['border_spacing_V'] / 2);
22656 								$pw = $w - $table['border_spacing_H'];
22657 								$ph = $h - $table['border_spacing_V'];
22658 							} else {
22659 								$px = $x;
22660 								$py = $y;
22661 								$pw = $w;
22662 								$ph = $h;
22663 							}
22664 							if ($this->ColActive) {
22665 								$this->gradient->Gradient($px, $py, $pw, $ph, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend']);
22666 							} else {
22667 								$this->tableBackgrounds[$level * 9 + 7][] = ['gradient' => true, 'x' => $px, 'y' => $py, 'w' => $pw, 'h' => $ph, 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => ''];
22668 							}
22669 						}
22670 					}
22671 
22672 					if (isset($cell['background-image']) && $paintcell) {
22673 						if (isset($cell['background-image']['gradient']) && $cell['background-image']['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $cell['background-image']['gradient'])) {
22674 							$g = $this->gradient->parseMozGradient($cell['background-image']['gradient']);
22675 							if ($g) {
22676 								if ($table['borders_separate']) {
22677 									$px = $x + ($table['border_spacing_H'] / 2);
22678 									$py = $y + ($table['border_spacing_V'] / 2);
22679 									$pw = $w - $table['border_spacing_H'];
22680 									$ph = $h - $table['border_spacing_V'];
22681 								} else {
22682 									$px = $x;
22683 									$py = $y;
22684 									$pw = $w;
22685 									$ph = $h;
22686 								}
22687 								if ($this->ColActive) {
22688 									$this->gradient->Gradient($px, $py, $pw, $ph, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend']);
22689 								} else {
22690 									$this->tableBackgrounds[$level * 9 + 7][] = ['gradient' => true, 'x' => $px, 'y' => $py, 'w' => $pw, 'h' => $ph, 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => ''];
22691 								}
22692 							}
22693 						} elseif (isset($cell['background-image']['image_id']) && $cell['background-image']['image_id']) { // Background pattern
22694 							$n = count($this->patterns) + 1;
22695 							if ($table['borders_separate']) {
22696 								$px = $x + ($table['border_spacing_H'] / 2);
22697 								$py = $y + ($table['border_spacing_V'] / 2);
22698 								$pw = $w - $table['border_spacing_H'];
22699 								$ph = $h - $table['border_spacing_V'];
22700 							} else {
22701 								$px = $x;
22702 								$py = $y;
22703 								$pw = $w;
22704 								$ph = $h;
22705 							}
22706 							if ($this->ColActive) {
22707 								list($orig_w, $orig_h, $x_repeat, $y_repeat) = $this->_resizeBackgroundImage($cell['background-image']['orig_w'], $cell['background-image']['orig_h'], $pw, $ph, $cell['background-image']['resize'], $cell['background-image']['x_repeat'], $cell['background-image']['y_repeat']);
22708 								$this->patterns[$n] = ['x' => $px, 'y' => $py, 'w' => $pw, 'h' => $ph, 'pgh' => $this->h, 'image_id' => $cell['background-image']['image_id'], 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $cell['background-image']['x_pos'], 'y_pos' => $cell['background-image']['y_pos'], 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat];
22709 								if ($cell['background-image']['opacity'] > 0 && $cell['background-image']['opacity'] < 1) {
22710 									$opac = $this->SetAlpha($cell['background-image']['opacity'], 'Normal', true);
22711 								} else {
22712 									$opac = '';
22713 								}
22714 								$this->writer->write(sprintf('q /Pattern cs /P%d scn %s %.3F %.3F %.3F %.3F re f Q', $n, $opac, $px * Mpdf::SCALE, ($this->h - $py) * Mpdf::SCALE, $pw * Mpdf::SCALE, -$ph * Mpdf::SCALE));
22715 							} else {
22716 								$image_id = $cell['background-image']['image_id'];
22717 								$orig_w = $cell['background-image']['orig_w'];
22718 								$orig_h = $cell['background-image']['orig_h'];
22719 								$x_pos = $cell['background-image']['x_pos'];
22720 								$y_pos = $cell['background-image']['y_pos'];
22721 								$x_repeat = $cell['background-image']['x_repeat'];
22722 								$y_repeat = $cell['background-image']['y_repeat'];
22723 								$resize = $cell['background-image']['resize'];
22724 								$opacity = $cell['background-image']['opacity'];
22725 								$itype = $cell['background-image']['itype'];
22726 								$this->tableBackgrounds[$level * 9 + 8][] = ['x' => $px, 'y' => $py, 'w' => $pw, 'h' => $ph, 'image_id' => $image_id, 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $x_pos, 'y_pos' => $y_pos, 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat, 'clippath' => '', 'resize' => $resize, 'opacity' => $opacity, 'itype' => $itype];
22727 							}
22728 						}
22729 					}
22730 					/* -- END BACKGROUNDS -- */
22731 
22732 					if (isset($cell['colspan']) && $cell['colspan'] > 1) {
22733 						$ccolsp = $cell['colspan'];
22734 					} else {
22735 						$ccolsp = 1;
22736 					}
22737 					if (isset($cell['rowspan']) && $cell['rowspan'] > 1) {
22738 						$crowsp = $cell['rowspan'];
22739 					} else {
22740 						$crowsp = 1;
22741 					}
22742 
22743 
22744 					// but still need to do this for repeated headers...
22745 					if (!$table['borders_separate'] && $this->tabletheadjustfinished && !$this->simpleTables) {
22746 						if (isset($table['topntail']) && $table['topntail']) {
22747 							$bord_det['T'] = $this->border_details($table['topntail']);
22748 							$bord_det['T']['w'] /= $this->shrin_k;
22749 							$this->setBorder($bord, Border::TOP);
22750 						}
22751 						if (isset($table['thead-underline']) && $table['thead-underline']) {
22752 							$bord_det['T'] = $this->border_details($table['thead-underline']);
22753 							$bord_det['T']['w'] /= $this->shrin_k;
22754 							$this->setBorder($bord, Border::TOP);
22755 						}
22756 					}
22757 
22758 
22759 					// Get info of first row ==>> table header
22760 					// Use > 1 row if THEAD
22761 					if (isset($table['is_thead'][$i]) && $table['is_thead'][$i] && $level == 1) {
22762 						if ($j == 0) {
22763 							$tableheaderrowheight += $table['hr'][$i];
22764 						}
22765 						$tableheader[$i][0]['trbackground-images'] = (isset($table['trbackground-images'][$i]) ? $table['trbackground-images'][$i] : null);
22766 						$tableheader[$i][0]['trgradients'] = (isset($table['trgradients'][$i]) ? $table['trgradients'][$i] : null);
22767 						$tableheader[$i][0]['trbgcolor'] = (isset($table['bgcolor'][$i]) ? $table['bgcolor'][$i] : null);
22768 						$tableheader[$i][$j]['x'] = $x;
22769 						$tableheader[$i][$j]['y'] = $y;
22770 						$tableheader[$i][$j]['h'] = $h;
22771 						$tableheader[$i][$j]['w'] = $w;
22772 						if (isset($cell['textbuffer'])) {
22773 							$tableheader[$i][$j]['textbuffer'] = $cell['textbuffer'];
22774 						} else {
22775 							$tableheader[$i][$j]['textbuffer'] = '';
22776 						}
22777 						$tableheader[$i][$j]['a'] = $cell['a'];
22778 						$tableheader[$i][$j]['R'] = $cell['R'];
22779 
22780 						$tableheader[$i][$j]['va'] = $cell['va'];
22781 						$tableheader[$i][$j]['mih'] = $cell['mih'];
22782 						$tableheader[$i][$j]['gradient'] = (isset($cell['gradient']) ? $cell['gradient'] : null); // *BACKGROUNDS*
22783 						$tableheader[$i][$j]['background-image'] = (isset($cell['background-image']) ? $cell['background-image'] : null); // *BACKGROUNDS*
22784 						$tableheader[$i][$j]['rowspan'] = (isset($cell['rowspan']) ? $cell['rowspan'] : null);
22785 						$tableheader[$i][$j]['colspan'] = (isset($cell['colspan']) ? $cell['colspan'] : null);
22786 						$tableheader[$i][$j]['bgcolor'] = $cell['bgcolor'];
22787 
22788 						if (!$this->simpleTables) {
22789 							$tableheader[$i][$j]['border'] = $bord;
22790 							$tableheader[$i][$j]['border_details'] = $bord_det;
22791 						} elseif ($this->simpleTables) {
22792 							$tableheader[$i][$j]['border'] = $table['simple']['border'];
22793 							$tableheader[$i][$j]['border_details'] = $table['simple']['border_details'];
22794 						}
22795 						$tableheader[$i][$j]['padding'] = $cell['padding'];
22796 						if (isset($cell['direction'])) {
22797 							$tableheader[$i][$j]['direction'] = $cell['direction'];
22798 						}
22799 						if (isset($cell['cellLineHeight'])) {
22800 							$tableheader[$i][$j]['cellLineHeight'] = $cell['cellLineHeight'];
22801 						}
22802 						if (isset($cell['cellLineStackingStrategy'])) {
22803 							$tableheader[$i][$j]['cellLineStackingStrategy'] = $cell['cellLineStackingStrategy'];
22804 						}
22805 						if (isset($cell['cellLineStackingShift'])) {
22806 							$tableheader[$i][$j]['cellLineStackingShift'] = $cell['cellLineStackingShift'];
22807 						}
22808 					}
22809 
22810 					// CELL BORDER
22811 					if ($bord) {
22812 						if ($table['borders_separate'] && $paintcell) {
22813 							$this->_tableRect($x + ($table['border_spacing_H'] / 2) + ($bord_det['L']['w'] / 2), $y + ($table['border_spacing_V'] / 2) + ($bord_det['T']['w'] / 2), $w - $table['border_spacing_H'] - ($bord_det['L']['w'] / 2) - ($bord_det['R']['w'] / 2), $h - $table['border_spacing_V'] - ($bord_det['T']['w'] / 2) - ($bord_det['B']['w'] / 2), $bord, $bord_det, false, $table['borders_separate']);
22814 						} elseif (!$table['borders_separate']) {
22815 							$this->_tableRect($x, $y, $w, $h, $bord, $bord_det, true, $table['borders_separate']);  // true causes buffer
22816 						}
22817 					}
22818 
22819 					// VERTICAL ALIGN
22820 					if ($cell['R'] && intval($cell['R']) > 0 && intval($cell['R']) < 90 && isset($cell['va']) && $cell['va'] != 'B') {
22821 						$cell['va'] = 'B';
22822 					}
22823 					if (!isset($cell['va']) || $cell['va'] == 'M') {
22824 						$this->y += ($h - $cell['mih']) / 2;
22825 					} elseif (isset($cell['va']) && $cell['va'] == 'B') {
22826 						$this->y += $h - $cell['mih'];
22827 					}
22828 
22829 					// NESTED CONTENT
22830 					// TEXT (and nested tables)
22831 
22832 					$this->divwidth = $w;
22833 					if (!empty($cell['textbuffer'])) {
22834 						$this->cellTextAlign = $align;
22835 						$this->cellLineHeight = $cell['cellLineHeight'];
22836 						$this->cellLineStackingStrategy = $cell['cellLineStackingStrategy'];
22837 						$this->cellLineStackingShift = $cell['cellLineStackingShift'];
22838 						if ($level == 1) {
22839 							if (isset($table['is_tfoot'][$i]) && $table['is_tfoot'][$i]) {
22840 								if (preg_match('/{colsum([0-9]*)[_]*}/', $cell['textbuffer'][0][0], $m)) {
22841 									$rep = sprintf("%01." . intval($m[1]) . "f", $this->colsums[$j]);
22842 									$cell['textbuffer'][0][0] = preg_replace('/{colsum[0-9_]*}/', $rep, $cell['textbuffer'][0][0]);
22843 								}
22844 							} elseif (!isset($table['is_thead'][$i])) {
22845 								if (isset($this->colsums[$j])) {
22846 									$this->colsums[$j] += $this->toFloat($cell['textbuffer'][0][0]);
22847 								} else {
22848 									$this->colsums[$j] = $this->toFloat($cell['textbuffer'][0][0]);
22849 								}
22850 							}
22851 						}
22852 						$opy = $this->y;
22853 						// mPDF ITERATION
22854 						if ($this->iterationCounter) {
22855 							foreach ($cell['textbuffer'] as $k => $t) {
22856 								if (preg_match('/{iteration ([a-zA-Z0-9_]+)}/', $t[0], $m)) {
22857 									$vname = '__' . $m[1] . '_';
22858 									if (!isset($this->$vname)) {
22859 										$this->$vname = 1;
22860 									} else {
22861 										$this->$vname++;
22862 									}
22863 									$cell['textbuffer'][$k][0] = preg_replace('/{iteration ' . $m[1] . '}/', $this->$vname, $cell['textbuffer'][$k][0]);
22864 								}
22865 							}
22866 						}
22867 
22868 
22869 						if ($cell['R']) {
22870 							$cellPtSize = $cell['textbuffer'][0][11] / $this->shrin_k;
22871 							if (!$cellPtSize) {
22872 								$cellPtSize = $this->default_font_size;
22873 							}
22874 							$cellFontHeight = ($cellPtSize / Mpdf::SCALE);
22875 							$opx = $this->x;
22876 							$angle = intval($cell['R']);
22877 							// Only allow 45 to 89 degrees (when bottom-aligned) or exactly 90 or -90
22878 							if ($angle > 90) {
22879 								$angle = 90;
22880 							} elseif ($angle > 0 && $angle < 45) {
22881 								$angle = 45;
22882 							} elseif ($angle < 0) {
22883 								$angle = -90;
22884 							}
22885 							$offset = ((sin(deg2rad($angle))) * 0.37 * $cellFontHeight);
22886 							if (isset($cell['a']) && $cell['a'] == 'R') {
22887 								$this->x += ($w) + ($offset) - ($cellFontHeight / 3) - ($cell['padding']['R'] + ($table['border_spacing_H'] / 2));
22888 							} elseif (!isset($cell['a']) || $cell['a'] == 'C') {
22889 								$this->x += ($w / 2) + ($offset);
22890 							} else {
22891 								$this->x += ($offset) + ($cellFontHeight / 3) + ($cell['padding']['L'] + ($table['border_spacing_H'] / 2));
22892 							}
22893 							$str = '';
22894 							foreach ($cell['textbuffer'] as $t) {
22895 								$str .= $t[0] . ' ';
22896 							}
22897 							$str = rtrim($str);
22898 							if (!isset($cell['va']) || $cell['va'] == 'M') {
22899 								$this->y -= ($h - $cell['mih']) / 2; // Undo what was added earlier VERTICAL ALIGN
22900 								if ($angle > 0) {
22901 									$this->y += (($h - $cell['mih']) / 2) + $cell['padding']['T'] + ($cell['mih'] - ($cell['padding']['T'] + $cell['padding']['B']));
22902 								} elseif ($angle < 0) {
22903 									$this->y += (($h - $cell['mih']) / 2) + ($cell['padding']['T'] + ($table['border_spacing_V'] / 2));
22904 								}
22905 							} elseif (isset($cell['va']) && $cell['va'] == 'B') {
22906 								$this->y -= $h - $cell['mih']; // Undo what was added earlier VERTICAL ALIGN
22907 								if ($angle > 0) {
22908 									$this->y += $h - ($cell['padding']['B'] + ($table['border_spacing_V'] / 2));
22909 								} elseif ($angle < 0) {
22910 									$this->y += $h - $cell['mih'] + ($cell['padding']['T'] + ($table['border_spacing_V'] / 2));
22911 								}
22912 							} elseif (isset($cell['va']) && $cell['va'] == 'T') {
22913 								if ($angle > 0) {
22914 									$this->y += $cell['mih'] - ($cell['padding']['B'] + ($table['border_spacing_V'] / 2));
22915 								} elseif ($angle < 0) {
22916 									$this->y += ($cell['padding']['T'] + ($table['border_spacing_V'] / 2));
22917 								}
22918 							}
22919 							$this->Rotate($angle, $this->x, $this->y);
22920 							$s_fs = $this->FontSizePt;
22921 							$s_f = $this->FontFamily;
22922 							$s_st = $this->FontStyle;
22923 							if (!empty($cell['textbuffer'][0][3])) { // Font Color
22924 								$cor = $cell['textbuffer'][0][3];
22925 								$this->SetTColor($cor);
22926 							}
22927 							$this->SetFont($cell['textbuffer'][0][4], $cell['textbuffer'][0][2], $cellPtSize, true, true);
22928 
22929 							$this->magic_reverse_dir($str, $this->directionality, $cell['textbuffer'][0][18]);
22930 							$this->Text($this->x, $this->y, $str, $cell['textbuffer'][0][18], $cell['textbuffer'][0][8]); // textvar
22931 							$this->Rotate(0);
22932 							$this->SetFont($s_f, $s_st, $s_fs, true, true);
22933 							$this->SetTColor(0);
22934 							$this->x = $opx;
22935 						} else {
22936 							if (!$this->simpleTables) {
22937 								if ($bord_det) {
22938 									$btlw = $bord_det['L']['w'];
22939 									$btrw = $bord_det['R']['w'];
22940 									$bttw = $bord_det['T']['w'];
22941 								} else {
22942 									$btlw = 0;
22943 									$btrw = 0;
22944 									$bttw = 0;
22945 								}
22946 								if ($table['borders_separate']) {
22947 									$xadj = $btlw + $cell['padding']['L'] + ($table['border_spacing_H'] / 2);
22948 									$wadj = $btlw + $btrw + $cell['padding']['L'] + $cell['padding']['R'] + $table['border_spacing_H'];
22949 									$yadj = $bttw + $cell['padding']['T'] + ($table['border_spacing_H'] / 2);
22950 								} else {
22951 									$xadj = $btlw / 2 + $cell['padding']['L'];
22952 									$wadj = ($btlw + $btrw) / 2 + $cell['padding']['L'] + $cell['padding']['R'];
22953 									$yadj = $bttw / 2 + $cell['padding']['T'];
22954 								}
22955 							} elseif ($this->simpleTables) {
22956 								if ($table['borders_separate']) { // NB twice border width
22957 									$xadj = $table['simple']['border_details']['L']['w'] + $cell['padding']['L'] + ($table['border_spacing_H'] / 2);
22958 									$wadj = $table['simple']['border_details']['L']['w'] + $table['simple']['border_details']['R']['w'] + $cell['padding']['L'] + $cell['padding']['R'] + $table['border_spacing_H'];
22959 									$yadj = $table['simple']['border_details']['T']['w'] + $cell['padding']['T'] + ($table['border_spacing_H'] / 2);
22960 								} else {
22961 									$xadj = $table['simple']['border_details']['L']['w'] / 2 + $cell['padding']['L'];
22962 									$wadj = ($table['simple']['border_details']['L']['w'] + $table['simple']['border_details']['R']['w']) / 2 + $cell['padding']['L'] + $cell['padding']['R'];
22963 									$yadj = $table['simple']['border_details']['T']['w'] / 2 + $cell['padding']['T'];
22964 								}
22965 							}
22966 							$this->decimal_offset = 0;
22967 							if (substr($cell['a'], 0, 1) == 'D') {
22968 								if (isset($cell['colspan']) && $cell['colspan'] > 1) {
22969 									$this->cellTextAlign = $c['a'] = substr($cell['a'], 2, 1);
22970 								} else {
22971 									$smax = $table['decimal_align'][$j]['maxs0'];
22972 									$d_content = $table['decimal_align'][$j]['maxs0'] + $table['decimal_align'][$j]['maxs1'];
22973 									$this->decimal_offset = $smax;
22974 									$extra = ($w - $d_content - $wadj);
22975 									if ($extra > 0) {
22976 										if (substr($cell['a'], 2, 1) == 'R') {
22977 											$this->decimal_offset += $extra;
22978 										} elseif (substr($cell['a'], 2, 1) == 'C') {
22979 											$this->decimal_offset += ($extra) / 2;
22980 										}
22981 									}
22982 								}
22983 							}
22984 							$this->divwidth = $w - $wadj;
22985 							if ($this->divwidth == 0) {
22986 								$this->divwidth = 0.0001;
22987 							}
22988 							$this->x += $xadj;
22989 							$this->y += $yadj;
22990 							$this->printbuffer($cell['textbuffer'], '', true, false, $cell['direction']);
22991 						}
22992 						$this->y = $opy;
22993 					}
22994 
22995 					/* -- BACKGROUNDS -- */
22996 					if (!$this->ColActive) {
22997 						if (isset($table['trgradients'][$i]) && ($j == 0 || $table['borders_separate'])) {
22998 							$g = $this->gradient->parseBackgroundGradient($table['trgradients'][$i]);
22999 							if ($g) {
23000 								$gx = $x0;
23001 								$gy = $y;
23002 								$gh = $h;
23003 								$gw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
23004 								if ($table['borders_separate']) {
23005 									$gw -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['padding']['R'] + $table['border_details']['R']['w'] + $table['border_spacing_H']);
23006 									$clx = $x + ($table['border_spacing_H'] / 2);
23007 									$cly = $y + ($table['border_spacing_V'] / 2);
23008 									$clw = $w - $table['border_spacing_H'];
23009 									$clh = $h - $table['border_spacing_V'];
23010 									// Set clipping path
23011 									$s = $this->_setClippingPath($clx, $cly, $clw, $clh); // mPDF 6
23012 									$this->tableBackgrounds[$level * 9 + 4][] = ['gradient' => true, 'x' => $gx + ($table['border_spacing_H'] / 2), 'y' => $gy + ($table['border_spacing_V'] / 2), 'w' => $gw - $table['border_spacing_V'], 'h' => $gh - $table['border_spacing_H'], 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => $s];
23013 								} else {
23014 									$this->tableBackgrounds[$level * 9 + 4][] = ['gradient' => true, 'x' => $gx, 'y' => $gy, 'w' => $gw, 'h' => $gh, 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => ''];
23015 								}
23016 							}
23017 						}
23018 						if (isset($table['trbackground-images'][$i]) && ($j == 0 || $table['borders_separate'])) {
23019 							if (isset($table['trbackground-images'][$i]['gradient']) && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $table['trbackground-images'][$i]['gradient'])) {
23020 								$g = $this->gradient->parseMozGradient($table['trbackground-images'][$i]['gradient']);
23021 								if ($g) {
23022 									$gx = $x0;
23023 									$gy = $y;
23024 									$gh = $h;
23025 									$gw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
23026 									if ($table['borders_separate']) {
23027 										$gw -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['padding']['R'] + $table['border_details']['R']['w'] + $table['border_spacing_H']);
23028 										$clx = $x + ($table['border_spacing_H'] / 2);
23029 										$cly = $y + ($table['border_spacing_V'] / 2);
23030 										$clw = $w - $table['border_spacing_H'];
23031 										$clh = $h - $table['border_spacing_V'];
23032 										// Set clipping path
23033 										$s = $this->_setClippingPath($clx, $cly, $clw, $clh); // mPDF 6
23034 										$this->tableBackgrounds[$level * 9 + 4][] = ['gradient' => true, 'x' => $gx + ($table['border_spacing_H'] / 2), 'y' => $gy + ($table['border_spacing_V'] / 2), 'w' => $gw - $table['border_spacing_V'], 'h' => $gh - $table['border_spacing_H'], 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => $s];
23035 									} else {
23036 										$this->tableBackgrounds[$level * 9 + 4][] = ['gradient' => true, 'x' => $gx, 'y' => $gy, 'w' => $gw, 'h' => $gh, 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => ''];
23037 									}
23038 								}
23039 							} else {
23040 								$image_id = $table['trbackground-images'][$i]['image_id'];
23041 								$orig_w = $table['trbackground-images'][$i]['orig_w'];
23042 								$orig_h = $table['trbackground-images'][$i]['orig_h'];
23043 								$x_pos = $table['trbackground-images'][$i]['x_pos'];
23044 								$y_pos = $table['trbackground-images'][$i]['y_pos'];
23045 								$x_repeat = $table['trbackground-images'][$i]['x_repeat'];
23046 								$y_repeat = $table['trbackground-images'][$i]['y_repeat'];
23047 								$resize = $table['trbackground-images'][$i]['resize'];
23048 								$opacity = $table['trbackground-images'][$i]['opacity'];
23049 								$itype = $table['trbackground-images'][$i]['itype'];
23050 								$clippath = '';
23051 								$gx = $x0;
23052 								$gy = $y;
23053 								$gh = $h;
23054 								$gw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
23055 								if ($table['borders_separate']) {
23056 									$gw -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['padding']['R'] + $table['border_details']['R']['w'] + $table['border_spacing_H']);
23057 									$clx = $x + ($table['border_spacing_H'] / 2);
23058 									$cly = $y + ($table['border_spacing_V'] / 2);
23059 									$clw = $w - $table['border_spacing_H'];
23060 									$clh = $h - $table['border_spacing_V'];
23061 									// Set clipping path
23062 									$s = $this->_setClippingPath($clx, $cly, $clw, $clh); // mPDF 6
23063 									$this->tableBackgrounds[$level * 9 + 5][] = ['x' => $gx + ($table['border_spacing_H'] / 2), 'y' => $gy + ($table['border_spacing_V'] / 2), 'w' => $gw - $table['border_spacing_V'], 'h' => $gh - $table['border_spacing_H'], 'image_id' => $image_id, 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $x_pos, 'y_pos' => $y_pos, 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat, 'clippath' => $s, 'resize' => $resize, 'opacity' => $opacity, 'itype' => $itype];
23064 								} else {
23065 									$this->tableBackgrounds[$level * 9 + 5][] = ['x' => $gx, 'y' => $gy, 'w' => $gw, 'h' => $gh, 'image_id' => $image_id, 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $x_pos, 'y_pos' => $y_pos, 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat, 'clippath' => '', 'resize' => $resize, 'opacity' => $opacity, 'itype' => $itype];
23066 								}
23067 							}
23068 						}
23069 					}
23070 
23071 					/* -- END BACKGROUNDS -- */
23072 
23073 					// TABLE BORDER - if separate
23074 					if (($table['borders_separate'] || ($this->simpleTables && !$table['simple']['border'])) && $table['border']) {
23075 						$halfspaceL = $table['padding']['L'] + ($table['border_spacing_H'] / 2);
23076 						$halfspaceR = $table['padding']['R'] + ($table['border_spacing_H'] / 2);
23077 						$halfspaceT = $table['padding']['T'] + ($table['border_spacing_V'] / 2);
23078 						$halfspaceB = $table['padding']['B'] + ($table['border_spacing_V'] / 2);
23079 						$tbx = $x;
23080 						$tby = $y;
23081 						$tbw = $w;
23082 						$tbh = $h;
23083 						$tab_bord = 0;
23084 
23085 						$corner = '';
23086 						if ($i == 0) {  // Top
23087 							$tby -= $halfspaceT + ($table['border_details']['T']['w'] / 2);
23088 							$tbh += $halfspaceT + ($table['border_details']['T']['w'] / 2);
23089 							$this->setBorder($tab_bord, Border::TOP);
23090 							$corner .= 'T';
23091 						}
23092 						if ($i == ($numrows - 1) || (isset($cell['rowspan']) && ($i + $cell['rowspan']) == $numrows)) { // Bottom
23093 							$tbh += $halfspaceB + ($table['border_details']['B']['w'] / 2);
23094 							$this->setBorder($tab_bord, Border::BOTTOM);
23095 							$corner .= 'B';
23096 						}
23097 						if ($j == 0) {  // Left
23098 							$tbx -= $halfspaceL + ($table['border_details']['L']['w'] / 2);
23099 							$tbw += $halfspaceL + ($table['border_details']['L']['w'] / 2);
23100 							$this->setBorder($tab_bord, Border::LEFT);
23101 							$corner .= 'L';
23102 						}
23103 						if ($j == ($numcols - 1) || (isset($cell['colspan']) && ($j + $cell['colspan']) == $numcols)) { // Right
23104 							$tbw += $halfspaceR + ($table['border_details']['R']['w'] / 2);
23105 							$this->setBorder($tab_bord, Border::RIGHT);
23106 							$corner .= 'R';
23107 						}
23108 						$this->_tableRect($tbx, $tby, $tbw, $tbh, $tab_bord, $table['border_details'], false, $table['borders_separate'], 'table', $corner, $table['border_spacing_V'], $table['border_spacing_H']);
23109 					}
23110 
23111 					unset($cell);
23112 					// Reset values
23113 					$this->Reset();
23114 				}//end of (if isset(cells)...)
23115 			}// end of columns
23116 
23117 			$newpagestarted = false;
23118 			$this->tabletheadjustfinished = false;
23119 
23120 			/* -- COLUMNS -- */
23121 			if ($this->ColActive) {
23122 				if (!$this->table_keep_together && $i < $numrows - 1 && $level == 1) {
23123 					$this->breakpoints[$this->CurrCol][] = $y + $h;
23124 				} // mPDF 6
23125 				if (count($this->cellBorderBuffer)) {
23126 					$this->printcellbuffer();
23127 				}
23128 			}
23129 			/* -- END COLUMNS -- */
23130 
23131 			if ($i == $numrows - 1) {
23132 				$this->y = $y + $h;
23133 			} // last row jump (update this->y position)
23134 			if ($this->table_rotate && $level == 1) {
23135 				$this->tbrot_h += $h;
23136 			}
23137 		} // end of rows
23138 
23139 		if (count($this->cellBorderBuffer)) {
23140 			$this->printcellbuffer();
23141 		}
23142 
23143 
23144 		if ($this->tableClipPath) {
23145 			$this->writer->write("Q");
23146 		}
23147 		$this->tableClipPath = '';
23148 
23149 		// Advance down page by half width of bottom border
23150 		if ($table['borders_separate']) {
23151 			$this->y += $table['padding']['B'] + $table['border_details']['B']['w'] + $table['border_spacing_V'] / 2;
23152 		} else {
23153 			$this->y += $table['max_cell_border_width']['B'] / 2;
23154 		}
23155 
23156 		if ($table['borders_separate'] && $level == 1) {
23157 			$this->tbrot_h += $table['margin']['B'] + $table['padding']['B'] + $table['border_details']['B']['w'] + $table['border_spacing_V'] / 2;
23158 		} elseif ($level == 1) {
23159 			$this->tbrot_h += $table['margin']['B'] + $table['max_cell_border_width']['B'] / 2;
23160 		}
23161 
23162 		$bx = $x0;
23163 		$by = $y0;
23164 		if ($table['borders_separate']) {
23165 			$bx -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['border_spacing_H'] / 2);
23166 			if ($tablestartpageno != $this->page) { // IF broken across page
23167 				$by += $table['max_cell_border_width']['T'] / 2;
23168 				if (empty($tableheader)) {
23169 					$by -= ($table['border_spacing_V'] / 2);
23170 				}
23171 			} elseif ($split && $startrow > 0 && empty($tableheader)) {
23172 				$by -= ($table['border_spacing_V'] / 2);
23173 			} else {
23174 				$by -= ($table['padding']['T'] + $table['border_details']['T']['w'] + $table['border_spacing_V'] / 2);
23175 			}
23176 		} elseif ($tablestartpageno != $this->page && !empty($tableheader)) {
23177 			$by += $maxbwtop / 2;
23178 		}
23179 		$by -= $tableheaderadj;
23180 		$bh = $this->y - $by;
23181 		if (!$table['borders_separate']) {
23182 			$bh -= $table['max_cell_border_width']['B'] / 2;
23183 		}
23184 
23185 		if ($split) {
23186 			$bw = 0;
23187 			$finalSpread = true;
23188 			for ($t = $startcol; $t < $numcols; $t++) {
23189 				if ($table['colPg'][$t] == $splitpg) {
23190 					$bw += $table['wc'][$t];
23191 				}
23192 				if ($table['colPg'][$t] > $splitpg) {
23193 					$finalSpread = false;
23194 					break;
23195 				}
23196 			}
23197 			if ($startcol == 0) {
23198 				$firstSpread = true;
23199 			} else {
23200 				$firstSpread = false;
23201 			}
23202 			if ($table['borders_separate']) {
23203 				$bw += $table['border_spacing_H'];
23204 				if ($firstSpread) {
23205 					$bw += $table['padding']['L'] + $table['border_details']['L']['w'];
23206 				} else {
23207 					$bx += ($table['padding']['L'] + $table['border_details']['L']['w']);
23208 				}
23209 				if ($finalSpread) {
23210 					$bw += $table['padding']['R'] + $table['border_details']['R']['w'];
23211 				}
23212 			}
23213 		} else {
23214 			$bw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
23215 		}
23216 
23217 		if (!$this->ColActive) {
23218 			if (isset($table['bgcolor'][-1])) {
23219 				$color = $this->colorConverter->convert($table['bgcolor'][-1], $this->PDFAXwarnings);
23220 				if ($color) {
23221 					$this->tableBackgrounds[$level * 9][] = ['gradient' => false, 'x' => $bx, 'y' => $by, 'w' => $bw, 'h' => $bh, 'col' => $color];
23222 				}
23223 			}
23224 
23225 			/* -- BACKGROUNDS -- */
23226 			if (isset($table['gradient'])) {
23227 				$g = $this->gradient->parseBackgroundGradient($table['gradient']);
23228 				if ($g) {
23229 					$this->tableBackgrounds[$level * 9 + 1][] = ['gradient' => true, 'x' => $bx, 'y' => $by, 'w' => $bw, 'h' => $bh, 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => ''];
23230 				}
23231 			}
23232 
23233 			if (isset($table['background-image'])) {
23234 				if (isset($table['background-image']['gradient']) && $table['background-image']['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $table['background-image']['gradient'])) {
23235 					$g = $this->gradient->parseMozGradient($table['background-image']['gradient']);
23236 					if ($g) {
23237 						$this->tableBackgrounds[$level * 9 + 1][] = ['gradient' => true, 'x' => $bx, 'y' => $by, 'w' => $bw, 'h' => $bh, 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => ''];
23238 					}
23239 				} else {
23240 					$image_id = $table['background-image']['image_id'];
23241 					$orig_w = $table['background-image']['orig_w'];
23242 					$orig_h = $table['background-image']['orig_h'];
23243 					$x_pos = $table['background-image']['x_pos'];
23244 					$y_pos = $table['background-image']['y_pos'];
23245 					$x_repeat = $table['background-image']['x_repeat'];
23246 					$y_repeat = $table['background-image']['y_repeat'];
23247 					$resize = $table['background-image']['resize'];
23248 					$opacity = $table['background-image']['opacity'];
23249 					$itype = $table['background-image']['itype'];
23250 					$this->tableBackgrounds[$level * 9 + 2][] = ['x' => $bx, 'y' => $by, 'w' => $bw, 'h' => $bh, 'image_id' => $image_id, 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $x_pos, 'y_pos' => $y_pos, 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat, 'clippath' => '', 'resize' => $resize, 'opacity' => $opacity, 'itype' => $itype];
23251 				}
23252 			}
23253 			/* -- END BACKGROUNDS -- */
23254 		}
23255 
23256 		if ($this->tableBackgrounds && $level == 1) {
23257 			$s = $this->PrintTableBackgrounds();
23258 			if ($this->table_rotate && !$this->processingHeader && !$this->processingFooter) {
23259 				$this->tablebuffer = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->tablebuffer);
23260 				if ($level == 1) {
23261 					$this->tablebuffer = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', " ", $this->tablebuffer);
23262 				}
23263 			} elseif ($this->bufferoutput) {
23264 				$this->headerbuffer = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->headerbuffer);
23265 				if ($level == 1) {
23266 					$this->headerbuffer = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', " ", $this->headerbuffer);
23267 				}
23268 			} else {
23269 				$this->pages[$this->page] = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->pages[$this->page]);
23270 				if ($level == 1) {
23271 					$this->pages[$this->page] = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', " ", $this->pages[$this->page]);
23272 				}
23273 			}
23274 			$this->tableBackgrounds = [];
23275 		}
23276 
23277 
23278 		// TABLE BOTTOM MARGIN
23279 		if ($table['margin']['B']) {
23280 			if (!$this->table_rotate && $level == 1) {
23281 				$this->DivLn($table['margin']['B'], $this->blklvl, true);  // collapsible
23282 			} else {
23283 				$this->y += ($table['margin']['B']);
23284 			}
23285 		}
23286 
23287 		if ($this->ColActive && $level == 1) {
23288 			$this->breakpoints[$this->CurrCol][] = $this->y;
23289 		} // *COLUMNS*
23290 
23291 		if ($split) {
23292 			// Are there more columns to print on a next page?
23293 			if ($lastCol < $numcols - 1) {
23294 				$splitpg++;
23295 				$startcol = $lastCol + 1;
23296 				return [false, $startrow, $startcol, $splitpg, $returny, $y0];
23297 			} else {
23298 				return [true, 0, 0, 0, false, false];
23299 			}
23300 		}
23301 	}
23302 
23303 	// END OF FUNCTION _tableWrite()
23304 	/////////////////////////END OF TABLE CODE//////////////////////////////////
23305 	/* -- END TABLES -- */
23306 
23307 	function _putextgstates()
23308 	{
23309 		for ($i = 1; $i <= count($this->extgstates); $i++) {
23310 			$this->writer->object();
23311 			$this->extgstates[$i]['n'] = $this->n;
23312 			$this->writer->write('<</Type /ExtGState');
23313 			foreach ($this->extgstates[$i]['parms'] as $k => $v) {
23314 				$this->writer->write('/' . $k . ' ' . $v);
23315 			}
23316 			$this->writer->write('>>');
23317 			$this->writer->write('endobj');
23318 		}
23319 	}
23320 
23321 	function SetProtection($permissions = [], $user_pass = '', $owner_pass = null, $length = 40)
23322 	{
23323 		$this->encrypted = $this->protection->setProtection($permissions, $user_pass, $owner_pass, $length);
23324 	}
23325 
23326 	// =========================================
23327 	// FROM class PDF_Bookmark
23328 	function Bookmark($txt, $level = 0, $y = 0)
23329 	{
23330 		$txt = $this->purify_utf8_text($txt);
23331 		if ($this->text_input_as_HTML) {
23332 			$txt = $this->all_entities_to_utf8($txt);
23333 		}
23334 		if ($y == -1) {
23335 			if (!$this->ColActive) {
23336 				$y = $this->y;
23337 			} else {
23338 				$y = $this->y0;
23339 			} // If columns are on - mark top of columns
23340 		}
23341 
23342 		// else y is used as set, or =0 i.e. top of page
23343 		// DIRECTIONALITY RTL
23344 		$bmo = ['t' => $txt, 'l' => $level, 'y' => $y, 'p' => $this->page];
23345 
23346 		if ($this->keep_block_together) {
23347 			// do nothing
23348 		} elseif ($this->table_rotate) {
23349 			$this->tbrot_BMoutlines[] = $bmo;
23350 		} elseif ($this->kwt) {
23351 			$this->kwt_BMoutlines[] = $bmo;
23352 		} elseif ($this->ColActive) {
23353 			$this->col_BMoutlines[] = $bmo;
23354 		} else {
23355 			$this->BMoutlines[] = $bmo;
23356 		}
23357 	}
23358 
23359 	/**
23360 	 * Initiate, and Mark a place for the Table of Contents to be inserted
23361 	 */
23362 	function TOC(
23363 		$tocfont = '',
23364 		$tocfontsize = 0,
23365 		$tocindent = 0,
23366 		$resetpagenum = '',
23367 		$pagenumstyle = '',
23368 		$suppress = '',
23369 		$toc_orientation = '',
23370 		$TOCusePaging = true,
23371 		$TOCuseLinking = false,
23372 		$toc_id = 0,
23373 		$tocoutdent = ''
23374 	) {
23375 
23376 		$this->tableOfContents->TOC(
23377 			$tocfont,
23378 			$tocfontsize,
23379 			$tocindent,
23380 			$resetpagenum,
23381 			$pagenumstyle,
23382 			$suppress,
23383 			$toc_orientation,
23384 			$TOCusePaging,
23385 			$TOCuseLinking,
23386 			$toc_id,
23387 			$tocoutdent
23388 		);
23389 	}
23390 
23391 	function TOCpagebreakByArray($a)
23392 	{
23393 		if (!is_array($a)) {
23394 			$a = [];
23395 		}
23396 		$tocoutdent = (isset($a['tocoutdent']) ? $a['tocoutdent'] : (isset($a['outdent']) ? $a['outdent'] : ''));
23397 		$TOCusePaging = (isset($a['TOCusePaging']) ? $a['TOCusePaging'] : (isset($a['paging']) ? $a['paging'] : true));
23398 		$TOCuseLinking = (isset($a['TOCuseLinking']) ? $a['TOCuseLinking'] : (isset($a['links']) ? $a['links'] : ''));
23399 		$toc_orientation = (isset($a['toc_orientation']) ? $a['toc_orientation'] : (isset($a['toc-orientation']) ? $a['toc-orientation'] : ''));
23400 		$toc_mgl = (isset($a['toc_mgl']) ? $a['toc_mgl'] : (isset($a['toc-margin-left']) ? $a['toc-margin-left'] : ''));
23401 		$toc_mgr = (isset($a['toc_mgr']) ? $a['toc_mgr'] : (isset($a['toc-margin-right']) ? $a['toc-margin-right'] : ''));
23402 		$toc_mgt = (isset($a['toc_mgt']) ? $a['toc_mgt'] : (isset($a['toc-margin-top']) ? $a['toc-margin-top'] : ''));
23403 		$toc_mgb = (isset($a['toc_mgb']) ? $a['toc_mgb'] : (isset($a['toc-margin-bottom']) ? $a['toc-margin-bottom'] : ''));
23404 		$toc_mgh = (isset($a['toc_mgh']) ? $a['toc_mgh'] : (isset($a['toc-margin-header']) ? $a['toc-margin-header'] : ''));
23405 		$toc_mgf = (isset($a['toc_mgf']) ? $a['toc_mgf'] : (isset($a['toc-margin-footer']) ? $a['toc-margin-footer'] : ''));
23406 		$toc_ohname = (isset($a['toc_ohname']) ? $a['toc_ohname'] : (isset($a['toc-odd-header-name']) ? $a['toc-odd-header-name'] : ''));
23407 		$toc_ehname = (isset($a['toc_ehname']) ? $a['toc_ehname'] : (isset($a['toc-even-header-name']) ? $a['toc-even-header-name'] : ''));
23408 		$toc_ofname = (isset($a['toc_ofname']) ? $a['toc_ofname'] : (isset($a['toc-odd-footer-name']) ? $a['toc-odd-footer-name'] : ''));
23409 		$toc_efname = (isset($a['toc_efname']) ? $a['toc_efname'] : (isset($a['toc-even-footer-name']) ? $a['toc-even-footer-name'] : ''));
23410 		$toc_ohvalue = (isset($a['toc_ohvalue']) ? $a['toc_ohvalue'] : (isset($a['toc-odd-header-value']) ? $a['toc-odd-header-value'] : 0));
23411 		$toc_ehvalue = (isset($a['toc_ehvalue']) ? $a['toc_ehvalue'] : (isset($a['toc-even-header-value']) ? $a['toc-even-header-value'] : 0));
23412 		$toc_ofvalue = (isset($a['toc_ofvalue']) ? $a['toc_ofvalue'] : (isset($a['toc-odd-footer-value']) ? $a['toc-odd-footer-value'] : 0));
23413 		$toc_efvalue = (isset($a['toc_efvalue']) ? $a['toc_efvalue'] : (isset($a['toc-even-footer-value']) ? $a['toc-even-footer-value'] : 0));
23414 		$toc_preHTML = (isset($a['toc_preHTML']) ? $a['toc_preHTML'] : (isset($a['toc-preHTML']) ? $a['toc-preHTML'] : ''));
23415 		$toc_postHTML = (isset($a['toc_postHTML']) ? $a['toc_postHTML'] : (isset($a['toc-postHTML']) ? $a['toc-postHTML'] : ''));
23416 		$toc_bookmarkText = (isset($a['toc_bookmarkText']) ? $a['toc_bookmarkText'] : (isset($a['toc-bookmarkText']) ? $a['toc-bookmarkText'] : ''));
23417 		$resetpagenum = (isset($a['resetpagenum']) ? $a['resetpagenum'] : '');
23418 		$pagenumstyle = (isset($a['pagenumstyle']) ? $a['pagenumstyle'] : '');
23419 		$suppress = (isset($a['suppress']) ? $a['suppress'] : '');
23420 		$orientation = (isset($a['orientation']) ? $a['orientation'] : '');
23421 		$mgl = (isset($a['mgl']) ? $a['mgl'] : (isset($a['margin-left']) ? $a['margin-left'] : ''));
23422 		$mgr = (isset($a['mgr']) ? $a['mgr'] : (isset($a['margin-right']) ? $a['margin-right'] : ''));
23423 		$mgt = (isset($a['mgt']) ? $a['mgt'] : (isset($a['margin-top']) ? $a['margin-top'] : ''));
23424 		$mgb = (isset($a['mgb']) ? $a['mgb'] : (isset($a['margin-bottom']) ? $a['margin-bottom'] : ''));
23425 		$mgh = (isset($a['mgh']) ? $a['mgh'] : (isset($a['margin-header']) ? $a['margin-header'] : ''));
23426 		$mgf = (isset($a['mgf']) ? $a['mgf'] : (isset($a['margin-footer']) ? $a['margin-footer'] : ''));
23427 		$ohname = (isset($a['ohname']) ? $a['ohname'] : (isset($a['odd-header-name']) ? $a['odd-header-name'] : ''));
23428 		$ehname = (isset($a['ehname']) ? $a['ehname'] : (isset($a['even-header-name']) ? $a['even-header-name'] : ''));
23429 		$ofname = (isset($a['ofname']) ? $a['ofname'] : (isset($a['odd-footer-name']) ? $a['odd-footer-name'] : ''));
23430 		$efname = (isset($a['efname']) ? $a['efname'] : (isset($a['even-footer-name']) ? $a['even-footer-name'] : ''));
23431 		$ohvalue = (isset($a['ohvalue']) ? $a['ohvalue'] : (isset($a['odd-header-value']) ? $a['odd-header-value'] : 0));
23432 		$ehvalue = (isset($a['ehvalue']) ? $a['ehvalue'] : (isset($a['even-header-value']) ? $a['even-header-value'] : 0));
23433 		$ofvalue = (isset($a['ofvalue']) ? $a['ofvalue'] : (isset($a['odd-footer-value']) ? $a['odd-footer-value'] : 0));
23434 		$efvalue = (isset($a['efvalue']) ? $a['efvalue'] : (isset($a['even-footer-value']) ? $a['even-footer-value'] : 0));
23435 		$toc_id = (isset($a['toc_id']) ? $a['toc_id'] : (isset($a['name']) ? $a['name'] : 0));
23436 		$pagesel = (isset($a['pagesel']) ? $a['pagesel'] : (isset($a['pageselector']) ? $a['pageselector'] : ''));
23437 		$toc_pagesel = (isset($a['toc_pagesel']) ? $a['toc_pagesel'] : (isset($a['toc-pageselector']) ? $a['toc-pageselector'] : ''));
23438 		$sheetsize = (isset($a['sheetsize']) ? $a['sheetsize'] : (isset($a['sheet-size']) ? $a['sheet-size'] : ''));
23439 		$toc_sheetsize = (isset($a['toc_sheetsize']) ? $a['toc_sheetsize'] : (isset($a['toc-sheet-size']) ? $a['toc-sheet-size'] : ''));
23440 
23441 		$this->TOCpagebreak('', '', '', $TOCusePaging, $TOCuseLinking, $toc_orientation, $toc_mgl, $toc_mgr, $toc_mgt, $toc_mgb, $toc_mgh, $toc_mgf, $toc_ohname, $toc_ehname, $toc_ofname, $toc_efname, $toc_ohvalue, $toc_ehvalue, $toc_ofvalue, $toc_efvalue, $toc_preHTML, $toc_postHTML, $toc_bookmarkText, $resetpagenum, $pagenumstyle, $suppress, $orientation, $mgl, $mgr, $mgt, $mgb, $mgh, $mgf, $ohname, $ehname, $ofname, $efname, $ohvalue, $ehvalue, $ofvalue, $efvalue, $toc_id, $pagesel, $toc_pagesel, $sheetsize, $toc_sheetsize, $tocoutdent);
23442 	}
23443 
23444 	function TOCpagebreak($tocfont = '', $tocfontsize = '', $tocindent = '', $TOCusePaging = true, $TOCuseLinking = '', $toc_orientation = '', $toc_mgl = '', $toc_mgr = '', $toc_mgt = '', $toc_mgb = '', $toc_mgh = '', $toc_mgf = '', $toc_ohname = '', $toc_ehname = '', $toc_ofname = '', $toc_efname = '', $toc_ohvalue = 0, $toc_ehvalue = 0, $toc_ofvalue = 0, $toc_efvalue = 0, $toc_preHTML = '', $toc_postHTML = '', $toc_bookmarkText = '', $resetpagenum = '', $pagenumstyle = '', $suppress = '', $orientation = '', $mgl = '', $mgr = '', $mgt = '', $mgb = '', $mgh = '', $mgf = '', $ohname = '', $ehname = '', $ofname = '', $efname = '', $ohvalue = 0, $ehvalue = 0, $ofvalue = 0, $efvalue = 0, $toc_id = 0, $pagesel = '', $toc_pagesel = '', $sheetsize = '', $toc_sheetsize = '', $tocoutdent = '')
23445 	{
23446 		// Start a new page
23447 		if ($this->state == 0) {
23448 			$this->AddPage();
23449 		}
23450 		if ($this->y == $this->tMargin && (!$this->mirrorMargins || ($this->mirrorMargins && $this->page % 2 == 1))) {
23451 			// Don't add a page
23452 			if ($this->page == 1 && count($this->PageNumSubstitutions) == 0) {
23453 				if (!$suppress) {
23454 					$suppress = 'off';
23455 				}
23456 				// $this->PageNumSubstitutions[] = array('from'=>1, 'reset'=> $resetpagenum, 'type'=>$pagenumstyle, 'suppress'=> $suppress);
23457 			}
23458 			$this->PageNumSubstitutions[] = ['from' => $this->page, 'reset' => $resetpagenum, 'type' => $pagenumstyle, 'suppress' => $suppress];
23459 		} else {
23460 			$this->AddPage($orientation, 'NEXT-ODD', $resetpagenum, $pagenumstyle, $suppress, $mgl, $mgr, $mgt, $mgb, $mgh, $mgf, $ohname, $ehname, $ofname, $efname, $ohvalue, $ehvalue, $ofvalue, $efvalue, $pagesel, $sheetsize);
23461 		}
23462 		$this->tableOfContents->TOCpagebreak($tocfont, $tocfontsize, $tocindent, $TOCusePaging, $TOCuseLinking, $toc_orientation, $toc_mgl, $toc_mgr, $toc_mgt, $toc_mgb, $toc_mgh, $toc_mgf, $toc_ohname, $toc_ehname, $toc_ofname, $toc_efname, $toc_ohvalue, $toc_ehvalue, $toc_ofvalue, $toc_efvalue, $toc_preHTML, $toc_postHTML, $toc_bookmarkText, $resetpagenum, $pagenumstyle, $suppress, $orientation, $mgl, $mgr, $mgt, $mgb, $mgh, $mgf, $ohname, $ehname, $ofname, $efname, $ohvalue, $ehvalue, $ofvalue, $efvalue, $toc_id, $pagesel, $toc_pagesel, $sheetsize, $toc_sheetsize, $tocoutdent);
23463 	}
23464 
23465 	function TOC_Entry($txt, $level = 0, $toc_id = 0)
23466 	{
23467 		if ($this->ColActive) {
23468 			$ily = $this->y0;
23469 		} else {
23470 			$ily = $this->y;
23471 		} // use top of columns
23472 
23473 		$linkn = $this->AddLink();
23474 		$uid = '__mpdfinternallink_' . $linkn;
23475 		if ($this->table_rotate) {
23476 			$this->internallink[$uid] = ["Y" => $ily, "PAGE" => $this->page, "tbrot" => true];
23477 		} elseif ($this->kwt) {
23478 			$this->internallink[$uid] = ["Y" => $ily, "PAGE" => $this->page, "kwt" => true];
23479 		} elseif ($this->ColActive) {
23480 			$this->internallink[$uid] = ["Y" => $ily, "PAGE" => $this->page, "col" => $this->CurrCol];
23481 		} elseif (!$this->keep_block_together) {
23482 			$this->internallink[$uid] = ["Y" => $ily, "PAGE" => $this->page];
23483 		}
23484 		$this->internallink['#' . $uid] = $linkn;
23485 		$this->SetLink($linkn, $ily, $this->page);
23486 
23487 		if (strtoupper($toc_id) == 'ALL') {
23488 			$toc_id = '_mpdf_all';
23489 		} elseif (!$toc_id) {
23490 			$toc_id = 0;
23491 		} else {
23492 			$toc_id = strtolower($toc_id);
23493 		}
23494 		$btoc = ['t' => $txt, 'l' => $level, 'p' => $this->page, 'link' => $linkn, 'toc_id' => $toc_id];
23495 		if ($this->keep_block_together) {
23496 			// do nothing
23497 		} /* -- TABLES -- */ elseif ($this->table_rotate) {
23498 			$this->tbrot_toc[] = $btoc;
23499 		} elseif ($this->kwt) {
23500 			$this->kwt_toc[] = $btoc;
23501 		} /* -- END TABLES -- */ elseif ($this->ColActive) {  // *COLUMNS*
23502 			$this->col_toc[] = $btoc; // *COLUMNS*
23503 		} // *COLUMNS*
23504 		else {
23505 			$this->tableOfContents->_toc[] = $btoc;
23506 		}
23507 	}
23508 
23509 	/* -- END TOC -- */
23510 
23511 	// ======================================================
23512 	function MovePages($target_page, $start_page, $end_page = -1)
23513 	{
23514 		// move a page/pages EARLIER in the document
23515 		if ($end_page < 1) {
23516 			$end_page = $start_page;
23517 		}
23518 		$n_toc = $end_page - $start_page + 1;
23519 
23520 		// Set/Update PageNumSubstitutions changes before moving anything
23521 		if (count($this->PageNumSubstitutions)) {
23522 			$tp_present = false;
23523 			$sp_present = false;
23524 			$ep_present = false;
23525 			foreach ($this->PageNumSubstitutions as $k => $v) {
23526 				if ($this->PageNumSubstitutions[$k]['from'] == $target_page) {
23527 					$tp_present = true;
23528 					if ($this->PageNumSubstitutions[$k]['suppress'] != 'on' && $this->PageNumSubstitutions[$k]['suppress'] != 1) {
23529 						$this->PageNumSubstitutions[$k]['suppress'] = 'off';
23530 					}
23531 				}
23532 				if ($this->PageNumSubstitutions[$k]['from'] == $start_page) {
23533 					$sp_present = true;
23534 					if ($this->PageNumSubstitutions[$k]['suppress'] != 'on' && $this->PageNumSubstitutions[$k]['suppress'] != 1) {
23535 						$this->PageNumSubstitutions[$k]['suppress'] = 'off';
23536 					}
23537 				}
23538 				if ($this->PageNumSubstitutions[$k]['from'] == ($end_page + 1)) {
23539 					$ep_present = true;
23540 					if ($this->PageNumSubstitutions[$k]['suppress'] != 'on' && $this->PageNumSubstitutions[$k]['suppress'] != 1) {
23541 						$this->PageNumSubstitutions[$k]['suppress'] = 'off';
23542 					}
23543 				}
23544 			}
23545 
23546 			if (!$tp_present) {
23547 				list($tp_type, $tp_suppress, $tp_reset) = $this->docPageSettings($target_page);
23548 			}
23549 			if (!$sp_present) {
23550 				list($sp_type, $sp_suppress, $sp_reset) = $this->docPageSettings($start_page);
23551 			}
23552 			if (!$ep_present) {
23553 				list($ep_type, $ep_suppress, $ep_reset) = $this->docPageSettings($start_page - 1);
23554 			}
23555 		}
23556 
23557 		$last = [];
23558 		// store pages
23559 		for ($i = $start_page; $i <= $end_page; $i++) {
23560 			$last[] = $this->pages[$i];
23561 		}
23562 		// move pages
23563 		for ($i = $start_page - 1; $i >= ($target_page); $i--) {
23564 			$this->pages[$i + $n_toc] = $this->pages[$i];
23565 		}
23566 		// Put toc pages at insert point
23567 		for ($i = 0; $i < $n_toc; $i++) {
23568 			$this->pages[$target_page + $i] = $last[$i];
23569 		}
23570 
23571 		/* -- BOOKMARKS -- */
23572 		// Update Bookmarks
23573 		foreach ($this->BMoutlines as $i => $o) {
23574 			if ($o['p'] >= $target_page) {
23575 				$this->BMoutlines[$i]['p'] += $n_toc;
23576 			}
23577 		}
23578 		/* -- END BOOKMARKS -- */
23579 
23580 		// Update Page Links
23581 		if (count($this->PageLinks)) {
23582 			$newarr = [];
23583 			foreach ($this->PageLinks as $i => $o) {
23584 				foreach ($this->PageLinks[$i] as $key => $pl) {
23585 					if (strpos($pl[4], '@') === 0) {
23586 						$p = substr($pl[4], 1);
23587 						if ($p >= $start_page && $p <= $end_page) {
23588 							$this->PageLinks[$i][$key][4] = '@' . ($p + ($target_page - $start_page));
23589 						} elseif ($p >= $target_page && $p < $start_page) {
23590 							$this->PageLinks[$i][$key][4] = '@' . ($p + $n_toc);
23591 						}
23592 					}
23593 				}
23594 				if ($i >= $start_page && $i <= $end_page) {
23595 					$newarr[($i + ($target_page - $start_page))] = $this->PageLinks[$i];
23596 				} elseif ($i >= $target_page && $i < $start_page) {
23597 					$newarr[($i + $n_toc)] = $this->PageLinks[$i];
23598 				} else {
23599 					$newarr[$i] = $this->PageLinks[$i];
23600 				}
23601 			}
23602 			$this->PageLinks = $newarr;
23603 		}
23604 
23605 		// OrientationChanges
23606 		if (count($this->OrientationChanges)) {
23607 			$newarr = [];
23608 			foreach ($this->OrientationChanges as $p => $v) {
23609 				if ($p >= $start_page && $p <= $end_page) {
23610 					$newarr[($p + ($target_page - $start_page))] = $this->OrientationChanges[$p];
23611 				} elseif ($p >= $target_page && $p < $start_page) {
23612 					$newarr[$p + $n_toc] = $this->OrientationChanges[$p];
23613 				} else {
23614 					$newarr[$p] = $this->OrientationChanges[$p];
23615 				}
23616 			}
23617 			ksort($newarr);
23618 			$this->OrientationChanges = $newarr;
23619 		}
23620 
23621 		// Page Dimensions
23622 		if (count($this->pageDim)) {
23623 			$newarr = [];
23624 			foreach ($this->pageDim as $p => $v) {
23625 				if ($p >= $start_page && $p <= $end_page) {
23626 					$newarr[($p + ($target_page - $start_page))] = $this->pageDim[$p];
23627 				} elseif ($p >= $target_page && $p < $start_page) {
23628 					$newarr[$p + $n_toc] = $this->pageDim[$p];
23629 				} else {
23630 					$newarr[$p] = $this->pageDim[$p];
23631 				}
23632 			}
23633 			ksort($newarr);
23634 			$this->pageDim = $newarr;
23635 		}
23636 
23637 		// HTML Headers & Footers
23638 		if (count($this->saveHTMLHeader)) {
23639 			$newarr = [];
23640 			foreach ($this->saveHTMLHeader as $p => $v) {
23641 				if ($p >= $start_page && $p <= $end_page) {
23642 					$newarr[($p + ($target_page - $start_page))] = $this->saveHTMLHeader[$p];
23643 				} elseif ($p >= $target_page && $p < $start_page) {
23644 					$newarr[$p + $n_toc] = $this->saveHTMLHeader[$p];
23645 				} else {
23646 					$newarr[$p] = $this->saveHTMLHeader[$p];
23647 				}
23648 			}
23649 			ksort($newarr);
23650 			$this->saveHTMLHeader = $newarr;
23651 		}
23652 		if (count($this->saveHTMLFooter)) {
23653 			$newarr = [];
23654 			foreach ($this->saveHTMLFooter as $p => $v) {
23655 				if ($p >= $start_page && $p <= $end_page) {
23656 					$newarr[($p + ($target_page - $start_page))] = $this->saveHTMLFooter[$p];
23657 				} elseif ($p >= $target_page && $p < $start_page) {
23658 					$newarr[$p + $n_toc] = $this->saveHTMLFooter[$p];
23659 				} else {
23660 					$newarr[$p] = $this->saveHTMLFooter[$p];
23661 				}
23662 			}
23663 			ksort($newarr);
23664 			$this->saveHTMLFooter = $newarr;
23665 		}
23666 
23667 		// Update Internal Links
23668 		if (count($this->internallink)) {
23669 			foreach ($this->internallink as $key => $o) {
23670 				if (is_array($o) && $o['PAGE'] >= $start_page && $o['PAGE'] <= $end_page) {
23671 					$this->internallink[$key]['PAGE'] += ($target_page - $start_page);
23672 				} elseif (is_array($o) && $o['PAGE'] >= $target_page && $o['PAGE'] < $start_page) {
23673 					$this->internallink[$key]['PAGE'] += $n_toc;
23674 				}
23675 			}
23676 		}
23677 
23678 		// Update Links
23679 		if (count($this->links)) {
23680 			foreach ($this->links as $key => $o) {
23681 				if ($o[0] >= $start_page && $o[0] <= $end_page) {
23682 					$this->links[$key][0] += ($target_page - $start_page);
23683 				}
23684 				if ($o[0] >= $target_page && $o[0] < $start_page) {
23685 					$this->links[$key][0] += $n_toc;
23686 				}
23687 			}
23688 		}
23689 
23690 		// Update Form fields
23691 		if (count($this->form->forms)) {
23692 			foreach ($this->form->forms as $key => $f) {
23693 				if ($f['page'] >= $start_page && $f['page'] <= $end_page) {
23694 					$this->form->forms[$key]['page'] += ($target_page - $start_page);
23695 				}
23696 				if ($f['page'] >= $target_page && $f['page'] < $start_page) {
23697 					$this->form->forms[$key]['page'] += $n_toc;
23698 				}
23699 			}
23700 		}
23701 
23702 		/* -- ANNOTATIONS -- */
23703 		// Update Annotations
23704 		if (count($this->PageAnnots)) {
23705 			$newarr = [];
23706 			foreach ($this->PageAnnots as $p => $anno) {
23707 				if ($p >= $start_page && $p <= $end_page) {
23708 					$np = $p + ($target_page - $start_page);
23709 					foreach ($anno as $o) {
23710 						$newarr[$np][] = $o;
23711 					}
23712 				} elseif ($p >= $target_page && $p < $start_page) {
23713 					$np = $p + $n_toc;
23714 					foreach ($anno as $o) {
23715 						$newarr[$np][] = $o;
23716 					}
23717 				} else {
23718 					$newarr[$p] = $this->PageAnnots[$p];
23719 				}
23720 			}
23721 			$this->PageAnnots = $newarr;
23722 			unset($newarr);
23723 		}
23724 		/* -- END ANNOTATIONS -- */
23725 
23726 		// Update TOC pages
23727 		if (count($this->tableOfContents->_toc)) {
23728 			foreach ($this->tableOfContents->_toc as $key => $t) {
23729 				if ($t['p'] >= $start_page && $t['p'] <= $end_page) {
23730 					$this->tableOfContents->_toc[$key]['p'] += ($target_page - $start_page);
23731 				}
23732 				if ($t['p'] >= $target_page && $t['p'] < $start_page) {
23733 					$this->tableOfContents->_toc[$key]['p'] += $n_toc;
23734 				}
23735 			}
23736 		}
23737 
23738 		// Update PageNumSubstitutions
23739 		if (count($this->PageNumSubstitutions)) {
23740 			$newarr = [];
23741 			foreach ($this->PageNumSubstitutions as $k => $v) {
23742 				if ($this->PageNumSubstitutions[$k]['from'] >= $start_page && $this->PageNumSubstitutions[$k]['from'] <= $end_page) {
23743 					$this->PageNumSubstitutions[$k]['from'] += ($target_page - $start_page);
23744 					$newarr[$this->PageNumSubstitutions[$k]['from']] = $this->PageNumSubstitutions[$k];
23745 				} elseif ($this->PageNumSubstitutions[$k]['from'] >= $target_page && $this->PageNumSubstitutions[$k]['from'] < $start_page) {
23746 					$this->PageNumSubstitutions[$k]['from'] += $n_toc;
23747 					$newarr[$this->PageNumSubstitutions[$k]['from']] = $this->PageNumSubstitutions[$k];
23748 				} else {
23749 					$newarr[$this->PageNumSubstitutions[$k]['from']] = $this->PageNumSubstitutions[$k];
23750 				}
23751 			}
23752 
23753 			if (!$sp_present) {
23754 				$newarr[$target_page] = ['from' => $target_page, 'suppress' => $sp_suppress, 'reset' => $sp_reset, 'type' => $sp_type];
23755 			}
23756 			if (!$tp_present) {
23757 				$newarr[($target_page + $n_toc)] = ['from' => ($target_page + $n_toc), 'suppress' => $tp_suppress, 'reset' => $tp_reset, 'type' => $tp_type];
23758 			}
23759 			if (!$ep_present && $end_page > count($this->pages)) {
23760 				$newarr[($end_page + 1)] = ['from' => ($end_page + 1), 'suppress' => $ep_suppress, 'reset' => $ep_reset, 'type' => $ep_type];
23761 			}
23762 			ksort($newarr);
23763 			$this->PageNumSubstitutions = [];
23764 			foreach ($newarr as $v) {
23765 				$this->PageNumSubstitutions[] = $v;
23766 			}
23767 		}
23768 	}
23769 
23770 	function DeletePages($start_page, $end_page = -1)
23771 	{
23772 		// move a page/pages EARLIER in the document
23773 		if ($end_page < 1) {
23774 			$end_page = $start_page;
23775 		}
23776 		$n_tod = $end_page - $start_page + 1;
23777 		$last_page = count($this->pages);
23778 		$n_atend = $last_page - $end_page + 1;
23779 
23780 		// move pages
23781 		for ($i = 0; $i < $n_atend; $i++) {
23782 			$this->pages[$start_page + $i] = $this->pages[$end_page + 1 + $i];
23783 		}
23784 		// delete pages
23785 		for ($i = 0; $i < $n_tod; $i++) {
23786 			unset($this->pages[$last_page - $i]);
23787 		}
23788 
23789 
23790 		/* -- BOOKMARKS -- */
23791 		// Update Bookmarks
23792 		foreach ($this->BMoutlines as $i => $o) {
23793 			if ($o['p'] >= $end_page) {
23794 				$this->BMoutlines[$i]['p'] -= $n_tod;
23795 			} elseif ($p < $start_page) {
23796 				unset($this->BMoutlines[$i]);
23797 			}
23798 		}
23799 		/* -- END BOOKMARKS -- */
23800 
23801 		// Update Page Links
23802 		if (count($this->PageLinks)) {
23803 			$newarr = [];
23804 			foreach ($this->PageLinks as $i => $o) {
23805 				foreach ($this->PageLinks[$i] as $key => $pl) {
23806 					if (strpos($pl[4], '@') === 0) {
23807 						$p = substr($pl[4], 1);
23808 						if ($p > $end_page) {
23809 							$this->PageLinks[$i][$key][4] = '@' . ($p - $n_tod);
23810 						} elseif ($p < $start_page) {
23811 							unset($this->PageLinks[$i][$key]);
23812 						}
23813 					}
23814 				}
23815 				if ($i > $end_page) {
23816 					$newarr[($i - $n_tod)] = $this->PageLinks[$i];
23817 				} elseif ($p < $start_page) {
23818 					$newarr[$i] = $this->PageLinks[$i];
23819 				}
23820 			}
23821 			$this->PageLinks = $newarr;
23822 		}
23823 
23824 		// OrientationChanges
23825 		if (count($this->OrientationChanges)) {
23826 			$newarr = [];
23827 			foreach ($this->OrientationChanges as $p => $v) {
23828 				if ($p > $end_page) {
23829 					$newarr[($p - $t_tod)] = $this->OrientationChanges[$p];
23830 				} elseif ($p < $start_page) {
23831 					$newarr[$p] = $this->OrientationChanges[$p];
23832 				}
23833 			}
23834 			ksort($newarr);
23835 			$this->OrientationChanges = $newarr;
23836 		}
23837 
23838 		// Page Dimensions
23839 		if (count($this->pageDim)) {
23840 			$newarr = [];
23841 			foreach ($this->pageDim as $p => $v) {
23842 				if ($p > $end_page) {
23843 					$newarr[($p - $n_tod)] = $this->pageDim[$p];
23844 				} elseif ($p < $start_page) {
23845 					$newarr[$p] = $this->pageDim[$p];
23846 				}
23847 			}
23848 			ksort($newarr);
23849 			$this->pageDim = $newarr;
23850 		}
23851 
23852 		// HTML Headers & Footers
23853 		if (count($this->saveHTMLHeader)) {
23854 			foreach ($this->saveHTMLHeader as $p => $v) {
23855 				if ($p > $end_page) {
23856 					$newarr[($p - $n_tod)] = $this->saveHTMLHeader[$p];
23857 				} // mPDF 5.7.3
23858 				elseif ($p < $start_page) {
23859 					$newarr[$p] = $this->saveHTMLHeader[$p];
23860 				}
23861 			}
23862 			ksort($newarr);
23863 			$this->saveHTMLHeader = $newarr;
23864 		}
23865 		if (count($this->saveHTMLFooter)) {
23866 			$newarr = [];
23867 			foreach ($this->saveHTMLFooter as $p => $v) {
23868 				if ($p > $end_page) {
23869 					$newarr[($p - $n_tod)] = $this->saveHTMLFooter[$p];
23870 				} elseif ($p < $start_page) {
23871 					$newarr[$p] = $this->saveHTMLFooter[$p];
23872 				}
23873 			}
23874 			ksort($newarr);
23875 			$this->saveHTMLFooter = $newarr;
23876 		}
23877 
23878 		// Update Internal Links
23879 		foreach ($this->internallink as $key => $o) {
23880 			if ($o['PAGE'] > $end_page) {
23881 				$this->internallink[$key]['PAGE'] -= $n_tod;
23882 			} elseif ($o['PAGE'] < $start_page) {
23883 				unset($this->internallink[$key]);
23884 			}
23885 		}
23886 
23887 		// Update Links
23888 		foreach ($this->links as $key => $o) {
23889 			if ($o[0] > $end_page) {
23890 				$this->links[$key][0] -= $n_tod;
23891 			} elseif ($o[0] < $start_page) {
23892 				unset($this->links[$key]);
23893 			}
23894 		}
23895 
23896 		// Update Form fields
23897 		foreach ($this->form->forms as $key => $f) {
23898 			if ($f['page'] > $end_page) {
23899 				$this->form->forms[$key]['page'] -= $n_tod;
23900 			} elseif ($f['page'] < $start_page) {
23901 				unset($this->form->forms[$key]);
23902 			}
23903 		}
23904 
23905 		/* -- ANNOTATIONS -- */
23906 		// Update Annotations
23907 		if (count($this->PageAnnots)) {
23908 			$newarr = [];
23909 			foreach ($this->PageAnnots as $p => $anno) {
23910 				if ($p > $end_page) {
23911 					foreach ($anno as $o) {
23912 						$newarr[($p - $n_tod)][] = $o;
23913 					}
23914 				} elseif ($p < $start_page) {
23915 					$newarr[$p] = $this->PageAnnots[$p];
23916 				}
23917 			}
23918 			ksort($newarr);
23919 			$this->PageAnnots = $newarr;
23920 		}
23921 		/* -- END ANNOTATIONS -- */
23922 
23923 		// Update PageNumSubstitutions
23924 		foreach ($this->PageNumSubstitutions as $k => $v) {
23925 			if ($this->PageNumSubstitutions[$k]['from'] > $end_page) {
23926 				$this->PageNumSubstitutions[$k]['from'] -= $n_tod;
23927 			} elseif ($this->PageNumSubstitutions[$k]['from'] < $start_page) {
23928 				unset($this->PageNumSubstitutions[$k]);
23929 			}
23930 		}
23931 
23932 		unset($newarr);
23933 		$this->page = count($this->pages);
23934 	}
23935 
23936 	// ======================================================
23937 		/* -- INDEX -- */
23938 	// FROM class PDF_Ref == INDEX
23939 
23940 	function IndexEntry($txt, $xref = '')
23941 	{
23942 		if ($xref) {
23943 			$this->IndexEntrySee($txt, $xref);
23944 			return;
23945 		}
23946 
23947 		// Search the reference (AND Ref/PageNo) in the array
23948 		$Present = false;
23949 		if ($this->keep_block_together) {
23950 			// do nothing
23951 		} /* -- TABLES -- */ elseif ($this->kwt) {
23952 			$size = count($this->kwt_Reference);
23953 			for ($i = 0; $i < $size; $i++) {
23954 				if (isset($this->kwt_Reference[$i]['t']) && $this->kwt_Reference[$i]['t'] == $txt) {
23955 					$Present = true;
23956 					if ($this->page != $this->kwt_Reference[$i]['op']) {
23957 						$this->kwt_Reference[$i]['op'] = $this->page;
23958 					}
23959 				}
23960 			}
23961 			if (!$Present) { // If not found, add it
23962 				$this->kwt_Reference[] = ['t' => $txt, 'op' => $this->page];
23963 			}
23964 		} /* -- END TABLES -- */ else {
23965 			$size = count($this->Reference);
23966 			for ($i = 0; $i < $size; $i++) {
23967 				if (isset($this->Reference[$i]['t']) && $this->Reference[$i]['t'] == $txt) {
23968 					$Present = true;
23969 					if (!in_array($this->page, $this->Reference[$i]['p'])) {
23970 						$this->Reference[$i]['p'][] = $this->page;
23971 					}
23972 				}
23973 			}
23974 			if (!$Present) { // If not found, add it
23975 				$this->Reference[] = ['t' => $txt, 'p' => [$this->page]];
23976 			}
23977 		}
23978 	}
23979 
23980 	// Added function to add a reference "Elephants. See Chickens"
23981 	function IndexEntrySee($txta, $txtb)
23982 	{
23983 		if ($this->directionality == 'rtl') { // *OTL*
23984 			// ONLY DO THIS IF NOT IN TAGS
23985 			if ($txta == strip_tags($txta)) {
23986 				$txta = str_replace(':', ' - ', $txta); // *OTL*
23987 			}
23988 			if ($txtb == strip_tags($txtb)) {
23989 				$txtb = str_replace(':', ' - ', $txtb); // *OTL*
23990 			}
23991 		} // *OTL*
23992 		else { // *OTL*
23993 			if ($txta == strip_tags($txta)) {
23994 				$txta = str_replace(':', ', ', $txta);
23995 			}
23996 			if ($txtb == strip_tags($txtb)) {
23997 				$txtb = str_replace(':', ', ', $txtb);
23998 			}
23999 		} // *OTL*
24000 		$this->Reference[] = ['t' => $txta . ' - see ' . $txtb, 'p' => []];
24001 	}
24002 
24003 	private function filesInDir($directory)
24004 	{
24005 		$files = [];
24006 		foreach ((new \DirectoryIterator($directory)) as $v) {
24007 			if ($v->isDir() || $v->isDot()) {
24008 				continue;
24009 			}
24010 
24011 			$files[] = $v->getPathname();
24012 		}
24013 
24014 		return $files;
24015 	}
24016 
24017 	function InsertIndex($usedivletters = 1, $useLinking = false, $indexCollationLocale = '', $indexCollationGroup = '')
24018 	{
24019 		$size = count($this->Reference);
24020 		if ($size == 0) {
24021 			return false;
24022 		}
24023 
24024 		// $spacer used after named entry
24025 		// $sep  separates number [groups], $joiner joins numbers in range
24026 		//  e.g. "elephant 73, 97-99"  =  elephant[$spacer]73[$sep]97[$joiner]99
24027 		// $subEntrySeparator separates main and subentry (if $this->indexUseSubentries == false;) e.g.
24028 		// Mammal:elephant => Mammal[$subEntrySeparator]elephant
24029 		// $subEntryInset specifies what precedes a subentry (if $this->indexUseSubentries == true;) e.g.
24030 		// Mammal:elephant => [$subEntryInset]elephant
24031 		$spacer = "\xc2\xa0 ";
24032 		if ($this->directionality == 'rtl') {
24033 			$sep = '&#x060c; ';
24034 			$joiner = '-';
24035 			$subEntrySeparator = '&#x060c; ';
24036 			$subEntryInset = ' - ';
24037 		} else {
24038 			$sep = ', ';
24039 			$joiner = '-';
24040 			$subEntrySeparator = ', ';
24041 			$subEntryInset = ' - ';
24042 		}
24043 
24044 		for ($i = 0; $i < $size; $i++) {
24045 			$txt = $this->Reference[$i]['t'];
24046 			$txt = strip_tags($txt); // mPDF 6
24047 			$txt = $this->purify_utf8($txt);
24048 			$this->Reference[$i]['uf'] = $txt; // Unformatted e.g. pure utf-8 encoded characters, no mark-up/tags
24049 			// Used for ordering and collation
24050 		}
24051 
24052 		if ($usedivletters) {
24053 			if ($indexCollationGroup && \in_array(strtolower($indexCollationGroup), array_map(function ($v) {
24054 					return strtolower(basename($v, '.php'));
24055 			}, $this->filesInDir(__DIR__ . '/../data/collations/')))) {
24056 				$collation = require __DIR__ . '/../data/collations/' . $indexCollationGroup . '.php';
24057 			} else {
24058 				$collation = [];
24059 			}
24060 			for ($i = 0; $i < $size; $i++) {
24061 				if ($this->Reference[$i]['uf']) {
24062 					$l = mb_substr($this->Reference[$i]['uf'], 0, 1, 'UTF-8');
24063 					if (isset($indexCollationGroup) && $indexCollationGroup) {
24064 						$uni = $this->UTF8StringToArray($l);
24065 						$ucode = $uni[0];
24066 						if (isset($collation[$ucode])) {
24067 							$this->Reference[$i]['d'] = UtfString::code2utf($collation[$ucode]);
24068 						} else {
24069 							$this->Reference[$i]['d'] = mb_strtolower($l, 'UTF-8');
24070 						}
24071 					} else {
24072 						$this->Reference[$i]['d'] = mb_strtolower($l, 'UTF-8');
24073 					}
24074 				}
24075 			}
24076 		}
24077 
24078 		// Alphabetic sort of the references
24079 		$originalLocale = setlocale(LC_COLLATE, 0);
24080 		if ($indexCollationLocale) {
24081 			setlocale(LC_COLLATE, $indexCollationLocale);
24082 		}
24083 
24084 		usort($this->Reference, function ($a, $b) {
24085 			return strcoll(strtolower($a['uf']), strtolower($b['uf']));
24086 		});
24087 
24088 		if ($indexCollationLocale) {
24089 			setlocale(LC_COLLATE, $originalLocale);
24090 		}
24091 
24092 		$html = '<div class="mpdf_index_main">';
24093 
24094 		$lett = '';
24095 		$last_lett = '';
24096 		$mainentry = '';
24097 		for ($i = 0; $i < $size; $i++) {
24098 			if ($this->Reference[$i]['t']) {
24099 				if ($usedivletters) {
24100 					$lett = $this->Reference[$i]['d'];
24101 					if ($lett != $last_lett) {
24102 						$html .= '<div class="mpdf_index_letter">' . $lett . '</div>';
24103 					}
24104 				}
24105 				$txt = $this->Reference[$i]['t'];
24106 
24107 				// Sub-entries e.g. Mammals:elephant
24108 				// But allow for tags e.g. <b>Mammal</b>:elephants
24109 				$a = preg_split('/(<.*?>)/', $txt, -1, PREG_SPLIT_DELIM_CAPTURE);
24110 				$txt = '';
24111 				$marker = false;
24112 				foreach ($a as $k => $e) {
24113 					if ($k % 2 == 0 && !$marker) {
24114 						if (strpos($e, ':') !== false) { // == SubEntry
24115 							if ($this->indexUseSubentries) {
24116 								// If the Main entry does not have any page numbers associated with it
24117 								// create and insert an entry
24118 								list($txtmain, $sub) = preg_split('/[:]/', $e, 2);
24119 								if (strip_tags($txt . $txtmain) != $mainentry) {
24120 									$html .= '<div class="mpdf_index_entry">' . $txt . $txtmain . '</div>';
24121 									$mainentry = strip_tags($txt . $txtmain);
24122 								}
24123 
24124 								$txt = $subEntryInset;
24125 								$e = $sub; // Only replace first one
24126 							} else {
24127 								$e = preg_replace('/[:]/', $subEntrySeparator, $e, 1); // Only replace first one
24128 							}
24129 							$marker = true; // Don't replace any more once the subentry marker has been found
24130 						}
24131 					}
24132 					$txt .= $e;
24133 				}
24134 
24135 				if (!$marker) {
24136 					$mainentry = strip_tags($txt);
24137 				}
24138 
24139 				$html .= '<div class="mpdf_index_entry">';
24140 				$html .= $txt;
24141 				$ppp = $this->Reference[$i]['p']; // = array of page numbers to point to
24142 				if (count($ppp)) {
24143 					sort($ppp);
24144 					$newarr = [];
24145 					$range_start = $ppp[0];
24146 					$range_end = 0;
24147 
24148 					$html .= $spacer;
24149 
24150 					for ($zi = 1; $zi < count($ppp); $zi++) {
24151 						if ($ppp[$zi] == ($ppp[($zi - 1)] + 1)) {
24152 							$range_end = $ppp[$zi];
24153 						} else {
24154 							if ($range_end) {
24155 								if ($range_end == $range_start + 1) {
24156 									if ($useLinking) {
24157 										$html .= '<a class="mpdf_index_link" href="@' . $range_start . '">';
24158 									}
24159 									$html .= $this->docPageNum($range_start);
24160 									if ($useLinking) {
24161 										$html .= '</a>';
24162 									}
24163 									$html .= $sep;
24164 
24165 									if ($useLinking) {
24166 										$html .= '<a class="mpdf_index_link" href="@' . $ppp[$zi - 1] . '">';
24167 									}
24168 									$html .= $this->docPageNum($ppp[$zi - 1]);
24169 									if ($useLinking) {
24170 										$html .= '</a>';
24171 									}
24172 									$html .= $sep;
24173 								}
24174 							} else {
24175 								if ($useLinking) {
24176 									$html .= '<a class="mpdf_index_link" href="@' . $ppp[$zi - 1] . '">';
24177 								}
24178 								$html .= $this->docPageNum($ppp[$zi - 1]);
24179 								if ($useLinking) {
24180 									$html .= '</a>';
24181 								}
24182 								$html .= $sep;
24183 							}
24184 							$range_start = $ppp[$zi];
24185 							$range_end = 0;
24186 						}
24187 					}
24188 
24189 					if ($range_end) {
24190 						if ($useLinking) {
24191 							$html .= '<a class="mpdf_index_link" href="@' . $range_start . '">';
24192 						}
24193 						$html .= $this->docPageNum($range_start);
24194 						if ($range_end == $range_start + 1) {
24195 							if ($useLinking) {
24196 								$html .= '</a>';
24197 							}
24198 							$html .= $sep;
24199 							if ($useLinking) {
24200 								$html .= '<a class="mpdf_index_link" href="@' . $range_end . '">';
24201 							}
24202 							$html .= $this->docPageNum($range_end);
24203 							if ($useLinking) {
24204 								$html .= '</a>';
24205 							}
24206 						} else {
24207 							$html .= $joiner;
24208 							$html .= $this->docPageNum($range_end);
24209 							if ($useLinking) {
24210 								$html .= '</a>';
24211 							}
24212 						}
24213 					} else {
24214 						if ($useLinking) {
24215 							$html .= '<a class="mpdf_index_link" href="@' . $ppp[(count($ppp) - 1)] . '">';
24216 						}
24217 						$html .= $this->docPageNum($ppp[(count($ppp) - 1)]);
24218 						if ($useLinking) {
24219 							$html .= '</a>';
24220 						}
24221 					}
24222 				}
24223 			}
24224 			$html .= '</div>';
24225 			$last_lett = $lett;
24226 		}
24227 		$html .= '</div>';
24228 		$save_fpb = $this->fixedPosBlockSave;
24229 		$this->WriteHTML($html);
24230 		$this->fixedPosBlockSave = $save_fpb;
24231 
24232 		$this->breakpoints[$this->CurrCol][] = $this->y;  // *COLUMNS*
24233 	}
24234 
24235 	/* -- END INDEX -- */
24236 
24237 	function AcceptPageBreak()
24238 	{
24239 		if (count($this->cellBorderBuffer)) {
24240 			$this->printcellbuffer();
24241 		} // *TABLES*
24242 		/* -- COLUMNS -- */
24243 		if ($this->ColActive == 1) {
24244 			if ($this->CurrCol < $this->NbCol - 1) {
24245 				// Go to the next column
24246 				$this->CurrCol++;
24247 				$this->SetCol($this->CurrCol);
24248 				$this->y = $this->y0;
24249 				$this->ChangeColumn = 1; // Number (and direction) of columns changed +1, +2, -2 etc.
24250 				// DIRECTIONALITY RTL
24251 				if ($this->directionality == 'rtl') {
24252 					$this->ChangeColumn = -($this->ChangeColumn);
24253 				} // *OTL*
24254 				// Stay on the page
24255 				return false;
24256 			} else {
24257 				// Go back to the first column - NEW PAGE
24258 				if (count($this->columnbuffer)) {
24259 					$this->printcolumnbuffer();
24260 				}
24261 				$this->SetCol(0);
24262 				$this->y0 = $this->tMargin;
24263 				$this->ChangeColumn = -($this->NbCol - 1);
24264 				// DIRECTIONALITY RTL
24265 				if ($this->directionality == 'rtl') {
24266 					$this->ChangeColumn = -($this->ChangeColumn);
24267 				} // *OTL*
24268 				// Page break
24269 				return true;
24270 			}
24271 		} /* -- END COLUMNS -- */
24272 		/* -- TABLES -- */ elseif ($this->table_rotate) {
24273 			if ($this->tablebuffer) {
24274 				$this->printtablebuffer();
24275 			}
24276 			return true;
24277 		} /* -- END TABLES -- */ else { // *COLUMNS*
24278 			$this->ChangeColumn = 0;
24279 			return $this->autoPageBreak;
24280 		} // *COLUMNS*
24281 		return $this->autoPageBreak;
24282 	}
24283 
24284 	// ----------- COLUMNS ---------------------
24285 	/* -- COLUMNS -- */
24286 
24287 	function SetColumns($NbCol, $vAlign = '', $gap = 5)
24288 	{
24289 		// NbCol = number of columns
24290 		// Anything less than 2 turns columns off
24291 		if ($NbCol < 2) { // SET COLUMNS OFF
24292 			if ($this->ColActive) {
24293 				$this->ColActive = 0;
24294 				if (count($this->columnbuffer)) {
24295 					$this->printcolumnbuffer();
24296 				}
24297 				$this->NbCol = 1;
24298 				$this->ResetMargins();
24299 				$this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
24300 				$this->divwidth = 0;
24301 				$this->Ln();
24302 			}
24303 			$this->ColActive = 0;
24304 			$this->columnbuffer = [];
24305 			$this->ColDetails = [];
24306 			$this->columnLinks = [];
24307 			$this->columnAnnots = [];
24308 			$this->columnForms = [];
24309 			$this->col_BMoutlines = [];
24310 			$this->col_toc = [];
24311 			$this->breakpoints = [];
24312 		} else { // SET COLUMNS ON
24313 			if ($this->ColActive) {
24314 				$this->ColActive = 0;
24315 				if (count($this->columnbuffer)) {
24316 					$this->printcolumnbuffer();
24317 				}
24318 				$this->ResetMargins();
24319 			}
24320 			if (isset($this->y) && $this->y > $this->tMargin) {
24321 				$this->Ln();
24322 			}
24323 			$this->NbCol = $NbCol;
24324 			$this->ColGap = $gap;
24325 			$this->divwidth = 0;
24326 			$this->ColActive = 1;
24327 			$this->ColumnAdjust = true; // enables column height adjustment for the page
24328 			$this->columnbuffer = [];
24329 			$this->ColDetails = [];
24330 			$this->columnLinks = [];
24331 			$this->columnAnnots = [];
24332 			$this->columnForms = [];
24333 			$this->col_BMoutlines = [];
24334 			$this->col_toc = [];
24335 			$this->breakpoints = [];
24336 			if ((strtoupper($vAlign) == 'J') || (strtoupper($vAlign) == 'JUSTIFY')) {
24337 				$vAlign = 'J';
24338 			} else {
24339 				$vAlign = '';
24340 			}
24341 			$this->colvAlign = $vAlign;
24342 			// Save the ordinate
24343 			$absL = $this->DeflMargin - ($gap / 2);
24344 			$absR = $this->DefrMargin - ($gap / 2);
24345 			$PageWidth = $this->w - $absL - $absR; // virtual pagewidth for calculation only
24346 			$ColWidth = (($PageWidth - ($gap * ($NbCol))) / $NbCol);
24347 			$this->ColWidth = $ColWidth;
24348 			/* -- OTL -- */
24349 
24350 			if ($this->directionality == 'rtl') {
24351 				for ($i = 0; $i < $this->NbCol; $i++) {
24352 					$this->ColL[$i] = $absL + ($gap / 2) + (($NbCol - ($i + 1)) * ($PageWidth / $NbCol));
24353 					$this->ColR[$i] = $this->ColL[$i] + $ColWidth; // NB This is not R margin -> R pos
24354 				}
24355 			} else {
24356 				/* -- END OTL -- */
24357 				for ($i = 0; $i < $this->NbCol; $i++) {
24358 					$this->ColL[$i] = $absL + ($gap / 2) + ($i * ($PageWidth / $NbCol) );
24359 					$this->ColR[$i] = $this->ColL[$i] + $ColWidth; // NB This is not R margin -> R pos
24360 				}
24361 			} // *OTL*
24362 			$this->pgwidth = $ColWidth;
24363 			$this->SetCol(0);
24364 			$this->y0 = $this->y;
24365 		}
24366 		$this->x = $this->lMargin;
24367 	}
24368 
24369 	function SetCol($CurrCol)
24370 	{
24371 		// Used internally to set column by number: 0 is 1st column
24372 		// Set position on a column
24373 		$this->CurrCol = $CurrCol;
24374 		$x = $this->ColL[$CurrCol];
24375 		$xR = $this->ColR[$CurrCol]; // NB This is not R margin -> R pos
24376 		if (($this->mirrorMargins) && (($this->page) % 2 == 0)) { // EVEN
24377 			$x += $this->MarginCorrection;
24378 			$xR += $this->MarginCorrection;
24379 		}
24380 		$this->SetMargins($x, ($this->w - $xR), $this->tMargin);
24381 	}
24382 
24383 	function AddColumn()
24384 	{
24385 		$this->NewColumn();
24386 		$this->ColumnAdjust = false; // disables all column height adjustment for the page.
24387 	}
24388 
24389 	function NewColumn()
24390 	{
24391 		if ($this->ColActive == 1) {
24392 			if ($this->CurrCol < $this->NbCol - 1) {
24393 				// Go to the next column
24394 				$this->CurrCol++;
24395 				$this->SetCol($this->CurrCol);
24396 				$this->y = $this->y0;
24397 				$this->ChangeColumn = 1;
24398 				// DIRECTIONALITY RTL
24399 				if ($this->directionality == 'rtl') {
24400 					$this->ChangeColumn = -($this->ChangeColumn);
24401 				} // *OTL*
24402 				// Stay on the page
24403 			} else {
24404 				// Go back to the first column
24405 				// Page break
24406 				if (count($this->columnbuffer)) {
24407 					$this->printcolumnbuffer();
24408 				}
24409 				$this->AddPage($this->CurOrientation);
24410 				$this->SetCol(0);
24411 				$this->y0 = $this->tMargin;
24412 				$this->ChangeColumn = -($this->NbCol - 1);
24413 				// DIRECTIONALITY RTL
24414 				if ($this->directionality == 'rtl') {
24415 					$this->ChangeColumn = -($this->ChangeColumn);
24416 				} // *OTL*
24417 			}
24418 			$this->x = $this->lMargin;
24419 		} else {
24420 			$this->AddPage($this->CurOrientation);
24421 		}
24422 	}
24423 
24424 	function printcolumnbuffer()
24425 	{
24426 		// Columns ended (but page not ended) -> try to match all columns - unless disabled by using a custom column-break
24427 		if (!$this->ColActive && $this->ColumnAdjust && !$this->keepColumns) {
24428 			// Calculate adjustment to add to each column to calculate rel_y value
24429 			$this->ColDetails[0]['add_y'] = 0;
24430 			$last_col = 0;
24431 			// Recursively add previous column's height
24432 			for ($i = 1; $i < $this->NbCol; $i++) {
24433 				if (isset($this->ColDetails[$i]['bottom_margin']) && $this->ColDetails[$i]['bottom_margin']) { // If any entries in the column
24434 					$this->ColDetails[$i]['add_y'] = ($this->ColDetails[$i - 1]['bottom_margin'] - $this->y0) + $this->ColDetails[$i - 1]['add_y'];
24435 					$last_col = $i;  // Last column actually printed
24436 				}
24437 			}
24438 
24439 			// Calculate value for each position sensitive entry as though for one column
24440 			foreach ($this->columnbuffer as $key => $s) {
24441 				$t = $s['s'];
24442 				if ($t == 'ACROFORM') {
24443 					$this->columnbuffer[$key]['rel_y'] = $s['y'] + $this->ColDetails[$s['col']]['add_y'] - $this->y0;
24444 					$this->columnbuffer[$key]['s'] = '';
24445 				} elseif (preg_match('/BT \d+\.\d\d+ (\d+\.\d\d+) Td/', $t)) {
24446 					$this->columnbuffer[$key]['rel_y'] = $s['y'] + $this->ColDetails[$s['col']]['add_y'] - $this->y0;
24447 				} elseif (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) \d+\.\d\d+ [\-]{0,1}\d+\.\d\d+ re/', $t)) {
24448 					$this->columnbuffer[$key]['rel_y'] = $s['y'] + $this->ColDetails[$s['col']]['add_y'] - $this->y0;
24449 				} elseif (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) m/', $t)) {
24450 					$this->columnbuffer[$key]['rel_y'] = $s['y'] + $this->ColDetails[$s['col']]['add_y'] - $this->y0;
24451 				} elseif (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) l/', $t)) {
24452 					$this->columnbuffer[$key]['rel_y'] = $s['y'] + $this->ColDetails[$s['col']]['add_y'] - $this->y0;
24453 				} elseif (preg_match('/q \d+\.\d\d+ 0 0 \d+\.\d\d+ \d+\.\d\d+ (\d+\.\d\d+) cm \/(I|FO)\d+ Do Q/', $t)) {
24454 					$this->columnbuffer[$key]['rel_y'] = $s['y'] + $this->ColDetails[$s['col']]['add_y'] - $this->y0;
24455 				} elseif (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) \d+\.\d\d+ \d+\.\d\d+ \d+\.\d\d+ \d+\.\d\d+ c/', $t)) {
24456 					$this->columnbuffer[$key]['rel_y'] = $s['y'] + $this->ColDetails[$s['col']]['add_y'] - $this->y0;
24457 				}
24458 			}
24459 			foreach ($this->internallink as $key => $f) {
24460 				if (is_array($f) && isset($f['col'])) {
24461 					$this->internallink[$key]['rel_y'] = $f['Y'] + $this->ColDetails[$f['col']]['add_y'] - $this->y0;
24462 				}
24463 			}
24464 
24465 			$breaks = [];
24466 			foreach ($this->breakpoints as $c => $bpa) {
24467 				foreach ($bpa as $rely) {
24468 					$breaks[] = $rely + $this->ColDetails[$c]['add_y'] - $this->y0;
24469 				}
24470 			}
24471 
24472 
24473 			if (isset($this->ColDetails[$last_col]['bottom_margin'])) {
24474 				$lcbm = $this->ColDetails[$last_col]['bottom_margin'];
24475 			} else {
24476 				$lcbm = 0;
24477 			}
24478 			$sum_h = $this->ColDetails[$last_col]['add_y'] + $lcbm - $this->y0;
24479 			// $sum_h = max($this->ColDetails[$last_col]['add_y'] + $this->ColDetails[$last_col]['bottom_margin'] - $this->y0, end($breaks));
24480 			$target_h = ($sum_h / $this->NbCol);
24481 
24482 			$cbr = [];
24483 			for ($i = 1; $i < $this->NbCol; $i++) {
24484 				$th = ($sum_h * $i / $this->NbCol);
24485 				foreach ($breaks as $bk => $val) {
24486 					if ($val > $th) {
24487 						if (($val - $th) < ($th - $breaks[$bk - 1])) {
24488 							$cbr[$i - 1] = $val;
24489 						} else {
24490 							$cbr[$i - 1] = $breaks[$bk - 1];
24491 						}
24492 						break;
24493 					}
24494 				}
24495 			}
24496 			$cbr[($this->NbCol - 1)] = $sum_h;
24497 
24498 			// mPDF 6
24499 			// Avoid outputing with 1st column empty
24500 			if (isset($cbr[0]) && $cbr[0] == 0) {
24501 				for ($i = 0; $i < $this->NbCol - 1; $i++) {
24502 					$cbr[$i] = $cbr[$i + 1];
24503 				}
24504 			}
24505 
24506 			// Now update the columns - divide into columns of approximately equal value
24507 			$last_new_col = 0;
24508 			$yadj = 0; // mm
24509 			$xadj = 0;
24510 			$last_col_bottom = 0;
24511 			$lowest_bottom_y = 0;
24512 			$block_bottom = 0;
24513 			$newcolumn = 0;
24514 			foreach ($this->columnbuffer as $key => $s) {
24515 				if (isset($s['rel_y'])) { // only process position sensitive data
24516 					if ($s['rel_y'] >= $cbr[$newcolumn]) {
24517 						$newcolumn++;
24518 					} else {
24519 						$newcolumn = $last_new_col;
24520 					}
24521 
24522 
24523 					$block_bottom = max($block_bottom, ($s['rel_y'] + $s['h']));
24524 
24525 					if ($this->directionality == 'rtl') { // *OTL*
24526 						$xadj = -(($newcolumn - $s['col']) * ($this->ColWidth + $this->ColGap)); // *OTL*
24527 					} // *OTL*
24528 					else { // *OTL*
24529 						$xadj = ($newcolumn - $s['col']) * ($this->ColWidth + $this->ColGap);
24530 					} // *OTL*
24531 
24532 					if ($last_new_col != $newcolumn) { // Added new column
24533 						$last_col_bottom = $this->columnbuffer[$key]['rel_y'];
24534 						$block_bottom = 0;
24535 					}
24536 					$yadj = ($s['rel_y'] - $s['y']) - ($last_col_bottom) + $this->y0;
24537 					// callback function
24538 					$t = $s['s'];
24539 
24540 					// mPDF 5.7+
24541 					$t = $this->columnAdjustPregReplace('Td', $xadj, $yadj, '/BT (\d+\.\d\d+) (\d+\.\d\d+) Td/', $t);
24542 					$t = $this->columnAdjustPregReplace('re', $xadj, $yadj, '/(\d+\.\d\d+) (\d+\.\d\d+) (\d+\.\d\d+) ([\-]{0,1}\d+\.\d\d+) re/', $t);
24543 					$t = $this->columnAdjustPregReplace('l', $xadj, $yadj, '/(\d+\.\d\d+) (\d+\.\d\d+) l/', $t);
24544 					$t = $this->columnAdjustPregReplace('img', $xadj, $yadj, '/q (\d+\.\d\d+) 0 0 (\d+\.\d\d+) (\d+\.\d\d+) (\d+\.\d\d+) cm \/(I|FO)/', $t);
24545 					$t = $this->columnAdjustPregReplace('draw', $xadj, $yadj, '/(\d+\.\d\d+) (\d+\.\d\d+) m/', $t);
24546 					$t = $this->columnAdjustPregReplace('bezier', $xadj, $yadj, '/(\d+\.\d\d+) (\d+\.\d\d+) (\d+\.\d\d+) (\d+\.\d\d+) (\d+\.\d\d+) (\d+\.\d\d+) c/', $t);
24547 
24548 					$this->columnbuffer[$key]['s'] = $t;
24549 					$this->columnbuffer[$key]['newcol'] = $newcolumn;
24550 					$this->columnbuffer[$key]['newy'] = $s['y'] + $yadj;
24551 					$last_new_col = $newcolumn;
24552 					$clb = $s['y'] + $yadj + $s['h']; // bottom_margin of current
24553 					if ((isset($this->ColDetails[$newcolumn]['max_bottom']) && $clb > $this->ColDetails[$newcolumn]['max_bottom']) || (!isset($this->ColDetails[$newcolumn]['max_bottom']) && $clb)) {
24554 						$this->ColDetails[$newcolumn]['max_bottom'] = $clb;
24555 					}
24556 					if ($clb > $lowest_bottom_y) {
24557 						$lowest_bottom_y = $clb;
24558 					}
24559 					// Adjust LINKS
24560 					if (isset($this->columnLinks[$s['col']][intval($s['x'])][intval($s['y'])])) {
24561 						$ref = $this->columnLinks[$s['col']][intval($s['x'])][intval($s['y'])];
24562 						$this->PageLinks[$this->page][$ref][0] += ($xadj * Mpdf::SCALE);
24563 						$this->PageLinks[$this->page][$ref][1] -= ($yadj * Mpdf::SCALE);
24564 						unset($this->columnLinks[$s['col']][intval($s['x'])][intval($s['y'])]);
24565 					}
24566 					// Adjust FORM FIELDS
24567 					if (isset($this->columnForms[$s['col']][intval($s['x'])][intval($s['y'])])) {
24568 						$ref = $this->columnForms[$s['col']][intval($s['x'])][intval($s['y'])];
24569 						$this->form->forms[$ref]['x'] += ($xadj);
24570 						$this->form->forms[$ref]['y'] += ($yadj);
24571 						unset($this->columnForms[$s['col']][intval($s['x'])][intval($s['y'])]);
24572 					}
24573 					/* -- ANNOTATIONS -- */
24574 					if (isset($this->columnAnnots[$s['col']][intval($s['x'])][intval($s['y'])])) {
24575 						$ref = $this->columnAnnots[$s['col']][intval($s['x'])][intval($s['y'])];
24576 						if ($this->PageAnnots[$this->page][$ref]['x'] < 0) {
24577 							$this->PageAnnots[$this->page][$ref]['x'] -= ($xadj);
24578 						} else {
24579 							$this->PageAnnots[$this->page][$ref]['x'] += ($xadj);
24580 						}
24581 						$this->PageAnnots[$this->page][$ref]['y'] += ($yadj); // unlike PageLinks, Page annots has y values from top in mm
24582 						unset($this->columnAnnots[$s['col']][intval($s['x'])][intval($s['y'])]);
24583 					}
24584 					/* -- END ANNOTATIONS -- */
24585 				}
24586 			}
24587 
24588 			/* -- BOOKMARKS -- */
24589 			// Adjust Bookmarks
24590 			foreach ($this->col_BMoutlines as $v) {
24591 				$this->BMoutlines[] = ['t' => $v['t'], 'l' => $v['l'], 'y' => $this->y0, 'p' => $v['p']];
24592 			}
24593 			/* -- END BOOKMARKS -- */
24594 
24595 			/* -- TOC -- */
24596 
24597 			// Adjust ToC
24598 			foreach ($this->col_toc as $v) {
24599 				$this->tableOfContents->_toc[] = ['t' => $v['t'], 'l' => $v['l'], 'p' => $v['p'], 'link' => $v['link'], 'toc_id' => $v['toc_id']];
24600 				$this->links[$v['link']][1] = $this->y0;
24601 			}
24602 			/* -- END TOC -- */
24603 
24604 			// Adjust column length to be equal
24605 			if ($this->colvAlign == 'J') {
24606 				foreach ($this->columnbuffer as $key => $s) {
24607 					if (isset($s['rel_y'])) { // only process position sensitive data
24608 						// Set ratio to expand y values or heights
24609 						if (isset($this->ColDetails[$s['newcol']]['max_bottom']) && $this->ColDetails[$s['newcol']]['max_bottom'] && $this->ColDetails[$s['newcol']]['max_bottom'] != $this->y0) {
24610 							$ratio = ($lowest_bottom_y - ($this->y0)) / ($this->ColDetails[$s['newcol']]['max_bottom'] - ($this->y0));
24611 						} else {
24612 							$ratio = 1;
24613 						}
24614 						if (($ratio > 1) && ($ratio <= $this->max_colH_correction)) {
24615 							$yadj = ($s['newy'] - $this->y0) * ($ratio - 1);
24616 
24617 							// Adjust LINKS
24618 							if (isset($this->columnLinks[$s['col']][intval($s['x'])][intval($s['y'])])) {
24619 								$ref = $this->columnLinks[$s['col']][intval($s['x'])][intval($s['y'])];
24620 								$this->PageLinks[$this->page][$ref][1] -= ($yadj * Mpdf::SCALE); // y value
24621 								$this->PageLinks[$this->page][$ref][3] *= $ratio; // height
24622 								unset($this->columnLinks[$s['col']][intval($s['x'])][intval($s['y'])]);
24623 							}
24624 							// Adjust FORM FIELDS
24625 							if (isset($this->columnForms[$s['col']][intval($s['x'])][intval($s['y'])])) {
24626 								$ref = $this->columnForms[$s['col']][intval($s['x'])][intval($s['y'])];
24627 								$this->form->forms[$ref]['x'] += ($xadj);
24628 								$this->form->forms[$ref]['y'] += ($yadj);
24629 								unset($this->columnForms[$s['col']][intval($s['x'])][intval($s['y'])]);
24630 							}
24631 							/* -- ANNOTATIONS -- */
24632 							if (isset($this->columnAnnots[$s['col']][intval($s['x'])][intval($s['y'])])) {
24633 								$ref = $this->columnAnnots[$s['col']][intval($s['x'])][intval($s['y'])];
24634 								$this->PageAnnots[$this->page][$ref]['y'] += ($yadj);
24635 								unset($this->columnAnnots[$s['col']][intval($s['x'])][intval($s['y'])]);
24636 							}
24637 							/* -- END ANNOTATIONS -- */
24638 						}
24639 					}
24640 				}
24641 				foreach ($this->internallink as $key => $f) {
24642 					if (is_array($f) && isset($f['col'])) {
24643 						$last_col_bottom = 0;
24644 						for ($nbc = 0; $nbc < $this->NbCol; $nbc++) {
24645 							if ($f['rel_y'] >= $cbr[$nbc]) {
24646 								$last_col_bottom = $cbr[$nbc];
24647 							}
24648 						}
24649 						$yadj = ($f['rel_y'] - $f['Y']) - $last_col_bottom + $this->y0;
24650 						$f['Y'] += $yadj;
24651 						unset($f['col']);
24652 						unset($f['rel_y']);
24653 						$this->internallink[$key] = $f;
24654 					}
24655 				}
24656 
24657 				$last_col = -1;
24658 				$trans_on = false;
24659 				foreach ($this->columnbuffer as $key => $s) {
24660 					if (isset($s['rel_y'])) { // only process position sensitive data
24661 						// Set ratio to expand y values or heights
24662 						if (isset($this->ColDetails[$s['newcol']]['max_bottom']) && $this->ColDetails[$s['newcol']]['max_bottom'] && $this->ColDetails[$s['newcol']]['max_bottom'] != $this->y0) {
24663 							$ratio = ($lowest_bottom_y - ($this->y0)) / ($this->ColDetails[$s['newcol']]['max_bottom'] - ($this->y0));
24664 						} else {
24665 							$ratio = 1;
24666 						}
24667 						if (($ratio > 1) && ($ratio <= $this->max_colH_correction)) {
24668 							// Start Transformation
24669 							$this->pages[$this->page] .= $this->StartTransform(true) . "\n";
24670 							$this->pages[$this->page] .= $this->transformScale(100, $ratio * 100, $x = '', $this->y0, true) . "\n";
24671 							$trans_on = true;
24672 						}
24673 					}
24674 					// Now output the adjusted values
24675 					$this->pages[$this->page] .= $s['s'] . "\n";
24676 					if (isset($s['rel_y']) && ($ratio > 1) && ($ratio <= $this->max_colH_correction)) { // only process position sensitive data
24677 						// Stop Transformation
24678 						$this->pages[$this->page] .= $this->StopTransform(true) . "\n";
24679 						$trans_on = false;
24680 					}
24681 				}
24682 				if ($trans_on) {
24683 					$this->pages[$this->page] .= $this->StopTransform(true) . "\n";
24684 				}
24685 			} else { // if NOT $this->colvAlign == 'J'
24686 				// Now output the adjusted values
24687 				foreach ($this->columnbuffer as $s) {
24688 					$this->pages[$this->page] .= $s['s'] . "\n";
24689 				}
24690 			}
24691 			if ($lowest_bottom_y > 0) {
24692 				$this->y = $lowest_bottom_y;
24693 			}
24694 		} // Columns not ended but new page -> align columns (can leave the columns alone - just tidy up the height)
24695 		elseif ($this->colvAlign == 'J' && $this->ColumnAdjust && !$this->keepColumns) {
24696 			// calculate the lowest bottom margin
24697 			$lowest_bottom_y = 0;
24698 			foreach ($this->columnbuffer as $key => $s) {
24699 				// Only process output data
24700 				$t = $s['s'];
24701 				if ($t == 'ACROFORM' || (preg_match('/BT \d+\.\d\d+ (\d+\.\d\d+) Td/', $t)) || (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) \d+\.\d\d+ [\-]{0,1}\d+\.\d\d+ re/', $t)) ||
24702 					(preg_match('/\d+\.\d\d+ (\d+\.\d\d+) l/', $t)) ||
24703 					(preg_match('/q \d+\.\d\d+ 0 0 \d+\.\d\d+ \d+\.\d\d+ (\d+\.\d\d+) cm \/(I|FO)\d+ Do Q/', $t)) ||
24704 					(preg_match('/\d+\.\d\d+ (\d+\.\d\d+) m/', $t)) ||
24705 					(preg_match('/\d+\.\d\d+ (\d+\.\d\d+) \d+\.\d\d+ \d+\.\d\d+ \d+\.\d\d+ \d+\.\d\d+ c/', $t))) {
24706 					$clb = $s['y'] + $s['h'];
24707 					if ((isset($this->ColDetails[$s['col']]['max_bottom']) && $clb > $this->ColDetails[$s['col']]['max_bottom']) || !isset($this->ColDetails[$s['col']]['max_bottom'])) {
24708 						$this->ColDetails[$s['col']]['max_bottom'] = $clb;
24709 					}
24710 					if ($clb > $lowest_bottom_y) {
24711 						$lowest_bottom_y = $clb;
24712 					}
24713 					$this->columnbuffer[$key]['rel_y'] = $s['y']; // Marks position sensitive data to process later
24714 					if ($t == 'ACROFORM') {
24715 						$this->columnbuffer[$key]['s'] = '';
24716 					}
24717 				}
24718 			}
24719 			// Adjust column length equal
24720 			foreach ($this->columnbuffer as $key => $s) {
24721 				// Set ratio to expand y values or heights
24722 				if (isset($this->ColDetails[$s['col']]['max_bottom']) && $this->ColDetails[$s['col']]['max_bottom']) {
24723 					$ratio = ($lowest_bottom_y - ($this->y0)) / ($this->ColDetails[$s['col']]['max_bottom'] - ($this->y0));
24724 				} else {
24725 					$ratio = 1;
24726 				}
24727 				if (($ratio > 1) && ($ratio <= $this->max_colH_correction)) {
24728 					$yadj = ($s['y'] - $this->y0) * ($ratio - 1);
24729 
24730 					// Adjust LINKS
24731 					if (isset($s['rel_y'])) { // only process position sensitive data
24732 						// otherwise triggers for all entries in column buffer (.e.g. formatting) and makes below adjustments more than once
24733 						if (isset($this->columnLinks[$s['col']][intval($s['x'])][intval($s['y'])])) {
24734 							$ref = $this->columnLinks[$s['col']][intval($s['x'])][intval($s['y'])];
24735 							$this->PageLinks[$this->page][$ref][1] -= ($yadj * Mpdf::SCALE); // y value
24736 							$this->PageLinks[$this->page][$ref][3] *= $ratio; // height
24737 							unset($this->columnLinks[$s['col']][intval($s['x'])][intval($s['y'])]);
24738 						}
24739 						// Adjust FORM FIELDS
24740 						if (isset($this->columnForms[$s['col']][intval($s['x'])][intval($s['y'])])) {
24741 							$ref = $this->columnForms[$s['col']][intval($s['x'])][intval($s['y'])];
24742 							$this->form->forms[$ref]['x'] += ($xadj);
24743 							$this->form->forms[$ref]['y'] += ($yadj);
24744 							unset($this->columnForms[$s['col']][intval($s['x'])][intval($s['y'])]);
24745 						}
24746 						/* -- ANNOTATIONS -- */
24747 						if (isset($this->columnAnnots[$s['col']][intval($s['x'])][intval($s['y'])])) {
24748 							$ref = $this->columnAnnots[$s['col']][intval($s['x'])][intval($s['y'])];
24749 							$this->PageAnnots[$this->page][$ref]['y'] += ($yadj);
24750 							unset($this->columnAnnots[$s['col']][intval($s['x'])][intval($s['y'])]);
24751 						}
24752 						/* -- END ANNOTATIONS -- */
24753 					}
24754 				}
24755 			}
24756 
24757 			/* -- BOOKMARKS -- */
24758 
24759 			// Adjust Bookmarks
24760 			foreach ($this->col_BMoutlines as $v) {
24761 				$this->BMoutlines[] = ['t' => $v['t'], 'l' => $v['l'], 'y' => $this->y0, 'p' => $v['p']];
24762 			}
24763 			/* -- END BOOKMARKS -- */
24764 
24765 			/* -- TOC -- */
24766 
24767 			// Adjust ToC
24768 			foreach ($this->col_toc as $v) {
24769 				$this->tableOfContents->_toc[] = ['t' => $v['t'], 'l' => $v['l'], 'p' => $v['p'], 'link' => $v['link'], 'toc_id' => $v['toc_id']];
24770 				$this->links[$v['link']][1] = $this->y0;
24771 			}
24772 			/* -- END TOC -- */
24773 
24774 			$trans_on = false;
24775 			foreach ($this->columnbuffer as $key => $s) {
24776 
24777 				if (isset($s['rel_y'])) { // only process position sensitive data
24778 
24779 					// Set ratio to expand y values or heights
24780 					if (isset($this->ColDetails[$s['col']]['max_bottom']) && $this->ColDetails[$s['col']]['max_bottom']) {
24781 						$ratio = ($lowest_bottom_y - ($this->y0)) / ($this->ColDetails[$s['col']]['max_bottom'] - ($this->y0));
24782 					} else {
24783 						$ratio = 1;
24784 					}
24785 
24786 					if (($ratio > 1) && ($ratio <= $this->max_colH_correction)) {
24787 						// Start Transformation
24788 						$this->pages[$this->page] .= $this->StartTransform(true) . "\n";
24789 						$this->pages[$this->page] .= $this->transformScale(100, $ratio * 100, $x = '', $this->y0, true) . "\n";
24790 						$trans_on = true;
24791 					}
24792 				}
24793 
24794 				// Now output the adjusted values
24795 				$this->pages[$this->page] .= $s['s'] . "\n";
24796 				if (isset($s['rel_y']) && ($ratio > 1) && ($ratio <= $this->max_colH_correction)) {
24797 					// Stop Transformation
24798 					$this->pages[$this->page] .= $this->StopTransform(true) . "\n";
24799 					$trans_on = false;
24800 				}
24801 			}
24802 
24803 			if ($trans_on) {
24804 				$this->pages[$this->page] .= $this->StopTransform(true) . "\n";
24805 			}
24806 
24807 			if ($lowest_bottom_y > 0) {
24808 				$this->y = $lowest_bottom_y;
24809 			}
24810 
24811 		} else { // Just reproduce the page as it was
24812 
24813 			// If page has not ended but height adjustment was disabled by custom column-break - adjust y
24814 			$lowest_bottom_y = 0;
24815 
24816 			if (!$this->ColActive && (!$this->ColumnAdjust || $this->keepColumns)) {
24817 
24818 				// calculate the lowest bottom margin
24819 				foreach ($this->columnbuffer as $key => $s) {
24820 
24821 					// Only process output data
24822 					$t = $s['s'];
24823 					if ($t === 'ACROFORM'
24824 							|| (preg_match('/BT \d+\.\d\d+ (\d+\.\d\d+) Td/', $t))
24825 							|| (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) \d+\.\d\d+ [\-]{0,1}\d+\.\d\d+ re/', $t))
24826 							|| (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) l/', $t))
24827 							|| (preg_match('/q \d+\.\d\d+ 0 0 \d+\.\d\d+ \d+\.\d\d+ (\d+\.\d\d+) cm \/(I|FO)\d+ Do Q/', $t))
24828 							|| (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) m/', $t))
24829 							|| (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) \d+\.\d\d+ \d+\.\d\d+ \d+\.\d\d+ \d+\.\d\d+ c/', $t))) {
24830 
24831 						$clb = $s['y'] + $s['h'];
24832 
24833 						if (isset($this->ColDetails[$s['col']]['max_bottom']) && $clb > $this->ColDetails[$s['col']]['max_bottom'] || (!isset($this->ColDetails[$s['col']]['max_bottom']) && $clb)) {
24834 							$this->ColDetails[$s['col']]['max_bottom'] = $clb;
24835 						}
24836 
24837 						if ($clb > $lowest_bottom_y) {
24838 							$lowest_bottom_y = $clb;
24839 						}
24840 					}
24841 				}
24842 			}
24843 
24844 			foreach ($this->columnbuffer as $key => $s) {
24845 				if ($s['s'] != 'ACROFORM') {
24846 					$this->pages[$this->page] .= $s['s'] . "\n";
24847 				}
24848 			}
24849 
24850 			if ($lowest_bottom_y > 0) {
24851 				$this->y = $lowest_bottom_y;
24852 			}
24853 
24854 			/* -- BOOKMARKS -- */
24855 			// Output Bookmarks
24856 			foreach ($this->col_BMoutlines as $v) {
24857 				$this->BMoutlines[] = ['t' => $v['t'], 'l' => $v['l'], 'y' => $v['y'], 'p' => $v['p']];
24858 			}
24859 			/* -- END BOOKMARKS -- */
24860 
24861 			/* -- TOC -- */
24862 			// Output ToC
24863 			foreach ($this->col_toc as $v) {
24864 				$this->tableOfContents->_toc[] = ['t' => $v['t'], 'l' => $v['l'], 'p' => $v['p'], 'link' => $v['link'], 'toc_id' => $v['toc_id']];
24865 			}
24866 			/* -- END TOC -- */
24867 		}
24868 
24869 		foreach ($this->internallink as $key => $f) {
24870 
24871 			if (isset($this->internallink[$key]['col'])) {
24872 				unset($this->internallink[$key]['col']);
24873 			}
24874 
24875 			if (isset($this->internallink[$key]['rel_y'])) {
24876 				unset($this->internallink[$key]['rel_y']);
24877 			}
24878 		}
24879 
24880 		$this->columnbuffer = [];
24881 		$this->ColDetails = [];
24882 		$this->columnLinks = [];
24883 		$this->columnAnnots = [];
24884 		$this->columnForms = [];
24885 
24886 		$this->col_BMoutlines = [];
24887 		$this->col_toc = [];
24888 		$this->breakpoints = [];
24889 	}
24890 
24891 	// mPDF 5.7+
24892 	function columnAdjustPregReplace($type, $xadj, $yadj, $pattern, $subject)
24893 	{
24894 		preg_match($pattern, $subject, $matches);
24895 
24896 		if (!count($matches)) {
24897 			return $subject;
24898 		}
24899 
24900 		if (!isset($matches[3])) {
24901 			$matches[3] = 0;
24902 		}
24903 
24904 		if (!isset($matches[4])) {
24905 			$matches[4] = 0;
24906 		}
24907 
24908 		if (!isset($matches[5])) {
24909 			$matches[5] = 0;
24910 		}
24911 
24912 		if (!isset($matches[6])) {
24913 			$matches[6] = 0;
24914 		}
24915 
24916 		return str_replace($matches[0], $this->columnAdjustAdd($type, Mpdf::SCALE, $xadj, $yadj, $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]), $subject);
24917 	}
24918 	/* -- END COLUMNS -- */
24919 
24920 	// ==================================================================
24921 	/* -- TABLES -- */
24922 	function printcellbuffer()
24923 	{
24924 		if (count($this->cellBorderBuffer)) {
24925 
24926 			sort($this->cellBorderBuffer);
24927 
24928 			foreach ($this->cellBorderBuffer as $cbb) {
24929 
24930 				$cba = unpack("A16dom/nbord/A1side/ns/dbw/a6ca/A10style/dx/dy/dw/dh/dmbl/dmbr/dmrt/dmrb/dmtl/dmtr/dmlt/dmlb/dcpd/dover/", $cbb);
24931 				$side = $cba['side'];
24932 				$color = str_pad($cba['ca'], 6, "\x00");
24933 
24934 				$details = [];
24935 
24936 				$details[$side]['dom'] = (float) $cba['dom'];
24937 				$details[$side]['s'] = $cba['s'];
24938 				$details[$side]['w'] = $cba['bw'];
24939 				$details[$side]['c'] = $color;
24940 				$details[$side]['style'] = trim($cba['style']);
24941 
24942 				$details['mbw']['BL'] = $cba['mbl'];
24943 				$details['mbw']['BR'] = $cba['mbr'];
24944 				$details['mbw']['RT'] = $cba['mrt'];
24945 				$details['mbw']['RB'] = $cba['mrb'];
24946 				$details['mbw']['TL'] = $cba['mtl'];
24947 				$details['mbw']['TR'] = $cba['mtr'];
24948 				$details['mbw']['LT'] = $cba['mlt'];
24949 				$details['mbw']['LB'] = $cba['mlb'];
24950 
24951 				$details['cellposdom'] = $cba['cpd'];
24952 
24953 				$details['p'] = $side;
24954 
24955 				if ($cba['over'] == 1) {
24956 					$details[$side]['overlay'] = true;
24957 				} else {
24958 					$details[$side]['overlay'] = false;
24959 				}
24960 
24961 				$this->_tableRect($cba['x'], $cba['y'], $cba['w'], $cba['h'], $cba['bord'], $details, false, false);
24962 			}
24963 
24964 			$this->cellBorderBuffer = [];
24965 		}
24966 	}
24967 
24968 	// ==================================================================
24969 	function printtablebuffer()
24970 	{
24971 
24972 		if (!$this->table_rotate) {
24973 
24974 			$this->pages[$this->page] .= $this->tablebuffer;
24975 
24976 			foreach ($this->tbrot_Links as $p => $l) {
24977 				foreach ($l as $v) {
24978 					$this->PageLinks[$p][] = $v;
24979 				}
24980 			}
24981 			$this->tbrot_Links = [];
24982 
24983 			/* -- ANNOTATIONS -- */
24984 			foreach ($this->tbrot_Annots as $p => $l) {
24985 				foreach ($l as $v) {
24986 					$this->PageAnnots[$p][] = $v;
24987 				}
24988 			}
24989 			$this->tbrot_Annots = [];
24990 			/* -- END ANNOTATIONS -- */
24991 
24992 			/* -- BOOKMARKS -- */
24993 			// Output Bookmarks
24994 			foreach ($this->tbrot_BMoutlines as $v) {
24995 				$this->BMoutlines[] = ['t' => $v['t'], 'l' => $v['l'], 'y' => $v['y'], 'p' => $v['p']];
24996 			}
24997 			$this->tbrot_BMoutlines = [];
24998 			/* -- END BOOKMARKS -- */
24999 
25000 			/* -- TOC -- */
25001 			// Output ToC
25002 			foreach ($this->tbrot_toc as $v) {
25003 				$this->tableOfContents->_toc[] = ['t' => $v['t'], 'l' => $v['l'], 'p' => $v['p'], 'link' => $v['link'], 'toc_id' => $v['toc_id']];
25004 			}
25005 			$this->tbrot_toc = [];
25006 			/* -- END TOC -- */
25007 
25008 			return;
25009 		}
25010 
25011 		// elseif rotated
25012 		$lm = $this->lMargin + $this->blk[$this->blklvl]['outer_left_margin'] + $this->blk[$this->blklvl]['border_left']['w'] + $this->blk[$this->blklvl]['padding_left'];
25013 		$pw = $this->blk[$this->blklvl]['inner_width'];
25014 
25015 		// Start Transformation
25016 		$this->pages[$this->page] .= $this->StartTransform(true) . "\n";
25017 
25018 		if ($this->table_rotate > 1) { // clockwise
25019 
25020 			if ($this->tbrot_align == 'L') {
25021 				$xadj = $this->tbrot_h; // align L (as is)
25022 			} elseif ($this->tbrot_align == 'R') {
25023 				$xadj = $lm - $this->tbrot_x0 + ($pw); // align R
25024 			} else {
25025 				$xadj = $lm - $this->tbrot_x0 + (($pw + $this->tbrot_h) / 2); // align C
25026 			}
25027 
25028 			$yadj = 0;
25029 
25030 		} else { // anti-clockwise
25031 
25032 			if ($this->tbrot_align == 'L') {
25033 				$xadj = 0; // align L (as is)
25034 			} elseif ($this->tbrot_align == 'R') {
25035 				$xadj = $lm - $this->tbrot_x0 + ($pw - $this->tbrot_h); // align R
25036 			} else {
25037 				$xadj = $lm - $this->tbrot_x0 + (($pw - $this->tbrot_h) / 2); // align C
25038 			}
25039 
25040 			$yadj = $this->tbrot_w;
25041 		}
25042 
25043 
25044 		$this->pages[$this->page] .= $this->transformTranslate($xadj, $yadj, true) . "\n";
25045 		$this->pages[$this->page] .= $this->transformRotate($this->table_rotate, $this->tbrot_x0, $this->tbrot_y0, true) . "\n";
25046 
25047 		// Now output the adjusted values
25048 		$this->pages[$this->page] .= $this->tablebuffer;
25049 
25050 		foreach ($this->tbrot_Links as $p => $l) {
25051 
25052 			foreach ($l as $v) {
25053 
25054 				$w = $v[2] / Mpdf::SCALE;
25055 				$h = $v[3] / Mpdf::SCALE;
25056 				$ax = ($v[0] / Mpdf::SCALE) - $this->tbrot_x0;
25057 				$ay = (($this->hPt - $v[1]) / Mpdf::SCALE) - $this->tbrot_y0;
25058 
25059 				if ($this->table_rotate > 1) { // clockwise
25060 					$bx = $this->tbrot_x0 + $xadj - $ay - $h;
25061 					$by = $this->tbrot_y0 + $yadj + $ax;
25062 				} else {
25063 					$bx = $this->tbrot_x0 + $xadj + $ay;
25064 					$by = $this->tbrot_y0 + $yadj - $ax - $w;
25065 				}
25066 
25067 				$v[0] = $bx * Mpdf::SCALE;
25068 				$v[1] = ($this->h - $by) * Mpdf::SCALE;
25069 				$v[2] = $h * Mpdf::SCALE; // swap width and height
25070 				$v[3] = $w * Mpdf::SCALE;
25071 
25072 				$this->PageLinks[$p][] = $v;
25073 			}
25074 		}
25075 
25076 		$this->tbrot_Links = [];
25077 		foreach ($this->internallink as $key => $f) {
25078 			if (is_array($f) && isset($f['tbrot'])) {
25079 				$f['Y'] = $this->tbrot_y0;
25080 				$f['PAGE'] = $this->page;
25081 				unset($f['tbrot']);
25082 				$this->internallink[$key] = $f;
25083 			}
25084 		}
25085 
25086 		/* -- ANNOTATIONS -- */
25087 		foreach ($this->tbrot_Annots as $p => $l) {
25088 			foreach ($l as $v) {
25089 				$ax = abs($v['x']) - $this->tbrot_x0; // abs because -ve values are internally set and held for reference if annotMargin set
25090 				$ay = $v['y'] - $this->tbrot_y0;
25091 
25092 				if ($this->table_rotate > 1) { // clockwise
25093 					$bx = $this->tbrot_x0 + $xadj - $ay;
25094 					$by = $this->tbrot_y0 + $yadj + $ax;
25095 				} else {
25096 					$bx = $this->tbrot_x0 + $xadj + $ay;
25097 					$by = $this->tbrot_y0 + $yadj - $ax;
25098 				}
25099 
25100 				if ($v['x'] < 0) {
25101 					$v['x'] = -$bx;
25102 				} else {
25103 					$v['x'] = $bx;
25104 				}
25105 
25106 				$v['y'] = ($by);
25107 				$this->PageAnnots[$p][] = $v;
25108 			}
25109 		}
25110 
25111 		$this->tbrot_Annots = [];
25112 		/* -- END ANNOTATIONS -- */
25113 
25114 		/* -- BOOKMARKS -- */
25115 		// Adjust Bookmarks
25116 		foreach ($this->tbrot_BMoutlines as $v) {
25117 			$v['y'] = $this->tbrot_y0;
25118 			$this->BMoutlines[] = ['t' => $v['t'], 'l' => $v['l'], 'y' => $v['y'], 'p' => $this->page];
25119 		}
25120 		/* -- END BOOKMARKS -- */
25121 
25122 		/* -- TOC -- */
25123 		// Adjust ToC - uses document page number
25124 		foreach ($this->tbrot_toc as $v) {
25125 			$this->tableOfContents->_toc[] = ['t' => $v['t'], 'l' => $v['l'], 'p' => $this->page, 'link' => $v['link'], 'toc_id' => $v['toc_id']];
25126 			$this->links[$v['link']][1] = $this->tbrot_y0;
25127 		}
25128 		/* -- END TOC -- */
25129 
25130 		$this->tbrot_BMoutlines = [];
25131 		$this->tbrot_toc = [];
25132 
25133 		// Stop Transformation
25134 		$this->pages[$this->page] .= $this->StopTransform(true) . "\n";
25135 
25136 		$this->y = $this->tbrot_y0 + $this->tbrot_w;
25137 		$this->x = $this->lMargin;
25138 
25139 		$this->tablebuffer = '';
25140 	}
25141 
25142 	/**
25143 	 * Keep-with-table This buffers contents of h1-6 to keep on page with table
25144 	 */
25145 	function printkwtbuffer()
25146 	{
25147 		if (!$this->kwt_moved) {
25148 
25149 			foreach ($this->kwt_buffer as $s) {
25150 				$this->pages[$this->page] .= $s['s'] . "\n";
25151 			}
25152 
25153 			foreach ($this->kwt_Links as $p => $l) {
25154 				foreach ($l as $v) {
25155 					$this->PageLinks[$p][] = $v;
25156 				}
25157 			}
25158 
25159 			$this->kwt_Links = [];
25160 
25161 			/* -- ANNOTATIONS -- */
25162 			foreach ($this->kwt_Annots as $p => $l) {
25163 				foreach ($l as $v) {
25164 					$this->PageAnnots[$p][] = $v;
25165 				}
25166 			}
25167 			$this->kwt_Annots = [];
25168 			/* -- END ANNOTATIONS -- */
25169 
25170 			/* -- INDEX -- */
25171 			// Output Reference (index)
25172 			foreach ($this->kwt_Reference as $v) {
25173 
25174 				$Present = 0;
25175 
25176 				for ($i = 0; $i < count($this->Reference); $i++) {
25177 					if ($this->Reference[$i]['t'] == $v['t']) {
25178 						$Present = 1;
25179 						if (!in_array($v['op'], $this->Reference[$i]['p'])) {
25180 							$this->Reference[$i]['p'][] = $v['op'];
25181 						}
25182 					}
25183 				}
25184 
25185 				if ($Present == 0) {
25186 					$this->Reference[] = ['t' => $v['t'], 'p' => [$v['op']]];
25187 				}
25188 			}
25189 			$this->kwt_Reference = [];
25190 			/* -- END INDEX -- */
25191 
25192 			/* -- BOOKMARKS -- */
25193 			// Output Bookmarks
25194 			foreach ($this->kwt_BMoutlines as $v) {
25195 				$this->BMoutlines[] = ['t' => $v['t'], 'l' => $v['l'], 'y' => $v['y'], 'p' => $v['p']];
25196 			}
25197 			$this->kwt_BMoutlines = [];
25198 			/* -- END BOOKMARKS -- */
25199 
25200 			/* -- TOC -- */
25201 			// Output ToC
25202 			foreach ($this->kwt_toc as $v) {
25203 				$this->tableOfContents->_toc[] = ['t' => $v['t'], 'l' => $v['l'], 'p' => $v['p'], 'link' => $v['link'], 'toc_id' => $v['toc_id']];
25204 			}
25205 			$this->kwt_toc = [];
25206 			/* -- END TOC -- */
25207 
25208 			$this->pageoutput[$this->page] = []; // mPDF 6
25209 
25210 			return;
25211 		}
25212 
25213 		// Start Transformation
25214 		$this->pages[$this->page] .= $this->StartTransform(true) . "\n";
25215 		$xadj = $this->lMargin - $this->kwt_x0;
25216 		// $yadj = $this->y - $this->kwt_y0 ;
25217 		$yadj = $this->tMargin - $this->kwt_y0;
25218 
25219 		$this->pages[$this->page] .= $this->transformTranslate($xadj, $yadj, true) . "\n";
25220 
25221 		// Now output the adjusted values
25222 		foreach ($this->kwt_buffer as $s) {
25223 			$this->pages[$this->page] .= $s['s'] . "\n";
25224 		}
25225 
25226 		// Adjust hyperLinks
25227 		foreach ($this->kwt_Links as $p => $l) {
25228 			foreach ($l as $v) {
25229 				$bx = $this->kwt_x0 + $xadj;
25230 				$by = $this->kwt_y0 + $yadj;
25231 				$v[0] = $bx * Mpdf::SCALE;
25232 				$v[1] = ($this->h - $by) * Mpdf::SCALE;
25233 				$this->PageLinks[$p][] = $v;
25234 			}
25235 		}
25236 
25237 		foreach ($this->internallink as $key => $f) {
25238 			if (is_array($f) && isset($f['kwt'])) {
25239 				$f['Y'] += $yadj;
25240 				$f['PAGE'] = $this->page;
25241 				unset($f['kwt']);
25242 				$this->internallink[$key] = $f;
25243 			}
25244 		}
25245 
25246 		/* -- ANNOTATIONS -- */
25247 		foreach ($this->kwt_Annots as $p => $l) {
25248 			foreach ($l as $v) {
25249 				$bx = $this->kwt_x0 + $xadj;
25250 				$by = $this->kwt_y0 + $yadj;
25251 				if ($v['x'] < 0) {
25252 					$v['x'] = -$bx;
25253 				} else {
25254 					$v['x'] = $bx;
25255 				}
25256 				$v['y'] = $by;
25257 				$this->PageAnnots[$p][] = $v;
25258 			}
25259 		}
25260 		/* -- END ANNOTATIONS -- */
25261 
25262 		/* -- BOOKMARKS -- */
25263 
25264 		// Adjust Bookmarks
25265 		foreach ($this->kwt_BMoutlines as $v) {
25266 			if ($v['y'] != 0) {
25267 				$v['y'] += $yadj;
25268 			}
25269 			$this->BMoutlines[] = ['t' => $v['t'], 'l' => $v['l'], 'y' => $v['y'], 'p' => $this->page];
25270 		}
25271 		/* -- END BOOKMARKS -- */
25272 
25273 		/* -- INDEX -- */
25274 		// Adjust Reference (index)
25275 		foreach ($this->kwt_Reference as $v) {
25276 
25277 			$Present = 0;
25278 
25279 			// Search the reference (AND Ref/PageNo) in the array
25280 			for ($i = 0; $i < count($this->Reference); $i++) {
25281 				if ($this->Reference[$i]['t'] == $v['t']) {
25282 					$Present = 1;
25283 					if (!in_array($this->page, $this->Reference[$i]['p'])) {
25284 						$this->Reference[$i]['p'][] = $this->page;
25285 					}
25286 				}
25287 			}
25288 
25289 			if ($Present == 0) {
25290 				$this->Reference[] = ['t' => $v['t'], 'p' => [$this->page]];
25291 			}
25292 		}
25293 		/* -- END INDEX -- */
25294 
25295 		/* -- TOC -- */
25296 
25297 		// Adjust ToC
25298 		foreach ($this->kwt_toc as $v) {
25299 			$this->tableOfContents->_toc[] = ['t' => $v['t'], 'l' => $v['l'], 'p' => $this->page, 'link' => $v['link'], 'toc_id' => $v['toc_id']];
25300 			$this->links[$v['link']][0] = $this->page;
25301 			$this->links[$v['link']][1] += $yadj;
25302 		}
25303 		/* -- END TOC -- */
25304 
25305 
25306 		$this->kwt_Links = [];
25307 		$this->kwt_Annots = [];
25308 
25309 		$this->kwt_Reference = [];
25310 		$this->kwt_BMoutlines = [];
25311 		$this->kwt_toc = [];
25312 
25313 		// Stop Transformation
25314 		$this->pages[$this->page] .= $this->StopTransform(true) . "\n";
25315 
25316 		$this->kwt_buffer = [];
25317 
25318 		$this->y += $this->kwt_height;
25319 		$this->pageoutput[$this->page] = []; // mPDF 6
25320 	}
25321 	/* -- END TABLES -- */
25322 
25323 	function printfloatbuffer()
25324 	{
25325 		if (count($this->floatbuffer)) {
25326 			$this->objectbuffer = $this->floatbuffer;
25327 			$this->printobjectbuffer(false);
25328 			$this->objectbuffer = [];
25329 			$this->floatbuffer = [];
25330 			$this->floatmargins = [];
25331 		}
25332 	}
25333 
25334 	function Circle($x, $y, $r, $style = 'S')
25335 	{
25336 		$this->Ellipse($x, $y, $r, $r, $style);
25337 	}
25338 
25339 	function Ellipse($x, $y, $rx, $ry, $style = 'S')
25340 	{
25341 		if ($style === 'F') {
25342 			$op = 'f';
25343 		} elseif ($style === 'FD' or $style === 'DF') {
25344 			$op = 'B';
25345 		} else {
25346 			$op = 'S';
25347 		}
25348 
25349 		$lx = 4 / 3 * (M_SQRT2 - 1) * $rx;
25350 		$ly = 4 / 3 * (M_SQRT2 - 1) * $ry;
25351 
25352 		$h = $this->h;
25353 
25354 		$this->writer->write(sprintf('%.3F %.3F m %.3F %.3F %.3F %.3F %.3F %.3F c', ($x + $rx) * Mpdf::SCALE, ($h - $y) * Mpdf::SCALE, ($x + $rx) * Mpdf::SCALE, ($h - ($y - $ly)) * Mpdf::SCALE, ($x + $lx) * Mpdf::SCALE, ($h - ($y - $ry)) * Mpdf::SCALE, $x * Mpdf::SCALE, ($h - ($y - $ry)) * Mpdf::SCALE));
25355 		$this->writer->write(sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c', ($x - $lx) * Mpdf::SCALE, ($h - ($y - $ry)) * Mpdf::SCALE, ($x - $rx) * Mpdf::SCALE, ($h - ($y - $ly)) * Mpdf::SCALE, ($x - $rx) * Mpdf::SCALE, ($h - $y) * Mpdf::SCALE));
25356 		$this->writer->write(sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c', ($x - $rx) * Mpdf::SCALE, ($h - ($y + $ly)) * Mpdf::SCALE, ($x - $lx) * Mpdf::SCALE, ($h - ($y + $ry)) * Mpdf::SCALE, $x * Mpdf::SCALE, ($h - ($y + $ry)) * Mpdf::SCALE));
25357 		$this->writer->write(sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c %s', ($x + $lx) * Mpdf::SCALE, ($h - ($y + $ry)) * Mpdf::SCALE, ($x + $rx) * Mpdf::SCALE, ($h - ($y + $ly)) * Mpdf::SCALE, ($x + $rx) * Mpdf::SCALE, ($h - $y) * Mpdf::SCALE, $op));
25358 	}
25359 
25360 	/* -- DIRECTW -- */
25361 	function AutosizeText($text, $w, $font, $style, $szfont = 72)
25362 	{
25363 
25364 		$text = ' ' . $text . ' ';
25365 
25366 		$this->SetFont($font, $style, $szfont, false);
25367 
25368 		$text = $this->purify_utf8_text($text);
25369 		if ($this->text_input_as_HTML) {
25370 			$text = $this->all_entities_to_utf8($text);
25371 		}
25372 		if ($this->usingCoreFont) {
25373 			$text = mb_convert_encoding($text, $this->mb_enc, 'UTF-8');
25374 		}
25375 
25376 		// DIRECTIONALITY
25377 		if (preg_match("/([" . $this->pregRTLchars . "])/u", $text)) {
25378 			$this->biDirectional = true;
25379 		}
25380 
25381 		$textvar = 0;
25382 		$save_OTLtags = $this->OTLtags;
25383 		$this->OTLtags = [];
25384 
25385 		if ($this->useKerning) {
25386 			if ($this->CurrentFont['haskernGPOS']) {
25387 				$this->OTLtags['Plus'] .= ' kern';
25388 			} else {
25389 				$textvar = ($textvar | TextVars::FC_KERNING);
25390 			}
25391 		}
25392 
25393 		/* -- OTL -- */
25394 		// Use OTL OpenType Table Layout - GSUB & GPOS
25395 		if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
25396 			$text = $this->otl->applyOTL($text, $this->CurrentFont['useOTL']);
25397 			$OTLdata = $this->otl->OTLdata;
25398 		}
25399 		/* -- END OTL -- */
25400 
25401 		$this->OTLtags = $save_OTLtags;
25402 
25403 		$this->magic_reverse_dir($text, $this->directionality, $OTLdata);
25404 
25405 		$width = $this->sizeConverter->convert($w);
25406 		$loop = 0;
25407 
25408 		while ($loop == 0) {
25409 
25410 			$this->SetFont($font, $style, $szfont, false);
25411 			$sz = $this->GetStringWidth($text, true, $OTLdata, $textvar);
25412 
25413 			if ($sz > $w) {
25414 				$szfont --;
25415 			} else {
25416 				$loop ++;
25417 			}
25418 		}
25419 
25420 		$this->SetFont($font, $style, $szfont, true, true);
25421 		$this->Cell($w, 0, $text, 0, 0, "C", 0, '', 0, 0, 0, 'M', 0, false, $OTLdata, $textvar);
25422 	}
25423 	/* -- END DIRECTW -- */
25424 
25425 	// ====================================================
25426 	// ====================================================
25427 
25428 	function magic_reverse_dir(&$chunk, $dir, &$chunkOTLdata)
25429 	{
25430 		/* -- OTL -- */
25431 		if ($this->usingCoreFont) {
25432 			return 0;
25433 		}
25434 
25435 		if ($chunk == '') {
25436 			return 0;
25437 		}
25438 
25439 		if ($this->biDirectional || $dir == 'rtl') {
25440 
25441 			// check if string contains RTL text
25442 			// including any added from OTL tables (in PUA)
25443 			$pregRTLchars = $this->pregRTLchars;
25444 
25445 			if (isset($this->CurrentFont['rtlPUAstr']) && $this->CurrentFont['rtlPUAstr']) {
25446 				$pregRTLchars .= $this->CurrentFont['rtlPUAstr'];
25447 			}
25448 
25449 			if (!preg_match("/[" . $pregRTLchars . "]/u", $chunk) && $dir != 'rtl') {
25450 				return 0;
25451 			}   // Chunk doesn't contain RTL characters
25452 
25453 			$unicode = $this->UTF8StringToArray($chunk, false);
25454 
25455 			$isStrong = false;
25456 			if (empty($chunkOTLdata)) {
25457 				$this->getBasicOTLdata($chunkOTLdata, $unicode, $isStrong);
25458 			}
25459 
25460 			$useGPOS = isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0x80);
25461 
25462 			// NB Returned $chunk may be a shorter string (with adjusted $cOTLdata) by removal of LRE, RLE etc embedding codes.
25463 			list($chunk, $rtl_content) = $this->otl->bidiSort($unicode, $chunk, $dir, $chunkOTLdata, $useGPOS);
25464 
25465 			return $rtl_content;
25466 		}
25467 
25468 		/* -- END OTL -- */
25469 		return 0;
25470 	}
25471 
25472 	/* -- OTL -- */
25473 
25474 	function getBasicOTLdata(&$chunkOTLdata, $unicode, &$is_strong)
25475 	{
25476 		if (empty($this->otl)) {
25477 			$this->otl = new Otl($this, $this->fontCache);
25478 		}
25479 
25480 		$chunkOTLdata['group'] = '';
25481 		$chunkOTLdata['GPOSinfo'] = [];
25482 		$chunkOTLdata['char_data'] = [];
25483 
25484 		foreach ($unicode as $char) {
25485 
25486 			$ucd_record = Ucdn::get_ucd_record($char);
25487 			$chunkOTLdata['char_data'][] = ['bidi_class' => $ucd_record[2], 'uni' => $char];
25488 
25489 			if ($ucd_record[2] == 0 || $ucd_record[2] == 3 || $ucd_record[2] == 4) {
25490 				$is_strong = true;
25491 			} // contains strong character
25492 
25493 			if ($ucd_record[0] == Ucdn::UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) {
25494 				$chunkOTLdata['group'] .= 'M';
25495 			} elseif ($char == 32 || $char == 12288) {
25496 				$chunkOTLdata['group'] .= 'S';
25497 			} else {
25498 				$chunkOTLdata['group'] .= 'C';
25499 			}
25500 		}
25501 	}
25502 
25503 	function _setBidiCodes($mode = 'start', $bdf = '')
25504 	{
25505 		$s = '';
25506 
25507 		if ($mode == 'end') {
25508 
25509 			// PDF comes before PDI to close isolate-override (e.g. "LRILROPDFPDI")
25510 			if (strpos($bdf, 'PDF') !== false) {
25511 				$s .= UtfString::code2utf(0x202C);
25512 			} // POP DIRECTIONAL FORMATTING
25513 
25514 			if (strpos($bdf, 'PDI') !== false) {
25515 				$s .= UtfString::code2utf(0x2069);
25516 			} // POP DIRECTIONAL ISOLATE
25517 
25518 		} elseif ($mode == 'start') {
25519 
25520 			// LRI comes before LRO to open isolate-override (e.g. "LRILROPDFPDI")
25521 			if (strpos($bdf, 'LRI') !== false) {  // U+2066 LRI
25522 				$s .= UtfString::code2utf(0x2066);
25523 			} elseif (strpos($bdf, 'RLI') !== false) { // U+2067 RLI
25524 				$s .= UtfString::code2utf(0x2067);
25525 			} elseif (strpos($bdf, 'FSI') !== false) { // U+2068 FSI
25526 				$s .= UtfString::code2utf(0x2068);
25527 			}
25528 
25529 			if (strpos($bdf, 'LRO') !== false) { // U+202D LRO
25530 				$s .= UtfString::code2utf(0x202D);
25531 			} elseif (strpos($bdf, 'RLO') !== false) { // U+202E RLO
25532 				$s .= UtfString::code2utf(0x202E);
25533 			} elseif (strpos($bdf, 'LRE') !== false) { // U+202A LRE
25534 				$s .= UtfString::code2utf(0x202A);
25535 			} elseif (strpos($bdf, 'RLE') !== false) { // U+202B RLE
25536 				$s .= UtfString::code2utf(0x202B);
25537 			}
25538 		}
25539 
25540 		return $s;
25541 	}
25542 	/* -- END OTL -- */
25543 
25544 	function SetSubstitutions()
25545 	{
25546 		$subsarray = [];
25547 		require __DIR__ . '/../data/subs_win-1252.php';
25548 		$this->substitute = [];
25549 		foreach ($subsarray as $key => $val) {
25550 			$this->substitute[UtfString::code2utf($key)] = $val;
25551 		}
25552 	}
25553 
25554 	function SubstituteChars($html)
25555 	{
25556 		// only substitute characters between tags
25557 		if (count($this->substitute)) {
25558 			$a = preg_split('/(<.*?>)/ms', $html, -1, PREG_SPLIT_DELIM_CAPTURE);
25559 			$html = '';
25560 			foreach ($a as $i => $e) {
25561 				if ($i % 2 == 0) {
25562 					$e = strtr($e, $this->substitute);
25563 				}
25564 				$html .= $e;
25565 			}
25566 		}
25567 
25568 		return $html;
25569 	}
25570 
25571 	function SubstituteCharsSIP(&$writehtml_a, &$writehtml_i, &$writehtml_e)
25572 	{
25573 		if (preg_match("/^(.*?)([\x{20000}-\x{2FFFF}]+)(.*)/u", $writehtml_e, $m)) {
25574 			if (isset($this->CurrentFont['sipext']) && $this->CurrentFont['sipext']) {
25575 				$font = $this->CurrentFont['sipext'];
25576 				if (!in_array($font, $this->available_unifonts)) {
25577 					return 0;
25578 				}
25579 				$writehtml_a[$writehtml_i] = $writehtml_e = $m[1];
25580 				array_splice($writehtml_a, $writehtml_i + 1, 0, ['span style="font-family: ' . $font . '"', $m[2], '/span', $m[3]]);
25581 				$this->subPos = $writehtml_i;
25582 				return 4;
25583 			}
25584 		}
25585 
25586 		return 0;
25587 	}
25588 
25589 	/**
25590 	 * If core font is selected in document which is not onlyCoreFonts - substitute with non-core font
25591 	 */
25592 	function SubstituteCharsNonCore(&$writehtml_a, &$writehtml_i, &$writehtml_e)
25593 	{
25594 		// Ignore if in Textarea
25595 		if ($writehtml_i > 0 && strtolower(substr($writehtml_a[$writehtml_i - 1], 0, 8)) == 'textarea') {
25596 			return 0;
25597 		}
25598 
25599 		if (mb_convert_encoding(mb_convert_encoding($writehtml_e, $this->mb_enc, "UTF-8"), "UTF-8", $this->mb_enc) == $writehtml_e) {
25600 			return 0;
25601 		}
25602 
25603 		$cw = &$this->CurrentFont['cw'];
25604 		$unicode = $this->UTF8StringToArray($writehtml_e, false);
25605 		$start = -1;
25606 		$end = 0;
25607 		$flag = 0;
25608 		$ftype = '';
25609 		$u = [];
25610 
25611 		if (!$this->subArrMB) {
25612 
25613 			require __DIR__ . '/../data/subs_core.php';
25614 
25615 			$this->subArrMB['a'] = $aarr;
25616 			$this->subArrMB['s'] = $sarr;
25617 			$this->subArrMB['z'] = $zarr;
25618 		}
25619 
25620 		foreach ($unicode as $c => $char) {
25621 
25622 			if (($char > 127 || ($flag == 1 && $char == 32)) && $char != 173 && (!isset($this->subArrMB['a'][$char]) || ($flag == 1 && $char == 32)) && ($char < 1536 || ($char > 1791 && $char < 2304) || $char > 3455)) {
25623 				if ($flag == 0) {
25624 					$start = $c;
25625 				}
25626 				$flag = 1;
25627 				$u[] = $char;
25628 			} elseif ($flag > 0) {
25629 				$end = $c - 1;
25630 				break;
25631 			}
25632 		}
25633 
25634 		if ($flag > 0 && !$end) {
25635 			$end = count($unicode) - 1;
25636 		}
25637 
25638 		if ($start == -1) {
25639 			return 0;
25640 		}
25641 
25642 		// Try in backup subs font
25643 		if (!is_array($this->backupSubsFont)) {
25644 			$this->backupSubsFont = ["$this->backupSubsFont"];
25645 		}
25646 
25647 		foreach ($this->backupSubsFont as $bsfctr => $bsf) {
25648 
25649 			if ($this->fonttrans[$bsf] == 'chelvetica' || $this->fonttrans[$bsf] == 'ctimes' || $this->fonttrans[$bsf] == 'ccourier') {
25650 				continue;
25651 			}
25652 
25653 			$font = $bsf;
25654 			unset($cw);
25655 			$cw = '';
25656 
25657 			if (isset($this->fonts[$font])) {
25658 				$cw = &$this->fonts[$font]['cw'];
25659 			} elseif ($this->fontCache->has($font . '.cw.dat')) {
25660 				$cw = $this->fontCache->load($font . '.cw.dat');
25661 			} else {
25662 				$prevFontFamily = $this->FontFamily;
25663 				$prevFontStyle = $this->currentfontstyle;
25664 				$prevFontSizePt = $this->FontSizePt;
25665 				$this->SetFont($bsf, '', '', false);
25666 				$this->SetFont($prevFontFamily, $prevFontStyle, $prevFontSizePt, false);
25667 			}
25668 
25669 			if (!$cw) {
25670 				continue;
25671 			}
25672 
25673 			$l = 0;
25674 			foreach ($u as $char) {
25675 				if ($char == 173 || $this->_charDefined($cw, $char) || ($char > 1536 && $char < 1791) || ($char > 2304 && $char < 3455 )) {
25676 					$l++;
25677 				} else {
25678 					if ($l == 0 && $bsfctr == (count($this->backupSubsFont) - 1)) { // Not found even in last backup font
25679 						$cont = mb_substr($writehtml_e, $start + 1);
25680 						$writehtml_e = mb_substr($writehtml_e, 0, $start + 1, 'UTF-8');
25681 						array_splice($writehtml_a, $writehtml_i + 1, 0, ['', $cont]);
25682 						$this->subPos = $writehtml_i + 1;
25683 
25684 						return 2;
25685 					} else {
25686 						break;
25687 					}
25688 				}
25689 			}
25690 
25691 			if ($l > 0) {
25692 				$patt = mb_substr($writehtml_e, $start, $l, 'UTF-8');
25693 				if (preg_match("/(.*?)(" . preg_quote($patt, '/') . ")(.*)/u", $writehtml_e, $m)) {
25694 					$writehtml_e = $m[1];
25695 					array_splice($writehtml_a, $writehtml_i + 1, 0, ['span style="font-family: ' . $font . '"', $m[2], '/span', $m[3]]);
25696 					$this->subPos = $writehtml_i + 3;
25697 
25698 					return 4;
25699 				}
25700 			}
25701 		}
25702 
25703 		unset($cw);
25704 
25705 		return 0;
25706 	}
25707 
25708 	function SubstituteCharsMB(&$writehtml_a, &$writehtml_i, &$writehtml_e)
25709 	{
25710 		// Ignore if in Textarea
25711 		if ($writehtml_i > 0 && strtolower(substr($writehtml_a[$writehtml_i - 1], 0, 8)) == 'textarea') {
25712 			return 0;
25713 		}
25714 
25715 		$cw = &$this->CurrentFont['cw'];
25716 		$unicode = $this->UTF8StringToArray($writehtml_e, false);
25717 		$start = -1;
25718 		$end = 0;
25719 		$flag = 0;
25720 		$ftype = '';
25721 		$u = [];
25722 
25723 		foreach ($unicode as $c => $char) {
25724 
25725 			if (($flag == 0 || $flag == 2) && (!$this->_charDefined($cw, $char) || ($flag == 2 && $char == 32)) && $this->checkSIP && $char > 131071) {  // Unicode Plane 2 (SIP)
25726 
25727 				if (in_array($this->FontFamily, $this->available_CJK_fonts)) {
25728 					return 0;
25729 				}
25730 
25731 				if ($flag == 0) {
25732 					$start = $c;
25733 				}
25734 
25735 				$flag = 2;
25736 				$u[] = $char;
25737 
25738 				// elseif (($flag == 0 || $flag==1) && $char != 173 && !$this->_charDefined($cw,$char) && ($char<1423 ||  ($char>3583 && $char < 11263))) {
25739 
25740 			} elseif (($flag == 0 || $flag == 1) && $char != 173 && (!$this->_charDefined($cw, $char) || ($flag == 1 && $char == 32)) && ($char < 1536 || ($char > 1791 && $char < 2304) || $char > 3455)) {
25741 
25742 				if ($flag == 0) {
25743 					$start = $c;
25744 				}
25745 
25746 				$flag = 1;
25747 				$u[] = $char;
25748 
25749 			} elseif ($flag > 0) {
25750 
25751 				$end = $c - 1;
25752 				break;
25753 
25754 			}
25755 		}
25756 
25757 		if ($flag > 0 && !$end) {
25758 			$end = count($unicode) - 1;
25759 		}
25760 
25761 		if ($start == -1) {
25762 			return 0;
25763 		}
25764 
25765 		if ($flag == 2) { // SIP
25766 
25767 			// Check if current CJK font has a ext-B related font
25768 			if (isset($this->CurrentFont['sipext']) && $this->CurrentFont['sipext']) {
25769 				$font = $this->CurrentFont['sipext'];
25770 				unset($cw);
25771 				$cw = '';
25772 
25773 				if (isset($this->fonts[$font])) {
25774 					$cw = &$this->fonts[$font]['cw'];
25775 				} elseif ($this->fontCache->has($font . '.cw.dat')) {
25776 					$cw = $this->fontCache->load($font . '.cw.dat');
25777 				} else {
25778 					$prevFontFamily = $this->FontFamily;
25779 					$prevFontStyle = $this->currentfontstyle;
25780 					$prevFontSizePt = $this->FontSizePt;
25781 					$this->SetFont($font, '', '', false);
25782 					$this->SetFont($prevFontFamily, $prevFontStyle, $prevFontSizePt, false);
25783 				}
25784 
25785 				if (!$cw) {
25786 					return 0;
25787 				}
25788 
25789 				$l = 0;
25790 				foreach ($u as $char) {
25791 					if ($this->_charDefined($cw, $char) || $char > 131071) {
25792 						$l++;
25793 					} else {
25794 						break;
25795 					}
25796 				}
25797 
25798 				if ($l > 0) {
25799 					$patt = mb_substr($writehtml_e, $start, $l);
25800 					if (preg_match("/(.*?)(" . preg_quote($patt, '/') . ")(.*)/u", $writehtml_e, $m)) {
25801 						$writehtml_e = $m[1];
25802 						array_splice($writehtml_a, $writehtml_i + 1, 0, ['span style="font-family: ' . $font . '"', $m[2], '/span', $m[3]]);
25803 						$this->subPos = $writehtml_i + 3;
25804 						return 4;
25805 					}
25806 				}
25807 			}
25808 
25809 			// Check Backup SIP font (defined in Config\FontVariables)
25810 			if (isset($this->backupSIPFont) && $this->backupSIPFont) {
25811 
25812 				if ($this->currentfontfamily != $this->backupSIPFont) {
25813 					$font = $this->backupSIPFont;
25814 				} else {
25815 					unset($cw);
25816 					return 0;
25817 				}
25818 
25819 				unset($cw);
25820 				$cw = '';
25821 
25822 				if (isset($this->fonts[$font])) {
25823 					$cw = &$this->fonts[$font]['cw'];
25824 				} elseif ($this->fontCache->has($font . '.cw.dat')) {
25825 					$cw = $this->fontCache->load($font . '.cw.dat');
25826 				} else {
25827 					$prevFontFamily = $this->FontFamily;
25828 					$prevFontStyle = $this->currentfontstyle;
25829 					$prevFontSizePt = $this->FontSizePt;
25830 					$this->SetFont($this->backupSIPFont, '', '', false);
25831 					$this->SetFont($prevFontFamily, $prevFontStyle, $prevFontSizePt, false);
25832 				}
25833 
25834 				if (!$cw) {
25835 					return 0;
25836 				}
25837 
25838 				$l = 0;
25839 				foreach ($u as $char) {
25840 					if ($this->_charDefined($cw, $char) || $char > 131071) {
25841 						$l++;
25842 					} else {
25843 						break;
25844 					}
25845 				}
25846 
25847 				if ($l > 0) {
25848 					$patt = mb_substr($writehtml_e, $start, $l);
25849 					if (preg_match("/(.*?)(" . preg_quote($patt, '/') . ")(.*)/u", $writehtml_e, $m)) {
25850 						$writehtml_e = $m[1];
25851 						array_splice($writehtml_a, $writehtml_i + 1, 0, ['span style="font-family: ' . $font . '"', $m[2], '/span', $m[3]]);
25852 						$this->subPos = $writehtml_i + 3;
25853 						return 4;
25854 					}
25855 				}
25856 			}
25857 
25858 			return 0;
25859 		}
25860 
25861 		// FIRST TRY CORE FONTS (when appropriate)
25862 		if (!$this->PDFA && !$this->PDFX && !$this->biDirectional) {  // mPDF 6
25863 			$repl = [];
25864 			if (!$this->subArrMB) {
25865 				require __DIR__ . '/../data/subs_core.php';
25866 				$this->subArrMB['a'] = $aarr;
25867 				$this->subArrMB['s'] = $sarr;
25868 				$this->subArrMB['z'] = $zarr;
25869 			}
25870 			if (isset($this->subArrMB['a'][$u[0]])) {
25871 				$font = 'tta';
25872 				$ftype = 'C';
25873 				foreach ($u as $char) {
25874 					if (isset($this->subArrMB['a'][$char])) {
25875 						$repl[] = $this->subArrMB['a'][$char];
25876 					} else {
25877 						break;
25878 					}
25879 				}
25880 			} elseif (isset($this->subArrMB['z'][$u[0]])) {
25881 				$font = 'ttz';
25882 				$ftype = 'C';
25883 				foreach ($u as $char) {
25884 					if (isset($this->subArrMB['z'][$char])) {
25885 						$repl[] = $this->subArrMB['z'][$char];
25886 					} else {
25887 						break;
25888 					}
25889 				}
25890 			} elseif (isset($this->subArrMB['s'][$u[0]])) {
25891 				$font = 'tts';
25892 				$ftype = 'C';
25893 				foreach ($u as $char) {
25894 					if (isset($this->subArrMB['s'][$char])) {
25895 						$repl[] = $this->subArrMB['s'][$char];
25896 					} else {
25897 						break;
25898 					}
25899 				}
25900 			}
25901 			if ($ftype == 'C') {
25902 				$patt = mb_substr($writehtml_e, $start, count($repl));
25903 				if (preg_match("/(.*?)(" . preg_quote($patt, '/') . ")(.*)/u", $writehtml_e, $m)) {
25904 					$writehtml_e = $m[1];
25905 					array_splice($writehtml_a, $writehtml_i + 1, 0, [$font, implode('|', $repl), '/' . $font, $m[3]]); // e.g. <tts>
25906 					$this->subPos = $writehtml_i + 3;
25907 					return 4;
25908 				}
25909 				return 0;
25910 			}
25911 		}
25912 
25913 		// LASTLY TRY IN BACKUP SUBS FONT
25914 		if (!is_array($this->backupSubsFont)) {
25915 			$this->backupSubsFont = ["$this->backupSubsFont"];
25916 		}
25917 
25918 		foreach ($this->backupSubsFont as $bsfctr => $bsf) {
25919 			if ($this->currentfontfamily != $bsf) {
25920 				$font = $bsf;
25921 			} else {
25922 				continue;
25923 			}
25924 
25925 			unset($cw);
25926 			$cw = '';
25927 
25928 			if (isset($this->fonts[$font])) {
25929 				$cw = &$this->fonts[$font]['cw'];
25930 			} elseif ($this->fontCache->has($font . '.cw.dat')) {
25931 				$cw = $this->fontCache->load($font . '.cw.dat');
25932 			} else {
25933 				$prevFontFamily = $this->FontFamily;
25934 				$prevFontStyle = $this->currentfontstyle;
25935 				$prevFontSizePt = $this->FontSizePt;
25936 				$this->SetFont($bsf, '', '', false);
25937 				$this->SetFont($prevFontFamily, $prevFontStyle, $prevFontSizePt, false);
25938 				if ($this->fontCache->has($font . '.cw.dat')) {
25939 					$cw = $this->fontCache->load($font . '.cw.dat');
25940 				}
25941 			}
25942 
25943 			if (!$cw) {
25944 				continue;
25945 			}
25946 
25947 			$l = 0;
25948 			foreach ($u as $char) {
25949 				if ($char == 173 || $this->_charDefined($cw, $char) || ($char > 1536 && $char < 1791) || ($char > 2304 && $char < 3455 )) {  // Arabic and Indic
25950 					$l++;
25951 				} else {
25952 					if ($l == 0 && $bsfctr == (count($this->backupSubsFont) - 1)) { // Not found even in last backup font
25953 						$cont = mb_substr($writehtml_e, $start + 1);
25954 						$writehtml_e = mb_substr($writehtml_e, 0, $start + 1);
25955 						array_splice($writehtml_a, $writehtml_i + 1, 0, ['', $cont]);
25956 						$this->subPos = $writehtml_i + 1;
25957 						return 2;
25958 					} else {
25959 						break;
25960 					}
25961 				}
25962 			}
25963 
25964 			if ($l > 0) {
25965 				$patt = mb_substr($writehtml_e, $start, $l);
25966 				if (preg_match("/(.*?)(" . preg_quote($patt, '/') . ")(.*)/u", $writehtml_e, $m)) {
25967 					$writehtml_e = $m[1];
25968 					array_splice($writehtml_a, $writehtml_i + 1, 0, ['span style="font-family: ' . $font . '"', $m[2], '/span', $m[3]]);
25969 					$this->subPos = $writehtml_i + 3;
25970 					return 4;
25971 				}
25972 			}
25973 		}
25974 
25975 		unset($cw);
25976 
25977 		return 0;
25978 	}
25979 
25980 	function setHiEntitySubstitutions()
25981 	{
25982 		$entarr = include __DIR__ . '/../data/entity_substitutions.php';
25983 
25984 		foreach ($entarr as $key => $val) {
25985 			$this->entsearch[] = '&' . $key . ';';
25986 			$this->entsubstitute[] = UtfString::code2utf($val);
25987 		}
25988 	}
25989 
25990 	function SubstituteHiEntities($html)
25991 	{
25992 		// converts html_entities > ASCII 127 to unicode
25993 		// Leaves in particular &lt; to distinguish from tag marker
25994 		if (count($this->entsearch)) {
25995 			$html = str_replace($this->entsearch, $this->entsubstitute, $html);
25996 		}
25997 
25998 		return $html;
25999 	}
26000 
26001 	/**
26002 	 * Edited v1.2 Pass by reference; option to continue if invalid UTF-8 chars
26003 	 */
26004 	function is_utf8(&$string)
26005 	{
26006 		if ($string === mb_convert_encoding(mb_convert_encoding($string, "UTF-32", "UTF-8"), "UTF-8", "UTF-32")) {
26007 			return true;
26008 		}
26009 
26010 		if ($this->ignore_invalid_utf8) {
26011 			$string = mb_convert_encoding(mb_convert_encoding($string, "UTF-32", "UTF-8"), "UTF-8", "UTF-32");
26012 			return true;
26013 		}
26014 
26015 		return false;
26016 	}
26017 
26018 	/**
26019 	 * For HTML
26020 	 *
26021 	 * Checks string is valid UTF-8 encoded
26022 	 * converts html_entities > ASCII 127 to UTF-8
26023 	 * Only exception - leaves low ASCII entities e.g. &lt; &amp; etc.
26024 	 * Leaves in particular &lt; to distinguish from tag marker
26025 	 */
26026 	function purify_utf8($html, $lo = true)
26027 	{
26028 		if (!$this->is_utf8($html)) {
26029 
26030 			while (mb_convert_encoding(mb_convert_encoding($html, "UTF-32", "UTF-8"), "UTF-8", "UTF-32") != $html) {
26031 
26032 				$a = @iconv('UTF-8', 'UTF-8', $html);
26033 				$error = error_get_last();
26034 				if ($error && $error['message'] === 'iconv(): Detected an illegal character in input string') {
26035 					throw new \Mpdf\MpdfException('Invalid input characters. Did you set $mpdf->in_charset properly?');
26036 				}
26037 
26038 				$pos = $start = strlen($a);
26039 				$err = '';
26040 				while (ord(substr($html, $pos, 1)) > 128) {
26041 					$err .= '[[#' . ord(substr($html, $pos, 1)) . ']]';
26042 					$pos++;
26043 				}
26044 
26045 				$this->logger->error($err, ['context' => LogContext::UTF8]);
26046 				$html = substr($html, $pos);
26047 			}
26048 
26049 			throw new \Mpdf\MpdfException("HTML contains invalid UTF-8 character(s). See log for further details");
26050 		}
26051 
26052 		$html = preg_replace("/\r/", "", $html);
26053 
26054 		// converts html_entities > ASCII 127 to UTF-8
26055 		// Leaves in particular &lt; to distinguish from tag marker
26056 		$html = $this->SubstituteHiEntities($html);
26057 
26058 		// converts all &#nnn; or &#xHHH; to UTF-8 multibyte
26059 		// If $lo==true then includes ASCII < 128
26060 		$html = UtfString::strcode2utf($html, $lo);
26061 
26062 		return $html;
26063 	}
26064 
26065 	/**
26066 	 * For TEXT
26067 	 */
26068 	function purify_utf8_text($txt)
26069 	{
26070 		// Make sure UTF-8 string of characters
26071 		if (!$this->is_utf8($txt)) {
26072 			throw new \Mpdf\MpdfException("Text contains invalid UTF-8 character(s)");
26073 		}
26074 
26075 		$txt = preg_replace("/\r/", "", $txt);
26076 
26077 		return ($txt);
26078 	}
26079 
26080 	function all_entities_to_utf8($txt)
26081 	{
26082 		// converts txt_entities > ASCII 127 to UTF-8
26083 		// Leaves in particular &lt; to distinguish from tag marker
26084 		$txt = $this->SubstituteHiEntities($txt);
26085 
26086 		// converts all &#nnn; or &#xHHH; to UTF-8 multibyte
26087 		$txt = UtfString::strcode2utf($txt);
26088 
26089 		$txt = $this->lesser_entity_decode($txt);
26090 		return ($txt);
26091 	}
26092 
26093 	/* -- BARCODES -- */
26094 	/**
26095 	 * UPC/EAN barcode
26096 	 *
26097 	 * EAN13, EAN8, UPCA, UPCE, ISBN, ISSN
26098 	 * Accepts 12 or 13 digits with or without - hyphens
26099 	 */
26100 	function WriteBarcode($code, $showtext = 1, $x = '', $y = '', $size = 1, $border = 0, $paddingL = 1, $paddingR = 1, $paddingT = 2, $paddingB = 2, $height = 1, $bgcol = false, $col = false, $btype = 'ISBN', $supplement = '0', $supplement_code = '', $k = 1)
26101 	{
26102 		if (empty($code)) {
26103 			return;
26104 		}
26105 
26106 		$codestr = $code;
26107 		$code = preg_replace('/\-/', '', $code);
26108 
26109 		$this->barcode = new Barcode();
26110 		if ($btype == 'ISSN' || $btype == 'ISBN') {
26111 			$arrcode = $this->barcode->getBarcodeArray($code, 'EAN13');
26112 		} else {
26113 			$arrcode = $this->barcode->getBarcodeArray($code, $btype);
26114 		}
26115 
26116 		if ($arrcode === false) {
26117 			throw new \Mpdf\MpdfException('Error in barcode string: ' . $codestr);
26118 		}
26119 
26120 		if ((($btype === 'EAN13' || $btype === 'ISBN' || $btype === 'ISSN') && strlen($code) === 12)
26121 				|| ($btype == 'UPCA' && strlen($code) === 11)
26122 				|| ($btype == 'UPCE' && strlen($code) === 11)
26123 				|| ($btype == 'EAN8' && strlen($code) === 7)) {
26124 
26125 			$code .= $arrcode['checkdigit'];
26126 
26127 			if (stristr($codestr, '-')) {
26128 				$codestr .= '-' . $arrcode['checkdigit'];
26129 			} else {
26130 				$codestr .= $arrcode['checkdigit'];
26131 			}
26132 		}
26133 
26134 		if ($btype === 'ISBN') {
26135 			$codestr = 'ISBN ' . $codestr;
26136 		}
26137 
26138 		if ($btype === 'ISSN') {
26139 			$codestr = 'ISSN ' . $codestr;
26140 		}
26141 
26142 		if (empty($x)) {
26143 			$x = $this->x;
26144 		}
26145 
26146 		if (empty($y)) {
26147 			$y = $this->y;
26148 		}
26149 
26150 		// set foreground color
26151 		$prevDrawColor = $this->DrawColor;
26152 		$prevTextColor = $this->TextColor;
26153 		$prevFillColor = $this->FillColor;
26154 
26155 		$lw = $this->LineWidth;
26156 		$this->SetLineWidth(0.01);
26157 
26158 		$size /= $k; // in case resized in a table
26159 
26160 		$xres = $arrcode['nom-X'] * $size;
26161 		$llm = $arrcode['lightmL'] * $arrcode['nom-X'] * $size; // Left Light margin
26162 		$rlm = $arrcode['lightmR'] * $arrcode['nom-X'] * $size; // Right Light margin
26163 
26164 		$bcw = ($arrcode["maxw"] * $xres); // Barcode width = Should always be 31.35mm * $size
26165 
26166 		$fbw = $bcw + $llm + $rlm; // Full barcode width incl. light margins
26167 		$ow = $fbw + $paddingL + $paddingR; // Full overall width incl. user-defined padding
26168 
26169 		$fbwi = $fbw - 2; // Full barcode width incl. light margins - 2mm - for isbn string
26170 		// cf. http://www.gs1uk.org/downloads/bar_code/Bar coding getting it right.pdf
26171 		$num_height = 3 * $size;     // Height of numerals
26172 		$fbh = $arrcode['nom-H'] * $size * $height;  // Full barcode height incl. numerals
26173 		$bch = $fbh - (1.5 * $size);     // Barcode height of bars	 (3mm for numerals)
26174 
26175 		if (($btype == 'EAN13' && $showtext) || $btype == 'ISSN' || $btype == 'ISBN') { // Add height for ISBN string + margin from top of bars
26176 			$tisbnm = 1.5 * $size; // Top margin between isbn (if shown) & bars
26177 			$codestr_fontsize = 2.1 * $size;
26178 			$paddingT += $codestr_fontsize + $tisbnm;
26179 		}
26180 
26181 		$oh = $fbh + $paddingT + $paddingB;  // Full overall height incl. user-defined padding
26182 
26183 		// PRINT border background color
26184 		$xpos = $x;
26185 		$ypos = $y;
26186 
26187 		if ($col) {
26188 			$this->SetDColor($col);
26189 			$this->SetTColor($col);
26190 		} else {
26191 			$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
26192 			$this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
26193 		}
26194 
26195 		if ($bgcol) {
26196 			$this->SetFColor($bgcol);
26197 		} else {
26198 			$this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
26199 		}
26200 
26201 		if (!$bgcol && !$col) { // fn. called directly - not via HTML
26202 
26203 			if ($border) {
26204 				$fillb = 'DF';
26205 			} else {
26206 				$fillb = 'F';
26207 			}
26208 
26209 			$this->Rect($xpos, $ypos, $ow, $oh, $fillb);
26210 		}
26211 
26212 
26213 		// PRINT BARS
26214 		$xpos = $x + $paddingL + $llm;
26215 		$ypos = $y + $paddingT;
26216 
26217 		if ($col) {
26218 			$this->SetFColor($col);
26219 		} else {
26220 			$this->SetFColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
26221 		}
26222 
26223 		if ($arrcode !== false) {
26224 			foreach ($arrcode["bcode"] as $v) {
26225 				$bw = ($v["w"] * $xres);
26226 				if ($v["t"]) {
26227 					// draw a vertical bar
26228 					$this->Rect($xpos, $ypos, $bw, $bch, 'F');
26229 				}
26230 				$xpos += $bw;
26231 			}
26232 		}
26233 
26234 		// print text
26235 		$prevFontFamily = $this->FontFamily;
26236 		$prevFontStyle = $this->FontStyle;
26237 		$prevFontSizePt = $this->FontSizePt;
26238 
26239 		// ISBN string
26240 		if (($btype === 'EAN13' && $showtext) || $btype === 'ISBN' || $btype === 'ISSN') {
26241 
26242 			if ($this->onlyCoreFonts) {
26243 				$this->SetFont('chelvetica');
26244 			} else {
26245 				$this->SetFont('sans');
26246 			}
26247 
26248 			if ($bgcol) {
26249 				$this->SetFColor($bgcol);
26250 			} else {
26251 				$this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
26252 			}
26253 
26254 			$this->x = $x + $paddingL + 1; // 1mm left margin (cf. $fbwi above)
26255 
26256 			// max width is $fbwi
26257 			$loop = 0;
26258 			while ($loop == 0) {
26259 				$this->SetFontSize($codestr_fontsize * 1.4 * Mpdf::SCALE, false); // don't write
26260 				$sz = $this->GetStringWidth($codestr);
26261 
26262 				if ($sz > $fbwi) {
26263 					$codestr_fontsize -= 0.1;
26264 				} else {
26265 					$loop ++;
26266 				}
26267 			}
26268 
26269 			$this->SetFont('', '', $codestr_fontsize * 1.4 * Mpdf::SCALE, true, true); // * 1.4 because font height is only 7/10 of given mm
26270 			// WORD SPACING
26271 			if ($fbwi > $sz) {
26272 				$xtra = $fbwi - $sz;
26273 				$charspacing = $xtra / (strlen($codestr) - 1);
26274 				if ($charspacing) {
26275 					$this->writer->write(sprintf('BT %.3F Tc ET', $charspacing * Mpdf::SCALE));
26276 				}
26277 			}
26278 
26279 			$this->y = $y + $paddingT - ($codestr_fontsize ) - $tisbnm;
26280 			$this->Cell($fbw, $codestr_fontsize, $codestr);
26281 
26282 			if ($charspacing) {
26283 				$this->writer->write('BT 0 Tc ET');
26284 			}
26285 		}
26286 
26287 
26288 		// Bottom NUMERALS
26289 		// mPDF 5.7.4
26290 		if ($this->onlyCoreFonts) {
26291 			$this->SetFont('ccourier');
26292 			$fh = 1.3;
26293 		} else {
26294 			$this->SetFont('ocrb');
26295 			$fh = 1.06;
26296 		}
26297 
26298 		$charRO = '';
26299 
26300 		if ($btype === 'EAN13' || $btype === 'ISBN' || $btype === 'ISSN') {
26301 
26302 			$outerfontsize = 3; // Inner fontsize = 3
26303 			$outerp = $xres * 4;
26304 			$innerp = $xres * 2.5;
26305 			$textw = ($bcw * 0.5) - $outerp - $innerp;
26306 			$chars = 6; // number of numerals in each half
26307 			$charLO = substr($code, 0, 1); // Left Outer
26308 			$charLI = substr($code, 1, 6); // Left Inner
26309 			$charRI = substr($code, 7, 6); // Right Inner
26310 
26311 			if (!$supplement) {
26312 				$charRO = '>'; // Right Outer
26313 			}
26314 
26315 		} elseif ($btype === 'UPCA') {
26316 
26317 			$outerfontsize = 2.3; // Inner fontsize = 3
26318 			$outerp = $xres * 10;
26319 			$innerp = $xres * 2.5;
26320 			$textw = ($bcw * 0.5) - $outerp - $innerp;
26321 			$chars = 5;
26322 			$charLO = substr($code, 0, 1); // Left Outer
26323 			$charLI = substr($code, 1, 5); // Left Inner
26324 			$charRI = substr($code, 6, 5); // Right Inner
26325 			$charRO = substr($code, 11, 1); // Right Outer
26326 
26327 		} elseif ($btype === 'UPCE') {
26328 
26329 			$outerfontsize = 2.3; // Inner fontsize = 3
26330 			$outerp = $xres * 4;
26331 			$innerp = 0;
26332 			$textw = ($bcw * 0.5) - $outerp - $innerp;
26333 			$chars = 3;
26334 			$upce_code = $arrcode['code'];
26335 			$charLO = substr($code, 0, 1); // Left Outer
26336 			$charLI = substr($upce_code, 0, 3); // Left Inner
26337 			$charRI = substr($upce_code, 3, 3); // Right Inner
26338 			$charRO = substr($code, 11, 1); // Right Outer
26339 
26340 		} elseif ($btype === 'EAN8') {
26341 
26342 			$outerfontsize = 3; // Inner fontsize = 3
26343 			$outerp = $xres * 4;
26344 			$innerp = $xres * 2.5;
26345 			$textw = ($bcw * 0.5) - $outerp - $innerp;
26346 			$chars = 4;
26347 			$charLO = '<'; // Left Outer
26348 			$charLI = substr($code, 0, 4); // Left Inner
26349 			$charRI = substr($code, 4, 4); // Right Inner
26350 
26351 			if (!$supplement) {
26352 				$charRO = '>'; // Right Outer
26353 			}
26354 		}
26355 
26356 		$this->SetFontSize(($outerfontsize / 3) * 3 * $fh * $size * Mpdf::SCALE); // 3mm numerals (FontSize is larger to account for space above/below characters)
26357 
26358 		if (!$this->usingCoreFont) { // character width at 3mm
26359 			$cw = $this->_getCharWidth($this->CurrentFont['cw'], 32) * 3 * $fh * $size / 1000;
26360 		} else {
26361 			$cw = 600 * 3 * $fh * $size / 1000;
26362 		}
26363 
26364 		// Outer left character
26365 		$y_text = $y + $paddingT + $bch - ($num_height / 2);
26366 		$y_text_outer = $y + $paddingT + $bch - ($num_height * ($outerfontsize / 3) / 2);
26367 
26368 		$this->x = $x + $paddingL - ($cw * ($outerfontsize / 3) * 0.1); // 0.1 is correction as char does not fill full width;
26369 		$this->y = $y_text_outer;
26370 		$this->Cell($cw, $num_height, $charLO);
26371 
26372 		// WORD SPACING for inner chars
26373 		$xtra = $textw - ($cw * $chars);
26374 		$charspacing = $xtra / ($chars - 1);
26375 		if ($charspacing) {
26376 			$this->writer->write(sprintf('BT %.3F Tc ET', $charspacing * Mpdf::SCALE));
26377 		}
26378 
26379 		if ($bgcol) {
26380 			$this->SetFColor($bgcol);
26381 		} else {
26382 			$this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
26383 		}
26384 
26385 		$this->SetFontSize(3 * $fh * $size * Mpdf::SCALE); // 3mm numerals (FontSize is larger to account for space above/below characters)
26386 
26387 		// Inner left half characters
26388 		$this->x = $x + $paddingL + $llm + $outerp;
26389 		$this->y = $y_text;
26390 		$this->Cell($textw, $num_height, $charLI, 0, 0, '', 1);
26391 
26392 		// Inner right half characters
26393 		$this->x = $x + $paddingL + $llm + ($bcw * 0.5) + $innerp;
26394 		$this->y = $y_text;
26395 		$this->Cell($textw, $num_height, $charRI, 0, 0, '', 1);
26396 
26397 		if ($charspacing) {
26398 			$this->writer->write('BT 0 Tc ET');
26399 		}
26400 
26401 		// Outer Right character
26402 		$this->SetFontSize(($outerfontsize / 3) * 3 * $fh * $size * Mpdf::SCALE); // 3mm numerals (FontSize is larger to account for space above/below characters)
26403 
26404 		$this->x = $x + $paddingL + $llm + $bcw + $rlm - ($cw * ($outerfontsize / 3) * 0.9); // 0.9 is correction as char does not fill full width
26405 		$this->y = $y_text_outer;
26406 		$this->Cell($cw * ($outerfontsize / 3), $num_height, $charRO, 0, 0, 'R');
26407 
26408 		if ($supplement) { // EAN-2 or -5 Supplement
26409 			// PRINT BARS
26410 			$supparrcode = $this->barcode->getBarcodeArray($supplement_code, 'EAN' . $supplement);
26411 
26412 			if ($supparrcode === false) {
26413 				throw new \Mpdf\MpdfException('Error in barcode string (supplement): ' . $codestr . ' ' . $supplement_code);
26414 			}
26415 
26416 			if (strlen($supplement_code) != $supplement) {
26417 				throw new \Mpdf\MpdfException('Barcode supplement incorrect: ' . $supplement_code);
26418 			}
26419 
26420 			$llm = $fbw - (($arrcode['lightmR'] - $supparrcode['sepM']) * $arrcode['nom-X'] * $size); // Left Light margin
26421 			$rlm = $arrcode['lightmR'] * $arrcode['nom-X'] * $size; // Right Light margin
26422 
26423 			$bcw = ($supparrcode["maxw"] * $xres); // Barcode width = Should always be 31.35mm * $size
26424 
26425 			$fbw = $bcw + $llm + $rlm; // Full barcode width incl. light margins
26426 			$ow = $fbw + $paddingL + $paddingR; // Full overall width incl. user-defined padding
26427 			$bch = $fbh - (1.5 * $size) - ($num_height + 0.5);  // Barcode height of bars	 (3mm for numerals)
26428 
26429 			$xpos = $x + $paddingL + $llm;
26430 			$ypos = $y + $paddingT + $num_height + 0.5;
26431 
26432 			if ($col) {
26433 				$this->SetFColor($col);
26434 			} else {
26435 				$this->SetFColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
26436 			}
26437 
26438 			if ($supparrcode !== false) {
26439 				foreach ($supparrcode["bcode"] as $v) {
26440 					$bw = ($v["w"] * $xres);
26441 					if ($v["t"]) {
26442 						// draw a vertical bar
26443 						$this->Rect($xpos, $ypos, $bw, $bch, 'F');
26444 					}
26445 					$xpos += $bw;
26446 				}
26447 			}
26448 
26449 			// Characters
26450 			if ($bgcol) {
26451 				$this->SetFColor($bgcol);
26452 			} else {
26453 				$this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
26454 			}
26455 
26456 			$this->SetFontSize(3 * $fh * $size * Mpdf::SCALE); // 3mm numerals (FontSize is larger to account for space above/below characters)
26457 			$this->x = $x + $paddingL + $llm;
26458 			$this->y = $y + $paddingT;
26459 			$this->Cell($bcw, $num_height, $supplement_code, 0, 0, 'C');
26460 
26461 			// Outer Right character (light margin)
26462 			$this->SetFontSize(($outerfontsize / 3) * 3 * $fh * $size * Mpdf::SCALE); // 3mm numerals (FontSize is larger to account for space above/below characters)
26463 			$this->x = $x + $paddingL + $llm + $bcw + $rlm - ($cw * 0.9); // 0.9 is correction as char does not fill full width
26464 			$this->y = $y + $paddingT;
26465 			$this->Cell($cw * ($outerfontsize / 3), $num_height, '>', 0, 0, 'R');
26466 		}
26467 
26468 		// Restore **************
26469 		$this->SetFont($prevFontFamily, $prevFontStyle, $prevFontSizePt);
26470 		$this->DrawColor = $prevDrawColor;
26471 		$this->TextColor = $prevTextColor;
26472 		$this->FillColor = $prevFillColor;
26473 		$this->SetLineWidth($lw);
26474 		$this->SetY($y);
26475 	}
26476 
26477 	/**
26478 	 * POSTAL and OTHER barcodes
26479 	 */
26480 	function WriteBarcode2($code, $x = '', $y = '', $size = 1, $height = 1, $bgcol = false, $col = false, $btype = 'IMB', $print_ratio = '', $k = 1, $quiet_zone_left = null, $quiet_zone_right = null)
26481 	{
26482 		if (empty($code)) {
26483 			return;
26484 		}
26485 
26486 		$this->barcode = new Barcode();
26487 		$arrcode = $this->barcode->getBarcodeArray($code, $btype, $print_ratio, $quiet_zone_left, $quiet_zone_right);
26488 
26489 		if (empty($x)) {
26490 			$x = $this->x;
26491 		}
26492 
26493 		if (empty($y)) {
26494 			$y = $this->y;
26495 		}
26496 
26497 		$prevDrawColor = $this->DrawColor;
26498 		$prevTextColor = $this->TextColor;
26499 		$prevFillColor = $this->FillColor;
26500 		$lw = $this->LineWidth;
26501 		$this->SetLineWidth(0.01);
26502 		$size /= $k; // in case resized in a table
26503 		$xres = $arrcode['nom-X'] * $size;
26504 
26505 		if ($btype === 'IMB' || $btype === 'RM4SCC' || $btype === 'KIX' || $btype === 'POSTNET' || $btype === 'PLANET') {
26506 			$llm = $arrcode['quietL'] / $k; // Left Quiet margin
26507 			$rlm = $arrcode['quietR'] / $k; // Right Quiet margin
26508 			$tlm = $blm = $arrcode['quietTB'] / $k;
26509 			$height = 1;  // Overrides
26510 		} elseif (in_array($btype, ['C128A', 'C128B', 'C128C', 'C128RAW', 'EAN128A', 'EAN128B', 'EAN128C', 'C39', 'C39+', 'C39E', 'C39E+', 'S25', 'S25+', 'I25', 'I25+', 'I25B', 'I25B+', 'C93', 'MSI', 'MSI+', 'CODABAR', 'CODE11'])) {
26511 			$llm = $arrcode['lightmL'] * $xres; // Left Quiet margin
26512 			$rlm = $arrcode['lightmR'] * $xres; // Right Quiet margin
26513 			$tlm = $blm = $arrcode['lightTB'] * $xres * $height;
26514 		}
26515 
26516 		$bcw = ($arrcode["maxw"] * $xres);
26517 		$fbw = $bcw + $llm + $rlm;  // Full barcode width incl. light margins
26518 
26519 		$bch = ($arrcode["nom-H"] * $size * $height);
26520 		$fbh = $bch + $tlm + $blm;  // Full barcode height
26521 
26522 		// PRINT border background color
26523 		$xpos = $x;
26524 		$ypos = $y;
26525 
26526 		if ($col) {
26527 			$this->SetDColor($col);
26528 			$this->SetTColor($col);
26529 		} else {
26530 			$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
26531 			$this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
26532 		}
26533 
26534 		if ($bgcol) {
26535 			$this->SetFColor($bgcol);
26536 		} else {
26537 			$this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
26538 		}
26539 
26540 		// PRINT BARS
26541 		if ($col) {
26542 			$this->SetFColor($col);
26543 		} else {
26544 			$this->SetFColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
26545 		}
26546 		$xpos = $x + $llm;
26547 
26548 		if ($arrcode !== false) {
26549 			foreach ($arrcode["bcode"] as $v) {
26550 				$bw = ($v["w"] * $xres);
26551 				if ($v["t"]) {
26552 					$ypos = $y + $tlm + ($bch * $v['p'] / $arrcode['maxh']);
26553 					$this->Rect($xpos, $ypos, $bw, ($v['h'] * $bch / $arrcode['maxh']), 'F');
26554 				}
26555 				$xpos += $bw;
26556 			}
26557 		}
26558 
26559 		// PRINT BEARER BARS
26560 		if ($btype == 'I25B' || $btype == 'I25B+') {
26561 			$this->Rect($x, $y, $fbw, ($arrcode['lightTB'] * $xres * $height), 'F');
26562 			$this->Rect($x, $y + $tlm + $bch, $fbw, ($arrcode['lightTB'] * $xres * $height), 'F');
26563 		}
26564 
26565 		// Restore **************
26566 		$this->DrawColor = $prevDrawColor;
26567 		$this->TextColor = $prevTextColor;
26568 		$this->FillColor = $prevFillColor;
26569 		$this->SetLineWidth($lw);
26570 		$this->SetY($y);
26571 	}
26572 	/* -- END BARCODES -- */
26573 
26574 	function StartTransform($returnstring = false)
26575 	{
26576 		if ($returnstring) {
26577 			return('q');
26578 		} else {
26579 			$this->writer->write('q');
26580 		}
26581 	}
26582 
26583 	function StopTransform($returnstring = false)
26584 	{
26585 		if ($returnstring) {
26586 			return('Q');
26587 		} else {
26588 			$this->writer->write('Q');
26589 		}
26590 	}
26591 
26592 	function transformScale($s_x, $s_y, $x = '', $y = '', $returnstring = false)
26593 	{
26594 		if ($x === '') {
26595 			$x = $this->x;
26596 		}
26597 
26598 		if ($y === '') {
26599 			$y = $this->y;
26600 		}
26601 
26602 		if (($s_x == 0) or ( $s_y == 0)) {
26603 			throw new \Mpdf\MpdfException('Please do not use values equal to zero for scaling');
26604 		}
26605 
26606 		$y = ($this->h - $y) * Mpdf::SCALE;
26607 		$x *= Mpdf::SCALE;
26608 
26609 		// calculate elements of transformation matrix
26610 		$s_x /= 100;
26611 		$s_y /= 100;
26612 		$tm = [];
26613 		$tm[0] = $s_x;
26614 		$tm[1] = 0;
26615 		$tm[2] = 0;
26616 		$tm[3] = $s_y;
26617 		$tm[4] = $x * (1 - $s_x);
26618 		$tm[5] = $y * (1 - $s_y);
26619 
26620 		// scale the coordinate system
26621 		if ($returnstring) {
26622 			return($this->_transform($tm, true));
26623 		} else {
26624 			$this->_transform($tm);
26625 		}
26626 	}
26627 
26628 	function transformTranslate($t_x, $t_y, $returnstring = false)
26629 	{
26630 		// calculate elements of transformation matrix
26631 		$tm = [];
26632 		$tm[0] = 1;
26633 		$tm[1] = 0;
26634 		$tm[2] = 0;
26635 		$tm[3] = 1;
26636 		$tm[4] = $t_x * Mpdf::SCALE;
26637 		$tm[5] = -$t_y * Mpdf::SCALE;
26638 
26639 		// translate the coordinate system
26640 		if ($returnstring) {
26641 			return($this->_transform($tm, true));
26642 		} else {
26643 			$this->_transform($tm);
26644 		}
26645 	}
26646 
26647 	function transformRotate($angle, $x = '', $y = '', $returnstring = false)
26648 	{
26649 		if ($x === '') {
26650 			$x = $this->x;
26651 		}
26652 
26653 		if ($y === '') {
26654 			$y = $this->y;
26655 		}
26656 
26657 		$angle = -$angle;
26658 		$y = ($this->h - $y) * Mpdf::SCALE;
26659 		$x *= Mpdf::SCALE;
26660 
26661 		// calculate elements of transformation matrix
26662 		$tm = [];
26663 		$tm[0] = cos(deg2rad($angle));
26664 		$tm[1] = sin(deg2rad($angle));
26665 		$tm[2] = -$tm[1];
26666 		$tm[3] = $tm[0];
26667 		$tm[4] = $x + $tm[1] * $y - $tm[0] * $x;
26668 		$tm[5] = $y - $tm[0] * $y - $tm[1] * $x;
26669 
26670 		// rotate the coordinate system around ($x,$y)
26671 		if ($returnstring) {
26672 			return $this->_transform($tm, true);
26673 		} else {
26674 			$this->_transform($tm);
26675 		}
26676 	}
26677 
26678 	/**
26679 	 * mPDF 5.7.3 TRANSFORMS
26680 	 */
26681 	function transformSkew($angle_x, $angle_y, $x = '', $y = '', $returnstring = false)
26682 	{
26683 		if ($x === '') {
26684 			$x = $this->x;
26685 		}
26686 
26687 		if ($y === '') {
26688 			$y = $this->y;
26689 		}
26690 
26691 		$angle_x = -$angle_x;
26692 		$angle_y = -$angle_y;
26693 
26694 		$x *= Mpdf::SCALE;
26695 		$y = ($this->h - $y) * Mpdf::SCALE;
26696 
26697 		// calculate elements of transformation matrix
26698 		$tm = [];
26699 		$tm[0] = 1;
26700 		$tm[1] = tan(deg2rad($angle_y));
26701 		$tm[2] = tan(deg2rad($angle_x));
26702 		$tm[3] = 1;
26703 		$tm[4] = -$tm[2] * $y;
26704 		$tm[5] = -$tm[1] * $x;
26705 
26706 		// skew the coordinate system
26707 		if ($returnstring) {
26708 			return $this->_transform($tm, true);
26709 		} else {
26710 			$this->_transform($tm);
26711 		}
26712 	}
26713 
26714 	function _transform($tm, $returnstring = false)
26715 	{
26716 		if ($returnstring) {
26717 			return(sprintf('%.4F %.4F %.4F %.4F %.4F %.4F cm', $tm[0], $tm[1], $tm[2], $tm[3], $tm[4], $tm[5]));
26718 		} else {
26719 			$this->writer->write(sprintf('%.4F %.4F %.4F %.4F %.4F %.4F cm', $tm[0], $tm[1], $tm[2], $tm[3], $tm[4], $tm[5]));
26720 		}
26721 	}
26722 
26723 	// AUTOFONT =========================
26724 	function markScriptToLang($html)
26725 	{
26726 		if ($this->onlyCoreFonts) {
26727 			return $html;
26728 		}
26729 
26730 		$n = '';
26731 		$a = preg_split('/<(.*?)>/ms', $html, -1, PREG_SPLIT_DELIM_CAPTURE);
26732 		foreach ($a as $i => $e) {
26733 			if ($i % 2 == 0) {
26734 
26735 				// ignore if in Textarea
26736 				if ($i > 0 && strtolower(substr($a[$i - 1], 1, 8)) == 'textarea') {
26737 					$a[$i] = $e;
26738 					continue;
26739 				}
26740 
26741 				$e = UtfString::strcode2utf($e);
26742 				$e = $this->lesser_entity_decode($e);
26743 
26744 				$earr = $this->UTF8StringToArray($e, false);
26745 
26746 				$scriptblock = 0;
26747 				$scriptblocks = [];
26748 				$scriptblocks[0] = 0;
26749 				$chardata = [];
26750 				$subchunk = 0;
26751 				$charctr = 0;
26752 
26753 				foreach ($earr as $char) {
26754 
26755 					$ucd_record = Ucdn::get_ucd_record($char);
26756 					$sbl = $ucd_record[6];
26757 
26758 					if ($sbl && $sbl != 40 && $sbl != 102) {
26759 						if ($scriptblock == 0) {
26760 							$scriptblock = $sbl;
26761 							$scriptblocks[$subchunk] = $scriptblock;
26762 						} elseif ($scriptblock > 0 && $scriptblock != $sbl) {
26763 							// NEW (non-common) Script encountered in this chunk.
26764 							// Start a new subchunk
26765 							$subchunk++;
26766 							$scriptblock = $sbl;
26767 							$charctr = 0;
26768 							$scriptblocks[$subchunk] = $scriptblock;
26769 						}
26770 					}
26771 
26772 					$chardata[$subchunk][$charctr]['script'] = $sbl;
26773 					$chardata[$subchunk][$charctr]['uni'] = $char;
26774 					$charctr++;
26775 				}
26776 
26777 				// If scriptblock[x] = common & non-baseScript
26778 				// and scriptblock[x+1] = baseScript
26779 				// Move common script from end of x to start of x+1
26780 				for ($sch = 0; $sch < $subchunk; $sch++) {
26781 					if ($scriptblocks[$sch] > 0 && $scriptblocks[$sch] != $this->baseScript && $scriptblocks[$sch + 1] == $this->baseScript) {
26782 						$end = count($chardata[$sch]) - 1;
26783 						while ($chardata[$sch][$end]['script'] == 0 && $end > 1) { // common script
26784 							$tmp = array_pop($chardata[$sch]);
26785 							array_unshift($chardata[$sch + 1], $tmp);
26786 							$end--;
26787 						}
26788 					}
26789 				}
26790 
26791 				$o = '';
26792 				for ($sch = 0; $sch <= $subchunk; $sch++) {
26793 
26794 					if (isset($chardata[$sch])) {
26795 						$s = '';
26796 						for ($j = 0; $j < count($chardata[$sch]); $j++) {
26797 							$s .= UtfString::code2utf($chardata[$sch][$j]['uni']);
26798 						}
26799 
26800 						// ZZZ99 Undo lesser_entity_decode as above - but only for <>&
26801 						$s = str_replace("&", "&amp;", $s);
26802 						$s = str_replace("<", "&lt;", $s);
26803 						$s = str_replace(">", "&gt;", $s);
26804 
26805 						// Check Vietnamese if Latin script - even if Basescript
26806 						if ($scriptblocks[$sch] == Ucdn::SCRIPT_LATIN && $this->autoVietnamese && preg_match("/([" . $this->scriptToLanguage->getLanguageDelimiters('viet') . "])/u", $s)) {
26807 							$o .= '<span lang="vi" class="lang_vi">' . $s . '</span>';
26808 						} elseif ($scriptblocks[$sch] == Ucdn::SCRIPT_ARABIC && $this->autoArabic) { // Check Arabic for different languages if Arabic script - even if Basescript
26809 							if (preg_match("/[" . $this->scriptToLanguage->getLanguageDelimiters('sindhi') . "]/u", $s)) {
26810 								$o .= '<span lang="sd" class="lang_sd">' . $s . '</span>';
26811 							} elseif (preg_match("/[" . $this->scriptToLanguage->getLanguageDelimiters('urdu') . "]/u", $s)) {
26812 								$o .= '<span lang="ur" class="lang_ur">' . $s . '</span>';
26813 							} elseif (preg_match("/[" . $this->scriptToLanguage->getLanguageDelimiters('pashto') . "]/u", $s)) {
26814 								$o .= '<span lang="ps" class="lang_ps">' . $s . '</span>';
26815 							} elseif (preg_match("/[" . $this->scriptToLanguage->getLanguageDelimiters('persian') . "]/u", $s)) {
26816 								$o .= '<span lang="fa" class="lang_fa">' . $s . '</span>';
26817 							} elseif ($this->baseScript != Ucdn::SCRIPT_ARABIC && $this->scriptToLanguage->getLanguageByScript($scriptblocks[$sch])) {
26818 								$o .= '<span lang="' . $this->scriptToLanguage->getLanguageByScript($scriptblocks[$sch]) . '" class="lang_' . $this->scriptToLanguage->getLanguageByScript($scriptblocks[$sch]) . '">' . $s . '</span>';
26819 							} else {
26820 								// Just output chars
26821 								$o .= $s;
26822 							}
26823 						} elseif ($scriptblocks[$sch] > 0 && $scriptblocks[$sch] != $this->baseScript && $this->scriptToLanguage->getLanguageByScript($scriptblocks[$sch])) { // Identify Script block if not Basescript, and mark up as language
26824 							// Encase in <span>
26825 							$o .= '<span lang="' . $this->scriptToLanguage->getLanguageByScript($scriptblocks[$sch]) . '" class="lang_' . $this->scriptToLanguage->getLanguageByScript($scriptblocks[$sch]) . '">';
26826 							$o .= $s;
26827 							$o .= '</span>';
26828 						} else {
26829 							// Just output chars
26830 							$o .= $s;
26831 						}
26832 					}
26833 				}
26834 
26835 				$a[$i] = $o;
26836 			} else {
26837 				$a[$i] = '<' . $e . '>';
26838 			}
26839 		}
26840 
26841 		$n = implode('', $a);
26842 
26843 		return $n;
26844 	}
26845 
26846 	/* -- COLUMNS -- */
26847 	/**
26848 	 * Callback function from function printcolumnbuffer in mpdf
26849 	 */
26850 	function columnAdjustAdd($type, $k, $xadj, $yadj, $a, $b, $c = 0, $d = 0, $e = 0, $f = 0)
26851 	{
26852 		if ($type === 'Td') {  // xpos,ypos
26853 
26854 			$a += ($xadj * $k);
26855 			$b -= ($yadj * $k);
26856 
26857 			return 'BT ' . sprintf('%.3F %.3F', $a, $b) . ' Td';
26858 
26859 		} elseif ($type === 're') {  // xpos,ypos,width,height
26860 
26861 			$a += ($xadj * $k);
26862 			$b -= ($yadj * $k);
26863 
26864 			return sprintf('%.3F %.3F %.3F %.3F', $a, $b, $c, $d) . ' re';
26865 
26866 		} elseif ($type === 'l') {  // xpos,ypos,x2pos,y2pos
26867 
26868 			$a += ($xadj * $k);
26869 			$b -= ($yadj * $k);
26870 
26871 			return sprintf('%.3F %.3F l', $a, $b);
26872 
26873 		} elseif ($type === 'img') {  // width,height,xpos,ypos
26874 
26875 			$c += ($xadj * $k);
26876 			$d -= ($yadj * $k);
26877 
26878 			return sprintf('q %.3F 0 0 %.3F %.3F %.3F', $a, $b, $c, $d) . ' cm /' . $e;
26879 
26880 		} elseif ($type === 'draw') {  // xpos,ypos
26881 
26882 			$a += ($xadj * $k);
26883 			$b -= ($yadj * $k);
26884 
26885 			return sprintf('%.3F %.3F m', $a, $b);
26886 
26887 		} elseif ($type === 'bezier') {  // xpos,ypos,x2pos,y2pos,x3pos,y3pos
26888 
26889 			$a += ($xadj * $k);
26890 			$b -= ($yadj * $k);
26891 			$c += ($xadj * $k);
26892 			$d -= ($yadj * $k);
26893 			$e += ($xadj * $k);
26894 			$f -= ($yadj * $k);
26895 
26896 			return sprintf('%.3F %.3F %.3F %.3F %.3F %.3F', $a, $b, $c, $d, $e, $f) . ' c';
26897 		}
26898 	}
26899 
26900 	/* -- END COLUMNS -- */
26901 
26902 	// mPDF 5.7.3 TRANSFORMS
26903 	function ConvertAngle($s, $makepositive = true)
26904 	{
26905 		if (preg_match('/([\-]*[0-9\.]+)(deg|grad|rad)/i', $s, $m)) {
26906 
26907 			$angle = $m[1] + 0;
26908 
26909 			if (strtolower($m[2]) == 'deg') {
26910 				$angle = $angle;
26911 			} elseif (strtolower($m[2]) == 'grad') {
26912 				$angle *= (360 / 400);
26913 			} elseif (strtolower($m[2]) == 'rad') {
26914 				$angle = rad2deg($angle);
26915 			}
26916 
26917 			while ($angle >= 360) {
26918 				$angle -= 360;
26919 			}
26920 
26921 			while ($angle <= -360) {
26922 				$angle += 360;
26923 			}
26924 
26925 			if ($makepositive) { // always returns an angle between 0 and 360deg
26926 				if ($angle < 0) {
26927 					$angle += 360;
26928 				}
26929 			}
26930 
26931 		} else {
26932 			$angle = $s + 0;
26933 		}
26934 
26935 		return $angle;
26936 	}
26937 
26938 	function lesser_entity_decode($html)
26939 	{
26940 		// supports the most used entity codes (only does ascii safe characters)
26941 		$html = str_replace("&lt;", "<", $html);
26942 		$html = str_replace("&gt;", ">", $html);
26943 
26944 		$html = str_replace("&apos;", "'", $html);
26945 		$html = str_replace("&quot;", '"', $html);
26946 		$html = str_replace("&amp;", "&", $html);
26947 
26948 		return $html;
26949 	}
26950 
26951 	function AdjustHTML($html, $tabSpaces = 8)
26952 	{
26953 		$limit = ini_get('pcre.backtrack_limit');
26954 
26955 		if (0 >= (int) $limit) {
26956 			throw new \Mpdf\MpdfException(sprintf(
26957 				'mPDF will not process HTML with disabled pcre.backtrack_limit to prevent unexpected behaviours, please set a positive backtrack limit.',
26958 				$limit
26959 			));
26960 		}
26961 
26962 		if (strlen($html) > (int) $limit) {
26963 			throw new \Mpdf\MpdfException(sprintf(
26964 				'The HTML code size is larger than pcre.backtrack_limit %d. You should use WriteHTML() with smaller string lengths.',
26965 				$limit
26966 			));
26967 		}
26968 
26969 		preg_match_all("/(<annotation.*?>)/si", $html, $m);
26970 		if (count($m[1])) {
26971 			for ($i = 0; $i < count($m[1]); $i++) {
26972 				$sub = preg_replace("/\n/si", "\xbb\xa4\xac", $m[1][$i]);
26973 				$html = preg_replace('/' . preg_quote($m[1][$i], '/') . '/si', $sub, $html);
26974 			}
26975 		}
26976 
26977 		preg_match_all("/(<svg.*?<\/svg>)/si", $html, $svgi);
26978 		if (count($svgi[0])) {
26979 			for ($i = 0; $i < count($svgi[0]); $i++) {
26980 				$file = $this->cache->write('/_tempSVG' . uniqid(random_int(1, 100000), true) . '_' . $i . '.svg', $svgi[0][$i]);
26981 				$html = str_replace($svgi[0][$i], '<img src="' . $file . '" />', $html);
26982 			}
26983 		}
26984 
26985 		// Remove javascript code from HTML (should not appear in the PDF file)
26986 		$html = preg_replace('/<script.*?<\/script>/is', '', $html);
26987 
26988 		// Remove special comments
26989 		$html = preg_replace('/<!--mpdf/i', '', $html);
26990 		$html = preg_replace('/mpdf-->/i', '', $html);
26991 
26992 		// Remove comments from HTML (should not appear in the PDF file)
26993 		$html = preg_replace('/<!--.*?-->/s', '', $html);
26994 
26995 		$html = preg_replace('/\f/', '', $html); // replace formfeed by nothing
26996 		$html = preg_replace('/\r/', '', $html); // replace carriage return by nothing
26997 
26998 		// Well formed XHTML end tags
26999 		$html = preg_replace('/<(br|hr)>/i', "<\\1 />", $html); // mPDF 6
27000 		$html = preg_replace('/<(br|hr)\/>/i', "<\\1 />", $html);
27001 
27002 		// Get rid of empty <thead></thead> etc
27003 		$html = preg_replace('/<tr>\s*<\/tr>/i', '', $html);
27004 		$html = preg_replace('/<thead>\s*<\/thead>/i', '', $html);
27005 		$html = preg_replace('/<tfoot>\s*<\/tfoot>/i', '', $html);
27006 		$html = preg_replace('/<table[^>]*>\s*<\/table>/i', '', $html);
27007 
27008 		// Remove spaces at end of table cells
27009 		$html = preg_replace("/[ \n\r]+<\/t(d|h)/", '</t\\1', $html);
27010 
27011 		$html = preg_replace("/[ ]*<dottab\s*[\/]*>[ ]*/", '<dottab />', $html);
27012 
27013 		// Concatenates any Substitute characters from symbols/dingbats
27014 		$html = str_replace('</tts><tts>', '|', $html);
27015 		$html = str_replace('</ttz><ttz>', '|', $html);
27016 		$html = str_replace('</tta><tta>', '|', $html);
27017 
27018 		$html = preg_replace('/<br \/>\s*/is', "<br />", $html);
27019 
27020 		$html = preg_replace('/<wbr[ \/]*>\s*/is', "&#173;", $html);
27021 
27022 		// Preserve '\n's in content between the tags <pre> and </pre>
27023 		if (preg_match('/<pre/', $html)) {
27024 
27025 			$html_a = preg_split('/(\<\/?pre[^\>]*\>)/', $html, -1, 2);
27026 			$h = [];
27027 			$c = 0;
27028 
27029 			foreach ($html_a as $s) {
27030 				if ($c > 1 && preg_match('/^<\/pre/i', $s)) {
27031 					$c--;
27032 					$s = preg_replace('/<\/pre/i', '</innerpre', $s);
27033 				} elseif ($c > 0 && preg_match('/^<pre/i', $s)) {
27034 					$c++;
27035 					$s = preg_replace('/<pre/i', '<innerpre', $s);
27036 				} elseif (preg_match('/^<pre/i', $s)) {
27037 					$c++;
27038 				} elseif (preg_match('/^<\/pre/i', $s)) {
27039 					$c--;
27040 				}
27041 				array_push($h, $s);
27042 			}
27043 
27044 			$html = implode('', $h);
27045 		}
27046 
27047 		$thereispre = preg_match_all('#<pre(.*?)>(.*?)</pre>#si', $html, $temp);
27048 
27049 		// Preserve '\n's in content between the tags <textarea> and </textarea>
27050 		$thereistextarea = preg_match_all('#<textarea(.*?)>(.*?)</textarea>#si', $html, $temp2);
27051 		$html = preg_replace('/[\n]/', ' ', $html); // replace linefeed by spaces
27052 		$html = preg_replace('/[\t]/', ' ', $html); // replace tabs by spaces
27053 
27054 		// Converts < to &lt; when not a tag
27055 		$html = preg_replace('/<([^!\/a-zA-Z_:])/i', '&lt;\\1', $html); // mPDF 5.7.3
27056 		$html = preg_replace("/[ ]+/", ' ', $html);
27057 
27058 		$html = preg_replace('/\/li>\s+<\/(u|o)l/i', '/li></\\1l', $html);
27059 		$html = preg_replace('/\/(u|o)l>\s+<\/li/i', '/\\1l></li', $html);
27060 		$html = preg_replace('/\/li>\s+<\/(u|o)l/i', '/li></\\1l', $html);
27061 		$html = preg_replace('/\/li>\s+<li/i', '/li><li', $html);
27062 		$html = preg_replace('/<(u|o)l([^>]*)>[ ]+/i', '<\\1l\\2>', $html);
27063 		$html = preg_replace('/[ ]+<(u|o)l/i', '<\\1l', $html);
27064 
27065 		// Make self closing tabs valid XHTML
27066 		// Tags which are self-closing: 1) Replaceable and 2) Non-replaced items
27067 		$selftabs = 'input|hr|img|br|barcode|dottab';
27068 		$selftabs2 = 'indexentry|indexinsert|bookmark|watermarktext|watermarkimage|column_break|columnbreak|newcolumn|newpage|page_break|pagebreak|formfeed|columns|toc|tocpagebreak|setpageheader|setpagefooter|sethtmlpageheader|sethtmlpagefooter|annotation';
27069 
27070 		// Fix self-closing tags which don't close themselves
27071 		$html = preg_replace('/(<(' . $selftabs . '|' . $selftabs2 . ')[^>\/]*)>/i', '\\1 />', $html);
27072 
27073 		// Fix self-closing tags that don't include a space between the tag name and the closing slash
27074 		$html = preg_replace('/(<(' . $selftabs . '|' . $selftabs2 . '))\/>/i', '\\1 />', $html);
27075 
27076 		$iterator = 0;
27077 		while ($thereispre) { // Recover <pre attributes>content</pre>
27078 			$temp[2][$iterator] = preg_replace('/<([^!\/a-zA-Z_:])/', '&lt;\\1', $temp[2][$iterator]); // mPDF 5.7.2	// mPDF 5.7.3
27079 
27080 			$temp[2][$iterator] = preg_replace_callback("/^([^\n\t]*?)\t/m", [$this, 'tabs2spaces_callback'], $temp[2][$iterator]); // mPDF 5.7+
27081 			$temp[2][$iterator] = preg_replace('/\t/', str_repeat(" ", $tabSpaces), $temp[2][$iterator]);
27082 
27083 			$temp[2][$iterator] = preg_replace('/\n/', "<br />", $temp[2][$iterator]);
27084 			$temp[2][$iterator] = str_replace('\\', "\\\\", $temp[2][$iterator]);
27085 			// $html = preg_replace('#<pre(.*?)>(.*?)</pre>#si','<erp'.$temp[1][$iterator].'>'.$temp[2][$iterator].'</erp>',$html,1);
27086 			$html = preg_replace('#<pre(.*?)>(.*?)</pre>#si', '<erp' . $temp[1][$iterator] . '>' . str_replace('$', '\$', $temp[2][$iterator]) . '</erp>', $html, 1); // mPDF 5.7+
27087 			$thereispre--;
27088 			$iterator++;
27089 		}
27090 
27091 		$iterator = 0;
27092 		while ($thereistextarea) { // Recover <textarea attributes>content</textarea>
27093 			$temp2[2][$iterator] = preg_replace('/\t/', str_repeat(" ", $tabSpaces), $temp2[2][$iterator]);
27094 			$temp2[2][$iterator] = str_replace('\\', "\\\\", $temp2[2][$iterator]);
27095 			$html = preg_replace('#<textarea(.*?)>(.*?)</textarea>#si', '<aeratxet' . $temp2[1][$iterator] . '>' . trim($temp2[2][$iterator]) . '</aeratxet>', $html, 1);
27096 			$thereistextarea--;
27097 			$iterator++;
27098 		}
27099 
27100 		// Restore original tag names
27101 		$html = str_replace("<erp", "<pre", $html);
27102 		$html = str_replace("</erp>", "</pre>", $html);
27103 		$html = str_replace("<aeratxet", "<textarea", $html);
27104 		$html = str_replace("</aeratxet>", "</textarea>", $html);
27105 		$html = str_replace("</innerpre", "</pre", $html);
27106 		$html = str_replace("<innerpre", "<pre", $html);
27107 
27108 		$html = preg_replace('/<textarea([^>]*)><\/textarea>/si', '<textarea\\1> </textarea>', $html);
27109 		$html = preg_replace('/(<table[^>]*>)\s*(<caption)(.*?<\/caption>)(.*?<\/table>)/si', '\\2 position="top"\\3\\1\\4\\2 position="bottom"\\3', $html); // *TABLES*
27110 		$html = preg_replace('/<(h[1-6])([^>]*)(>(?:(?!h[1-6]).)*?<\/\\1>\s*<table)/si', '<\\1\\2 keep-with-table="1"\\3', $html); // *TABLES*
27111 		$html = preg_replace("/\xbb\xa4\xac/", "\n", $html);
27112 
27113 		// Fixes <p>&#8377</p> which browser copes with even though it is wrong!
27114 		$html = preg_replace("/(&#[x]{0,1}[0-9a-f]{1,5})</i", "\\1;<", $html);
27115 
27116 		return $html;
27117 	}
27118 
27119 	// mPDF 5.7+
27120 	function tabs2spaces_callback($matches)
27121 	{
27122 		return (stripslashes($matches[1]) . str_repeat(' ', $this->tabSpaces - (mb_strlen(stripslashes($matches[1])) % $this->tabSpaces)));
27123 	}
27124 
27125 	// mPDF 5.7+
27126 	function date_callback($matches)
27127 	{
27128 		return date($matches[1]);
27129 	}
27130 
27131 	// ========== OVERWRITE SEARCH STRING IN A PDF FILE ================
27132 	function OverWrite($file_in, $search, $replacement, $dest = Destination::DOWNLOAD, $file_out = "mpdf")
27133 	{
27134 		$pdf = file_get_contents($file_in);
27135 
27136 		if (!is_array($search)) {
27137 			$x = $search;
27138 			$search = [$x];
27139 		}
27140 		if (!is_array($replacement)) {
27141 			$x = $replacement;
27142 			$replacement = [$x]; // mPDF 5.7.4
27143 		}
27144 
27145 		if (!$this->onlyCoreFonts && !$this->usingCoreFont) {
27146 			foreach ($search as $k => $val) {
27147 				$search[$k] = $this->writer->utf8ToUtf16BigEndian($search[$k], false);
27148 				$search[$k] = $this->writer->escape($search[$k]);
27149 				$replacement[$k] = $this->writer->utf8ToUtf16BigEndian($replacement[$k], false);
27150 				$replacement[$k] = $this->writer->escape($replacement[$k]);
27151 			}
27152 		} else {
27153 			foreach ($replacement as $k => $val) {
27154 				$replacement[$k] = mb_convert_encoding($replacement[$k], $this->mb_enc, 'utf-8');
27155 				$replacement[$k] = $this->writer->escape($replacement[$k]);
27156 			}
27157 		}
27158 
27159 		// Get xref into array
27160 		$xref = [];
27161 		preg_match("/xref\n0 (\d+)\n(.*?)\ntrailer/s", $pdf, $m);
27162 		$xref_objid = $m[1];
27163 		preg_match_all('/(\d{10}) (\d{5}) (f|n)/', $m[2], $x);
27164 		for ($i = 0; $i < count($x[0]); $i++) {
27165 			$xref[] = [intval($x[1][$i]), $x[2][$i], $x[3][$i]];
27166 		}
27167 
27168 		$changes = [];
27169 		preg_match("/<<\s*\/Type\s*\/Pages\s*\/Kids\s*\[(.*?)\]\s*\/Count/s", $pdf, $m);
27170 		preg_match_all("/(\d+) 0 R /s", $m[1], $o);
27171 		$objlist = $o[1];
27172 
27173 		foreach ($objlist as $obj) {
27174 			if ($this->compress) {
27175 				preg_match("/" . ($obj + 1) . " 0 obj\n<<\s*\/Filter\s*\/FlateDecode\s*\/Length (\d+)>>\nstream\n(.*?)\nendstream\n/s", $pdf, $m);
27176 			} else {
27177 				preg_match("/" . ($obj + 1) . " 0 obj\n<<\s*\/Length (\d+)>>\nstream\n(.*?)\nendstream\n/s", $pdf, $m);
27178 			}
27179 
27180 			$s = $m[2];
27181 			if (!$s) {
27182 				continue;
27183 			}
27184 
27185 			$oldlen = $m[1];
27186 
27187 			if ($this->encrypted) {
27188 				$s = $this->protection->rc4($this->protection->objectKey($obj + 1), $s);
27189 			}
27190 
27191 			if ($this->compress) {
27192 				$s = gzuncompress($s);
27193 			}
27194 
27195 			foreach ($search as $k => $val) {
27196 				$s = str_replace($search[$k], $replacement[$k], $s);
27197 			}
27198 
27199 			if ($this->compress) {
27200 				$s = gzcompress($s);
27201 			}
27202 
27203 			if ($this->encrypted) {
27204 				$s = $this->protection->rc4($this->protection->objectKey($obj + 1), $s);
27205 			}
27206 
27207 			$newlen = strlen($s);
27208 
27209 			$changes[($xref[$obj + 1][0])] = ($newlen - $oldlen) + (strlen($newlen) - strlen($oldlen));
27210 
27211 			if ($this->compress) {
27212 				$newstr = ($obj + 1) . " 0 obj\n<</Filter /FlateDecode /Length " . $newlen . ">>\nstream\n" . $s . "\nendstream\n";
27213 			} else {
27214 				$newstr = ($obj + 1) . " 0 obj\n<</Length " . $newlen . ">>\nstream\n" . $s . "\nendstream\n";
27215 			}
27216 
27217 			$pdf = str_replace($m[0], $newstr, $pdf);
27218 		}
27219 
27220 		// Update xref in PDF
27221 		krsort($changes);
27222 		$newxref = "xref\n0 " . $xref_objid . "\n";
27223 		foreach ($xref as $v) {
27224 			foreach ($changes as $ck => $cv) {
27225 				if ($v[0] > $ck) {
27226 					$v[0] += $cv;
27227 				}
27228 			}
27229 			$newxref .= sprintf('%010d', $v[0]) . ' ' . $v[1] . ' ' . $v[2] . " \n";
27230 		}
27231 		$newxref .= "trailer";
27232 		$pdf = preg_replace("/xref\n0 \d+\n.*?\ntrailer/s", $newxref, $pdf);
27233 
27234 		// Update startxref in PDF
27235 		preg_match("/startxref\n(\d+)\n%%EOF/s", $pdf, $m);
27236 		$startxref = $m[1];
27237 		$startxref += array_sum($changes);
27238 		$pdf = preg_replace("/startxref\n(\d+)\n%%EOF/s", "startxref\n" . $startxref . "\n%%EOF", $pdf);
27239 
27240 		// OUTPUT
27241 		switch ($dest) {
27242 			case Destination::INLINE:
27243 				if (isset($_SERVER['SERVER_NAME'])) {
27244 					// We send to a browser
27245 					header('Content-Type: application/pdf');
27246 					header('Content-Length: ' . strlen($pdf));
27247 					header('Content-disposition: inline; filename=' . $file_out);
27248 				}
27249 
27250 				echo $pdf;
27251 
27252 				break;
27253 
27254 			case Destination::FILE:
27255 				if (!$file_out) {
27256 					$file_out = 'mpdf.pdf';
27257 				}
27258 
27259 				$f = fopen($file_out, 'wb');
27260 
27261 				if (!$f) {
27262 					throw new \Mpdf\MpdfException('Unable to create output file: ' . $file_out);
27263 				}
27264 
27265 				fwrite($f, $pdf, strlen($pdf));
27266 
27267 				fclose($f);
27268 
27269 				break;
27270 
27271 			case Destination::STRING_RETURN:
27272 				return $pdf;
27273 
27274 			case Destination::DOWNLOAD: // Download file
27275 			default:
27276 				if (isset($_SERVER['HTTP_USER_AGENT']) and strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
27277 					header('Content-Type: application/force-download');
27278 				} else {
27279 					header('Content-Type: application/octet-stream');
27280 				}
27281 
27282 				header('Content-Length: ' . strlen($pdf));
27283 				header('Content-disposition: attachment; filename=' . $file_out);
27284 
27285 				echo $pdf;
27286 
27287 				break;
27288 		}
27289 	}
27290 
27291 
27292 	function Thumbnail($file, $npr = 3, $spacing = 10)
27293 	{
27294 		// $npr = number per row
27295 		$w = (($this->pgwidth + $spacing) / $npr) - $spacing;
27296 		$oldlinewidth = $this->LineWidth;
27297 		$this->SetLineWidth(0.02);
27298 		$this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
27299 		$h = 0;
27300 		$maxh = 0;
27301 		$x = $_x = $this->lMargin;
27302 		$_y = $this->tMargin;
27303 
27304 		if ($this->y == 0) {
27305 			$y = $_y;
27306 		} else {
27307 			$y = $this->y;
27308 		}
27309 
27310 		$pagecount = $this->setSourceFile($file);
27311 
27312 		for ($n = 1; $n <= $pagecount; $n++) {
27313 			$tplidx = $this->importPage($n);
27314 			$size = $this->useTemplate($tplidx, $x, $y, $w);
27315 			$this->Rect($x, $y, $size['width'], $size['height']);
27316 			$h = max($h, $size['height']);
27317 			$maxh = max($h, $maxh);
27318 
27319 			if ($n % $npr == 0) {
27320 				if (($y + $h + $spacing + $maxh) > $this->PageBreakTrigger && $n != $pagecount) {
27321 					$this->AddPage();
27322 					$x = $_x;
27323 					$y = $_y;
27324 				} else {
27325 					$y += $h + $spacing;
27326 					$x = $_x;
27327 					$h = 0;
27328 				}
27329 			} else {
27330 				$x += $w + $spacing;
27331 			}
27332 		}
27333 		$this->SetLineWidth($oldlinewidth);
27334 	}
27335 
27336 	function SetPageTemplate($tplidx = '')
27337 	{
27338 		if (!isset($this->importedPages[$tplidx])) {
27339 			$this->pageTemplate = '';
27340 			return false;
27341 		}
27342 		$this->pageTemplate = $tplidx;
27343 	}
27344 
27345 	function SetDocTemplate($file = '', $continue = 0, $continue2pages = 0)
27346 	{
27347 		$this->docTemplate = $file;
27348 		$this->docTemplateContinue = $continue;
27349 		$this->docTemplateContinue2pages = $continue2pages;
27350 
27351 		if ($this->docTemplateContinue2pages) { // Enable continue when continue2pages is set
27352 			$this->docTemplateContinue = $this->docTemplateContinue2pages;
27353 		}
27354 	}
27355 
27356 	/* -- END IMPORTS -- */
27357 
27358 	// JAVASCRIPT
27359 	function _set_object_javascript($string)
27360 	{
27361 		$this->writer->object();
27362 		$this->writer->write('<<');
27363 		$this->writer->write('/S /JavaScript ');
27364 		$this->writer->write('/JS ' . $this->writer->string($string));
27365 		$this->writer->write('>>');
27366 		$this->writer->write('endobj');
27367 	}
27368 
27369 	function SetJS($script)
27370 	{
27371 		$this->js = $script;
27372 	}
27373 
27374 	/**
27375 	 * This function takes the last comma or dot (if any) to make a clean float, ignoring thousand separator, currency or any other letter
27376 	 *
27377 	 * @param string $num
27378 	 * @see http://php.net/manual/de/function.floatval.php#114486
27379 	 * @return float
27380 	 */
27381 	public function toFloat($num)
27382 	{
27383 		$dotPos = strrpos($num, '.');
27384 		$commaPos = strrpos($num, ',');
27385 		$sep = (($dotPos > $commaPos) && $dotPos) ? $dotPos : ((($commaPos > $dotPos) && $commaPos) ? $commaPos : false);
27386 
27387 		if (!$sep) {
27388 			return floatval(preg_replace('/[^0-9]/', '', $num));
27389 		}
27390 
27391 		return floatval(
27392 			preg_replace('/[^0-9]/', '', substr($num, 0, $sep)) . '.' .
27393 			preg_replace('/[^0-9]/', '', substr($num, $sep+1, strlen($num)))
27394 		);
27395 	}
27396 
27397 	public function getFontDescriptor()
27398 	{
27399 		return $this->fontDescriptor;
27400 	}
27401 
27402 	/**
27403 	 * Temporarily return the method to preserve example 44 yearbook
27404 	 */
27405 	public function _out($s)
27406 	{
27407 		$this->writer->write($s);
27408 	}
27409 
27410 	/**
27411 	 * @param string $html
27412 	 * @param string $PAGENO
27413 	 * @param string $NbPgGp
27414 	 * @param string $NbPg
27415 	 * @return string
27416 	 */
27417 	protected function aliasReplace($html, $PAGENO, $NbPgGp, $NbPg)
27418 	{
27419 		// Replaces for header and footer
27420 		$html = str_replace('{PAGENO}', $PAGENO, $html);
27421 		$html = str_replace($this->aliasNbPgGp, $NbPgGp, $html); // {nbpg}
27422 		$html = str_replace($this->aliasNbPg, $NbPg, $html); // {nb}
27423 
27424 		// Replaces for the body
27425 		$html = str_replace(mb_convert_encoding('{PAGENO}', 'UTF-16BE', 'UTF-8'), mb_convert_encoding($PAGENO, 'UTF-16BE', 'UTF-8'), $html);
27426 		$html = str_replace(mb_convert_encoding($this->aliasNbPgGp, 'UTF-16BE', 'UTF-8'), mb_convert_encoding($NbPgGp, 'UTF-16BE', 'UTF-8'), $html); // {nbpg}
27427 		$html = str_replace(mb_convert_encoding($this->aliasNbPg, 'UTF-16BE', 'UTF-8'), mb_convert_encoding($NbPg, 'UTF-16BE', 'UTF-8'), $html); // {nb}
27428 
27429 		// Date replace
27430 		$html = preg_replace_callback('/\{DATE\s+(.*?)\}/', [$this, 'date_callback'], $html); // mPDF 5.7
27431 
27432 		return $html;
27433 	}
27434 
27435 }
27436